From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 77631 invoked by alias); 9 Oct 2017 13:11:24 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 77620 invoked by uid 89); 9 Oct 2017 13:11:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.1 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,RCVD_IN_SORBS_SPAM,SPF_PASS autolearn=ham version=3.3.2 spammy=niy, dsi, survive, 2nd X-HELO: mail-wm0-f49.google.com Received: from mail-wm0-f49.google.com (HELO mail-wm0-f49.google.com) (74.125.82.49) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 09 Oct 2017 13:11:14 +0000 Received: by mail-wm0-f49.google.com with SMTP id m72so11508734wmc.0 for ; Mon, 09 Oct 2017 06:11:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=RNSP2Bjryhd+d+2XEbDdz5rFfeJsxOVwi0ScIn8C/94=; b=HFs1ayNOuEpgahpsGD8VYE+wtkfqSVQV8IdpHEkjjeWDHYl0D+askG9wqvI+jTCgCN 3E4jCPSEXu5vMWcZyORG295PrHl+NHi/1xqFxEqqJ9NoCNzWIDS3dQjXFULJom0O9L+W Nuqh5Z+3KfvhVLuBI8VC8sJ45RM8eceNtAv3wmYrBhjzurpQk2pcPIBBscp6vzGiJqS2 bucF5iWSxn6yrgEPrHF1lreRC4GloeLcHinBmTN0fNR6ORawwzrJwCrEfV1BszbLPYNB hLN/kxF/tdJegUEO+ji2IZCunLP8NLlNxNb6Era+9tpXgPIwkrEmZt19DA6mDDqff+aB UNfA== X-Gm-Message-State: AMCzsaU43wVU6GjcoJQgxpRTgUNAluUUSQjwjGoXGNcQyn+k/9gI/74j Xz2cJHVZHcnq1EF1IoPtcZOdoNlaCC+sMWm+ikg75g== X-Google-Smtp-Source: AOwi7QB36Sf0L1uIDeCBUAvJwAGc/tD0EzqhyWqmEsrpS8CmriC4h2dSyr2oyG+nlgYqcMTvCBFoooVKpapqS6VlouA= X-Received: by 10.80.208.222 with SMTP id g30mr12623468edf.246.1507554668510; Mon, 09 Oct 2017 06:11:08 -0700 (PDT) MIME-Version: 1.0 Received: by 10.80.143.34 with HTTP; Mon, 9 Oct 2017 06:11:07 -0700 (PDT) In-Reply-To: <20170930090827.6604-4-aoliva@redhat.com> References: <20170930090827.6604-4-aoliva@redhat.com> From: Richard Biener Date: Mon, 09 Oct 2017 13:11:00 -0000 Message-ID: Subject: Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled To: Alexandre Oliva Cc: GCC Patches Content-Type: text/plain; charset="UTF-8" X-IsSubscribed: yes X-SW-Source: 2017-10/txt/msg00479.txt.bz2 On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva wrote: > This patch completes the infrastructure for the introduction of > statement frontiers in C-family languages. > > It brings in all the code remaining code needed to introduce and > transform begin stmt trees, gimple stmts, insns and notes, and > ultimately use them to generate the is_stmt column in DWARF2+ line > number tables/programs, however none of it is activated: the option > that would do so will be introduced in a subsequent patch. > > This patch depends on an earlier patch with not-quite-boilerplate > changes towards SFN. The middle-end changes are ok. The C FE change looks reasonable, I'd appreciate a 2nd look at the C++ FE changes by a maintainer. Thanks, Richard. > for gcc/c-family/ChangeLog > > * c-semantics.c (pop_stmt_list): Move begin stmt marker into > subsequent statement list. > > for gcc/c/ChangeLog > > * 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. > > for gcc/cp/ChangeLog > > * constexpr.c (build_data_member_initialization): Skip begin stmt > markers. > (check_constexpr_ctor_body_1): Likewise. > (build_constexpr_constructor_member_initializers): Likewise. > (constexpr_fn_retval): Likewise. > (cxx_eval_statement_list): Likewise. > (potential_constant_expression_1): Likewise. > * 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. > > for gcc/ChangeLog > > * 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. > --- > gcc/c-family/c-semantics.c | 21 ++++++ > gcc/c/c-objc-common.h | 2 + > gcc/c/c-parser.c | 20 ++++++ > gcc/c/c-typeck.c | 8 ++- > gcc/cfgexpand.c | 113 +++++++++++++++++--------------- > gcc/cp/constexpr.c | 11 ++++ > gcc/cp/cp-array-notation.c | 37 +++++++++-- > gcc/cp/cp-objcp-common.h | 2 + > gcc/cp/parser.c | 14 ++++ > gcc/cp/pt.c | 6 ++ > gcc/cse.c | 7 ++ > gcc/df-scan.c | 2 +- > gcc/doc/generic.texi | 5 ++ > gcc/doc/gimple.texi | 24 ++++++- > gcc/doc/invoke.texi | 7 ++ > gcc/doc/rtl.texi | 53 ++++++++++++--- > gcc/final.c | 89 +++++++++++++++++++------ > gcc/function.c | 6 ++ > gcc/function.h | 10 +++ > gcc/gimple-iterator.c | 4 ++ > gcc/gimple-low.c | 29 +++++++++ > gcc/gimple-pretty-print.c | 7 ++ > gcc/gimple.c | 24 +++++++ > gcc/gimple.h | 1 + > gcc/gimplify.c | 158 +++++++++++++++++++++++++++++++++++---------- > gcc/langhooks-def.h | 2 + > gcc/langhooks.h | 3 + > gcc/lra-constraints.c | 10 ++- > gcc/lra.c | 36 +++++++++-- > gcc/lto-streamer-in.c | 12 +++- > gcc/params.def | 9 +++ > gcc/print-rtl.c | 24 +++++++ > gcc/recog.c | 1 + > gcc/rtl.def | 3 + > gcc/tree-inline.c | 31 ++++++++- > gcc/tree-iterator.c | 48 +++++++++++--- > gcc/tree-pretty-print.c | 4 ++ > gcc/tree-ssa-threadedge.c | 25 ++++--- > gcc/tree.c | 8 ++- > gcc/tree.def | 3 + > gcc/tree.h | 2 +- > gcc/var-tracking.c | 70 +++++++++++++++++--- > 42 files changed, 793 insertions(+), 158 deletions(-) > > 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/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 a36397b..aa70c91 100644 > --- a/gcc/c/c-parser.c > +++ b/gcc/c/c-parser.c > @@ -1640,6 +1640,19 @@ c_parser_external_declaration (c_parser *parser) > static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec); > 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: > diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c > index 73e7460..33bd4b8 100644 > --- a/gcc/c/c-typeck.c > +++ b/gcc/c/c-typeck.c > @@ -10740,6 +10740,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; > } > @@ -10759,7 +10763,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 5a46b5e..c854ffd 100644 > --- a/gcc/cfgexpand.c > +++ b/gcc/cfgexpand.c > @@ -5635,39 +5635,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); > > @@ -5675,9 +5704,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: > @@ -5693,42 +5727,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 (stmt); > @@ -6367,6 +6371,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; > FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun), > next_bb) > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c > index a89ee49..f9209ac 100644 > --- a/gcc/cp/constexpr.c > +++ b/gcc/cp/constexpr.c > @@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec **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: > @@ -3783,6 +3791,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); > @@ -5119,6 +5129,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-array-notation.c b/gcc/cp/cp-array-notation.c > index 31be7d6..17f0b35c 100644 > --- a/gcc/cp/cp-array-notation.c > +++ b/gcc/cp/cp-array-notation.c > @@ -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; > } > diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h > index 3e4cc9c5..c1c82b6 100644 > --- a/gcc/cp/cp-objcp-common.h > +++ b/gcc/cp/cp-objcp-common.h > @@ -105,6 +105,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 6e817cb..1b31182 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -10661,6 +10661,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: > @@ -10736,6 +10749,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 c29c779..4714b53 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -15289,6 +15289,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 d1577a6..bb9b317 100644 > --- a/gcc/cse.c > +++ b/gcc/cse.c > @@ -6967,11 +6967,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 a51cfd6e..a13bce9 100644 > --- a/gcc/doc/generic.texi > +++ b/gcc/doc/generic.texi > @@ -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 > > > diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi > index 635abd39..6c9c4789 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 > @@ -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} > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index f862b7f..108d730 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -10480,6 +10480,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 3b2b247..888ab02 100644 > --- a/gcc/doc/rtl.texi > +++ b/gcc/doc/rtl.texi > @@ -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 > diff --git a/gcc/final.c b/gcc/final.c > index eff2ee6..49cfbfb 100644 > --- a/gcc/final.c > +++ b/gcc/final.c > @@ -1646,7 +1646,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)) > @@ -1654,17 +1653,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; > @@ -1685,6 +1696,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) > @@ -1701,7 +1713,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); > > @@ -2404,6 +2416,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; > @@ -2490,7 +2513,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; > @@ -2593,7 +2624,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); > @@ -3086,7 +3117,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; > @@ -3119,7 +3165,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; > @@ -3131,7 +3178,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; > } > > @@ -4483,6 +4531,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); > @@ -4670,6 +4722,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 ae61d3d..468dc9a 100644 > --- a/gcc/function.c > +++ b/gcc/function.c > @@ -4933,6 +4933,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 76434cd..1186116 100644 > --- a/gcc/function.h > +++ b/gcc/function.h > @@ -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. */ > diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c > index fb75f99..2359760 100644 > --- a/gcc/gimple-iterator.c > +++ b/gcc/gimple-iterator.c > @@ -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); > } > 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 ed8e51c..2702854 100644 > --- a/gcc/gimple-pretty-print.c > +++ b/gcc/gimple-pretty-print.c > @@ -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 (); > } > diff --git a/gcc/gimple.c b/gcc/gimple.c > index c4e6f81..dc9aa79 100644 > --- a/gcc/gimple.c > +++ b/gcc/gimple.c > @@ -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 ( > + 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; > } > > diff --git a/gcc/gimple.h b/gcc/gimple.h > index 8f289ac..68cd34f 100644 > --- a/gcc/gimple.h > +++ b/gcc/gimple.h > @@ -1454,6 +1454,7 @@ gswitch *gimple_build_switch (tree, tree, vec ); > 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 e9dffc3..6c80a81 100644 > --- a/gcc/gimplify.c > +++ b/gcc/gimplify.c > @@ -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)) > { > @@ -3441,7 +3490,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); > @@ -3464,7 +3513,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); > @@ -3486,7 +3535,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), > @@ -3510,6 +3559,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. */ > @@ -3540,8 +3628,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); > @@ -3562,8 +3650,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); > @@ -3590,20 +3678,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; > } > @@ -3667,8 +3751,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) > @@ -3961,39 +4045,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); > @@ -11789,6 +11869,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 61b081b..a3f02b2 100644 > --- a/gcc/langhooks-def.h > +++ b/gcc/langhooks-def.h > @@ -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 > > @@ -343,6 +344,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 b0c9829..3493ff3 100644 > --- a/gcc/langhooks.h > +++ b/gcc/langhooks.h > @@ -528,6 +528,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 4734c072..47527b0 100644 > --- a/gcc/lra-constraints.c > +++ b/gcc/lra-constraints.c > @@ -5253,10 +5253,11 @@ inherit_reload_reg (bool def_p, int original_regno, > lra_update_insn_regno_info (as_a (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 (usage_insn)); > } > } > @@ -5796,6 +5797,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 9037495..ac99d5e 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 > @@ -949,12 +965,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) > @@ -1600,7 +1624,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--) > diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c > index 51d9a7b..37fa14e 100644 > --- a/gcc/lto-streamer-in.c > +++ b/gcc/lto-streamer-in.c > @@ -1130,7 +1130,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)) > @@ -1184,6 +1187,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 136f927..9f63e63 100644 > --- a/gcc/params.def > +++ b/gcc/params.def > @@ -963,6 +963,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 79ec463..0d36a42 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; > } > @@ -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))) > diff --git a/gcc/recog.c b/gcc/recog.c > index cfce029..566425d 100644 > --- a/gcc/recog.c > +++ b/gcc/recog.c > @@ -2251,6 +2251,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 4c2607a..ccdaa82 100644 > --- a/gcc/rtl.def > +++ b/gcc/rtl.def > @@ -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 > diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c > index a142488..a99e975 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" > @@ -1354,7 +1355,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 > @@ -1637,6 +1640,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 (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); > @@ -1732,7 +1749,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; > @@ -2606,6 +2624,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 (gimple_copy (stmt)); > else > gcc_unreachable (); > gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT); > @@ -2922,6 +2942,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; > @@ -2930,8 +2953,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 1fe3e63..22c6667 100644 > --- a/gcc/tree-pretty-print.c > +++ b/gcc/tree-pretty-print.c > @@ -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; > } > 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 e379940..30cadd7 100644 > --- a/gcc/tree.c > +++ b/gcc/tree.c > @@ -1015,7 +1015,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: > @@ -4412,7 +4413,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 9f80c4d..e30e950 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 2e8b3e9..62a85ea 100644 > --- a/gcc/tree.h > +++ b/gcc/tree.h > @@ -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 > diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c > index 974b4ea..d3850af 100644 > --- a/gcc/var-tracking.c > +++ b/gcc/var-tracking.c > @@ -9919,6 +9919,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. */ > > @@ -10162,6 +10192,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)) > @@ -10238,10 +10274,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; > @@ -10257,6 +10294,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) > @@ -10282,10 +10325,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. */ > @@ -10350,15 +10396,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) > { > @@ -10380,7 +10432,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; > -- > 2.9.5 >