diff options
author | Richard Henderson <rth@cygnus.com> | 2000-01-28 14:22:50 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2000-01-28 14:22:50 -0800 |
commit | 19d3c25c9a4da9526a2012b47d14bc731fd0422e (patch) | |
tree | 838b5c749cb462341ad1b64dc6cc0bd1daa6820f | |
parent | 47e6ea667d23d2fd20ad3664e39654cc8a44502f (diff) | |
download | gcc-19d3c25c9a4da9526a2012b47d14bc731fd0422e.zip gcc-19d3c25c9a4da9526a2012b47d14bc731fd0422e.tar.gz gcc-19d3c25c9a4da9526a2012b47d14bc731fd0422e.tar.bz2 |
flow.c (find_basic_blocks): Remove do_cleanup argument.
* flow.c (find_basic_blocks): Remove do_cleanup argument.
Break out that code ...
(cleanup_cfg): ... here.
(commit_one_edge_insertion): Detect a return instruction being
emitted to an edge. Emit a barrier following; clear fallthru.
(commit_edge_insertions): Verify CFG consistency.
* function.c (expand_function_start): Kill unused variable.
(expand_function_end): Likewise.
(thread_prologue_and_epilogue_insns): Use insert_insn_on_edge
to insert the epilogue.
* gcse.c (gcse_main): Adjust for find_basic_blocks change.
(delete_null_pointer_checks): Likewise.
* output.h: Likewise.
* reg-stack.c (reg_to_stack): Likewise.
* toplev.c (rest_of_compilation): Likewise. Run
thread_prologue_and_epilogue_insns after rebuilding the CFG.
From-SVN: r31676
-rw-r--r-- | gcc/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/flow.c | 77 | ||||
-rw-r--r-- | gcc/function.c | 148 | ||||
-rw-r--r-- | gcc/gcse.c | 6 | ||||
-rw-r--r-- | gcc/output.h | 3 | ||||
-rw-r--r-- | gcc/reg-stack.c | 2 | ||||
-rw-r--r-- | gcc/toplev.c | 23 |
7 files changed, 125 insertions, 154 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c1e8282..8f43f07 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,25 @@ 2000-01-28 Richard Henderson <rth@cygnus.com> + * flow.c (find_basic_blocks): Remove do_cleanup argument. + Break out that code ... + (cleanup_cfg): ... here. + (commit_one_edge_insertion): Detect a return instruction being + emitted to an edge. Emit a barrier following; clear fallthru. + (commit_edge_insertions): Verify CFG consistency. + * function.c (expand_function_start): Kill unused variable. + (expand_function_end): Likewise. + (thread_prologue_and_epilogue_insns): Use insert_insn_on_edge + to insert the epilogue. + + * gcse.c (gcse_main): Adjust for find_basic_blocks change. + (delete_null_pointer_checks): Likewise. + * output.h: Likewise. + * reg-stack.c (reg_to_stack): Likewise. + * toplev.c (rest_of_compilation): Likewise. Run + thread_prologue_and_epilogue_insns after rebuilding the CFG. + +2000-01-28 Richard Henderson <rth@cygnus.com> + * Makefile.in (flow.o): Revert 24 Jan change. * flow.c (mark_regs_live_at_end): Likewise. Force BLKmode FUNCTION_VALUE result to DECL_RESULT's mode. @@ -372,11 +372,10 @@ int flow_loop_outside_edge_p PARAMS ((const struct loop *, edge)); numbers in use. */ void -find_basic_blocks (f, nregs, file, do_cleanup) +find_basic_blocks (f, nregs, file) rtx f; int nregs ATTRIBUTE_UNUSED; FILE *file ATTRIBUTE_UNUSED; - int do_cleanup; { int max_uid; @@ -425,23 +424,8 @@ find_basic_blocks (f, nregs, file, do_cleanup) compute_bb_for_insn (max_uid); /* Discover the edges of our cfg. */ - record_active_eh_regions (f); make_edges (label_value_list); - - /* Delete unreachable blocks, then merge blocks when possible. */ - - if (do_cleanup) - { - delete_unreachable_blocks (); - move_stray_eh_region_notes (); - record_active_eh_regions (f); - if (optimize) - try_merge_blocks (); - } - - /* Mark critical edges. */ - mark_critical_edges (); /* Kill the data we won't maintain. */ @@ -740,6 +724,19 @@ find_basic_blocks_1 (f) return label_value_list; } +/* Tidy the CFG by deleting unreachable code and whatnot. */ + +void +cleanup_cfg (f) + rtx f; +{ + delete_unreachable_blocks (); + move_stray_eh_region_notes (); + record_active_eh_regions (f); + try_merge_blocks (); + mark_critical_edges (); +} + /* Create a new basic block consisting of the instructions between HEAD and END inclusive. Reuses the note and basic block struct in BB_NOTE, if any. */ @@ -1552,9 +1549,13 @@ static void commit_one_edge_insertion (e) edge e; { - rtx before = NULL_RTX, after = NULL_RTX, tmp; + rtx before = NULL_RTX, after = NULL_RTX, insns, tmp; basic_block bb; + /* Pull the insns off the edge now since the edge might go away. */ + insns = e->insns; + e->insns = NULL_RTX; + /* Figure out where to put these things. If the destination has one predecessor, insert there. Except for the exit block. */ if (e->dest->pred->pred_next == NULL @@ -1611,28 +1612,50 @@ commit_one_edge_insertion (e) } /* Now that we've found the spot, do the insertion. */ - tmp = e->insns; - e->insns = NULL_RTX; /* Set the new block number for these insns, if structure is allocated. */ if (basic_block_for_insn) { rtx i; - for (i = tmp; i != NULL_RTX; i = NEXT_INSN (i)) + for (i = insns; i != NULL_RTX; i = NEXT_INSN (i)) set_block_for_insn (i, bb); } if (before) { - emit_insns_before (tmp, before); + emit_insns_before (insns, before); if (before == bb->head) - bb->head = tmp; + bb->head = insns; } else { - tmp = emit_insns_after (tmp, after); + rtx last = emit_insns_after (insns, after); if (after == bb->end) - bb->end = tmp; + { + bb->end = last; + + if (GET_CODE (last) == JUMP_INSN) + { + if (returnjump_p (last)) + { + /* ??? Remove all outgoing edges from BB and add one + for EXIT. This is not currently a problem because + this only happens for the (single) epilogue, which + already has a fallthru edge to EXIT. */ + + e = bb->succ; + if (e->dest != EXIT_BLOCK_PTR + || e->succ_next != NULL + || (e->flags & EDGE_FALLTHRU) == 0) + abort (); + e->flags &= ~EDGE_FALLTHRU; + + emit_barrier_after (last); + } + else + abort (); + } + } } } @@ -1644,6 +1667,10 @@ commit_edge_insertions () int i; basic_block bb; +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif + i = -1; bb = ENTRY_BLOCK_PTR; while (1) diff --git a/gcc/function.c b/gcc/function.c index 8339208..960fd1c 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -5867,7 +5867,6 @@ expand_function_start (subr, parms_have_cleanups) tree subr; int parms_have_cleanups; { - register int i; tree tem; rtx last_ptr = NULL_RTX; @@ -6171,7 +6170,6 @@ expand_function_end (filename, line, end_bindings) int line; int end_bindings; { - register int i; tree link; #ifdef TRAMPOLINE_TEMPLATE @@ -6546,12 +6544,12 @@ thread_prologue_and_epilogue_insns (f) rtx f ATTRIBUTE_UNUSED; { int insertted = 0; + edge e; + rtx seq; #ifdef HAVE_prologue if (HAVE_prologue) { - rtx seq; - start_sequence (); seq = gen_prologue(); emit_insn (seq); @@ -6581,129 +6579,47 @@ thread_prologue_and_epilogue_insns (f) } #endif + /* If the exit block has no non-fake predecessors, we don't need + an epilogue. */ + for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) + if ((e->flags & EDGE_FAKE) == 0) + break; + if (e == NULL) + goto epilogue_done; + #ifdef HAVE_epilogue if (HAVE_epilogue) { - edge e; - basic_block bb = 0; - rtx tail = get_last_insn (); - - /* ??? This is gastly. If function returns were not done via uses, - but via mark_regs_live_at_end, we could use insert_insn_on_edge - and all of this uglyness would go away. */ - - switch (optimize) - { - default: - /* If the exit block has no non-fake predecessors, we don't - need an epilogue. Furthermore, only pay attention to the - fallthru predecessors; if (conditional) return insns were - generated, by definition we do not need to emit epilogue - insns. */ - - for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) - if ((e->flags & EDGE_FAKE) == 0 - && (e->flags & EDGE_FALLTHRU) != 0) - break; - if (e == NULL) - break; - - /* We can't handle multiple epilogues -- if one is needed, - we won't be able to place it multiple times. - - ??? Fix epilogue expanders to not assume they are the - last thing done compiling the function. Either that - or copy_rtx each insn. - - ??? Blah, it's not a simple expression to assert that - we've exactly one fallthru exit edge. */ + /* 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... */ - bb = e->src; - tail = bb->end; - - /* ??? If the last insn of the basic block is a jump, then we - are creating a new basic block. Wimp out and leave these - insns outside any block. */ - if (GET_CODE (tail) == JUMP_INSN) - bb = 0; - - /* FALLTHRU */ - case 0: - { - rtx prev, seq, first_use; - - /* Move the USE insns at the end of a function onto a list. */ - prev = tail; - if (GET_CODE (prev) == BARRIER - || GET_CODE (prev) == NOTE) - prev = prev_nonnote_insn (prev); - - first_use = 0; - if (prev - && GET_CODE (prev) == INSN - && GET_CODE (PATTERN (prev)) == USE) - { - /* If the end of the block is the use, grab hold of something - else so that we emit barriers etc in the right place. */ - if (prev == tail) - { - do - tail = PREV_INSN (tail); - while (GET_CODE (tail) == INSN - && GET_CODE (PATTERN (tail)) == USE); - } - - do - { - rtx use = prev; - prev = prev_nonnote_insn (prev); - - remove_insn (use); - if (first_use) - { - NEXT_INSN (use) = first_use; - PREV_INSN (first_use) = use; - } - else - NEXT_INSN (use) = NULL_RTX; - first_use = use; - } - while (prev - && GET_CODE (prev) == INSN - && GET_CODE (PATTERN (prev)) == USE); - } - - /* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the - epilogue insns, the USE insns at the end of a function, - the jump insn that returns, and then a BARRIER. */ + for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) + if (e->flags & EDGE_FALLTHRU) + break; + if (e == NULL) + goto epilogue_done; - if (GET_CODE (tail) != BARRIER) - { - prev = next_nonnote_insn (tail); - if (!prev || GET_CODE (prev) != BARRIER) - emit_barrier_after (tail); - } + start_sequence (); + emit_note (NULL, NOTE_INSN_EPILOGUE_BEG); - seq = gen_epilogue (); - prev = tail; - tail = emit_jump_insn_after (seq, tail); + seq = gen_epilogue (); + emit_jump_insn (seq); - /* Insert the USE insns immediately before the return insn, which - must be the last instruction emitted in the sequence. */ - if (first_use) - emit_insns_before (first_use, tail); - emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev); + /* Retain a map of the epilogue insns. */ + if (GET_CODE (seq) != SEQUENCE) + seq = get_insns (); + epilogue = record_insns (seq); - /* Update the tail of the basic block. */ - if (bb) - bb->end = tail; + seq = gen_sequence (); + end_sequence(); - /* Retain a map of the epilogue insns. */ - epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail); - } - } + insert_insn_on_edge (seq, e); + insertted = 1; } #endif +epilogue_done: if (insertted) commit_edge_insertions (); @@ -673,7 +673,8 @@ gcse_main (f, file) /* Identify the basic block information for this function, including successors and predecessors. */ max_gcse_regno = max_reg_num (); - find_basic_blocks (f, max_gcse_regno, file, 1); + find_basic_blocks (f, max_gcse_regno, file); + cleanup_cfg (f); if (file) dump_flow_info (file); @@ -5201,7 +5202,8 @@ delete_null_pointer_checks (f) struct null_pointer_info npi; /* First break the program into basic blocks. */ - find_basic_blocks (f, max_reg_num (), NULL, 1); + find_basic_blocks (f, max_reg_num (), NULL); + cleanup_cfg (f); /* If we have only a single block, then there's nothing to do. */ if (n_basic_blocks <= 1) diff --git a/gcc/output.h b/gcc/output.h index dbc373d..ecd3253 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -131,7 +131,8 @@ extern void allocate_for_life_analysis PARAMS ((void)); extern int regno_uninitialized PARAMS ((int)); extern int regno_clobbered_at_setjmp PARAMS ((int)); extern void dump_flow_info PARAMS ((FILE *)); -extern void find_basic_blocks PARAMS ((rtx, int, FILE *, int)); +extern void find_basic_blocks PARAMS ((rtx, int, FILE *)); +extern void cleanup_cfg PARAMS ((rtx)); extern void calculate_loop_depth PARAMS ((FILE *)); extern void free_basic_block_vars PARAMS ((int)); extern void set_block_num PARAMS ((rtx, int)); diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 2edd579..ab27407 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -430,7 +430,7 @@ reg_to_stack (first, file) /* Ok, floating point instructions exist. If not optimizing, build the CFG and run life analysis. */ - find_basic_blocks (first, max_reg_num (), file, 0); + find_basic_blocks (first, max_reg_num (), file); count_or_remove_death_notes (NULL, 1); life_analysis (first, max_reg_num (), file, 0); diff --git a/gcc/toplev.c b/gcc/toplev.c index 189c3e7..136d966 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3216,7 +3216,8 @@ rest_of_compilation (decl) TIMEVAR (flow_time, { - find_basic_blocks (insns, max_reg_num (), rtl_dump_file, 1); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + cleanup_cfg (insns); if (optimize) calculate_loop_depth (rtl_dump_file); life_analysis (insns, max_reg_num (), rtl_dump_file, 1); @@ -3384,13 +3385,6 @@ rest_of_compilation (decl) if (rebuild_label_notes_after_reload) TIMEVAR (jump_time, rebuild_jump_labels (insns)); - /* On some machines, the prologue and epilogue code, or parts thereof, - can be represented as RTL. Doing so lets us schedule insns between - it and the rest of the code and also allows delayed branch - scheduling to operate in the epilogue. */ - - thread_prologue_and_epilogue_insns (insns); - /* If optimizing and we are performing instruction scheduling after reload, then go ahead and split insns now since we are about to recompute flow information anyway. @@ -3412,12 +3406,23 @@ rest_of_compilation (decl) if (flow2_dump) open_dump_file (".14.flow2", decl_printable_name (decl, 2)); + TIMEVAR (flow2_time, + { + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + }); + + /* On some machines, the prologue and epilogue code, or parts thereof, + can be represented as RTL. Doing so lets us schedule insns between + it and the rest of the code and also allows delayed branch + scheduling to operate in the epilogue. */ + thread_prologue_and_epilogue_insns (insns); + if (optimize) { TIMEVAR (flow2_time, { - find_basic_blocks (insns, max_reg_num (), rtl_dump_file, 1); + cleanup_cfg (insns); life_analysis (insns, max_reg_num (), rtl_dump_file, 1); }); |