From 623a66fa858ef308693b61e33f2c7ba6686d3151 Mon Sep 17 00:00:00 2001 From: "J\"orn Rennecke" Date: Mon, 14 Jun 2004 12:09:08 +0000 Subject: [PATCH] basic-block.h (could_fall_through): Declare. * basic-block.h (could_fall_through): Declare. * cfganal.c (can_fallthru): Succeed if the target is EXIT_BLOCK_PTR. Fail if the source already has a fallthrough edge to the exit block pointer. (could_fall_through): New function. * cfgbuild.c (make_edges): Check if we already have a fallthrough edge to the exit block pointer. * cfglayout.c (fixup_fallthru_exit_predecessor): Check that it is not called before reload has completed. Handle special case of first block having a fall-through exit edge. (cfg_layout_finalize): Don't call it before reload or if we have rtl epilogues. (fixup_reorder_chain): A fall through to the exit block does not require the block to come last. Add sanity checks. * cfgrtl.c (rtl_split_edge): Add special handling of fall through edges to the exit block. * function.c (cfglayout.h): #include. (thread_prologue_and_epilogue_insns): If we have neither return nor epilogue, but a fall through to the exit block from mid-function, force a non-fall-through exit. * Makefile.in (function.o): Depend on CFGLAYOUT_H. From-SVN: r83089 --- gcc/ChangeLog | 24 ++++++++++++++++++++++++ gcc/Makefile.in | 3 ++- gcc/basic-block.h | 1 + gcc/cfganal.c | 27 ++++++++++++++++++++++++++- gcc/cfgbuild.c | 7 +++++++ gcc/cfglayout.c | 39 +++++++++++++++++++++++++++++++++++---- gcc/cfgrtl.c | 14 +++++++++++++- gcc/function.c | 42 +++++++++++++++++++++++++++++++----------- 8 files changed, 139 insertions(+), 18 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7ef4027fc7c..24a8365f461 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2004-06-14 J"orn Rennecke + + * basic-block.h (could_fall_through): Declare. + * cfganal.c (can_fallthru): Succeed if the target is EXIT_BLOCK_PTR. + Fail if the source already has a fallthrough edge to the exit + block pointer. + (could_fall_through): New function. + * cfgbuild.c (make_edges): Check if we already have a fallthrough + edge to the exit block pointer. + * cfglayout.c (fixup_fallthru_exit_predecessor): Check that it is + not called before reload has completed. + Handle special case of first block having a fall-through exit edge. + (cfg_layout_finalize): Don't call it before reload or if we have + rtl epilogues. + (fixup_reorder_chain): A fall through to the exit block does not + require the block to come last. Add sanity checks. + * cfgrtl.c (rtl_split_edge): Add special handling of fall through + edges to the exit block. + * function.c (cfglayout.h): #include. + (thread_prologue_and_epilogue_insns): If we have neither return nor + epilogue, but a fall through to the exit block from mid-function, + force a non-fall-through exit. + * Makefile.in (function.o): Depend on CFGLAYOUT_H. + 2004-06-14 Alan Modra * config/rs6000/rs6000.h (ASM_CPU_SPEC): Handle -mpowerpc64 and -mcpu diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6b25b343321..0e94fd630f9 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1759,7 +1759,8 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_ flags.h function.h $(EXPR_H) hard-reg-set.h $(REGS_H) \ output.h c-pragma.h toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \ $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h real.h -function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ +function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + $(TREE_H) $(CFGLAYOUT_H) \ flags.h function.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h \ insn-config.h $(RECOG_H) output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) \ $(TM_P_H) langhooks.h gt-function.h $(TARGET_H) basic-block.h diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 02ca28180ab..97f71efef4c 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -629,6 +629,7 @@ extern void find_sub_basic_blocks (basic_block); extern void find_many_sub_basic_blocks (sbitmap); extern void rtl_make_eh_edge (sbitmap *, basic_block, rtx); extern bool can_fallthru (basic_block, basic_block); +extern bool could_fall_through (basic_block, basic_block); extern void flow_nodes_print (const char *, const sbitmap, FILE *); extern void flow_edge_list_print (const char *, const edge *, int, FILE *); extern void alloc_aux_for_block (basic_block, int); diff --git a/gcc/cfganal.c b/gcc/cfganal.c index 1a7d280513f..c8675dca6e2 100644 --- a/gcc/cfganal.c +++ b/gcc/cfganal.c @@ -103,17 +103,42 @@ bool can_fallthru (basic_block src, basic_block target) { rtx insn = BB_END (src); - rtx insn2 = target == EXIT_BLOCK_PTR ? NULL : BB_HEAD (target); + rtx insn2; + edge e; + if (target == EXIT_BLOCK_PTR) + return true; if (src->next_bb != target) return 0; + for (e = src->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR + && e->flags & EDGE_FALLTHRU) + return 0; + insn2 = BB_HEAD (target); if (insn2 && !active_insn_p (insn2)) insn2 = next_active_insn (insn2); /* ??? Later we may add code to move jump tables offline. */ return next_active_insn (insn) == insn2; } + +/* Return nonzero if we could reach target from src by falling through, + if the target was made adjacent. If we already have a fall-through + edge to the exit block, we can't do that. */ +bool +could_fall_through (basic_block src, basic_block target) +{ + edge e; + + if (target == EXIT_BLOCK_PTR) + return true; + for (e = src->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR + && e->flags & EDGE_FALLTHRU) + return 0; + return true; +} /* Mark the back edges in DFS traversal. Return nonzero if a loop (natural or otherwise) is present. diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index 0cef94eafd3..8402dad578f 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -267,6 +267,7 @@ make_edges (rtx label_value_list, basic_block min, basic_block max, int update_p rtx insn, x; enum rtx_code code; int force_fallthru = 0; + edge e; if (GET_CODE (BB_HEAD (bb)) == CODE_LABEL && LABEL_ALT_ENTRY_P (BB_HEAD (bb))) @@ -389,6 +390,12 @@ make_edges (rtx label_value_list, basic_block min, basic_block max, int update_p /* Find out if we can drop through to the next block. */ insn = NEXT_INSN (insn); + for (e = bb->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR && e->flags & EDGE_FALLTHRU) + { + insn = 0; + break; + } while (insn && GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK) diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 899aa1a5665..66742686e16 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -714,6 +714,10 @@ fixup_reorder_chain (void) && invert_jump (bb_end_insn, label_for_bb (e_fall->dest), 0)) { +#ifdef ENABLE_CHECKING + if (!could_fall_through (e_taken->src, e_taken->dest)) + abort (); +#endif e_fall->flags &= ~EDGE_FALLTHRU; e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); @@ -731,6 +735,10 @@ fixup_reorder_chain (void) else if (invert_jump (bb_end_insn, label_for_bb (e_fall->dest), 0)) { +#ifdef ENABLE_CHECKING + if (!could_fall_through (e_taken->src, e_taken->dest)) + abort (); +#endif e_fall->flags &= ~EDGE_FALLTHRU; e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); @@ -770,7 +778,7 @@ fixup_reorder_chain (void) continue; /* A fallthru to exit block. */ - if (!bb->rbi->next && e_fall->dest == EXIT_BLOCK_PTR) + if (e_fall->dest == EXIT_BLOCK_PTR) continue; } @@ -910,14 +918,20 @@ verify_insn_chain (void) abort (); } -/* The block falling through to exit must be the last one in the - reordered chain. Ensure that this condition is met. */ +/* If we have assembler epilogues, the block falling through to exit must + be the last one in the reordered chain when we reach final. Ensure + that this condition is met. */ static void fixup_fallthru_exit_predecessor (void) { edge e; basic_block bb = NULL; + /* This transformation is not valid before reload, because we might separate + a call from the instruction that copies the return value. */ + if (! reload_completed) + abort (); + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) if (e->flags & EDGE_FALLTHRU) bb = e->src; @@ -926,6 +940,18 @@ fixup_fallthru_exit_predecessor (void) { basic_block c = ENTRY_BLOCK_PTR->next_bb; + /* If the very first block is the one with the fall-through exit + edge, we have to split that block. */ + if (c == bb) + { + bb = split_block (bb, NULL)->dest; + initialize_bb_rbi (bb); + bb->rbi->next = c->rbi->next; + c->rbi->next = bb; + bb->rbi->footer = c->rbi->footer; + c->rbi->footer = NULL; + } + while (c->rbi->next != bb) c = c->rbi->next; @@ -1176,7 +1202,12 @@ cfg_layout_finalize (void) verify_flow_info (); #endif rtl_register_cfg_hooks (); - fixup_fallthru_exit_predecessor (); + if (reload_completed +#ifdef HAVE_epilogue + && !HAVE_epilogue +#endif + ) + fixup_fallthru_exit_predecessor (); fixup_reorder_chain (); #ifdef ENABLE_CHECKING diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index cdfde6fba05..6e22d80ac84 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -1336,7 +1336,19 @@ rtl_split_edge (edge edge_in) else before = NULL_RTX; - bb = create_basic_block (before, NULL, edge_in->dest->prev_bb); + /* If this is a fall through edge to the exit block, the blocks might be + not adjacent, and the right place is the after the source. */ + if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR) + { + before = NEXT_INSN (BB_END (edge_in->src)); + if (before + && GET_CODE (before) == NOTE + && NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END) + before = NEXT_INSN (before); + bb = create_basic_block (before, NULL, edge_in->src); + } + else + bb = create_basic_block (before, NULL, edge_in->dest->prev_bb); /* ??? This info is likely going to be out of date very soon. */ if (edge_in->dest->global_live_at_start) diff --git a/gcc/function.c b/gcc/function.c index 00c56e322af..b59da9a4160 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -63,6 +63,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "integrate.h" #include "langhooks.h" #include "target.h" +#include "cfglayout.h" #ifndef LOCAL_ALIGNMENT #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT @@ -7558,20 +7559,20 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) } } #endif + /* Find the edge that falls through to EXIT. Other edges may exist + due to RETURN instructions, but those don't need epilogues. + There really shouldn't be a mixture -- either all should have + been converted or none, however... */ + + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + if (e->flags & EDGE_FALLTHRU) + break; + if (e == NULL) + goto epilogue_done; + #ifdef HAVE_epilogue if (HAVE_epilogue) { - /* Find the edge that falls through to EXIT. Other edges may exist - due to RETURN instructions, but those don't need epilogues. - There really shouldn't be a mixture -- either all should have - been converted or none, however... */ - - for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) - if (e->flags & EDGE_FALLTHRU) - break; - if (e == NULL) - goto epilogue_done; - start_sequence (); epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG); @@ -7597,7 +7598,26 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED) insert_insn_on_edge (seq, e); inserted = 1; } + else #endif + { + basic_block cur_bb; + + if (! next_active_insn (BB_END (e->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 (); + FOR_EACH_BB (cur_bb) + if (cur_bb->index >= 0 && cur_bb->next_bb->index >= 0) + cur_bb->rbi->next = cur_bb->next_bb; + cfg_layout_finalize (); + } epilogue_done: if (inserted) -- 2.30.2