diff options
Diffstat (limited to 'gcc/cfgrtl.c')
-rw-r--r-- | gcc/cfgrtl.c | 119 |
1 files changed, 78 insertions, 41 deletions
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 5b99ab237e2..e2cb773379a 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -1,6 +1,6 @@ /* Control flow graph manipulation code for GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -101,8 +101,7 @@ can_delete_label_p (label) /* User declared labels must be preserved. */ && LABEL_NAME (label) == 0 && !in_expr_list_p (forced_labels, label) - && !in_expr_list_p (label_value_list, label) - && !in_expr_list_p (exception_handler_labels, label)); + && !in_expr_list_p (label_value_list, label)); } /* Delete INSN by patching it out. Return the next insn. */ @@ -323,7 +322,7 @@ create_basic_block (index, head, end) to post-process the stream to remove empty blocks, loops, ranges, etc. */ int -flow_delete_block (b) +flow_delete_block_noexpunge (b) basic_block b; { int deleted_handler = 0; @@ -372,6 +371,15 @@ flow_delete_block (b) b->pred = NULL; b->succ = NULL; + return deleted_handler; +} + +int +flow_delete_block (b) + basic_block b; +{ + int deleted_handler = flow_delete_block_noexpunge (b); + /* Remove the basic block from the array, and compact behind it. */ expunge_block (b); @@ -611,9 +619,9 @@ merge_blocks_nomove (a, b) rtx x; for (x = a_end; x != b_end; x = NEXT_INSN (x)) - BLOCK_FOR_INSN (x) = a; + set_block_for_insn (x, a); - BLOCK_FOR_INSN (b_end) = a; + set_block_for_insn (b_end, a); } a_end = b_end; @@ -657,6 +665,7 @@ try_redirect_by_replacing_jump (e, target) edge tmp; rtx set; int fallthru = 0; + rtx table; /* Verify that all targets will be TARGET. */ for (tmp = src->succ; tmp; tmp = tmp->succ_next) @@ -666,6 +675,13 @@ try_redirect_by_replacing_jump (e, target) if (tmp || !onlyjump_p (insn)) return false; + if (reload_completed && JUMP_LABEL (insn) + && (table = NEXT_INSN (JUMP_LABEL (insn))) != NULL_RTX + && GET_CODE (table) == JUMP_INSN + && (GET_CODE (PATTERN (table)) == ADDR_VEC + || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC)) + return false; + /* Avoid removing branch with side effects. */ set = single_set (insn); if (!set || side_effects_p (set)) @@ -928,6 +944,9 @@ force_nonfallthru_and_redirect (e, target) /* Change the existing edge's source to be the new block, and add a new edge from the entry block to the new block. */ e->src = bb; + bb->count = e->count; + bb->frequency = EDGE_FREQUENCY (e); + bb->loop_depth = 0; for (pe1 = &ENTRY_BLOCK_PTR->succ; *pe1; pe1 = &(*pe1)->succ_next) if (*pe1 == e) { @@ -942,9 +961,21 @@ force_nonfallthru_and_redirect (e, target) if (e->src->succ->succ_next) { /* Create the new structures. */ + + /* Position the new block correctly relative to loop notes. */ note = last_loop_beg_note (e->src->end); - jump_block - = create_basic_block (e->src->index + 1, NEXT_INSN (note), NULL); + note = NEXT_INSN (note); + + /* ... and ADDR_VECs. */ + if (note != NULL + && GET_CODE (note) == CODE_LABEL + && NEXT_INSN (note) + && GET_CODE (NEXT_INSN (note)) == JUMP_INSN + && (GET_CODE (PATTERN (NEXT_INSN (note))) == ADDR_DIFF_VEC + || GET_CODE (PATTERN (NEXT_INSN (note))) == ADDR_VEC)) + note = NEXT_INSN (NEXT_INSN (note)); + + jump_block = create_basic_block (e->src->index + 1, note, NULL); jump_block->count = e->count; jump_block->frequency = EDGE_FREQUENCY (e); jump_block->loop_depth = target->loop_depth; @@ -1214,6 +1245,7 @@ split_edge (edge_in) : edge_in->dest->index, before, NULL); bb->count = edge_in->count; bb->frequency = EDGE_FREQUENCY (edge_in); + bb->loop_depth = edge_in->dest->loop_depth; /* ??? This info is likely going to be out of date very soon. */ if (edge_in->dest->global_live_at_start) @@ -1897,9 +1929,30 @@ purge_dead_edges (bb) rtx insn = bb->end, note; bool purged = false; - /* ??? This makes no sense since the later test includes more cases. */ - if (GET_CODE (insn) == JUMP_INSN && !simplejump_p (insn)) - return false; + /* If this instruction cannot trap, remove REG_EH_REGION notes. */ + if (GET_CODE (insn) == INSN + && (note = find_reg_note (insn, REG_EH_REGION, NULL))) + { + rtx eqnote; + + if (! may_trap_p (PATTERN (insn)) + || ((eqnote = find_reg_equal_equiv_note (insn)) + && ! may_trap_p (XEXP (eqnote, 0)))) + remove_note (insn, note); + } + + /* Cleanup abnormal edges caused by throwing insns that have been + eliminated. */ + if (! can_throw_internal (bb->end)) + for (e = bb->succ; e; e = next) + { + next = e->succ_next; + if (e->flags & EDGE_EH) + { + remove_edge (e); + purged = true; + } + } if (GET_CODE (insn) == JUMP_INSN) { @@ -1921,17 +1974,26 @@ purge_dead_edges (bb) e->flags &= ~EDGE_ABNORMAL; - /* Check purposes we can have edge. */ - if ((e->flags & EDGE_FALLTHRU) - && any_condjump_p (insn)) + /* See if this edge is one we should keep. */ + if ((e->flags & EDGE_FALLTHRU) && any_condjump_p (insn)) + /* A conditional jump can fall through into the next + block, so we should keep the edge. */ continue; else if (e->dest != EXIT_BLOCK_PTR && e->dest->head == JUMP_LABEL (insn)) + /* If the destination block is the target of the jump, + keep the edge. */ + continue; + else if (e->dest == EXIT_BLOCK_PTR && returnjump_p (insn)) + /* If the destination block is the exit block, and this + instruction is a return, then keep the edge. */ continue; - else if (e->dest == EXIT_BLOCK_PTR - && returnjump_p (insn)) + else if ((e->flags & EDGE_EH) && can_throw_internal (insn)) + /* Keep the edges that correspond to exceptions thrown by + this instruction. */ continue; + /* We do not need this edge. */ purged = true; remove_edge (e); } @@ -1968,31 +2030,6 @@ purge_dead_edges (bb) return purged; } - /* If this instruction cannot trap, remove REG_EH_REGION notes. */ - if (GET_CODE (insn) == INSN - && (note = find_reg_note (insn, REG_EH_REGION, NULL))) - { - rtx eqnote; - - if (! may_trap_p (PATTERN (insn)) - || ((eqnote = find_reg_equal_equiv_note (insn)) - && ! may_trap_p (XEXP (eqnote, 0)))) - remove_note (insn, note); - } - - /* Cleanup abnormal edges caused by throwing insns that have been - eliminated. */ - if (! can_throw_internal (bb->end)) - for (e = bb->succ; e; e = next) - { - next = e->succ_next; - if (e->flags & EDGE_EH) - { - remove_edge (e); - purged = true; - } - } - /* If we don't see a jump insn, we don't know exactly why the block would have been broken at this point. Look for a simple, non-fallthru edge, as these are only created by conditional branches. If we find such an |