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.
(try_optimize_cfg): Simplify jumps to return, branches to return,
and branches around return.
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. */
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
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;
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
}
}
- 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));
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))
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);
}
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);
- }
- }
-}
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 ())