From: Segher Boessenkool Date: Thu, 19 May 2016 22:17:53 +0000 (+0200) Subject: function: Restructure *logue insertion X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=33fec8d5b3c94cc8f73838abd27a4f0cfa2b3fd6;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c5e637bdaea..fed248d32e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2016-05-19 Segher Boessenkool + + * 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 * 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 +2016-05-19 Ryan Burn * Makefile.in (GTFILES): Add cilk.h and cilk-common.c. * gengtype.c (open_base_files): Add cilk.h to ifiles. diff --git a/gcc/function.c b/gcc/function.c index 4c236eb50f2..5ff17c75b26 100644 --- a/gcc/function.c +++ b/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; - } } + default_rtl_profile (); + /* 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); - - if (!CALL_P (insn) - || ! SIBLING_CALL_P (insn) - || (targetm.have_simple_return () - && entry_edge != orig_entry_edge - && !bitmap_bit_p (&bb_flags, bb->index))) + 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; diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c index 0ba1fedf161..b85b1c3b349 100644 --- a/gcc/shrink-wrap.c +++ b/gcc/shrink-wrap.c @@ -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; + + e->flags &= ~EDGE_FALLTHRU; + emit_barrier_after_bb (e->src); + return; + } + + /* 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); + } - redirect_edge_succ (e, new_bb); - e->flags |= EDGE_FALLTHRU; - e->flags &= ~EDGE_FAKE; + 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); - return make_edge (new_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE); + 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 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); } diff --git a/gcc/shrink-wrap.h b/gcc/shrink-wrap.h index 4d821d73499..e06ab37952f 100644 --- a/gcc/shrink-wrap.h +++ b/gcc/shrink-wrap.h @@ -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 ())