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"
static int can_delete_note_p (rtx);
static int can_delete_label_p (rtx);
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);
+ || NOTE_LINE_NUMBER (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. */
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;
update_bb_for_insn (bb);
{
basic_block newbb = rtl_create_basic_block (head, end, after);
- initialize_bb_rbi (newbb);
return newbb;
}
\f
BLOCK_FOR_INSN (insn) = NULL;
}
+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 ());
}
/* Update insns block within BB. */
FOR_EACH_EDGE (e, ei, new_bb->succs)
e->src = new_bb;
- if (bb->global_live_at_start)
+ if (bb->il.rtl->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);
+ new_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack);
+ new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack);
+ COPY_REG_SET (new_bb->il.rtl->global_live_at_end, bb->il.rtl->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);
+ COPY_REG_SET (new_bb->il.rtl->global_live_at_start, bb->il.rtl->global_live_at_end);
+ propagate_block (new_bb, new_bb->il.rtl->global_live_at_start, NULL, NULL, 0);
+ COPY_REG_SET (bb->il.rtl->global_live_at_end,
+ new_bb->il.rtl->global_live_at_start);
#ifdef HAVE_conditional_execution
/* In the presence of conditional execution we are not able to update
liveness precisely. */
/* 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)
}
BB_END (a) = a_end;
+ a->il.rtl->global_live_at_end = b->il.rtl->global_live_at_end;
}
/* Return true when block A and B can be merged. */
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,
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
/* 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));
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);
}
}
/* 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
&& 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);
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;
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);
}
}
jump_block->frequency = EDGE_FREQUENCY (e);
jump_block->loop_depth = target->loop_depth;
- if (target->global_live_at_start)
+ if (target->il.rtl->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);
+ jump_block->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack);
+ jump_block->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack);
+ COPY_REG_SET (jump_block->il.rtl->global_live_at_start,
+ target->il.rtl->global_live_at_start);
+ COPY_REG_SET (jump_block->il.rtl->global_live_at_end,
+ target->il.rtl->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);
new_edge->probability = e->probability;
/* 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 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
}
/* 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
}
/* ??? This info is likely going to be out of date very soon. */
- if (edge_in->dest->global_live_at_start)
+ if (edge_in->dest->il.rtl->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);
+ bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack);
+ bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack);
+ COPY_REG_SET (bb->il.rtl->global_live_at_start,
+ edge_in->dest->il.rtl->global_live_at_start);
+ COPY_REG_SET (bb->il.rtl->global_live_at_end,
+ edge_in->dest->il.rtl->global_live_at_start);
}
make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
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))
&& !REGNO_PTR_FRAME_P (regno))
SET_REGNO_REG_SET (killed, regno);
- bitmap_and_into (killed, e->dest->global_live_at_start);
+ bitmap_and_into (killed, e->dest->il.rtl->global_live_at_start);
EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno, rsi)
{
if (mode == VOIDmode)
return false;
- if (noccmode && mode == CCmode)
+ /* Avoid copying in CCmode if we can't. */
+ if (!can_copy_p (mode))
return false;
save_regs = alloc_EXPR_LIST (0,
/* 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
+ && single_pred_p (e->dest)
&& e->src != ENTRY_BLOCK_PTR
&& CALL_P (BB_END (e->src)))
{
{
/* 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)
+ 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. */
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;
&& 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));
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))
+ && (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;
}
}
}
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. */
+ /* Mark the basic block for find_many_sub_basic_blocks. */
bb->aux = &bb->aux;
}
s_indent[indent] = '\0';
fprintf (outf, ";;%s Registers live at start: ", s_indent);
- dump_regset (bb->global_live_at_start, outf);
+ dump_regset (bb->il.rtl->global_live_at_start, outf);
putc ('\n', outf);
for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
print_rtl_single (outf, insn);
fprintf (outf, ";;%s Registers live at end: ", s_indent);
- dump_regset (bb->global_live_at_end, outf);
+ dump_regset (bb->il.rtl->global_live_at_end, outf);
putc ('\n', outf);
}
\f
{
fprintf (outf, ";; Start of basic block %d, registers live:",
bb->index);
- dump_regset (bb->global_live_at_start, outf);
+ dump_regset (bb->il.rtl->global_live_at_start, outf);
putc ('\n', outf);
}
{
fprintf (outf, ";; End of basic block %d, registers live:\n",
bb->index);
- dump_regset (bb->global_live_at_end, outf);
+ dump_regset (bb->il.rtl->global_live_at_end, outf);
putc ('\n', outf);
}
basic_block *bb_info;
rtx x;
int err = 0;
- basic_block bb, last_bb_seen;
+ basic_block bb;
bb_info = xcalloc (max_uid, sizeof (basic_block));
- /* Check bb chain & numbers. */
- last_bb_seen = ENTRY_BLOCK_PTR;
-
FOR_EACH_BB_REVERSE (bb)
{
rtx head = BB_HEAD (bb);
if (x == end)
break;
+ if (!(bb->flags & BB_RTL))
+ {
+ error ("BB_RTL flag not set for block %d", bb->index);
+ err = 1;
+ }
+
if (!x)
{
error ("end insn %d for block %d not found in the insn stream",
&& 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))
+ && 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;
}
edge e;
edge_iterator ei;
+ if (bb->predictions)
+ {
+ error ("bb prediction set for block %i, but it is not used in RTL land", bb->index);
+ err = 1;
+ }
+
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
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;
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;
remove_edge (e);
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;
}
rtx insn = 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;
}
{
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)
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. */
? 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)
{
/* 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));
+ last = emit_insn_after_noloc (b->il.rtl->header, BB_END (a));
delete_insn_chain (NEXT_INSN (first), last);
- b->rbi->header = NULL;
+ b->il.rtl->header = NULL;
}
/* In the case basic blocks are not adjacent, move them around. */
}
/* 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;
}
+ a->il.rtl->global_live_at_end = b->il.rtl->global_live_at_end;
if (dump_file)
fprintf (dump_file, "Merged blocks %d and %d.\n",
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 (),
/* ??? 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)
+ if (e->dest->il.rtl->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_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (®_obstack);
+ new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (®_obstack);
+ COPY_REG_SET (new_bb->il.rtl->global_live_at_start,
+ e->dest->il.rtl->global_live_at_start);
+ COPY_REG_SET (new_bb->il.rtl->global_live_at_end,
+ e->dest->il.rtl->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;
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;
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_alloc_cleared (sizeof (struct rtl_bb_info));
+}
+
+
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
"rtl",
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
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 */
};