+2017-12-20 Alexandre Oliva <aoliva@redhat.com>
+
+ PR bootstrap/83396
+ * cfgexpand.c (label_rtx_for_bb): Revert SFN changes that
+ allowed debug stmts before labels.
+ (expand_gimple_basic_block): Likewise.
+ * gimple-iterator.c (gimple_find_edge_insert_loc): Likewise.
+ * gimple-iterator.h (gsi_after_labels): Likewise.
+ * tree-cfgcleanup (remove_forwarder_block): Likewise, but
+ rename reused variable, and simplify using gsi_move_before.
+ * tree-ssa-tail-merge.c (find_duplicate): Likewise.
+ * tree-cfg.c (make_edges, cleanup_dead_labels): Likewise.
+ (gimple_can_merge_blocks_p, verify_gimple_in_cfg): Likewise.
+ (gimple_verify_flow_info, gimple_block_label): Likewise.
+ (make_blocks): Move debug markers after adjacent labels.
+ * cfgrtl.c (skip_insns_after_block): Revert SFN changes that
+ allowed debug insns outside blocks.
+ * df-scan.c (df_insn_delete): Likewise.
+ * lra-constraints.c (update_ebb_live_info): Likewise.
+ * var-tracking.c (get_first_insn, vt_emit_notes): Likewise.
+ (vt_initialize, delete_vta_debug_insns): Likewise.
+ (reemit_marker_as_note): Drop BB parm. Adjust callers.
+
2017-12-20 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
{
glabel *lab_stmt;
- if (is_gimple_debug (gsi_stmt (gsi)))
- continue;
-
lab_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
if (!lab_stmt)
break;
}
}
- gsi = gsi_start_nondebug (stmts);
+ gsi = gsi_start (stmts);
if (!gsi_end_p (gsi))
{
stmt = gsi_stmt (gsi);
if (gimple_code (stmt) != GIMPLE_LABEL)
stmt = NULL;
}
- gsi = gsi_start (stmts);
- gimple *label_stmt = stmt;
rtx_code_label **elt = lab_rtx_for_bb->get (bb);
if (stmt || elt)
if (stmt)
{
expand_gimple_stmt (stmt);
- if (gsi_stmt (gsi) == stmt)
- gsi_next (&gsi);
+ gsi_next (&gsi);
}
if (elt)
stmt = gsi_stmt (gsi);
- if (stmt == label_stmt)
- continue;
-
/* If this statement is a non-debug one, and we generate debug
insns, then this one might be the last real use of a TERed
SSA_NAME, but where there are still some debug uses further
last_insn = insn;
continue;
- case DEBUG_INSN:
- continue;
-
case NOTE:
switch (NOTE_KIND (insn))
{
In any case, we expect BB to be non-NULL at least up to register
allocation, so disallow a non-NULL BB up to there. Not perfect
but better than nothing... */
- gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed);
+ gcc_checking_assert (bb != NULL || reload_completed);
df_grow_bb_info (df_scan);
df_grow_reg_info ();
if (gsi_end_p (*gsi))
return true;
- /* Make sure we insert after any leading labels. We have to
- skip debug stmts before or among them, though. We didn't
- have to skip debug stmts after the last label, but it
- shouldn't hurt if we do. */
+ /* Make sure we insert after any leading labels. */
tmp = gsi_stmt (*gsi);
- while (gimple_code (tmp) == GIMPLE_LABEL
- || is_gimple_debug (tmp))
+ while (gimple_code (tmp) == GIMPLE_LABEL)
{
gsi_next (gsi);
if (gsi_end_p (*gsi))
}
/* Return a block statement iterator that points to the first
- non-label statement in block BB. Skip debug stmts only if they
- precede labels. */
+ non-label statement in block BB. */
static inline gimple_stmt_iterator
gsi_after_labels (basic_block bb)
{
gimple_stmt_iterator gsi = gsi_start_bb (bb);
- for (gimple_stmt_iterator gskip = gsi;
- !gsi_end_p (gskip); )
+ for (; !gsi_end_p (gsi); )
{
- if (is_gimple_debug (gsi_stmt (gskip)))
- gsi_next (&gskip);
- else if (gimple_code (gsi_stmt (gskip)) == GIMPLE_LABEL)
- {
- gsi_next (&gskip);
- gsi = gskip;
- }
+ if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
+ gsi_next (&gsi);
else
break;
}
if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
continue;
curr_bb = BLOCK_FOR_INSN (curr_insn);
- if (!curr_bb)
- {
- gcc_assert (DEBUG_INSN_P (curr_insn));
- if (DEBUG_MARKER_INSN_P (curr_insn))
- continue;
- curr_bb = prev_bb;
- }
if (curr_bb != prev_bb)
{
if (prev_bb != NULL)
static void
make_blocks (gimple_seq seq)
{
+ /* Look for debug markers right before labels, and move the debug
+ stmts after the labels. Accepting labels among debug markers
+ adds no value, just complexity; if we wanted to annotate labels
+ with view numbers (so sequencing among markers would matter) or
+ somesuch, we're probably better off still moving the labels, but
+ adding other debug annotations in their original positions or
+ emitting nonbind or bind markers associated with the labels in
+ the original position of the labels.
+
+ Moving labels would probably be simpler, but we can't do that:
+ moving labels assigns label ids to them, and doing so because of
+ debug markers makes for -fcompare-debug and possibly even codegen
+ differences. So, we have to move the debug stmts instead. To
+ that end, we scan SEQ backwards, marking the position of the
+ latest (earliest we find) label, and moving debug stmts that are
+ not separated from it by nondebug nonlabel stmts after the
+ label. */
+ if (MAY_HAVE_DEBUG_MARKER_STMTS)
+ {
+ gimple_stmt_iterator label = gsi_none ();
+
+ for (gimple_stmt_iterator i = gsi_last (seq); !gsi_end_p (i); gsi_prev (&i))
+ {
+ gimple *stmt = gsi_stmt (i);
+
+ /* If this is the first label we encounter (latest in SEQ)
+ before nondebug stmts, record its position. */
+ if (is_a <glabel *> (stmt))
+ {
+ if (gsi_end_p (label))
+ label = i;
+ continue;
+ }
+
+ /* Without a recorded label position to move debug stmts to,
+ there's nothing to do. */
+ if (gsi_end_p (label))
+ continue;
+
+ /* Move the debug stmt at I after LABEL. */
+ if (is_gimple_debug (stmt))
+ {
+ gcc_assert (gimple_debug_nonbind_marker_p (stmt));
+ /* As STMT is removed, I advances to the stmt after
+ STMT, so the gsi_prev in the for "increment"
+ expression gets us to the stmt we're to visit after
+ STMT. LABEL, however, would advance to the moved
+ stmt if we passed it to gsi_move_after, so pass it a
+ copy instead, so as to keep LABEL pointing to the
+ LABEL. */
+ gimple_stmt_iterator copy = label;
+ gsi_move_after (&i, ©);
+ continue;
+ }
+
+ /* There aren't any (more?) debug stmts before label, so
+ there isn't anything else to move after it. */
+ label = gsi_none ();
+ }
+ }
+
make_blocks_1 (seq, ENTRY_BLOCK_PTR_FOR_FN (cfun));
}
tree target;
if (!label_stmt)
- {
- if (is_gimple_debug (gsi_stmt (gsi)))
- continue;
- break;
- }
+ break;
target = gimple_label_label (label_stmt);
for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
- if (is_gimple_debug (gsi_stmt (i)))
- continue;
-
tree label;
glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (i));
for (i = gsi_start_bb (bb); !gsi_end_p (i); )
{
- if (is_gimple_debug (gsi_stmt (i)))
- {
- gsi_next (&i);
- continue;
- }
-
tree label;
glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (i));
gsi_next (&gsi))
{
tree lab;
- if (is_gimple_debug (gsi_stmt (gsi)))
- continue;
glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
if (!label_stmt)
break;
err |= err2;
}
- bool label_allowed = true;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
err2 = true;
}
- /* Labels may be preceded only by debug markers, not debug bind
- or source bind or any other statements. */
- if (gimple_code (stmt) == GIMPLE_LABEL)
- {
- if (!label_allowed)
- {
- error ("gimple label in the middle of a basic block");
- err2 = true;
- }
- }
- else if (!gimple_debug_begin_stmt_p (stmt))
- label_allowed = false;
-
err2 |= verify_gimple_stmt (stmt);
err2 |= verify_location (&blocks, gimple_location (stmt));
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
tree label;
-
- if (is_gimple_debug (gsi_stmt (gsi)))
- continue;
-
gimple *prev_stmt = stmt;
stmt = gsi_stmt (gsi);
tree label;
glabel *stmt;
- for (i = s; !gsi_end_p (i); gsi_next (&i))
+ for (i = s; !gsi_end_p (i); first = false, gsi_next (&i))
{
- if (is_gimple_debug (gsi_stmt (i)))
- continue;
stmt = dyn_cast <glabel *> (gsi_stmt (i));
if (!stmt)
break;
gsi_move_before (&i, &s);
return label;
}
- first = false;
}
label = create_artificial_label (UNKNOWN_LOCATION);
{
edge succ = single_succ_edge (bb), e, s;
basic_block dest = succ->dest;
- gimple *label;
+ gimple *stmt;
edge_iterator ei;
gimple_stmt_iterator gsi, gsi_to;
bool can_move_debug_stmts;
/* If the destination block consists of a nonlocal label or is a
EH landing pad, do not merge it. */
- label = first_stmt (dest);
- if (label)
- if (glabel *label_stmt = dyn_cast <glabel *> (label))
+ stmt = first_stmt (dest);
+ if (stmt)
+ if (glabel *label_stmt = dyn_cast <glabel *> (stmt))
if (DECL_NONLOCAL (gimple_label_label (label_stmt))
|| EH_LANDING_PAD_NR (gimple_label_label (label_stmt)) != 0)
return false;
defined labels and labels with an EH landing pad number to the
new block, so that the redirection of the abnormal edges works,
jump targets end up in a sane place and debug information for
- labels is retained.
-
- While at that, move any debug stmts that appear before or in between
- labels, but not those that can only appear after labels. */
+ labels is retained. */
gsi_to = gsi_start_bb (dest);
- gsi = gsi_start_bb (bb);
- gimple_stmt_iterator gsie = gsi_after_labels (bb);
- while (gsi_stmt (gsi) != gsi_stmt (gsie))
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
{
- tree decl;
- label = gsi_stmt (gsi);
- if (is_gimple_debug (label)
- ? can_move_debug_stmts
- : ((decl = gimple_label_label (as_a <glabel *> (label))),
- EH_LANDING_PAD_NR (decl) != 0
- || DECL_NONLOCAL (decl)
- || FORCED_LABEL (decl)
- || !DECL_ARTIFICIAL (decl)))
- {
- gsi_remove (&gsi, false);
- gsi_insert_before (&gsi_to, label, GSI_SAME_STMT);
- }
+ stmt = gsi_stmt (gsi);
+ if (is_gimple_debug (stmt))
+ break;
+
+ /* Forwarder blocks can only contain labels and debug stmts, and
+ labels must come first, so if we get to this point, we know
+ we're looking at a label. */
+ tree decl = gimple_label_label (as_a <glabel *> (stmt));
+ if (EH_LANDING_PAD_NR (decl) != 0
+ || DECL_NONLOCAL (decl)
+ || FORCED_LABEL (decl)
+ || !DECL_ARTIFICIAL (decl))
+ gsi_move_before (&gsi, &gsi_to);
else
gsi_next (&gsi);
}
/* Move debug statements if the destination has a single predecessor. */
if (can_move_debug_stmts && !gsi_end_p (gsi))
{
- gcc_assert (gsi_stmt (gsi) == gsi_stmt (gsie));
- gimple_stmt_iterator gsie_to = gsi_after_labels (dest);
+ gsi_to = gsi_after_labels (dest);
do
{
gimple *debug = gsi_stmt (gsi);
gcc_assert (is_gimple_debug (debug));
- gsi_remove (&gsi, false);
- gsi_insert_before (&gsie_to, debug, GSI_SAME_STMT);
+ gsi_move_before (&gsi, &gsi_to);
}
while (!gsi_end_p (gsi));
}
tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi1)));
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
return;
- gsi_prev_nondebug (&gsi1);
+ gsi_prev (&gsi1);
}
while (!gsi_end_p (gsi2) && gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2)));
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
return;
- gsi_prev_nondebug (&gsi2);
+ gsi_prev (&gsi2);
}
if (!(gsi_end_p (gsi1) && gsi_end_p (gsi2)))
return;
}
}
-/* Return BB's head, unless BB is the block that succeeds ENTRY_BLOCK,
- in which case it searches back from BB's head for the very first
- insn. Use [get_first_insn (bb), BB_HEAD (bb->next_bb)[ as a range
- to iterate over all insns of a function while iterating over its
- BBs. */
-
-static rtx_insn *
-get_first_insn (basic_block bb)
-{
- rtx_insn *insn = BB_HEAD (bb);
-
- if (bb->prev_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
- while (rtx_insn *prev = PREV_INSN (insn))
- insn = prev;
-
- return insn;
-}
-
/* Emit notes for the whole function. */
static void
{
/* Emit the notes for changes of variable locations between two
subsequent basic blocks. */
- emit_notes_for_differences (get_first_insn (bb),
- &cur, &VTI (bb)->in);
+ emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
if (MAY_HAVE_DEBUG_BIND_INSNS)
local_get_addr_cache = new hash_map<rtx, rtx>;
/* Reemit INSN, a MARKER_DEBUG_INSN, as a note. */
static rtx_insn *
-reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
+reemit_marker_as_note (rtx_insn *insn)
{
gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
{
note = emit_note_before (kind, insn);
NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
- if (bb)
- BLOCK_FOR_INSN (note) = *bb;
}
delete_insn (insn);
return note;
HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
- /* If we are walking the first basic block, walk any HEADER
- insns that might be before it too. Unfortunately,
- BB_HEADER and BB_FOOTER are not set while we run this
- pass. */
rtx_insn *next;
- bool outside_bb = true;
- for (insn = get_first_insn (bb); insn != BB_HEAD (bb->next_bb);
- insn = next)
+ FOR_BB_INSNS_SAFE (bb, insn, next)
{
- if (insn == BB_HEAD (bb))
- outside_bb = false;
- else if (insn == NEXT_INSN (BB_END (bb)))
- outside_bb = true;
- next = NEXT_INSN (insn);
if (INSN_P (insn))
{
- if (outside_bb)
- {
- /* Ignore non-debug insns outside of basic blocks. */
- if (!DEBUG_INSN_P (insn))
- continue;
- /* Debug binds shouldn't appear outside of bbs. */
- gcc_assert (!DEBUG_BIND_INSN_P (insn));
- }
- basic_block save_bb = BLOCK_FOR_INSN (insn);
- if (!BLOCK_FOR_INSN (insn))
- {
- gcc_assert (outside_bb);
- BLOCK_FOR_INSN (insn) = bb;
- }
- else
- gcc_assert (BLOCK_FOR_INSN (insn) == bb);
-
if (!frame_pointer_needed)
{
insn_stack_adjust_offset_pre_post (insn, &pre, &post);
adjust_insn (bb, insn);
if (DEBUG_MARKER_INSN_P (insn))
{
- insn = reemit_marker_as_note (insn, &save_bb);
+ reemit_marker_as_note (insn);
continue;
}
}
}
}
- BLOCK_FOR_INSN (insn) = save_bb;
}
}
gcc_assert (offset == VTI (bb)->out.stack_adjust);
FOR_EACH_BB_FN (bb, cfun)
{
- for (insn = get_first_insn (bb);
- insn != BB_HEAD (bb->next_bb)
- ? next = NEXT_INSN (insn), true : false;
- insn = next)
+ FOR_BB_INSNS_SAFE (bb, insn, next)
if (DEBUG_INSN_P (insn))
{
if (DEBUG_MARKER_INSN_P (insn))
{
- insn = reemit_marker_as_note (insn, NULL);
+ reemit_marker_as_note (insn);
continue;
}