function: Restructure *logue insertion

This patch restructures how the prologues/epilogues are inserted.  Sibcalls
that run without prologue are now handled in shrink-wrap.c; it communicates
what is already handled by setting the EDGE_IGNORE flag.  The
try_shrink_wrapping function then doesn't need to be passed the bb_flags
anymore.


	* function.c (make_epilogue_seq): Remove epilogue_end parameter.
	(thread_prologue_and_epilogue_insns): Remove bb_flags.  Restructure
	code.  Ignore sibcalls on EDGE_IGNORE edges.
	* shrink-wrap.c (handle_simple_exit): New function.  Set EDGE_IGNORE
	on edges for sibcalls that run without prologue.  The rest of the
	function is combined from...
	(fix_fake_fallthrough_edge): ... this, and ...
	(try_shrink_wrapping): ... a part of this.  Remove the bb_with
	function argument, make it a local variable.

From-SVN: r236491
This commit is contained in:
Segher Boessenkool 2016-05-20 00:17:53 +02:00
parent 6befaff666
commit 33fec8d5b3
4 changed files with 124 additions and 145 deletions

View File

@ -1,3 +1,15 @@
2016-05-19 Segher Boessenkool <segher@kernel.crashing.org>
* function.c (make_epilogue_seq): Remove epilogue_end parameter.
(thread_prologue_and_epilogue_insns): Remove bb_flags. Restructure
code. Ignore sibcalls on EDGE_IGNORE edges.
* shrink-wrap.c (handle_simple_exit): New function. Set EDGE_IGNORE
on edges for sibcalls that run without prologue. The rest of the
function is combined from...
(fix_fake_fallthrough_edge): ... this, and ...
(try_shrink_wrapping): ... a part of this. Remove the bb_with
function argument, make it a local variable.
2016-05-19 Sandra Loosemore <sandra@codesourcery.com>
* config/i386/cygming.h (DWARF2_UNWIND_INFO): Allow
@ -6,7 +18,7 @@
* config/i386/mingw32.h (SHARED_LIBGCC_UNDEFS_SPEC): Handle
TARGET_64BIT_DEFAULT.
2016-05-16 Ryan Burn <contact@rnburn.com>
2016-05-19 Ryan Burn <contact@rnburn.com>
* Makefile.in (GTFILES): Add cilk.h and cilk-common.c.
* gengtype.c (open_base_files): Add cilk.h to ifiles.

View File

@ -5828,13 +5828,13 @@ make_prologue_seq (void)
or NULL. */
static rtx_insn *
make_epilogue_seq (rtx_insn **epilogue_end)
make_epilogue_seq (void)
{
if (!targetm.have_epilogue ())
return NULL;
start_sequence ();
*epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
emit_note (NOTE_INSN_EPILOGUE_BEG);
rtx_insn *seq = targetm.gen_epilogue ();
if (seq)
emit_jump_insn (seq);
@ -5905,61 +5905,29 @@ make_epilogue_seq (rtx_insn **epilogue_end)
void
thread_prologue_and_epilogue_insns (void)
{
bool inserted;
bitmap_head bb_flags;
rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
edge e, entry_edge, orig_entry_edge, exit_fallthru_edge;
edge_iterator ei;
df_analyze ();
rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
inserted = false;
epilogue_end = NULL;
/* Can't deal with multiple successors of the entry block at the
moment. Function should always have at least one entry
point. */
gcc_assert (single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
orig_entry_edge = entry_edge;
edge entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
edge orig_entry_edge = entry_edge;
rtx_insn *split_prologue_seq = make_split_prologue_seq ();
rtx_insn *prologue_seq = make_prologue_seq ();
rtx_insn *epilogue_seq = make_epilogue_seq (&epilogue_end);
bitmap_initialize (&bb_flags, &bitmap_default_obstack);
rtx_insn *epilogue_seq = make_epilogue_seq ();
/* Try to perform a kind of shrink-wrapping, making sure the
prologue/epilogue is emitted only around those parts of the
function that require it. */
try_shrink_wrapping (&entry_edge, &bb_flags, prologue_seq);
try_shrink_wrapping (&entry_edge, prologue_seq);
if (split_prologue_seq != NULL_RTX)
{
insert_insn_on_edge (split_prologue_seq, orig_entry_edge);
inserted = true;
}
if (prologue_seq != NULL_RTX)
{
insert_insn_on_edge (prologue_seq, entry_edge);
inserted = true;
}
/* If the exit block has no non-fake predecessors, we don't need
an epilogue. */
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
if ((e->flags & EDGE_FAKE) == 0)
break;
if (e == NULL)
goto epilogue_done;
rtl_profile_for_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
/* 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
uses the flag in the meantime. */
@ -5970,6 +5938,8 @@ thread_prologue_and_epilogue_insns (void)
code. In order to be able to properly annotate these with unwind
info, try to split them now. If we get a valid split, drop an
EPILOGUE_BEG note and mark the insns as epilogue insns. */
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
{
rtx_insn *prev, *last, *trial;
@ -5989,83 +5959,84 @@ thread_prologue_and_epilogue_insns (void)
emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
}
/* If nothing falls through into the exit block, we don't need an
epilogue. */
if (exit_fallthru_edge == NULL)
goto epilogue_done;
edge exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
if (epilogue_seq)
if (exit_fallthru_edge)
{
insert_insn_on_edge (epilogue_seq, exit_fallthru_edge);
inserted = true;
}
else
{
basic_block cur_bb;
if (epilogue_seq)
{
insert_insn_on_edge (epilogue_seq, exit_fallthru_edge);
if (! next_active_insn (BB_END (exit_fallthru_edge->src)))
goto epilogue_done;
/* We have a fall-through edge to the exit block, the source is not
at the end of the function, and there will be an assembler epilogue
at the end of the function.
We can't use force_nonfallthru here, because that would try to
use return. Inserting a jump 'by hand' is extremely messy, so
we take advantage of cfg_layout_finalize using
fixup_fallthru_exit_predecessor. */
cfg_layout_initialize (0);
FOR_EACH_BB_FN (cur_bb, cfun)
if (cur_bb->index >= NUM_FIXED_BLOCKS
&& cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
cur_bb->aux = cur_bb->next_bb;
cfg_layout_finalize ();
/* The epilogue insns we inserted may cause the exit edge to no longer
be fallthru. */
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
{
if (((e->flags & EDGE_FALLTHRU) != 0)
&& returnjump_p (BB_END (e->src)))
e->flags &= ~EDGE_FALLTHRU;
}
}
else if (next_active_insn (BB_END (exit_fallthru_edge->src)))
{
/* We have a fall-through edge to the exit block, the source is not
at the end of the function, and there will be an assembler epilogue
at the end of the function.
We can't use force_nonfallthru here, because that would try to
use return. Inserting a jump 'by hand' is extremely messy, so
we take advantage of cfg_layout_finalize using
fixup_fallthru_exit_predecessor. */
cfg_layout_initialize (0);
basic_block cur_bb;
FOR_EACH_BB_FN (cur_bb, cfun)
if (cur_bb->index >= NUM_FIXED_BLOCKS
&& cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
cur_bb->aux = cur_bb->next_bb;
cfg_layout_finalize ();
}
}
epilogue_done:
/* Insert the prologue. */
default_rtl_profile ();
rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
if (inserted)
if (split_prologue_seq || prologue_seq)
{
sbitmap blocks;
if (split_prologue_seq)
insert_insn_on_edge (split_prologue_seq, orig_entry_edge);
if (prologue_seq)
insert_insn_on_edge (prologue_seq, entry_edge);
commit_edge_insertions ();
/* Look for basic blocks within the prologue insns. */
blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
sbitmap blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (blocks);
bitmap_set_bit (blocks, entry_edge->dest->index);
bitmap_set_bit (blocks, orig_entry_edge->dest->index);
find_many_sub_basic_blocks (blocks);
sbitmap_free (blocks);
/* The epilogue insns we inserted may cause the exit edge to no longer
be fallthru. */
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
{
if (((e->flags & EDGE_FALLTHRU) != 0)
&& returnjump_p (BB_END (e->src)))
e->flags &= ~EDGE_FALLTHRU;
}
}
/* Emit sibling epilogues before any sibling call sites. */
for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); (e =
ei_safe_edge (ei));
)
{
basic_block bb = e->src;
rtx_insn *insn = BB_END (bb);
default_rtl_profile ();
if (!CALL_P (insn)
|| ! SIBLING_CALL_P (insn)
|| (targetm.have_simple_return ()
&& entry_edge != orig_entry_edge
&& !bitmap_bit_p (&bb_flags, bb->index)))
/* Emit sibling epilogues before any sibling call sites. */
for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
(e = ei_safe_edge (ei));
ei_next (&ei))
{
/* Skip those already handled, the ones that run without prologue. */
if (e->flags & EDGE_IGNORE)
{
ei_next (&ei);
e->flags &= ~EDGE_IGNORE;
continue;
}
rtx_insn *insn = BB_END (e->src);
if (!(CALL_P (insn) && SIBLING_CALL_P (insn)))
continue;
if (rtx_insn *ep_seq = targetm.gen_sibcall_epilogue ())
{
start_sequence ();
@ -6082,10 +6053,9 @@ epilogue_done:
emit_insn_before (seq, insn);
}
ei_next (&ei);
}
if (epilogue_end)
if (epilogue_seq)
{
rtx_insn *insn, *next;
@ -6094,17 +6064,15 @@ epilogue_done:
of such a note. Also possibly move
NOTE_INSN_FUNCTION_BEG notes, as those can be relevant for debug
info generation. */
for (insn = epilogue_end; insn; insn = next)
for (insn = epilogue_seq; insn; insn = next)
{
next = NEXT_INSN (insn);
if (NOTE_P (insn)
&& (NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG))
reorder_insns (insn, insn, PREV_INSN (epilogue_end));
reorder_insns (insn, insn, PREV_INSN (epilogue_seq));
}
}
bitmap_clear (&bb_flags);
/* Threading the prologue and epilogue changes the artificial refs
in the entry and exit blocks. */
epilogue_completed = 1;

View File

@ -529,30 +529,49 @@ can_dup_for_shrink_wrapping (basic_block bb, basic_block pro, unsigned max_size)
return true;
}
/* If the source of edge E has more than one successor, the verifier for
branch probabilities gets confused by the fake edges we make where
simple_return statements will be inserted later (because those are not
marked as fallthrough edges). Fix this by creating an extra block just
for that fallthrough. */
/* Do whatever needs to be done for exits that run without prologue.
Sibcalls need nothing done. Normal exits get a simple_return inserted. */
static edge
fix_fake_fallthrough_edge (edge e)
static void
handle_simple_exit (edge e)
{
if (EDGE_COUNT (e->src->succs) <= 1)
return e;
basic_block old_bb = e->src;
rtx_insn *end = BB_END (old_bb);
rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end);
basic_block new_bb = create_basic_block (note, note, old_bb);
BB_COPY_PARTITION (new_bb, old_bb);
BB_END (old_bb) = end;
if (e->flags & EDGE_SIBCALL)
{
/* Tell function.c to take no further action on this edge. */
e->flags |= EDGE_IGNORE;
redirect_edge_succ (e, new_bb);
e->flags |= EDGE_FALLTHRU;
e->flags &= ~EDGE_FAKE;
e->flags &= ~EDGE_FALLTHRU;
emit_barrier_after_bb (e->src);
return;
}
return make_edge (new_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
/* If the basic block the edge comes from has multiple successors,
split the edge. */
if (EDGE_COUNT (e->src->succs) > 1)
{
basic_block old_bb = e->src;
rtx_insn *end = BB_END (old_bb);
rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end);
basic_block new_bb = create_basic_block (note, note, old_bb);
BB_COPY_PARTITION (new_bb, old_bb);
BB_END (old_bb) = end;
redirect_edge_succ (e, new_bb);
e->flags |= EDGE_FALLTHRU;
e = make_edge (new_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
}
e->flags &= ~EDGE_FALLTHRU;
rtx_jump_insn *ret = emit_jump_insn_after (targetm.gen_simple_return (),
BB_END (e->src));
JUMP_LABEL (ret) = simple_return_rtx;
emit_barrier_after_bb (e->src);
if (dump_file)
fprintf (dump_file, "Made simple_return with UID %d in bb %d\n",
INSN_UID (ret), e->src->index);
}
/* Try to perform a kind of shrink-wrapping, making sure the
@ -610,13 +629,10 @@ fix_fake_fallthrough_edge (edge e)
(bb 4 is duplicated to 5; the prologue is inserted on the edge 5->3).
ENTRY_EDGE is the edge where the prologue will be placed, possibly
changed by this function. BB_WITH is a bitmap that, if we do shrink-
wrap, will on return contain the interesting blocks that run with
prologue. PROLOGUE_SEQ is the prologue we will insert. */
changed by this function. PROLOGUE_SEQ is the prologue we will insert. */
void
try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
rtx_insn *prologue_seq)
try_shrink_wrapping (edge *entry_edge, rtx_insn *prologue_seq)
{
/* If we cannot shrink-wrap, are told not to shrink-wrap, or it makes
no sense to shrink-wrap: then do not shrink-wrap! */
@ -739,6 +755,7 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
reachable from PRO that we already found, and in VEC a stack of
those we still need to consider (to find successors). */
bitmap bb_with = BITMAP_ALLOC (NULL);
bitmap_set_bit (bb_with, pro->index);
vec<basic_block> vec;
@ -851,6 +868,7 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
if (pro == entry)
{
BITMAP_FREE (bb_with);
free_dominance_info (CDI_DOMINATORS);
return;
}
@ -952,26 +970,7 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
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 = fix_fake_fallthrough_edge (e);
e->flags &= ~EDGE_FALLTHRU;
if (!(e->flags & EDGE_SIBCALL))
{
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);
}
handle_simple_exit (e);
/* Finally, we want a single edge to put the prologue on. Make a new
block before the PRO block; the edge beteen them is the edge we want.
@ -1004,5 +1003,6 @@ try_shrink_wrapping (edge *entry_edge, bitmap_head *bb_with,
*entry_edge = make_single_succ_edge (new_bb, pro, EDGE_FALLTHRU);
force_nonfallthru (*entry_edge);
BITMAP_FREE (bb_with);
free_dominance_info (CDI_DOMINATORS);
}

View File

@ -24,8 +24,7 @@ along with GCC; see the file COPYING3. If not see
/* In shrink-wrap.c. */
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 void try_shrink_wrapping (edge *entry_edge, rtx_insn *prologue_seq);
#define SHRINK_WRAPPING_ENABLED \
(flag_shrink_wrap && targetm.have_simple_return ())