Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/808501/?format=api
{ "id": 808501, "url": "http://patchwork.ozlabs.org/api/patches/808501/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20170901011500.15345-4-aoliva@redhat.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170901011500.15345-4-aoliva@redhat.com>", "list_archive_url": null, "date": "2017-09-01T01:14:55", "name": "[4/9,SFN] introduce statement frontier notes, still disabled", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "2eda34c2cec1ca41042f80d66188f40bb69720e3", "submitter": { "id": 2058, "url": "http://patchwork.ozlabs.org/api/people/2058/?format=api", "name": "Alexandre Oliva", "email": "aoliva@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20170901011500.15345-4-aoliva@redhat.com/mbox/", "series": [ { "id": 934, "url": "http://patchwork.ozlabs.org/api/series/934/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=934", "date": "2017-09-01T01:14:52", "name": "[1/9,SFN] adjust RTL insn-walking API", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/934/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/808501/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/808501/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-return-461245-incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "mailing list gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org\n\t(client-ip=209.132.180.131; helo=sourceware.org;\n\tenvelope-from=gcc-patches-return-461245-incoming=patchwork.ozlabs.org@gcc.gnu.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org\n\theader.b=\"RxOizXY4\"; dkim-atps=neutral", "sourceware.org; auth=none", "ext-mx07.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com", "ext-mx07.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=aoliva@redhat.com" ], "Received": [ "from sourceware.org (server1.sourceware.org [209.132.180.131])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xk1ZV65Fpz9sMN\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 1 Sep 2017 11:17:54 +1000 (AEST)", "(qmail 96038 invoked by alias); 1 Sep 2017 01:16:07 -0000", "(qmail 95985 invoked by uid 89); 1 Sep 2017 01:16:06 -0000", "from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by\n\tsourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP;\n\tFri, 01 Sep 2017 01:15:56 +0000", "from smtp.corp.redhat.com\n\t(int-mx01.intmail.prod.int.phx2.redhat.com\n\t[10.5.11.11])\t(using TLSv1.2 with cipher AECDH-AES256-SHA\n\t(256/256 bits))\t(No client certificate requested)\tby\n\tmx1.redhat.com (Postfix) with ESMTPS id 41829C047B9C;\n\tFri, 1 Sep 2017 01:15:55 +0000 (UTC)", "from freie.home (ovpn04.gateway.prod.ext.phx2.redhat.com\n\t[10.5.9.4])\tby smtp.corp.redhat.com (Postfix) with ESMTPS id\n\t52106600C4; Fri, 1 Sep 2017 01:15:54 +0000 (UTC)", "from frit.home (frit.home [172.31.160.7])\tby freie.home\n\t(8.15.2/8.15.2) with ESMTP id v811FZOh009211;\n\tThu, 31 Aug 2017 22:15:42 -0300" ], "DomainKey-Signature": "a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender:from\n\t:to:cc:subject:date:message-id:in-reply-to:references; q=dns; s=\n\tdefault; b=MrbcjMC5iAI05FaAQLtRBqwaidVHIOtj6YIhN6VQqfyL8MybdBYQA\n\tCVzatXBdoFeqLJJwzqsRoK+JLt4OLiN5cmn0RzzU8TEUozhHcPbTlybClYKsIevL\n\toGYY1J9SzWbPO86sRmFz00tYQnj3M1ENxIIJN6+JB345wwndkl4xFI=", "DKIM-Signature": "v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender:from\n\t:to:cc:subject:date:message-id:in-reply-to:references; s=\n\tdefault; bh=BQ1rNZpusGuLv1XW+woXoMksMoc=; b=RxOizXY4Iv94FuftruUU\n\t2ljrX3iwcpbWtKXyJV5Ye5CR7STwrSSemH1GtC5HFo2lZek6tUVEKgb3kNkBk6bp\n\tJq095pNa8LkYQACHbtXL5qgT34XICA7Xgjj2g9VRZElYZcyVFSxvqFgR1sSCvga0\n\toHa/KY42golkfPkCTqUj1f8=", "Mailing-List": "contact gcc-patches-help@gcc.gnu.org; run by ezmlm", "Precedence": "bulk", "List-Id": "<gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<mailto:gcc-patches-unsubscribe-incoming=patchwork.ozlabs.org@gcc.gnu.org>", "List-Archive": "<http://gcc.gnu.org/ml/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-help@gcc.gnu.org>", "Sender": "gcc-patches-owner@gcc.gnu.org", "X-Virus-Found": "No", "X-Spam-SWARE-Status": "No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0,\n\tGIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD,\n\tSPF_HELO_PASS autolearn=ham version=3.3.2 spammy=disregard,\n\tHard, 6.7", "X-HELO": "mx1.redhat.com", "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com 41829C047B9C", "From": "Alexandre Oliva <aoliva@redhat.com>", "To": "Richard Biener <richard.guenther@gmail.com>", "Cc": "GCC Patches <gcc-patches@gcc.gnu.org>,\n\tAlexandre Oliva <aoliva@redhat.com>", "Subject": "[PATCH 4/9] [SFN] introduce statement frontier notes, still disabled", "Date": "Thu, 31 Aug 2017 22:14:55 -0300", "Message-Id": "<20170901011500.15345-4-aoliva@redhat.com>", "In-Reply-To": "<orr2vrns5k.fsf@lxoliva.fsfla.org>", "References": "<orr2vrns5k.fsf@lxoliva.fsfla.org>" }, "content": "This patch completes the infrastructure for the introduction of\nstatement frontiers in C-family languages.\n\nIt brings in all the code remaining code needed to introduce and\ntransform begin stmt trees, gimple stmts, insns and notes, and\nultimately use them to generate the is_stmt column in DWARF2+ line\nnumber tables/programs, however none of it is activated: the option\nthat would do so will be introduced in a subsequent patch.\n\nThis patch depends on an earlier patch with not-quite-boilerplate\nchanges towards SFN.\n\nfor gcc/c-family/ChangeLog\n\n\t* c-semantics.c (pop_stmt_list): Move begin stmt marker into\n\tsubsequent statement list.\n\nfor gcc/c/ChangeLog\n\n\t* c-objc-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.\n\t* c-parser.c (add_debug_begin_stmt): New.\n\t(c_parser_declaration_or_fndef): Call it.\n\t(c_parser_compound_statement_nostart): Likewise.\n\t(c_parser_statement_after_labels): Likewise.\n\t* c-typeck (c_finish_stmt_expr): Skip begin stmts markers.\n\nfor gcc/cp/ChangeLog\n\n\t* constexpr.c (build_data_member_initialization): Skip begin stmt\n\tmarkers.\n\t(check_constexpr_ctor_body_1): Likewise.\n\t(build_constexpr_constructor_member_initializers): Likewise.\n\t(constexpr_fn_retval): Likewise.\n\t(cxx_eval_statement_list): Likewise.\n\t(potential_constant_expression_1): Likewise.\n\t* cp-array-notation.c (stmt_location): New.\n\t(cp_expand_cond_array_notations): Use it.\n\t* cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.\n\t* parser.c (add_debug_begin_stmt): New.\n\t(cp_parser_statement): Call it.\n\t* pt.c (tsubst_copy): Handle begin stmt markers.\n\nfor gcc/ChangeLog\n\n\t* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt\n\tmarkers. Integrate source bind into debug stmt expand loop.\n\t(pass_expand::execute): Check debug marker limit. Avoid deep\n\tTER and expand debug locations for debug bind insns only.\n\t* cse.c (insn_live_p): Keep nonbind markers and debug bindings\n\tfollowed by them.\n\t* df-scan.c (df_insn_delete): Accept out-of-block debug insn.\n\t* final.c (reemit_insn_block_notes): Take current block from\n\tnonbind markers. Declare note where it's first set.\n\t(final_scan_insn): Handle begin stmt notes. Emit is_stmt according to\n\tbegin stmt markers if enabled.\n\t(notice_source_line): Handle nonbind markers. Fail if their\n\tlocation is unknown or that of builtins.\n\t(rest_of_handle_final): Convert begin stmt markers to notes if\n\tvar-tracking didn't run.\n\t(rest_of_clean_state): Skip begin stmt markers.\n\t* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt\n\tmarkers.\n\t* function.c (allocate_struct_function): Set begin_stmt_markers.\n\t* function.h (struct function): Add debug_marker_count counter\n\tand debug_nonbind_markers flag.\n\t* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.\n\t* gimple-low.c (lower_function_body): Adjust\n\tdebug_nonbind_markers.\n\t(lower_stmt): Drop or skip gimple debug stmts.\n\t(lower_try_catch): Skip debug stmts.\n\t* gimple.c (gimple_build_debug_begin_stmt): New.\n\t(gimple_copy): Increment debug_marker_count if copying one.\n\t* gimple.h (gimple_build_debug_begin_stmt): Declare.\n\t* gimplify.c (rexpr_location): New.\n\t(rexpr_has_location): New.\n\t(warn_switch_unreachable_r): Handle gimple debug stmts.\n\t(shortcut_cond_r): Call expr_location.\n\t(find_goto): New.\n\t(find_goto_label): New.\n\t(shortcut_cond_expr): Call expr_has_location, expr_location, and\n\tfind_goto_label.\n\t(gimplify_cond_expr): Call find_goto_label, expr_has_location, and\n\texpr_location.\n\t(gimplify_expr): Handle begin stmt markers. Reject debug expr decls.\n\t* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New. Add to...\n\t(LANG_HOOKS_INITIALIZER): ... this.\n\t* langhooks.h (struct lang_hooks): Add emits_begin_stmt.\n\t* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks\n\tdebug insns.\n\t(update_ebb_live_info): Skip debug insn markers.\n\t* lra.c (debug_insn_static_data): Rename to...\n\t(debug_bind_static_data): ... this.\n\t(debug_marker_static_data): New.\n\t(lra_set_insn_recog_data): Select one of the above depending\n\ton debug insn kind.\n\t(lra_update_isn_regno_info): Don't assume debug insns have\n\tfreqs.\n\t(push_insns): Skip debug insns.\n\t* lto-streamer-in.c (input_function): Drop debug stmts\n\tdepending on active options. Adjust debug_nonbind_markers.\n\t* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.\n\t* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle\n\tbegin stmt marker notes.\n\t(print_insn): Likewise.\n\t* recog.c (extract_insn): Recognize rtl for debug markers.\n\t* rtl.def (DEBUG_MARKER): New.\n\t* tree-inline.c: Include params.h.\n\t(remap_gimple_stmt): Handle nonbind markers.\n\t(maybe_move_debug_stmts_to_successors): Likewise.\n\t(copy_debug_stmt): Likewise.\n\t* tree-iterator.c (append_to_statement_list_1): Append begin stmt\n\tmarkers regardless of no side effects.\n\t(tsi_link_before): Don't update container's side effects when adding\n\ta begin stmt marker.\n\t(tsi_link_after): Likewise.\n\t(expr_first): Skip begin stmt markers.\n\t(expr_last): Likewise.\n\t* tree-pretty-print (dump_generic_node): Handle begin stmt markers.\n\t* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):\n\tDisregard nonbind markers.\n\t* tree.c (make_node_stat): Don't set side effects for begin stmt\n\tmarkers.\n\t(build1_stat): Likewise.\n\t* tree.def (DEBUG_BEGIN_STMT): New.\n\t* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.\n\t* var-tracking.c (delete_debug_insns): Renamed to...\n\t(delete_vta_debug_insns): ... this.\n\t(reemit_marker_as_note): New.\n\t(vt_initialize): Reemit markers.\n\t(delete_vta_debug_insns): Likewise.\n\t(vt_debug_insns_local): Reemit or delete markers.\n\t(variable_tracking_main_1): Likewise.\n\t* doc/generic.texi (DEBUG_BEGIN_STMT): Document.\n\t* doc/gimple.texi (gimple_debug_begin_stmt_p): New.\n\t(gimple_debug_nonbind_marker_p): New.\n\t(gimple_build_debug_bind): Adjust.\n\t(gimple_build_debug_begin_stmt): New.\n\t* doc/invoke.texi (max-debug-marker-count): New param.\n\t* doc/rtl.texi (debug_implicit_ptr, entry_value): New.\n\t(debug_parameter_ref, debug_marker): New.\n\t(NOTE_INSN_BEGIN_STMT): New.\n\t(DEBUG_INSN): Describe begin stmt markers.\n---\n gcc/c-family/c-semantics.c | 21 ++++++\n gcc/c/c-objc-common.h | 2 +\n gcc/c/c-parser.c | 20 ++++++\n gcc/c/c-typeck.c | 8 ++-\n gcc/cfgexpand.c | 113 +++++++++++++++++---------------\n gcc/cp/constexpr.c | 11 ++++\n gcc/cp/cp-array-notation.c | 37 +++++++++--\n gcc/cp/cp-objcp-common.h | 2 +\n gcc/cp/parser.c | 14 ++++\n gcc/cp/pt.c | 6 ++\n gcc/cse.c | 7 ++\n gcc/df-scan.c | 2 +-\n gcc/doc/generic.texi | 5 ++\n gcc/doc/gimple.texi | 24 ++++++-\n gcc/doc/invoke.texi | 7 ++\n gcc/doc/rtl.texi | 53 ++++++++++++---\n gcc/final.c | 89 +++++++++++++++++++------\n gcc/function.c | 6 ++\n gcc/function.h | 10 +++\n gcc/gimple-iterator.c | 4 ++\n gcc/gimple-low.c | 29 +++++++++\n gcc/gimple-pretty-print.c | 7 ++\n gcc/gimple.c | 24 +++++++\n gcc/gimple.h | 1 +\n gcc/gimplify.c | 158 +++++++++++++++++++++++++++++++++++----------\n gcc/langhooks-def.h | 2 +\n gcc/langhooks.h | 3 +\n gcc/lra-constraints.c | 10 ++-\n gcc/lra.c | 36 +++++++++--\n gcc/lto-streamer-in.c | 12 +++-\n gcc/params.def | 9 +++\n gcc/print-rtl.c | 24 +++++++\n gcc/recog.c | 1 +\n gcc/rtl.def | 3 +\n gcc/tree-inline.c | 31 ++++++++-\n gcc/tree-iterator.c | 48 +++++++++++---\n gcc/tree-pretty-print.c | 4 ++\n gcc/tree-ssa-threadedge.c | 25 ++++---\n gcc/tree.c | 8 ++-\n gcc/tree.def | 3 +\n gcc/tree.h | 2 +-\n gcc/var-tracking.c | 70 +++++++++++++++++---\n 42 files changed, 793 insertions(+), 158 deletions(-)", "diff": "diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c\nindex 3ceb714..cd872d8 100644\n--- a/gcc/c-family/c-semantics.c\n+++ b/gcc/c-family/c-semantics.c\n@@ -76,6 +76,27 @@ pop_stmt_list (tree t)\n \t free_stmt_list (t);\n \t t = u;\n \t}\n+ /* If the statement list contained a debug begin stmt and a\n+\t statement list, move the debug begin stmt into the statement\n+\t list and return it. */\n+ else if (!tsi_end_p (i)\n+\t && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)\n+\t{\n+\t u = tsi_stmt (i);\n+\t tsi_next (&i);\n+\t if (tsi_one_before_end_p (i)\n+\t && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST)\n+\t {\n+\t tree l = tsi_stmt (i);\n+\t tsi_prev (&i);\n+\t tsi_delink (&i);\n+\t tsi_delink (&i);\n+\t i = tsi_start (l);\n+\t free_stmt_list (t);\n+\t t = l;\n+\t tsi_link_before (&i, u, TSI_SAME_STMT);\n+\t }\n+\t}\n }\n \n return t;\ndiff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h\nindex bee06e9..27ceabc 100644\n--- a/gcc/c/c-objc-common.h\n+++ b/gcc/c/c-objc-common.h\n@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3. If not see\n #define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function\n #undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE\n #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope\n+#undef LANG_HOOKS_EMITS_BEGIN_STMT\n+#define LANG_HOOKS_EMITS_BEGIN_STMT true\n \n /* Attribute hooks. */\n #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE\ndiff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c\nindex 1402ba6..f3dd887 100644\n--- a/gcc/c/c-parser.c\n+++ b/gcc/c/c-parser.c\n@@ -1640,6 +1640,19 @@ c_parser_external_declaration (c_parser *parser)\n static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);\n static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);\n \n+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */\n+\n+static void\n+add_debug_begin_stmt (location_t loc)\n+{\n+ if (!MAY_HAVE_DEBUG_MARKER_STMTS)\n+ return;\n+\n+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);\n+ SET_EXPR_LOCATION (stmt, loc);\n+ add_stmt (stmt);\n+}\n+\n /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99\n 6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition\n is accepted; otherwise (old-style parameter declarations) only other\n@@ -1740,6 +1753,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,\n bool diagnosed_no_specs = false;\n location_t here = c_parser_peek_token (parser)->location;\n \n+ add_debug_begin_stmt (c_parser_peek_token (parser)->location);\n+\n if (static_assert_ok\n && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))\n {\n@@ -4949,6 +4964,7 @@ c_parser_compound_statement_nostart (c_parser *parser)\n location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */\n if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))\n {\n+ add_debug_begin_stmt (c_parser_peek_token (parser)->location);\n c_parser_consume_token (parser);\n return;\n }\n@@ -5403,6 +5419,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,\n parser->in_if_block = false;\n if (if_p != NULL)\n *if_p = false;\n+\n+ if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)\n+ add_debug_begin_stmt (loc);\n+\n switch (c_parser_peek_token (parser)->type)\n {\n case CPP_OPEN_BRACE:\ndiff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c\nindex c33601f..d378470 100644\n--- a/gcc/c/c-typeck.c\n+++ b/gcc/c/c-typeck.c\n@@ -10681,6 +10681,10 @@ c_finish_stmt_expr (location_t loc, tree body)\n \t}\n else\n \ti = tsi_last (last);\n+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)\n+\tdo\n+\t tsi_prev (&i);\n+\twhile (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT);\n last_p = tsi_stmt_ptr (i);\n last = *last_p;\n }\n@@ -10700,7 +10704,9 @@ c_finish_stmt_expr (location_t loc, tree body)\n \n /* In the case that the BIND_EXPR is not necessary, return the\n expression out from inside it. */\n- if (last == BIND_EXPR_BODY (body)\n+ if ((last == BIND_EXPR_BODY (body)\n+ /* Skip nested debug stmts. */\n+ || last == expr_first (BIND_EXPR_BODY (body)))\n && BIND_EXPR_VARS (body) == NULL)\n {\n /* Even if this looks constant, do not allow it in a constant\ndiff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c\nindex 93e0f10..8b25e9f 100644\n--- a/gcc/cfgexpand.c\n+++ b/gcc/cfgexpand.c\n@@ -5638,39 +5638,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)\n \t if (new_bb)\n \t return new_bb;\n \t}\n- else if (gimple_debug_bind_p (stmt))\n+ else if (is_gimple_debug (stmt))\n \t{\n \t location_t sloc = curr_insn_location ();\n \t gimple_stmt_iterator nsi = gsi;\n \n \t for (;;)\n \t {\n-\t tree var = gimple_debug_bind_get_var (stmt);\n-\t tree value;\n-\t rtx val;\n+\t tree var;\n+\t tree value = NULL_TREE;\n+\t rtx val = NULL_RTX;\n \t machine_mode mode;\n \n-\t if (TREE_CODE (var) != DEBUG_EXPR_DECL\n-\t\t && TREE_CODE (var) != LABEL_DECL\n-\t\t && !target_for_debug_bind (var))\n-\t\tgoto delink_debug_stmt;\n+\t if (!gimple_debug_nonbind_marker_p (stmt))\n+\t\t{\n+\t\t if (gimple_debug_bind_p (stmt))\n+\t\t {\n+\t\t var = gimple_debug_bind_get_var (stmt);\n \n-\t if (gimple_debug_bind_has_value_p (stmt))\n-\t\tvalue = gimple_debug_bind_get_value (stmt);\n-\t else\n-\t\tvalue = NULL_TREE;\n+\t\t if (TREE_CODE (var) != DEBUG_EXPR_DECL\n+\t\t\t && TREE_CODE (var) != LABEL_DECL\n+\t\t\t && !target_for_debug_bind (var))\n+\t\t\tgoto delink_debug_stmt;\n \n-\t last = get_last_insn ();\n+\t\t if (DECL_P (var))\n+\t\t\tmode = DECL_MODE (var);\n+\t\t else\n+\t\t\tmode = TYPE_MODE (TREE_TYPE (var));\n \n-\t set_curr_insn_location (gimple_location (stmt));\n+\t\t if (gimple_debug_bind_has_value_p (stmt))\n+\t\t\tvalue = gimple_debug_bind_get_value (stmt);\n+\n+\t\t val = gen_rtx_VAR_LOCATION\n+\t\t\t(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);\n+\t\t }\n+\t\t else if (gimple_debug_source_bind_p (stmt))\n+\t\t {\n+\t\t var = gimple_debug_source_bind_get_var (stmt);\n+\n+\t\t value = gimple_debug_source_bind_get_value (stmt);\n+\n+\t\t mode = DECL_MODE (var);\n \n-\t if (DECL_P (var))\n-\t\tmode = DECL_MODE (var);\n+\t\t val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,\n+\t\t\t\t\t\t VAR_INIT_STATUS_UNINITIALIZED);\n+\t\t }\n+\t\t else\n+\t\t gcc_unreachable ();\n+\t\t}\n+\t /* If this function was first compiled with markers\n+\t\t enabled, but they're now disable (e.g. LTO), drop\n+\t\t them on the floor. */\n+\t else if (gimple_debug_nonbind_marker_p (stmt)\n+\t\t && !MAY_HAVE_DEBUG_MARKER_INSNS)\n+\t\tgoto delink_debug_stmt;\n+\t else if (gimple_debug_begin_stmt_p (stmt))\n+\t\tval = gen_rtx_DEBUG_MARKER (VOIDmode);\n \t else\n-\t\tmode = TYPE_MODE (TREE_TYPE (var));\n+\t\tgcc_unreachable ();\n \n-\t val = gen_rtx_VAR_LOCATION\n-\t\t(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);\n+\t last = get_last_insn ();\n+\n+\t set_curr_insn_location (gimple_location (stmt));\n \n \t emit_debug_insn (val);\n \n@@ -5678,9 +5707,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)\n \t\t{\n \t\t /* We can't dump the insn with a TREE where an RTX\n \t\t is expected. */\n-\t\t PAT_VAR_LOCATION_LOC (val) = const0_rtx;\n+\t\t if (GET_CODE (val) == VAR_LOCATION)\n+\t\t {\n+\t\t gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);\n+\t\t PAT_VAR_LOCATION_LOC (val) = const0_rtx;\n+\t\t }\n \t\t maybe_dump_rtl_for_gimple_stmt (stmt, last);\n-\t\t PAT_VAR_LOCATION_LOC (val) = (rtx)value;\n+\t\t if (GET_CODE (val) == VAR_LOCATION)\n+\t\t PAT_VAR_LOCATION_LOC (val) = (rtx)value;\n \t\t}\n \n \t delink_debug_stmt:\n@@ -5696,42 +5730,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)\n \t if (gsi_end_p (nsi))\n \t\tbreak;\n \t stmt = gsi_stmt (nsi);\n-\t if (!gimple_debug_bind_p (stmt))\n+\t if (!is_gimple_debug (stmt))\n \t\tbreak;\n \t }\n \n \t set_curr_insn_location (sloc);\n \t}\n- else if (gimple_debug_source_bind_p (stmt))\n-\t{\n-\t location_t sloc = curr_insn_location ();\n-\t tree var = gimple_debug_source_bind_get_var (stmt);\n-\t tree value = gimple_debug_source_bind_get_value (stmt);\n-\t rtx val;\n-\t machine_mode mode;\n-\n-\t last = get_last_insn ();\n-\n-\t set_curr_insn_location (gimple_location (stmt));\n-\n-\t mode = DECL_MODE (var);\n-\n-\t val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,\n-\t\t\t\t VAR_INIT_STATUS_UNINITIALIZED);\n-\n-\t emit_debug_insn (val);\n-\n-\t if (dump_file && (dump_flags & TDF_DETAILS))\n-\t {\n-\t /* We can't dump the insn with a TREE where an RTX\n-\t\t is expected. */\n-\t PAT_VAR_LOCATION_LOC (val) = const0_rtx;\n-\t maybe_dump_rtl_for_gimple_stmt (stmt, last);\n-\t PAT_VAR_LOCATION_LOC (val) = (rtx)value;\n-\t }\n-\n-\t set_curr_insn_location (sloc);\n-\t}\n else\n \t{\n \t gcall *call_stmt = dyn_cast <gcall *> (stmt);\n@@ -6370,6 +6374,11 @@ pass_expand::execute (function *fun)\n FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)\n e->flags &= ~EDGE_EXECUTABLE;\n \n+ /* If the function has too many markers, drop them while expanding. */\n+ if (cfun->debug_marker_count\n+ >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))\n+ cfun->debug_nonbind_markers = false;\n+\n lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;\n FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),\n \t\t next_bb)\ndiff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c\nindex 29ba2c3..c8f1255 100644\n--- a/gcc/cp/constexpr.c\n+++ b/gcc/cp/constexpr.c\n@@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)\n tree_stmt_iterator i;\n for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))\n \t{\n+\t if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)\n+\t /* ??? Can we retain this information somehow? */\n+\t continue;\n \t if (! build_data_member_initialization (tsi_stmt (i), vec))\n \t return false;\n \t}\n@@ -448,6 +451,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)\n \n case USING_STMT:\n case STATIC_ASSERT:\n+ case DEBUG_BEGIN_STMT:\n return true;\n \n default:\n@@ -586,6 +590,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)\n tree_stmt_iterator i;\n for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))\n \t{\n+\t if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)\n+\t /* ??? Can we retain this information somehow? */\n+\t continue;\n \t ok = build_data_member_initialization (tsi_stmt (i), &vec);\n \t if (!ok)\n \t break;\n@@ -673,6 +680,7 @@ constexpr_fn_retval (tree body)\n return constexpr_fn_retval (BIND_EXPR_BODY (body));\n \n case USING_STMT:\n+ case DEBUG_BEGIN_STMT:\n return NULL_TREE;\n \n default:\n@@ -3765,6 +3773,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,\n for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))\n {\n tree stmt = tsi_stmt (i);\n+ if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)\n+\tcontinue;\n r = cxx_eval_constant_expression (ctx, stmt, false,\n \t\t\t\t\tnon_constant_p, overflow_p,\n \t\t\t\t\tjump_target);\n@@ -5096,6 +5106,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,\n case CONTINUE_STMT:\n case REQUIRES_EXPR:\n case STATIC_ASSERT:\n+ case DEBUG_BEGIN_STMT:\n return true;\n \n case AGGR_INIT_EXPR:\ndiff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c\nindex 31be7d6..17f0b35c 100644\n--- a/gcc/cp/cp-array-notation.c\n+++ b/gcc/cp/cp-array-notation.c\n@@ -780,6 +780,31 @@ error:\n return error_mark_node;\n }\n \n+/* Return a location associated with stmt. If it is an expresion,\n+ that's the expression's location. If it is a STATEMENT_LIST,\n+ instead of no location, use expr_first to skip any debug stmts and\n+ take the location of the first nondebug stmt found. */\n+\n+static location_t\n+stmt_location (tree stmt)\n+{\n+ location_t loc = UNKNOWN_LOCATION;\n+\n+ if (!stmt)\n+ return loc;\n+\n+ loc = EXPR_LOCATION (stmt);\n+\n+ if (loc != UNKNOWN_LOCATION || TREE_CODE (stmt) != STATEMENT_LIST)\n+ return loc;\n+\n+ stmt = expr_first (stmt);\n+ if (stmt)\n+ loc = EXPR_LOCATION (stmt);\n+\n+ return loc;\n+}\n+\n /* Helper function for expand_conditonal_array_notations. Encloses the\n conditional statement passed in ORIG_STMT with a loop around it and\n replaces the condition in STMT with a ARRAY_REF tree-node to the array. \n@@ -835,10 +860,12 @@ cp_expand_cond_array_notations (tree orig_stmt)\n tree cond = IF_COND (orig_stmt);\n if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)\n \t || (yes_expr\n-\t && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,\n+\t && !find_rank (stmt_location (yes_expr),\n+\t\t\t yes_expr, yes_expr, true,\n \t\t\t &yes_rank))\n \t || (no_expr\n-\t && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,\n+\t && !find_rank (stmt_location (no_expr),\n+\t\t\t no_expr, no_expr, true,\n \t\t\t &no_rank)))\n \treturn error_mark_node;\n \n@@ -847,13 +874,15 @@ cp_expand_cond_array_notations (tree orig_stmt)\n \treturn orig_stmt;\n else if (cond_rank != yes_rank && yes_rank != 0)\n \t{\n-\t error_at (EXPR_LOCATION (yes_expr), \"rank mismatch with controlling\"\n+\t error_at (stmt_location (yes_expr),\n+\t\t \"rank mismatch with controlling\"\n \t\t \" expression of parent if-statement\");\n \t return error_mark_node;\n \t}\n else if (cond_rank != no_rank && no_rank != 0)\n \t{\n-\t error_at (EXPR_LOCATION (no_expr), \"rank mismatch with controlling \"\n+\t error_at (stmt_location (no_expr),\n+\t\t \"rank mismatch with controlling \"\n \t\t \"expression of parent if-statement\");\n \t return error_mark_node;\n \t}\ndiff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h\nindex 10fcdf3..e98c5c5 100644\n--- a/gcc/cp/cp-objcp-common.h\n+++ b/gcc/cp/cp-objcp-common.h\n@@ -103,6 +103,8 @@ extern void cp_register_dumps (gcc::dump_manager *);\n #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p\n #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU\n #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru\n+#undef LANG_HOOKS_EMITS_BEGIN_STMT\n+#define LANG_HOOKS_EMITS_BEGIN_STMT true\n \n /* Attribute hooks. */\n #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE\ndiff --git a/gcc/cp/parser.c b/gcc/cp/parser.c\nindex b849824..c1be6b8 100644\n--- a/gcc/cp/parser.c\n+++ b/gcc/cp/parser.c\n@@ -10712,6 +10712,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)\n \n /* Statements [gram.stmt.stmt] */\n \n+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */\n+\n+static void\n+add_debug_begin_stmt (location_t loc)\n+{\n+ if (!MAY_HAVE_DEBUG_MARKER_STMTS)\n+ return;\n+\n+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);\n+ SET_EXPR_LOCATION (stmt, loc);\n+ add_stmt (stmt);\n+}\n+\n /* Parse a statement.\n \n statement:\n@@ -10787,6 +10800,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,\n token = cp_lexer_peek_token (parser->lexer);\n /* Remember the location of the first token in the statement. */\n statement_location = token->location;\n+ add_debug_begin_stmt (statement_location);\n /* If this is a keyword, then that will often determine what kind of\n statement we have. */\n if (token->type == CPP_KEYWORD)\ndiff --git a/gcc/cp/pt.c b/gcc/cp/pt.c\nindex bf1f75d..ced7ec6 100644\n--- a/gcc/cp/pt.c\n+++ b/gcc/cp/pt.c\n@@ -15120,6 +15120,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n case PREDICT_EXPR:\n return t;\n \n+ case DEBUG_BEGIN_STMT:\n+ /* ??? There's no point in copying it for now, but maybe some\n+\t day it will contain more information, such as a pointer back\n+\t to the containing function, inlined copy or so. */\n+ return t;\n+\n default:\n /* We shouldn't get here, but keep going if !flag_checking. */\n if (flag_checking)\ndiff --git a/gcc/cse.c b/gcc/cse.c\nindex e51fcd9..97d9852 100644\n--- a/gcc/cse.c\n+++ b/gcc/cse.c\n@@ -6953,11 +6953,18 @@ insn_live_p (rtx_insn *insn, int *counts)\n {\n rtx_insn *next;\n \n+ if (DEBUG_MARKER_INSN_P (insn))\n+\treturn true;\n+\n for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))\n \tif (NOTE_P (next))\n \t continue;\n \telse if (!DEBUG_INSN_P (next))\n \t return true;\n+\t/* If we find an inspection point, such as a debug begin stmt,\n+\t we want to keep the earlier debug insn. */\n+\telse if (DEBUG_MARKER_INSN_P (next))\n+\t return true;\n \telse if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))\n \t return false;\n \ndiff --git a/gcc/df-scan.c b/gcc/df-scan.c\nindex dde6d15..a7b04e7 100644\n--- a/gcc/df-scan.c\n+++ b/gcc/df-scan.c\n@@ -945,7 +945,7 @@ df_insn_delete (rtx_insn *insn)\n In any case, we expect BB to be non-NULL at least up to register\n allocation, so disallow a non-NULL BB up to there. Not perfect\n but better than nothing... */\n- gcc_checking_assert (bb != NULL || reload_completed);\n+ gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed);\n \n df_grow_bb_info (df_scan);\n df_grow_reg_info ();\ndiff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi\nindex 874d464..c938be8 100644\n--- a/gcc/doc/generic.texi\n+++ b/gcc/doc/generic.texi\n@@ -1930,6 +1930,11 @@ case 2 ... 5:\n The first value will be @code{CASE_LOW}, while the second will be\n @code{CASE_HIGH}.\n \n+@item DEBUG_BEGIN_STMT\n+\n+Marks the beginning of a source statement, for purposes of debug\n+information generation.\n+\n @end table\n \n \ndiff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi\nindex 635abd39..6c9c4789 100644\n--- a/gcc/doc/gimple.texi\n+++ b/gcc/doc/gimple.texi\n@@ -831,6 +831,16 @@ expression to a variable.\n Return true if g is any of the OpenMP codes.\n @end deftypefn\n \n+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)\n+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of\n+a source statement.\n+@end deftypefn\n+\n+@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)\n+Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,\n+without any variable binding.\n+@end deftypefn\n+\n @node Manipulating GIMPLE statements\n @section Manipulating GIMPLE statements\n @cindex Manipulating GIMPLE statements\n@@ -1528,10 +1538,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.\n @subsection @code{GIMPLE_DEBUG}\n @cindex @code{GIMPLE_DEBUG}\n @cindex @code{GIMPLE_DEBUG_BIND}\n+@cindex @code{GIMPLE_DEBUG_BEGIN_STMT}\n \n @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @\n tree value, gimple stmt)\n-Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of\n+Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND}\n @code{subcode}. The effect of this statement is to tell debug\n information generation machinery that the value of user variable\n @code{var} is given by @code{value} at that point, and to remain with\n@@ -1602,6 +1613,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,\n and @code{FALSE} if it unbinds the variable.\n @end deftypefn\n \n+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)\n+Build a @code{GIMPLE_DEBUG} statement with\n+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}. The effect of this\n+statement is to tell debug information generation machinery that the\n+user statement at the given @code{location} and @code{block} starts at\n+the point at which the statement is inserted. The intent is that side\n+effects (e.g. variable bindings) of all prior user statements are\n+observable, and that none of the side effects of subsequent user\n+statements are.\n+@end deftypefn\n+\n @node @code{GIMPLE_EH_FILTER}\n @subsection @code{GIMPLE_EH_FILTER}\n @cindex @code{GIMPLE_EH_FILTER}\ndiff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi\nindex ec29f1d..6dbc362 100644\n--- a/gcc/doc/invoke.texi\n+++ b/gcc/doc/invoke.texi\n@@ -10419,6 +10419,13 @@ debug information may end up not being used; setting this higher may\n enable the compiler to find more complex debug expressions, but compile\n time and memory use may grow. The default is 12.\n \n+@item max-debug-marker-count\n+Sets a threshold on the number of debug markers (e.g. begin stmt\n+markers) to avoid complexity explosion at inlining or expanding to RTL.\n+If a function has more such gimple stmts than the set limit, such stmts\n+will be dropped from the inlined copy of a function, and from its RTL\n+expansion. The default is 100000.\n+\n @item min-nondebug-insn-uid\n Use uids starting at this parameter for nondebug insns. The range below\n the parameter is reserved exclusively for debug insns created by\ndiff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi\nindex 6e2799a..e58f0ab 100644\n--- a/gcc/doc/rtl.texi\n+++ b/gcc/doc/rtl.texi\n@@ -3413,6 +3413,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},\n that points back to it, within value expressions in\n @code{VAR_LOCATION} nodes.\n \n+@findex debug_implicit_ptr\n+@item (debug_implicit_ptr:@var{mode} @var{decl})\n+Stands for the location of a @var{decl} that is no longer addressable.\n+\n+@findex entry_value\n+@item (entry_value:@var{mode} @var{decl})\n+Stands for the value a @var{decl} had at the entry point of the\n+containing function.\n+\n+@findex debug_parameter_ref\n+@item (debug_parameter_ref:@var{mode} @var{decl})\n+Refers to a parameter that was completely optimized out.\n+\n+@findex debug_marker\n+@item (debug_marker:@var{mode})\n+Marks a program location. With @code{VOIDmode}, it stands for the\n+beginning of a statement, a recommended inspection point logically after\n+all prior side effects, and before any subsequent side effects.\n+\n @end table\n \n @node Insns\n@@ -3689,6 +3708,12 @@ can be computed by evaluating the RTL expression from that static\n point in the program up to the next such note for the same user\n variable.\n \n+@findex NOTE_INSN_BEGIN_STMT\n+@item NOTE_INSN_BEGIN_STMT\n+This note is used to generate @code{is_stmt} markers in line number\n+debuggign information. It indicates the beginning of a user\n+statement.\n+\n @end table\n \n These codes are printed symbolically when they appear in debugging dumps.\n@@ -3706,15 +3731,25 @@ binds a user variable tree to an RTL representation of the\n it stands for the value bound to the corresponding\n @code{DEBUG_EXPR_DECL}.\n \n-Throughout optimization passes, binding information is kept in\n-pseudo-instruction form, so that, unlike notes, it gets the same\n-treatment and adjustments that regular instructions would. It is the\n-variable tracking pass that turns these pseudo-instructions into var\n-location notes, analyzing control flow, value equivalences and changes\n-to registers and memory referenced in value expressions, propagating\n-the values of debug temporaries and determining expressions that can\n-be used to compute the value of each user variable at as many points\n-(ranges, actually) in the program as possible.\n+@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}\n+with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}. These\n+@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,\n+just @code{DEBUG_MARKER}s, can be detected by testing\n+@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as\n+@code{DEBUG_BIND_INSN_P}.\n+\n+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered\n+with respect to each other, particularly during scheduling. Binding\n+information is kept in pseudo-instruction form, so that, unlike notes,\n+it gets the same treatment and adjustments that regular instructions\n+would. It is the variable tracking pass that turns these\n+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and\n+@code{NOTE_INSN_BEGIN_STMT} notes,\n+analyzing control flow, value equivalences and changes to registers and\n+memory referenced in value expressions, propagating the values of debug\n+temporaries and determining expressions that can be used to compute the\n+value of each user variable at as many points (ranges, actually) in the\n+program as possible.\n \n Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an\n @code{INSN_VAR_LOCATION} denotes a value at that specific point in the\ndiff --git a/gcc/final.c b/gcc/final.c\nindex ad999f7..401cfb6 100644\n--- a/gcc/final.c\n+++ b/gcc/final.c\n@@ -1653,7 +1653,6 @@ reemit_insn_block_notes (void)\n {\n tree cur_block = DECL_INITIAL (cfun->decl);\n rtx_insn *insn;\n- rtx_note *note;\n \n insn = get_insns ();\n for (; insn; insn = NEXT_INSN (insn))\n@@ -1661,17 +1660,29 @@ reemit_insn_block_notes (void)\n tree this_block;\n \n /* Prevent lexical blocks from straddling section boundaries. */\n- if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)\n- {\n- for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);\n- s = BLOCK_SUPERCONTEXT (s))\n- {\n- rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);\n- NOTE_BLOCK (note) = s;\n- note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);\n- NOTE_BLOCK (note) = s;\n- }\n- }\n+ if (NOTE_P (insn))\n+\tswitch (NOTE_KIND (insn))\n+\t {\n+\t case NOTE_INSN_SWITCH_TEXT_SECTIONS:\n+\t {\n+\t for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);\n+\t\t s = BLOCK_SUPERCONTEXT (s))\n+\t\t{\n+\t\t rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);\n+\t\t NOTE_BLOCK (note) = s;\n+\t\t note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);\n+\t\t NOTE_BLOCK (note) = s;\n+\t\t}\n+\t }\n+\t break;\n+\n+\t case NOTE_INSN_BEGIN_STMT:\n+\t this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));\n+\t goto set_cur_block_to_this_block;\n+\n+\t default:\n+\t continue;\n+\t}\n \n if (!active_insn_p (insn))\n continue;\n@@ -1692,6 +1703,7 @@ reemit_insn_block_notes (void)\n \t this_block = choose_inner_scope (this_block,\n \t\t\t\t\t insn_scope (body->insn (i)));\n \t}\n+ set_cur_block_to_this_block:\n if (! this_block)\n \t{\n \t if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)\n@@ -1708,7 +1720,7 @@ reemit_insn_block_notes (void)\n }\n \n /* change_scope emits before the insn, not after. */\n- note = emit_note (NOTE_INSN_DELETED);\n+ rtx_note *note = emit_note (NOTE_INSN_DELETED);\n change_scope (note, cur_block, DECL_INITIAL (cfun->decl));\n delete_insn (note);\n \n@@ -2410,6 +2422,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,\n \t debug_hooks->var_location (insn);\n \t break;\n \n+\tcase NOTE_INSN_BEGIN_STMT:\n+\t gcc_checking_assert (cfun->debug_nonbind_markers);\n+\t if (!DECL_IGNORED_P (current_function_decl)\n+\t && notice_source_line (insn, NULL))\n+\t {\n+\t (*debug_hooks->source_line) (last_linenum, last_columnnum,\n+\t\t\t\t\t last_filename, last_discriminator,\n+\t\t\t\t\t true);\n+\t }\n+\t break;\n+\n \tdefault:\n \t gcc_unreachable ();\n \t break;\n@@ -2497,7 +2520,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,\n \trtx body = PATTERN (insn);\n \tint insn_code_number;\n \tconst char *templ;\n-\tbool is_stmt;\n+\tbool is_stmt, *is_stmt_p;\n+\n+\tif (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)\n+\t {\n+\t is_stmt = false;\n+\t is_stmt_p = NULL;\n+\t }\n+\telse\n+\t is_stmt_p = &is_stmt;\n \n \t/* Reset this early so it is correct for ASM statements. */\n \tcurrent_insn_predicate = NULL_RTX;\n@@ -2600,7 +2631,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,\n \t/* Output this line note if it is the first or the last line\n \t note in a row. */\n \tif (!DECL_IGNORED_P (current_function_decl)\n-\t && notice_source_line (insn, &is_stmt))\n+\t && notice_source_line (insn, is_stmt_p))\n \t {\n \t if (flag_verbose_asm)\n \t asm_show_source (last_filename, last_linenum);\n@@ -3093,7 +3124,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)\n const char *filename;\n int linenum, columnnum;\n \n- if (override_filename)\n+ if (NOTE_MARKER_P (insn))\n+ {\n+ location_t loc = NOTE_MARKER_LOCATION (insn);\n+ expanded_location xloc = expand_location (loc);\n+ if (xloc.line == 0)\n+\t{\n+\t gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION\n+\t\t\t || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);\n+\t return false;\n+\t}\n+ filename = xloc.file;\n+ linenum = xloc.line;\n+ columnnum = xloc.column;\n+ force_source_line = true;\n+ }\n+ else if (override_filename)\n {\n filename = override_filename;\n linenum = override_linenum;\n@@ -3126,7 +3172,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)\n last_linenum = linenum;\n last_columnnum = columnnum;\n last_discriminator = discriminator;\n- *is_stmt = true;\n+ if (is_stmt)\n+\t*is_stmt = true;\n high_block_linenum = MAX (last_linenum, high_block_linenum);\n high_function_linenum = MAX (last_linenum, high_function_linenum);\n return true;\n@@ -3138,7 +3185,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)\n output the line table entry with is_stmt false so the\n debugger does not treat this as a breakpoint location. */\n last_discriminator = discriminator;\n- *is_stmt = false;\n+ if (is_stmt)\n+\t*is_stmt = false;\n return true;\n }\n \n@@ -4491,6 +4539,10 @@ rest_of_handle_final (void)\n {\n const char *fnname = get_fnname_from_decl (current_function_decl);\n \n+ /* Turn debug markers into notes. */\n+ if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)\n+ variable_tracking_main ();\n+\n assemble_start_function (current_function_decl, fnname);\n final_start_function (get_insns (), asm_out_file, optimize);\n final (get_insns (), asm_out_file, optimize);\n@@ -4678,6 +4730,7 @@ rest_of_clean_state (void)\n if (final_output\n \t && (!NOTE_P (insn) ||\n \t (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION\n+\t && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT\n \t && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION\n \t && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG\n \t && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END\ndiff --git a/gcc/function.c b/gcc/function.c\nindex f42227a..e29cbde 100644\n--- a/gcc/function.c\n+++ b/gcc/function.c\n@@ -4941,6 +4941,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)\n if (!profile_flag && !flag_instrument_function_entry_exit)\n \tDECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;\n }\n+\n+ /* Don't enable begin stmt markers if var-tracking at assignments is\n+ disabled. The markers make little sense without the variable\n+ binding annotations among them. */\n+ cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt\n+ && MAY_HAVE_DEBUG_MARKER_STMTS;\n }\n \n /* This is like allocate_struct_function, but pushes a new cfun for FNDECL\ndiff --git a/gcc/function.h b/gcc/function.h\nindex 0f34bcd..2c2e622 100644\n--- a/gcc/function.h\n+++ b/gcc/function.h\n@@ -284,6 +284,12 @@ struct GTY(()) function {\n /* Last statement uid. */\n int last_stmt_uid;\n \n+ /* Debug marker counter. Count begin stmt markers. We don't have\n+ to keep it exact, it's more of a rough estimate to enable us to\n+ decide whether they are too many to copy during inlining, or when\n+ expanding to RTL. */\n+ int debug_marker_count;\n+\n /* Function sequence number for profiling, debugging, etc. */\n int funcdef_no;\n \n@@ -387,6 +393,10 @@ struct GTY(()) function {\n \n /* Set when the tail call has been identified. */\n unsigned int tail_call_marked : 1;\n+\n+ /* Set when the function was compiled with generation of debug\n+ (begin stmt, inline entry, ...) markers enabled. */\n+ unsigned int debug_nonbind_markers : 1;\n };\n \n /* Add the decl D to the local_decls list of FUN. */\ndiff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c\nindex fb75f99..2359760 100644\n--- a/gcc/gimple-iterator.c\n+++ b/gcc/gimple-iterator.c\n@@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)\n \n if (remove_permanently)\n {\n+ if (gimple_debug_nonbind_marker_p (stmt))\n+\t/* We don't need this to be exact, but try to keep it at least\n+\t close. */\n+\tcfun->debug_marker_count--;\n require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);\n gimple_remove_stmt_histograms (cfun, stmt);\n }\ndiff --git a/gcc/gimple-low.c b/gcc/gimple-low.c\nindex 22db61b..95f3f45 100644\n--- a/gcc/gimple-low.c\n+++ b/gcc/gimple-low.c\n@@ -110,6 +110,17 @@ lower_function_body (void)\n \n i = gsi_last (lowered_body);\n \n+ /* If we had begin stmt markers from e.g. PCH, but this compilation\n+ doesn't want them, lower_stmt will have cleaned them up; we can\n+ now clear the flag that indicates we had them. */\n+ if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)\n+ {\n+ /* This counter needs not be exact, but before lowering it will\n+\t most certainly be. */\n+ gcc_assert (cfun->debug_marker_count == 0);\n+ cfun->debug_nonbind_markers = false;\n+ }\n+\n /* If the function falls off the end, we need a null return statement.\n If we've already got one in the return_statements vector, we don't\n need to do anything special. Otherwise build one by hand. */\n@@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)\n }\n break;\n \n+ case GIMPLE_DEBUG:\n+ gcc_checking_assert (cfun->debug_nonbind_markers);\n+ /* We can't possibly have debug bind stmts before lowering, we\n+\t first emit them when entering SSA. */\n+ gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));\n+ /* Propagate fallthruness. */\n+ /* If the function (e.g. from PCH) had debug stmts, but they're\n+\t disabled for this compilation, remove them. */\n+ if (!MAY_HAVE_DEBUG_MARKER_STMTS)\n+\tgsi_remove (gsi, true);\n+ else\n+\tgsi_next (gsi);\n+ return;\n+\n case GIMPLE_NOP:\n case GIMPLE_ASM:\n case GIMPLE_ASSIGN:\n@@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)\n \tcannot_fallthru = false;\n break;\n \n+ case GIMPLE_DEBUG:\n+ gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));\n+ break;\n+\n default:\n /* This case represents statements to be executed when an\n \t exception occurs. Those statements are implicitly followed\ndiff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c\nindex ed8e51c..2702854 100644\n--- a/gcc/gimple-pretty-print.c\n+++ b/gcc/gimple-pretty-print.c\n@@ -1370,6 +1370,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,\n \t\t\t gimple_debug_source_bind_get_value (gs));\n break;\n \n+ case GIMPLE_DEBUG_BEGIN_STMT:\n+ if (flags & TDF_RAW)\n+\tdump_gimple_fmt (buffer, spc, flags, \"%G BEGIN_STMT\", gs);\n+ else\n+\tdump_gimple_fmt (buffer, spc, flags, \"# DEBUG BEGIN_STMT\");\n+ break;\n+\n default:\n gcc_unreachable ();\n }\ndiff --git a/gcc/gimple.c b/gcc/gimple.c\nindex c4e6f81..dc9aa79 100644\n--- a/gcc/gimple.c\n+++ b/gcc/gimple.c\n@@ -836,6 +836,27 @@ gimple_build_debug_source_bind (tree var, tree value,\n }\n \n \n+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at\n+ LOCATION. */\n+\n+gdebug *\n+gimple_build_debug_begin_stmt (tree block, location_t location\n+\t\t\t\t MEM_STAT_DECL)\n+{\n+ gdebug *p\n+ = as_a <gdebug *> (\n+ gimple_build_with_ops_stat (GIMPLE_DEBUG,\n+\t\t\t\t (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0\n+\t\t\t\t PASS_MEM_STAT));\n+\n+ gimple_set_location (p, location);\n+ gimple_set_block (p, block);\n+ cfun->debug_marker_count++;\n+\n+ return p;\n+}\n+\n+\n /* Build a GIMPLE_OMP_CRITICAL statement.\n \n BODY is the sequence of statements for which only one thread can execute.\n@@ -1874,6 +1895,9 @@ gimple_copy (gimple *stmt)\n gimple_set_modified (copy, true);\n }\n \n+ if (gimple_debug_nonbind_marker_p (stmt))\n+ cfun->debug_marker_count++;\n+\n return copy;\n }\n \ndiff --git a/gcc/gimple.h b/gcc/gimple.h\nindex 8f289ac..68cd34f 100644\n--- a/gcc/gimple.h\n+++ b/gcc/gimple.h\n@@ -1454,6 +1454,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );\n geh_dispatch *gimple_build_eh_dispatch (int);\n gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);\n gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);\n+gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);\n gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);\n gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);\n gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);\ndiff --git a/gcc/gimplify.c b/gcc/gimplify.c\nindex d391039..8c5804b 100644\n--- a/gcc/gimplify.c\n+++ b/gcc/gimplify.c\n@@ -982,6 +982,48 @@ unshare_expr_without_location (tree expr)\n walk_tree (&expr, prune_expr_location, NULL, NULL);\n return expr;\n }\n+\n+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has\n+ one, OR_ELSE otherwise. The location of a STATEMENT_LISTs\n+ comprising at least one DEBUG_BEGIN_STMT followed by exactly one\n+ EXPR is the location of the EXPR. */\n+\n+static location_t\n+rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)\n+{\n+ if (!expr)\n+ return or_else;\n+\n+ if (EXPR_HAS_LOCATION (expr))\n+ return EXPR_LOCATION (expr);\n+\n+ if (TREE_CODE (expr) != STATEMENT_LIST)\n+ return or_else;\n+\n+ tree_stmt_iterator i = tsi_start (expr);\n+\n+ bool found = false;\n+ while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)\n+ {\n+ found = true;\n+ tsi_next (&i);\n+ }\n+\n+ if (!found || !tsi_one_before_end_p (i))\n+ return or_else;\n+\n+ return rexpr_location (tsi_stmt (i), or_else);\n+}\n+\n+/* Return TRUE iff EXPR (maybe recursively) has a location; see\n+ rexpr_location for the potential recursion. */\n+\n+static inline bool\n+rexpr_has_location (tree expr)\n+{\n+ return rexpr_location (expr) != UNKNOWN_LOCATION;\n+}\n+\n \f\n /* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both\n contain statements and have a value. Assign its value to a temporary\n@@ -1772,6 +1814,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,\n /* Walk the sub-statements. */\n *handled_ops_p = false;\n break;\n+\n+ case GIMPLE_DEBUG:\n+ /* Ignore these. We may generate them before declarations that\n+\t are never executed. If there's something to warn about,\n+\t there will be non-debug stmts too, and we'll catch those. */\n+ break;\n+\n case GIMPLE_CALL:\n if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))\n \t{\n@@ -3440,7 +3489,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,\n append_to_statement_list (t, &expr);\n \n /* Set the source location of the && on the second 'if'. */\n- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;\n+ new_locus = rexpr_location (pred, locus);\n t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,\n \t\t\t new_locus);\n append_to_statement_list (t, &expr);\n@@ -3463,7 +3512,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,\n append_to_statement_list (t, &expr);\n \n /* Set the source location of the || on the second 'if'. */\n- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;\n+ new_locus = rexpr_location (pred, locus);\n t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,\n \t\t\t new_locus);\n append_to_statement_list (t, &expr);\n@@ -3485,7 +3534,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,\n \n /* Keep the original source location on the first 'if'. Set the source\n \t location of the ? on the second 'if'. */\n- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;\n+ new_locus = rexpr_location (pred, locus);\n expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),\n \t\t shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,\n \t\t\t\t false_label_p, locus),\n@@ -3509,6 +3558,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,\n return expr;\n }\n \n+/* If EXPR is a GOTO_EXPR, return it. If it is a STATEMENT_LIST, skip\n+ any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent\n+ statement, if it is the last one. Otherwise, return NULL. */\n+\n+static tree\n+find_goto (tree expr)\n+{\n+ if (!expr)\n+ return NULL_TREE;\n+\n+ if (TREE_CODE (expr) == GOTO_EXPR)\n+ return expr;\n+\n+ if (TREE_CODE (expr) != STATEMENT_LIST)\n+ return NULL_TREE;\n+\n+ tree_stmt_iterator i = tsi_start (expr);\n+\n+ while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)\n+ tsi_next (&i);\n+\n+ if (!tsi_one_before_end_p (i))\n+ return NULL_TREE;\n+\n+ return find_goto (tsi_stmt (i));\n+}\n+\n+/* Same as find_goto, except that it returns NULL if the destination\n+ is not a LABEL_DECL. */\n+\n+static inline tree\n+find_goto_label (tree expr)\n+{\n+ tree dest = find_goto (expr);\n+ if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)\n+ return dest;\n+ return NULL_TREE;\n+}\n+\n /* Given a conditional expression EXPR with short-circuit boolean\n predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the\n predicate apart into the equivalent sequence of conditionals. */\n@@ -3539,8 +3627,8 @@ shortcut_cond_expr (tree expr)\n \t location_t locus = EXPR_LOC_OR_LOC (expr, input_location);\n \t TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);\n \t /* Set the source location of the && on the second 'if'. */\n-\t if (EXPR_HAS_LOCATION (pred))\n-\t SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));\n+\t if (rexpr_has_location (pred))\n+\t SET_EXPR_LOCATION (expr, rexpr_location (pred));\n \t then_ = shortcut_cond_expr (expr);\n \t then_se = then_ && TREE_SIDE_EFFECTS (then_);\n \t pred = TREE_OPERAND (pred, 0);\n@@ -3561,8 +3649,8 @@ shortcut_cond_expr (tree expr)\n \t location_t locus = EXPR_LOC_OR_LOC (expr, input_location);\n \t TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);\n \t /* Set the source location of the || on the second 'if'. */\n-\t if (EXPR_HAS_LOCATION (pred))\n-\t SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));\n+\t if (rexpr_has_location (pred))\n+\t SET_EXPR_LOCATION (expr, rexpr_location (pred));\n \t else_ = shortcut_cond_expr (expr);\n \t else_se = else_ && TREE_SIDE_EFFECTS (else_);\n \t pred = TREE_OPERAND (pred, 0);\n@@ -3589,20 +3677,16 @@ shortcut_cond_expr (tree expr)\n /* If our arms just jump somewhere, hijack those labels so we don't\n generate jumps to jumps. */\n \n- if (then_\n- && TREE_CODE (then_) == GOTO_EXPR\n- && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)\n+ if (tree then_goto = find_goto_label (then_))\n {\n- true_label = GOTO_DESTINATION (then_);\n+ true_label = GOTO_DESTINATION (then_goto);\n then_ = NULL;\n then_se = false;\n }\n \n- if (else_\n- && TREE_CODE (else_) == GOTO_EXPR\n- && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)\n+ if (tree else_goto = find_goto_label (else_))\n {\n- false_label = GOTO_DESTINATION (else_);\n+ false_label = GOTO_DESTINATION (else_goto);\n else_ = NULL;\n else_se = false;\n }\n@@ -3666,8 +3750,8 @@ shortcut_cond_expr (tree expr)\n \t{\n \t tree last = expr_last (expr);\n \t t = build_and_jump (&end_label);\n-\t if (EXPR_HAS_LOCATION (last))\n-\t SET_EXPR_LOCATION (t, EXPR_LOCATION (last));\n+\t if (rexpr_has_location (last))\n+\t SET_EXPR_LOCATION (t, rexpr_location (last));\n \t append_to_statement_list (t, &expr);\n \t}\n if (emit_false)\n@@ -3960,39 +4044,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)\n gimple_push_condition ();\n \n have_then_clause_p = have_else_clause_p = false;\n- if (TREE_OPERAND (expr, 1) != NULL\n- && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR\n- && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL\n- && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))\n-\t == current_function_decl)\n+ label_true = find_goto_label (TREE_OPERAND (expr, 1));\n+ if (label_true\n+ && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl\n /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR\n \t have different locations, otherwise we end up with incorrect\n \t location information on the branches. */\n && (optimize\n \t || !EXPR_HAS_LOCATION (expr)\n-\t || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))\n-\t || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))\n+\t || !rexpr_has_location (label_true)\n+\t || EXPR_LOCATION (expr) == rexpr_location (label_true)))\n {\n- label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));\n have_then_clause_p = true;\n+ label_true = GOTO_DESTINATION (label_true);\n }\n else\n label_true = create_artificial_label (UNKNOWN_LOCATION);\n- if (TREE_OPERAND (expr, 2) != NULL\n- && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR\n- && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL\n- && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))\n-\t == current_function_decl)\n+ label_false = find_goto_label (TREE_OPERAND (expr, 2));\n+ if (label_false\n+ && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl\n /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR\n \t have different locations, otherwise we end up with incorrect\n \t location information on the branches. */\n && (optimize\n \t || !EXPR_HAS_LOCATION (expr)\n-\t || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))\n-\t || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))\n+\t || !rexpr_has_location (label_false)\n+\t || EXPR_LOCATION (expr) == rexpr_location (label_false)))\n {\n- label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));\n have_else_clause_p = true;\n+ label_false = GOTO_DESTINATION (label_false);\n }\n else\n label_false = create_artificial_label (UNKNOWN_LOCATION);\n@@ -11782,6 +11862,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,\n \t ret = GS_ALL_DONE;\n \t break;\n \n+\tcase DEBUG_EXPR_DECL:\n+\t gcc_unreachable ();\n+\n+\tcase DEBUG_BEGIN_STMT:\n+\t gimplify_seq_add_stmt (pre_p,\n+\t\t\t\t gimple_build_debug_begin_stmt\n+\t\t\t\t (TREE_BLOCK (*expr_p),\n+\t\t\t\t EXPR_LOCATION (*expr_p)));\n+\t ret = GS_ALL_DONE;\n+\t *expr_p = NULL;\n+\t break;\n+\n \tcase SSA_NAME:\n \t /* Allow callbacks into the gimplifier during optimization. */\n \t ret = GS_ALL_DONE;\ndiff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h\nindex ea2006c..fa6f247 100644\n--- a/gcc/langhooks-def.h\n+++ b/gcc/langhooks-def.h\n@@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int);\n #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP\tfalse\n #define LANG_HOOKS_DEEP_UNSHARING\tfalse\n #define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS\tfalse\n+#define LANG_HOOKS_EMITS_BEGIN_STMT\tfalse\n #define LANG_HOOKS_RUN_LANG_SELFTESTS lhd_do_nothing\n #define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location\n \n@@ -341,6 +342,7 @@ extern void lhd_end_section (void);\n LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \\\n LANG_HOOKS_DEEP_UNSHARING, \\\n LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \\\n+ LANG_HOOKS_EMITS_BEGIN_STMT, \\\n LANG_HOOKS_RUN_LANG_SELFTESTS, \\\n LANG_HOOKS_GET_SUBSTRING_LOCATION \\\n }\ndiff --git a/gcc/langhooks.h b/gcc/langhooks.h\nindex 88f6f71..8d91cfc 100644\n--- a/gcc/langhooks.h\n+++ b/gcc/langhooks.h\n@@ -524,6 +524,9 @@ struct lang_hooks\n instead of trampolines. */\n bool custom_function_descriptors;\n \n+ /* True if this language emits begin stmt notes. */\n+ bool emits_begin_stmt;\n+\n /* Run all lang-specific selftests. */\n void (*run_lang_selftests) (void);\n \ndiff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c\nindex b1d864f..497a7cf 100644\n--- a/gcc/lra-constraints.c\n+++ b/gcc/lra-constraints.c\n@@ -5269,10 +5269,11 @@ inherit_reload_reg (bool def_p, int original_regno,\n lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));\n if (lra_dump_file != NULL)\n \t{\n+\t basic_block bb = BLOCK_FOR_INSN (usage_insn);\n \t fprintf (lra_dump_file,\n \t\t \" Inheritance reuse change %d->%d (bb%d):\\n\",\n \t\t original_regno, REGNO (new_reg),\n-\t\t BLOCK_FOR_INSN (usage_insn)->index);\n+\t\t bb ? bb->index : -1);\n \t dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));\n \t}\n }\n@@ -5816,6 +5817,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)\n if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)\n \tcontinue;\n curr_bb = BLOCK_FOR_INSN (curr_insn);\n+ if (!curr_bb)\n+\t{\n+\t gcc_assert (DEBUG_INSN_P (curr_insn));\n+\t if (DEBUG_MARKER_INSN_P (curr_insn))\n+\t continue;\n+\t curr_bb = prev_bb;\n+\t}\n if (curr_bb != prev_bb)\n \t{\n \t if (prev_bb != NULL)\ndiff --git a/gcc/lra.c b/gcc/lra.c\nindex 236cef7..4e81d5d 100644\n--- a/gcc/lra.c\n+++ b/gcc/lra.c\n@@ -602,9 +602,9 @@ static struct lra_operand_data debug_operand_data =\n };\n \n /* The following data are used as static insn data for all debug\n- insns. If structure lra_static_insn_data is changed, the\n+ bind insns. If structure lra_static_insn_data is changed, the\n initializer should be changed too. */\n-static struct lra_static_insn_data debug_insn_static_data =\n+static struct lra_static_insn_data debug_bind_static_data =\n {\n &debug_operand_data,\n 0,\t/* Duplication operands #. */\n@@ -618,6 +618,22 @@ static struct lra_static_insn_data debug_insn_static_data =\n NULL /* Descriptions of operands in alternatives.\t*/\n };\n \n+/* The following data are used as static insn data for all debug\n+ marker insns. If structure lra_static_insn_data is changed, the\n+ initializer should be changed too. */\n+static struct lra_static_insn_data debug_marker_static_data =\n+ {\n+ &debug_operand_data,\n+ 0,\t/* Duplication operands #. */\n+ -1, /* Commutative operand #. */\n+ 0,\t/* Operands #.\tThere isn't any operand. */\n+ 0,\t/* Duplications #. */\n+ 0,\t/* Alternatives #. We are not interesting in alternatives\n+\t because we does not proceed debug_insns for reloads.\t */\n+ NULL, /* Hard registers referenced in machine description.\t*/\n+ NULL /* Descriptions of operands in alternatives.\t*/\n+ };\n+\n /* Called once per compiler work to initialize some LRA data related\n to insns. */\n static void\n@@ -951,12 +967,20 @@ lra_set_insn_recog_data (rtx_insn *insn)\n data->regs = NULL;\n if (DEBUG_INSN_P (insn))\n {\n- data->insn_static_data = &debug_insn_static_data;\n data->dup_loc = NULL;\n data->arg_hard_regs = NULL;\n data->preferred_alternatives = ALL_ALTERNATIVES;\n- data->operand_loc = XNEWVEC (rtx *, 1);\n- data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);\n+ if (DEBUG_BIND_INSN_P (insn))\n+\t{\n+\t data->insn_static_data = &debug_bind_static_data;\n+\t data->operand_loc = XNEWVEC (rtx *, 1);\n+\t data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);\n+\t}\n+ else if (DEBUG_MARKER_INSN_P (insn))\n+\t{\n+\t data->insn_static_data = &debug_marker_static_data;\n+\t data->operand_loc = NULL;\n+\t}\n return data;\n }\n if (icode < 0)\n@@ -1602,7 +1626,7 @@ lra_update_insn_regno_info (rtx_insn *insn)\n return;\n data = lra_get_insn_recog_data (insn);\n static_data = data->insn_static_data;\n- freq = get_insn_freq (insn);\n+ freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;\n invalidate_insn_data_regno_info (data, insn, freq);\n uid = INSN_UID (insn);\n for (i = static_data->n_operands - 1; i >= 0; i--)\ndiff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c\nindex 5710e8f..6ffa5f0 100644\n--- a/gcc/lto-streamer-in.c\n+++ b/gcc/lto-streamer-in.c\n@@ -1119,7 +1119,10 @@ input_function (tree fn_decl, struct data_in *data_in,\n \t Similarly remove all IFN_*SAN_* internal calls */\n \t if (!flag_wpa)\n \t {\n-\t if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))\n+\t if (is_gimple_debug (stmt)\n+\t\t && (gimple_debug_nonbind_marker_p (stmt)\n+\t\t ? !MAY_HAVE_DEBUG_MARKER_STMTS\n+\t\t : !MAY_HAVE_DEBUG_BIND_STMTS))\n \t\tremove = true;\n \t if (is_gimple_call (stmt)\n \t\t && gimple_call_internal_p (stmt))\n@@ -1173,6 +1176,13 @@ input_function (tree fn_decl, struct data_in *data_in,\n \t {\n \t gsi_next (&bsi);\n \t stmts[gimple_uid (stmt)] = stmt;\n+\n+\t /* Remember that the input function has begin stmt\n+\t\t markers, so that we know to expect them when emitting\n+\t\t debug info. */\n+\t if (!cfun->debug_nonbind_markers\n+\t\t && gimple_debug_nonbind_marker_p (stmt))\n+\t\tcfun->debug_nonbind_markers = true;\n \t }\n \t}\n }\ndiff --git a/gcc/params.def b/gcc/params.def\nindex 805302b..1d6a494 100644\n--- a/gcc/params.def\n+++ b/gcc/params.def\n@@ -960,6 +960,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,\n \t \"Max. size of loc list for which reverse ops should be added.\",\n \t 50, 0, 0)\n \n+/* Set a threshold to discard debug markers (e.g. debug begin stmt\n+ markers) when expanding a function to RTL, or inlining it into\n+ another function. */\n+\n+DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,\n+\t \"max-debug-marker-count\",\n+\t \"Max. count of debug markers to expand or inline.\",\n+\t 100000, 0, 0)\n+\n /* Set minimum insn uid for non-debug insns. */\n \n DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,\ndiff --git a/gcc/print-rtl.c b/gcc/print-rtl.c\nindex 79ec463..0d36a42 100644\n--- a/gcc/print-rtl.c\n+++ b/gcc/print-rtl.c\n@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,\n \t fputc ('\\t', m_outfile);\n \t break;\n \n+\tcase NOTE_INSN_BEGIN_STMT:\n+#ifndef GENERATOR_FILE\n+\t {\n+\t expanded_location xloc\n+\t = expand_location (NOTE_MARKER_LOCATION (in_rtx));\n+\t fprintf (m_outfile, \" %s:%i\", xloc.file, xloc.line);\n+\t }\n+#endif\n+\t break;\n+\n \tdefault:\n \t break;\n \t}\n@@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)\n \n case DEBUG_INSN:\n {\n+\tif (DEBUG_MARKER_INSN_P (x))\n+\t {\n+\t switch (INSN_DEBUG_MARKER_KIND (x))\n+\t {\n+\t case NOTE_INSN_BEGIN_STMT:\n+\t\tpp_string (pp, \"debug begin stmt marker\");\n+\t\tbreak;\n+\n+\t default:\n+\t\tgcc_unreachable ();\n+\t }\n+\t break;\n+\t }\n+\n \tconst char *name = \"?\";\n \n \tif (DECL_P (INSN_VAR_LOCATION_DECL (x)))\ndiff --git a/gcc/recog.c b/gcc/recog.c\nindex fd4e460..4b4d8f1 100644\n--- a/gcc/recog.c\n+++ b/gcc/recog.c\n@@ -2258,6 +2258,7 @@ extract_insn (rtx_insn *insn)\n case ADDR_VEC:\n case ADDR_DIFF_VEC:\n case VAR_LOCATION:\n+ case DEBUG_MARKER:\n return;\n \n case SET:\ndiff --git a/gcc/rtl.def b/gcc/rtl.def\nindex 4c2607a..ccdaa82 100644\n--- a/gcc/rtl.def\n+++ b/gcc/rtl.def\n@@ -761,6 +761,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, \"entry_value\", \"0\", RTX_OBJ)\n been optimized away completely. */\n DEF_RTL_EXPR(DEBUG_PARAMETER_REF, \"debug_parameter_ref\", \"t\", RTX_OBJ)\n \n+/* Used in marker DEBUG_INSNs to avoid being recognized as an insn. */\n+DEF_RTL_EXPR(DEBUG_MARKER, \"debug_marker\", \"\", RTX_OBJ)\n+\n /* All expressions from this point forward appear only in machine\n descriptions. */\n #ifdef GENERATOR_FILE\ndiff --git a/gcc/tree-inline.c b/gcc/tree-inline.c\nindex 097a893..76c23ad 100644\n--- a/gcc/tree-inline.c\n+++ b/gcc/tree-inline.c\n@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see\n #include \"tree-ssa.h\"\n #include \"except.h\"\n #include \"debug.h\"\n+#include \"params.h\"\n #include \"value-prof.h\"\n #include \"cfgloop.h\"\n #include \"builtins.h\"\n@@ -1347,7 +1348,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)\n gimple_seq stmts = NULL;\n \n if (is_gimple_debug (stmt)\n- && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))\n+ && (gimple_debug_nonbind_marker_p (stmt)\n+\t ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers\n+\t : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))\n return stmts;\n \n /* Begin by recognizing trees that we'll completely rewrite for the\n@@ -1630,6 +1633,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)\n \t gimple_seq_add_stmt (&stmts, copy);\n \t return stmts;\n \t}\n+ if (gimple_debug_nonbind_marker_p (stmt))\n+\t{\n+\t /* If the inlined function has too many debug markers,\n+\t don't copy them. */\n+\t if (id->src_cfun->debug_marker_count\n+\t > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))\n+\t return stmts;\n+\n+\t gdebug *copy = as_a <gdebug *> (gimple_copy (stmt));\n+\t id->debug_stmts.safe_push (copy);\n+\t gimple_seq_add_stmt (&stmts, copy);\n+\t return stmts;\n+\t}\n+ gcc_checking_assert (!is_gimple_debug (stmt));\n \n /* Create a new deep copy of the statement. */\n copy = gimple_copy (stmt);\n@@ -1725,7 +1742,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)\n gimple_set_block (copy, *n);\n }\n \n- if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))\n+ if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)\n+ || gimple_debug_nonbind_marker_p (copy))\n {\n gimple_seq_add_stmt (&stmts, copy);\n return stmts;\n@@ -2599,6 +2617,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)\n \t value = gimple_debug_source_bind_get_value (stmt);\n \t new_stmt = gimple_build_debug_source_bind (var, value, stmt);\n \t }\n+\t else if (gimple_debug_nonbind_marker_p (stmt))\n+\t new_stmt = as_a <gdebug *> (gimple_copy (stmt));\n \t else\n \t gcc_unreachable ();\n \t gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);\n@@ -2915,6 +2935,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)\n gimple_set_block (stmt, n ? *n : id->block);\n }\n \n+ if (gimple_debug_nonbind_marker_p (stmt))\n+ return;\n+\n /* Remap all the operands in COPY. */\n memset (&wi, 0, sizeof (wi));\n wi.info = id;\n@@ -2923,8 +2946,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)\n \n if (gimple_debug_source_bind_p (stmt))\n t = gimple_debug_source_bind_get_var (stmt);\n- else\n+ else if (gimple_debug_bind_p (stmt))\n t = gimple_debug_bind_get_var (stmt);\n+ else\n+ gcc_unreachable ();\n \n if (TREE_CODE (t) == PARM_DECL && id->debug_map\n && (n = id->debug_map->get (t)))\ndiff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c\nindex c485413..10e510d 100644\n--- a/gcc/tree-iterator.c\n+++ b/gcc/tree-iterator.c\n@@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)\n void\n append_to_statement_list (tree t, tree *list_p)\n {\n- if (t && TREE_SIDE_EFFECTS (t))\n+ if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))\n append_to_statement_list_1 (t, list_p);\n }\n \n@@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)\n tail = head;\n }\n \n- TREE_SIDE_EFFECTS (i->container) = 1;\n+ if (TREE_CODE (t) != DEBUG_BEGIN_STMT)\n+ TREE_SIDE_EFFECTS (i->container) = 1;\n \n cur = i->ptr;\n \n@@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)\n tail = head;\n }\n \n- TREE_SIDE_EFFECTS (i->container) = 1;\n+ if (TREE_CODE (t) != DEBUG_BEGIN_STMT)\n+ TREE_SIDE_EFFECTS (i->container) = 1;\n \n cur = i->ptr;\n \n@@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)\n i->ptr = next;\n }\n \n-/* Return the first expression in a sequence of COMPOUND_EXPRs,\n- or in a STATEMENT_LIST. */\n+/* Return the first expression in a sequence of COMPOUND_EXPRs, or in\n+ a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a\n+ STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT. */\n \n tree\n expr_first (tree expr)\n@@ -291,7 +294,20 @@ expr_first (tree expr)\n if (TREE_CODE (expr) == STATEMENT_LIST)\n {\n struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);\n- return n ? n->stmt : NULL_TREE;\n+ if (!n)\n+\treturn NULL_TREE;\n+ while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)\n+\t{\n+\t n = n->next;\n+\t if (!n)\n+\t return NULL_TREE;\n+\t}\n+ /* If the first non-debug stmt is not a statement list, we\n+\t already know it's what we're looking for. */\n+ if (TREE_CODE (n->stmt) != STATEMENT_LIST)\n+\treturn n->stmt;\n+\n+ return expr_first (n->stmt);\n }\n \n while (TREE_CODE (expr) == COMPOUND_EXPR)\n@@ -300,8 +316,9 @@ expr_first (tree expr)\n return expr;\n }\n \n-/* Return the last expression in a sequence of COMPOUND_EXPRs,\n- or in a STATEMENT_LIST. */\n+/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a\n+ STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a\n+ STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT. */\n \n tree\n expr_last (tree expr)\n@@ -312,7 +329,20 @@ expr_last (tree expr)\n if (TREE_CODE (expr) == STATEMENT_LIST)\n {\n struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);\n- return n ? n->stmt : NULL_TREE;\n+ if (!n)\n+\treturn NULL_TREE;\n+ while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)\n+\t{\n+\t n = n->prev;\n+\t if (!n)\n+\t return NULL_TREE;\n+\t}\n+ /* If the last non-debug stmt is not a statement list, we\n+\t already know it's what we're looking for. */\n+ if (TREE_CODE (n->stmt) != STATEMENT_LIST)\n+\treturn n->stmt;\n+\n+ return expr_last (n->stmt);\n }\n \n while (TREE_CODE (expr) == COMPOUND_EXPR)\ndiff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c\nindex c6af413..255f84c 100644\n--- a/gcc/tree-pretty-print.c\n+++ b/gcc/tree-pretty-print.c\n@@ -3291,6 +3291,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,\n pp_string (pp, \"_Cilk_sync\");\n break;\n \n+ case DEBUG_BEGIN_STMT:\n+ pp_string (pp, \"# DEBUG BEGIN STMT\");\n+ break;\n+\n default:\n NIY;\n }\ndiff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c\nindex 70675e4..91793bf 100644\n--- a/gcc/tree-ssa-threadedge.c\n+++ b/gcc/tree-ssa-threadedge.c\n@@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)\n gimple *stmt = gsi_stmt (si);\n if (!is_gimple_debug (stmt))\n \tbreak;\n+ if (gimple_debug_nonbind_marker_p (stmt))\n+\tcontinue;\n i++;\n }\n \n@@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)\n \tvar = gimple_debug_bind_get_var (stmt);\n else if (gimple_debug_source_bind_p (stmt))\n \tvar = gimple_debug_source_bind_get_var (stmt);\n+ else if (gimple_debug_nonbind_marker_p (stmt))\n+\tcontinue;\n else\n \tgcc_unreachable ();\n \n@@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)\n \t var = gimple_debug_bind_get_var (stmt);\n \t else if (gimple_debug_source_bind_p (stmt))\n \t var = gimple_debug_source_bind_get_var (stmt);\n+\t else if (gimple_debug_nonbind_marker_p (stmt))\n+\t continue;\n \t else\n \t gcc_unreachable ();\n \n-\t /* Discard debug bind overlaps. ??? Unlike stmts from src,\n+\t /* Discard debug bind overlaps. Unlike stmts from src,\n \t copied into a new block that will precede BB, debug bind\n \t stmts in bypassed BBs may actually be discarded if\n-\t they're overwritten by subsequent debug bind stmts, which\n-\t might be a problem once we introduce stmt frontier notes\n-\t or somesuch. Adding `&& bb == src' to the condition\n-\t below will preserve all potentially relevant debug\n-\t notes. */\n+\t they're overwritten by subsequent debug bind stmts. We\n+\t want to copy binds for all modified variables, so that we\n+\t retain a bind to the shared def if there is one, or to a\n+\t newly introduced PHI node if there is one. Our bind will\n+\t end up reset if the value is dead, but that implies the\n+\t variable couldn't have survived, so it's fine. We are\n+\t not actually running the code that performed the binds at\n+\t this point, we're just adding binds so that they survive\n+\t the new confluence, so markers should not be copied. */\n \t if (vars && vars->add (var))\n \t continue;\n \t else if (!vars)\n@@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)\n \t\t break;\n \t if (i >= 0)\n \t\tcontinue;\n-\n-\t if (fewvars.length () < (unsigned) alloc_count)\n+\t else if (fewvars.length () < (unsigned) alloc_count)\n \t\tfewvars.quick_push (var);\n \t else\n \t\t{\ndiff --git a/gcc/tree.c b/gcc/tree.c\nindex c493edd5..5e98e46 100644\n--- a/gcc/tree.c\n+++ b/gcc/tree.c\n@@ -1013,7 +1013,8 @@ make_node (enum tree_code code MEM_STAT_DECL)\n switch (type)\n {\n case tcc_statement:\n- TREE_SIDE_EFFECTS (t) = 1;\n+ if (code != DEBUG_BEGIN_STMT)\n+\tTREE_SIDE_EFFECTS (t) = 1;\n break;\n \n case tcc_declaration:\n@@ -4405,7 +4406,10 @@ build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)\n }\n \n if (TREE_CODE_CLASS (code) == tcc_statement)\n- TREE_SIDE_EFFECTS (t) = 1;\n+ {\n+ if (code != DEBUG_BEGIN_STMT)\n+\tTREE_SIDE_EFFECTS (t) = 1;\n+ }\n else switch (code)\n {\n case VA_ARG_EXPR:\ndiff --git a/gcc/tree.def b/gcc/tree.def\nindex 9f80c4d..e30e950 100644\n--- a/gcc/tree.def\n+++ b/gcc/tree.def\n@@ -382,6 +382,9 @@ DEFTREECODE (RESULT_DECL, \"result_decl\", tcc_declaration, 0)\n DEBUG stmts. */\n DEFTREECODE (DEBUG_EXPR_DECL, \"debug_expr_decl\", tcc_declaration, 0)\n \n+/* A stmt that marks the beginning of a source statement. */\n+DEFTREECODE (DEBUG_BEGIN_STMT, \"debug_begin_stmt\", tcc_statement, 0)\n+\n /* A namespace declaration. Namespaces appear in DECL_CONTEXT of other\n _DECLs, providing a hierarchy of names. */\n DEFTREECODE (NAMESPACE_DECL, \"namespace_decl\", tcc_declaration, 0)\ndiff --git a/gcc/tree.h b/gcc/tree.h\nindex be299b9..379efa8 100644\n--- a/gcc/tree.h\n+++ b/gcc/tree.h\n@@ -1225,7 +1225,7 @@ extern void protected_set_expr_location (tree, location_t);\n \n /* GOTO_EXPR accessor. This gives access to the label associated with\n a goto statement. */\n-#define GOTO_DESTINATION(NODE) TREE_OPERAND ((NODE), 0)\n+#define GOTO_DESTINATION(NODE) TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)\n \n /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the\n instruction (e.g., \"mov x, y\"). ASM_OUTPUTS, ASM_INPUTS, and\ndiff --git a/gcc/var-tracking.c b/gcc/var-tracking.c\nindex d554a35..8f283b7 100644\n--- a/gcc/var-tracking.c\n+++ b/gcc/var-tracking.c\n@@ -9918,6 +9918,36 @@ vt_init_cfa_base (void)\n cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));\n }\n \n+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note. */\n+\n+static rtx_insn *\n+reemit_marker_as_note (rtx_insn *insn, basic_block *bb)\n+{\n+ gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));\n+\n+ enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);\n+\n+ switch (kind)\n+ {\n+ case NOTE_INSN_BEGIN_STMT:\n+ {\n+\trtx_insn *note = NULL;\n+\tif (cfun->debug_nonbind_markers)\n+\t {\n+\t note = emit_note_before (kind, insn);\n+\t NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);\n+\t if (bb)\n+\t BLOCK_FOR_INSN (note) = *bb;\n+\t }\n+\tdelete_insn (insn);\n+\treturn note;\n+ }\n+\n+ default:\n+ gcc_unreachable ();\n+ }\n+}\n+\n /* Allocate and initialize the data structures for variable tracking\n and parse the RTL to get the micro operations. */\n \n@@ -10161,6 +10191,12 @@ vt_initialize (void)\n \n \t\t cselib_hook_called = false;\n \t\t adjust_insn (bb, insn);\n+\t\t if (DEBUG_MARKER_INSN_P (insn))\n+\t\t {\n+\t\t insn = reemit_marker_as_note (insn, &save_bb);\n+\t\t continue;\n+\t\t }\n+\n \t\t if (MAY_HAVE_DEBUG_BIND_INSNS)\n \t\t {\n \t\t if (CALL_P (insn))\n@@ -10237,10 +10273,11 @@ vt_initialize (void)\n \n static int debug_label_num = 1;\n \n-/* Get rid of all debug insns from the insn stream. */\n+/* Remove from the insn stream all debug insns used for variable\n+ tracking at assignments. */\n \n static void\n-delete_debug_insns (void)\n+delete_vta_debug_insns (void)\n {\n basic_block bb;\n rtx_insn *insn, *next;\n@@ -10256,6 +10293,12 @@ delete_debug_insns (void)\n \t insn = next)\n \tif (DEBUG_INSN_P (insn))\n \t {\n+\t if (DEBUG_MARKER_INSN_P (insn))\n+\t {\n+\t\tinsn = reemit_marker_as_note (insn, NULL);\n+\t\tcontinue;\n+\t }\n+\n \t tree decl = INSN_VAR_LOCATION_DECL (insn);\n \t if (TREE_CODE (decl) == LABEL_DECL\n \t\t&& DECL_NAME (decl)\n@@ -10281,10 +10324,13 @@ delete_debug_insns (void)\n handled as well.. */\n \n static void\n-vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)\n+vt_debug_insns_local (bool skipped)\n {\n- /* ??? Just skip it all for now. */\n- delete_debug_insns ();\n+ /* ??? Just skip it all for now. If we skipped the global pass,\n+ arrange for stmt markers to be dropped as well. */\n+ if (skipped)\n+ cfun->debug_nonbind_markers = 0;\n+ delete_vta_debug_insns ();\n }\n \n /* Free the data structures needed for variable tracking. */\n@@ -10349,15 +10395,21 @@ variable_tracking_main_1 (void)\n {\n bool success;\n \n- if (flag_var_tracking_assignments < 0\n+ /* We won't be called as a separate pass if flag_var_tracking is not\n+ set, but final may call us to turn debug markers into notes. */\n+ if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)\n+ || flag_var_tracking_assignments < 0\n /* Var-tracking right now assumes the IR doesn't contain\n \t any pseudos at this point. */\n || targetm.no_register_allocation)\n {\n- delete_debug_insns ();\n+ delete_vta_debug_insns ();\n return 0;\n }\n \n+ if (!flag_var_tracking)\n+ return 0;\n+\n if (n_basic_blocks_for_fn (cfun) > 500 &&\n n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)\n {\n@@ -10379,7 +10431,9 @@ variable_tracking_main_1 (void)\n {\n vt_finalize ();\n \n- delete_debug_insns ();\n+ cfun->debug_nonbind_markers = 0;\n+\n+ delete_vta_debug_insns ();\n \n /* This is later restored by our caller. */\n flag_var_tracking_assignments = 0;\n", "prefixes": [ "4/9", "SFN" ] }