/* 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, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
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"
#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 "df.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);
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);
-static void update_unlikely_executed_notes (basic_block);
\f
rtx
unlink_insn_chain (rtx first, rtx last)
continue;
case NOTE:
- switch (NOTE_LINE_NUMBER (insn))
+ switch (NOTE_KIND (insn))
{
- case NOTE_INSN_LOOP_END:
case NOTE_INSN_BLOCK_END:
- last_insn = insn;
- continue;
- case NOTE_INSN_DELETED:
- case NOTE_INSN_DELETED_LABEL:
+ gcc_unreachable ();
continue;
-
default:
continue;
break;
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))
+ || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC))
{
insn = NEXT_INSN (insn);
last_insn = insn;
/* 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 (NOTE_P (insn))
- switch (NOTE_LINE_NUMBER (insn))
+ switch (NOTE_KIND (insn))
{
- case NOTE_INSN_LOOP_END:
case NOTE_INSN_BLOCK_END:
+ gcc_unreachable ();
+ break;
case NOTE_INSN_DELETED:
case NOTE_INSN_DELETED_LABEL:
continue;
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? */
gcc_assert (insn);
-
+
if (PREV_INSN (insn))
cfg_layout_function_header =
unlink_insn_chain (get_insns (), PREV_INSN (insn));
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));
}
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 GTY(()) varray_type file_locators_files;
+static VEC(int,heap) *block_locators_locs;
+static GTY(()) VEC(tree,gc) *block_locators_blocks;
+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. */
+location_t curr_location, last_location;
+static tree curr_block, last_block;
+static int curr_rtl_loc = -1;
+/* Allocate insn locator datastructure. */
void
-insn_locators_initialize (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;
- 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");
- VARRAY_CHAR_PTR_INIT (file_locators_files, 32, "file_locators_files");
+ block_locators_locs = VEC_alloc (int, heap, 32);
+ block_locators_blocks = VEC_alloc (tree, gc, 32);
+ locations_locators_locs = VEC_alloc (int, heap, 32);
+ locations_locators_vals = VEC_alloc (location_t, heap, 32);
- for (insn = get_insns (); insn; insn = next)
- {
- int active = 0;
-
- next = 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;
- }
- }
- 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);
- 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);
- 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, (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;
- }
- }
+#ifdef USE_MAPPED_LOCATION
+ last_location = -1;
+ curr_location = -1;
+#else
+ last_location.line = -1;
+ curr_location.line = -1;
+#endif
+ curr_block = NULL;
+ last_block = NULL;
+ curr_rtl_loc = 0;
+}
- /* 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);
+/* 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;
+}
- free_block_changes ();
+/* 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;
+#ifdef USE_MAPPED_LOCATION
+ if (location == last_location)
+ return;
+#else
+ if (location.file && last_location.file
+ && !strcmp (location.file, last_location.file)
+ && location.line == last_location.line)
+ return;
+#endif
+ curr_location = location;
}
-/* For each lexical block, set BLOCK_NUMBER to the depth at which it is
- found in the block tree. */
+/* 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;
+}
-static void
-set_block_levels (tree block, int level)
+/* Return current insn locator. */
+int
+curr_insn_locator (void)
{
- while (block)
+ if (curr_rtl_loc == -1)
+ return 0;
+ if (last_block != curr_block)
{
- BLOCK_NUMBER (block) = level;
- set_block_levels (BLOCK_SUBBLOCKS (block), level + 1);
- block = BLOCK_CHAIN (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;
}
+#ifdef USE_MAPPED_LOCATION
+ if (last_location != curr_location)
+#else
+ if (last_location.file != curr_location.file
+ || last_location.line != curr_location.line)
+#endif
+ {
+ 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)
+{
+ 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 */
+};
\f
/* Return sope resulting from combination of S1 and S2. */
-tree
+static tree
choose_inner_scope (tree s1, tree s2)
{
if (!s1)
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);
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;
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)
+static location_t
+locator_location (int loc)
{
- int max = VARRAY_ACTIVE_SIZE (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 = VARRAY_INT (line_locators_locs, pos);
+ int tmp = VEC_index (int, locations_locators_locs, pos);
if (tmp <= loc && min != pos)
min = pos;
break;
}
}
- return VARRAY_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. */
const char *
locator_file (int loc)
{
- int max = VARRAY_ACTIVE_SIZE (file_locators_locs);
- int min = 0;
-
- if (!max || !loc)
- return NULL;
- while (1)
- {
- int pos = (min + max) / 2;
- int tmp = VARRAY_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. */
{
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;
reorder_blocks ();
}
\f
+
+/* 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 ();
+}
+\f
+
/* 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)
/* 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 = (basic_block) 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);
}
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);
}
}
- 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;
#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 = (basic_block) bb->aux)
{
edge e_fall, e_taken, e;
rtx bb_end_insn;
basic_block nb;
- basic_block old_bb;
edge_iterator ei;
if (EDGE_COUNT (bb->succs) == 0)
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;
- bool redirected;
-
- e_fake = unchecked_make_edge (bb, e_fall->dest, 0);
-
- redirected = redirect_jump (BB_END (bb),
- block_label (bb), 0);
- gcc_assert (redirected);
-
- 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);
}
else
{
-#ifndef CASE_DROPS_THROUGH
/* 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
- if (returnjump_p (bb_end_insn) || !e_fall)
- continue;
- /* 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);
-#endif
}
}
else
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. */
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, since you cannot fall-throu across
section boundaries). */
- BB_COPY_PARTITION (e_fall->src, EDGE_PRED (bb, 0)->src);
+ BB_COPY_PARTITION (e_fall->src, single_pred (bb));
if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections)
- {
- if (BB_PARTITION (EDGE_PRED (bb, 0)->src) == BB_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 (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)));
- }
+ && 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)));
}
}
- /* 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)
- && !LABEL_P (BB_HEAD (bb)))
- fprintf (dump_file, "compensation ");
- else
- fprintf (dump_file, "bb %i ", bb->index);
- fprintf (dump_file, " [%i]\n", bb->frequency);
- }
- }
-
- 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)
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
-
+
if (e && !can_fallthru (e->src, e->dest))
force_nonfallthru (e);
}
}
\f
-/* 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 (NOTE_P (cur_insn)
- && NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
- NOTE_BASIC_BLOCK (cur_insn) = bb;
-}
-\f
/* Perform sanity checks on the insn chain.
1. Check that next/prev pointers are consistent in both the forward and
reverse direction.
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;
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 = (basic_block) c->aux;
- c->rbi->next = bb->rbi->next;
- while (c->rbi->next)
- c = c->rbi->next;
+ c->aux = bb->aux;
+ while (c->aux)
+ c = (basic_block) c->aux;
- c->rbi->next = bb;
- bb->rbi->next = NULL;
+ c->aux = bb;
+ bb->aux = NULL;
}
}
\f
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. */
+ in first BB, we may want to copy the block. */
case NOTE_INSN_PROLOGUE_END:
- 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;
- case NOTE_INSN_REPEATED_LINE_NUMBER:
- case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
+ 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);
+ gcc_unreachable ();
}
break;
default:
EXIT_BLOCK_PTR->prev_bb);
BB_COPY_PARTITION (new_bb, bb);
- if (bb->rbi->header)
+ 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 ());
- }
-
- if (bb->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->footer = unlink_insn_chain (insn, get_last_insn ());
}
return new_bb;
}
+
\f
/* 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;
- /* 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 ();
+ /* 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);
}
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
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
}
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++)
{
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;
end:
for (i = 0; i < n; i++)
- bbs[i]->rbi->duplicated = 0;
+ bbs[i]->flags &= ~BB_DUPLICATED;
return ret;
}
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;
{
/* 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. */
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++)
{
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"