aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog99
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c-family/c-semantics.c21
-rw-r--r--gcc/c/ChangeLog9
-rw-r--r--gcc/c/c-objc-common.h2
-rw-r--r--gcc/c/c-parser.c20
-rw-r--r--gcc/c/c-typeck.c8
-rw-r--r--gcc/cfgexpand.c113
-rw-r--r--gcc/cp/ChangeLog17
-rw-r--r--gcc/cp/constexpr.c16
-rw-r--r--gcc/cp/cp-objcp-common.h2
-rw-r--r--gcc/cp/parser.c14
-rw-r--r--gcc/cp/pt.c6
-rw-r--r--gcc/cse.c7
-rw-r--r--gcc/df-scan.c2
-rw-r--r--gcc/doc/generic.texi5
-rw-r--r--gcc/doc/gimple.texi24
-rw-r--r--gcc/doc/invoke.texi7
-rw-r--r--gcc/doc/rtl.texi53
-rw-r--r--gcc/final.c89
-rw-r--r--gcc/function.c6
-rw-r--r--gcc/function.h10
-rw-r--r--gcc/gimple-iterator.c4
-rw-r--r--gcc/gimple-low.c29
-rw-r--r--gcc/gimple-pretty-print.c7
-rw-r--r--gcc/gimple.c24
-rw-r--r--gcc/gimple.h1
-rw-r--r--gcc/gimplify.c158
-rw-r--r--gcc/langhooks-def.h2
-rw-r--r--gcc/langhooks.h3
-rw-r--r--gcc/lra-constraints.c10
-rw-r--r--gcc/lra.c36
-rw-r--r--gcc/lto-streamer-in.c12
-rw-r--r--gcc/params.def9
-rw-r--r--gcc/print-rtl.c24
-rw-r--r--gcc/recog.c1
-rw-r--r--gcc/rtl.def3
-rw-r--r--gcc/tree-inline.c31
-rw-r--r--gcc/tree-iterator.c48
-rw-r--r--gcc/tree-pretty-print.c4
-rw-r--r--gcc/tree-ssa-threadedge.c25
-rw-r--r--gcc/tree.c8
-rw-r--r--gcc/tree.def3
-rw-r--r--gcc/tree.h2
-rw-r--r--gcc/var-tracking.c70
45 files changed, 895 insertions, 154 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3c1add6..01bd2b9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,104 @@
2017-12-12 Alexandre Oliva <aoliva@redhat.com>
+ * cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
+ markers. Integrate source bind into debug stmt expand loop.
+ (pass_expand::execute): Check debug marker limit. Avoid deep
+ TER and expand debug locations for debug bind insns only.
+ * cse.c (insn_live_p): Keep nonbind markers and debug bindings
+ followed by them.
+ * df-scan.c (df_insn_delete): Accept out-of-block debug insn.
+ * final.c (reemit_insn_block_notes): Take current block from
+ nonbind markers. Declare note where it's first set.
+ (final_scan_insn): Handle begin stmt notes. Emit is_stmt according to
+ begin stmt markers if enabled.
+ (notice_source_line): Handle nonbind markers. Fail if their
+ location is unknown or that of builtins.
+ (rest_of_handle_final): Convert begin stmt markers to notes if
+ var-tracking didn't run.
+ (rest_of_clean_state): Skip begin stmt markers.
+ * gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
+ markers.
+ * function.c (allocate_struct_function): Set begin_stmt_markers.
+ * function.h (struct function): Add debug_marker_count counter
+ and debug_nonbind_markers flag.
+ * gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
+ * gimple-low.c (lower_function_body): Adjust
+ debug_nonbind_markers.
+ (lower_stmt): Drop or skip gimple debug stmts.
+ (lower_try_catch): Skip debug stmts.
+ * gimple.c (gimple_build_debug_begin_stmt): New.
+ (gimple_copy): Increment debug_marker_count if copying one.
+ * gimple.h (gimple_build_debug_begin_stmt): Declare.
+ * gimplify.c (rexpr_location): New.
+ (rexpr_has_location): New.
+ (warn_switch_unreachable_r): Handle gimple debug stmts.
+ (shortcut_cond_r): Call expr_location.
+ (find_goto): New.
+ (find_goto_label): New.
+ (shortcut_cond_expr): Call expr_has_location, expr_location, and
+ find_goto_label.
+ (gimplify_cond_expr): Call find_goto_label, expr_has_location, and
+ expr_location.
+ (gimplify_expr): Handle begin stmt markers. Reject debug expr decls.
+ * langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New. Add to...
+ (LANG_HOOKS_INITIALIZER): ... this.
+ * langhooks.h (struct lang_hooks): Add emits_begin_stmt.
+ * lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
+ debug insns.
+ (update_ebb_live_info): Skip debug insn markers.
+ * lra.c (debug_insn_static_data): Rename to...
+ (debug_bind_static_data): ... this.
+ (debug_marker_static_data): New.
+ (lra_set_insn_recog_data): Select one of the above depending
+ on debug insn kind.
+ (lra_update_isn_regno_info): Don't assume debug insns have
+ freqs.
+ (push_insns): Skip debug insns.
+ * lto-streamer-in.c (input_function): Drop debug stmts
+ depending on active options. Adjust debug_nonbind_markers.
+ * params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
+ * print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
+ begin stmt marker notes.
+ (print_insn): Likewise.
+ * recog.c (extract_insn): Recognize rtl for debug markers.
+ * rtl.def (DEBUG_MARKER): New.
+ * tree-inline.c: Include params.h.
+ (remap_gimple_stmt): Handle nonbind markers.
+ (maybe_move_debug_stmts_to_successors): Likewise.
+ (copy_debug_stmt): Likewise.
+ * tree-iterator.c (append_to_statement_list_1): Append begin stmt
+ markers regardless of no side effects.
+ (tsi_link_before): Don't update container's side effects when adding
+ a begin stmt marker.
+ (tsi_link_after): Likewise.
+ (expr_first): Skip begin stmt markers.
+ (expr_last): Likewise.
+ * tree-pretty-print (dump_generic_node): Handle begin stmt markers.
+ * tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
+ Disregard nonbind markers.
+ * tree.c (make_node_stat): Don't set side effects for begin stmt
+ markers.
+ (build1_stat): Likewise.
+ * tree.def (DEBUG_BEGIN_STMT): New.
+ * tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
+ * var-tracking.c (delete_debug_insns): Renamed to...
+ (delete_vta_debug_insns): ... this.
+ (reemit_marker_as_note): New.
+ (vt_initialize): Reemit markers.
+ (delete_vta_debug_insns): Likewise.
+ (vt_debug_insns_local): Reemit or delete markers.
+ (variable_tracking_main_1): Likewise.
+ * doc/generic.texi (DEBUG_BEGIN_STMT): Document.
+ * doc/gimple.texi (gimple_debug_begin_stmt_p): New.
+ (gimple_debug_nonbind_marker_p): New.
+ (gimple_build_debug_bind): Adjust.
+ (gimple_build_debug_begin_stmt): New.
+ * doc/invoke.texi (max-debug-marker-count): New param.
+ * doc/rtl.texi (debug_implicit_ptr, entry_value): New.
+ (debug_parameter_ref, debug_marker): New.
+ (NOTE_INSN_BEGIN_STMT): New.
+ (DEBUG_INSN): Describe begin stmt markers.
+
* cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
without debug insns, we wouldn't, but clean up debug insns
after a control flow insn nevertheless.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 4ad83f3..6c31dbe 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,8 @@
+2017-12-12 Alexandre Oliva <aoliva@redhat.com>
+
+ * c-semantics.c (pop_stmt_list): Move begin stmt marker into
+ subsequent statement list.
+
2017-12-07 Martin Sebor <msebor@redhat.com>
PR c/81544
diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 3ceb714..cd872d8 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -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;
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 14d7f63..f981266 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,12 @@
+2017-12-12 Alexandre Oliva <aoliva@redhat.com>
+
+ * c-objc-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
+ * c-parser.c (add_debug_begin_stmt): New.
+ (c_parser_declaration_or_fndef): Call it.
+ (c_parser_compound_statement_nostart): Likewise.
+ (c_parser_statement_after_labels): Likewise.
+ * c-typeck (c_finish_stmt_expr): Skip begin stmts markers.
+
2017-12-07 Joseph Myers <joseph@codesourcery.com>
* c-decl.c (build_compound_literal): Add parameter alignas_align
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index bee06e9..27ceabc 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -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
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index d398548..f1bae8a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1649,6 +1649,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
@@ -1749,6 +1762,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))
{
@@ -4911,6 +4926,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;
}
@@ -5365,6 +5381,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:
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 676dbbd..13b2684 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10710,6 +10710,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;
}
@@ -10729,7 +10733,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
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 3ee242df..ce98264 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5657,39 +5657,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_BEGIN_STMT_PAT ();
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);
@@ -5697,9 +5726,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:
@@ -5715,42 +5749,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);
@@ -6383,6 +6387,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)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e492f0a..4f1be5b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,20 @@
+2017-12-12 Alexandre Oliva <aoliva@redhat.com>
+
+ * constexpr.c (check_constexpr_ctor_body_1): Skip begin stmt
+ markers.
+ (constexpr_fn_retval): Likewise.
+ (potential_constant_expression_1): Likewise.
+ (cxx_eval_statement_list): Check that a begin stmt marker is
+ not used as the value of a statement list.
+ (cxx_eval_constant_expression): Return begin stmt markers
+ unchanged.
+ * cp-array-notation.c (stmt_location): New.
+ (cp_expand_cond_array_notations): Use it.
+ * cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
+ * parser.c (add_debug_begin_stmt): New.
+ (cp_parser_statement): Call it.
+ * pt.c (tsubst_copy): Handle begin stmt markers.
+
2017-12-07 Martin Sebor <msebor@redhat.com>
PR c/81544
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 6dfecfc..0455be1 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -455,6 +455,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
case USING_STMT:
case STATIC_ASSERT:
+ case DEBUG_BEGIN_STMT:
return true;
default:
@@ -694,6 +695,7 @@ constexpr_fn_retval (tree body)
return constexpr_fn_retval (BIND_EXPR_BODY (body));
case USING_STMT:
+ case DEBUG_BEGIN_STMT:
return NULL_TREE;
case CALL_EXPR:
@@ -3856,6 +3858,14 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
if (returns (jump_target) || breaks (jump_target))
break;
}
+ /* Make sure we don't use the "result" of a debug-only marker. That
+ would be wrong. We should be using the result of the previous
+ statement, or NULL if there isn't one. In practice, this should
+ never happen: the statement after the marker should override the
+ result of the marker, so its value shouldn't survive in R. Now,
+ should that ever change, we'll need some fixing here to stop
+ markers from modifying the generated executable code. */
+ gcc_checking_assert (!r || TREE_CODE (r) != DEBUG_BEGIN_STMT);
return r;
}
@@ -4081,6 +4091,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
}
break;
+ case DEBUG_BEGIN_STMT:
+ /* ??? It might be nice to retain this information somehow, so
+ as to be able to step into a constexpr function call. */
+ /* Fall through. */
+
case FUNCTION_DECL:
case TEMPLATE_DECL:
case LABEL_DECL:
@@ -5187,6 +5202,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case CONTINUE_STMT:
case REQUIRES_EXPR:
case STATIC_ASSERT:
+ case DEBUG_BEGIN_STMT:
return true;
case PARM_DECL:
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index a1b1fcd..8d3bc87 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -107,6 +107,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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 891f742..94e87c2 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10684,6 +10684,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:
@@ -10759,6 +10772,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)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 252712e..0cf6509 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15305,6 +15305,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)
diff --git a/gcc/cse.c b/gcc/cse.c
index e449223..c0db32b 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -6962,11 +6962,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;
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 8ab3d71..429dab8 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -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 ();
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 75c448e..b01cdaa 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -2006,6 +2006,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
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index fa98800..4926787 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -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
@@ -1530,10 +1540,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
@@ -1604,6 +1615,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}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1413095..189b3e4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10609,6 +10609,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
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index a58eedc..dd3c0d3 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3448,6 +3448,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
@@ -3724,6 +3743,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.
@@ -3741,15 +3766,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
diff --git a/gcc/final.c b/gcc/final.c
index afb6906..3bcb9c5 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1652,7 +1652,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))
@@ -1660,17 +1659,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;
@@ -1691,6 +1702,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)
@@ -1707,7 +1719,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);
@@ -2413,6 +2425,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;
@@ -2499,7 +2522,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;
@@ -2602,7 +2633,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);
@@ -3095,7 +3126,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;
@@ -3128,7 +3174,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;
@@ -3140,7 +3187,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;
}
@@ -4493,6 +4541,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);
@@ -4680,6 +4732,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
diff --git a/gcc/function.c b/gcc/function.c
index 88f93db..cdb2fc8 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4939,6 +4939,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
diff --git a/gcc/function.h b/gcc/function.h
index 971ab66..b94abb6 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -281,6 +281,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;
@@ -381,6 +387,10 @@ struct GTY(()) function {
/* Nonzero if the current function contains a #pragma GCC unroll. */
unsigned int has_unroll : 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. */
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 1e87825..46d3c6a 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -568,6 +568,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);
}
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 22db61b..95f3f45 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -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
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index e952f33..aee2ad8 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1363,6 +1363,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 ();
}
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c986a73..5a118e9 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -853,6 +853,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.
@@ -1915,6 +1936,9 @@ gimple_copy (gimple *stmt)
gimple_set_modified (copy, true);
}
+ if (gimple_debug_nonbind_marker_p (stmt))
+ cfun->debug_marker_count++;
+
return copy;
}
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 26fed1d..7c36679 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1453,6 +1453,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);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 6a15daf4..8e1d400 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -983,6 +983,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
@@ -1764,6 +1806,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))
{
@@ -3466,7 +3515,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);
@@ -3489,7 +3538,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);
@@ -3511,7 +3560,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),
@@ -3535,6 +3584,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. */
@@ -3565,8 +3653,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);
@@ -3587,8 +3675,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);
@@ -3615,20 +3703,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;
}
@@ -3692,8 +3776,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)
@@ -3988,39 +4072,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);
@@ -11809,6 +11889,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;
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 44e7edf..9362d96 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -132,6 +132,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
@@ -346,6 +347,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 \
}
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index afc879f..dddb027 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -532,6 +532,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);
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index a6600ef..4adf4bf 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -5265,10 +5265,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));
}
}
@@ -5807,6 +5808,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)
diff --git a/gcc/lra.c b/gcc/lra.c
index f790904..943d1ca 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -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
@@ -947,12 +963,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)
@@ -1597,7 +1621,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);
for (i = static_data->n_operands - 1; i >= 0; i--)
add_regs_to_insn_regno_info (data, *data->operand_loc[i], insn,
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 3db1d38..9b785ff 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1128,7 +1128,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))
@@ -1182,6 +1185,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;
}
}
}
diff --git a/gcc/params.def b/gcc/params.def
index 923ebc8..9d7f34f 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -976,6 +976,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,
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 5fe2380..0af739d 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -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;
}
@@ -1808,6 +1818,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 = "?";
char idbuf[32];
diff --git a/gcc/recog.c b/gcc/recog.c
index cdcff8f..3da6e5b 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -2252,6 +2252,7 @@ extract_insn (rtx_insn *insn)
case ADDR_VEC:
case ADDR_DIFF_VEC:
case VAR_LOCATION:
+ case DEBUG_MARKER:
return;
case SET:
diff --git a/gcc/rtl.def b/gcc/rtl.def
index ee7b7e1..0000808 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -766,6 +766,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_EXTRA)
+
/* All expressions from this point forward appear only in machine
descriptions. */
#ifdef GENERATOR_FILE
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index e6e3f12..8604ba1 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -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"
@@ -1355,7 +1356,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
@@ -1638,6 +1641,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);
@@ -1733,7 +1750,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;
@@ -2555,6 +2573,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);
@@ -2825,6 +2845,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;
@@ -2833,8 +2856,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)))
diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
index c485413..10e510d 100644
--- a/gcc/tree-iterator.c
+++ b/gcc/tree-iterator.c
@@ -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)
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index bf872b8..6519f3e 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3230,6 +3230,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
dump_block_node (pp, node, spc, flags);
break;
+ case DEBUG_BEGIN_STMT:
+ pp_string (pp, "# DEBUG BEGIN STMT");
+ break;
+
default:
NIY;
}
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 70675e4..91793bf 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -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
{
diff --git a/gcc/tree.c b/gcc/tree.c
index 053670c..ed1852b 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1040,7 +1040,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:
@@ -4397,7 +4398,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:
diff --git a/gcc/tree.def b/gcc/tree.def
index edcb7ef..137e63f 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -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)
diff --git a/gcc/tree.h b/gcc/tree.h
index 49cbb99..892a8ba 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1223,7 +1223,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
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index b324a2c..8e500b1 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9926,6 +9926,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. */
@@ -10169,6 +10199,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))
@@ -10245,10 +10281,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;
@@ -10264,6 +10301,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)
@@ -10289,10 +10332,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. */
@@ -10357,15 +10403,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)
{
@@ -10387,7 +10439,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;