/* Control flow graph manipulation code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Free Software Foundation, Inc.
This file is part of GCC.
insert_insn_on_edge, commit_edge_insertions
- CFG updating after insn simplification
purge_dead_edges, purge_all_dead_edges
+ - CFG fixing after coarse manipulation
+ fixup_abnormal_edges
Functions not supposed for generic use:
- Infrastructure to determine quickly basic block for insn
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "rtl.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "regs.h"
#include "output.h"
#include "function.h"
#include "except.h"
-#include "toplev.h"
+#include "rtl-error.h"
#include "tm_p.h"
#include "obstack.h"
+#include "insn-attr.h"
#include "insn-config.h"
#include "cfglayout.h"
#include "expr.h"
#include "target.h"
+#include "common/common-target.h"
#include "cfgloop.h"
#include "ggc.h"
#include "tree-pass.h"
static int can_delete_note_p (const_rtx);
static int can_delete_label_p (const_rtx);
-static void commit_one_edge_insertion (edge);
static basic_block rtl_split_edge (edge);
static bool rtl_move_block_after (basic_block, basic_block);
static int rtl_verify_flow_info (void);
static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
static edge rtl_redirect_edge_and_branch (edge, basic_block);
static basic_block rtl_split_block (basic_block, void *);
-static void rtl_dump_bb (basic_block, FILE *, int);
+static void rtl_dump_bb (basic_block, FILE *, int, int);
static int rtl_verify_flow_info_1 (void);
static void rtl_make_forwarder_block (edge);
\f
static int
can_delete_note_p (const_rtx note)
{
- return (NOTE_KIND (note) == NOTE_INSN_DELETED
- || NOTE_KIND (note) == NOTE_INSN_BASIC_BLOCK);
+ switch (NOTE_KIND (note))
+ {
+ case NOTE_INSN_DELETED:
+ case NOTE_INSN_BASIC_BLOCK:
+ case NOTE_INSN_EPILOGUE_BEG:
+ return true;
+
+ default:
+ return false;
+ }
}
/* True if a given label can be deleted. */
remove_note (insn, note);
}
- if (JUMP_P (insn)
- && (GET_CODE (PATTERN (insn)) == ADDR_VEC
- || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+ if (JUMP_TABLE_DATA_P (insn))
{
rtx pat = PATTERN (insn);
int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
start = next;
}
}
-
-/* Like delete_insn_chain but also purge dead edges from BB. */
-
-void
-delete_insn_chain_and_edges (rtx first, rtx last)
-{
- bool purge = false;
-
- if (INSN_P (last)
- && BLOCK_FOR_INSN (last)
- && BB_END (BLOCK_FOR_INSN (last)) == last)
- purge = true;
- delete_insn_chain (first, last, false);
- if (purge)
- purge_dead_edges (BLOCK_FOR_INSN (last));
-}
\f
/* Create a new basic block consisting of the instructions between HEAD and END
inclusive. This function is designed to allow fast BB construction - reuses
}
/* Create new basic block consisting of instructions in between HEAD and END
- and place it to the BB chain after block AFTER. END can be NULL in to
- create new empty basic block before HEAD. Both END and HEAD can be NULL to
- create basic block at the end of INSN chain. */
+ and place it to the BB chain after block AFTER. END can be NULL to
+ create a new empty basic block before HEAD. Both END and HEAD can be
+ NULL to create basic block at the end of INSN chain. */
static basic_block
rtl_create_basic_block (void *headp, void *endp, basic_block after)
label for an exception handler which can't be reached. We need
to remove the label from the exception_handler_label list. */
insn = BB_HEAD (b);
- if (LABEL_P (insn))
- maybe_remove_eh_handler (insn);
end = get_last_bb_insn (b);
return 0;
}
+static unsigned int
+rest_of_pass_free_cfg (void)
+{
+#ifdef DELAY_SLOTS
+ /* The resource.c machinery uses DF but the CFG isn't guaranteed to be
+ valid at that point so it would be too late to call df_analyze. */
+ if (optimize > 0 && flag_delayed_branch)
+ {
+ df_note_add_problem ();
+ df_analyze ();
+ }
+#endif
+
+ free_bb_for_insn ();
+ return 0;
+}
+
struct rtl_opt_pass pass_free_cfg =
{
{
RTL_PASS,
- NULL, /* name */
+ "*free_cfg", /* name */
NULL, /* gate */
- free_bb_for_insn, /* execute */
+ rest_of_pass_free_cfg, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
PROP_cfg, /* properties_destroyed */
}
/* Update BLOCK_FOR_INSN of insns between BEGIN and END
- (or BARRIER if found) and notify df of the bb change.
+ (or BARRIER if found) and notify df of the bb change.
The insn chain range is inclusive
(i.e. both BEGIN and END will be updated. */
}
\f
+/* Return the NOTE_INSN_BASIC_BLOCK of BB. */
+rtx
+bb_note (basic_block bb)
+{
+ rtx note;
+
+ note = BB_HEAD (bb);
+ if (LABEL_P (note))
+ note = NEXT_INSN (note);
+
+ gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
+ return note;
+}
+
/* Return the INSN immediately following the NOTE_INSN_BASIC_BLOCK
note associated with the BLOCK. */
insn = first_insn_after_basic_block_note (bb);
if (insn)
- insn = PREV_INSN (insn);
+ {
+ rtx next = insn;
+
+ insn = PREV_INSN (insn);
+
+ /* If the block contains only debug insns, insn would have
+ been NULL in a non-debug compilation, and then we'd end
+ up emitting a DELETED note. For -fcompare-debug
+ stability, emit the note too. */
+ if (insn != BB_END (bb)
+ && DEBUG_INSN_P (next)
+ && DEBUG_INSN_P (BB_END (bb)))
+ {
+ while (next != BB_END (bb) && DEBUG_INSN_P (next))
+ next = NEXT_INSN (next);
+
+ if (next == BB_END (bb))
+ emit_note_after (NOTE_INSN_DELETED, next);
+ }
+ }
else
insn = get_last_insn ();
}
{
rtx b_head = BB_HEAD (b), b_end = BB_END (b), a_end = BB_END (a);
rtx del_first = NULL_RTX, del_last = NULL_RTX;
+ rtx b_debug_start = b_end, b_debug_end = b_end;
+ bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
int b_empty = 0;
if (dump_file)
- fprintf (dump_file, "merging block %d into block %d\n", b->index, a->index);
+ fprintf (dump_file, "Merging block %d into block %d...\n", b->index,
+ a->index);
+
+ while (DEBUG_INSN_P (b_end))
+ b_end = PREV_INSN (b_debug_start = b_end);
/* If there was a CODE_LABEL beginning B, delete it. */
if (LABEL_P (b_head))
{
- /* This might have been an EH label that no longer has incoming
- EH edges. Update data structures to match. */
- maybe_remove_eh_handler (b_head);
-
/* Detect basic blocks with nothing but a label. This can happen
in particular at the end of a function. */
if (b_head == b_end)
/* Reassociate the insns of B with A. */
if (!b_empty)
{
- update_bb_for_insn_chain (a_end, b_end, a);
+ update_bb_for_insn_chain (a_end, b_debug_end, a);
- a_end = b_end;
+ a_end = b_debug_end;
+ }
+ else if (b_end != b_debug_end)
+ {
+ /* Move any deleted labels and other notes between the end of A
+ and the debug insns that make up B after the debug insns,
+ bringing the debug insns into A while keeping the notes after
+ the end of A. */
+ if (NEXT_INSN (a_end) != b_debug_start)
+ reorder_insns_nobb (NEXT_INSN (a_end), PREV_INSN (b_debug_start),
+ b_debug_end);
+ update_bb_for_insn_chain (b_debug_start, b_debug_end, a);
+ a_end = b_debug_end;
}
df_bb_delete (b->index);
BB_END (a) = a_end;
+
+ /* If B was a forwarder block, propagate the locus on the edge. */
+ if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus)
+ EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
+ if (dump_file)
+ fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index);
}
return e;
}
-/* Redirect edge representing branch of (un)conditional jump or tablejump,
- NULL on failure */
-static edge
-redirect_branch_edge (edge e, basic_block target)
+/* Subroutine of redirect_branch_edge that tries to patch the jump
+ instruction INSN so that it reaches block NEW. Do this
+ only when it originally reached block OLD. Return true if this
+ worked or the original target wasn't OLD, return false if redirection
+ doesn't work. */
+
+static bool
+patch_jump_insn (rtx insn, rtx old_label, basic_block new_bb)
{
rtx tmp;
- rtx old_label = BB_HEAD (e->dest);
- basic_block src = e->src;
- rtx insn = BB_END (src);
-
- /* We can only redirect non-fallthru edges of jump insn. */
- if (e->flags & EDGE_FALLTHRU)
- return NULL;
- else if (!JUMP_P (insn))
- return NULL;
-
/* Recognize a tablejump and adjust all matching cases. */
if (tablejump_p (insn, NULL, &tmp))
{
rtvec vec;
int j;
- rtx new_label = block_label (target);
+ rtx new_label = block_label (new_bb);
- if (target == EXIT_BLOCK_PTR)
- return NULL;
+ if (new_bb == EXIT_BLOCK_PTR)
+ return false;
if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
vec = XVEC (PATTERN (tmp), 0);
else
++LABEL_NUSES (new_label);
}
}
+ else if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+ {
+ int i, n = ASM_OPERANDS_LABEL_LENGTH (tmp);
+ rtx new_label, note;
+
+ if (new_bb == EXIT_BLOCK_PTR)
+ return false;
+ new_label = block_label (new_bb);
+
+ for (i = 0; i < n; ++i)
+ {
+ rtx old_ref = ASM_OPERANDS_LABEL (tmp, i);
+ gcc_assert (GET_CODE (old_ref) == LABEL_REF);
+ if (XEXP (old_ref, 0) == old_label)
+ {
+ ASM_OPERANDS_LABEL (tmp, i)
+ = gen_rtx_LABEL_REF (Pmode, new_label);
+ --LABEL_NUSES (old_label);
+ ++LABEL_NUSES (new_label);
+ }
+ }
+
+ if (JUMP_LABEL (insn) == old_label)
+ {
+ JUMP_LABEL (insn) = new_label;
+ note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
+ if (note)
+ remove_note (insn, note);
+ }
+ else
+ {
+ note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
+ if (note)
+ remove_note (insn, note);
+ if (JUMP_LABEL (insn) != new_label
+ && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
+ add_reg_note (insn, REG_LABEL_TARGET, new_label);
+ }
+ while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
+ != NULL_RTX)
+ XEXP (note, 0) = new_label;
+ }
else
{
/* ?? We may play the games with moving the named labels from
if (computed_jump_p (insn)
/* A return instruction can't be redirected. */
|| returnjump_p (insn))
- return NULL;
-
- /* If the insn doesn't go where we think, we're confused. */
- gcc_assert (JUMP_LABEL (insn) == old_label);
+ return false;
- /* If the substitution doesn't succeed, die. This can happen
- if the back end emitted unrecognizable instructions or if
- target is exit block on some arches. */
- if (!redirect_jump (insn, block_label (target), 0))
+ if (!currently_expanding_to_rtl || JUMP_LABEL (insn) == old_label)
{
- gcc_assert (target == EXIT_BLOCK_PTR);
- return NULL;
+ /* If the insn doesn't go where we think, we're confused. */
+ gcc_assert (JUMP_LABEL (insn) == old_label);
+
+ /* If the substitution doesn't succeed, die. This can happen
+ if the back end emitted unrecognizable instructions or if
+ target is exit block on some arches. */
+ if (!redirect_jump (insn, block_label (new_bb), 0))
+ {
+ gcc_assert (new_bb == EXIT_BLOCK_PTR);
+ return false;
+ }
}
}
+ return true;
+}
+
+
+/* Redirect edge representing branch of (un)conditional jump or tablejump,
+ NULL on failure */
+static edge
+redirect_branch_edge (edge e, basic_block target)
+{
+ rtx old_label = BB_HEAD (e->dest);
+ basic_block src = e->src;
+ rtx insn = BB_END (src);
+
+ /* We can only redirect non-fallthru edges of jump insn. */
+ if (e->flags & EDGE_FALLTHRU)
+ return NULL;
+ else if (!JUMP_P (insn) && !currently_expanding_to_rtl)
+ return NULL;
+
+ if (!currently_expanding_to_rtl)
+ {
+ if (!patch_jump_insn (insn, old_label, target))
+ return NULL;
+ }
+ else
+ /* When expanding this BB might actually contain multiple
+ jumps (i.e. not yet split by find_many_sub_basic_blocks).
+ Redirect all of those that match our label. */
+ FOR_BB_INSNS (src, insn)
+ if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target))
+ return NULL;
if (dump_file)
fprintf (dump_file, "Edge %i->%i redirected to %i\n",
}
/* Like force_nonfallthru below, but additionally performs redirection
- Used by redirect_edge_and_branch_force. */
+ Used by redirect_edge_and_branch_force. JUMP_LABEL is used only
+ when redirecting to the EXIT_BLOCK, it is either ret_rtx or
+ simple_return_rtx, indicating which kind of returnjump to create.
+ It should be NULL otherwise. */
-static basic_block
-force_nonfallthru_and_redirect (edge e, basic_block target)
+basic_block
+force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
{
basic_block jump_block, new_bb = NULL, src = e->src;
rtx note;
edge new_edge;
int abnormal_edge_flags = 0;
+ bool asm_goto_edge = false;
+ int loc;
/* In the case the last instruction is conditional jump to the next
instruction, first redirect the jump itself and then continue
}
}
- if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags)
+ /* If e->src ends with asm goto, see if any of the ASM_OPERANDS_LABELs
+ don't point to target label. */
+ if (JUMP_P (BB_END (e->src))
+ && target != EXIT_BLOCK_PTR
+ && e->dest == target
+ && (e->flags & EDGE_FALLTHRU)
+ && (note = extract_asm_operands (PATTERN (BB_END (e->src)))))
{
+ int i, n = ASM_OPERANDS_LABEL_LENGTH (note);
+
+ for (i = 0; i < n; ++i)
+ if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target))
+ {
+ asm_goto_edge = true;
+ break;
+ }
+ }
+
+ if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge)
+ {
+ gcov_type count = e->count;
+ int probability = e->probability;
/* Create the new structures. */
/* If the old block ended with a tablejump, skip its table
note = NEXT_INSN (note);
jump_block = create_basic_block (note, NULL, e->src);
- jump_block->count = e->count;
+ jump_block->count = count;
jump_block->frequency = EDGE_FREQUENCY (e);
jump_block->loop_depth = target->loop_depth;
BB_COPY_PARTITION (jump_block, e->src);
if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections
+ && targetm_common.have_named_sections
&& JUMP_P (BB_END (jump_block))
&& !any_condjump_p (BB_END (jump_block))
&& (EDGE_SUCC (jump_block, 0)->flags & EDGE_CROSSING))
- REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP,
- NULL_RTX,
- REG_NOTES
- (BB_END
- (jump_block)));
+ add_reg_note (BB_END (jump_block), REG_CROSSING_JUMP, NULL_RTX);
/* Wire edge in. */
new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
- new_edge->probability = e->probability;
- new_edge->count = e->count;
+ new_edge->probability = probability;
+ new_edge->count = count;
/* Redirect old edge. */
redirect_edge_pred (e, jump_block);
e->probability = REG_BR_PROB_BASE;
+ /* If asm goto has any label refs to target's label,
+ add also edge from asm goto bb to target. */
+ if (asm_goto_edge)
+ {
+ new_edge->probability /= 2;
+ new_edge->count /= 2;
+ jump_block->count /= 2;
+ jump_block->frequency /= 2;
+ new_edge = make_edge (new_edge->src, target,
+ e->flags & ~EDGE_FALLTHRU);
+ new_edge->probability = probability - probability / 2;
+ new_edge->count = count - count / 2;
+ }
+
new_bb = jump_block;
}
else
jump_block = e->src;
+ if (e->goto_locus && e->goto_block == NULL)
+ loc = e->goto_locus;
+ else
+ loc = 0;
e->flags &= ~EDGE_FALLTHRU;
if (target == EXIT_BLOCK_PTR)
{
+ if (jump_label == ret_rtx)
+ {
#ifdef HAVE_return
- emit_jump_insn_after_noloc (gen_return (), BB_END (jump_block));
+ emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), loc);
+#else
+ gcc_unreachable ();
+#endif
+ }
+ else
+ {
+ gcc_assert (jump_label == simple_return_rtx);
+#ifdef HAVE_simple_return
+ emit_jump_insn_after_setloc (gen_simple_return (),
+ BB_END (jump_block), loc);
#else
- gcc_unreachable ();
+ gcc_unreachable ();
#endif
+ }
+ set_return_jump_label (BB_END (jump_block));
}
else
{
rtx label = block_label (target);
- emit_jump_insn_after_noloc (gen_jump (label), BB_END (jump_block));
+ emit_jump_insn_after_setloc (gen_jump (label), BB_END (jump_block), loc);
JUMP_LABEL (BB_END (jump_block)) = label;
LABEL_NUSES (label)++;
}
if (abnormal_edge_flags)
make_edge (src, target, abnormal_edge_flags);
- df_mark_solutions_dirty ();
+ df_mark_solutions_dirty ();
return new_bb;
}
(and possibly create new basic block) to make edge non-fallthru.
Return newly created BB or NULL if none. */
-basic_block
-force_nonfallthru (edge e)
+static basic_block
+rtl_force_nonfallthru (edge e)
{
- return force_nonfallthru_and_redirect (e, e->dest);
+ return force_nonfallthru_and_redirect (e, e->dest, NULL_RTX);
}
/* Redirect edge even at the expense of creating new jump insn or
/* In case the edge redirection failed, try to force it to be non-fallthru
and redirect newly created simplejump. */
df_set_bb_dirty (e->src);
- return force_nonfallthru_and_redirect (e, target);
+ return force_nonfallthru_and_redirect (e, target, NULL_RTX);
}
/* The given edge should potentially be a fallthru edge. If that is in
Avoid existence of fallthru predecessors. */
if ((edge_in->flags & EDGE_FALLTHRU) == 0)
{
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, edge_in->dest->preds)
- if (e->flags & EDGE_FALLTHRU)
- break;
+ edge e = find_fallthru_edge (edge_in->dest->preds);
if (e)
force_nonfallthru (e);
before = NULL_RTX;
/* If this is a fall through edge to the exit block, the blocks might be
- not adjacent, and the right place is the after the source. */
- if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR)
+ not adjacent, and the right place is after the source. */
+ if ((edge_in->flags & EDGE_FALLTHRU) && edge_in->dest == EXIT_BLOCK_PTR)
{
before = NEXT_INSN (BB_END (edge_in->src));
bb = create_basic_block (before, NULL, edge_in->src);
gcc_assert (redirected);
}
else
- redirect_edge_succ (edge_in, bb);
+ {
+ if (edge_in->src != ENTRY_BLOCK_PTR)
+ {
+ /* For asm goto even splitting of fallthru edge might
+ need insn patching, as other labels might point to the
+ old label. */
+ rtx last = BB_END (edge_in->src);
+ if (last
+ && JUMP_P (last)
+ && edge_in->dest != EXIT_BLOCK_PTR
+ && extract_asm_operands (PATTERN (last)) != NULL_RTX
+ && patch_jump_insn (last, before, bb))
+ df_set_bb_dirty (edge_in->src);
+ }
+ redirect_edge_succ (edge_in, bb);
+ }
return bb;
}
/* Update the CFG for the instructions queued on edge E. */
-static void
+void
commit_one_edge_insertion (edge e)
{
rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
- basic_block bb = NULL;
+ basic_block bb;
/* Pull the insns off the edge now since the edge might go away. */
insns = e->insns.r;
e->insns.r = NULL_RTX;
- if (!before && !after)
- {
- /* Figure out where to put these things. If the destination has
- one predecessor, insert there. Except for the exit block. */
- if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
- {
- bb = e->dest;
-
- /* Get the location correct wrt a code label, and "nice" wrt
- a basic block note, and before everything else. */
- tmp = BB_HEAD (bb);
- if (LABEL_P (tmp))
- tmp = NEXT_INSN (tmp);
- if (NOTE_INSN_BASIC_BLOCK_P (tmp))
- tmp = NEXT_INSN (tmp);
- if (tmp == BB_HEAD (bb))
- before = tmp;
- else if (tmp)
- after = PREV_INSN (tmp);
- else
- after = get_last_insn ();
- }
-
- /* If the source has one successor and the edge is not abnormal,
- insert there. Except for the entry block. */
- else if ((e->flags & EDGE_ABNORMAL) == 0
- && single_succ_p (e->src)
- && e->src != ENTRY_BLOCK_PTR)
- {
- bb = e->src;
+ /* Figure out where to put these insns. If the destination has
+ one predecessor, insert there. Except for the exit block. */
+ if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
+ {
+ bb = e->dest;
+
+ /* Get the location correct wrt a code label, and "nice" wrt
+ a basic block note, and before everything else. */
+ tmp = BB_HEAD (bb);
+ if (LABEL_P (tmp))
+ tmp = NEXT_INSN (tmp);
+ if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+ tmp = NEXT_INSN (tmp);
+ if (tmp == BB_HEAD (bb))
+ before = tmp;
+ else if (tmp)
+ after = PREV_INSN (tmp);
+ else
+ after = get_last_insn ();
+ }
- /* It is possible to have a non-simple jump here. Consider a target
- where some forms of unconditional jumps clobber a register. This
- happens on the fr30 for example.
+ /* If the source has one successor and the edge is not abnormal,
+ insert there. Except for the entry block. */
+ else if ((e->flags & EDGE_ABNORMAL) == 0
+ && single_succ_p (e->src)
+ && e->src != ENTRY_BLOCK_PTR)
+ {
+ bb = e->src;
- We know this block has a single successor, so we can just emit
- the queued insns before the jump. */
- if (JUMP_P (BB_END (bb)))
- before = BB_END (bb);
- else
- {
- /* We'd better be fallthru, or we've lost track of
- what's what. */
- gcc_assert (e->flags & EDGE_FALLTHRU);
+ /* It is possible to have a non-simple jump here. Consider a target
+ where some forms of unconditional jumps clobber a register. This
+ happens on the fr30 for example.
- after = BB_END (bb);
- }
- }
- /* Otherwise we must split the edge. */
+ We know this block has a single successor, so we can just emit
+ the queued insns before the jump. */
+ if (JUMP_P (BB_END (bb)))
+ before = BB_END (bb);
else
{
- bb = split_edge (e);
- after = BB_END (bb);
+ /* We'd better be fallthru, or we've lost track of what's what. */
+ gcc_assert (e->flags & EDGE_FALLTHRU);
- if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections
- && e->src != ENTRY_BLOCK_PTR
- && BB_PARTITION (e->src) == BB_COLD_PARTITION
- && !(e->flags & EDGE_CROSSING))
- {
- rtx bb_note, cur_insn;
-
- bb_note = NULL_RTX;
- for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
- cur_insn = NEXT_INSN (cur_insn))
- if (NOTE_INSN_BASIC_BLOCK_P (cur_insn))
- {
- bb_note = cur_insn;
- break;
- }
-
- if (JUMP_P (BB_END (bb))
- && !any_condjump_p (BB_END (bb))
- && (single_succ_edge (bb)->flags & EDGE_CROSSING))
- REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
- (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
- }
+ after = BB_END (bb);
}
}
- /* Now that we've found the spot, do the insertion. */
+ /* Otherwise we must split the edge. */
+ else
+ {
+ bb = split_edge (e);
+ after = BB_END (bb);
+
+ if (flag_reorder_blocks_and_partition
+ && targetm_common.have_named_sections
+ && e->src != ENTRY_BLOCK_PTR
+ && BB_PARTITION (e->src) == BB_COLD_PARTITION
+ && !(e->flags & EDGE_CROSSING)
+ && JUMP_P (after)
+ && !any_condjump_p (after)
+ && (single_succ_edge (bb)->flags & EDGE_CROSSING))
+ add_reg_note (after, REG_CROSSING_JUMP, NULL_RTX);
+ }
+ /* Now that we've found the spot, do the insertion. */
if (before)
{
emit_insn_before_noloc (insns, before, bb);
}
else
gcc_assert (!JUMP_P (last));
-
- /* Mark the basic block for find_many_sub_basic_blocks. */
- if (current_ir_type () != IR_RTL_CFGLAYOUT)
- bb->aux = &bb->aux;
}
/* Update the CFG for all queued instructions. */
commit_edge_insertions (void)
{
basic_block bb;
- sbitmap blocks;
- bool changed = false;
#ifdef ENABLE_CHECKING
verify_flow_info ();
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->insns.r)
- {
- changed = true;
- commit_one_edge_insertion (e);
- }
+ commit_one_edge_insertion (e);
}
-
- if (!changed)
- return;
-
- /* In the old rtl CFG API, it was OK to insert control flow on an
- edge, apparently? In cfglayout mode, this will *not* work, and
- the caller is responsible for making sure that control flow is
- valid at all times. */
- if (current_ir_type () == IR_RTL_CFGLAYOUT)
- return;
-
- blocks = sbitmap_alloc (last_basic_block);
- sbitmap_zero (blocks);
- FOR_EACH_BB (bb)
- if (bb->aux)
- {
- SET_BIT (blocks, bb->index);
- /* Check for forgotten bb->aux values before commit_edge_insertions
- call. */
- gcc_assert (bb->aux == &bb->aux);
- bb->aux = NULL;
- }
- find_many_sub_basic_blocks (blocks);
- sbitmap_free (blocks);
}
\f
at start and end). */
static void
-rtl_dump_bb (basic_block bb, FILE *outf, int indent)
+rtl_dump_bb (basic_block bb, FILE *outf, int indent, int flags ATTRIBUTE_UNUSED)
{
rtx insn;
rtx last;
s_indent = (char *) alloca ((size_t) indent + 1);
memset (s_indent, ' ', (size_t) indent);
s_indent[indent] = '\0';
-
+
if (df)
{
df_dump_top (bb, outf);
putc ('\n', outf);
}
- for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
- insn = NEXT_INSN (insn))
- print_rtl_single (outf, insn);
+ if (bb->index != ENTRY_BLOCK && bb->index != EXIT_BLOCK)
+ for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
+ insn = NEXT_INSN (insn))
+ print_rtl_single (outf, insn);
if (df)
{
for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
{
int did_output;
- if ((bb = start[INSN_UID (tmp_rtx)]) != NULL)
- {
- edge e;
- edge_iterator ei;
-
- fprintf (outf, ";; Start of basic block (");
- FOR_EACH_EDGE (e, ei, bb->preds)
- fprintf (outf, " %d", e->src->index);
- fprintf (outf, ") -> %d\n", bb->index);
-
- if (df)
- {
- df_dump_top (bb, outf);
- putc ('\n', outf);
- }
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- fputs (";; Pred edge ", outf);
- dump_edge_info (outf, e, 0);
- fputc ('\n', outf);
- }
- }
+
+ bb = start[INSN_UID (tmp_rtx)];
+ if (bb != NULL)
+ dump_bb_info (bb, true, false, dump_flags, ";; ", outf);
if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
&& !NOTE_P (tmp_rtx)
did_output = print_rtl_single (outf, tmp_rtx);
- if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
- {
- edge e;
- edge_iterator ei;
-
- fprintf (outf, ";; End of basic block %d -> (", bb->index);
- FOR_EACH_EDGE (e, ei, bb->succs)
- fprintf (outf, " %d", e->dest->index);
- fprintf (outf, ")\n");
-
- if (df)
- {
- df_dump_bottom (bb, outf);
- putc ('\n', outf);
- }
- putc ('\n', outf);
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- fputs (";; Succ edge ", outf);
- dump_edge_info (outf, e, 1);
- fputc ('\n', outf);
- }
- }
+ bb = end[INSN_UID (tmp_rtx)];
+ if (bb != NULL)
+ dump_bb_info (bb, false, true, dump_flags, ";; ", outf);
if (did_output)
putc ('\n', outf);
}
end = tmp;
/* Include any barriers that may follow the basic block. */
- tmp = next_nonnote_insn (end);
+ tmp = next_nonnote_insn_bb (end);
while (tmp && BARRIER_P (tmp))
{
end = tmp;
- tmp = next_nonnote_insn (end);
+ tmp = next_nonnote_insn_bb (end);
}
return end;
}
FOR_EACH_EDGE (e, ei, bb->succs)
{
+ bool is_crossing;
+
if (e->flags & EDGE_FALLTHRU)
+ n_fallthru++, fallthru = e;
+
+ is_crossing = (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
+ && e->src != ENTRY_BLOCK_PTR
+ && e->dest != EXIT_BLOCK_PTR);
+ if (e->flags & EDGE_CROSSING)
{
- n_fallthru++, fallthru = e;
- if ((e->flags & EDGE_CROSSING)
- || (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
- && e->src != ENTRY_BLOCK_PTR
- && e->dest != EXIT_BLOCK_PTR))
- {
+ if (!is_crossing)
+ {
+ error ("EDGE_CROSSING incorrectly set across same section");
+ err = 1;
+ }
+ if (e->flags & EDGE_FALLTHRU)
+ {
error ("fallthru edge crosses section boundary (bb %i)",
e->src->index);
err = 1;
}
+ if (e->flags & EDGE_EH)
+ {
+ error ("EH edge crosses section boundary (bb %i)",
+ e->src->index);
+ err = 1;
+ }
+ }
+ else if (is_crossing)
+ {
+ error ("EDGE_CROSSING missing across section boundary");
+ err = 1;
}
if ((e->flags & ~(EDGE_DFS_BACK
| EDGE_CAN_FALLTHRU
| EDGE_IRREDUCIBLE_LOOP
| EDGE_LOOP_EXIT
- | EDGE_CROSSING)) == 0)
+ | EDGE_CROSSING
+ | EDGE_PRESERVE)) == 0)
n_branch++;
if (e->flags & EDGE_ABNORMAL_CALL)
n_abnormal++;
}
- if (n_eh && GET_CODE (PATTERN (BB_END (bb))) != RESX
- && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
+ if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
{
error ("missing REG_EH_REGION note in the end of bb %i", bb->index);
err = 1;
}
+ if (n_eh > 1)
+ {
+ error ("too many eh edges %i", bb->index);
+ err = 1;
+ }
if (n_branch
&& (!JUMP_P (BB_END (bb))
|| (n_branch > 1 && (any_uncondjump_p (BB_END (bb))
}
if (n_branch != 1 && any_uncondjump_p (BB_END (bb)))
{
- error ("wrong amount of branch edges after unconditional jump %i", bb->index);
+ error ("wrong number of branch edges after unconditional jump %i",
+ bb->index);
err = 1;
}
if (n_branch != 1 && any_condjump_p (BB_END (bb))
FOR_EACH_BB_REVERSE (bb)
{
edge e;
- edge_iterator ei;
rtx head = BB_HEAD (bb);
rtx end = BB_END (bb);
last_head = PREV_INSN (x);
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_FALLTHRU)
- break;
+ e = find_fallthru_edge (bb->succs);
if (!e)
{
rtx insn;
/* Ensure existence of barrier in BB with no fallthru edges. */
- for (insn = BB_END (bb); !insn || !BARRIER_P (insn);
- insn = NEXT_INSN (insn))
- if (!insn
- || NOTE_INSN_BASIC_BLOCK_P (insn))
+ for (insn = NEXT_INSN (BB_END (bb)); ; insn = NEXT_INSN (insn))
+ {
+ if (!insn || NOTE_INSN_BASIC_BLOCK_P (insn))
{
error ("missing barrier after block %i", bb->index);
err = 1;
break;
}
+ if (BARRIER_P (insn))
+ break;
+ }
}
else if (e->src != ENTRY_BLOCK_PTR
&& e->dest != EXIT_BLOCK_PTR)
case CODE_LABEL:
/* An addr_vec is placed outside any basic block. */
if (NEXT_INSN (x)
- && JUMP_P (NEXT_INSN (x))
- && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
- || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
+ && JUMP_TABLE_DATA_P (NEXT_INSN (x)))
x = NEXT_INSN (x);
/* But in any case, non-deletable labels can appear anywhere. */
bool found;
edge_iterator ei;
+ if (DEBUG_INSN_P (insn) && insn != BB_HEAD (bb))
+ do
+ insn = PREV_INSN (insn);
+ while ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb));
+
/* If this instruction cannot trap, remove REG_EH_REGION notes. */
if (NONJUMP_INSN_P (insn)
&& (note = find_reg_note (insn, REG_EH_REGION, NULL)))
/* Cleanup abnormal edges caused by exceptions or non-local gotos. */
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
{
+ bool remove = false;
+
/* There are three types of edges we need to handle correctly here: EH
edges, abnormal call EH edges, and abnormal call non-EH edges. The
latter can appear when nonlocal gotos are used. */
- if (e->flags & EDGE_EH)
+ if (e->flags & EDGE_ABNORMAL_CALL)
{
- if (can_throw_internal (BB_END (bb))
- /* If this is a call edge, verify that this is a call insn. */
- && (! (e->flags & EDGE_ABNORMAL_CALL)
- || CALL_P (BB_END (bb))))
- {
- ei_next (&ei);
- continue;
- }
+ if (!CALL_P (insn))
+ remove = true;
+ else if (can_nonlocal_goto (insn))
+ ;
+ else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
+ ;
+ else if (flag_tm && find_reg_note (insn, REG_TM, NULL))
+ ;
+ else
+ remove = true;
}
- else if (e->flags & EDGE_ABNORMAL_CALL)
+ else if (e->flags & EDGE_EH)
+ remove = !can_throw_internal (insn);
+
+ if (remove)
{
- if (CALL_P (BB_END (bb))
- && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
- || INTVAL (XEXP (note, 0)) >= 0))
- {
- ei_next (&ei);
- continue;
- }
+ remove_edge (e);
+ df_set_bb_dirty (bb);
+ purged = true;
}
else
- {
- ei_next (&ei);
- continue;
- }
-
- remove_edge (e);
- df_set_bb_dirty (bb);
- purged = true;
+ ei_next (&ei);
}
if (JUMP_P (insn))
return purged;
}
+/* This is used by a few passes that emit some instructions after abnormal
+ calls, moving the basic block's end, while they in fact do want to emit
+ them on the fallthru edge. Look for abnormal call edges, find backward
+ the call in the block and insert the instructions on the edge instead.
+
+ Similarly, handle instructions throwing exceptions internally.
+
+ Return true when instructions have been found and inserted on edges. */
+
+bool
+fixup_abnormal_edges (void)
+{
+ bool inserted = false;
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ edge e;
+ edge_iterator ei;
+
+ /* Look for cases we are interested in - calls or instructions causing
+ exceptions. */
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if ((e->flags & EDGE_ABNORMAL_CALL)
+ || ((e->flags & (EDGE_ABNORMAL | EDGE_EH))
+ == (EDGE_ABNORMAL | EDGE_EH)))
+ break;
+
+ if (e && !CALL_P (BB_END (bb)) && !can_throw_internal (BB_END (bb)))
+ {
+ rtx insn;
+
+ /* Get past the new insns generated. Allow notes, as the insns
+ may be already deleted. */
+ insn = BB_END (bb);
+ while ((NONJUMP_INSN_P (insn) || NOTE_P (insn))
+ && !can_throw_internal (insn)
+ && insn != BB_HEAD (bb))
+ insn = PREV_INSN (insn);
+
+ if (CALL_P (insn) || can_throw_internal (insn))
+ {
+ rtx stop, next;
+
+ e = find_fallthru_edge (bb->succs);
+
+ stop = NEXT_INSN (BB_END (bb));
+ BB_END (bb) = insn;
+
+ for (insn = NEXT_INSN (insn); insn != stop; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (INSN_P (insn))
+ {
+ delete_insn (insn);
+
+ /* Sometimes there's still the return value USE.
+ If it's placed after a trapping call (i.e. that
+ call is the last insn anyway), we have no fallthru
+ edge. Simply delete this use and don't try to insert
+ on the non-existent edge. */
+ if (GET_CODE (PATTERN (insn)) != USE)
+ {
+ /* We're not deleting it, we're moving it. */
+ INSN_DELETED_P (insn) = 0;
+ PREV_INSN (insn) = NULL_RTX;
+ NEXT_INSN (insn) = NULL_RTX;
+
+ insert_insn_on_edge (insn, e);
+ inserted = true;
+ }
+ }
+ else if (!BARRIER_P (insn))
+ set_block_for_insn (insn, NULL);
+ }
+ }
+
+ /* It may be that we don't find any trapping insn. In this
+ case we discovered quite late that the insn that had been
+ marked as can_throw_internal in fact couldn't trap at all.
+ So we should in fact delete the EH edges out of the block. */
+ else
+ purge_dead_edges (bb);
+ }
+ }
+
+ return inserted;
+}
+
/* Same as split_block but update cfg_layout structures. */
static basic_block
e->flags &= ~EDGE_FALLTHRU;
redirected = redirect_branch_edge (e, dest);
gcc_assert (redirected);
- e->flags |= EDGE_FALLTHRU;
- df_set_bb_dirty (e->src);
- return e;
+ redirected->flags |= EDGE_FALLTHRU;
+ df_set_bb_dirty (redirected->src);
+ return redirected;
}
/* In case we are redirecting fallthru edge to the branch edge
of conditional jump, remove it. */
&& onlyjump_p (BB_END (src)))
delete_insn (BB_END (src));
}
- ret = redirect_edge_succ_nodup (e, dest);
if (dump_file)
- fprintf (dump_file, "Fallthru edge %i->%i redirected to %i\n",
+ fprintf (dump_file, "Redirecting fallthru edge %i->%i to %i\n",
e->src->index, e->dest->index, dest->index);
+ ret = redirect_edge_succ_nodup (e, dest);
}
else
ret = redirect_branch_edge (e, dest);
if (BB_PARTITION (a) != BB_PARTITION (b))
return false;
+ /* If we would end up moving B's instructions, make sure it doesn't fall
+ through into the exit block, since we cannot recover from a fallthrough
+ edge into the exit block occurring in the middle of a function. */
+ if (NEXT_INSN (BB_END (a)) != BB_HEAD (b))
+ {
+ edge e = find_fallthru_edge (b->succs);
+ if (e && e->dest == EXIT_BLOCK_PTR)
+ return false;
+ }
+
/* There must be exactly one edge in between the blocks. */
return (single_succ_p (a)
&& single_succ (a) == b
static void
cfg_layout_merge_blocks (basic_block a, basic_block b)
{
-#ifdef ENABLE_CHECKING
- gcc_assert (cfg_layout_can_merge_blocks_p (a, b));
-#endif
+ bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
+
+ gcc_checking_assert (cfg_layout_can_merge_blocks_p (a, b));
if (dump_file)
- fprintf (dump_file, "merging block %d into block %d\n", b->index, a->index);
+ fprintf (dump_file, "Merging block %d into block %d...\n", b->index,
+ a->index);
/* If there was a CODE_LABEL beginning B, delete it. */
if (LABEL_P (BB_HEAD (b)))
{
- /* This might have been an EH label that no longer has incoming
- EH edges. Update data structures to match. */
- maybe_remove_eh_handler (BB_HEAD (b));
-
delete_insn (BB_HEAD (b));
}
try_redirect_by_replacing_jump (EDGE_SUCC (a, 0), b, true);
gcc_assert (!JUMP_P (BB_END (a)));
+ /* When not optimizing and the edge is the only place in RTL which holds
+ some unique locus, emit a nop with that locus in between. */
+ if (!optimize && EDGE_SUCC (a, 0)->goto_locus)
+ {
+ rtx insn = BB_END (a), end = PREV_INSN (BB_HEAD (a));
+ int goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
+ while (insn != end && (!INSN_P (insn) || INSN_LOCATOR (insn) == 0))
+ insn = PREV_INSN (insn);
+ if (insn != end && locator_eq (INSN_LOCATOR (insn), goto_locus))
+ goto_locus = 0;
+ else
+ {
+ insn = BB_HEAD (b);
+ end = NEXT_INSN (BB_END (b));
+ while (insn != end && !INSN_P (insn))
+ insn = NEXT_INSN (insn);
+ if (insn != end && INSN_LOCATOR (insn) != 0
+ && locator_eq (INSN_LOCATOR (insn), goto_locus))
+ goto_locus = 0;
+ }
+ if (goto_locus)
+ {
+ BB_END (a) = emit_insn_after_noloc (gen_nop (), BB_END (a), a);
+ INSN_LOCATOR (BB_END (a)) = goto_locus;
+ }
+ }
+
/* Possible line number notes should appear in between. */
if (b->il.rtl->header)
{
rtx first = BB_END (a), last;
last = emit_insn_after_noloc (b->il.rtl->header, BB_END (a), a);
+ /* The above might add a BARRIER as BB_END, but as barriers
+ aren't valid parts of a bb, remove_insn doesn't update
+ BB_END if it is a barrier. So adjust BB_END here. */
+ while (BB_END (a) != first && BARRIER_P (BB_END (a)))
+ BB_END (a) = PREV_INSN (BB_END (a));
delete_insn_chain (NEXT_INSN (first), last, false);
b->il.rtl->header = NULL;
}
b->il.rtl->footer = NULL;
}
+ /* If B was a forwarder block, propagate the locus on the edge. */
+ if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus)
+ EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
if (dump_file)
- fprintf (dump_file, "Merged blocks %d and %d.\n",
- a->index, b->index);
+ fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index);
}
/* Split edge E. */
while (!CALL_P (insn)
&& insn != BB_HEAD (bb)
&& (keep_with_call_p (insn)
- || NOTE_P (insn)))
+ || NOTE_P (insn)
+ || DEBUG_INSN_P (insn)))
insn = PREV_INSN (insn);
return (CALL_P (insn));
}
if ((CALL_P (insn)
&& !SIBLING_CALL_P (insn)
&& !find_reg_note (insn, REG_NORETURN, NULL)
- && !CONST_OR_PURE_CALL_P (insn)))
+ && !(RTL_CONST_OR_PURE_CALL_P (insn))))
return true;
return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
e = find_edge (bb, EXIT_BLOCK_PTR);
if (e)
{
- insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+ insert_insn_on_edge (gen_use (const0_rtx), e);
commit_edge_insertions ();
}
}
op0 = force_operand (op0, NULL_RTX);
op1 = force_operand (op1, NULL_RTX);
do_compare_rtx_and_jump (op0, op1, comp, 0,
- mode, NULL_RTX, NULL_RTX, label);
+ mode, NULL_RTX, NULL_RTX, label, -1);
jump = get_last_insn ();
JUMP_LABEL (jump) = label;
LABEL_NUSES (label)++;
init_rtl_bb_info (basic_block bb)
{
gcc_assert (!bb->il.rtl);
- bb->il.rtl = GGC_CNEW (struct rtl_bb_info);
-}
-
-
-/* Add EXPR to the end of basic block BB. */
-
-rtx
-insert_insn_end_bb_new (rtx pat, basic_block bb)
-{
- rtx insn = BB_END (bb);
- rtx new_insn;
- rtx pat_end = pat;
-
- while (NEXT_INSN (pat_end) != NULL_RTX)
- pat_end = NEXT_INSN (pat_end);
-
- /* If the last insn is a jump, insert EXPR in front [taking care to
- handle cc0, etc. properly]. Similarly we need to care trapping
- instructions in presence of non-call exceptions. */
-
- if (JUMP_P (insn)
- || (NONJUMP_INSN_P (insn)
- && (!single_succ_p (bb)
- || single_succ_edge (bb)->flags & EDGE_ABNORMAL)))
- {
-#ifdef HAVE_cc0
- rtx note;
-#endif
- /* If this is a jump table, then we can't insert stuff here. Since
- we know the previous real insn must be the tablejump, we insert
- the new instruction just before the tablejump. */
- if (GET_CODE (PATTERN (insn)) == ADDR_VEC
- || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
- insn = prev_real_insn (insn);
-
-#ifdef HAVE_cc0
- /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts
- if cc0 isn't set. */
- note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
- if (note)
- insn = XEXP (note, 0);
- else
- {
- rtx maybe_cc0_setter = prev_nonnote_insn (insn);
- if (maybe_cc0_setter
- && INSN_P (maybe_cc0_setter)
- && sets_cc0_p (PATTERN (maybe_cc0_setter)))
- insn = maybe_cc0_setter;
- }
-#endif
- /* FIXME: What if something in cc0/jump uses value set in new
- insn? */
- new_insn = emit_insn_before_noloc (pat, insn, bb);
- }
-
- /* Likewise if the last insn is a call, as will happen in the presence
- of exception handling. */
- else if (CALL_P (insn)
- && (!single_succ_p (bb)
- || single_succ_edge (bb)->flags & EDGE_ABNORMAL))
- {
- /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
- we search backward and place the instructions before the first
- parameter is loaded. Do this for everyone for consistency and a
- presumption that we'll get better code elsewhere as well. */
-
- /* Since different machines initialize their parameter registers
- in different orders, assume nothing. Collect the set of all
- parameter registers. */
- insn = find_first_parameter_load (insn, BB_HEAD (bb));
-
- /* If we found all the parameter loads, then we want to insert
- before the first parameter load.
-
- If we did not find all the parameter loads, then we might have
- stopped on the head of the block, which could be a CODE_LABEL.
- If we inserted before the CODE_LABEL, then we would be putting
- the insn in the wrong basic block. In that case, put the insn
- after the CODE_LABEL. Also, respect NOTE_INSN_BASIC_BLOCK. */
- while (LABEL_P (insn)
- || NOTE_INSN_BASIC_BLOCK_P (insn))
- insn = NEXT_INSN (insn);
-
- new_insn = emit_insn_before_noloc (pat, insn, bb);
- }
- else
- new_insn = emit_insn_after_noloc (pat, insn, bb);
-
- return new_insn;
+ bb->il.rtl = ggc_alloc_cleared_rtl_bb_info ();
}
/* Returns true if it is possible to remove edge E by redirecting
return true;
}
+/* We do not want to declare these functions in a header file, since they
+ should only be used through the cfghooks interface, and we do not want to
+ move them here since it would require also moving quite a lot of related
+ code. They are in cfglayout.c. */
+extern bool cfg_layout_can_duplicate_bb_p (const_basic_block);
+extern basic_block cfg_layout_duplicate_bb (basic_block);
+
+static basic_block
+rtl_duplicate_bb (basic_block bb)
+{
+ bb = cfg_layout_duplicate_bb (bb);
+ bb->aux = NULL;
+ return bb;
+}
+
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
"rtl",
rtl_merge_blocks,
rtl_predict_edge,
rtl_predicted_by_p,
- NULL, /* can_duplicate_block_p */
- NULL, /* duplicate_block */
+ cfg_layout_can_duplicate_bb_p,
+ rtl_duplicate_bb,
rtl_split_edge,
rtl_make_forwarder_block,
rtl_tidy_fallthru_edge,
+ rtl_force_nonfallthru,
rtl_block_ends_with_call_p,
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,
This representation will hopefully become the default one in future
version of the compiler. */
-/* We do not want to declare these functions in a header file, since they
- should only be used through the cfghooks interface, and we do not want to
- move them here since it would require also moving quite a lot of related
- code. They are in cfglayout.c. */
-extern bool cfg_layout_can_duplicate_bb_p (const_basic_block);
-extern basic_block cfg_layout_duplicate_bb (basic_block);
-
struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
"cfglayout mode",
rtl_verify_flow_info_1,
cfg_layout_duplicate_bb,
cfg_layout_split_edge,
rtl_make_forwarder_block,
- NULL,
+ NULL, /* tidy_fallthru_edge */
+ rtl_force_nonfallthru,
rtl_block_ends_with_call_p,
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,