X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcfglayout.c;h=01784319c192d65fd71b57f654ff1f1e1c4adbd9;hb=5e9db045713255a09a312ccbe905c283f7f92e51;hp=e887015ac7f75d6f6fda49a4915e14a1f051bf6e;hpb=2c712008ca5c69048c649e541fd41e44b21d94f3;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index e887015ac7f..01784319c19 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -1,5 +1,5 @@ /* Basic block reordering routines for the GNU compiler. - Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -15,8 +15,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #include "system.h" @@ -25,24 +25,23 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree.h" #include "rtl.h" #include "hard-reg-set.h" +#include "obstack.h" #include "basic-block.h" #include "insn-config.h" #include "output.h" #include "function.h" -#include "obstack.h" #include "cfglayout.h" #include "cfgloop.h" #include "target.h" #include "ggc.h" #include "alloc-pool.h" #include "flags.h" - -/* The contents of the current function definition are allocated - in this obstack, and all are freed at the end of the function. */ -extern struct obstack flow_obstack; +#include "tree-pass.h" +#include "vecprim.h" /* Holds the interesting trailing notes for the function. */ -rtx cfg_layout_function_footer, cfg_layout_function_header; +rtx cfg_layout_function_footer; +rtx cfg_layout_function_header; static rtx skip_insns_after_block (basic_block); static void record_effective_endpoints (void); @@ -55,7 +54,6 @@ static void change_scope (rtx, tree, tree); void verify_insn_chain (void); static void fixup_fallthru_exit_predecessor (void); static tree insn_scope (rtx); -static void update_unlikely_executed_notes (basic_block); rtx unlink_insn_chain (rtx first, rtx last) @@ -103,7 +101,6 @@ skip_insns_after_block (basic_block bb) case NOTE: switch (NOTE_LINE_NUMBER (insn)) { - case NOTE_INSN_LOOP_END: case NOTE_INSN_BLOCK_END: last_insn = insn; continue; @@ -119,9 +116,9 @@ skip_insns_after_block (basic_block bb) case CODE_LABEL: if (NEXT_INSN (insn) - && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN + && JUMP_P (NEXT_INSN (insn)) && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC - || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)) + || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)) { insn = NEXT_INSN (insn); last_insn = insn; @@ -139,20 +136,19 @@ skip_insns_after_block (basic_block bb) /* It is possible to hit contradictory sequence. For instance: jump_insn - NOTE_INSN_LOOP_BEG + NOTE_INSN_BLOCK_BEG barrier Where barrier belongs to jump_insn, but the note does not. This can be created by removing the basic block originally following - NOTE_INSN_LOOP_BEG. In such case reorder the notes. */ + NOTE_INSN_BLOCK_BEG. In such case reorder the notes. */ for (insn = last_insn; insn != BB_END (bb); insn = prev) { prev = PREV_INSN (insn); - if (GET_CODE (insn) == NOTE) + if (NOTE_P (insn)) switch (NOTE_LINE_NUMBER (insn)) { - case NOTE_INSN_LOOP_END: case NOTE_INSN_BLOCK_END: case NOTE_INSN_DELETED: case NOTE_INSN_DELETED_LABEL: @@ -172,7 +168,7 @@ label_for_bb (basic_block bb) { rtx label = BB_HEAD (bb); - if (GET_CODE (label) != CODE_LABEL) + if (!LABEL_P (label)) { if (dump_file) fprintf (dump_file, "Emitting label for block %d\n", bb->index); @@ -195,12 +191,13 @@ record_effective_endpoints (void) for (insn = get_insns (); insn - && GET_CODE (insn) == NOTE + && NOTE_P (insn) && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK; insn = NEXT_INSN (insn)) continue; - if (!insn) - abort (); /* No basic blocks at all? */ + /* No basic blocks at all? */ + gcc_assert (insn); + if (PREV_INSN (insn)) cfg_layout_function_header = unlink_insn_chain (get_insns (), PREV_INSN (insn)); @@ -213,11 +210,11 @@ record_effective_endpoints (void) rtx end; if (PREV_INSN (BB_HEAD (bb)) && next_insn != BB_HEAD (bb)) - bb->rbi->header = unlink_insn_chain (next_insn, + bb->il.rtl->header = unlink_insn_chain (next_insn, PREV_INSN (BB_HEAD (bb))); end = skip_insns_after_block (bb); if (NEXT_INSN (BB_END (bb)) && BB_END (bb) != end) - bb->rbi->footer = unlink_insn_chain (NEXT_INSN (BB_END (bb)), end); + bb->il.rtl->footer = unlink_insn_chain (NEXT_INSN (BB_END (bb)), end); next_insn = NEXT_INSN (BB_END (bb)); } @@ -233,11 +230,11 @@ record_effective_endpoints (void) block_locators_blocks contains the scope block that is used for all insn locator greater than corresponding block_locators_locs value and smaller than the following one. Similarly for the other properties. */ -static GTY(()) varray_type block_locators_locs; -static GTY(()) varray_type block_locators_blocks; -static GTY(()) varray_type line_locators_locs; -static GTY(()) varray_type line_locators_lines; -static GTY(()) varray_type file_locators_locs; +static VEC(int,heap) *block_locators_locs; +static GTY(()) VEC(tree,gc) *block_locators_blocks; +static VEC(int,heap) *line_locators_locs; +static VEC(int,heap) *line_locators_lines; +static VEC(int,heap) *file_locators_locs; static GTY(()) varray_type file_locators_files; int prologue_locator; int epilogue_locator; @@ -246,7 +243,7 @@ int epilogue_locator; represented via INSN_NOTEs. Replace them by representation using INSN_LOCATORs. */ -void +unsigned int insn_locators_initialize (void) { tree block = NULL; @@ -254,95 +251,157 @@ insn_locators_initialize (void) rtx insn, next; int loc = 0; int line_number = 0, last_line_number = 0; - char *file_name = NULL, *last_file_name = NULL; + const char *file_name = NULL, *last_file_name = NULL; prologue_locator = epilogue_locator = 0; - VARRAY_INT_INIT (block_locators_locs, 32, "block_locators_locs"); - VARRAY_TREE_INIT (block_locators_blocks, 32, "block_locators_blocks"); - VARRAY_INT_INIT (line_locators_locs, 32, "line_locators_locs"); - VARRAY_INT_INIT (line_locators_lines, 32, "line_locators_lines"); - VARRAY_INT_INIT (file_locators_locs, 32, "file_locators_locs"); + block_locators_locs = VEC_alloc (int, heap, 32); + block_locators_blocks = VEC_alloc (tree, gc, 32); + line_locators_locs = VEC_alloc (int, heap, 32); + line_locators_lines = VEC_alloc (int, heap, 32); + file_locators_locs = VEC_alloc (int, heap, 32); VARRAY_CHAR_PTR_INIT (file_locators_files, 32, "file_locators_files"); for (insn = get_insns (); insn; insn = next) { + int active = 0; + next = NEXT_INSN (insn); - if ((active_insn_p (insn) - && GET_CODE (PATTERN (insn)) != ADDR_VEC - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) - || !NEXT_INSN (insn) + if (NOTE_P (insn)) + { + gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_BEG + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_END); + if (NOTE_LINE_NUMBER (insn) > 0) + { + expanded_location xloc; + NOTE_EXPANDED_LOCATION (xloc, insn); + line_number = xloc.line; + file_name = xloc.file; + delete_insn (insn); + } + } + else + active = (active_insn_p (insn) + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC); + + check_block_change (insn, &block); + + if (active + || !next || (!prologue_locator && file_name)) { if (last_block != block) { loc++; - VARRAY_PUSH_INT (block_locators_locs, loc); - VARRAY_PUSH_TREE (block_locators_blocks, block); + VEC_safe_push (int, heap, block_locators_locs, loc); + VEC_safe_push (tree, gc, block_locators_blocks, block); last_block = block; } if (last_line_number != line_number) { loc++; - VARRAY_PUSH_INT (line_locators_locs, loc); - VARRAY_PUSH_INT (line_locators_lines, line_number); + VEC_safe_push (int, heap, line_locators_locs, loc); + VEC_safe_push (int, heap, line_locators_lines, line_number); last_line_number = line_number; } if (last_file_name != file_name) { loc++; - VARRAY_PUSH_INT (file_locators_locs, loc); - VARRAY_PUSH_CHAR_PTR (file_locators_files, file_name); + VEC_safe_push (int, heap, file_locators_locs, loc); + VARRAY_PUSH_CHAR_PTR (file_locators_files, (char *) file_name); last_file_name = file_name; } + if (!prologue_locator && file_name) + prologue_locator = loc; + if (!next) + epilogue_locator = loc; + if (active) + INSN_LOCATOR (insn) = loc; } - if (!prologue_locator && file_name) - prologue_locator = loc; - if (!NEXT_INSN (insn)) - epilogue_locator = loc; - if (active_insn_p (insn)) - INSN_LOCATOR (insn) = loc; - else if (GET_CODE (insn) == NOTE) - { - switch (NOTE_LINE_NUMBER (insn)) - { - case NOTE_INSN_BLOCK_BEG: - if (cfun->dont_emit_block_notes) - abort (); - block = NOTE_BLOCK (insn); - delete_insn (insn); - break; - case NOTE_INSN_BLOCK_END: - if (cfun->dont_emit_block_notes) - abort (); - block = BLOCK_SUPERCONTEXT (block); - if (block && TREE_CODE (block) == FUNCTION_DECL) - block = 0; - delete_insn (insn); - break; - default: - if (NOTE_LINE_NUMBER (insn) > 0) - { - line_number = NOTE_LINE_NUMBER (insn); - file_name = (char *)NOTE_SOURCE_FILE (insn); - } - break; - } - } - - if (cfun->dont_emit_block_notes) - check_block_change (insn, &block); } /* Tag the blocks with a depth number so that change_scope can find the common parent easily. */ set_block_levels (DECL_INITIAL (cfun->decl), 0); - if (cfun->dont_emit_block_notes) - free_block_changes (); + free_block_changes (); + return 0; +} + +struct tree_opt_pass pass_insn_locators_initialize = +{ + "locators", /* name */ + NULL, /* gate */ + insn_locators_initialize, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ +}; + +static unsigned int +into_cfg_layout_mode (void) +{ + cfg_layout_initialize (0); + return 0; +} + +static unsigned int +outof_cfg_layout_mode (void) +{ + basic_block bb; + + FOR_EACH_BB (bb) + if (bb->next_bb != EXIT_BLOCK_PTR) + bb->aux = bb->next_bb; + + cfg_layout_finalize (); + + return 0; } +struct tree_opt_pass pass_into_cfg_layout_mode = +{ + "into_cfglayout", /* name */ + NULL, /* gate */ + into_cfg_layout_mode, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ +}; + +struct tree_opt_pass pass_outof_cfg_layout_mode = +{ + "outof_cfglayout", /* name */ + NULL, /* gate */ + outof_cfg_layout_mode, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ +}; + /* For each lexical block, set BLOCK_NUMBER to the depth at which it is found in the block tree. */ @@ -358,7 +417,7 @@ set_block_levels (tree block, int level) } /* Return sope resulting from combination of S1 and S2. */ -tree +static tree choose_inner_scope (tree s1, tree s2) { if (!s1) @@ -382,8 +441,7 @@ change_scope (rtx orig_insn, tree s1, tree s2) while (ts1 != ts2) { - if (ts1 == NULL || ts2 == NULL) - abort (); + gcc_assert (ts1 && ts2); if (BLOCK_NUMBER (ts1) > BLOCK_NUMBER (ts2)) ts1 = BLOCK_SUPERCONTEXT (ts1); else if (BLOCK_NUMBER (ts1) < BLOCK_NUMBER (ts2)) @@ -419,7 +477,7 @@ change_scope (rtx orig_insn, tree s1, tree s2) static tree insn_scope (rtx insn) { - int max = VARRAY_ACTIVE_SIZE (block_locators_locs); + int max = VEC_length (int, block_locators_locs); int min = 0; int loc = INSN_LOCATOR (insn); @@ -440,7 +498,7 @@ insn_scope (rtx insn) while (1) { int pos = (min + max) / 2; - int tmp = VARRAY_INT (block_locators_locs, pos); + int tmp = VEC_index (int, block_locators_locs, pos); if (tmp <= loc && min != pos) min = pos; @@ -452,14 +510,14 @@ insn_scope (rtx insn) break; } } - return VARRAY_TREE (block_locators_blocks, min); + return VEC_index (tree, block_locators_blocks, min); } /* Return line number of the statement specified by the locator. */ int locator_line (int loc) { - int max = VARRAY_ACTIVE_SIZE (line_locators_locs); + int max = VEC_length (int, line_locators_locs); int min = 0; if (!max || !loc) @@ -467,7 +525,7 @@ locator_line (int loc) while (1) { int pos = (min + max) / 2; - int tmp = VARRAY_INT (line_locators_locs, pos); + int tmp = VEC_index (int, line_locators_locs, pos); if (tmp <= loc && min != pos) min = pos; @@ -479,7 +537,7 @@ locator_line (int loc) break; } } - return VARRAY_INT (line_locators_lines, min); + return VEC_index (int, line_locators_lines, min); } /* Return line number of the statement that produced this insn. */ @@ -493,7 +551,7 @@ insn_line (rtx insn) const char * locator_file (int loc) { - int max = VARRAY_ACTIVE_SIZE (file_locators_locs); + int max = VEC_length (int, file_locators_locs); int min = 0; if (!max || !loc) @@ -501,7 +559,7 @@ locator_file (int loc) while (1) { int pos = (min + max) / 2; - int tmp = VARRAY_INT (file_locators_locs, pos); + int tmp = VEC_index (int, file_locators_locs, pos); if (tmp <= loc && min != pos) min = pos; @@ -539,9 +597,15 @@ reemit_insn_block_notes (void) { tree this_block; + /* Avoid putting scope notes between jump table and its label. */ + if (JUMP_P (insn) + && (GET_CODE (PATTERN (insn)) == ADDR_VEC + || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) + continue; + this_block = insn_scope (insn); /* For sequences compute scope resulting from merging all scopes - of instructions nested inside. */ + of instructions nested inside. */ if (GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; @@ -570,13 +634,83 @@ reemit_insn_block_notes (void) reorder_blocks (); } + +/* Link the basic blocks in the correct order, compacting the basic + block queue while at it. This also clears the visited flag on + all basic blocks. If STAY_IN_CFGLAYOUT_MODE is false, this function + also clears the basic block header and footer fields. + + This function is usually called after a pass (e.g. tracer) finishes + some transformations while in cfglayout mode. The required sequence + of the basic blocks is in a linked list along the bb->aux field. + This functions re-links the basic block prev_bb and next_bb pointers + accordingly, and it compacts and renumbers the blocks. */ + +void +relink_block_chain (bool stay_in_cfglayout_mode) +{ + basic_block bb, prev_bb; + int index; + + /* Maybe dump the re-ordered sequence. */ + if (dump_file) + { + fprintf (dump_file, "Reordered sequence:\n"); + for (bb = ENTRY_BLOCK_PTR->next_bb, index = NUM_FIXED_BLOCKS; + bb; + bb = bb->aux, index++) + { + fprintf (dump_file, " %i ", index); + if (get_bb_original (bb)) + fprintf (dump_file, "duplicate of %i ", + get_bb_original (bb)->index); + else if (forwarder_block_p (bb) + && !LABEL_P (BB_HEAD (bb))) + fprintf (dump_file, "compensation "); + else + fprintf (dump_file, "bb %i ", bb->index); + fprintf (dump_file, " [%i]\n", bb->frequency); + } + } + + /* Now reorder the blocks. */ + prev_bb = ENTRY_BLOCK_PTR; + bb = ENTRY_BLOCK_PTR->next_bb; + for (; bb; prev_bb = bb, bb = bb->aux) + { + bb->prev_bb = prev_bb; + prev_bb->next_bb = bb; + } + prev_bb->next_bb = EXIT_BLOCK_PTR; + EXIT_BLOCK_PTR->prev_bb = prev_bb; + + /* Then, clean up the aux and visited fields. */ + FOR_ALL_BB (bb) + { + bb->aux = NULL; + bb->il.rtl->visited = 0; + if (!stay_in_cfglayout_mode) + bb->il.rtl->header = bb->il.rtl->footer = NULL; + } + + /* Maybe reset the original copy tables, they are not valid anymore + when we renumber the basic blocks in compact_blocks. If we are + are going out of cfglayout mode, don't re-allocate the tables. */ + free_original_copy_tables (); + if (stay_in_cfglayout_mode) + initialize_original_copy_tables (); + + /* Finally, put basic_block_info in the new order. */ + compact_blocks (); +} + + /* Given a reorder chain, rearrange the code to match. */ static void fixup_reorder_chain (void) { - basic_block bb, prev_bb; - int index; + basic_block bb; rtx insn = NULL; if (cfg_layout_function_header) @@ -590,18 +724,16 @@ fixup_reorder_chain (void) /* First do the bulk reordering -- rechain the blocks without regard to the needed changes to jumps and labels. */ - for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0; - bb != 0; - bb = bb->rbi->next, index++) + for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = bb->aux) { - if (bb->rbi->header) + if (bb->il.rtl->header) { if (insn) - NEXT_INSN (insn) = bb->rbi->header; + NEXT_INSN (insn) = bb->il.rtl->header; else - set_first_insn (bb->rbi->header); - PREV_INSN (bb->rbi->header) = insn; - insn = bb->rbi->header; + set_first_insn (bb->il.rtl->header); + PREV_INSN (bb->il.rtl->header) = insn; + insn = bb->il.rtl->header; while (NEXT_INSN (insn)) insn = NEXT_INSN (insn); } @@ -611,18 +743,15 @@ fixup_reorder_chain (void) set_first_insn (BB_HEAD (bb)); PREV_INSN (BB_HEAD (bb)) = insn; insn = BB_END (bb); - if (bb->rbi->footer) + if (bb->il.rtl->footer) { - NEXT_INSN (insn) = bb->rbi->footer; - PREV_INSN (bb->rbi->footer) = insn; + NEXT_INSN (insn) = bb->il.rtl->footer; + PREV_INSN (bb->il.rtl->footer) = insn; while (NEXT_INSN (insn)) insn = NEXT_INSN (insn); } } - if (index != n_basic_blocks) - abort (); - NEXT_INSN (insn) = cfg_layout_function_footer; if (cfg_layout_function_footer) PREV_INSN (cfg_layout_function_footer) = insn; @@ -634,77 +763,52 @@ fixup_reorder_chain (void) #ifdef ENABLE_CHECKING verify_insn_chain (); #endif - delete_dead_jumptables (); /* Now add jumps and labels as needed to match the blocks new outgoing edges. */ - for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = bb->rbi->next) + for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = bb->aux) { edge e_fall, e_taken, e; rtx bb_end_insn; basic_block nb; - basic_block old_bb; + edge_iterator ei; - if (bb->succ == NULL) + if (EDGE_COUNT (bb->succs) == 0) continue; /* Find the old fallthru edge, and another non-EH edge for a taken jump. */ e_taken = e_fall = NULL; - for (e = bb->succ; e ; e = e->succ_next) + + FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALLTHRU) e_fall = e; else if (! (e->flags & EDGE_EH)) e_taken = e; bb_end_insn = BB_END (bb); - if (GET_CODE (bb_end_insn) == JUMP_INSN) + if (JUMP_P (bb_end_insn)) { if (any_condjump_p (bb_end_insn)) { /* If the old fallthru is still next, nothing to do. */ - if (bb->rbi->next == e_fall->dest - || e_fall->dest == EXIT_BLOCK_PTR) + if (bb->aux == e_fall->dest + || e_fall->dest == EXIT_BLOCK_PTR) continue; /* The degenerated case of conditional jump jumping to the next - instruction can happen on target having jumps with side - effects. - - Create temporarily the duplicated edge representing branch. - It will get unidentified by force_nonfallthru_and_redirect - that would otherwise get confused by fallthru edge not pointing - to the next basic block. */ + instruction can happen for jumps with side effects. We need + to construct a forwarder block and this will be done just + fine by force_nonfallthru below. */ if (!e_taken) - { - rtx note; - edge e_fake; + ; - e_fake = unchecked_make_edge (bb, e_fall->dest, 0); - - if (!redirect_jump (BB_END (bb), block_label (bb), 0)) - abort (); - note = find_reg_note (BB_END (bb), REG_BR_PROB, NULL_RTX); - if (note) - { - int prob = INTVAL (XEXP (note, 0)); - - e_fake->probability = prob; - e_fake->count = e_fall->count * prob / REG_BR_PROB_BASE; - e_fall->probability -= e_fall->probability; - e_fall->count -= e_fake->count; - if (e_fall->probability < 0) - e_fall->probability = 0; - if (e_fall->count < 0) - e_fall->count = 0; - } - } - /* There is one special case: if *neither* block is next, + /* There is another special case: if *neither* block is next, such as happens at the very end of a function, then we'll need to add a new unconditional jump. Choose the taken edge based on known or assumed probability. */ - else if (bb->rbi->next != e_taken->dest) + else if (bb->aux != e_taken->dest) { rtx note = find_reg_note (bb_end_insn, REG_BR_PROB, 0); @@ -717,8 +821,8 @@ fixup_reorder_chain (void) { e_fall->flags &= ~EDGE_FALLTHRU; #ifdef ENABLE_CHECKING - if (!could_fall_through (e_taken->src, e_taken->dest)) - abort (); + gcc_assert (could_fall_through + (e_taken->src, e_taken->dest)); #endif e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); @@ -728,7 +832,8 @@ fixup_reorder_chain (void) /* If the "jumping" edge is a crossing edge, and the fall through edge is non-crossing, leave things as they are. */ - else if (e_taken->crossing_edge && !e_fall->crossing_edge) + else if ((e_taken->flags & EDGE_CROSSING) + && !(e_fall->flags & EDGE_CROSSING)) continue; /* Otherwise we can try to invert the jump. This will @@ -740,32 +845,21 @@ fixup_reorder_chain (void) { e_fall->flags &= ~EDGE_FALLTHRU; #ifdef ENABLE_CHECKING - if (!could_fall_through (e_taken->src, e_taken->dest)) - abort (); + gcc_assert (could_fall_through + (e_taken->src, e_taken->dest)); #endif e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); continue; } } - else if (returnjump_p (bb_end_insn)) - continue; else { - /* Otherwise we have some switch or computed jump. In the - 99% case, there should not have been a fallthru edge. */ - if (! e_fall) - continue; - -#ifdef CASE_DROPS_THROUGH - /* Except for VAX. Since we didn't have predication for the - tablejump, the fallthru block should not have moved. */ - if (bb->rbi->next == e_fall->dest) - continue; - bb_end_insn = skip_insns_after_block (bb); -#else - abort (); -#endif + /* Otherwise we have some return, switch or computed + jump. In the 99% case, there should not have been a + fallthru edge. */ + gcc_assert (returnjump_p (bb_end_insn) || !e_fall); + continue; } } else @@ -777,7 +871,7 @@ fixup_reorder_chain (void) continue; /* If the fallthru block is still next, nothing to do. */ - if (bb->rbi->next == e_fall->dest) + if (bb->aux == e_fall->dest) continue; /* A fallthru to exit block. */ @@ -789,107 +883,43 @@ fixup_reorder_chain (void) nb = force_nonfallthru (e_fall); if (nb) { - initialize_bb_rbi (nb); - nb->rbi->visited = 1; - nb->rbi->next = bb->rbi->next; - bb->rbi->next = nb; + nb->il.rtl->visited = 1; + nb->aux = bb->aux; + bb->aux = nb; /* Don't process this new block. */ - old_bb = bb; bb = nb; - - /* Make sure new bb is tagged for correct section (same as - fall-thru source). */ - e_fall->src->partition = bb->pred->src->partition; - if (flag_reorder_blocks_and_partition) - { - if (bb->pred->src->partition == COLD_PARTITION) - { - rtx new_note; - rtx note = BB_HEAD (e_fall->src); - - while (!INSN_P (note) - && note != BB_END (e_fall->src)) - note = NEXT_INSN (note); - - new_note = emit_note_before - (NOTE_INSN_UNLIKELY_EXECUTED_CODE, - note); - NOTE_BASIC_BLOCK (new_note) = bb; - } - if (GET_CODE (BB_END (bb)) == JUMP_INSN - && !any_condjump_p (BB_END (bb)) - && bb->succ->crossing_edge ) - REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST - (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb))); - } - } - } - - /* Put basic_block_info in the new order. */ - if (dump_file) - { - fprintf (dump_file, "Reordered sequence:\n"); - for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0; - bb; - bb = bb->rbi->next, index++) - { - fprintf (dump_file, " %i ", index); - if (bb->rbi->original) - fprintf (dump_file, "duplicate of %i ", - bb->rbi->original->index); - else if (forwarder_block_p (bb) - && GET_CODE (BB_HEAD (bb)) != CODE_LABEL) - fprintf (dump_file, "compensation "); - else - fprintf (dump_file, "bb %i ", bb->index); - fprintf (dump_file, " [%i]\n", bb->frequency); + /* Make sure new bb is tagged for correct section (same as + fall-thru source, since you cannot fall-throu across + section boundaries). */ + BB_COPY_PARTITION (e_fall->src, single_pred (bb)); + if (flag_reorder_blocks_and_partition + && targetm.have_named_sections + && JUMP_P (BB_END (bb)) + && !any_condjump_p (BB_END (bb)) + && (EDGE_SUCC (bb, 0)->flags & EDGE_CROSSING)) + REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST + (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb))); } } - prev_bb = ENTRY_BLOCK_PTR; - bb = ENTRY_BLOCK_PTR->next_bb; - index = 0; - - for (; bb; prev_bb = bb, bb = bb->rbi->next, index ++) - { - bb->index = index; - BASIC_BLOCK (index) = bb; - - update_unlikely_executed_notes (bb); - - bb->prev_bb = prev_bb; - prev_bb->next_bb = bb; - } - prev_bb->next_bb = EXIT_BLOCK_PTR; - EXIT_BLOCK_PTR->prev_bb = prev_bb; + relink_block_chain (/*stay_in_cfglayout_mode=*/false); /* Annoying special case - jump around dead jumptables left in the code. */ FOR_EACH_BB (bb) { edge e; - for (e = bb->succ; e && !(e->flags & EDGE_FALLTHRU); e = e->succ_next) - continue; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) + if (e->flags & EDGE_FALLTHRU) + break; + if (e && !can_fallthru (e->src, e->dest)) force_nonfallthru (e); } } -/* Update the basic block number information in any - NOTE_INSN_UNLIKELY_EXECUTED_CODE notes within the basic block. */ - -static void -update_unlikely_executed_notes (basic_block bb) -{ - rtx cur_insn; - - for (cur_insn = BB_HEAD (bb); cur_insn != BB_END (bb); - cur_insn = NEXT_INSN (cur_insn)) - if (GET_CODE (cur_insn) == NOTE - && NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_UNLIKELY_EXECUTED_CODE) - NOTE_BASIC_BLOCK (cur_insn) = bb; -} - /* Perform sanity checks on the insn chain. 1. Check that next/prev pointers are consistent in both the forward and reverse direction. @@ -905,20 +935,16 @@ verify_insn_chain (void) for (prevx = NULL, insn_cnt1 = 1, x = get_insns (); x != 0; prevx = x, insn_cnt1++, x = NEXT_INSN (x)) - if (PREV_INSN (x) != prevx) - abort (); + gcc_assert (PREV_INSN (x) == prevx); - if (prevx != get_last_insn ()) - abort (); + gcc_assert (prevx == get_last_insn ()); for (nextx = NULL, insn_cnt2 = 1, x = get_last_insn (); x != 0; nextx = x, insn_cnt2++, x = PREV_INSN (x)) - if (NEXT_INSN (x) != nextx) - abort (); + gcc_assert (NEXT_INSN (x) == nextx); - if (insn_cnt1 != insn_cnt2) - abort (); + gcc_assert (insn_cnt1 == insn_cnt2); } /* If we have assembler epilogues, the block falling through to exit must @@ -928,18 +954,19 @@ static void fixup_fallthru_exit_predecessor (void) { edge e; + edge_iterator ei; 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 (); + /* This transformation is not valid before reload, because we might + separate a call from the instruction that copies the return + value. */ + gcc_assert (reload_completed); - for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) if (e->flags & EDGE_FALLTHRU) bb = e->src; - if (bb && bb->rbi->next) + if (bb && bb->aux) { basic_block c = ENTRY_BLOCK_PTR->next_bb; @@ -948,22 +975,21 @@ fixup_fallthru_exit_predecessor (void) 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; + bb->aux = c->aux; + c->aux = bb; + bb->il.rtl->footer = c->il.rtl->footer; + c->il.rtl->footer = NULL; } - while (c->rbi->next != bb) - c = c->rbi->next; + while (c->aux != bb) + c = c->aux; - c->rbi->next = bb->rbi->next; - while (c->rbi->next) - c = c->rbi->next; + c->aux = bb->aux; + while (c->aux) + c = c->aux; - c->rbi->next = bb; - bb->rbi->next = NULL; + c->aux = bb; + bb->aux = NULL; } } @@ -1039,54 +1065,38 @@ duplicate_insn_chain (rtx from, rtx to) switch (NOTE_LINE_NUMBER (insn)) { /* In case prologue is empty and function contain label - in first BB, we may want to copy the block. */ + in first BB, we may want to copy the block. */ case NOTE_INSN_PROLOGUE_END: - case NOTE_INSN_LOOP_VTOP: - case NOTE_INSN_LOOP_CONT: - case NOTE_INSN_LOOP_BEG: - case NOTE_INSN_LOOP_END: - /* Strip down the loop notes - we don't really want to keep - them consistent in loop copies. */ case NOTE_INSN_DELETED: case NOTE_INSN_DELETED_LABEL: /* No problem to strip these. */ case NOTE_INSN_EPILOGUE_BEG: - case NOTE_INSN_FUNCTION_END: /* Debug code expect these notes to exist just once. - Keep them in the master copy. - ??? It probably makes more sense to duplicate them for each - epilogue copy. */ + Keep them in the master copy. + ??? It probably makes more sense to duplicate them for each + epilogue copy. */ case NOTE_INSN_FUNCTION_BEG: /* There is always just single entry to function. */ case NOTE_INSN_BASIC_BLOCK: break; - /* There is no purpose to duplicate prologue. */ - case NOTE_INSN_BLOCK_BEG: - case NOTE_INSN_BLOCK_END: - /* The BLOCK_BEG/BLOCK_END notes should be eliminated when BB - reordering is in the progress. */ - case NOTE_INSN_EH_REGION_BEG: - case NOTE_INSN_EH_REGION_END: - /* Should never exist at BB duplication time. */ - abort (); - break; - case NOTE_INSN_REPEATED_LINE_NUMBER: - case NOTE_INSN_UNLIKELY_EXECUTED_CODE: + case NOTE_INSN_SWITCH_TEXT_SECTIONS: emit_note_copy (insn); break; default: - if (NOTE_LINE_NUMBER (insn) < 0) - abort (); + /* All other notes should have already been eliminated. + */ + gcc_assert (NOTE_LINE_NUMBER (insn) >= 0); + /* It is possible that no_line_number is set and the note - won't be emitted. */ + won't be emitted. */ emit_note_copy (insn); } break; default: - abort (); + gcc_unreachable (); } } insn = NEXT_INSN (last); @@ -1112,57 +1122,57 @@ cfg_layout_duplicate_bb (basic_block bb) insn ? get_last_insn () : NULL, EXIT_BLOCK_PTR->prev_bb); - if (bb->rbi->header) + BB_COPY_PARTITION (new_bb, bb); + if (bb->il.rtl->header) { - insn = bb->rbi->header; + insn = bb->il.rtl->header; while (NEXT_INSN (insn)) insn = NEXT_INSN (insn); - insn = duplicate_insn_chain (bb->rbi->header, insn); + insn = duplicate_insn_chain (bb->il.rtl->header, insn); if (insn) - new_bb->rbi->header = unlink_insn_chain (insn, get_last_insn ()); + new_bb->il.rtl->header = unlink_insn_chain (insn, get_last_insn ()); } - if (bb->rbi->footer) + if (bb->il.rtl->footer) { - insn = bb->rbi->footer; + insn = bb->il.rtl->footer; while (NEXT_INSN (insn)) insn = NEXT_INSN (insn); - insn = duplicate_insn_chain (bb->rbi->footer, insn); + insn = duplicate_insn_chain (bb->il.rtl->footer, insn); if (insn) - new_bb->rbi->footer = unlink_insn_chain (insn, get_last_insn ()); + new_bb->il.rtl->footer = unlink_insn_chain (insn, get_last_insn ()); } - if (bb->global_live_at_start) + if (bb->il.rtl->global_live_at_start) { - new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack); - new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack); - COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_start); - COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end); + new_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack); + new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack); + COPY_REG_SET (new_bb->il.rtl->global_live_at_start, + bb->il.rtl->global_live_at_start); + COPY_REG_SET (new_bb->il.rtl->global_live_at_end, + bb->il.rtl->global_live_at_end); } return new_bb; } -/* Main entry point to this module - initialize the data structures for - CFG layout changes. It keeps LOOPS up-to-date if not null. */ +/* Main entry point to this module - initialize the datastructures for + CFG layout changes. It keeps LOOPS up-to-date if not null. + + FLAGS is a set of additional flags to pass to cleanup_cfg(). It should + include CLEANUP_UPDATE_LIFE if liveness information must be kept up + to date. */ void -cfg_layout_initialize (void) +cfg_layout_initialize (unsigned int flags) { - basic_block bb; - - /* Our algorithm depends on fact that there are no dead jumptables - around the code. */ - alloc_rbi_pool (); - - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) - initialize_bb_rbi (bb); + initialize_original_copy_tables (); cfg_layout_rtl_register_cfg_hooks (); record_effective_endpoints (); - cleanup_cfg (CLEANUP_CFGLAYOUT); + cleanup_cfg (CLEANUP_CFGLAYOUT | flags); } /* Splits superblocks. */ @@ -1193,14 +1203,12 @@ break_superblocks (void) free (superblocks); } -/* Finalize the changes: reorder insn list according to the sequence, enter - compensation code, rebuild scope forest. */ +/* Finalize the changes: reorder insn list according to the sequence specified + by aux pointers, enter compensation code, rebuild scope forest. */ void cfg_layout_finalize (void) { - basic_block bb; - #ifdef ENABLE_CHECKING verify_flow_info (); #endif @@ -1213,17 +1221,11 @@ cfg_layout_finalize (void) fixup_fallthru_exit_predecessor (); fixup_reorder_chain (); -#ifdef ENABLE_CHECKING - verify_insn_chain (); -#endif - - free_rbi_pool (); - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) - bb->rbi = NULL; - - break_superblocks (); + rebuild_jump_labels (get_insns ()); + delete_dead_jumptables (); #ifdef ENABLE_CHECKING + verify_insn_chain (); verify_flow_info (); #endif } @@ -1237,14 +1239,15 @@ can_copy_bbs_p (basic_block *bbs, unsigned n) int ret = true; for (i = 0; i < n; i++) - bbs[i]->rbi->duplicated = 1; + bbs[i]->flags |= BB_DUPLICATED; for (i = 0; i < n; i++) { /* In case we should redirect abnormal edge during duplication, fail. */ - for (e = bbs[i]->succ; e; e = e->succ_next) + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bbs[i]->succs) if ((e->flags & EDGE_ABNORMAL) - && e->dest->rbi->duplicated) + && (e->dest->flags & BB_DUPLICATED)) { ret = false; goto end; @@ -1259,7 +1262,7 @@ can_copy_bbs_p (basic_block *bbs, unsigned n) end: for (i = 0; i < n; i++) - bbs[i]->rbi->duplicated = 0; + bbs[i]->flags &= ~BB_DUPLICATED; return ret; } @@ -1277,12 +1280,15 @@ end: is copied, we do not set the new blocks as header or latch. Created copies of N_EDGES edges in array EDGES are stored in array NEW_EDGES, - also in the same order. */ + also in the same order. + + Newly created basic blocks are put after the basic block AFTER in the + instruction stream, and the order of the blocks in BBS array is preserved. */ void copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs, - edge *edges, unsigned n_edges, edge *new_edges, - struct loop *base) + edge *edges, unsigned num_edges, edge *new_edges, + struct loop *base, basic_block after) { unsigned i, j; basic_block bb, new_bb, dom_bb; @@ -1293,11 +1299,10 @@ copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs, { /* Duplicate. */ bb = bbs[i]; - new_bb = new_bbs[i] = duplicate_block (bb, NULL); - bb->rbi->duplicated = 1; - /* Add to loop. */ - add_bb_to_loop (new_bb, bb->loop_father->copy); - /* Possibly set header. */ + new_bb = new_bbs[i] = duplicate_block (bb, NULL, after); + after = new_bb; + bb->flags |= BB_DUPLICATED; + /* Possibly set loop header. */ if (bb->loop_father->header == bb && bb->loop_father != base) new_bb->loop_father->header = new_bb; /* Or latch. */ @@ -1312,36 +1317,37 @@ copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs, new_bb = new_bbs[i]; dom_bb = get_immediate_dominator (CDI_DOMINATORS, bb); - if (dom_bb->rbi->duplicated) + if (dom_bb->flags & BB_DUPLICATED) { - dom_bb = dom_bb->rbi->copy; + dom_bb = get_bb_copy (dom_bb); set_immediate_dominator (CDI_DOMINATORS, new_bb, dom_bb); } } /* Redirect edges. */ - for (j = 0; j < n_edges; j++) + for (j = 0; j < num_edges; j++) new_edges[j] = NULL; for (i = 0; i < n; i++) { + edge_iterator ei; new_bb = new_bbs[i]; bb = bbs[i]; - for (e = new_bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, new_bb->succs) { - for (j = 0; j < n_edges; j++) + for (j = 0; j < num_edges; j++) if (edges[j] && edges[j]->src == bb && edges[j]->dest == e->dest) new_edges[j] = e; - if (!e->dest->rbi->duplicated) + if (!(e->dest->flags & BB_DUPLICATED)) continue; - redirect_edge_and_branch_force (e, e->dest->rbi->copy); + redirect_edge_and_branch_force (e, get_bb_copy (e->dest)); } } /* Clear information about duplicates. */ for (i = 0; i < n; i++) - bbs[i]->rbi->duplicated = 0; + bbs[i]->flags &= ~BB_DUPLICATED; } #include "gt-cfglayout.h"