diff options
author | Richard Henderson <rth@cygnus.com> | 1999-09-21 14:15:37 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 1999-09-21 14:15:37 -0700 |
commit | 336a6399a9ab84ac787c525ec2a2a469b8b488d5 (patch) | |
tree | 5f84bcf24f6d398455afd08aec40a0b90bdab8c1 /gcc | |
parent | 9f14fb64049bc3598da0624b59c74a89abdee09d (diff) | |
download | gcc-336a6399a9ab84ac787c525ec2a2a469b8b488d5.zip gcc-336a6399a9ab84ac787c525ec2a2a469b8b488d5.tar.gz gcc-336a6399a9ab84ac787c525ec2a2a469b8b488d5.tar.bz2 |
basic-block.h (basic_block): Add eh_beg, eh_end.
* basic-block.h (basic_block): Add eh_beg, eh_end.
* flow.c (entry_exit_blocks): Update.
(find_basic_blocks): Don't allocate bb_eh_end, or pass it around.
Call new functions.
(find_basic_blocks_1): Don't record eh_list at each bb. Use
lists.c functions to allocate insn lists.
(make_edges): Use eh_beg+eh_end, not the lists. Split out EH
edge creation ...
(make_eh_edge): ... here. New.
(move_stray_eh_region_notes): New.
(record_active_eh_regions): New.
(delete_unreachable_blocks): Split out block merging ...
(try_merge_blocks): ... here. New.
(merge_blocks_move_predecessor_nojumps): Remove edge arg.
Dump debugging data.
(merge_blocks_move_successor_nojumps): Likewise.
(merge_blocks): Use eh_beg+eh_end to validate block movement.
From-SVN: r29565
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/basic-block.h | 3 | ||||
-rw-r--r-- | gcc/flow.c | 416 |
3 files changed, 300 insertions, 139 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3cf9abe..b103476 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +Tue Sep 21 14:14:50 1999 Richard Henderson <rth@cygnus.com> + + * basic-block.h (basic_block): Add eh_beg, eh_end. + * flow.c (entry_exit_blocks): Update. + (find_basic_blocks): Don't allocate bb_eh_end, or pass it around. + Call new functions. + (find_basic_blocks_1): Don't record eh_list at each bb. Use + lists.c functions to allocate insn lists. + (make_edges): Use eh_beg+eh_end, not the lists. Split out EH + edge creation ... + (make_eh_edge): ... here. New. + (move_stray_eh_region_notes): New. + (record_active_eh_regions): New. + (delete_unreachable_blocks): Split out block merging ... + (try_merge_blocks): ... here. New. + (merge_blocks_move_predecessor_nojumps): Remove edge arg. + Dump debugging data. + (merge_blocks_move_successor_nojumps): Likewise. + (merge_blocks): Use eh_beg+eh_end to validate block movement. + Tue Sep 21 11:15:03 1999 Martin v. Löwis <loewis@informatik.hu-berlin.de> * extend.texi (Bound member functions): Document unbound pmf diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 26b509c..13f8c47 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -144,6 +144,9 @@ typedef struct basic_block_def { int index; /* The loop depth of this block plus one. */ int loop_depth; + + /* The active eh region before head and after end. */ + int eh_beg, eh_end; } *basic_block; /* Number of basic blocks in the current function. */ @@ -178,7 +178,8 @@ struct basic_block_def entry_exit_blocks[2] = NULL, /* global_live_at_end */ NULL, /* aux */ ENTRY_BLOCK, /* index */ - 0 /* loop_depth */ + 0, /* loop_depth */ + -1, -1 /* eh_beg, eh_end */ }, { NULL, /* head */ @@ -190,7 +191,8 @@ struct basic_block_def entry_exit_blocks[2] = NULL, /* global_live_at_end */ NULL, /* aux */ EXIT_BLOCK, /* index */ - 0 /* loop_depth */ + 0, /* loop_depth */ + -1, -1 /* eh_beg, eh_end */ } }; @@ -274,13 +276,17 @@ static bitmap uid_volatile; /* Forward declarations */ static int count_basic_blocks PROTO((rtx)); -static rtx find_basic_blocks_1 PROTO((rtx, rtx*)); +static rtx find_basic_blocks_1 PROTO((rtx)); static void create_basic_block PROTO((int, rtx, rtx, rtx)); static void clear_edges PROTO((void)); -static void make_edges PROTO((rtx, rtx*)); +static void make_edges PROTO((rtx)); static void make_edge PROTO((basic_block, basic_block, int)); static void make_label_edge PROTO((basic_block, rtx, int)); +static void make_eh_edge PROTO((eh_nesting_info *, basic_block, + rtx, int)); static void mark_critical_edges PROTO((void)); +static void move_stray_eh_region_notes PROTO((void)); +static void record_active_eh_regions PROTO((rtx)); static void commit_one_edge_insertion PROTO((edge)); @@ -292,8 +298,13 @@ static int delete_block PROTO((basic_block)); static void expunge_block PROTO((basic_block)); static rtx flow_delete_insn PROTO((rtx)); static int can_delete_label_p PROTO((rtx)); +static int merge_blocks_move_predecessor_nojumps PROTO((basic_block, + basic_block)); +static int merge_blocks_move_successor_nojumps PROTO((basic_block, + basic_block)); static void merge_blocks_nomove PROTO((basic_block, basic_block)); static int merge_blocks PROTO((edge,basic_block,basic_block)); +static void try_merge_blocks PROTO((void)); static void tidy_fallthru_edge PROTO((edge,basic_block,basic_block)); static void calculate_loop_depth PROTO((rtx)); @@ -354,7 +365,6 @@ find_basic_blocks (f, nregs, file, do_cleanup) FILE *file ATTRIBUTE_UNUSED; int do_cleanup; { - rtx *bb_eh_end; int max_uid; /* Flush out existing data. */ @@ -385,11 +395,7 @@ find_basic_blocks (f, nregs, file, do_cleanup) VARRAY_BB_INIT (basic_block_info, n_basic_blocks, "basic_block_info"); - /* An array to record the active exception region at the end of each - basic block. It is filled in by find_basic_blocks_1 for make_edges. */ - bb_eh_end = (rtx *) alloca (n_basic_blocks * sizeof (rtx)); - - label_value_list = find_basic_blocks_1 (f, bb_eh_end); + label_value_list = find_basic_blocks_1 (f); /* Record the block to which an insn belongs. */ /* ??? This should be done another way, by which (perhaps) a label is @@ -407,12 +413,18 @@ find_basic_blocks (f, nregs, file, do_cleanup) /* Discover the edges of our cfg. */ - make_edges (label_value_list, bb_eh_end); + record_active_eh_regions (f); + make_edges (label_value_list); - /* Delete unreachable blocks. */ + /* Delete unreachable blocks, then merge blocks when possible. */ if (do_cleanup) - delete_unreachable_blocks (); + { + delete_unreachable_blocks (); + move_stray_eh_region_notes (); + record_active_eh_regions (f); + try_merge_blocks (); + } /* Mark critical edges. */ @@ -513,20 +525,13 @@ count_basic_blocks (f) } /* Find all basic blocks of the function whose first insn is F. - Store the correct data in the tables that describe the basic blocks, - set up the chains of references for each CODE_LABEL, and - delete any entire basic blocks that cannot be reached. - - NONLOCAL_LABEL_LIST is a list of non-local labels in the function. Blocks - that are otherwise unreachable may be reachable with a non-local goto. - BB_EH_END is an array in which we record the list of exception regions - active at the end of every basic block. */ + Collect and return a list of labels whose addresses are taken. This + will be used in make_edges for use with computed gotos. */ static rtx -find_basic_blocks_1 (f, bb_eh_end) +find_basic_blocks_1 (f) rtx f; - rtx *bb_eh_end; { register rtx insn, next; int call_has_abnormal_edge = 0; @@ -541,7 +546,7 @@ find_basic_blocks_1 (f, bb_eh_end) previously. This is so that we see a NOTE_BASIC_BLOCK after we have closed out the previous block, so that it gets attached at the proper place. Since this form should be equivalent to the previous, - find_basic_blocks_0 continues to use the old form as a check. */ + count_basic_blocks continues to use the old form as a check. */ for (insn = f; insn; insn = next) { @@ -577,9 +582,13 @@ find_basic_blocks_1 (f, bb_eh_end) /* Keep a LIFO list of the currently active exception notes. */ if (kind == NOTE_INSN_EH_REGION_BEG) - eh_list = gen_rtx_INSN_LIST (VOIDmode, insn, eh_list); + eh_list = alloc_INSN_LIST (insn, eh_list); else if (kind == NOTE_INSN_EH_REGION_END) - eh_list = XEXP (eh_list, 1); + { + rtx t = eh_list; + eh_list = XEXP (eh_list, 1); + free_INSN_LIST_node (t); + } /* Look for basic block notes with which to keep the basic_block_info pointers stable. Unthread the note now; @@ -611,7 +620,6 @@ find_basic_blocks_1 (f, bb_eh_end) end = emit_insn_after (nop, end); } - bb_eh_end[i] = eh_list; create_basic_block (i++, head, end, bb_note); bb_note = NULL_RTX; } @@ -676,7 +684,6 @@ find_basic_blocks_1 (f, bb_eh_end) end = insn; new_bb_exclusive: - bb_eh_end[i] = eh_list; create_basic_block (i++, head, end, bb_note); head = end = NULL_RTX; bb_note = NULL_RTX; @@ -728,10 +735,7 @@ find_basic_blocks_1 (f, bb_eh_end) } if (head != NULL_RTX) - { - bb_eh_end[i] = eh_list; - create_basic_block (i++, head, end, bb_note); - } + create_basic_block (i++, head, end, bb_note); if (i != n_basic_blocks) abort (); @@ -870,9 +874,8 @@ clear_edges () the list of exception regions active at the end of the basic block. */ static void -make_edges (label_value_list, bb_eh_end) +make_edges (label_value_list) rtx label_value_list; - rtx *bb_eh_end; { int i; eh_nesting_info *eh_nest_info = init_eh_nesting_info (); @@ -886,26 +889,11 @@ make_edges (label_value_list, bb_eh_end) for (i = 0; i < n_basic_blocks; ++i) { basic_block bb = BASIC_BLOCK (i); - rtx insn, x, eh_list; + rtx insn, x; enum rtx_code code; int force_fallthru = 0; - /* If we have asynchronous exceptions, scan the notes for all exception - regions active in the block. In the normal case, we only need the - one active at the end of the block, which is bb_eh_end[i]. */ - - eh_list = bb_eh_end[i]; - if (asynchronous_exceptions) - { - for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn)) - { - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END) - eh_list = gen_rtx_INSN_LIST (VOIDmode, insn, eh_list); - } - } - - /* Now examine the last instruction of the block, and discover the + /* Examine the last instruction of the block, and discover the ways we can leave the block. */ insn = bb->end; @@ -984,20 +972,27 @@ make_edges (label_value_list, bb_eh_end) if (code == CALL_INSN || asynchronous_exceptions) { - int is_call = (code == CALL_INSN ? EDGE_ABNORMAL_CALL : 0); - handler_info **handler_list; - int eh_region = -1; - int num; - - if (eh_list) - eh_region = NOTE_EH_HANDLER (XEXP (eh_list, 0)); - - num = reachable_handlers (eh_region, eh_nest_info, - insn, &handler_list); - for ( ; num > 0; num--) + /* If there's an EH region active at the end of a block, + add the appropriate edges. */ + if (bb->eh_end >= 0) + make_eh_edge (eh_nest_info, bb, insn, bb->eh_end); + + /* If we have asynchronous exceptions, do the same for *all* + exception regions active in the block. */ + if (asynchronous_exceptions + && bb->eh_beg != bb->eh_end) { - make_label_edge (bb, handler_list[num - 1]->handler_label, - EDGE_ABNORMAL | EDGE_EH | is_call); + if (bb->eh_beg >= 0) + make_eh_edge (eh_nest_info, bb, NULL_RTX, bb->eh_beg); + + for (x = bb->head; x != bb->end; x = PREV_INSN (x)) + if (GET_CODE (x) == NOTE + && (NOTE_LINE_NUMBER (x) == NOTE_INSN_EH_REGION_BEG + || NOTE_LINE_NUMBER (x) == NOTE_INSN_EH_REGION_END)) + { + int region = NOTE_EH_HANDLER (x); + make_eh_edge (eh_nest_info, bb, NULL_RTX, region); + } } if (code == CALL_INSN && nonlocal_goto_handler_labels) @@ -1096,7 +1091,119 @@ make_label_edge (src, label, flags) make_edge (src, BLOCK_FOR_INSN (label), flags); } +/* Create the edges generated by INSN in REGION. */ + +static void +make_eh_edge (eh_nest_info, src, insn, region) + eh_nesting_info *eh_nest_info; + basic_block src; + rtx insn; + int region; +{ + handler_info **handler_list; + int num, is_call; + + is_call = (insn && GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0); + num = reachable_handlers (region, eh_nest_info, insn, &handler_list); + while (--num >= 0) + { + make_label_edge (src, handler_list[num]->handler_label, + EDGE_ABNORMAL | EDGE_EH | is_call); + } +} + +/* EH_REGION notes appearing between basic blocks is ambiguous, and even + dangerous if we intend to move basic blocks around. Move such notes + into the following block. */ + +static void +move_stray_eh_region_notes () +{ + int i; + basic_block b1, b2; + + if (n_basic_blocks < 2) + return; + + b2 = BASIC_BLOCK (n_basic_blocks - 1); + for (i = n_basic_blocks - 2; i >= 0; --i, b2 = b1) + { + rtx insn, next, list = NULL_RTX; + + b1 = BASIC_BLOCK (i); + for (insn = NEXT_INSN (b1->end); insn != b2->head; insn = next) + { + next = NEXT_INSN (insn); + if (GET_CODE (insn) == NOTE + && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) + { + /* Unlink from the insn chain. */ + NEXT_INSN (PREV_INSN (insn)) = next; + PREV_INSN (next) = PREV_INSN (insn); + + /* Queue it. */ + NEXT_INSN (insn) = list; + list = insn; + } + } + + if (list == NULL_RTX) + continue; + + /* Find where to insert these things. */ + insn = b2->head; + if (GET_CODE (insn) == CODE_LABEL) + insn = NEXT_INSN (insn); + + while (list) + { + next = NEXT_INSN (list); + add_insn_after (list, insn); + list = next; + } + } +} + +/* Recompute eh_beg/eh_end for each basic block. */ + +static void +record_active_eh_regions (f) + rtx f; +{ + rtx insn, eh_list = NULL_RTX; + int i = 0; + basic_block bb = BASIC_BLOCK (0); + + for (insn = f; insn ; insn = NEXT_INSN (insn)) + { + if (bb->head == insn) + bb->eh_beg = (eh_list ? NOTE_EH_HANDLER (XEXP (eh_list, 0)) : -1); + + if (GET_CODE (insn) == NOTE) + { + int kind = NOTE_LINE_NUMBER (insn); + if (kind == NOTE_INSN_EH_REGION_BEG) + eh_list = alloc_INSN_LIST (insn, eh_list); + else if (kind == NOTE_INSN_EH_REGION_END) + { + rtx t = XEXP (eh_list, 1); + free_INSN_LIST_node (eh_list); + eh_list = t; + } + } + + if (bb->end == insn) + { + bb->eh_end = (eh_list ? NOTE_EH_HANDLER (XEXP (eh_list, 0)) : -1); + i += 1; + bb = BASIC_BLOCK (i); + } + } +} + /* Identify critical edges and set the bits appropriately. */ + static void mark_critical_edges () { @@ -1575,31 +1682,6 @@ delete_unreachable_blocks () tidy_fallthru_edge (s, b, c); } - /* Attempt to merge blocks as made possible by edge removal. If a block - has only one successor, and the successor has only one predecessor, - they may be combined. */ - - for (i = 0; i < n_basic_blocks; ) - { - basic_block c, b = BASIC_BLOCK (i); - edge s; - - /* A loop because chains of blocks might be combineable. */ - while ((s = b->succ) != NULL - && s->succ_next == NULL - && (s->flags & EDGE_EH) == 0 - && (c = s->dest) != EXIT_BLOCK_PTR - && c->pred->pred_next == NULL - /* If the jump insn has side effects, we can't kill the edge. */ - && (GET_CODE (b->end) != JUMP_INSN - || onlyjump_p (b->end)) - && merge_blocks (s, b, c)) - continue; - - /* Don't get confused by the index shift caused by deleting blocks. */ - i = b->index + 1; - } - /* If we deleted an exception handler, we may have EH region begin/end blocks to remove as well. */ if (deleted_handler) @@ -1858,8 +1940,7 @@ can_delete_label_p (label) any jumps (aside from the jump from A to B). */ static int -merge_blocks_move_predecessor_nojumps (e, a, b) - edge e; +merge_blocks_move_predecessor_nojumps (a, b) basic_block a, b; { rtx start, end, insertpoint, barrier; @@ -1896,6 +1977,13 @@ merge_blocks_move_predecessor_nojumps (e, a, b) /* Now blocks A and B are contiguous. Merge them. */ merge_blocks_nomove (a, b); + + if (rtl_dump_file) + { + fprintf (rtl_dump_file, "Moved block %d before %d and merged.\n", + a->index, b->index); + } + return 1; } @@ -1904,8 +1992,7 @@ merge_blocks_move_predecessor_nojumps (e, a, b) any jumps (aside from the jump from A to B). */ static int -merge_blocks_move_successor_nojumps (e, a, b) - edge e; +merge_blocks_move_successor_nojumps (a, b) basic_block a, b; { rtx start, end, insertpoint, barrier; @@ -1942,6 +2029,13 @@ merge_blocks_move_successor_nojumps (e, a, b) /* Now blocks A and B are contiguous. Merge them. */ merge_blocks_nomove (a, b); + + if (rtl_dump_file) + { + fprintf (rtl_dump_file, "Moved block %d after %d and merged.\n", + b->index, a->index); + } + return 1; } @@ -2042,35 +2136,46 @@ merge_blocks (e, b, c) basic_block b, c; { /* If B has a fallthru edge to C, no need to move anything. */ - if (!(e->flags & EDGE_FALLTHRU)) + if (e->flags & EDGE_FALLTHRU) { - edge tmp_edge; - int c_has_outgoing_fallthru; - int b_has_incoming_fallthru; - - /* ??? From here on out we must make sure to not munge nesting - of exception regions and lexical blocks. + /* If a label still appears somewhere and we cannot delete the label, + then we cannot merge the blocks. The edge was tidied already. */ - A few notes on the subject: + rtx insn, stop = NEXT_INSN (c->head); + for (insn = NEXT_INSN (b->end); insn != stop; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == CODE_LABEL && !can_delete_label_p (insn)) + return 0; - Not only do we have to be careful not to lose the nesting of - exception regions or lexical blocks, we also have to be careful - about merging blocks which are in different EH regions. + merge_blocks_nomove (b, c); - A call that throws may end a block. The insn to copy the return - value from its hard reg into a pseudo could end up in a - different block than the call. Moving either block might cause - problems for SMALL_REGISTER_CLASS machines. + if (rtl_dump_file) + { + fprintf (rtl_dump_file, "Merged %d and %d without moving.\n", + b->index, c->index); + } - A throw/catch edge (or any abnormal edge) should be rarely - executed and we may want to treat blocks which have two out - edges, one normal, one abnormal as only having one edge for - block merging purposes. + return 1; + } + else + { + edge tmp_edge; + basic_block d; + int c_has_outgoing_fallthru; + int b_has_incoming_fallthru; - For now we avoid the EH issues by not allowing any physical - block movement when exception handling is enabled. */ - if (flag_exceptions) - return 0; + /* We must make sure to not munge nesting of exception regions, + lexical blocks, and loop notes. + + The first is taken care of by requiring that the active eh + region at the end of one block always matches the active eh + region at the beginning of the next block. + + The later two are taken care of by squeezing out all the notes. */ + + /* ??? A throw/catch edge (or any abnormal edge) should be rarely + executed and we may want to treat blocks which have two out + edges, one normal, one abnormal as only having one edge for + block merging purposes. */ for (tmp_edge = c->succ; tmp_edge ; tmp_edge = tmp_edge->succ_next) if (tmp_edge->flags & EDGE_FALLTHRU) @@ -2082,33 +2187,66 @@ merge_blocks (e, b, c) break; b_has_incoming_fallthru = (tmp_edge != NULL); - /* If B does not have an incoming fallthru, then it can be moved - immediately before C without introducing or modifying jumps. - - Else if C does not have an outgoing fallthru, then it can be moved - immediately after B without introducing or modifying jumps. + /* If B does not have an incoming fallthru, and the exception regions + match, then it can be moved immediately before C without introducing + or modifying jumps. */ + d = BASIC_BLOCK (c->index - 1); + if (! b_has_incoming_fallthru + && d->eh_end == b->eh_beg + && b->eh_end == c->eh_beg) + return merge_blocks_move_predecessor_nojumps (b, c); + + /* Otherwise, we're going to try to move C after B. Make sure the + exception regions match. */ + d = BASIC_BLOCK (b->index + 1); + if (b->eh_end == c->eh_beg + && c->eh_end == d->eh_beg) + { + /* If C does not have an outgoing fallthru, then it can be moved + immediately after B without introducing or modifying jumps. */ + if (! c_has_outgoing_fallthru) + return merge_blocks_move_successor_nojumps (b, c); + + /* Otherwise, we'll need to insert an extra jump, and possibly + a new block to contain it. */ + /* ??? Not implemented yet. */ + } - Else move C after B, which will likely require insertion of a - new jump. ??? Not implemented yet. */ - if (! b_has_incoming_fallthru) - return merge_blocks_move_predecessor_nojumps (e, b, c); - else if (! c_has_outgoing_fallthru) - return merge_blocks_move_successor_nojumps (e, b, c); - else - return 0; + return 0; } +} - /* If a label still appears somewhere and we cannot delete the label, - then we cannot merge the blocks. The edge was tidied already. */ - { - rtx insn, stop = NEXT_INSN (c->head); - for (insn = NEXT_INSN (b->end); insn != stop; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CODE_LABEL && !can_delete_label_p (insn)) - return 0; - } +/* Top level driver for merge_blocks. */ - merge_blocks_nomove (b, c); - return 1; +static void +try_merge_blocks () +{ + int i; + + /* Attempt to merge blocks as made possible by edge removal. If a block + has only one successor, and the successor has only one predecessor, + they may be combined. */ + + for (i = 0; i < n_basic_blocks; ) + { + basic_block c, b = BASIC_BLOCK (i); + edge s; + + /* A loop because chains of blocks might be combineable. */ + while ((s = b->succ) != NULL + && s->succ_next == NULL + && (s->flags & EDGE_EH) == 0 + && (c = s->dest) != EXIT_BLOCK_PTR + && c->pred->pred_next == NULL + /* If the jump insn has side effects, we can't kill the edge. */ + && (GET_CODE (b->end) != JUMP_INSN + || onlyjump_p (b->end)) + && merge_blocks (s, b, c)) + continue; + + /* Don't get confused by the index shift caused by deleting blocks. */ + i = b->index + 1; + } } /* The given edge should potentially a fallthru edge. If that is in |