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:
parent
6befaff666
commit
33fec8d5b3
4 changed files with 124 additions and 145 deletions
|
@ -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.
|
||||
|
|
164
gcc/function.c
164
gcc/function.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ())
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue