@@ -76,6 +76,27 @@ pop_stmt_list (tree t)
free_stmt_list (t);
t = u;
}
+ /* If the statement list contained a debug begin stmt and a
+ statement list, move the debug begin stmt into the statement
+ list and return it. */
+ else if (!tsi_end_p (i)
+ && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ {
+ u = tsi_stmt (i);
+ tsi_next (&i);
+ if (tsi_one_before_end_p (i)
+ && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST)
+ {
+ tree l = tsi_stmt (i);
+ tsi_prev (&i);
+ tsi_delink (&i);
+ tsi_delink (&i);
+ i = tsi_start (l);
+ free_stmt_list (t);
+ t = l;
+ tsi_link_before (&i, u, TSI_SAME_STMT);
+ }
+ }
}
return t;
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3. If not see
#define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
#undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
#define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
/* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
@@ -1640,6 +1640,19 @@ c_parser_external_declaration (c_parser *parser)
static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+ if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+ return;
+
+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition
is accepted; otherwise (old-style parameter declarations) only other
@@ -1740,6 +1753,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool diagnosed_no_specs = false;
location_t here = c_parser_peek_token (parser)->location;
+ add_debug_begin_stmt (c_parser_peek_token (parser)->location);
+
if (static_assert_ok
&& c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
{
@@ -4949,6 +4964,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
+ add_debug_begin_stmt (c_parser_peek_token (parser)->location);
c_parser_consume_token (parser);
return;
}
@@ -5403,6 +5419,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
parser->in_if_block = false;
if (if_p != NULL)
*if_p = false;
+
+ if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+ add_debug_begin_stmt (loc);
+
switch (c_parser_peek_token (parser)->type)
{
case CPP_OPEN_BRACE:
@@ -10681,6 +10681,10 @@ c_finish_stmt_expr (location_t loc, tree body)
}
else
i = tsi_last (last);
+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ do
+ tsi_prev (&i);
+ while (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT);
last_p = tsi_stmt_ptr (i);
last = *last_p;
}
@@ -10700,7 +10704,9 @@ c_finish_stmt_expr (location_t loc, tree body)
/* In the case that the BIND_EXPR is not necessary, return the
expression out from inside it. */
- if (last == BIND_EXPR_BODY (body)
+ if ((last == BIND_EXPR_BODY (body)
+ /* Skip nested debug stmts. */
+ || last == expr_first (BIND_EXPR_BODY (body)))
&& BIND_EXPR_VARS (body) == NULL)
{
/* Even if this looks constant, do not allow it in a constant
@@ -5638,39 +5638,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
if (new_bb)
return new_bb;
}
- else if (gimple_debug_bind_p (stmt))
+ else if (is_gimple_debug (stmt))
{
location_t sloc = curr_insn_location ();
gimple_stmt_iterator nsi = gsi;
for (;;)
{
- tree var = gimple_debug_bind_get_var (stmt);
- tree value;
- rtx val;
+ tree var;
+ tree value = NULL_TREE;
+ rtx val = NULL_RTX;
machine_mode mode;
- if (TREE_CODE (var) != DEBUG_EXPR_DECL
- && TREE_CODE (var) != LABEL_DECL
- && !target_for_debug_bind (var))
- goto delink_debug_stmt;
+ if (!gimple_debug_nonbind_marker_p (stmt))
+ {
+ if (gimple_debug_bind_p (stmt))
+ {
+ var = gimple_debug_bind_get_var (stmt);
- if (gimple_debug_bind_has_value_p (stmt))
- value = gimple_debug_bind_get_value (stmt);
- else
- value = NULL_TREE;
+ if (TREE_CODE (var) != DEBUG_EXPR_DECL
+ && TREE_CODE (var) != LABEL_DECL
+ && !target_for_debug_bind (var))
+ goto delink_debug_stmt;
- last = get_last_insn ();
+ if (DECL_P (var))
+ mode = DECL_MODE (var);
+ else
+ mode = TYPE_MODE (TREE_TYPE (var));
- set_curr_insn_location (gimple_location (stmt));
+ if (gimple_debug_bind_has_value_p (stmt))
+ value = gimple_debug_bind_get_value (stmt);
+
+ val = gen_rtx_VAR_LOCATION
+ (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+ }
+ else if (gimple_debug_source_bind_p (stmt))
+ {
+ var = gimple_debug_source_bind_get_var (stmt);
+
+ value = gimple_debug_source_bind_get_value (stmt);
+
+ mode = DECL_MODE (var);
- if (DECL_P (var))
- mode = DECL_MODE (var);
+ val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+ VAR_INIT_STATUS_UNINITIALIZED);
+ }
+ else
+ gcc_unreachable ();
+ }
+ /* If this function was first compiled with markers
+ enabled, but they're now disable (e.g. LTO), drop
+ them on the floor. */
+ else if (gimple_debug_nonbind_marker_p (stmt)
+ && !MAY_HAVE_DEBUG_MARKER_INSNS)
+ goto delink_debug_stmt;
+ else if (gimple_debug_begin_stmt_p (stmt))
+ val = gen_rtx_DEBUG_MARKER (VOIDmode);
else
- mode = TYPE_MODE (TREE_TYPE (var));
+ gcc_unreachable ();
- val = gen_rtx_VAR_LOCATION
- (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+ last = get_last_insn ();
+
+ set_curr_insn_location (gimple_location (stmt));
emit_debug_insn (val);
@@ -5678,9 +5707,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
{
/* We can't dump the insn with a TREE where an RTX
is expected. */
- PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+ if (GET_CODE (val) == VAR_LOCATION)
+ {
+ gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);
+ PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+ }
maybe_dump_rtl_for_gimple_stmt (stmt, last);
- PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+ if (GET_CODE (val) == VAR_LOCATION)
+ PAT_VAR_LOCATION_LOC (val) = (rtx)value;
}
delink_debug_stmt:
@@ -5696,42 +5730,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
if (gsi_end_p (nsi))
break;
stmt = gsi_stmt (nsi);
- if (!gimple_debug_bind_p (stmt))
+ if (!is_gimple_debug (stmt))
break;
}
set_curr_insn_location (sloc);
}
- else if (gimple_debug_source_bind_p (stmt))
- {
- location_t sloc = curr_insn_location ();
- tree var = gimple_debug_source_bind_get_var (stmt);
- tree value = gimple_debug_source_bind_get_value (stmt);
- rtx val;
- machine_mode mode;
-
- last = get_last_insn ();
-
- set_curr_insn_location (gimple_location (stmt));
-
- mode = DECL_MODE (var);
-
- val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
- VAR_INIT_STATUS_UNINITIALIZED);
-
- emit_debug_insn (val);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- /* We can't dump the insn with a TREE where an RTX
- is expected. */
- PAT_VAR_LOCATION_LOC (val) = const0_rtx;
- maybe_dump_rtl_for_gimple_stmt (stmt, last);
- PAT_VAR_LOCATION_LOC (val) = (rtx)value;
- }
-
- set_curr_insn_location (sloc);
- }
else
{
gcall *call_stmt = dyn_cast <gcall *> (stmt);
@@ -6370,6 +6374,11 @@ pass_expand::execute (function *fun)
FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
e->flags &= ~EDGE_EXECUTABLE;
+ /* If the function has too many markers, drop them while expanding. */
+ if (cfun->debug_marker_count
+ >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+ cfun->debug_nonbind_markers = false;
+
lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
next_bb)
@@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
tree_stmt_iterator i;
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ /* ??? Can we retain this information somehow? */
+ continue;
if (! build_data_member_initialization (tsi_stmt (i), vec))
return false;
}
@@ -448,6 +451,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
case USING_STMT:
case STATIC_ASSERT:
+ case DEBUG_BEGIN_STMT:
return true;
default:
@@ -586,6 +590,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
tree_stmt_iterator i;
for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
{
+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ /* ??? Can we retain this information somehow? */
+ continue;
ok = build_data_member_initialization (tsi_stmt (i), &vec);
if (!ok)
break;
@@ -673,6 +680,7 @@ constexpr_fn_retval (tree body)
return constexpr_fn_retval (BIND_EXPR_BODY (body));
case USING_STMT:
+ case DEBUG_BEGIN_STMT:
return NULL_TREE;
default:
@@ -3765,6 +3773,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
tree stmt = tsi_stmt (i);
+ if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
+ continue;
r = cxx_eval_constant_expression (ctx, stmt, false,
non_constant_p, overflow_p,
jump_target);
@@ -5096,6 +5106,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case CONTINUE_STMT:
case REQUIRES_EXPR:
case STATIC_ASSERT:
+ case DEBUG_BEGIN_STMT:
return true;
case AGGR_INIT_EXPR:
@@ -780,6 +780,31 @@ error:
return error_mark_node;
}
+/* Return a location associated with stmt. If it is an expresion,
+ that's the expression's location. If it is a STATEMENT_LIST,
+ instead of no location, use expr_first to skip any debug stmts and
+ take the location of the first nondebug stmt found. */
+
+static location_t
+stmt_location (tree stmt)
+{
+ location_t loc = UNKNOWN_LOCATION;
+
+ if (!stmt)
+ return loc;
+
+ loc = EXPR_LOCATION (stmt);
+
+ if (loc != UNKNOWN_LOCATION || TREE_CODE (stmt) != STATEMENT_LIST)
+ return loc;
+
+ stmt = expr_first (stmt);
+ if (stmt)
+ loc = EXPR_LOCATION (stmt);
+
+ return loc;
+}
+
/* Helper function for expand_conditonal_array_notations. Encloses the
conditional statement passed in ORIG_STMT with a loop around it and
replaces the condition in STMT with a ARRAY_REF tree-node to the array.
@@ -835,10 +860,12 @@ cp_expand_cond_array_notations (tree orig_stmt)
tree cond = IF_COND (orig_stmt);
if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
|| (yes_expr
- && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
+ && !find_rank (stmt_location (yes_expr),
+ yes_expr, yes_expr, true,
&yes_rank))
|| (no_expr
- && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
+ && !find_rank (stmt_location (no_expr),
+ no_expr, no_expr, true,
&no_rank)))
return error_mark_node;
@@ -847,13 +874,15 @@ cp_expand_cond_array_notations (tree orig_stmt)
return orig_stmt;
else if (cond_rank != yes_rank && yes_rank != 0)
{
- error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
+ error_at (stmt_location (yes_expr),
+ "rank mismatch with controlling"
" expression of parent if-statement");
return error_mark_node;
}
else if (cond_rank != no_rank && no_rank != 0)
{
- error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
+ error_at (stmt_location (no_expr),
+ "rank mismatch with controlling "
"expression of parent if-statement");
return error_mark_node;
}
@@ -103,6 +103,8 @@ extern void cp_register_dumps (gcc::dump_manager *);
#define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
#undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
#define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
/* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
@@ -10712,6 +10712,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
/* Statements [gram.stmt.stmt] */
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+ if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+ return;
+
+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
/* Parse a statement.
statement:
@@ -10787,6 +10800,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
token = cp_lexer_peek_token (parser->lexer);
/* Remember the location of the first token in the statement. */
statement_location = token->location;
+ add_debug_begin_stmt (statement_location);
/* If this is a keyword, then that will often determine what kind of
statement we have. */
if (token->type == CPP_KEYWORD)
@@ -15120,6 +15120,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case PREDICT_EXPR:
return t;
+ case DEBUG_BEGIN_STMT:
+ /* ??? There's no point in copying it for now, but maybe some
+ day it will contain more information, such as a pointer back
+ to the containing function, inlined copy or so. */
+ return t;
+
default:
/* We shouldn't get here, but keep going if !flag_checking. */
if (flag_checking)
@@ -6953,11 +6953,18 @@ insn_live_p (rtx_insn *insn, int *counts)
{
rtx_insn *next;
+ if (DEBUG_MARKER_INSN_P (insn))
+ return true;
+
for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
if (NOTE_P (next))
continue;
else if (!DEBUG_INSN_P (next))
return true;
+ /* If we find an inspection point, such as a debug begin stmt,
+ we want to keep the earlier debug insn. */
+ else if (DEBUG_MARKER_INSN_P (next))
+ return true;
else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
return false;
@@ -945,7 +945,7 @@ df_insn_delete (rtx_insn *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 || reload_completed);
+ gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed);
df_grow_bb_info (df_scan);
df_grow_reg_info ();
@@ -1930,6 +1930,11 @@ case 2 ... 5:
The first value will be @code{CASE_LOW}, while the second will be
@code{CASE_HIGH}.
+@item DEBUG_BEGIN_STMT
+
+Marks the beginning of a source statement, for purposes of debug
+information generation.
+
@end table
@@ -831,6 +831,16 @@ expression to a variable.
Return true if g is any of the OpenMP codes.
@end deftypefn
+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
+a source statement.
+@end deftypefn
+
+@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
+without any variable binding.
+@end deftypefn
+
@node Manipulating GIMPLE statements
@section Manipulating GIMPLE statements
@cindex Manipulating GIMPLE statements
@@ -1528,10 +1538,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
@subsection @code{GIMPLE_DEBUG}
@cindex @code{GIMPLE_DEBUG}
@cindex @code{GIMPLE_DEBUG_BIND}
+@cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
@deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
tree value, gimple stmt)
-Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of
+Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND}
@code{subcode}. The effect of this statement is to tell debug
information generation machinery that the value of user variable
@code{var} is given by @code{value} at that point, and to remain with
@@ -1602,6 +1613,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
and @code{FALSE} if it unbinds the variable.
@end deftypefn
+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}. The effect of this
+statement is to tell debug information generation machinery that the
+user statement at the given @code{location} and @code{block} starts at
+the point at which the statement is inserted. The intent is that side
+effects (e.g. variable bindings) of all prior user statements are
+observable, and that none of the side effects of subsequent user
+statements are.
+@end deftypefn
+
@node @code{GIMPLE_EH_FILTER}
@subsection @code{GIMPLE_EH_FILTER}
@cindex @code{GIMPLE_EH_FILTER}
@@ -10419,6 +10419,13 @@ debug information may end up not being used; setting this higher may
enable the compiler to find more complex debug expressions, but compile
time and memory use may grow. The default is 12.
+@item max-debug-marker-count
+Sets a threshold on the number of debug markers (e.g. begin stmt
+markers) to avoid complexity explosion at inlining or expanding to RTL.
+If a function has more such gimple stmts than the set limit, such stmts
+will be dropped from the inlined copy of a function, and from its RTL
+expansion. The default is 100000.
+
@item min-nondebug-insn-uid
Use uids starting at this parameter for nondebug insns. The range below
the parameter is reserved exclusively for debug insns created by
@@ -3413,6 +3413,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},
that points back to it, within value expressions in
@code{VAR_LOCATION} nodes.
+@findex debug_implicit_ptr
+@item (debug_implicit_ptr:@var{mode} @var{decl})
+Stands for the location of a @var{decl} that is no longer addressable.
+
+@findex entry_value
+@item (entry_value:@var{mode} @var{decl})
+Stands for the value a @var{decl} had at the entry point of the
+containing function.
+
+@findex debug_parameter_ref
+@item (debug_parameter_ref:@var{mode} @var{decl})
+Refers to a parameter that was completely optimized out.
+
+@findex debug_marker
+@item (debug_marker:@var{mode})
+Marks a program location. With @code{VOIDmode}, it stands for the
+beginning of a statement, a recommended inspection point logically after
+all prior side effects, and before any subsequent side effects.
+
@end table
@node Insns
@@ -3689,6 +3708,12 @@ can be computed by evaluating the RTL expression from that static
point in the program up to the next such note for the same user
variable.
+@findex NOTE_INSN_BEGIN_STMT
+@item NOTE_INSN_BEGIN_STMT
+This note is used to generate @code{is_stmt} markers in line number
+debuggign information. It indicates the beginning of a user
+statement.
+
@end table
These codes are printed symbolically when they appear in debugging dumps.
@@ -3706,15 +3731,25 @@ binds a user variable tree to an RTL representation of the
it stands for the value bound to the corresponding
@code{DEBUG_EXPR_DECL}.
-Throughout optimization passes, binding information is kept in
-pseudo-instruction form, so that, unlike notes, it gets the same
-treatment and adjustments that regular instructions would. It is the
-variable tracking pass that turns these pseudo-instructions into var
-location notes, analyzing control flow, value equivalences and changes
-to registers and memory referenced in value expressions, propagating
-the values of debug temporaries and determining expressions that can
-be used to compute the value of each user variable at as many points
-(ranges, actually) in the program as possible.
+@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
+with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}. These
+@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
+just @code{DEBUG_MARKER}s, can be detected by testing
+@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
+@code{DEBUG_BIND_INSN_P}.
+
+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
+with respect to each other, particularly during scheduling. Binding
+information is kept in pseudo-instruction form, so that, unlike notes,
+it gets the same treatment and adjustments that regular instructions
+would. It is the variable tracking pass that turns these
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
+@code{NOTE_INSN_BEGIN_STMT} notes,
+analyzing control flow, value equivalences and changes to registers and
+memory referenced in value expressions, propagating the values of debug
+temporaries and determining expressions that can be used to compute the
+value of each user variable at as many points (ranges, actually) in the
+program as possible.
Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
@code{INSN_VAR_LOCATION} denotes a value at that specific point in the
@@ -1653,7 +1653,6 @@ reemit_insn_block_notes (void)
{
tree cur_block = DECL_INITIAL (cfun->decl);
rtx_insn *insn;
- rtx_note *note;
insn = get_insns ();
for (; insn; insn = NEXT_INSN (insn))
@@ -1661,17 +1660,29 @@ reemit_insn_block_notes (void)
tree this_block;
/* Prevent lexical blocks from straddling section boundaries. */
- if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
- {
- for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
- s = BLOCK_SUPERCONTEXT (s))
- {
- rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
- NOTE_BLOCK (note) = s;
- note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
- NOTE_BLOCK (note) = s;
- }
- }
+ if (NOTE_P (insn))
+ switch (NOTE_KIND (insn))
+ {
+ case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+ {
+ for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
+ s = BLOCK_SUPERCONTEXT (s))
+ {
+ rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+ NOTE_BLOCK (note) = s;
+ note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
+ NOTE_BLOCK (note) = s;
+ }
+ }
+ break;
+
+ case NOTE_INSN_BEGIN_STMT:
+ this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
+ goto set_cur_block_to_this_block;
+
+ default:
+ continue;
+ }
if (!active_insn_p (insn))
continue;
@@ -1692,6 +1703,7 @@ reemit_insn_block_notes (void)
this_block = choose_inner_scope (this_block,
insn_scope (body->insn (i)));
}
+ set_cur_block_to_this_block:
if (! this_block)
{
if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
@@ -1708,7 +1720,7 @@ reemit_insn_block_notes (void)
}
/* change_scope emits before the insn, not after. */
- note = emit_note (NOTE_INSN_DELETED);
+ rtx_note *note = emit_note (NOTE_INSN_DELETED);
change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
delete_insn (note);
@@ -2410,6 +2422,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
debug_hooks->var_location (insn);
break;
+ case NOTE_INSN_BEGIN_STMT:
+ gcc_checking_assert (cfun->debug_nonbind_markers);
+ if (!DECL_IGNORED_P (current_function_decl)
+ && notice_source_line (insn, NULL))
+ {
+ (*debug_hooks->source_line) (last_linenum, last_columnnum,
+ last_filename, last_discriminator,
+ true);
+ }
+ break;
+
default:
gcc_unreachable ();
break;
@@ -2497,7 +2520,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
rtx body = PATTERN (insn);
int insn_code_number;
const char *templ;
- bool is_stmt;
+ bool is_stmt, *is_stmt_p;
+
+ if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
+ {
+ is_stmt = false;
+ is_stmt_p = NULL;
+ }
+ else
+ is_stmt_p = &is_stmt;
/* Reset this early so it is correct for ASM statements. */
current_insn_predicate = NULL_RTX;
@@ -2600,7 +2631,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
/* Output this line note if it is the first or the last line
note in a row. */
if (!DECL_IGNORED_P (current_function_decl)
- && notice_source_line (insn, &is_stmt))
+ && notice_source_line (insn, is_stmt_p))
{
if (flag_verbose_asm)
asm_show_source (last_filename, last_linenum);
@@ -3093,7 +3124,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
const char *filename;
int linenum, columnnum;
- if (override_filename)
+ if (NOTE_MARKER_P (insn))
+ {
+ location_t loc = NOTE_MARKER_LOCATION (insn);
+ expanded_location xloc = expand_location (loc);
+ if (xloc.line == 0)
+ {
+ gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
+ || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
+ return false;
+ }
+ filename = xloc.file;
+ linenum = xloc.line;
+ columnnum = xloc.column;
+ force_source_line = true;
+ }
+ else if (override_filename)
{
filename = override_filename;
linenum = override_linenum;
@@ -3126,7 +3172,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
last_linenum = linenum;
last_columnnum = columnnum;
last_discriminator = discriminator;
- *is_stmt = true;
+ if (is_stmt)
+ *is_stmt = true;
high_block_linenum = MAX (last_linenum, high_block_linenum);
high_function_linenum = MAX (last_linenum, high_function_linenum);
return true;
@@ -3138,7 +3185,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
output the line table entry with is_stmt false so the
debugger does not treat this as a breakpoint location. */
last_discriminator = discriminator;
- *is_stmt = false;
+ if (is_stmt)
+ *is_stmt = false;
return true;
}
@@ -4491,6 +4539,10 @@ rest_of_handle_final (void)
{
const char *fnname = get_fnname_from_decl (current_function_decl);
+ /* Turn debug markers into notes. */
+ if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)
+ variable_tracking_main ();
+
assemble_start_function (current_function_decl, fnname);
final_start_function (get_insns (), asm_out_file, optimize);
final (get_insns (), asm_out_file, optimize);
@@ -4678,6 +4730,7 @@ rest_of_clean_state (void)
if (final_output
&& (!NOTE_P (insn) ||
(NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
&& NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
&& NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
&& NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
@@ -4941,6 +4941,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
if (!profile_flag && !flag_instrument_function_entry_exit)
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
}
+
+ /* Don't enable begin stmt markers if var-tracking at assignments is
+ disabled. The markers make little sense without the variable
+ binding annotations among them. */
+ cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
+ && MAY_HAVE_DEBUG_MARKER_STMTS;
}
/* This is like allocate_struct_function, but pushes a new cfun for FNDECL
@@ -284,6 +284,12 @@ struct GTY(()) function {
/* Last statement uid. */
int last_stmt_uid;
+ /* Debug marker counter. Count begin stmt markers. We don't have
+ to keep it exact, it's more of a rough estimate to enable us to
+ decide whether they are too many to copy during inlining, or when
+ expanding to RTL. */
+ int debug_marker_count;
+
/* Function sequence number for profiling, debugging, etc. */
int funcdef_no;
@@ -387,6 +393,10 @@ struct GTY(()) function {
/* Set when the tail call has been identified. */
unsigned int tail_call_marked : 1;
+
+ /* Set when the function was compiled with generation of debug
+ (begin stmt, inline entry, ...) markers enabled. */
+ unsigned int debug_nonbind_markers : 1;
};
/* Add the decl D to the local_decls list of FUN. */
@@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
if (remove_permanently)
{
+ if (gimple_debug_nonbind_marker_p (stmt))
+ /* We don't need this to be exact, but try to keep it at least
+ close. */
+ cfun->debug_marker_count--;
require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
gimple_remove_stmt_histograms (cfun, stmt);
}
@@ -110,6 +110,17 @@ lower_function_body (void)
i = gsi_last (lowered_body);
+ /* If we had begin stmt markers from e.g. PCH, but this compilation
+ doesn't want them, lower_stmt will have cleaned them up; we can
+ now clear the flag that indicates we had them. */
+ if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
+ {
+ /* This counter needs not be exact, but before lowering it will
+ most certainly be. */
+ gcc_assert (cfun->debug_marker_count == 0);
+ cfun->debug_nonbind_markers = false;
+ }
+
/* If the function falls off the end, we need a null return statement.
If we've already got one in the return_statements vector, we don't
need to do anything special. Otherwise build one by hand. */
@@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
}
break;
+ case GIMPLE_DEBUG:
+ gcc_checking_assert (cfun->debug_nonbind_markers);
+ /* We can't possibly have debug bind stmts before lowering, we
+ first emit them when entering SSA. */
+ gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
+ /* Propagate fallthruness. */
+ /* If the function (e.g. from PCH) had debug stmts, but they're
+ disabled for this compilation, remove them. */
+ if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+ gsi_remove (gsi, true);
+ else
+ gsi_next (gsi);
+ return;
+
case GIMPLE_NOP:
case GIMPLE_ASM:
case GIMPLE_ASSIGN:
@@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
cannot_fallthru = false;
break;
+ case GIMPLE_DEBUG:
+ gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
+ break;
+
default:
/* This case represents statements to be executed when an
exception occurs. Those statements are implicitly followed
@@ -1370,6 +1370,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
gimple_debug_source_bind_get_value (gs));
break;
+ case GIMPLE_DEBUG_BEGIN_STMT:
+ if (flags & TDF_RAW)
+ dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+ else
+ dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+ break;
+
default:
gcc_unreachable ();
}
@@ -836,6 +836,27 @@ gimple_build_debug_source_bind (tree var, tree value,
}
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+ LOCATION. */
+
+gdebug *
+gimple_build_debug_begin_stmt (tree block, location_t location
+ MEM_STAT_DECL)
+{
+ gdebug *p
+ = as_a <gdebug *> (
+ gimple_build_with_ops_stat (GIMPLE_DEBUG,
+ (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+ PASS_MEM_STAT));
+
+ gimple_set_location (p, location);
+ gimple_set_block (p, block);
+ cfun->debug_marker_count++;
+
+ return p;
+}
+
+
/* Build a GIMPLE_OMP_CRITICAL statement.
BODY is the sequence of statements for which only one thread can execute.
@@ -1874,6 +1895,9 @@ gimple_copy (gimple *stmt)
gimple_set_modified (copy, true);
}
+ if (gimple_debug_nonbind_marker_p (stmt))
+ cfun->debug_marker_count++;
+
return copy;
}
@@ -1454,6 +1454,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );
geh_dispatch *gimple_build_eh_dispatch (int);
gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
+gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
@@ -982,6 +982,48 @@ unshare_expr_without_location (tree expr)
walk_tree (&expr, prune_expr_location, NULL, NULL);
return expr;
}
+
+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
+ one, OR_ELSE otherwise. The location of a STATEMENT_LISTs
+ comprising at least one DEBUG_BEGIN_STMT followed by exactly one
+ EXPR is the location of the EXPR. */
+
+static location_t
+rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
+ if (!expr)
+ return or_else;
+
+ if (EXPR_HAS_LOCATION (expr))
+ return EXPR_LOCATION (expr);
+
+ if (TREE_CODE (expr) != STATEMENT_LIST)
+ return or_else;
+
+ tree_stmt_iterator i = tsi_start (expr);
+
+ bool found = false;
+ while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ {
+ found = true;
+ tsi_next (&i);
+ }
+
+ if (!found || !tsi_one_before_end_p (i))
+ return or_else;
+
+ return rexpr_location (tsi_stmt (i), or_else);
+}
+
+/* Return TRUE iff EXPR (maybe recursively) has a location; see
+ rexpr_location for the potential recursion. */
+
+static inline bool
+rexpr_has_location (tree expr)
+{
+ return rexpr_location (expr) != UNKNOWN_LOCATION;
+}
+
/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
contain statements and have a value. Assign its value to a temporary
@@ -1772,6 +1814,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
/* Walk the sub-statements. */
*handled_ops_p = false;
break;
+
+ case GIMPLE_DEBUG:
+ /* Ignore these. We may generate them before declarations that
+ are never executed. If there's something to warn about,
+ there will be non-debug stmts too, and we'll catch those. */
+ break;
+
case GIMPLE_CALL:
if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
{
@@ -3440,7 +3489,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
append_to_statement_list (t, &expr);
/* Set the source location of the && on the second 'if'. */
- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+ new_locus = rexpr_location (pred, locus);
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
new_locus);
append_to_statement_list (t, &expr);
@@ -3463,7 +3512,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
append_to_statement_list (t, &expr);
/* Set the source location of the || on the second 'if'. */
- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+ new_locus = rexpr_location (pred, locus);
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
new_locus);
append_to_statement_list (t, &expr);
@@ -3485,7 +3534,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
/* Keep the original source location on the first 'if'. Set the source
location of the ? on the second 'if'. */
- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+ new_locus = rexpr_location (pred, locus);
expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p, locus),
@@ -3509,6 +3558,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
return expr;
}
+/* If EXPR is a GOTO_EXPR, return it. If it is a STATEMENT_LIST, skip
+ any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent
+ statement, if it is the last one. Otherwise, return NULL. */
+
+static tree
+find_goto (tree expr)
+{
+ if (!expr)
+ return NULL_TREE;
+
+ if (TREE_CODE (expr) == GOTO_EXPR)
+ return expr;
+
+ if (TREE_CODE (expr) != STATEMENT_LIST)
+ return NULL_TREE;
+
+ tree_stmt_iterator i = tsi_start (expr);
+
+ while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ tsi_next (&i);
+
+ if (!tsi_one_before_end_p (i))
+ return NULL_TREE;
+
+ return find_goto (tsi_stmt (i));
+}
+
+/* Same as find_goto, except that it returns NULL if the destination
+ is not a LABEL_DECL. */
+
+static inline tree
+find_goto_label (tree expr)
+{
+ tree dest = find_goto (expr);
+ if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)
+ return dest;
+ return NULL_TREE;
+}
+
/* Given a conditional expression EXPR with short-circuit boolean
predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the
predicate apart into the equivalent sequence of conditionals. */
@@ -3539,8 +3627,8 @@ shortcut_cond_expr (tree expr)
location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
/* Set the source location of the && on the second 'if'. */
- if (EXPR_HAS_LOCATION (pred))
- SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+ if (rexpr_has_location (pred))
+ SET_EXPR_LOCATION (expr, rexpr_location (pred));
then_ = shortcut_cond_expr (expr);
then_se = then_ && TREE_SIDE_EFFECTS (then_);
pred = TREE_OPERAND (pred, 0);
@@ -3561,8 +3649,8 @@ shortcut_cond_expr (tree expr)
location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
/* Set the source location of the || on the second 'if'. */
- if (EXPR_HAS_LOCATION (pred))
- SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+ if (rexpr_has_location (pred))
+ SET_EXPR_LOCATION (expr, rexpr_location (pred));
else_ = shortcut_cond_expr (expr);
else_se = else_ && TREE_SIDE_EFFECTS (else_);
pred = TREE_OPERAND (pred, 0);
@@ -3589,20 +3677,16 @@ shortcut_cond_expr (tree expr)
/* If our arms just jump somewhere, hijack those labels so we don't
generate jumps to jumps. */
- if (then_
- && TREE_CODE (then_) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
+ if (tree then_goto = find_goto_label (then_))
{
- true_label = GOTO_DESTINATION (then_);
+ true_label = GOTO_DESTINATION (then_goto);
then_ = NULL;
then_se = false;
}
- if (else_
- && TREE_CODE (else_) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
+ if (tree else_goto = find_goto_label (else_))
{
- false_label = GOTO_DESTINATION (else_);
+ false_label = GOTO_DESTINATION (else_goto);
else_ = NULL;
else_se = false;
}
@@ -3666,8 +3750,8 @@ shortcut_cond_expr (tree expr)
{
tree last = expr_last (expr);
t = build_and_jump (&end_label);
- if (EXPR_HAS_LOCATION (last))
- SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
+ if (rexpr_has_location (last))
+ SET_EXPR_LOCATION (t, rexpr_location (last));
append_to_statement_list (t, &expr);
}
if (emit_false)
@@ -3960,39 +4044,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
gimple_push_condition ();
have_then_clause_p = have_else_clause_p = false;
- if (TREE_OPERAND (expr, 1) != NULL
- && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
- && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
- == current_function_decl)
+ label_true = find_goto_label (TREE_OPERAND (expr, 1));
+ if (label_true
+ && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
/* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
have different locations, otherwise we end up with incorrect
location information on the branches. */
&& (optimize
|| !EXPR_HAS_LOCATION (expr)
- || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
- || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
+ || !rexpr_has_location (label_true)
+ || EXPR_LOCATION (expr) == rexpr_location (label_true)))
{
- label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
have_then_clause_p = true;
+ label_true = GOTO_DESTINATION (label_true);
}
else
label_true = create_artificial_label (UNKNOWN_LOCATION);
- if (TREE_OPERAND (expr, 2) != NULL
- && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
- && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
- == current_function_decl)
+ label_false = find_goto_label (TREE_OPERAND (expr, 2));
+ if (label_false
+ && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
/* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
have different locations, otherwise we end up with incorrect
location information on the branches. */
&& (optimize
|| !EXPR_HAS_LOCATION (expr)
- || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
- || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
+ || !rexpr_has_location (label_false)
+ || EXPR_LOCATION (expr) == rexpr_location (label_false)))
{
- label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
have_else_clause_p = true;
+ label_false = GOTO_DESTINATION (label_false);
}
else
label_false = create_artificial_label (UNKNOWN_LOCATION);
@@ -11782,6 +11862,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
ret = GS_ALL_DONE;
break;
+ case DEBUG_EXPR_DECL:
+ gcc_unreachable ();
+
+ case DEBUG_BEGIN_STMT:
+ gimplify_seq_add_stmt (pre_p,
+ gimple_build_debug_begin_stmt
+ (TREE_BLOCK (*expr_p),
+ EXPR_LOCATION (*expr_p)));
+ ret = GS_ALL_DONE;
+ *expr_p = NULL;
+ break;
+
case SSA_NAME:
/* Allow callbacks into the gimplifier during optimization. */
ret = GS_ALL_DONE;
@@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int);
#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP false
#define LANG_HOOKS_DEEP_UNSHARING false
#define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS false
+#define LANG_HOOKS_EMITS_BEGIN_STMT false
#define LANG_HOOKS_RUN_LANG_SELFTESTS lhd_do_nothing
#define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
@@ -341,6 +342,7 @@ extern void lhd_end_section (void);
LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
LANG_HOOKS_DEEP_UNSHARING, \
LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \
+ LANG_HOOKS_EMITS_BEGIN_STMT, \
LANG_HOOKS_RUN_LANG_SELFTESTS, \
LANG_HOOKS_GET_SUBSTRING_LOCATION \
}
@@ -524,6 +524,9 @@ struct lang_hooks
instead of trampolines. */
bool custom_function_descriptors;
+ /* True if this language emits begin stmt notes. */
+ bool emits_begin_stmt;
+
/* Run all lang-specific selftests. */
void (*run_lang_selftests) (void);
@@ -5269,10 +5269,11 @@ inherit_reload_reg (bool def_p, int original_regno,
lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
if (lra_dump_file != NULL)
{
+ basic_block bb = BLOCK_FOR_INSN (usage_insn);
fprintf (lra_dump_file,
" Inheritance reuse change %d->%d (bb%d):\n",
original_regno, REGNO (new_reg),
- BLOCK_FOR_INSN (usage_insn)->index);
+ bb ? bb->index : -1);
dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
}
}
@@ -5816,6 +5817,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
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)
@@ -602,9 +602,9 @@ static struct lra_operand_data debug_operand_data =
};
/* The following data are used as static insn data for all debug
- insns. If structure lra_static_insn_data is changed, the
+ bind insns. If structure lra_static_insn_data is changed, the
initializer should be changed too. */
-static struct lra_static_insn_data debug_insn_static_data =
+static struct lra_static_insn_data debug_bind_static_data =
{
&debug_operand_data,
0, /* Duplication operands #. */
@@ -618,6 +618,22 @@ static struct lra_static_insn_data debug_insn_static_data =
NULL /* Descriptions of operands in alternatives. */
};
+/* The following data are used as static insn data for all debug
+ marker insns. If structure lra_static_insn_data is changed, the
+ initializer should be changed too. */
+static struct lra_static_insn_data debug_marker_static_data =
+ {
+ &debug_operand_data,
+ 0, /* Duplication operands #. */
+ -1, /* Commutative operand #. */
+ 0, /* Operands #. There isn't any operand. */
+ 0, /* Duplications #. */
+ 0, /* Alternatives #. We are not interesting in alternatives
+ because we does not proceed debug_insns for reloads. */
+ NULL, /* Hard registers referenced in machine description. */
+ NULL /* Descriptions of operands in alternatives. */
+ };
+
/* Called once per compiler work to initialize some LRA data related
to insns. */
static void
@@ -951,12 +967,20 @@ lra_set_insn_recog_data (rtx_insn *insn)
data->regs = NULL;
if (DEBUG_INSN_P (insn))
{
- data->insn_static_data = &debug_insn_static_data;
data->dup_loc = NULL;
data->arg_hard_regs = NULL;
data->preferred_alternatives = ALL_ALTERNATIVES;
- data->operand_loc = XNEWVEC (rtx *, 1);
- data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+ if (DEBUG_BIND_INSN_P (insn))
+ {
+ data->insn_static_data = &debug_bind_static_data;
+ data->operand_loc = XNEWVEC (rtx *, 1);
+ data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+ }
+ else if (DEBUG_MARKER_INSN_P (insn))
+ {
+ data->insn_static_data = &debug_marker_static_data;
+ data->operand_loc = NULL;
+ }
return data;
}
if (icode < 0)
@@ -1602,7 +1626,7 @@ lra_update_insn_regno_info (rtx_insn *insn)
return;
data = lra_get_insn_recog_data (insn);
static_data = data->insn_static_data;
- freq = get_insn_freq (insn);
+ freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
invalidate_insn_data_regno_info (data, insn, freq);
uid = INSN_UID (insn);
for (i = static_data->n_operands - 1; i >= 0; i--)
@@ -1119,7 +1119,10 @@ input_function (tree fn_decl, struct data_in *data_in,
Similarly remove all IFN_*SAN_* internal calls */
if (!flag_wpa)
{
- if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+ if (is_gimple_debug (stmt)
+ && (gimple_debug_nonbind_marker_p (stmt)
+ ? !MAY_HAVE_DEBUG_MARKER_STMTS
+ : !MAY_HAVE_DEBUG_BIND_STMTS))
remove = true;
if (is_gimple_call (stmt)
&& gimple_call_internal_p (stmt))
@@ -1173,6 +1176,13 @@ input_function (tree fn_decl, struct data_in *data_in,
{
gsi_next (&bsi);
stmts[gimple_uid (stmt)] = stmt;
+
+ /* Remember that the input function has begin stmt
+ markers, so that we know to expect them when emitting
+ debug info. */
+ if (!cfun->debug_nonbind_markers
+ && gimple_debug_nonbind_marker_p (stmt))
+ cfun->debug_nonbind_markers = true;
}
}
}
@@ -960,6 +960,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
"Max. size of loc list for which reverse ops should be added.",
50, 0, 0)
+/* Set a threshold to discard debug markers (e.g. debug begin stmt
+ markers) when expanding a function to RTL, or inlining it into
+ another function. */
+
+DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
+ "max-debug-marker-count",
+ "Max. count of debug markers to expand or inline.",
+ 100000, 0, 0)
+
/* Set minimum insn uid for non-debug insns. */
DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
fputc ('\t', m_outfile);
break;
+ case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+ {
+ expanded_location xloc
+ = expand_location (NOTE_MARKER_LOCATION (in_rtx));
+ fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+ }
+#endif
+ break;
+
default:
break;
}
@@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
case DEBUG_INSN:
{
+ if (DEBUG_MARKER_INSN_P (x))
+ {
+ switch (INSN_DEBUG_MARKER_KIND (x))
+ {
+ case NOTE_INSN_BEGIN_STMT:
+ pp_string (pp, "debug begin stmt marker");
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ }
+
const char *name = "?";
if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
@@ -2258,6 +2258,7 @@ extract_insn (rtx_insn *insn)
case ADDR_VEC:
case ADDR_DIFF_VEC:
case VAR_LOCATION:
+ case DEBUG_MARKER:
return;
case SET:
@@ -761,6 +761,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
been optimized away completely. */
DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
+/* Used in marker DEBUG_INSNs to avoid being recognized as an insn. */
+DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_OBJ)
+
/* All expressions from this point forward appear only in machine
descriptions. */
#ifdef GENERATOR_FILE
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa.h"
#include "except.h"
#include "debug.h"
+#include "params.h"
#include "value-prof.h"
#include "cfgloop.h"
#include "builtins.h"
@@ -1347,7 +1348,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
gimple_seq stmts = NULL;
if (is_gimple_debug (stmt)
- && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
+ && (gimple_debug_nonbind_marker_p (stmt)
+ ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers
+ : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
return stmts;
/* Begin by recognizing trees that we'll completely rewrite for the
@@ -1630,6 +1633,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
gimple_seq_add_stmt (&stmts, copy);
return stmts;
}
+ if (gimple_debug_nonbind_marker_p (stmt))
+ {
+ /* If the inlined function has too many debug markers,
+ don't copy them. */
+ if (id->src_cfun->debug_marker_count
+ > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+ return stmts;
+
+ gdebug *copy = as_a <gdebug *> (gimple_copy (stmt));
+ id->debug_stmts.safe_push (copy);
+ gimple_seq_add_stmt (&stmts, copy);
+ return stmts;
+ }
+ gcc_checking_assert (!is_gimple_debug (stmt));
/* Create a new deep copy of the statement. */
copy = gimple_copy (stmt);
@@ -1725,7 +1742,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
gimple_set_block (copy, *n);
}
- if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
+ if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)
+ || gimple_debug_nonbind_marker_p (copy))
{
gimple_seq_add_stmt (&stmts, copy);
return stmts;
@@ -2599,6 +2617,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
value = gimple_debug_source_bind_get_value (stmt);
new_stmt = gimple_build_debug_source_bind (var, value, stmt);
}
+ else if (gimple_debug_nonbind_marker_p (stmt))
+ new_stmt = as_a <gdebug *> (gimple_copy (stmt));
else
gcc_unreachable ();
gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2915,6 +2935,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
gimple_set_block (stmt, n ? *n : id->block);
}
+ if (gimple_debug_nonbind_marker_p (stmt))
+ return;
+
/* Remap all the operands in COPY. */
memset (&wi, 0, sizeof (wi));
wi.info = id;
@@ -2923,8 +2946,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
if (gimple_debug_source_bind_p (stmt))
t = gimple_debug_source_bind_get_var (stmt);
- else
+ else if (gimple_debug_bind_p (stmt))
t = gimple_debug_bind_get_var (stmt);
+ else
+ gcc_unreachable ();
if (TREE_CODE (t) == PARM_DECL && id->debug_map
&& (n = id->debug_map->get (t)))
@@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)
void
append_to_statement_list (tree t, tree *list_p)
{
- if (t && TREE_SIDE_EFFECTS (t))
+ if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
append_to_statement_list_1 (t, list_p);
}
@@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
tail = head;
}
- TREE_SIDE_EFFECTS (i->container) = 1;
+ if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (i->container) = 1;
cur = i->ptr;
@@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
tail = head;
}
- TREE_SIDE_EFFECTS (i->container) = 1;
+ if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (i->container) = 1;
cur = i->ptr;
@@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)
i->ptr = next;
}
-/* Return the first expression in a sequence of COMPOUND_EXPRs,
- or in a STATEMENT_LIST. */
+/* Return the first expression in a sequence of COMPOUND_EXPRs, or in
+ a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+ STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT. */
tree
expr_first (tree expr)
@@ -291,7 +294,20 @@ expr_first (tree expr)
if (TREE_CODE (expr) == STATEMENT_LIST)
{
struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
- return n ? n->stmt : NULL_TREE;
+ if (!n)
+ return NULL_TREE;
+ while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+ {
+ n = n->next;
+ if (!n)
+ return NULL_TREE;
+ }
+ /* If the first non-debug stmt is not a statement list, we
+ already know it's what we're looking for. */
+ if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+ return n->stmt;
+
+ return expr_first (n->stmt);
}
while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -300,8 +316,9 @@ expr_first (tree expr)
return expr;
}
-/* Return the last expression in a sequence of COMPOUND_EXPRs,
- or in a STATEMENT_LIST. */
+/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
+ STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+ STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT. */
tree
expr_last (tree expr)
@@ -312,7 +329,20 @@ expr_last (tree expr)
if (TREE_CODE (expr) == STATEMENT_LIST)
{
struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
- return n ? n->stmt : NULL_TREE;
+ if (!n)
+ return NULL_TREE;
+ while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+ {
+ n = n->prev;
+ if (!n)
+ return NULL_TREE;
+ }
+ /* If the last non-debug stmt is not a statement list, we
+ already know it's what we're looking for. */
+ if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+ return n->stmt;
+
+ return expr_last (n->stmt);
}
while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -3291,6 +3291,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
pp_string (pp, "_Cilk_sync");
break;
+ case DEBUG_BEGIN_STMT:
+ pp_string (pp, "# DEBUG BEGIN STMT");
+ break;
+
default:
NIY;
}
@@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
gimple *stmt = gsi_stmt (si);
if (!is_gimple_debug (stmt))
break;
+ if (gimple_debug_nonbind_marker_p (stmt))
+ continue;
i++;
}
@@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
var = gimple_debug_bind_get_var (stmt);
else if (gimple_debug_source_bind_p (stmt))
var = gimple_debug_source_bind_get_var (stmt);
+ else if (gimple_debug_nonbind_marker_p (stmt))
+ continue;
else
gcc_unreachable ();
@@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
var = gimple_debug_bind_get_var (stmt);
else if (gimple_debug_source_bind_p (stmt))
var = gimple_debug_source_bind_get_var (stmt);
+ else if (gimple_debug_nonbind_marker_p (stmt))
+ continue;
else
gcc_unreachable ();
- /* Discard debug bind overlaps. ??? Unlike stmts from src,
+ /* Discard debug bind overlaps. Unlike stmts from src,
copied into a new block that will precede BB, debug bind
stmts in bypassed BBs may actually be discarded if
- they're overwritten by subsequent debug bind stmts, which
- might be a problem once we introduce stmt frontier notes
- or somesuch. Adding `&& bb == src' to the condition
- below will preserve all potentially relevant debug
- notes. */
+ they're overwritten by subsequent debug bind stmts. We
+ want to copy binds for all modified variables, so that we
+ retain a bind to the shared def if there is one, or to a
+ newly introduced PHI node if there is one. Our bind will
+ end up reset if the value is dead, but that implies the
+ variable couldn't have survived, so it's fine. We are
+ not actually running the code that performed the binds at
+ this point, we're just adding binds so that they survive
+ the new confluence, so markers should not be copied. */
if (vars && vars->add (var))
continue;
else if (!vars)
@@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
break;
if (i >= 0)
continue;
-
- if (fewvars.length () < (unsigned) alloc_count)
+ else if (fewvars.length () < (unsigned) alloc_count)
fewvars.quick_push (var);
else
{
@@ -1013,7 +1013,8 @@ make_node (enum tree_code code MEM_STAT_DECL)
switch (type)
{
case tcc_statement:
- TREE_SIDE_EFFECTS (t) = 1;
+ if (code != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (t) = 1;
break;
case tcc_declaration:
@@ -4405,7 +4406,10 @@ build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)
}
if (TREE_CODE_CLASS (code) == tcc_statement)
- TREE_SIDE_EFFECTS (t) = 1;
+ {
+ if (code != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (t) = 1;
+ }
else switch (code)
{
case VA_ARG_EXPR:
@@ -382,6 +382,9 @@ DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
DEBUG stmts. */
DEFTREECODE (DEBUG_EXPR_DECL, "debug_expr_decl", tcc_declaration, 0)
+/* A stmt that marks the beginning of a source statement. */
+DEFTREECODE (DEBUG_BEGIN_STMT, "debug_begin_stmt", tcc_statement, 0)
+
/* A namespace declaration. Namespaces appear in DECL_CONTEXT of other
_DECLs, providing a hierarchy of names. */
DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
@@ -1225,7 +1225,7 @@ extern void protected_set_expr_location (tree, location_t);
/* GOTO_EXPR accessor. This gives access to the label associated with
a goto statement. */
-#define GOTO_DESTINATION(NODE) TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE) TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
/* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
@@ -9918,6 +9918,36 @@ vt_init_cfa_base (void)
cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
}
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note. */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
+{
+ gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
+
+ enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
+
+ switch (kind)
+ {
+ case NOTE_INSN_BEGIN_STMT:
+ {
+ rtx_insn *note = NULL;
+ if (cfun->debug_nonbind_markers)
+ {
+ 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;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Allocate and initialize the data structures for variable tracking
and parse the RTL to get the micro operations. */
@@ -10161,6 +10191,12 @@ vt_initialize (void)
cselib_hook_called = false;
adjust_insn (bb, insn);
+ if (DEBUG_MARKER_INSN_P (insn))
+ {
+ insn = reemit_marker_as_note (insn, &save_bb);
+ continue;
+ }
+
if (MAY_HAVE_DEBUG_BIND_INSNS)
{
if (CALL_P (insn))
@@ -10237,10 +10273,11 @@ vt_initialize (void)
static int debug_label_num = 1;
-/* Get rid of all debug insns from the insn stream. */
+/* Remove from the insn stream all debug insns used for variable
+ tracking at assignments. */
static void
-delete_debug_insns (void)
+delete_vta_debug_insns (void)
{
basic_block bb;
rtx_insn *insn, *next;
@@ -10256,6 +10293,12 @@ delete_debug_insns (void)
insn = next)
if (DEBUG_INSN_P (insn))
{
+ if (DEBUG_MARKER_INSN_P (insn))
+ {
+ insn = reemit_marker_as_note (insn, NULL);
+ continue;
+ }
+
tree decl = INSN_VAR_LOCATION_DECL (insn);
if (TREE_CODE (decl) == LABEL_DECL
&& DECL_NAME (decl)
@@ -10281,10 +10324,13 @@ delete_debug_insns (void)
handled as well.. */
static void
-vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
+vt_debug_insns_local (bool skipped)
{
- /* ??? Just skip it all for now. */
- delete_debug_insns ();
+ /* ??? Just skip it all for now. If we skipped the global pass,
+ arrange for stmt markers to be dropped as well. */
+ if (skipped)
+ cfun->debug_nonbind_markers = 0;
+ delete_vta_debug_insns ();
}
/* Free the data structures needed for variable tracking. */
@@ -10349,15 +10395,21 @@ variable_tracking_main_1 (void)
{
bool success;
- if (flag_var_tracking_assignments < 0
+ /* We won't be called as a separate pass if flag_var_tracking is not
+ set, but final may call us to turn debug markers into notes. */
+ if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
+ || flag_var_tracking_assignments < 0
/* Var-tracking right now assumes the IR doesn't contain
any pseudos at this point. */
|| targetm.no_register_allocation)
{
- delete_debug_insns ();
+ delete_vta_debug_insns ();
return 0;
}
+ if (!flag_var_tracking)
+ return 0;
+
if (n_basic_blocks_for_fn (cfun) > 500 &&
n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
{
@@ -10379,7 +10431,9 @@ variable_tracking_main_1 (void)
{
vt_finalize ();
- delete_debug_insns ();
+ cfun->debug_nonbind_markers = 0;
+
+ delete_vta_debug_insns ();
/* This is later restored by our caller. */
flag_var_tracking_assignments = 0;