X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcfglayout.c;h=22d3d87e68b7d264bdf134f7f438dfd63d766469;hb=6ef745dee79d8e5f140f274ce13a1fd22d126cb8;hp=ef085fcf6d4efab244bde81a2c6652aab26567f8;hpb=4aaec1807f556b5b8de98cbda59cb17bdea008c4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index ef085fcf6d4..22d3d87e68b 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -1,11 +1,12 @@ /* Basic block reordering routines for the GNU compiler. - Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -14,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" @@ -33,11 +33,14 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "cfglayout.h" #include "cfgloop.h" #include "target.h" +#include "common/common-target.h" #include "ggc.h" #include "alloc-pool.h" #include "flags.h" #include "tree-pass.h" +#include "df.h" #include "vecprim.h" +#include "emit-rtl.h" /* Holds the interesting trailing notes for the function. */ rtx cfg_layout_function_footer; @@ -48,12 +51,10 @@ static void record_effective_endpoints (void); static rtx label_for_bb (basic_block); static void fixup_reorder_chain (void); -static void set_block_levels (tree, int); static void change_scope (rtx, tree, tree); void verify_insn_chain (void); static void fixup_fallthru_exit_predecessor (void); -static tree insn_scope (rtx); rtx unlink_insn_chain (rtx first, rtx last) @@ -99,15 +100,11 @@ skip_insns_after_block (basic_block bb) continue; case NOTE: - switch (NOTE_LINE_NUMBER (insn)) + switch (NOTE_KIND (insn)) { case NOTE_INSN_BLOCK_END: - last_insn = insn; + gcc_unreachable (); continue; - case NOTE_INSN_DELETED: - case NOTE_INSN_DELETED_LABEL: - continue; - default: continue; break; @@ -116,9 +113,7 @@ skip_insns_after_block (basic_block bb) case CODE_LABEL: if (NEXT_INSN (insn) - && JUMP_P (NEXT_INSN (insn)) - && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC - || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)) + && JUMP_TABLE_DATA_P (NEXT_INSN (insn))) { insn = NEXT_INSN (insn); last_insn = insn; @@ -147,11 +142,14 @@ skip_insns_after_block (basic_block bb) { prev = PREV_INSN (insn); if (NOTE_P (insn)) - switch (NOTE_LINE_NUMBER (insn)) + switch (NOTE_KIND (insn)) { case NOTE_INSN_BLOCK_END: + gcc_unreachable (); + break; case NOTE_INSN_DELETED: case NOTE_INSN_DELETED_LABEL: + case NOTE_INSN_DELETED_DEBUG_LABEL: continue; default: reorder_insns (insn, insn, last_insn); @@ -192,7 +190,7 @@ record_effective_endpoints (void) for (insn = get_insns (); insn && NOTE_P (insn) - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK; + && NOTE_KIND (insn) != NOTE_INSN_BASIC_BLOCK; insn = NEXT_INSN (insn)) continue; /* No basic blocks at all? */ @@ -232,120 +230,119 @@ record_effective_endpoints (void) than the following one. Similarly for the other properties. */ 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; +static VEC(int,heap) *locations_locators_locs; +DEF_VEC_O(location_t); +DEF_VEC_ALLOC_O(location_t,heap); +static VEC(location_t,heap) *locations_locators_vals; int prologue_locator; int epilogue_locator; -/* During the RTL expansion the lexical blocks and line numbers are - represented via INSN_NOTEs. Replace them by representation using - INSN_LOCATORs. */ +/* Hold current location information and last location information, so the + datastructures are built lazily only when some instructions in given + place are needed. */ +static location_t curr_location, last_location; +static tree curr_block, last_block; +static int curr_rtl_loc = -1; -unsigned int -insn_locators_initialize (void) +/* Allocate insn locator datastructure. */ +void +insn_locators_alloc (void) { - tree block = NULL; - tree last_block = NULL; - rtx insn, next; - int loc = 0; - int line_number = 0, last_line_number = 0; - const char *file_name = NULL, *last_file_name = NULL; - prologue_locator = epilogue_locator = 0; 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"); + locations_locators_locs = VEC_alloc (int, heap, 32); + locations_locators_vals = VEC_alloc (location_t, heap, 32); + + curr_location = UNKNOWN_LOCATION; + last_location = UNKNOWN_LOCATION; + curr_block = NULL; + last_block = NULL; + curr_rtl_loc = 0; +} - for (insn = get_insns (); insn; insn = next) - { - int active = 0; +/* At the end of emit stage, clear current location. */ +void +insn_locators_finalize (void) +{ + if (curr_rtl_loc >= 0) + epilogue_locator = curr_insn_locator (); + curr_rtl_loc = -1; +} - next = NEXT_INSN (insn); +/* Allocate insn locator datastructure. */ +void +insn_locators_free (void) +{ + prologue_locator = epilogue_locator = 0; - 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); + VEC_free (int, heap, block_locators_locs); + VEC_free (tree,gc, block_locators_blocks); + VEC_free (int, heap, locations_locators_locs); + VEC_free (location_t, heap, locations_locators_vals); +} - check_block_change (insn, &block); - if (active - || !next - || (!prologue_locator && file_name)) - { - if (last_block != block) - { - loc++; - 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++; - 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++; - 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; - } - } +/* Set current location. */ +void +set_curr_insn_source_location (location_t location) +{ + /* IV opts calls into RTL expansion to compute costs of operations. At this + time locators are not initialized. */ + if (curr_rtl_loc == -1) + return; + curr_location = location; +} - /* 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); +/* Get current location. */ +location_t +get_curr_insn_source_location (void) +{ + return curr_location; +} - free_block_changes (); - return 0; +/* Set current scope block. */ +void +set_curr_insn_block (tree b) +{ + /* IV opts calls into RTL expansion to compute costs of operations. At this + time locators are not initialized. */ + if (curr_rtl_loc == -1) + return; + if (b) + curr_block = b; } -struct tree_opt_pass pass_insn_locators_initialize = +/* Get current scope block. */ +tree +get_curr_insn_block (void) { - "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 */ -}; + return curr_block; +} + +/* Return current insn locator. */ +int +curr_insn_locator (void) +{ + if (curr_rtl_loc == -1 || curr_location == UNKNOWN_LOCATION) + return 0; + if (last_block != curr_block) + { + curr_rtl_loc++; + VEC_safe_push (int, heap, block_locators_locs, curr_rtl_loc); + VEC_safe_push (tree, gc, block_locators_blocks, curr_block); + last_block = curr_block; + } + if (last_location != curr_location) + { + curr_rtl_loc++; + VEC_safe_push (int, heap, locations_locators_locs, curr_rtl_loc); + VEC_safe_push (location_t, heap, locations_locators_vals, &curr_location); + last_location = curr_location; + } + return curr_rtl_loc; +} static unsigned int into_cfg_layout_mode (void) @@ -368,55 +365,45 @@ outof_cfg_layout_mode (void) return 0; } -struct tree_opt_pass pass_into_cfg_layout_mode = +struct rtl_opt_pass pass_into_cfg_layout_mode = { + { + RTL_PASS, "into_cfglayout", /* name */ NULL, /* gate */ into_cfg_layout_mode, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_CFG, /* tv_id */ 0, /* properties_required */ - 0, /* properties_provided */ + PROP_cfglayout, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ + 0 /* todo_flags_finish */ + } }; -struct tree_opt_pass pass_outof_cfg_layout_mode = +struct rtl_opt_pass pass_outof_cfg_layout_mode = { + { + RTL_PASS, "outof_cfglayout", /* name */ NULL, /* gate */ outof_cfg_layout_mode, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_CFG, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ - 0, /* properties_destroyed */ + PROP_cfglayout, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 0 /* letter */ + 0 /* todo_flags_finish */ + } }; - -/* For each lexical block, set BLOCK_NUMBER to the depth at which it is - found in the block tree. */ - -static void -set_block_levels (tree block, int level) -{ - while (block) - { - BLOCK_NUMBER (block) = level; - set_block_levels (BLOCK_SUBBLOCKS (block), level + 1); - block = BLOCK_CHAIN (block); - } -} -/* Return sope resulting from combination of S1 and S2. */ +/* Return scope resulting from combination of S1 and S2. */ static tree choose_inner_scope (tree s1, tree s2) { @@ -473,13 +460,12 @@ change_scope (rtx orig_insn, tree s1, tree s2) } } -/* Return lexical scope block insn belong to. */ +/* Return lexical scope block locator belongs to. */ static tree -insn_scope (rtx insn) +locator_scope (int loc) { int max = VEC_length (int, block_locators_locs); int min = 0; - int loc = INSN_LOCATOR (insn); /* When block_locators_locs was initialized, the pro- and epilogue insns didn't exist yet and can therefore not be found this way. @@ -513,19 +499,24 @@ insn_scope (rtx insn) return VEC_index (tree, block_locators_blocks, min); } +/* Return lexical scope block insn belongs to. */ +tree +insn_scope (const_rtx insn) +{ + return locator_scope (INSN_LOCATOR (insn)); +} + /* Return line number of the statement specified by the locator. */ -int -locator_line (int loc) +location_t +locator_location (int loc) { - int max = VEC_length (int, line_locators_locs); + int max = VEC_length (int, locations_locators_locs); int min = 0; - if (!max || !loc) - return 0; while (1) { int pos = (min + max) / 2; - int tmp = VEC_index (int, line_locators_locs, pos); + int tmp = VEC_index (int, locations_locators_locs, pos); if (tmp <= loc && min != pos) min = pos; @@ -537,12 +528,24 @@ locator_line (int loc) break; } } - return VEC_index (int, line_locators_lines, min); + return *VEC_index (location_t, locations_locators_vals, min); +} + +/* Return source line of the statement that produced this insn. */ +int +locator_line (int loc) +{ + expanded_location xloc; + if (!loc) + return 0; + else + xloc = expand_location (locator_location (loc)); + return xloc.line; } /* Return line number of the statement that produced this insn. */ int -insn_line (rtx insn) +insn_line (const_rtx insn) { return locator_line (INSN_LOCATOR (insn)); } @@ -551,36 +554,32 @@ insn_line (rtx insn) const char * locator_file (int loc) { - int max = VEC_length (int, file_locators_locs); - int min = 0; - - if (!max || !loc) - return NULL; - while (1) - { - int pos = (min + max) / 2; - int tmp = VEC_index (int, file_locators_locs, pos); - - if (tmp <= loc && min != pos) - min = pos; - else if (tmp > loc && max != pos) - max = pos; - else - { - min = pos; - break; - } - } - return VARRAY_CHAR_PTR (file_locators_files, min); + expanded_location xloc; + if (!loc) + return 0; + else + xloc = expand_location (locator_location (loc)); + return xloc.file; } /* Return source file of the statement that produced this insn. */ const char * -insn_file (rtx insn) +insn_file (const_rtx insn) { return locator_file (INSN_LOCATOR (insn)); } +/* Return true if LOC1 and LOC2 locators have the same location and scope. */ +bool +locator_eq (int loc1, int loc2) +{ + if (loc1 == loc2) + return true; + if (locator_location (loc1) != locator_location (loc2)) + return false; + return locator_scope (loc1) == locator_scope (loc2); +} + /* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based on the scope tree and the newly reordered instructions. */ @@ -598,9 +597,7 @@ 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)) + if (JUMP_TABLE_DATA_P (insn)) continue; this_block = insn_scope (insn); @@ -634,13 +631,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 = (basic_block) 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 = (basic_block) 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) @@ -654,9 +721,7 @@ 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 = NUM_FIXED_BLOCKS; - bb != 0; - bb = bb->aux, index++) + for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = (basic_block) bb->aux) { if (bb->il.rtl->header) { @@ -684,8 +749,6 @@ fixup_reorder_chain (void) } } - gcc_assert (index == n_basic_blocks); - NEXT_INSN (insn) = cfg_layout_function_footer; if (cfg_layout_function_footer) PREV_INSN (cfg_layout_function_footer) = insn; @@ -701,11 +764,12 @@ fixup_reorder_chain (void) /* Now add jumps and labels as needed to match the blocks new outgoing edges. */ - for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = bb->aux) + for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = (basic_block) bb->aux) { edge e_fall, e_taken, e; rtx bb_end_insn; - basic_block nb; + rtx ret_label = NULL_RTX; + basic_block nb, src_bb; edge_iterator ei; if (EDGE_COUNT (bb->succs) == 0) @@ -724,8 +788,21 @@ fixup_reorder_chain (void) bb_end_insn = BB_END (bb); if (JUMP_P (bb_end_insn)) { + ret_label = JUMP_LABEL (bb_end_insn); if (any_condjump_p (bb_end_insn)) { + /* This might happen if the conditional jump has side + effects and could therefore not be optimized away. + Make the basic block to end with a barrier in order + to prevent rtl_verify_flow_info from complaining. */ + if (!e_fall) + { + gcc_assert (!onlyjump_p (bb_end_insn) + || returnjump_p (bb_end_insn)); + bb->il.rtl->footer = emit_barrier_after (bb_end_insn); + continue; + } + /* If the old fallthru is still next, nothing to do. */ if (bb->aux == e_fall->dest || e_fall->dest == EXIT_BLOCK_PTR) @@ -754,10 +831,8 @@ fixup_reorder_chain (void) : label_for_bb (e_fall->dest)), 0)) { e_fall->flags &= ~EDGE_FALLTHRU; -#ifdef ENABLE_CHECKING - gcc_assert (could_fall_through - (e_taken->src, e_taken->dest)); -#endif + gcc_checking_assert (could_fall_through + (e_taken->src, e_taken->dest)); e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); e = e_fall, e_fall = e_taken, e_taken = e; @@ -778,15 +853,25 @@ fixup_reorder_chain (void) : label_for_bb (e_fall->dest)), 0)) { e_fall->flags &= ~EDGE_FALLTHRU; -#ifdef ENABLE_CHECKING - gcc_assert (could_fall_through - (e_taken->src, e_taken->dest)); -#endif + gcc_checking_assert (could_fall_through + (e_taken->src, e_taken->dest)); e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); continue; } } + else if (extract_asm_operands (PATTERN (bb_end_insn)) != NULL) + { + /* If the old fallthru is still next or if + asm goto doesn't have a fallthru (e.g. when followed by + __builtin_unreachable ()), nothing to do. */ + if (! e_fall + || bb->aux == e_fall->dest + || e_fall->dest == EXIT_BLOCK_PTR) + continue; + + /* Otherwise we'll have to use the fallthru fixup below. */ + } else { /* Otherwise we have some return, switch or computed @@ -813,8 +898,11 @@ fixup_reorder_chain (void) continue; } - /* We got here if we need to add a new jump insn. */ - nb = force_nonfallthru (e_fall); + /* We got here if we need to add a new jump insn. + Note force_nonfallthru can delete E_FALL and thus we have to + save E_FALL->src prior to the call to force_nonfallthru. */ + src_bb = e_fall->src; + nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label); if (nb) { nb->il.rtl->visited = 1; @@ -824,69 +912,95 @@ fixup_reorder_chain (void) bb = nb; /* Make sure new bb is tagged for correct section (same as - fall-thru source, since you cannot fall-throu across + fall-thru source, since you cannot fall-thru across section boundaries). */ - BB_COPY_PARTITION (e_fall->src, single_pred (bb)); + BB_COPY_PARTITION (src_bb, single_pred (bb)); if (flag_reorder_blocks_and_partition - && targetm.have_named_sections + && targetm_common.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))); - } - } - - /* 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 = 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); + add_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX); } } - prev_bb = ENTRY_BLOCK_PTR; - bb = ENTRY_BLOCK_PTR->next_bb; - index = NUM_FIXED_BLOCKS; - - for (; bb; prev_bb = bb, bb = bb->aux, index ++) - { - bb->index = index; - SET_BASIC_BLOCK (index, 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; - edge_iterator ei; - - FOR_EACH_EDGE (e, ei, bb->succs) - if (e->flags & EDGE_FALLTHRU) - break; + edge e = find_fallthru_edge (bb->succs); if (e && !can_fallthru (e->src, e->dest)) force_nonfallthru (e); } + + /* Ensure goto_locus from edges has some instructions with that locus + in RTL. */ + if (!optimize) + FOR_EACH_BB (bb) + { + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) + if (e->goto_locus && !(e->flags & EDGE_ABNORMAL)) + { + edge e2; + edge_iterator ei2; + basic_block dest, nb; + rtx end; + + insn = BB_END (e->src); + end = PREV_INSN (BB_HEAD (e->src)); + while (insn != end + && (!NONDEBUG_INSN_P (insn) || INSN_LOCATOR (insn) == 0)) + insn = PREV_INSN (insn); + if (insn != end + && locator_eq (INSN_LOCATOR (insn), (int) e->goto_locus)) + continue; + if (simplejump_p (BB_END (e->src)) + && INSN_LOCATOR (BB_END (e->src)) == 0) + { + INSN_LOCATOR (BB_END (e->src)) = e->goto_locus; + continue; + } + dest = e->dest; + if (dest == EXIT_BLOCK_PTR) + { + /* Non-fallthru edges to the exit block cannot be split. */ + if (!(e->flags & EDGE_FALLTHRU)) + continue; + } + else + { + insn = BB_HEAD (dest); + end = NEXT_INSN (BB_END (dest)); + while (insn != end && !NONDEBUG_INSN_P (insn)) + insn = NEXT_INSN (insn); + if (insn != end && INSN_LOCATOR (insn) + && locator_eq (INSN_LOCATOR (insn), (int) e->goto_locus)) + continue; + } + nb = split_edge (e); + if (!INSN_P (BB_END (nb))) + BB_END (nb) = emit_insn_after_noloc (gen_nop (), BB_END (nb), + nb); + INSN_LOCATOR (BB_END (nb)) = e->goto_locus; + + /* If there are other incoming edges to the destination block + with the same goto locus, redirect them to the new block as + well, this can prevent other such blocks from being created + in subsequent iterations of the loop. */ + for (ei2 = ei_start (dest->preds); (e2 = ei_safe_edge (ei2)); ) + if (e2->goto_locus + && !(e2->flags & (EDGE_ABNORMAL | EDGE_FALLTHRU)) + && locator_eq (e->goto_locus, e2->goto_locus)) + redirect_edge_and_branch (e2, nb); + else + ei_next (&ei2); + } + } } /* Perform sanity checks on the insn chain. @@ -895,7 +1009,7 @@ fixup_reorder_chain (void) 2. Count insns in chain, going both directions, and check if equal. 3. Check that get_last_insn () returns the actual end of chain. */ -void +DEBUG_FUNCTION void verify_insn_chain (void) { rtx x, prevx, nextx; @@ -923,7 +1037,6 @@ 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 @@ -931,9 +1044,9 @@ fixup_fallthru_exit_predecessor (void) value. */ gcc_assert (reload_completed); - FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) - if (e->flags & EDGE_FALLTHRU) - bb = e->src; + e = find_fallthru_edge (EXIT_BLOCK_PTR->preds); + if (e) + bb = e->src; if (bb && bb->aux) { @@ -951,16 +1064,66 @@ fixup_fallthru_exit_predecessor (void) } while (c->aux != bb) - c = c->aux; + c = (basic_block) c->aux; c->aux = bb->aux; while (c->aux) - c = c->aux; + c = (basic_block) c->aux; c->aux = bb; bb->aux = NULL; } } + +/* In case there are more than one fallthru predecessors of exit, force that + there is only one. */ + +static void +force_one_exit_fallthru (void) +{ + edge e, predecessor = NULL; + bool more = false; + edge_iterator ei; + basic_block forwarder, bb; + + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) + if (e->flags & EDGE_FALLTHRU) + { + if (predecessor == NULL) + predecessor = e; + else + { + more = true; + break; + } + } + + if (!more) + return; + + /* Exit has several fallthru predecessors. Create a forwarder block for + them. */ + forwarder = split_edge (predecessor); + for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); ) + { + if (e->src == forwarder + || !(e->flags & EDGE_FALLTHRU)) + ei_next (&ei); + else + redirect_edge_and_branch_force (e, forwarder); + } + + /* Fix up the chain of blocks -- make FORWARDER immediately precede the + exit block. */ + FOR_EACH_BB (bb) + { + if (bb->aux == NULL && bb != forwarder) + { + bb->aux = forwarder; + break; + } + } +} /* Return true in case it is possible to duplicate the basic block BB. */ @@ -968,10 +1131,10 @@ fixup_fallthru_exit_predecessor (void) only be used through the cfghooks interface, and we do not want to move it to cfgrtl.c since it would require also moving quite a lot of related code. */ -extern bool cfg_layout_can_duplicate_bb_p (basic_block); +extern bool cfg_layout_can_duplicate_bb_p (const_basic_block); bool -cfg_layout_can_duplicate_bb_p (basic_block bb) +cfg_layout_can_duplicate_bb_p (const_basic_block bb) { /* Do not attempt to duplicate tablejumps, as we need to unshare the dispatch table. This is difficult to do, as the instructions @@ -999,7 +1162,7 @@ cfg_layout_can_duplicate_bb_p (basic_block bb) rtx duplicate_insn_chain (rtx from, rtx to) { - rtx insn, last; + rtx insn, last, copy; /* Avoid updating of boundaries of previous basic block. The note will get removed from insn stream in fixup. */ @@ -1011,6 +1174,11 @@ duplicate_insn_chain (rtx from, rtx to) { switch (GET_CODE (insn)) { + case DEBUG_INSN: + /* Don't duplicate label debug insns. */ + if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL) + break; + /* FALLTHRU */ case INSN: case CALL_INSN: case JUMP_INSN: @@ -1019,8 +1187,25 @@ duplicate_insn_chain (rtx from, rtx to) moved far from original jump. */ if (GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) - break; - emit_copy_of_insn_after (insn, get_last_insn ()); + { + /* Avoid copying following barrier as well if any + (and debug insns in between). */ + rtx next; + + for (next = NEXT_INSN (insn); + next != NEXT_INSN (to); + next = NEXT_INSN (next)) + if (!DEBUG_INSN_P (next)) + break; + if (next != NEXT_INSN (to) && BARRIER_P (next)) + insn = next; + break; + } + copy = emit_copy_of_insn_after (insn, get_last_insn ()); + if (JUMP_P (insn) && JUMP_LABEL (insn) != NULL_RTX + && ANY_RETURN_P (JUMP_LABEL (insn))) + JUMP_LABEL (copy) = JUMP_LABEL (insn); + maybe_copy_prologue_epilogue_insn (insn, copy); break; case CODE_LABEL: @@ -1031,7 +1216,7 @@ duplicate_insn_chain (rtx from, rtx to) break; case NOTE: - switch (NOTE_LINE_NUMBER (insn)) + switch (NOTE_KIND (insn)) { /* In case prologue is empty and function contain label in first BB, we may want to copy the block. */ @@ -1039,29 +1224,21 @@ duplicate_insn_chain (rtx from, rtx to) case NOTE_INSN_DELETED: case NOTE_INSN_DELETED_LABEL: + case NOTE_INSN_DELETED_DEBUG_LABEL: /* No problem to strip these. */ - case NOTE_INSN_EPILOGUE_BEG: - /* 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. */ case NOTE_INSN_FUNCTION_BEG: /* There is always just single entry to function. */ case NOTE_INSN_BASIC_BLOCK: break; + case NOTE_INSN_EPILOGUE_BEG: case NOTE_INSN_SWITCH_TEXT_SECTIONS: emit_note_copy (insn); break; default: - /* 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. */ - emit_note_copy (insn); + /* All other notes should have already been eliminated. */ + gcc_unreachable (); } break; default: @@ -1112,35 +1289,34 @@ cfg_layout_duplicate_bb (basic_block bb) new_bb->il.rtl->footer = unlink_insn_chain (insn, get_last_insn ()); } - if (bb->il.rtl->global_live_at_start) - { - 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 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. */ + FLAGS is a set of additional flags to pass to cleanup_cfg(). */ void cfg_layout_initialize (unsigned int flags) { + rtx x; + basic_block bb; + initialize_original_copy_tables (); cfg_layout_rtl_register_cfg_hooks (); record_effective_endpoints (); + /* Make sure that the targets of non local gotos are marked. */ + for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1)) + { + bb = BLOCK_FOR_INSN (XEXP (x, 0)); + bb->flags |= BB_NON_LOCAL_GOTO_TARGET; + } + cleanup_cfg (CLEANUP_CFGLAYOUT | flags); } @@ -1178,11 +1354,10 @@ break_superblocks (void) void cfg_layout_finalize (void) { - basic_block bb; - #ifdef ENABLE_CHECKING verify_flow_info (); #endif + force_one_exit_fallthru (); rtl_register_cfg_hooks (); if (reload_completed #ifdef HAVE_epilogue @@ -1197,19 +1372,8 @@ cfg_layout_finalize (void) #ifdef ENABLE_CHECKING verify_insn_chain (); -#endif - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) - { - bb->il.rtl->header = bb->il.rtl->footer = NULL; - bb->aux = NULL; - bb->il.rtl->visited = 0; - } - -#ifdef ENABLE_CHECKING verify_flow_info (); #endif - - free_original_copy_tables (); } /* Checks whether all N blocks in BBS array can be copied. */