Commit d07d2177 by Segher Boessenkool Committed by Segher Boessenkool

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
parent 45676a7c
2016-05-04 Segher Boessenkool <segher@kernel.crashing.org> 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. * cfgcleanup.c (bb_is_just_return): New function.
(try_optimize_cfg): Simplify jumps to return, branches to return, (try_optimize_cfg): Simplify jumps to return, branches to return,
and branches around return. and branches around return.
......
...@@ -5753,49 +5753,6 @@ prologue_epilogue_contains (const_rtx insn) ...@@ -5753,49 +5753,6 @@ prologue_epilogue_contains (const_rtx insn)
return 0; 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. */ /* Set JUMP_LABEL for a return insn. */
...@@ -5811,135 +5768,6 @@ set_return_jump_label (rtx_insn *returnjump) ...@@ -5811,135 +5768,6 @@ set_return_jump_label (rtx_insn *returnjump)
JUMP_LABEL (returnjump) = ret_rtx; 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 /* Generate the prologue and epilogue RTL if the machine supports it. Thread
this into place with notes indicating where the prologue ends and where this into place with notes indicating where the prologue ends and where
...@@ -5993,7 +5821,6 @@ void ...@@ -5993,7 +5821,6 @@ void
thread_prologue_and_epilogue_insns (void) thread_prologue_and_epilogue_insns (void)
{ {
bool inserted; bool inserted;
vec<edge> unconverted_simple_returns = vNULL;
bitmap_head bb_flags; bitmap_head bb_flags;
rtx_insn *returnjump; rtx_insn *returnjump;
rtx_insn *epilogue_end ATTRIBUTE_UNUSED; rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
...@@ -6088,40 +5915,8 @@ thread_prologue_and_epilogue_insns (void) ...@@ -6088,40 +5915,8 @@ thread_prologue_and_epilogue_insns (void)
exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
if (targetm.have_simple_return () && entry_edge != orig_entry_edge) if (targetm.have_return () && exit_fallthru_edge == NULL)
exit_fallthru_edge goto epilogue_done;
= 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;
}
}
}
/* A small fib -- epilogue is not yet completed, but we wish to re-use /* 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 this marker for the splits of EH_RETURN patterns, and nothing else
...@@ -6229,10 +6024,6 @@ epilogue_done: ...@@ -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. */ /* Emit sibling epilogues before any sibling call sites. */
for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); (e = for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); (e =
ei_safe_edge (ei)); ei_safe_edge (ei));
......
...@@ -946,10 +946,9 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with, ...@@ -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); redirect_edge_and_branch_force (e, (basic_block) e->dest->aux);
} }
/* Change all the exits that should get a simple_return to FAKE. /* Make a simple_return for those exits that run without prologue. */
They will be converted later. */
FOR_EACH_BB_FN (bb, cfun) FOR_EACH_BB_REVERSE_FN (bb, cfun)
if (!bitmap_bit_p (bb_with, bb->index)) if (!bitmap_bit_p (bb_with, bb->index))
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)) if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
...@@ -958,7 +957,18 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with, ...@@ -958,7 +957,18 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
e->flags &= ~EDGE_FALLTHRU; e->flags &= ~EDGE_FALLTHRU;
if (!(e->flags & EDGE_SIBCALL)) 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); emit_barrier_after_bb (e->src);
} }
...@@ -996,156 +1006,3 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with, ...@@ -996,156 +1006,3 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
free_dominance_info (CDI_DOMINATORS); 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 ...@@ -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 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, extern void try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_flags,
rtx_insn *prologue_seq); 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 \ #define SHRINK_WRAPPING_ENABLED \
(flag_shrink_wrap && targetm.have_simple_return ()) (flag_shrink_wrap && targetm.have_simple_return ())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment