static int can_delete_note_p (rtx);
static int can_delete_label_p (rtx);
-static void commit_one_edge_insertion (edge, int);
+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 int
can_delete_note_p (rtx note)
{
- return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
- || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
+ return (NOTE_KIND (note) == NOTE_INSN_DELETED
+ || NOTE_KIND (note) == NOTE_INSN_BASIC_BLOCK);
}
/* True if a given label can be deleted. */
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;
}
/* Grow the basic block array if needed. */
if ((size_t) last_basic_block >= VEC_length (basic_block, basic_block_info))
{
- size_t old_size = VEC_length (basic_block, basic_block_info);
size_t new_size = last_basic_block + (last_basic_block + 3) / 4;
- basic_block *p;
- VEC_safe_grow (basic_block, gc, basic_block_info, new_size);
- p = VEC_address (basic_block, basic_block_info);
- memset (&p[old_size], 0, sizeof (basic_block) * (new_size - old_size));
+ VEC_safe_grow_cleared (basic_block, gc, basic_block_info, new_size);
}
n_basic_blocks++;
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);
+ if (b->il.rtl->global_live_at_start)
+ {
+ FREE_REG_SET (b->il.rtl->global_live_at_start);
+ FREE_REG_SET (b->il.rtl->global_live_at_end);
+ b->il.rtl->global_live_at_start = NULL;
+ b->il.rtl->global_live_at_end = NULL;
+ }
}
\f
/* Records the basic block struct in BLOCK_FOR_INSN for every insn. */
rtx
entry_of_function (void)
{
- return (n_basic_blocks > NUM_FIXED_BLOCKS ?
+ 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. */
void
/* 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;
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 (BB_PARTITION (a) != BB_PARTITION (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 (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (src) != BB_PARTITION (target))
return NULL;
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
{
rtx insn = src->il.rtl->footer;
- delete_insn_chain (kill_from, BB_END (src));
+ delete_insn_chain (kill_from, BB_END (src));
/* Remove barriers but keep jumptables. */
while (insn)
}
}
else
- delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)));
+ delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)));
}
/* If this already is simplejump, redirect it. */
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);
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, gc, bb->succs, e);
make_single_succ_edge (ENTRY_BLOCK_PTR, bb, EDGE_FALLTHRU);
}
NULL_RTX,
REG_NOTES
(BB_END
- (jump_block)));
-
+ (jump_block)));
+
/* Wire edge in. */
new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
new_edge->probability = e->probability;
#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. */
/* 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)
- && single_pred_p (e->dest)
- && 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. */
+ one predecessor, insert there. Except for the exit block. */
if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
{
bb = e->dest;
}
/* 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
&& single_succ_p (e->src)
&& e->src != ENTRY_BLOCK_PTR)
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;
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
+ && (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 (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 = single_succ_edge (bb);
gcc_assert (e->dest == EXIT_BLOCK_PTR
gcc_assert (!JUMP_P (last));
/* Mark the basic block for find_many_sub_basic_blocks. */
- bb->aux = &bb->aux;
+ 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);
for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
{
int did_output;
+ edge_iterator ei;
+ edge e;
if ((bb = start[INSN_UID (tmp_rtx)]) != NULL)
{
bb->index);
dump_regset (bb->il.rtl->global_live_at_start, 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",
+ fprintf (outf, ";; End of basic block %d, registers live:",
bb->index);
dump_regset (bb->il.rtl->global_live_at_end, 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)
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;
- bb_info = XCNEWVEC (basic_block, max_uid);
-
+ /* 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 (!(bb->flags & BB_RTL))
{
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 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;
- }
-
- last_head = x;
+ 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;
+ }
}
/* 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)",
e->src->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);
+
+ /* 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;
+
+ 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;
+ }
- if (bb->predictions)
+ bb_info[INSN_UID (x)] = bb;
+
+ if (x == head)
+ break;
+ }
+ if (!x)
{
- error ("bb prediction set for block %i, but it is not used in RTL land", bb->index);
+ error ("head insn %d for block %d not found in the insn stream",
+ INSN_UID (head), bb->index);
err = 1;
}
+ last_head = x;
+
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
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;
}
- }
+ }
}
+ free (bb_info);
+
num_bb_notes = 0;
last_bb_seen = ENTRY_BLOCK_PTR;
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;
+ e->src->flags |= BB_DIRTY;
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. */
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 (BB_PARTITION (a) != BB_PARTITION (b))
/* Must be simple edge. */
&& !(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)))));
}
/* 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));
}
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. */
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)
+ basic_block second_head ATTRIBUTE_UNUSED,
+ basic_block cond_bb, void *comp_rtx)
{
rtx label, seq, jump;
rtx op0 = XEXP ((rtx)comp_rtx, 0);
}
+/* 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);
+ }
+
+ /* 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);
+ }
+ else
+ new_insn = emit_insn_after_noloc (pat, insn);
+
+ 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,
NULL, /* lv_add_condition_to_bb */
NULL, /* lv_adjust_loop_header_phi*/
NULL, /* extract_cond_bb_edges */
- NULL /* flush_pending_stmts */
+ NULL /* flush_pending_stmts */
};
/* Implementation of CFG manipulation for cfg layout RTL, where
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_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 */
+ NULL /* flush_pending_stmts */
};
-