/* Basic block reordering routines for the GNU compiler.
- Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- 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.
#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;
void verify_insn_chain (void);
static void fixup_fallthru_exit_predecessor (void);
-static tree insn_scope (const_rtx);
\f
rtx
unlink_insn_chain (rtx first, rtx last)
break;
case NOTE_INSN_DELETED:
case NOTE_INSN_DELETED_LABEL:
+ case NOTE_INSN_DELETED_DEBUG_LABEL:
continue;
default:
reorder_insns (insn, insn, last_insn);
locations_locators_locs = VEC_alloc (int, heap, 32);
locations_locators_vals = VEC_alloc (location_t, heap, 32);
- last_location = -1;
- curr_location = -1;
+ curr_location = UNKNOWN_LOCATION;
+ last_location = UNKNOWN_LOCATION;
curr_block = NULL;
last_block = NULL;
curr_rtl_loc = 0;
int
curr_insn_locator (void)
{
- if (curr_rtl_loc == -1)
+ if (curr_rtl_loc == -1 || curr_location == UNKNOWN_LOCATION)
return 0;
if (last_block != curr_block)
{
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- TV_NONE, /* tv_id */
+ TV_CFG, /* tv_id */
0, /* properties_required */
PROP_cfglayout, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
+ 0 /* todo_flags_finish */
}
};
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- TV_NONE, /* tv_id */
+ TV_CFG, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
PROP_cfglayout, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
+ 0 /* todo_flags_finish */
}
};
\f
}
/* Return lexical scope block insn belongs to. */
-static tree
+tree
insn_scope (const_rtx insn)
{
return locator_scope (INSN_LOCATOR (insn));
free_original_copy_tables ();
if (stay_in_cfglayout_mode)
initialize_original_copy_tables ();
-
+
/* Finally, put basic_block_info in the new order. */
compact_blocks ();
}
{
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)
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)
: 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;
: 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, nothing to do. */
- if (bb->aux == e_fall->dest
+ /* 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;
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;
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))
/* Annoying special case - jump around dead jumptables left in the code. */
FOR_EACH_BB (bb)
{
- edge e;
- edge_iterator ei;
+ edge e = find_fallthru_edge (bb->succs);
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_FALLTHRU)
- break;
-
if (e && !can_fallthru (e->src, e->dest))
force_nonfallthru (e);
}
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->goto_locus && !(e->flags & EDGE_ABNORMAL))
{
- basic_block nb;
+ 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
- && (!INSN_P (insn) || INSN_LOCATOR (insn) == 0))
+ && (!NONDEBUG_INSN_P (insn) || INSN_LOCATOR (insn) == 0))
insn = PREV_INSN (insn);
if (insn != end
&& locator_eq (INSN_LOCATOR (insn), (int) e->goto_locus))
INSN_LOCATOR (BB_END (e->src)) = e->goto_locus;
continue;
}
- if (e->dest != EXIT_BLOCK_PTR)
+ 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 (e->dest);
- end = NEXT_INSN (BB_END (e->dest));
- while (insn != end && !INSN_P (insn))
+ 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))
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);
}
}
}
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;
fixup_fallthru_exit_predecessor (void)
{
edge e;
- edge_iterator ei;
basic_block bb = NULL;
/* This transformation is not valid before reload, because we might
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)
{
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:
moved far from original jump. */
if (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
- break;
+ {
+ /* 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 ());
- maybe_copy_epilogue_insn (insn, copy);
+ 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:
case NOTE_INSN_DELETED:
case NOTE_INSN_DELETED_LABEL:
+ case NOTE_INSN_DELETED_DEBUG_LABEL:
/* No problem to strip these. */
case NOTE_INSN_FUNCTION_BEG:
/* There is always just single entry to function. */