diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 834468e6fb7..04b62dbbf94 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,45 @@ Thu Oct 29 23:55:43 1998 Bernd Schmidt + * flow.c (XNMALLOC): New macro. + (flow_int_list_blocks, basic_block_succ, basic_block_pred): New + static variables. + (add_edge, add_edge_to_label): New static functions. + (free_bb_memory): New function. + (flow_delete_insn): Delete function. + (basic_block_drops_in): Delete variable. + (find_basic_blocks): Allocate and initialize basic_block_head, + basic_block_succ. Don't allocate basic_block_drops_in. + Call free_bb_memory at the beginning. + (find_basic_blocks_1): Don't do multiple passes. + Delete code to compute basic_block_drops_in. + After calling make_edges, mark blocks reached by current block live. + Update test for unreachable live blocks. + (mark_label_ref): Delete args X, CHECKDUP. Add PRED arg. All callers + changed. + Simplify to call add_edge_to_label when a LABEL_REF is found. + (make_edges): Simplify to call add_edge_to_label instead of + mark_label_ref most of the time. + Compute here whether control drops into the next block. + (delete_unreachable_blocks): Return void. All callers changed. + Delete unreachable blocks in reverse order. + After deleting all unreachable blocks, renumber the remaining ones + and update n_basic_blocks. + (delete_block): Speed up deletion a bit. + Don't set basic_block_drops_in for deleted blocks. + (free_basic_block_vars): Don't free basic_block_drops_in. + (life_analysis_1): Update to use new edge representation. + (dump_flow_info): Delete code to print basic block info; call + dump_bb_data instead. + (compute_preds_succs): Delete code to recompute basic_block_drops_in + and uid_block_number. + Simply copy the previously computed cfg. + (dump_bb_data): New arg LIVE_INFO. All callers changed. + Print register lifetime information if LIVE_INFO is nonzero. + * basic-block.h (dump_bb_data): Adjust prototype. + * gcse.c (gcse_main): Update call to dump_bb_data. + * rtl.h (free_bb_memory): Declare. + * toplev.c (rest_of_compilation): Call free_bb_memory. + * reload1.c (struct elim_table): Delete MAX_OFFSET member. (update_eliminable_offsets): Don't compute it. (set_initial_elim_offsets): Don't initialize it. diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 5f146286222..a946405ee5e 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -190,7 +190,8 @@ extern int *uid_block_number; extern void compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *, int *, int *)); -extern void dump_bb_data PROTO ((FILE *, int_list_ptr *, int_list_ptr *)); +extern void dump_bb_data PROTO ((FILE *, int_list_ptr *, int_list_ptr *, + int)); extern void free_bb_mem PROTO ((void)); extern void free_basic_block_vars PROTO ((int)); diff --git a/gcc/flow.c b/gcc/flow.c index 51af041506e..22f7f1e4fa6 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -128,6 +128,8 @@ Boston, MA 02111-1307, USA. */ #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free +#define XNMALLOC(TYPE, COUNT) ((TYPE *) xmalloc ((COUNT) * sizeof (TYPE))) + /* The contents of the current function definition are allocated in this obstack, and all are freed at the end of the function. For top-level functions, this is temporary_obstack. @@ -218,10 +220,14 @@ regset regs_live_at_setjmp; are another pair, etc. */ rtx regs_may_share; -/* Element N is nonzero if control can drop into basic block N - from the preceding basic block. Freed after life_analysis. */ +/* Pointer to head of predecessor/successor block list. */ +static int_list_block *flow_int_list_blocks; -static char *basic_block_drops_in; +/* Element N is the list of successors of basic block N. */ +static int_list_ptr *basic_block_succ; + +/* Element N is the list of predecessors of basic block N. */ +static int_list_ptr *basic_block_pred; /* Element N is depth within loops of the last insn in basic block number N. Freed after life_analysis. */ @@ -249,14 +255,15 @@ static HARD_REG_SET elim_reg_set; /* Forward declarations */ static void find_basic_blocks_1 PROTO((rtx, rtx)); +static void add_edge PROTO((int, int)); +static void add_edge_to_label PROTO((int, rtx)); static void make_edges PROTO((int)); -static void mark_label_ref PROTO((rtx, rtx, int)); -static int delete_unreachable_blocks PROTO((void)); +static void mark_label_ref PROTO((int, rtx)); +static void delete_unreachable_blocks PROTO((void)); static int delete_block PROTO((int)); static void life_analysis_1 PROTO((rtx, int)); static void propagate_block PROTO((regset, rtx, rtx, int, regset, int)); -static rtx flow_delete_insn PROTO((rtx)); static int set_noop_p PROTO((rtx)); static int noop_move_p PROTO((rtx)); static void record_volatile_insns PROTO((rtx)); @@ -304,6 +311,10 @@ find_basic_blocks (f, nregs, file) rtx nonlocal_label_list = nonlocal_label_rtx_list (); int in_libcall_block = 0; + /* Avoid leaking memory if this is called multiple times per compiled + function. */ + free_bb_memory (); + /* Count the basic blocks. Also find maximum insn uid value used. */ { @@ -382,14 +393,17 @@ find_basic_blocks (f, nregs, file) /* Allocate some tables that last till end of compiling this function and some needed only in find_basic_blocks and life_analysis. */ - basic_block_head = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx)); - basic_block_end = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx)); - basic_block_drops_in = (char *) xmalloc (n_basic_blocks); + basic_block_head = XNMALLOC (rtx, n_basic_blocks); + basic_block_end = XNMALLOC (rtx, n_basic_blocks); + basic_block_succ = XNMALLOC (int_list_ptr, n_basic_blocks); + basic_block_pred = XNMALLOC (int_list_ptr, n_basic_blocks); + bzero ((char *)basic_block_succ, n_basic_blocks * sizeof (int_list_ptr)); + bzero ((char *)basic_block_pred, n_basic_blocks * sizeof (int_list_ptr)); + basic_block_computed_jump_target = (char *) oballoc (n_basic_blocks); - basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short)); - uid_block_number - = (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int)); - uid_volatile = (char *) xmalloc (max_uid_for_flow + 1); + basic_block_loop_depth = XNMALLOC (short, n_basic_blocks); + uid_block_number = XNMALLOC (int, (max_uid_for_flow + 1)); + uid_volatile = XNMALLOC (char, (max_uid_for_flow + 1)); bzero (uid_volatile, max_uid_for_flow + 1); find_basic_blocks_1 (f, nonlocal_label_list); @@ -435,15 +449,13 @@ find_basic_blocks_1 (f, nonlocal_labels) register char *block_marked = (char *) alloca (n_basic_blocks); rtx note, eh_note; enum rtx_code prev_code, code; - int depth, pass; + int depth; int in_libcall_block = 0; int call_had_abnormal_edge = 0; - pass = 1; active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int)); nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int)); nonlocal_label_list = nonlocal_labels; - restart: label_value_list = 0; block_live_static = block_live; @@ -564,23 +576,8 @@ find_basic_blocks_1 (f, nonlocal_labels) in_libcall_block = 0; } - /* During the second pass, `n_basic_blocks' is only an upper bound. - Only perform the sanity check for the first pass, and on the second - pass ensure `n_basic_blocks' is set to the correct value. */ - if (pass == 1 && i + 1 != n_basic_blocks) + if (i + 1 != n_basic_blocks) abort (); - n_basic_blocks = i + 1; - - /* Record which basic blocks control can drop in to. */ - - for (i = 0; i < n_basic_blocks; i++) - { - for (insn = PREV_INSN (basic_block_head[i]); - insn && GET_CODE (insn) == NOTE; insn = PREV_INSN (insn)) - ; - - basic_block_drops_in[i] = insn && GET_CODE (insn) != BARRIER; - } /* Now find which basic blocks can actually be reached and put all jump insns' LABEL_REFS onto the ref-chains @@ -589,7 +586,6 @@ find_basic_blocks_1 (f, nonlocal_labels) if (n_basic_blocks > 0) { int something_marked = 1; - int deleted = 0; /* Pass over all blocks, marking each block that is reachable and has not yet been marked. @@ -603,10 +599,15 @@ find_basic_blocks_1 (f, nonlocal_labels) for (i = 0; i < n_basic_blocks; i++) if (block_live[i] && !block_marked[i]) { + int_list_ptr p; + block_marked[i] = 1; something_marked = 1; make_edges (i); + + for (p = basic_block_succ[i]; p; p = p->next) + block_live[INT_LIST_VAL (p)] = 1; } } @@ -618,40 +619,11 @@ find_basic_blocks_1 (f, nonlocal_labels) later during the compile or at runtime. It's easier to debug the problem here than later! */ for (i = 1; i < n_basic_blocks; i++) - if (block_live[i] && ! basic_block_drops_in[i] - && GET_CODE (basic_block_head[i]) == CODE_LABEL - && LABEL_REFS (basic_block_head[i]) == basic_block_head[i]) + if (block_live[i] && basic_block_pred[i] == 0) abort (); if (! reload_completed) - deleted = delete_unreachable_blocks (); - - /* There are pathological cases where one function calling hundreds of - nested inline functions can generate lots and lots of unreachable - blocks that jump can't delete. Since we don't use sparse matrices - a lot of memory will be needed to compile such functions. - Implementing sparse matrices is a fair bit of work and it is not - clear that they win more than they lose (we don't want to - unnecessarily slow down compilation of normal code). By making - another pass for the pathological case, we can greatly speed up - their compilation without hurting normal code. This works because - all the insns in the unreachable blocks have either been deleted or - turned into notes. - Note that we're talking about reducing memory usage by 10's of - megabytes and reducing compilation time by several minutes. */ - /* ??? The choice of when to make another pass is a bit arbitrary, - and was derived from empirical data. */ - if (pass == 1 - && deleted > 200) - { - pass++; - n_basic_blocks -= deleted; - /* `n_basic_blocks' may not be correct at this point: two previously - separate blocks may now be merged. That's ok though as we - recalculate it during the second pass. It certainly can't be - any larger than the current value. */ - goto restart; - } + delete_unreachable_blocks (); } } @@ -671,10 +643,74 @@ set_block_num (insn, bb) } BLOCK_NUM (insn) = bb; } - /* Subroutines of find_basic_blocks. */ +void +free_bb_memory () +{ + free_int_list (&flow_int_list_blocks); +} + +/* Make an edge in the cfg from block PRED to block SUCC. */ +static void +add_edge (pred, succ) + int pred, succ; +{ + add_int_list_node (&flow_int_list_blocks, basic_block_pred + succ, pred); + add_int_list_node (&flow_int_list_blocks, basic_block_succ + pred, succ); +} + +/* Make an edge in the cfg from block PRED to the block starting with + label LABEL. */ +static void +add_edge_to_label (pred, label) + int pred; + rtx label; +{ + /* If the label was never emitted, this insn is junk, + but avoid a crash trying to refer to BLOCK_NUM (label). + This can happen as a result of a syntax error + and a diagnostic has already been printed. */ + if (INSN_UID (label) == 0) + return; + + add_edge (pred, BLOCK_NUM (label)); +} + +/* Check expression X for label references. If one is found, add an edge + from basic block PRED to the block beginning with the label. */ + +static void +mark_label_ref (pred, x) + int pred; + rtx x; +{ + register RTX_CODE code; + register int i; + register char *fmt; + + code = GET_CODE (x); + if (code == LABEL_REF) + { + add_edge_to_label (pred, XEXP (x, 0)); + return; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + mark_label_ref (pred, XEXP (x, i)); + if (fmt[i] == 'E') + { + register int j; + for (j = 0; j < XVECLEN (x, i); j++) + mark_label_ref (pred, XVECEXP (x, i, j)); + } + } +} + /* For basic block I, make edges and mark live all blocks which are reachable from it. */ static void @@ -683,18 +719,26 @@ make_edges (i) { rtx insn, x; - if (i + 1 < n_basic_blocks && basic_block_drops_in[i + 1]) - block_live_static[i + 1] = 1; + /* See if control drops into the next block. */ + if (i + 1 < n_basic_blocks) + { + for (insn = PREV_INSN (basic_block_head[i + 1]); + insn && GET_CODE (insn) == NOTE; insn = PREV_INSN (insn)) + ; + + if (insn && GET_CODE (insn) != BARRIER) + add_edge (i, i + 1); + } + insn = basic_block_end[i]; if (GET_CODE (insn) == JUMP_INSN) - mark_label_ref (PATTERN (insn), insn, 0); + mark_label_ref (i, PATTERN (insn)); /* If we have any forced labels, mark them as potentially reachable from this block. */ for (x = forced_labels; x; x = XEXP (x, 1)) if (! LABEL_REF_NONLOCAL_P (x)) - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, XEXP (x, 0)), - insn, 0); + add_edge_to_label (i, XEXP (x, 0)); /* Now scan the insns for this block, we may need to make edges for some of them to various non-obvious locations (exception handlers, nonlocal @@ -731,12 +775,7 @@ make_edges (i) { if (REG_NOTE_KIND (note) == REG_LABEL && XEXP (note, 0) != eh_return_stub_label) - { - x = XEXP (note, 0); - block_live_static[BLOCK_NUM (x)] = 1; - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, x), - insn, 0); - } + add_edge_to_label (i, XEXP (note, 0)); } /* If this is a computed jump, then mark it as reaching everything @@ -748,16 +787,14 @@ make_edges (i) { int b = BLOCK_NUM (XEXP (x, 0)); basic_block_computed_jump_target[b] = 1; - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, XEXP (x, 0)), - insn, 0); + add_edge (i, b); } for (x = forced_labels; x; x = XEXP (x, 1)) { int b = BLOCK_NUM (XEXP (x, 0)); basic_block_computed_jump_target[b] = 1; - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, XEXP (x, 0)), - insn, 0); + add_edge (i, b); } } @@ -775,21 +812,17 @@ make_edges (i) int region; handler_info *ptr; region = active_eh_region[INSN_UID (insn)]; - for ( ; region; - region = nested_eh_region[region]) + for ( ; region; region = nested_eh_region[region]) { ptr = get_first_handler (region); for ( ; ptr ; ptr = ptr->next) - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, - ptr->handler_label), - insn, 0); + add_edge_to_label (i, ptr->handler_label); } } if (! asynchronous_exceptions) { for (x = nonlocal_label_list; x; x = XEXP (x, 1)) - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, XEXP (x, 0)), - insn, 0); + add_edge_to_label (i, XEXP (x, 0)); } /* ??? This could be made smarter: in some cases it's possible to tell that certain calls will not do a nonlocal goto. @@ -807,101 +840,79 @@ make_edges (i) the eh_stub labels within it. So we have to make additional edges in the flow graph. */ if (i + 1 == n_basic_blocks && eh_return_stub_label != 0) - { - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, eh_return_stub_label), - basic_block_end[i], 0); - } -} - -/* Check expression X for label references; - if one is found, add INSN to the label's chain of references. - - CHECKDUP means check for and avoid creating duplicate references - from the same insn. Such duplicates do no serious harm but - can slow life analysis. CHECKDUP is set only when duplicates - are likely. */ - -static void -mark_label_ref (x, insn, checkdup) - rtx x, insn; - int checkdup; -{ - register RTX_CODE code; - register int i; - register char *fmt; - - /* We can be called with NULL when scanning label_value_list. */ - if (x == 0) - return; - - code = GET_CODE (x); - if (code == LABEL_REF) - { - register rtx label = XEXP (x, 0); - register rtx y; - if (GET_CODE (label) != CODE_LABEL) - abort (); - /* If the label was never emitted, this insn is junk, - but avoid a crash trying to refer to BLOCK_NUM (label). - This can happen as a result of a syntax error - and a diagnostic has already been printed. */ - if (INSN_UID (label) == 0) - return; - CONTAINING_INSN (x) = insn; - /* if CHECKDUP is set, check for duplicate ref from same insn - and don't insert. */ - if (checkdup) - for (y = LABEL_REFS (label); y != label; y = LABEL_NEXTREF (y)) - if (CONTAINING_INSN (y) == insn) - return; - LABEL_NEXTREF (x) = LABEL_REFS (label); - LABEL_REFS (label) = x; - block_live_static[BLOCK_NUM (label)] = 1; - return; - } - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - mark_label_ref (XEXP (x, i), insn, 0); - if (fmt[i] == 'E') - { - register int j; - for (j = 0; j < XVECLEN (x, i); j++) - mark_label_ref (XVECEXP (x, i, j), insn, 1); - } - } + add_edge_to_label (i, eh_return_stub_label); } /* Now delete the code for any basic blocks that can't be reached. They can occur because jump_optimize does not recognize unreachable loops - as unreachable. - Return the number of deleted blocks. */ -static int + as unreachable. */ +static void delete_unreachable_blocks () { int deleted_handler = 0; int deleted = 0; - int i; + int i, j; rtx insn; + int *block_num_map = XNMALLOC (int, n_basic_blocks); + + for (i = n_basic_blocks - 1; i >= 0; i--) + if (! block_live_static[i]) + deleted_handler |= delete_block (i); for (i = 0; i < n_basic_blocks; i++) - if (! block_live_static[i]) + if (block_live_static[i]) + block_num_map[i] = i - deleted; + else { deleted++; - - deleted_handler |= delete_block (i); + block_num_map[i] = -1; } + /* Eliminate all traces of the deleted blocks by renumbering the remaining + ones. */ + for (i = j = 0; i < n_basic_blocks; i++) + { + int_list_ptr p; + + if (block_num_map[i] == -1) + continue; + + for (p = basic_block_pred[i]; p; p = p->next) + INT_LIST_VAL (p) = block_num_map[INT_LIST_VAL (p)]; + for (p = basic_block_succ[i]; p; p = p->next) + INT_LIST_VAL (p) = block_num_map[INT_LIST_VAL (p)]; + + if (i != j) + { + rtx tmp = basic_block_head[i]; + for (;;) + { + BLOCK_NUM (tmp) = j; + if (tmp == basic_block_end[i]) + break; + tmp = NEXT_INSN (tmp); + } + basic_block_head[j] = basic_block_head[i]; + basic_block_end[j] = basic_block_end[i]; + basic_block_pred[j] = basic_block_pred[i]; + basic_block_succ[j] = basic_block_succ[i]; + basic_block_loop_depth[j] = basic_block_loop_depth[i]; + basic_block_computed_jump_target[j] + = basic_block_computed_jump_target[i]; + } + j++; + } + n_basic_blocks -= deleted; + free (block_num_map); + /* If we deleted an exception handler, we may have EH region begin/end blocks to remove as well. */ if (deleted_handler) for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == NOTE) { - if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) || - (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG || + NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END) { int num = CODE_LABEL_NUMBER (insn); /* A NULL handler indicates a region is no longer needed */ @@ -912,7 +923,6 @@ delete_unreachable_blocks () } } } - return deleted; } /* Delete the insns in a (non-live) block. We physically delete every @@ -932,83 +942,89 @@ delete_block (i) { int deleted_handler = 0; rtx insn; + rtx kept_head = 0; + rtx kept_tail = 0; - if (basic_block_head[i] != basic_block_end[i]) + /* If the head of this block is a CODE_LABEL, then it might + be the label for an exception handler which can't be + reached. + + We need to remove the label from the exception_handler_label + list and remove the associated NOTE_EH_REGION_BEG and + NOTE_EH_REGION_END notes. */ + insn = basic_block_head[i]; + if (GET_CODE (insn) == CODE_LABEL) { - /* It would be quicker to delete all of these with a single - unchaining, rather than one at a time, but we need to keep - the NOTE's. */ - insn = NEXT_INSN (basic_block_head[i]); - while (insn != basic_block_end[i]) + rtx x, *prev = &exception_handler_labels; + + for (x = exception_handler_labels; x; x = XEXP (x, 1)) { - if (GET_CODE (insn) == BARRIER) - abort (); - else if (GET_CODE (insn) != NOTE) - insn = flow_delete_insn (insn); - else - insn = NEXT_INSN (insn); + if (XEXP (x, 0) == insn) + { + /* Found a match, splice this label out of the + EH label list. */ + *prev = XEXP (x, 1); + XEXP (x, 1) = NULL_RTX; + XEXP (x, 0) = NULL_RTX; + + /* Remove the handler from all regions */ + remove_handler (insn); + deleted_handler = 1; + break; + } + prev = &XEXP (x, 1); } } + /* Walk the insns of the block, building a chain of NOTEs that need to be + kept. */ insn = basic_block_head[i]; - if (GET_CODE (insn) != NOTE) + for (;;) { - /* Turn the head into a deleted insn note. */ if (GET_CODE (insn) == BARRIER) abort (); - - /* If the head of this block is a CODE_LABEL, then it might - be the label for an exception handler which can't be - reached. - - We need to remove the label from the exception_handler_label - list and remove the associated NOTE_EH_REGION_BEG and - NOTE_EH_REGION_END notes. */ - if (GET_CODE (insn) == CODE_LABEL) + else if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED) { - rtx x, *prev = &exception_handler_labels; - - for (x = exception_handler_labels; x; x = XEXP (x, 1)) + if (kept_head == 0) + kept_head = kept_tail = insn; + else { - if (XEXP (x, 0) == insn) - { - /* Found a match, splice this label out of the - EH label list. */ - *prev = XEXP (x, 1); - XEXP (x, 1) = NULL_RTX; - XEXP (x, 0) = NULL_RTX; - - /* Remove the handler from all regions */ - remove_handler (insn); - deleted_handler = 1; - break; - } - prev = &XEXP (x, 1); + NEXT_INSN (kept_tail) = insn; + PREV_INSN (insn) = kept_tail; + kept_tail = insn; } } - - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; - } - insn = basic_block_end[i]; - if (GET_CODE (insn) != NOTE) - { - /* Turn the tail into a deleted insn note. */ - if (GET_CODE (insn) == BARRIER) - abort (); - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; + if (insn == basic_block_end[i]) + break; + insn = NEXT_INSN (insn); } + insn = NEXT_INSN (insn); + /* BARRIERs are between basic blocks, not part of one. Delete a BARRIER if the preceding jump is deleted. We cannot alter a BARRIER into a NOTE because it is too short; but we can really delete it because it is not part of a basic block. */ - if (NEXT_INSN (insn) != 0 - && GET_CODE (NEXT_INSN (insn)) == BARRIER) - delete_insn (NEXT_INSN (insn)); + if (insn != 0 && GET_CODE (insn) == BARRIER) + insn = NEXT_INSN (insn); + + /* Now unchain all of the block, and put the chain of kept notes in its + place. */ + if (kept_head == 0) + { + NEXT_INSN (PREV_INSN (basic_block_head[i])) = insn; + if (insn != 0) + PREV_INSN (insn) = PREV_INSN (basic_block_head[i]); + } + else + { + NEXT_INSN (PREV_INSN (basic_block_head[i])) = kept_head; + if (insn != 0) + PREV_INSN (insn) = kept_tail; + + PREV_INSN (kept_head) = PREV_INSN (basic_block_head[i]); + NEXT_INSN (kept_tail) = insn; + } /* Each time we delete some basic blocks, see if there is a jump around them that is @@ -1031,14 +1047,6 @@ delete_block (i) && INSN_UID (label) != 0 && BLOCK_NUM (label) == j) { - int k; - - /* The deleted blocks still show up in the cfg, - so we must set basic_block_drops_in for blocks - I to J inclusive to keep the cfg accurate. */ - for (k = i; k <= j; k++) - basic_block_drops_in[k] = 1; - PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; @@ -1052,20 +1060,6 @@ delete_block (i) return deleted_handler; } - -/* Delete INSN by patching it out. - Return the next insn. */ - -static rtx -flow_delete_insn (insn) - rtx insn; -{ - /* ??? For the moment we assume we don't have to watch for NULLs here - since the start/end of basic blocks aren't deleted like this. */ - NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn); - PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn); - return NEXT_INSN (insn); -} /* Perform data flow analysis. F is the first insn of the function and NREGS the number of register numbers @@ -1110,12 +1104,6 @@ void free_basic_block_vars (keep_head_end_p) int keep_head_end_p; { - if (basic_block_drops_in) - { - free (basic_block_drops_in); - /* Tell dump_flow_info this isn't available anymore. */ - basic_block_drops_in = 0; - } if (basic_block_loop_depth) { free (basic_block_loop_depth); @@ -1484,26 +1472,16 @@ life_analysis_1 (f, nregs) } { - register rtx jump, head; - - /* Update the basic_block_new_live_at_end's of the block - that falls through into this one (if any). */ - head = basic_block_head[i]; - if (basic_block_drops_in[i]) - IOR_REG_SET (basic_block_new_live_at_end[i-1], - basic_block_live_at_start[i]); + int_list_ptr p; /* Update the basic_block_new_live_at_end's of - all the blocks that jump to this one. */ - if (GET_CODE (head) == CODE_LABEL) - for (jump = LABEL_REFS (head); - jump != head; - jump = LABEL_NEXTREF (jump)) - { - register int from_block = BLOCK_NUM (CONTAINING_INSN (jump)); - IOR_REG_SET (basic_block_new_live_at_end[from_block], - basic_block_live_at_start[i]); - } + all the blocks that reach this one. */ + for (p = basic_block_pred[i]; p; p = p->next) + { + register int from_block = INT_LIST_VAL (p); + IOR_REG_SET (basic_block_new_live_at_end[from_block], + basic_block_live_at_start[i]); + } } #ifdef USE_C_ALLOCA alloca (0); @@ -3191,39 +3169,7 @@ dump_flow_info (file) fprintf (file, ".\n"); } fprintf (file, "\n%d basic blocks.\n", n_basic_blocks); - for (i = 0; i < n_basic_blocks; i++) - { - register rtx head, jump; - register int regno; - fprintf (file, "\nBasic block %d: first insn %d, last %d.\n", - i, - INSN_UID (basic_block_head[i]), - INSN_UID (basic_block_end[i])); - /* The control flow graph's storage is freed - now when flow_analysis returns. - Don't try to print it if it is gone. */ - if (basic_block_drops_in) - { - fprintf (file, "Reached from blocks: "); - head = basic_block_head[i]; - if (GET_CODE (head) == CODE_LABEL) - for (jump = LABEL_REFS (head); - jump != head; - jump = LABEL_NEXTREF (jump)) - { - register int from_block = BLOCK_NUM (CONTAINING_INSN (jump)); - fprintf (file, " %d", from_block); - } - if (basic_block_drops_in[i]) - fprintf (file, " previous"); - } - fprintf (file, "\nRegisters live at start:"); - for (regno = 0; regno < max_regno; regno++) - if (REGNO_REG_SET_P (basic_block_live_at_start[i], regno)) - fprintf (file, " %d", regno); - fprintf (file, "\n"); - } - fprintf (file, "\n"); + dump_bb_data (file, basic_block_pred, basic_block_succ, 1); } @@ -3406,117 +3352,46 @@ compute_preds_succs (s_preds, s_succs, num_preds, num_succs) int *num_preds; int *num_succs; { - int bb, clear_local_bb_vars = 0; + int bb; bzero ((char *) s_preds, n_basic_blocks * sizeof (int_list_ptr)); bzero ((char *) s_succs, n_basic_blocks * sizeof (int_list_ptr)); bzero ((char *) num_preds, n_basic_blocks * sizeof (int)); bzero ((char *) num_succs, n_basic_blocks * sizeof (int)); - /* This routine can be called after life analysis; in that case - basic_block_drops_in and uid_block_number will not be available - and we must recompute their values. */ - if (basic_block_drops_in == NULL || uid_block_number == NULL) - { - clear_local_bb_vars = 1; - basic_block_drops_in = (char *) alloca (n_basic_blocks); - uid_block_number = (int *) alloca ((get_max_uid () + 1) * sizeof (int)); - - bzero ((char *) basic_block_drops_in, n_basic_blocks * sizeof (char)); - bzero ((char *) uid_block_number, n_basic_blocks * sizeof (int)); - - /* Scan each basic block setting basic_block_drops_in and - uid_block_number as needed. */ - for (bb = 0; bb < n_basic_blocks; bb++) - { - rtx insn, stop_insn; - - if (bb == 0) - stop_insn = NULL_RTX; - else - stop_insn = basic_block_end[bb-1]; - - /* Look backwards from the start of this block. Stop if we - hit the start of the function or the end of a previous - block. Don't walk backwards through blocks that are just - deleted insns! */ - for (insn = PREV_INSN (basic_block_head[bb]); - insn && insn != stop_insn && GET_CODE (insn) == NOTE; - insn = PREV_INSN (insn)) - ; - - /* Never set basic_block_drops_in for the first block. It is - implicit. - - If we stopped on anything other than a BARRIER, then this - block drops in. */ - if (bb != 0) - basic_block_drops_in[bb] = (insn ? GET_CODE (insn) != BARRIER : 1); - - insn = basic_block_head[bb]; - while (insn) - { - BLOCK_NUM (insn) = bb; - if (insn == basic_block_end[bb]) - break; - insn = NEXT_INSN (insn); - } - } - } - + /* It's somewhat stupid to simply copy the information. The passes + which use this function ought to be changed to refer directly to + basic_block_succ and its relatives. */ for (bb = 0; bb < n_basic_blocks; bb++) { - rtx head; - rtx jump; + rtx jump = BLOCK_END (bb); + enum rtx_code code = GET_CODE (jump); + int_list_ptr p; - head = BLOCK_HEAD (bb); + for (p = basic_block_succ[bb]; p; p = p->next) + add_pred_succ (bb, INT_LIST_VAL (p), s_preds, s_succs, num_preds, + num_succs); - if (GET_CODE (head) == CODE_LABEL) - for (jump = LABEL_REFS (head); - jump != head; - jump = LABEL_NEXTREF (jump)) - { - if (! INSN_DELETED_P (CONTAINING_INSN (jump)) - && (GET_CODE (CONTAINING_INSN (jump)) != NOTE - || (NOTE_LINE_NUMBER (CONTAINING_INSN (jump)) - != NOTE_INSN_DELETED))) - add_pred_succ (BLOCK_NUM (CONTAINING_INSN (jump)), bb, - s_preds, s_succs, num_preds, num_succs); - } - - jump = BLOCK_END (bb); /* If this is a RETURN insn or a conditional jump in the last basic block, or a non-jump insn in the last basic block, then this block reaches the exit block. */ - if ((GET_CODE (jump) == JUMP_INSN && GET_CODE (PATTERN (jump)) == RETURN) - || (((GET_CODE (jump) == JUMP_INSN + if ((code == JUMP_INSN && GET_CODE (PATTERN (jump)) == RETURN) + || (((code == JUMP_INSN && condjump_p (jump) && !simplejump_p (jump)) - || GET_CODE (jump) != JUMP_INSN) - && (bb == n_basic_blocks - 1))) + || code != JUMP_INSN) + && bb == n_basic_blocks - 1)) add_pred_succ (bb, EXIT_BLOCK, s_preds, s_succs, num_preds, num_succs); - - if (basic_block_drops_in[bb]) - add_pred_succ (bb - 1, bb, s_preds, s_succs, num_preds, num_succs); } add_pred_succ (ENTRY_BLOCK, 0, s_preds, s_succs, num_preds, num_succs); - - - /* If we allocated any variables in temporary storage, clear out the - pointer to the local storage to avoid dangling pointers. */ - if (clear_local_bb_vars) - { - basic_block_drops_in = NULL; - uid_block_number = NULL; - - } } void -dump_bb_data (file, preds, succs) +dump_bb_data (file, preds, succs, live_info) FILE *file; int_list_ptr *preds; int_list_ptr *succs; + int live_info; { int bb; int_list_ptr p; @@ -3545,6 +3420,15 @@ dump_bb_data (file, preds, succs) else fprintf (file, " %d", succ_bb); } + if (live_info) + { + int regno; + fprintf (file, "\nRegisters live at start:"); + for (regno = 0; regno < max_regno; regno++) + if (REGNO_REG_SET_P (basic_block_live_at_start[bb], regno)) + fprintf (file, " %d", regno); + fprintf (file, "\n"); + } fprintf (file, "\n"); } fprintf (file, "\n"); diff --git a/gcc/gcse.c b/gcc/gcse.c index a330fef5b70..32e8b516fc2 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -700,9 +700,7 @@ gcse_main (f, file) compute_preds_succs (s_preds, s_succs, num_preds, num_succs); if (file) - { - dump_bb_data (file, s_preds, s_succs); - } + dump_bb_data (file, s_preds, s_succs, 0); /* Record where pseudo-registers are set. This data is kept accurate during each pass. diff --git a/gcc/rtl.h b/gcc/rtl.h index 0ca999e38ab..2a761c4e3bc 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1374,6 +1374,7 @@ extern void recompute_reg_usage PROTO ((rtx)); #ifdef BUFSIZ extern void dump_flow_info PROTO ((FILE *)); #endif +extern void free_bb_memory PROTO ((void)); /* In expmed.c */ extern void init_expmed PROTO ((void)); diff --git a/gcc/toplev.c b/gcc/toplev.c index acf3d431aa7..43fd83e41c7 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3951,6 +3951,8 @@ rest_of_compilation (decl) exit_rest_of_compilation: + free_bb_memory (); + /* In case the function was not output, don't leave any temporary anonymous types queued up for sdb output. */