/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 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. */
/* This file contains low level functions to manipulate the CFG and analyze it
that are aware of the RTL intermediate language.
#include "cfglayout.h"
#include "expr.h"
#include "target.h"
-
-
-/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
-/* ??? Should probably be using LABEL_NUSES instead. It would take a
- bit of surgery to be able to use or co-opt the routines in jump. */
-rtx label_value_list;
+#include "cfgloop.h"
+#include "ggc.h"
+#include "tree-pass.h"
+#include "df.h"
static int can_delete_note_p (rtx);
static int can_delete_label_p (rtx);
-static void commit_one_edge_insertion (edge, int);
-static rtx last_loop_beg_note (rtx);
-static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
+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_split_block (basic_block, void *);
static void rtl_dump_bb (basic_block, FILE *, int);
static int rtl_verify_flow_info_1 (void);
-static void mark_killed_regs (rtx, rtx, void *);
static void rtl_make_forwarder_block (edge);
\f
/* Return true if NOTE is not one of the ones that must be kept paired,
static int
can_delete_note_p (rtx note)
{
- return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
- || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK
- || NOTE_LINE_NUMBER (note) == NOTE_INSN_UNLIKELY_EXECUTED_CODE);
+ return (NOTE_KIND (note) == NOTE_INSN_DELETED
+ || NOTE_KIND (note) == NOTE_INSN_BASIC_BLOCK);
}
/* True if a given label can be deleted. */
return (!LABEL_PRESERVE_P (label)
/* User declared labels must be preserved. */
&& LABEL_NAME (label) == 0
- && !in_expr_list_p (forced_labels, label)
- && !in_expr_list_p (label_value_list, label));
+ && !in_expr_list_p (forced_labels, label));
}
/* Delete INSN by patching it out. Return the next insn. */
if (LABEL_P (insn))
{
/* Some labels can't be directly removed from the INSN chain, as they
- might be references via variables, constant pool etc.
- Convert them to the special NOTE_INSN_DELETED_LABEL note. */
+ might be references via variables, constant pool etc.
+ Convert them to the special NOTE_INSN_DELETED_LABEL note. */
if (! can_delete_label_p (insn))
{
const char *name = LABEL_NAME (insn);
really_delete = false;
PUT_CODE (insn, NOTE);
- NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
+ NOTE_KIND (insn) = NOTE_INSN_DELETED_LABEL;
NOTE_DELETED_LABEL_NAME (insn) = name;
}
}
/* Unlink a chain of insns between START and FINISH, leaving notes
- that must be paired. */
+ that must be paired. If CLEAR_BB is true, we set bb field for
+ insns that cannot be removed to NULL. */
void
-delete_insn_chain (rtx start, rtx finish)
+delete_insn_chain (rtx start, rtx finish, bool clear_bb)
{
rtx next;
else
next = delete_insn (start);
+ if (clear_bb && !INSN_DELETED_P (start))
+ set_block_for_insn (start, NULL);
+
if (start == finish)
break;
start = next;
&& BLOCK_FOR_INSN (last)
&& BB_END (BLOCK_FOR_INSN (last)) == last)
purge = true;
- delete_insn_chain (first, last);
+ delete_insn_chain (first, last, false);
if (purge)
purge_dead_edges (BLOCK_FOR_INSN (last));
}
bb = alloc_block ();
+ init_rtl_bb_info (bb);
if (!head && !end)
head = end = bb_note
= emit_note_after (NOTE_INSN_BASIC_BLOCK, get_last_insn ());
BB_HEAD (bb) = head;
BB_END (bb) = end;
bb->index = last_basic_block++;
- bb->flags = BB_NEW;
+ bb->flags = BB_NEW | BB_RTL;
link_block (bb, after);
- BASIC_BLOCK (bb->index) = bb;
+ SET_BASIC_BLOCK (bb->index, bb);
+ df_bb_refs_record (bb->index, false);
update_bb_for_insn (bb);
BB_SET_PARTITION (bb, BB_UNPARTITIONED);
static basic_block
rtl_create_basic_block (void *headp, void *endp, basic_block after)
{
- rtx head = headp, end = endp;
+ rtx head = (rtx) headp, end = (rtx) endp;
basic_block bb;
/* Grow the basic block array if needed. */
- if ((size_t) last_basic_block >= VARRAY_SIZE (basic_block_info))
+ if ((size_t) last_basic_block >= VEC_length (basic_block, basic_block_info))
{
size_t new_size = last_basic_block + (last_basic_block + 3) / 4;
- VARRAY_GROW (basic_block_info, new_size);
+ VEC_safe_grow_cleared (basic_block, gc, basic_block_info, new_size);
}
n_basic_blocks++;
{
basic_block newbb = rtl_create_basic_block (head, end, after);
- initialize_bb_rbi (newbb);
return newbb;
}
\f
static void
rtl_delete_block (basic_block b)
{
- rtx insn, end, tmp;
+ rtx insn, end;
/* If the head of this block is a CODE_LABEL, then it might be the
label for an exception handler which can't be reached. We need
if (LABEL_P (insn))
maybe_remove_eh_handler (insn);
- /* Include any jump table following the basic block. */
- end = BB_END (b);
- if (tablejump_p (end, NULL, &tmp))
- end = tmp;
-
- /* Include any barriers that may follow the basic block. */
- tmp = next_nonnote_insn (end);
- while (tmp && BARRIER_P (tmp))
- {
- end = tmp;
- tmp = next_nonnote_insn (end);
- }
+ end = get_last_bb_insn (b);
/* Selectively delete the entire chain. */
BB_HEAD (b) = NULL;
- delete_insn_chain (insn, end);
+ delete_insn_chain (insn, end, true);
+
+
+ if (dump_file)
+ fprintf (dump_file, "deleting block %d\n", b->index);
+ df_bb_delete (b->index);
}
\f
/* Records the basic block struct in BLOCK_FOR_INSN for every insn. */
/* Release the basic_block_for_insn array. */
-void
+unsigned int
free_bb_for_insn (void)
{
rtx insn;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (!BARRIER_P (insn))
BLOCK_FOR_INSN (insn) = NULL;
+ return 0;
}
+struct tree_opt_pass pass_free_cfg =
+{
+ NULL, /* name */
+ NULL, /* gate */
+ free_bb_for_insn, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ PROP_cfg, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
/* Return RTX to emit after when we want to emit code on the entry of function. */
rtx
entry_of_function (void)
{
- return (n_basic_blocks ? BB_HEAD (ENTRY_BLOCK_PTR->next_bb) : get_insns ());
+ return (n_basic_blocks > NUM_FIXED_BLOCKS ?
+ BB_HEAD (ENTRY_BLOCK_PTR->next_bb) : get_insns ());
+}
+
+/* Emit INSN at the entry point of the function, ensuring that it is only
+ executed once per function. */
+void
+emit_insn_at_entry (rtx insn)
+{
+ edge_iterator ei = ei_start (ENTRY_BLOCK_PTR->succs);
+ edge e = ei_safe_edge (ei);
+ gcc_assert (e->flags & EDGE_FALLTHRU);
+
+ insert_insn_on_edge (insn, e);
+ commit_edge_insertions ();
}
/* Update insns block within BB. */
for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
{
if (!BARRIER_P (insn))
- set_block_for_insn (insn, bb);
+ {
+ set_block_for_insn (insn, bb);
+ df_insn_change_bb (insn);
+ }
if (insn == BB_END (bb))
break;
}
}
\f
+/* Return the INSN immediately following the NOTE_INSN_BASIC_BLOCK
+ note associated with the BLOCK. */
+
+static rtx
+first_insn_after_basic_block_note (basic_block block)
+{
+ rtx insn;
+
+ /* Get the first instruction in the block. */
+ insn = BB_HEAD (block);
+
+ if (insn == NULL_RTX)
+ return NULL_RTX;
+ if (LABEL_P (insn))
+ insn = NEXT_INSN (insn);
+ gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn));
+
+ return NEXT_INSN (insn);
+}
+
/* Creates a new basic block just after basic block B by splitting
everything after specified instruction I. */
rtl_split_block (basic_block bb, void *insnp)
{
basic_block new_bb;
- rtx insn = insnp;
+ rtx insn = (rtx) insnp;
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, new_bb->succs)
e->src = new_bb;
- if (bb->global_live_at_start)
- {
- new_bb->global_live_at_start = ALLOC_REG_SET (®_obstack);
- new_bb->global_live_at_end = ALLOC_REG_SET (®_obstack);
- COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end);
-
- /* We now have to calculate which registers are live at the end
- of the split basic block and at the start of the new basic
- block. Start with those registers that are known to be live
- at the end of the original basic block and get
- propagate_block to determine which registers are live. */
- COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_end);
- propagate_block (new_bb, new_bb->global_live_at_start, NULL, NULL, 0);
- COPY_REG_SET (bb->global_live_at_end,
- new_bb->global_live_at_start);
-#ifdef HAVE_conditional_execution
- /* In the presence of conditional execution we are not able to update
- liveness precisely. */
- if (reload_completed)
- {
- bb->flags |= BB_DIRTY;
- new_bb->flags |= BB_DIRTY;
- }
-#endif
- }
-
+ /* The new block starts off being dirty. */
+ df_set_bb_dirty (bb);
return new_bb;
}
rtx del_first = NULL_RTX, del_last = NULL_RTX;
int b_empty = 0;
+ if (dump_file)
+ 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 (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)
for (prev = PREV_INSN (a_end); ; prev = PREV_INSN (prev))
if (!NOTE_P (prev)
- || NOTE_LINE_NUMBER (prev) == NOTE_INSN_BASIC_BLOCK
+ || NOTE_INSN_BASIC_BLOCK_P (prev)
|| prev == BB_HEAD (a))
break;
/* Delete everything marked above as well as crap that might be
hanging out between the two blocks. */
BB_HEAD (b) = NULL;
- delete_insn_chain (del_first, del_last);
+ delete_insn_chain (del_first, del_last, true);
/* Reassociate the insns of B with A. */
if (!b_empty)
rtx x;
for (x = a_end; x != b_end; x = NEXT_INSN (x))
- set_block_for_insn (x, a);
+ {
+ set_block_for_insn (x, a);
+ df_insn_change_bb (x);
+ }
set_block_for_insn (b_end, a);
+ df_insn_change_bb (b_end);
a_end = b_end;
}
+ df_bb_delete (b->index);
BB_END (a) = a_end;
}
+
/* Return true when block A and B can be merged. */
static bool
rtl_can_merge_blocks (basic_block a,basic_block b)
and cold sections.
Basic block partitioning may result in some jumps that appear to
- be optimizable (or blocks that appear to be mergeable), but which really
- must be left untouched (they are required to make it safely across
- partition boundaries). See the comments at the top of
+ be optimizable (or blocks that appear to be mergeable), but which really
+ must be left untouched (they are required to make it safely across
+ partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
- || find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (a) != BB_PARTITION (b)))
+ if (BB_PARTITION (a) != BB_PARTITION (b))
return false;
/* There must be exactly one edge in between the blocks. */
- return (EDGE_COUNT (a->succs) == 1
- && EDGE_SUCC (a, 0)->dest == b
- && EDGE_COUNT (b->preds) == 1
+ return (single_succ_p (a)
+ && single_succ (a) == b
+ && single_pred_p (b)
&& a != b
/* Must be simple edge. */
- && !(EDGE_SUCC (a, 0)->flags & EDGE_COMPLEX)
+ && !(single_succ_edge (a)->flags & EDGE_COMPLEX)
&& a->next_bb == b
&& a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
/* If the jump insn has side effects,
and cold sections.
Basic block partitioning may result in some jumps that appear to
- be optimizable (or blocks that appear to be mergeable), but which really
- must be left untouched (they are required to make it safely across
- partition boundaries). See the comments at the top of
+ be optimizable (or blocks that appear to be mergeable), but which really
+ must be left untouched (they are required to make it safely across
+ partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
-
- if (flag_reorder_blocks_and_partition
- && (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (src) != BB_PARTITION (target)))
+
+ if (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
+ || BB_PARTITION (src) != BB_PARTITION (target))
return NULL;
/* We can replace or remove a complex jump only when we have exactly
the cc0 setter too. */
kill_from = insn;
#ifdef HAVE_cc0
- if (reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+ if (reg_mentioned_p (cc0_rtx, PATTERN (insn))
+ && only_sets_cc0_p (PREV_INSN (insn)))
kill_from = PREV_INSN (insn);
#endif
/* Selectively unlink whole insn chain. */
if (in_cfglayout)
{
- rtx insn = src->rbi->footer;
+ rtx insn = src->il.rtl->footer;
- delete_insn_chain (kill_from, BB_END (src));
+ delete_insn_chain (kill_from, BB_END (src), false);
/* Remove barriers but keep jumptables. */
while (insn)
if (PREV_INSN (insn))
NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
else
- src->rbi->footer = NEXT_INSN (insn);
+ src->il.rtl->footer = NEXT_INSN (insn);
if (NEXT_INSN (insn))
PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
}
}
}
else
- delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)));
+ delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)),
+ false);
}
/* If this already is simplejump, redirect it. */
INSN_UID (insn), INSN_UID (BB_END (src)));
- delete_insn_chain (kill_from, insn);
+ delete_insn_chain (kill_from, insn, false);
/* Recognize a tablejump that we are converting to a
simple jump and remove its associated CODE_LABEL
and ADDR_VEC or ADDR_DIFF_VEC. */
if (tablejump_p (insn, &label, &table))
- delete_insn_chain (label, table);
+ delete_insn_chain (label, table, false);
barrier = next_nonnote_insn (BB_END (src));
if (!barrier || !BARRIER_P (barrier))
for (tmp = NEXT_INSN (BB_END (src)); tmp != barrier;
tmp = NEXT_INSN (tmp))
- set_block_for_insn (tmp, src);
+ {
+ set_block_for_insn (tmp, src);
+ df_insn_change_bb (tmp);
+ }
NEXT_INSN (PREV_INSN (new_insn)) = NEXT_INSN (new_insn);
PREV_INSN (NEXT_INSN (new_insn)) = PREV_INSN (new_insn);
}
/* Keep only one edge out and set proper flags. */
- while (EDGE_COUNT (src->succs) > 1)
+ if (!single_succ_p (src))
remove_edge (e);
+ gcc_assert (single_succ_p (src));
- e = EDGE_SUCC (src, 0);
+ e = single_succ_edge (src);
if (fallthru)
e->flags = EDGE_FALLTHRU;
else
e->probability = REG_BR_PROB_BASE;
e->count = src->count;
- /* We don't want a block to end on a line-number note since that has
- the potential of changing the code between -g and not -g. */
- while (NOTE_P (BB_END (e->src))
- && NOTE_LINE_NUMBER (BB_END (e->src)) >= 0)
- delete_insn (BB_END (e->src));
-
if (e->dest != target)
redirect_edge_succ (e, target);
-
return e;
}
-/* Return last loop_beg note appearing after INSN, before start of next
- basic block. Return INSN if there are no such notes.
-
- When emitting jump to redirect a fallthru edge, it should always appear
- after the LOOP_BEG notes, as loop optimizer expect loop to either start by
- fallthru edge or jump following the LOOP_BEG note jumping to the loop exit
- test. */
-
-static rtx
-last_loop_beg_note (rtx insn)
-{
- rtx last = insn;
-
- for (insn = NEXT_INSN (insn); insn && NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK;
- insn = NEXT_INSN (insn))
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- last = insn;
-
- return last;
-}
-
/* Redirect edge representing branch of (un)conditional jump or tablejump,
NULL on failure */
static edge
&& GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
&& XEXP (XEXP (SET_SRC (tmp), 2), 0) == old_label)
{
- XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (Pmode,
new_label);
--LABEL_NUSES (old_label);
++LABEL_NUSES (new_label);
if (e->dest != target)
e = redirect_edge_succ_nodup (e, target);
+
return e;
}
if ((ret = try_redirect_by_replacing_jump (e, target, false)) != NULL)
{
- src->flags |= BB_DIRTY;
+ df_set_bb_dirty (src);
return ret;
}
if (!ret)
return NULL;
- src->flags |= BB_DIRTY;
+ df_set_bb_dirty (src);
return ret;
}
by creating a basic block afterwards to redirect fallthru edge. */
if (e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR
&& any_condjump_p (BB_END (e->src))
- /* When called from cfglayout, fallthru edges do not
- necessarily go to the next block. */
- && e->src->next_bb == e->dest
&& JUMP_LABEL (BB_END (e->src)) == BB_HEAD (e->dest))
{
rtx note;
redirected = redirect_jump (BB_END (e->src), block_label (target), 0);
gcc_assert (redirected);
-
+
note = find_reg_note (BB_END (e->src), REG_BR_PROB, NULL_RTX);
if (note)
{
edge tmp;
edge_iterator ei;
bool found = false;
-
+
basic_block bb = create_basic_block (BB_HEAD (e->dest), NULL, ENTRY_BLOCK_PTR);
-
+
/* Change the existing edge's source to be the new block, and add
a new edge from the entry block to the new block. */
e->src = bb;
else
ei_next (&ei);
}
-
+
gcc_assert (found);
-
- VEC_safe_push (edge, bb->succs, e);
+
+ VEC_safe_push (edge, gc, bb->succs, e);
make_single_succ_edge (ENTRY_BLOCK_PTR, bb, EDGE_FALLTHRU);
}
}
forward from the last instruction of the old block. */
if (!tablejump_p (BB_END (e->src), NULL, ¬e))
note = BB_END (e->src);
-
- /* Position the new block correctly relative to loop notes. */
- note = last_loop_beg_note (note);
note = NEXT_INSN (note);
jump_block = create_basic_block (note, NULL, e->src);
jump_block->frequency = EDGE_FREQUENCY (e);
jump_block->loop_depth = target->loop_depth;
- if (target->global_live_at_start)
- {
- jump_block->global_live_at_start = ALLOC_REG_SET (®_obstack);
- jump_block->global_live_at_end = ALLOC_REG_SET (®_obstack);
- COPY_REG_SET (jump_block->global_live_at_start,
- target->global_live_at_start);
- COPY_REG_SET (jump_block->global_live_at_end,
- target->global_live_at_start);
- }
-
/* Make sure new block ends up in correct hot/cold section. */
BB_COPY_PARTITION (jump_block, e->src);
if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections)
- {
- if (BB_PARTITION (jump_block) == BB_COLD_PARTITION)
- {
- rtx bb_note, new_note;
- for (bb_note = BB_HEAD (jump_block);
- bb_note && bb_note != NEXT_INSN (BB_END (jump_block));
- bb_note = NEXT_INSN (bb_note))
- if (NOTE_P (bb_note)
- && NOTE_LINE_NUMBER (bb_note) == NOTE_INSN_BASIC_BLOCK)
- break;
- new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
- bb_note);
- NOTE_BASIC_BLOCK (new_note) = jump_block;
- }
- if (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)));
- }
+ && targetm.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)));
/* Wire edge in. */
new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
if (abnormal_edge_flags)
make_edge (src, target, abnormal_edge_flags);
+ df_mark_solutions_dirty ();
return new_bb;
}
/* Redirect edge even at the expense of creating new jump insn or
basic block. Return new basic block if created, NULL otherwise.
- Abort if conversion is impossible. */
+ Conversion must be possible. */
static basic_block
rtl_redirect_edge_and_branch_force (edge e, basic_block target)
/* 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);
}
/* ??? In a late-running flow pass, other folks may have deleted basic
blocks by nopping out blocks, leaving multiple BARRIERs between here
- and the target label. They ought to be chastized and fixed.
+ and the target label. They ought to be chastised and fixed.
We can also wind up with a sequence of undeletable labels between
one block and the next.
if (JUMP_P (q)
&& onlyjump_p (q)
&& (any_uncondjump_p (q)
- || EDGE_COUNT (b->succs) == 1))
+ || single_succ_p (b)))
{
#ifdef HAVE_cc0
/* If this was a conditional jump, we need to also delete
#endif
q = PREV_INSN (q);
-
- /* We don't want a block to end on a line-number note since that has
- the potential of changing the code between -g and not -g. */
- while (NOTE_P (q) && NOTE_LINE_NUMBER (q) >= 0)
- q = PREV_INSN (q);
}
/* Selectively unlink the sequence. */
if (q != PREV_INSN (BB_HEAD (c)))
- delete_insn_chain (NEXT_INSN (q), PREV_INSN (BB_HEAD (c)));
+ delete_insn_chain (NEXT_INSN (q), PREV_INSN (BB_HEAD (c)), false);
e->flags |= EDGE_FALLTHRU;
}
\f
-/* Helper function for split_edge. Return true in case edge BB2 to BB1
- is back edge of syntactic loop. */
-
-static bool
-back_edge_of_syntactic_loop_p (basic_block bb1, basic_block bb2)
-{
- rtx insn;
- int count = 0;
- basic_block bb;
-
- if (bb1 == bb2)
- return true;
-
- /* ??? Could we guarantee that bb indices are monotone, so that we could
- just compare them? */
- for (bb = bb1; bb && bb != bb2; bb = bb->next_bb)
- continue;
-
- if (!bb)
- return false;
-
- for (insn = BB_END (bb1); insn != BB_HEAD (bb2) && count >= 0;
- insn = NEXT_INSN (insn))
- if (NOTE_P (insn))
- {
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- count++;
- else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
- count--;
- }
-
- return count >= 0;
-}
-
/* Should move basic block BB after basic block AFTER. NIY. */
static bool
}
/* Split a (typically critical) edge. Return the new block.
- Abort on abnormal edges.
+ The edge must not be abnormal.
??? The code generally expects to be called on critical edges.
The case of a block ending in an unconditional jump to a
force_nonfallthru (e);
}
- /* Create the basic block note.
-
- Where we place the note can have a noticeable impact on the generated
- code. Consider this cfg:
-
- E
- |
- 0
- / \
- +->1-->2--->E
- | |
- +--+
-
- If we need to insert an insn on the edge from block 0 to block 1,
- we want to ensure the instructions we insert are outside of any
- loop notes that physically sit between block 0 and block 1. Otherwise
- we confuse the loop optimizer into thinking the loop is a phony. */
-
- if (edge_in->dest != EXIT_BLOCK_PTR
- && PREV_INSN (BB_HEAD (edge_in->dest))
- && NOTE_P (PREV_INSN (BB_HEAD (edge_in->dest)))
- && (NOTE_LINE_NUMBER (PREV_INSN (BB_HEAD (edge_in->dest)))
- == NOTE_INSN_LOOP_BEG)
- && !back_edge_of_syntactic_loop_p (edge_in->dest, edge_in->src))
- before = PREV_INSN (BB_HEAD (edge_in->dest));
- else if (edge_in->dest != EXIT_BLOCK_PTR)
+ /* Create the basic block note. */
+ if (edge_in->dest != EXIT_BLOCK_PTR)
before = BB_HEAD (edge_in->dest);
else
before = NULL_RTX;
if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR)
{
before = NEXT_INSN (BB_END (edge_in->src));
- if (before
- && NOTE_P (before)
- && NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END)
- before = NEXT_INSN (before);
bb = create_basic_block (before, NULL, edge_in->src);
BB_COPY_PARTITION (bb, edge_in->src);
}
BB_COPY_PARTITION (bb, edge_in->dest);
}
- /* ??? This info is likely going to be out of date very soon. */
- if (edge_in->dest->global_live_at_start)
- {
- bb->global_live_at_start = ALLOC_REG_SET (®_obstack);
- bb->global_live_at_end = ALLOC_REG_SET (®_obstack);
- COPY_REG_SET (bb->global_live_at_start,
- edge_in->dest->global_live_at_start);
- COPY_REG_SET (bb->global_live_at_end,
- edge_in->dest->global_live_at_start);
- }
-
make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
/* For non-fallthru edges, we must adjust the predecessor's
end_sequence ();
}
-/* Called from safe_insert_insn_on_edge through note_stores, marks live
- registers that are killed by the store. */
-static void
-mark_killed_regs (rtx reg, rtx set ATTRIBUTE_UNUSED, void *data)
-{
- regset killed = data;
- int regno, i;
-
- if (GET_CODE (reg) == SUBREG)
- reg = SUBREG_REG (reg);
- if (!REG_P (reg))
- return;
- regno = REGNO (reg);
- if (regno >= FIRST_PSEUDO_REGISTER)
- SET_REGNO_REG_SET (killed, regno);
- else
- {
- for (i = 0; i < (int) hard_regno_nregs[regno][GET_MODE (reg)]; i++)
- SET_REGNO_REG_SET (killed, regno + i);
- }
-}
-
-/* Similar to insert_insn_on_edge, tries to put INSN to edge E. Additionally
- it checks whether this will not clobber the registers that are live on the
- edge (i.e. it requires liveness information to be up-to-date) and if there
- are some, then it tries to save and restore them. Returns true if
- successful. */
-bool
-safe_insert_insn_on_edge (rtx insn, edge e)
-{
- rtx x;
- regset killed;
- rtx save_regs = NULL_RTX;
- unsigned regno;
- int noccmode;
- enum machine_mode mode;
- reg_set_iterator rsi;
-
-#ifdef AVOID_CCMODE_COPIES
- noccmode = true;
-#else
- noccmode = false;
-#endif
-
- killed = ALLOC_REG_SET (®_obstack);
-
- for (x = insn; x; x = NEXT_INSN (x))
- if (INSN_P (x))
- note_stores (PATTERN (x), mark_killed_regs, killed);
- bitmap_and_into (killed, e->dest->global_live_at_start);
-
- EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno, rsi)
- {
- mode = regno < FIRST_PSEUDO_REGISTER
- ? reg_raw_mode[regno]
- : GET_MODE (regno_reg_rtx[regno]);
- if (mode == VOIDmode)
- return false;
-
- if (noccmode && mode == CCmode)
- return false;
-
- save_regs = alloc_EXPR_LIST (0,
- alloc_EXPR_LIST (0,
- gen_reg_rtx (mode),
- gen_raw_REG (mode, regno)),
- save_regs);
- }
-
- if (save_regs)
- {
- rtx from, to;
-
- start_sequence ();
- for (x = save_regs; x; x = XEXP (x, 1))
- {
- from = XEXP (XEXP (x, 0), 1);
- to = XEXP (XEXP (x, 0), 0);
- emit_move_insn (to, from);
- }
- emit_insn (insn);
- for (x = save_regs; x; x = XEXP (x, 1))
- {
- from = XEXP (XEXP (x, 0), 0);
- to = XEXP (XEXP (x, 0), 1);
- emit_move_insn (to, from);
- }
- insn = get_insns ();
- end_sequence ();
- free_EXPR_LIST_list (&save_regs);
- }
- insert_insn_on_edge (insn, e);
-
- FREE_REG_SET (killed);
- return true;
-}
-
/* Update the CFG for the instructions queued on edge E. */
static void
-commit_one_edge_insertion (edge e, int watch_calls)
+commit_one_edge_insertion (edge e)
{
rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
basic_block bb = NULL;
insns = e->insns.r;
e->insns.r = NULL_RTX;
- /* Special case -- avoid inserting code between call and storing
- its return value. */
- if (watch_calls && (e->flags & EDGE_FALLTHRU)
- && EDGE_COUNT (e->dest->preds) == 1
- && e->src != ENTRY_BLOCK_PTR
- && CALL_P (BB_END (e->src)))
- {
- rtx next = next_nonnote_insn (BB_END (e->src));
-
- after = BB_HEAD (e->dest);
- /* The first insn after the call may be a stack pop, skip it. */
- while (next
- && keep_with_call_p (next))
- {
- after = next;
- next = next_nonnote_insn (next);
- }
- bb = e->dest;
- }
if (!before && !after)
{
/* Figure out where to put these things. If the destination has
- one predecessor, insert there. Except for the exit block. */
- if (EDGE_COUNT (e->dest->preds) == 1 && e->dest != EXIT_BLOCK_PTR)
+ one predecessor, insert there. Except for the exit block. */
+ if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
{
bb = e->dest;
tmp = NEXT_INSN (tmp);
if (NOTE_INSN_BASIC_BLOCK_P (tmp))
tmp = NEXT_INSN (tmp);
- if (tmp
- && NOTE_P (tmp)
- && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
- tmp = NEXT_INSN (tmp);
if (tmp == BB_HEAD (bb))
before = tmp;
else if (tmp)
}
/* If the source has one successor and the edge is not abnormal,
- insert there. Except for the entry block. */
+ insert there. Except for the entry block. */
else if ((e->flags & EDGE_ABNORMAL) == 0
- && EDGE_COUNT (e->src->succs) == 1
+ && 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)))
- for (before = BB_END (bb);
- NOTE_P (PREV_INSN (before))
- && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
- NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
- ;
+ before = BB_END (bb);
else
{
/* We'd better be fallthru, or we've lost track of
&& BB_PARTITION (e->src) == BB_COLD_PARTITION
&& !(e->flags & EDGE_CROSSING))
{
- rtx bb_note, new_note, cur_insn;
+ 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_P (cur_insn)
- && NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_BASIC_BLOCK)
+ if (NOTE_INSN_BASIC_BLOCK_P (cur_insn))
{
bb_note = cur_insn;
break;
}
- new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
- bb_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
+ && (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)));
- if (after == bb_note)
- after = new_note;
}
}
}
if (before)
{
- emit_insn_before_noloc (insns, before);
+ emit_insn_before_noloc (insns, before, bb);
last = prev_nonnote_insn (before);
}
else
- last = emit_insn_after_noloc (insns, after);
+ last = emit_insn_after_noloc (insns, after, bb);
if (returnjump_p (last))
{
/* ??? Remove all outgoing edges from BB and add one for EXIT.
- This is not currently a problem because this only happens
- for the (single) epilogue, which already has a fallthru edge
- to EXIT. */
+ This is not currently a problem because this only happens
+ for the (single) epilogue, which already has a fallthru edge
+ to EXIT. */
- e = EDGE_SUCC (bb, 0);
+ e = single_succ_edge (bb);
gcc_assert (e->dest == EXIT_BLOCK_PTR
- && EDGE_COUNT (bb->succs) == 1 && (e->flags & EDGE_FALLTHRU));
+ && single_succ_p (bb) && (e->flags & EDGE_FALLTHRU));
e->flags &= ~EDGE_FALLTHRU;
emit_barrier_after (last);
else
gcc_assert (!JUMP_P (last));
- /* Mark the basic block for find_sub_basic_blocks. */
- bb->aux = &bb->aux;
+ /* 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. */
if (e->insns.r)
{
changed = true;
- commit_one_edge_insertion (e, false);
+ commit_one_edge_insertion (e);
}
}
if (!changed)
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
-/* Update the CFG for all queued instructions, taking special care of inserting
- code on edges between call and storing its return value. */
-
-void
-commit_edge_insertions_watch_calls (void)
-{
- basic_block bb;
- sbitmap blocks;
- bool changed = false;
-
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
-
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
- {
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->insns.r)
- {
- changed = true;
- commit_one_edge_insertion (e, true);
- }
- }
-
- if (!changed)
+ /* 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);
FOR_EACH_BB (bb)
if (bb->aux)
{
- SET_BIT (blocks, bb->index);
+ SET_BIT (blocks, bb->index);
/* Check for forgotten bb->aux values before commit_edge_insertions
call. */
gcc_assert (bb->aux == &bb->aux);
sbitmap_free (blocks);
}
\f
+
/* Print out RTL-specific basic block information (live information
at start and end). */
rtx last;
char *s_indent;
- s_indent = alloca ((size_t) indent + 1);
+ s_indent = (char *) alloca ((size_t) indent + 1);
memset (s_indent, ' ', (size_t) indent);
s_indent[indent] = '\0';
-
- fprintf (outf, ";;%s Registers live at start: ", s_indent);
- dump_regset (bb->global_live_at_start, outf);
- putc ('\n', outf);
+
+ 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);
- fprintf (outf, ";;%s Registers live at end: ", s_indent);
- dump_regset (bb->global_live_at_end, outf);
- putc ('\n', outf);
+ if (df)
+ {
+ df_dump_bottom (bb, outf);
+ putc ('\n', outf);
+ }
+
}
\f
/* Like print_rtl, but also print out live information for the start of each
print_rtl_with_bb (FILE *outf, rtx rtx_first)
{
rtx tmp_rtx;
-
if (rtx_first == 0)
fprintf (outf, "(nil)\n");
else
{
enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
int max_uid = get_max_uid ();
- basic_block *start = xcalloc (max_uid, sizeof (basic_block));
- basic_block *end = xcalloc (max_uid, sizeof (basic_block));
- enum bb_state *in_bb_p = xcalloc (max_uid, sizeof (enum bb_state));
+ basic_block *start = XCNEWVEC (basic_block, max_uid);
+ basic_block *end = XCNEWVEC (basic_block, max_uid);
+ enum bb_state *in_bb_p = XCNEWVEC (enum bb_state, max_uid);
basic_block bb;
+ if (df)
+ df_dump_start (outf);
+
FOR_EACH_BB_REVERSE (bb)
{
rtx x;
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)
{
- fprintf (outf, ";; Start of basic block %d, registers live:",
- bb->index);
- dump_regset (bb->global_live_at_start, outf);
- putc ('\n', outf);
+ 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);
+ }
}
if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
{
- fprintf (outf, ";; End of basic block %d, registers live:\n",
- bb->index);
- dump_regset (bb->global_live_at_end, outf);
+ 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);
+ }
}
-
if (did_output)
putc ('\n', outf);
}
return;
XEXP (note, 0) = GEN_INT (BRANCH_EDGE (bb)->probability);
}
+
+/* Get the last insn associated with block BB (that includes barriers and
+ tablejumps after BB). */
+rtx
+get_last_bb_insn (basic_block bb)
+{
+ rtx tmp;
+ rtx end = BB_END (bb);
+
+ /* Include any jump table following the basic block. */
+ if (tablejump_p (end, NULL, &tmp))
+ end = tmp;
+
+ /* Include any barriers that may follow the basic block. */
+ tmp = next_nonnote_insn (end);
+ while (tmp && BARRIER_P (tmp))
+ {
+ end = tmp;
+ tmp = next_nonnote_insn (end);
+ }
+
+ return end;
+}
\f
/* Verify the CFG and RTL consistency common for both underlying RTL and
cfglayout RTL.
Currently it does following checks:
- - test head/end pointers
- overlapping of basic blocks
+ - insns with wrong BLOCK_FOR_INSN pointers
- headers of basic blocks (the NOTE_INSN_BASIC_BLOCK note)
- tails of basic blocks (ensure that boundary is necessary)
- scans body of the basic block for JUMP_INSN, CODE_LABEL
and NOTE_INSN_BASIC_BLOCK
- verify that no fall_thru edge crosses hot/cold partition boundaries
+ - verify that there are no pending RTL branch predictions
In future it can be extended check a lot of other stuff as well
(reachability of basic blocks, life information, etc. etc.). */
static int
rtl_verify_flow_info_1 (void)
{
- const int max_uid = get_max_uid ();
- rtx last_head = get_last_insn ();
- basic_block *bb_info;
rtx x;
int err = 0;
- basic_block bb, last_bb_seen;
-
- bb_info = xcalloc (max_uid, sizeof (basic_block));
-
- /* Check bb chain & numbers. */
- last_bb_seen = ENTRY_BLOCK_PTR;
+ basic_block bb;
+ /* Check the general integrity of the basic blocks. */
FOR_EACH_BB_REVERSE (bb)
{
- rtx head = BB_HEAD (bb);
- rtx end = BB_END (bb);
-
- /* Verify the end of the basic block is in the INSN chain. */
- for (x = last_head; x != NULL_RTX; x = PREV_INSN (x))
- if (x == end)
- break;
+ rtx insn;
- if (!x)
+ if (!(bb->flags & BB_RTL))
{
- error ("end insn %d for block %d not found in the insn stream",
- INSN_UID (end), bb->index);
+ error ("BB_RTL flag not set for block %d", bb->index);
err = 1;
}
- /* Work backwards from the end to the head of the basic block
- to verify the head is in the RTL chain. */
- for (; x != NULL_RTX; x = PREV_INSN (x))
- {
- /* While walking over the insn chain, verify insns appear
- in only one basic block and initialize the BB_INFO array
- used by other passes. */
- if (bb_info[INSN_UID (x)] != NULL)
- {
- error ("insn %d is in multiple basic blocks (%d and %d)",
- INSN_UID (x), bb->index, bb_info[INSN_UID (x)]->index);
- err = 1;
- }
-
- bb_info[INSN_UID (x)] = bb;
-
- if (x == head)
- break;
- }
- if (!x)
- {
- error ("head insn %d for block %d not found in the insn stream",
- INSN_UID (head), bb->index);
- err = 1;
- }
+ FOR_BB_INSNS (bb, insn)
+ if (BLOCK_FOR_INSN (insn) != bb)
+ {
+ error ("insn %d basic block pointer is %d, should be %d",
+ INSN_UID (insn),
+ BLOCK_FOR_INSN (insn) ? BLOCK_FOR_INSN (insn)->index : 0,
+ bb->index);
+ err = 1;
+ }
- last_head = x;
+ for (insn = bb->il.rtl->header; insn; insn = NEXT_INSN (insn))
+ if (!BARRIER_P (insn)
+ && BLOCK_FOR_INSN (insn) != NULL)
+ {
+ error ("insn %d in header of bb %d has non-NULL basic block",
+ INSN_UID (insn), bb->index);
+ err = 1;
+ }
+ for (insn = bb->il.rtl->footer; insn; insn = NEXT_INSN (insn))
+ if (!BARRIER_P (insn)
+ && BLOCK_FOR_INSN (insn) != NULL)
+ {
+ error ("insn %d in footer of bb %d has non-NULL basic block",
+ INSN_UID (insn), bb->index);
+ err = 1;
+ }
}
/* Now check the basic blocks (boundaries etc.) */
|| (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
&& e->src != ENTRY_BLOCK_PTR
&& e->dest != EXIT_BLOCK_PTR))
- {
- error ("Fallthru edge crosses section boundary (bb %i)",
+ {
+ error ("fallthru edge crosses section boundary (bb %i)",
e->src->index);
err = 1;
}
if (n_eh && GET_CODE (PATTERN (BB_END (bb))) != RESX
&& !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);
+ error ("missing REG_EH_REGION note in the end of bb %i", bb->index);
err = 1;
}
if (n_branch
|| (n_branch > 1 && (any_uncondjump_p (BB_END (bb))
|| any_condjump_p (BB_END (bb))))))
{
- error ("Too many outgoing branch edges from bb %i", bb->index);
+ error ("too many outgoing branch edges from bb %i", bb->index);
err = 1;
}
if (n_fallthru && any_uncondjump_p (BB_END (bb)))
{
- error ("Fallthru edge after unconditional jump %i", bb->index);
+ error ("fallthru edge after unconditional jump %i", bb->index);
err = 1;
}
if (n_branch != 1 && any_uncondjump_p (BB_END (bb)))
{
- error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
+ error ("wrong amount of branch edges after unconditional jump %i", bb->index);
err = 1;
}
if (n_branch != 1 && any_condjump_p (BB_END (bb))
&& JUMP_LABEL (BB_END (bb)) != BB_HEAD (fallthru->dest))
{
- error ("Wrong amount of branch edges after conditional jump %i", bb->index);
+ error ("wrong amount of branch edges after conditional jump %i",
+ bb->index);
err = 1;
}
if (n_call && !CALL_P (BB_END (bb)))
{
- error ("Call edges for non-call insn in bb %i", bb->index);
+ error ("call edges for non-call insn in bb %i", bb->index);
err = 1;
}
if (n_abnormal
|| any_condjump_p (BB_END (bb))
|| any_uncondjump_p (BB_END (bb))))
{
- error ("Abnormal edges for no purpose in bb %i", bb->index);
+ error ("abnormal edges for no purpose in bb %i", bb->index);
err = 1;
}
}
/* OK pointers are correct. Now check the header of basic
- block. It ought to contain optional CODE_LABEL followed
+ block. It ought to contain optional CODE_LABEL followed
by NOTE_BASIC_BLOCK. */
x = BB_HEAD (bb);
if (LABEL_P (x))
}
/* Clean up. */
- free (bb_info);
return err;
}
Currently it does following checks:
- all checks of rtl_verify_flow_info_1
+ - test head/end pointers
- check that all insns are in the basic blocks
(except the switch handling code, barriers and notes)
- check that all returns are followed by barriers
- check that all fallthru edge points to the adjacent blocks. */
+
static int
rtl_verify_flow_info (void)
{
basic_block bb;
int err = rtl_verify_flow_info_1 ();
rtx x;
+ rtx last_head = get_last_insn ();
+ basic_block *bb_info;
int num_bb_notes;
const rtx rtx_first = get_insns ();
basic_block last_bb_seen = ENTRY_BLOCK_PTR, curr_bb = NULL;
+ const int max_uid = get_max_uid ();
+
+ bb_info = XCNEWVEC (basic_block, max_uid);
FOR_EACH_BB_REVERSE (bb)
{
edge e;
edge_iterator ei;
+ rtx head = BB_HEAD (bb);
+ rtx end = BB_END (bb);
+
+ for (x = last_head; x != NULL_RTX; x = PREV_INSN (x))
+ {
+ /* Verify the end of the basic block is in the INSN chain. */
+ if (x == end)
+ break;
+
+ /* And that the code outside of basic blocks has NULL bb field. */
+ if (!BARRIER_P (x)
+ && BLOCK_FOR_INSN (x) != NULL)
+ {
+ error ("insn %d outside of basic blocks has non-NULL bb field",
+ INSN_UID (x));
+ err = 1;
+ }
+ }
+
+ if (!x)
+ {
+ error ("end insn %d for block %d not found in the insn stream",
+ INSN_UID (end), bb->index);
+ err = 1;
+ }
+
+ /* Work backwards from the end to the head of the basic block
+ to verify the head is in the RTL chain. */
+ for (; x != NULL_RTX; x = PREV_INSN (x))
+ {
+ /* While walking over the insn chain, verify insns appear
+ in only one basic block. */
+ if (bb_info[INSN_UID (x)] != NULL)
+ {
+ error ("insn %d is in multiple basic blocks (%d and %d)",
+ INSN_UID (x), bb->index, bb_info[INSN_UID (x)]->index);
+ err = 1;
+ }
+
+ bb_info[INSN_UID (x)] = bb;
+
+ if (x == head)
+ break;
+ }
+ if (!x)
+ {
+ error ("head insn %d for block %d not found in the insn stream",
+ INSN_UID (head), bb->index);
+ err = 1;
+ }
+
+ last_head = PREV_INSN (x);
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
for (insn = BB_END (bb); !insn || !BARRIER_P (insn);
insn = NEXT_INSN (insn))
if (!insn
- || (NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK))
+ || NOTE_INSN_BASIC_BLOCK_P (insn))
{
error ("missing barrier after block %i", bb->index);
err = 1;
}
else if (e->src != ENTRY_BLOCK_PTR
&& e->dest != EXIT_BLOCK_PTR)
- {
+ {
rtx insn;
if (e->src->next_bb != e->dest)
fatal_insn ("wrong insn in the fallthru edge", insn);
err = 1;
}
- }
+ }
}
+ for (x = last_head; x != NULL_RTX; x = PREV_INSN (x))
+ {
+ /* Check that the code before the first basic block has NULL
+ bb field. */
+ if (!BARRIER_P (x)
+ && BLOCK_FOR_INSN (x) != NULL)
+ {
+ error ("insn %d outside of basic blocks has non-NULL bb field",
+ INSN_UID (x));
+ err = 1;
+ }
+ }
+ free (bb_info);
+
num_bb_notes = 0;
last_bb_seen = ENTRY_BLOCK_PTR;
if (JUMP_P (x)
&& returnjump_p (x) && ! condjump_p (x)
- && ! (NEXT_INSN (x) && BARRIER_P (NEXT_INSN (x))))
+ && ! (next_nonnote_insn (x) && BARRIER_P (next_nonnote_insn (x))))
fatal_insn ("return not followed by barrier", x);
if (curr_bb && x == BB_END (curr_bb))
curr_bb = NULL;
}
- if (num_bb_notes != n_basic_blocks)
+ if (num_bb_notes != n_basic_blocks - NUM_FIXED_BLOCKS)
internal_error
("number of bb notes in insn chain (%d) != n_basic_blocks (%d)",
num_bb_notes, n_basic_blocks);
/* Cleanup abnormal edges caused by exceptions or non-local gotos. */
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
{
+ /* 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 (can_throw_internal (BB_END (bb)))
+ 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;
}
remove_edge (e);
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
purged = true;
}
}
/* We do not need this edge. */
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
purged = true;
remove_edge (e);
}
return purged;
/* Redistribute probabilities. */
- if (EDGE_COUNT (bb->succs) == 1)
+ if (single_succ_p (bb))
{
- EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
- EDGE_SUCC (bb, 0)->count = bb->count;
+ single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
+ single_succ_edge (bb)->count = bb->count;
}
else
{
from non-local gotos and the like. If there were, we shouldn't
have created the sibcall in the first place. Second, there
should of course never have been a fallthru edge. */
- gcc_assert (EDGE_COUNT (bb->succs) == 1);
- gcc_assert (EDGE_SUCC (bb, 0)->flags == (EDGE_SIBCALL | EDGE_ABNORMAL));
+ gcc_assert (single_succ_p (bb));
+ gcc_assert (single_succ_edge (bb)->flags
+ == (EDGE_SIBCALL | EDGE_ABNORMAL));
return 0;
}
if (!found)
return purged;
+ /* Remove all but the fake and fallthru edges. The fake edge may be
+ the only successor for this block in the case of noreturn
+ calls. */
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
{
- if (!(e->flags & EDGE_FALLTHRU))
+ if (!(e->flags & (EDGE_FALLTHRU | EDGE_FAKE)))
{
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
remove_edge (e);
purged = true;
}
ei_next (&ei);
}
- gcc_assert (EDGE_COUNT (bb->succs) == 1);
+ gcc_assert (single_succ_p (bb));
- EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
- EDGE_SUCC (bb, 0)->count = bb->count;
+ single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
+ single_succ_edge (bb)->count = bb->count;
if (dump_file)
fprintf (dump_file, "Purged non-fallthru edges from bb %i\n",
true if some edge has been eliminated. */
bool
-purge_all_dead_edges (int update_life_p)
+purge_all_dead_edges (void)
{
int purged = false;
- sbitmap blocks = 0;
basic_block bb;
- if (update_life_p)
- {
- blocks = sbitmap_alloc (last_basic_block);
- sbitmap_zero (blocks);
- }
-
FOR_EACH_BB (bb)
{
bool purged_here = purge_dead_edges (bb);
purged |= purged_here;
- if (purged_here && update_life_p)
- SET_BIT (blocks, bb->index);
}
- if (update_life_p && purged)
- update_life_info (blocks, UPDATE_LIFE_GLOBAL,
- PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
- | PROP_KILL_DEAD_CODE);
-
- if (update_life_p)
- sbitmap_free (blocks);
return purged;
}
static basic_block
cfg_layout_split_block (basic_block bb, void *insnp)
{
- rtx insn = insnp;
+ rtx insn = (rtx) insnp;
basic_block new_bb = rtl_split_block (bb, insn);
- new_bb->rbi->footer = bb->rbi->footer;
- bb->rbi->footer = NULL;
+ new_bb->il.rtl->footer = bb->il.rtl->footer;
+ bb->il.rtl->footer = NULL;
return new_bb;
}
-
/* Redirect Edge to DEST. */
static edge
cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
if (e->src != ENTRY_BLOCK_PTR
&& (ret = try_redirect_by_replacing_jump (e, dest, true)))
{
- src->flags |= BB_DIRTY;
+ df_set_bb_dirty (src);
return ret;
}
fprintf (dump_file, "Redirecting entry edge from bb %i to %i\n",
e->src->index, dest->index);
- e->src->flags |= BB_DIRTY;
+ df_set_bb_dirty (e->src);
redirect_edge_succ (e, dest);
return e;
}
BB_END (src)))
{
edge redirected;
-
+
if (dump_file)
fprintf (dump_file, "Fallthru edge unified with branch "
"%i->%i redirected to %i\n",
redirected = redirect_branch_edge (e, dest);
gcc_assert (redirected);
e->flags |= EDGE_FALLTHRU;
- e->src->flags |= BB_DIRTY;
+ df_set_bb_dirty (e->src);
return e;
}
/* In case we are redirecting fallthru edge to the branch edge
- of conditional jump, remove it. */
+ of conditional jump, remove it. */
if (EDGE_COUNT (src->succs) == 2)
{
/* Find the edge that is different from E. */
/* We don't want simplejumps in the insn stream during cfglayout. */
gcc_assert (!simplejump_p (BB_END (src)));
- src->flags |= BB_DIRTY;
+ df_set_bb_dirty (src);
return ret;
}
{
rtx insn, next, prev = PREV_INSN (BB_HEAD (bb)), *to, remaints;
- if (bb->rbi->header)
+ if (bb->il.rtl->header)
{
next = BB_HEAD (bb);
if (prev)
- NEXT_INSN (prev) = bb->rbi->header;
+ NEXT_INSN (prev) = bb->il.rtl->header;
else
- set_first_insn (bb->rbi->header);
- PREV_INSN (bb->rbi->header) = prev;
- insn = bb->rbi->header;
+ set_first_insn (bb->il.rtl->header);
+ PREV_INSN (bb->il.rtl->header) = prev;
+ insn = bb->il.rtl->header;
while (NEXT_INSN (insn))
insn = NEXT_INSN (insn);
NEXT_INSN (insn) = next;
PREV_INSN (next) = insn;
}
next = NEXT_INSN (BB_END (bb));
- if (bb->rbi->footer)
+ if (bb->il.rtl->footer)
{
- insn = bb->rbi->footer;
+ insn = bb->il.rtl->footer;
while (insn)
{
if (BARRIER_P (insn))
if (PREV_INSN (insn))
NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
else
- bb->rbi->footer = NEXT_INSN (insn);
+ bb->il.rtl->footer = NEXT_INSN (insn);
if (NEXT_INSN (insn))
PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
}
break;
insn = NEXT_INSN (insn);
}
- if (bb->rbi->footer)
+ if (bb->il.rtl->footer)
{
insn = BB_END (bb);
- 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);
NEXT_INSN (insn) = next;
}
}
if (bb->next_bb != EXIT_BLOCK_PTR)
- to = &bb->next_bb->rbi->header;
+ to = &bb->next_bb->il.rtl->header;
else
to = &cfg_layout_function_footer;
+
rtl_delete_block (bb);
if (prev)
and cold sections.
Basic block partitioning may result in some jumps that appear to
- be optimizable (or blocks that appear to be mergeable), but which really
- must be left untouched (they are required to make it safely across
- partition boundaries). See the comments at the top of
+ be optimizable (or blocks that appear to be mergeable), but which really
+ must be left untouched (they are required to make it safely across
+ partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
- || find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (a) != BB_PARTITION (b)))
+ if (BB_PARTITION (a) != BB_PARTITION (b))
return false;
/* There must be exactly one edge in between the blocks. */
- return (EDGE_COUNT (a->succs) == 1
- && EDGE_SUCC (a, 0)->dest == b
- && EDGE_COUNT (b->preds) == 1
+ return (single_succ_p (a)
+ && single_succ (a) == b
+ && single_pred_p (b) == 1
&& a != b
/* Must be simple edge. */
- && !(EDGE_SUCC (a, 0)->flags & EDGE_COMPLEX)
+ && !(single_succ_edge (a)->flags & EDGE_COMPLEX)
&& a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
- /* If the jump insn has side effects,
- we can't kill the edge. */
+ /* If the jump insn has side effects, we can't kill the edge.
+ When not optimizing, try_redirect_by_replacing_jump will
+ not allow us to redirect an edge by replacing a table jump. */
&& (!JUMP_P (BB_END (a))
- || (reload_completed
+ || ((!optimize || reload_completed)
? simplejump_p (BB_END (a)) : onlyjump_p (BB_END (a)))));
}
-/* Merge block A and B, abort when it is not possible. */
+/* Merge block A and B. The blocks must be mergeable. */
+
static void
cfg_layout_merge_blocks (basic_block a, basic_block b)
{
gcc_assert (cfg_layout_can_merge_blocks_p (a, b));
#endif
+ if (dump_file)
+ 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)))
- delete_insn (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));
+ }
/* We should have fallthru edge in a, or we can do dummy redirection to get
it cleaned up. */
gcc_assert (!JUMP_P (BB_END (a)));
/* Possible line number notes should appear in between. */
- if (b->rbi->header)
+ if (b->il.rtl->header)
{
rtx first = BB_END (a), last;
- last = emit_insn_after_noloc (b->rbi->header, BB_END (a));
- delete_insn_chain (NEXT_INSN (first), last);
- b->rbi->header = NULL;
+ last = emit_insn_after_noloc (b->il.rtl->header, BB_END (a), a);
+ delete_insn_chain (NEXT_INSN (first), last, false);
+ b->il.rtl->header = NULL;
}
/* In the case basic blocks are not adjacent, move them around. */
{
rtx first = unlink_insn_chain (BB_HEAD (b), BB_END (b));
- emit_insn_after_noloc (first, BB_END (a));
+ emit_insn_after_noloc (first, BB_END (a), a);
/* Skip possible DELETED_LABEL insn. */
if (!NOTE_INSN_BASIC_BLOCK_P (first))
first = NEXT_INSN (first);
for (insn = BB_HEAD (b);
insn != NEXT_INSN (BB_END (b));
insn = NEXT_INSN (insn))
- set_block_for_insn (insn, a);
+ {
+ set_block_for_insn (insn, a);
+ df_insn_change_bb (insn);
+ }
+
insn = BB_HEAD (b);
/* Skip possible DELETED_LABEL insn. */
if (!NOTE_INSN_BASIC_BLOCK_P (insn))
delete_insn (insn);
}
+ df_bb_delete (b->index);
+
/* Possible tablejumps and barriers should appear after the block. */
- if (b->rbi->footer)
+ if (b->il.rtl->footer)
{
- if (!a->rbi->footer)
- a->rbi->footer = b->rbi->footer;
+ if (!a->il.rtl->footer)
+ a->il.rtl->footer = b->il.rtl->footer;
else
{
- rtx last = a->rbi->footer;
+ rtx last = a->il.rtl->footer;
while (NEXT_INSN (last))
last = NEXT_INSN (last);
- NEXT_INSN (last) = b->rbi->footer;
- PREV_INSN (b->rbi->footer) = last;
+ NEXT_INSN (last) = b->il.rtl->footer;
+ PREV_INSN (b->il.rtl->footer) = last;
}
- b->rbi->footer = NULL;
+ b->il.rtl->footer = NULL;
}
if (dump_file)
static basic_block
cfg_layout_split_edge (edge e)
{
- edge new_e;
basic_block new_bb =
create_basic_block (e->src != ENTRY_BLOCK_PTR
? NEXT_INSN (BB_END (e->src)) : get_insns (),
NULL_RTX, e->src);
- /* ??? This info is likely going to be out of date very soon, but we must
- create it to avoid getting an ICE later. */
- if (e->dest->global_live_at_start)
- {
- new_bb->global_live_at_start = ALLOC_REG_SET (®_obstack);
- new_bb->global_live_at_end = ALLOC_REG_SET (®_obstack);
- COPY_REG_SET (new_bb->global_live_at_start,
- e->dest->global_live_at_start);
- COPY_REG_SET (new_bb->global_live_at_end,
- e->dest->global_live_at_start);
- }
-
- new_e = make_edge (new_bb, e->dest, EDGE_FALLTHRU);
+ make_edge (new_bb, e->dest, EDGE_FALLTHRU);
redirect_edge_and_branch_force (e, new_bb);
return new_bb;
if ((CALL_P (insn)
&& !SIBLING_CALL_P (insn)
&& !find_reg_note (insn, REG_NORETURN, NULL)
- && !find_reg_note (insn, REG_ALWAYS_RETURN, NULL)
&& !CONST_OR_PURE_CALL_P (insn)))
return true;
int last_bb = last_basic_block;
bool check_last_block = false;
- if (n_basic_blocks == 0)
+ if (n_basic_blocks == NUM_FIXED_BLOCKS)
return 0;
if (! blocks)
calls since there is no way that we can determine if they will
return or not... */
- for (i = 0; i < last_bb; i++)
+ for (i = NUM_FIXED_BLOCKS; i < last_bb; i++)
{
basic_block bb = BASIC_BLOCK (i);
rtx insn;
rtx split_at_insn = insn;
/* Don't split the block between a call and an insn that should
- remain in the same block as the call. */
+ remain in the same block as the call. */
if (CALL_P (insn))
while (split_at_insn != BB_END (bb)
&& keep_with_call_p (NEXT_INSN (split_at_insn)))
split_at_insn = NEXT_INSN (split_at_insn);
/* The handling above of the final block before the epilogue
- should be enough to verify that there is no edge to the exit
+ should be enough to verify that there is no edge to the exit
block in CFG already. Calling make_edge in such case would
cause us to mark that edge as fake and remove it later. */
return blocks_split;
}
+/* Add COMP_RTX as a condition at end of COND_BB. FIRST_HEAD is
+ the conditional branch target, SECOND_HEAD should be the fall-thru
+ there is no need to handle this here the loop versioning code handles
+ this. the reason for SECON_HEAD is that it is needed for condition
+ in trees, and this should be of the same type since it is a hook. */
+static void
+rtl_lv_add_condition_to_bb (basic_block first_head ,
+ basic_block second_head ATTRIBUTE_UNUSED,
+ basic_block cond_bb, void *comp_rtx)
+{
+ rtx label, seq, jump;
+ rtx op0 = XEXP ((rtx)comp_rtx, 0);
+ rtx op1 = XEXP ((rtx)comp_rtx, 1);
+ enum rtx_code comp = GET_CODE ((rtx)comp_rtx);
+ enum machine_mode mode;
+
+
+ label = block_label (first_head);
+ mode = GET_MODE (op0);
+ if (mode == VOIDmode)
+ mode = GET_MODE (op1);
+
+ start_sequence ();
+ 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);
+ jump = get_last_insn ();
+ JUMP_LABEL (jump) = label;
+ LABEL_NUSES (label)++;
+ seq = get_insns ();
+ end_sequence ();
+
+ /* Add the new cond , in the new head. */
+ emit_insn_after(seq, BB_END(cond_bb));
+}
+
+
+/* Given a block B with unconditional branch at its end, get the
+ store the return the branch edge and the fall-thru edge in
+ BRANCH_EDGE and FALLTHRU_EDGE respectively. */
+static void
+rtl_extract_cond_bb_edges (basic_block b, edge *branch_edge,
+ edge *fallthru_edge)
+{
+ edge e = EDGE_SUCC (b, 0);
+
+ if (e->flags & EDGE_FALLTHRU)
+ {
+ *fallthru_edge = e;
+ *branch_edge = EDGE_SUCC (b, 1);
+ }
+ else
+ {
+ *branch_edge = e;
+ *fallthru_edge = EDGE_SUCC (b, 1);
+ }
+}
+
+void
+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;
+}
+
+/* Returns true if it is possible to remove edge E by redirecting
+ it to the destination of the other edge from E->src. */
+
+static bool
+rtl_can_remove_branch_p (edge e)
+{
+ basic_block src = e->src;
+ basic_block target = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e)->dest;
+ rtx insn = BB_END (src), set;
+
+ /* The conditions are taken from try_redirect_by_replacing_jump. */
+ if (target == EXIT_BLOCK_PTR)
+ return false;
+
+ if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
+ return false;
+
+ if (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
+ || BB_PARTITION (src) != BB_PARTITION (target))
+ return false;
+
+ if (!onlyjump_p (insn)
+ || tablejump_p (insn, NULL, NULL))
+ return false;
+
+ set = single_set (insn);
+ if (!set || side_effects_p (set))
+ return false;
+
+ return true;
+}
+
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
"rtl",
rtl_create_basic_block,
rtl_redirect_edge_and_branch,
rtl_redirect_edge_and_branch_force,
+ rtl_can_remove_branch_p,
rtl_delete_block,
rtl_split_block,
rtl_move_block_after,
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,
NULL, /* execute_on_growing_pred */
- NULL /* execute_on_shrinking_pred */
+ NULL, /* execute_on_shrinking_pred */
+ NULL, /* duplicate loop for trees */
+ NULL, /* lv_add_condition_to_bb */
+ NULL, /* lv_adjust_loop_header_phi*/
+ NULL, /* extract_cond_bb_edges */
+ NULL /* flush_pending_stmts */
};
/* Implementation of CFG manipulation for cfg layout RTL, where
/* 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. */
+ code. They are in cfglayout.c. */
extern bool cfg_layout_can_duplicate_bb_p (basic_block);
extern basic_block cfg_layout_duplicate_bb (basic_block);
cfg_layout_create_basic_block,
cfg_layout_redirect_edge_and_branch,
cfg_layout_redirect_edge_and_branch_force,
+ rtl_can_remove_branch_p,
cfg_layout_delete_block,
cfg_layout_split_block,
rtl_move_block_after,
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,
NULL, /* execute_on_growing_pred */
- NULL /* execute_on_shrinking_pred */
+ NULL, /* execute_on_shrinking_pred */
+ duplicate_loop_to_header_edge, /* duplicate loop for trees */
+ rtl_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
+ NULL, /* lv_adjust_loop_header_phi*/
+ rtl_extract_cond_bb_edges, /* extract_cond_bb_edges */
+ NULL /* flush_pending_stmts */
};
-