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 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,
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);
/* 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)
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;
{
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. */
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
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);
}
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);
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;
/* In case the edge redirection failed, try to force it to be non-fallthru
and redirect newly created simplejump. */
+ e->src->flags |= BB_DIRTY;
return force_nonfallthru_and_redirect (e, target);
}
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
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);
}
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;
- enum machine_mode mode;
- reg_set_iterator rsi;
-
- 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);
-
- /* Mark all hard registers as killed. Register allocator/reload cannot
- cope with the situation when life range of hard register spans operation
- for that the appropriate register is needed, i.e. it would be unsafe to
- extend the life ranges of hard registers. */
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (!fixed_regs[regno]
- && !REGNO_PTR_FRAME_P (regno))
- SET_REGNO_REG_SET (killed, regno);
-
- bitmap_and_into (killed, e->dest->il.rtl->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;
-
- /* Avoid copying in CCmode if we can't. */
- if (!can_copy_p (mode))
- 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
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)
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
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
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_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);
|| (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))
}
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;
}
- }
+ }
}
num_bb_notes = 0;
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))
/* 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;
+}
+
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
"rtl",
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
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 */
};
-