shrink-wrap: Remove complicated simple_return manipulations
Now that cfgcleanup knows how to optimize with return statements, the epilogue insertion code doesn't have to deal with it itself anymore. * function.c (emit_use_return_register_into_block): Delete. (gen_return_pattern): Delete. (emit_return_into_block): Delete. (active_insn_between): Delete. (convert_jumps_to_returns): Delete. (emit_return_for_exit): Delete. (thread_prologue_and_epilogue_insns): Delete all code dealing with simple_return for shrink-wrapped blocks. * shrink-wrap.c (try_shrink_wrapping): Insert simple_return at the end of blocks that need one. (get_unconverted_simple_return): Delete. (convert_to_simple_return): Delete. * shrink-wrap.c (get_unconverted_simple_return): Delete declaration. (convert_to_simple_return): Ditto. From-SVN: r235905
This commit is contained in:
parent
45676a7c8a
commit
d07d21777f
|
@ -1,3 +1,20 @@
|
|||
2016-05-04 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
|
||||
* function.c (emit_use_return_register_into_block): Delete.
|
||||
(gen_return_pattern): Delete.
|
||||
(emit_return_into_block): Delete.
|
||||
(active_insn_between): Delete.
|
||||
(convert_jumps_to_returns): Delete.
|
||||
(emit_return_for_exit): Delete.
|
||||
(thread_prologue_and_epilogue_insns): Delete all code dealing with
|
||||
simple_return for shrink-wrapped blocks.
|
||||
* shrink-wrap.c (try_shrink_wrapping): Insert simple_return at the
|
||||
end of blocks that need one.
|
||||
(get_unconverted_simple_return): Delete.
|
||||
(convert_to_simple_return): Delete.
|
||||
* shrink-wrap.c (get_unconverted_simple_return): Delete declaration.
|
||||
(convert_to_simple_return): Ditto.
|
||||
|
||||
2016-05-04 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
|
||||
* cfgcleanup.c (bb_is_just_return): New function.
|
||||
|
|
213
gcc/function.c
213
gcc/function.c
|
@ -5753,49 +5753,6 @@ prologue_epilogue_contains (const_rtx insn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Insert use of return register before the end of BB. */
|
||||
|
||||
static void
|
||||
emit_use_return_register_into_block (basic_block bb)
|
||||
{
|
||||
start_sequence ();
|
||||
use_return_register ();
|
||||
rtx_insn *seq = get_insns ();
|
||||
end_sequence ();
|
||||
rtx_insn *insn = BB_END (bb);
|
||||
if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
|
||||
insn = prev_cc0_setter (insn);
|
||||
|
||||
emit_insn_before (seq, insn);
|
||||
}
|
||||
|
||||
|
||||
/* Create a return pattern, either simple_return or return, depending on
|
||||
simple_p. */
|
||||
|
||||
static rtx_insn *
|
||||
gen_return_pattern (bool simple_p)
|
||||
{
|
||||
return (simple_p
|
||||
? targetm.gen_simple_return ()
|
||||
: targetm.gen_return ());
|
||||
}
|
||||
|
||||
/* Insert an appropriate return pattern at the end of block BB. This
|
||||
also means updating block_for_insn appropriately. SIMPLE_P is
|
||||
the same as in gen_return_pattern and passed to it. */
|
||||
|
||||
void
|
||||
emit_return_into_block (bool simple_p, basic_block bb)
|
||||
{
|
||||
rtx_jump_insn *jump = emit_jump_insn_after (gen_return_pattern (simple_p),
|
||||
BB_END (bb));
|
||||
rtx pat = PATTERN (jump);
|
||||
if (GET_CODE (pat) == PARALLEL)
|
||||
pat = XVECEXP (pat, 0, 0);
|
||||
gcc_assert (ANY_RETURN_P (pat));
|
||||
JUMP_LABEL (jump) = pat;
|
||||
}
|
||||
|
||||
/* Set JUMP_LABEL for a return insn. */
|
||||
|
||||
|
@ -5811,135 +5768,6 @@ set_return_jump_label (rtx_insn *returnjump)
|
|||
JUMP_LABEL (returnjump) = ret_rtx;
|
||||
}
|
||||
|
||||
/* Return true if there are any active insns between HEAD and TAIL. */
|
||||
bool
|
||||
active_insn_between (rtx_insn *head, rtx_insn *tail)
|
||||
{
|
||||
while (tail)
|
||||
{
|
||||
if (active_insn_p (tail))
|
||||
return true;
|
||||
if (tail == head)
|
||||
return false;
|
||||
tail = PREV_INSN (tail);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* LAST_BB is a block that exits, and empty of active instructions.
|
||||
Examine its predecessors for jumps that can be converted to
|
||||
(conditional) returns. */
|
||||
vec<edge>
|
||||
convert_jumps_to_returns (basic_block last_bb, bool simple_p,
|
||||
vec<edge> unconverted ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int i;
|
||||
basic_block bb;
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
auto_vec<basic_block> src_bbs (EDGE_COUNT (last_bb->preds));
|
||||
|
||||
FOR_EACH_EDGE (e, ei, last_bb->preds)
|
||||
if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
|
||||
src_bbs.quick_push (e->src);
|
||||
|
||||
rtx_insn *label = BB_HEAD (last_bb);
|
||||
|
||||
FOR_EACH_VEC_ELT (src_bbs, i, bb)
|
||||
{
|
||||
rtx_insn *jump = BB_END (bb);
|
||||
|
||||
if (!JUMP_P (jump) || JUMP_LABEL (jump) != label)
|
||||
continue;
|
||||
|
||||
e = find_edge (bb, last_bb);
|
||||
|
||||
/* If we have an unconditional jump, we can replace that
|
||||
with a simple return instruction. */
|
||||
if (simplejump_p (jump))
|
||||
{
|
||||
/* The use of the return register might be present in the exit
|
||||
fallthru block. Either:
|
||||
- removing the use is safe, and we should remove the use in
|
||||
the exit fallthru block, or
|
||||
- removing the use is not safe, and we should add it here.
|
||||
For now, we conservatively choose the latter. Either of the
|
||||
2 helps in crossjumping. */
|
||||
emit_use_return_register_into_block (bb);
|
||||
|
||||
emit_return_into_block (simple_p, bb);
|
||||
delete_insn (jump);
|
||||
}
|
||||
|
||||
/* If we have a conditional jump branching to the last
|
||||
block, we can try to replace that with a conditional
|
||||
return instruction. */
|
||||
else if (condjump_p (jump))
|
||||
{
|
||||
rtx dest;
|
||||
|
||||
if (simple_p)
|
||||
dest = simple_return_rtx;
|
||||
else
|
||||
dest = ret_rtx;
|
||||
if (!redirect_jump (as_a <rtx_jump_insn *> (jump), dest, 0))
|
||||
{
|
||||
if (targetm.have_simple_return () && simple_p)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file,
|
||||
"Failed to redirect bb %d branch.\n", bb->index);
|
||||
unconverted.safe_push (e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* See comment in simplejump_p case above. */
|
||||
emit_use_return_register_into_block (bb);
|
||||
|
||||
/* If this block has only one successor, it both jumps
|
||||
and falls through to the fallthru block, so we can't
|
||||
delete the edge. */
|
||||
if (single_succ_p (bb))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetm.have_simple_return () && simple_p)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file,
|
||||
"Failed to redirect bb %d branch.\n", bb->index);
|
||||
unconverted.safe_push (e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fix up the CFG for the successful change we just made. */
|
||||
redirect_edge_succ (e, EXIT_BLOCK_PTR_FOR_FN (cfun));
|
||||
e->flags &= ~EDGE_CROSSING;
|
||||
}
|
||||
src_bbs.release ();
|
||||
return unconverted;
|
||||
}
|
||||
|
||||
/* Emit a return insn for the exit fallthru block. */
|
||||
basic_block
|
||||
emit_return_for_exit (edge exit_fallthru_edge, bool simple_p)
|
||||
{
|
||||
basic_block last_bb = exit_fallthru_edge->src;
|
||||
|
||||
if (JUMP_P (BB_END (last_bb)))
|
||||
{
|
||||
last_bb = split_edge (exit_fallthru_edge);
|
||||
exit_fallthru_edge = single_succ_edge (last_bb);
|
||||
}
|
||||
emit_barrier_after (BB_END (last_bb));
|
||||
emit_return_into_block (simple_p, last_bb);
|
||||
exit_fallthru_edge->flags &= ~EDGE_FALLTHRU;
|
||||
return last_bb;
|
||||
}
|
||||
|
||||
|
||||
/* Generate the prologue and epilogue RTL if the machine supports it. Thread
|
||||
this into place with notes indicating where the prologue ends and where
|
||||
|
@ -5993,7 +5821,6 @@ void
|
|||
thread_prologue_and_epilogue_insns (void)
|
||||
{
|
||||
bool inserted;
|
||||
vec<edge> unconverted_simple_returns = vNULL;
|
||||
bitmap_head bb_flags;
|
||||
rtx_insn *returnjump;
|
||||
rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
|
||||
|
@ -6088,40 +5915,8 @@ thread_prologue_and_epilogue_insns (void)
|
|||
|
||||
exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
|
||||
|
||||
if (targetm.have_simple_return () && entry_edge != orig_entry_edge)
|
||||
exit_fallthru_edge
|
||||
= get_unconverted_simple_return (exit_fallthru_edge, bb_flags,
|
||||
&unconverted_simple_returns,
|
||||
&returnjump);
|
||||
if (targetm.have_return ())
|
||||
{
|
||||
if (exit_fallthru_edge == NULL)
|
||||
goto epilogue_done;
|
||||
|
||||
if (optimize)
|
||||
{
|
||||
basic_block last_bb = exit_fallthru_edge->src;
|
||||
|
||||
if (LABEL_P (BB_HEAD (last_bb))
|
||||
&& !active_insn_between (BB_HEAD (last_bb), BB_END (last_bb)))
|
||||
convert_jumps_to_returns (last_bb, false, vNULL);
|
||||
|
||||
if (EDGE_COUNT (last_bb->preds) != 0
|
||||
&& single_succ_p (last_bb))
|
||||
{
|
||||
last_bb = emit_return_for_exit (exit_fallthru_edge, false);
|
||||
epilogue_end = returnjump = BB_END (last_bb);
|
||||
|
||||
/* Emitting the return may add a basic block.
|
||||
Fix bb_flags for the added block. */
|
||||
if (targetm.have_simple_return ()
|
||||
&& last_bb != exit_fallthru_edge->src)
|
||||
bitmap_set_bit (&bb_flags, last_bb->index);
|
||||
|
||||
goto epilogue_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetm.have_return () && exit_fallthru_edge == NULL)
|
||||
goto epilogue_done;
|
||||
|
||||
/* A small fib -- epilogue is not yet completed, but we wish to re-use
|
||||
this marker for the splits of EH_RETURN patterns, and nothing else
|
||||
|
@ -6229,10 +6024,6 @@ epilogue_done:
|
|||
}
|
||||
}
|
||||
|
||||
if (targetm.have_simple_return ())
|
||||
convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags,
|
||||
returnjump, unconverted_simple_returns);
|
||||
|
||||
/* Emit sibling epilogues before any sibling call sites. */
|
||||
for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); (e =
|
||||
ei_safe_edge (ei));
|
||||
|
|
|
@ -946,10 +946,9 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
|
|||
redirect_edge_and_branch_force (e, (basic_block) e->dest->aux);
|
||||
}
|
||||
|
||||
/* Change all the exits that should get a simple_return to FAKE.
|
||||
They will be converted later. */
|
||||
/* Make a simple_return for those exits that run without prologue. */
|
||||
|
||||
FOR_EACH_BB_FN (bb, cfun)
|
||||
FOR_EACH_BB_REVERSE_FN (bb, cfun)
|
||||
if (!bitmap_bit_p (bb_with, bb->index))
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
|
||||
|
@ -958,7 +957,18 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
|
|||
|
||||
e->flags &= ~EDGE_FALLTHRU;
|
||||
if (!(e->flags & EDGE_SIBCALL))
|
||||
e->flags |= EDGE_FAKE;
|
||||
{
|
||||
rtx_insn *ret = targetm.gen_simple_return ();
|
||||
rtx_insn *end = BB_END (e->src);
|
||||
rtx_jump_insn *start = emit_jump_insn_after (ret, end);
|
||||
JUMP_LABEL (start) = simple_return_rtx;
|
||||
e->flags &= ~EDGE_FAKE;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file,
|
||||
"Made simple_return with UID %d in bb %d\n",
|
||||
INSN_UID (start), e->src->index);
|
||||
}
|
||||
|
||||
emit_barrier_after_bb (e->src);
|
||||
}
|
||||
|
@ -996,156 +1006,3 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
|
|||
|
||||
free_dominance_info (CDI_DOMINATORS);
|
||||
}
|
||||
|
||||
/* If we're allowed to generate a simple return instruction, then by
|
||||
definition we don't need a full epilogue. If the last basic
|
||||
block before the exit block does not contain active instructions,
|
||||
examine its predecessors and try to emit (conditional) return
|
||||
instructions. */
|
||||
|
||||
edge
|
||||
get_unconverted_simple_return (edge exit_fallthru_edge, bitmap_head bb_flags,
|
||||
vec<edge> *unconverted_simple_returns,
|
||||
rtx_insn **returnjump)
|
||||
{
|
||||
if (optimize)
|
||||
{
|
||||
unsigned i, last;
|
||||
|
||||
/* convert_jumps_to_returns may add to preds of the exit block
|
||||
(but won't remove). Stop at end of current preds. */
|
||||
last = EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
|
||||
for (i = 0; i < last; i++)
|
||||
{
|
||||
edge e = EDGE_I (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds, i);
|
||||
if (LABEL_P (BB_HEAD (e->src))
|
||||
&& !bitmap_bit_p (&bb_flags, e->src->index)
|
||||
&& !active_insn_between (BB_HEAD (e->src), BB_END (e->src)))
|
||||
*unconverted_simple_returns
|
||||
= convert_jumps_to_returns (e->src, true,
|
||||
*unconverted_simple_returns);
|
||||
}
|
||||
}
|
||||
|
||||
if (exit_fallthru_edge != NULL
|
||||
&& EDGE_COUNT (exit_fallthru_edge->src->preds) != 0
|
||||
&& !bitmap_bit_p (&bb_flags, exit_fallthru_edge->src->index))
|
||||
{
|
||||
basic_block last_bb;
|
||||
|
||||
last_bb = emit_return_for_exit (exit_fallthru_edge, true);
|
||||
*returnjump = BB_END (last_bb);
|
||||
exit_fallthru_edge = NULL;
|
||||
}
|
||||
return exit_fallthru_edge;
|
||||
}
|
||||
|
||||
/* If there were branches to an empty LAST_BB which we tried to
|
||||
convert to conditional simple_returns, but couldn't for some
|
||||
reason, create a block to hold a simple_return insn and redirect
|
||||
those remaining edges. */
|
||||
|
||||
void
|
||||
convert_to_simple_return (edge entry_edge, edge orig_entry_edge,
|
||||
bitmap_head bb_flags, rtx_insn *returnjump,
|
||||
vec<edge> unconverted_simple_returns)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
if (!unconverted_simple_returns.is_empty ())
|
||||
{
|
||||
basic_block simple_return_block_hot = NULL;
|
||||
basic_block simple_return_block_cold = NULL;
|
||||
edge pending_edge_hot = NULL;
|
||||
edge pending_edge_cold = NULL;
|
||||
basic_block exit_pred;
|
||||
int i;
|
||||
|
||||
gcc_assert (entry_edge != orig_entry_edge);
|
||||
|
||||
/* See if we can reuse the last insn that was emitted for the
|
||||
epilogue. */
|
||||
if (returnjump != NULL_RTX
|
||||
&& JUMP_LABEL (returnjump) == simple_return_rtx)
|
||||
{
|
||||
e = split_block (BLOCK_FOR_INSN (returnjump), PREV_INSN (returnjump));
|
||||
if (BB_PARTITION (e->src) == BB_HOT_PARTITION)
|
||||
simple_return_block_hot = e->dest;
|
||||
else
|
||||
simple_return_block_cold = e->dest;
|
||||
}
|
||||
|
||||
/* Also check returns we might need to add to tail blocks. */
|
||||
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
|
||||
if (EDGE_COUNT (e->src->preds) != 0
|
||||
&& (e->flags & EDGE_FAKE) != 0
|
||||
&& !bitmap_bit_p (&bb_flags, e->src->index))
|
||||
{
|
||||
if (BB_PARTITION (e->src) == BB_HOT_PARTITION)
|
||||
pending_edge_hot = e;
|
||||
else
|
||||
pending_edge_cold = e;
|
||||
}
|
||||
|
||||
/* Save a pointer to the exit's predecessor BB for use in
|
||||
inserting new BBs at the end of the function. Do this
|
||||
after the call to split_block above which may split
|
||||
the original exit pred. */
|
||||
exit_pred = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
|
||||
|
||||
FOR_EACH_VEC_ELT (unconverted_simple_returns, i, e)
|
||||
{
|
||||
basic_block *pdest_bb;
|
||||
edge pending;
|
||||
|
||||
if (BB_PARTITION (e->src) == BB_HOT_PARTITION)
|
||||
{
|
||||
pdest_bb = &simple_return_block_hot;
|
||||
pending = pending_edge_hot;
|
||||
}
|
||||
else
|
||||
{
|
||||
pdest_bb = &simple_return_block_cold;
|
||||
pending = pending_edge_cold;
|
||||
}
|
||||
|
||||
if (*pdest_bb == NULL && pending != NULL)
|
||||
{
|
||||
emit_return_into_block (true, pending->src);
|
||||
pending->flags &= ~(EDGE_FALLTHRU | EDGE_FAKE);
|
||||
*pdest_bb = pending->src;
|
||||
}
|
||||
else if (*pdest_bb == NULL)
|
||||
{
|
||||
basic_block bb;
|
||||
|
||||
bb = create_basic_block (NULL, NULL, exit_pred);
|
||||
BB_COPY_PARTITION (bb, e->src);
|
||||
rtx_insn *ret = targetm.gen_simple_return ();
|
||||
rtx_jump_insn *start = emit_jump_insn_after (ret, BB_END (bb));
|
||||
JUMP_LABEL (start) = simple_return_rtx;
|
||||
emit_barrier_after (start);
|
||||
|
||||
*pdest_bb = bb;
|
||||
make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
|
||||
}
|
||||
redirect_edge_and_branch_force (e, *pdest_bb);
|
||||
}
|
||||
unconverted_simple_returns.release ();
|
||||
}
|
||||
|
||||
if (entry_edge != orig_entry_edge)
|
||||
{
|
||||
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
|
||||
if (EDGE_COUNT (e->src->preds) != 0
|
||||
&& (e->flags & EDGE_FAKE) != 0
|
||||
&& !bitmap_bit_p (&bb_flags, e->src->index))
|
||||
{
|
||||
e = fix_fake_fallthrough_edge (e);
|
||||
|
||||
emit_return_into_block (true, e->src);
|
||||
e->flags &= ~(EDGE_FALLTHRU | EDGE_FAKE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
extern bool requires_stack_frame_p (rtx_insn *, HARD_REG_SET, HARD_REG_SET);
|
||||
extern void try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_flags,
|
||||
rtx_insn *prologue_seq);
|
||||
extern edge get_unconverted_simple_return (edge, bitmap_head,
|
||||
vec<edge> *, rtx_insn **);
|
||||
extern void convert_to_simple_return (edge entry_edge, edge orig_entry_edge,
|
||||
bitmap_head bb_flags,
|
||||
rtx_insn *returnjump,
|
||||
vec<edge> unconverted_simple_returns);
|
||||
#define SHRINK_WRAPPING_ENABLED \
|
||||
(flag_shrink_wrap && targetm.have_simple_return ())
|
||||
|
||||
|
|
Loading…
Reference in New Issue