/* 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
+ 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
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
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "alloc-pool.h"
#include "flags.h"
#include "tree-pass.h"
+#include "df.h"
#include "vecprim.h"
/* Holds the interesting trailing notes for the function. */
void verify_insn_chain (void);
static void fixup_fallthru_exit_predecessor (void);
-static tree insn_scope (rtx);
+static tree insn_scope (const_rtx);
\f
rtx
unlink_insn_chain (rtx first, rtx last)
continue;
case NOTE:
- switch (NOTE_LINE_NUMBER (insn))
+ switch (NOTE_KIND (insn))
{
case NOTE_INSN_BLOCK_END:
- last_insn = insn;
- continue;
- case NOTE_INSN_DELETED:
- case NOTE_INSN_DELETED_LABEL:
+ gcc_unreachable ();
continue;
-
default:
continue;
break;
{
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:
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? */
int epilogue_locator;
/* Hold current location information and last location information, so the
- datastructures are built lazilly only when some instructions in given
+ 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;
locations_locators_locs = VEC_alloc (int, heap, 32);
locations_locators_vals = VEC_alloc (location_t, heap, 32);
-#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;
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;
}
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);
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 */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ }
};
-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 */
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. */
/* Return lexical scope block insn belong to. */
static tree
-insn_scope (rtx insn)
+insn_scope (const_rtx insn)
{
int max = VEC_length (int, block_locators_locs);
int min = 0;
/* 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));
}
/* 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));
}
fprintf (dump_file, "Reordered sequence:\n");
for (bb = ENTRY_BLOCK_PTR->next_bb, index = NUM_FIXED_BLOCKS;
bb;
- bb = bb->aux, index++)
+ bb = (basic_block) bb->aux, index++)
{
fprintf (dump_file, " %i ", index);
if (get_bb_original (bb))
/* Now reorder the blocks. */
prev_bb = ENTRY_BLOCK_PTR;
bb = ENTRY_BLOCK_PTR->next_bb;
- for (; bb; prev_bb = bb, bb = bb->aux)
+ for (; bb; prev_bb = bb, bb = (basic_block) bb->aux)
{
bb->prev_bb = prev_bb;
prev_bb->next_bb = bb;
/* 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; bb; bb = bb->aux)
+ for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = (basic_block) bb->aux)
{
if (bb->il.rtl->header)
{
/* 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;
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
-
+
if (e && !can_fallthru (e->src, e->dest))
force_nonfallthru (e);
}
}
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;
+ }
+ }
+}
\f
/* Return true in case it is possible to duplicate the basic block BB. */
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
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. */
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:
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;
}
+
\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;
+
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);
}
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
+ force_one_exit_fallthru ();
rtl_register_cfg_hooks ();
if (reload_completed
#ifdef HAVE_epilogue