On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aol...@redhat.com> 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<c_token>);
>  static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
>
> +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
> +
> +static void
> +add_debug_begin_stmt (location_t loc)
> +{
> +  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
> +    return;
> +
> +  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
> +  SET_EXPR_LOCATION (stmt, loc);
> +  add_stmt (stmt);
> +}
> +
>  /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
>     6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
>     is accepted; otherwise (old-style parameter declarations) only other
> @@ -1740,6 +1753,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
> fndef_ok,
>    bool diagnosed_no_specs = false;
>    location_t here = c_parser_peek_token (parser)->location;
>
> +  add_debug_begin_stmt (c_parser_peek_token (parser)->location);
> +
>    if (static_assert_ok
>        && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
>      {
> @@ -4949,6 +4964,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
>    location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
>    if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
>      {
> +      add_debug_begin_stmt (c_parser_peek_token (parser)->location);
>        c_parser_consume_token (parser);
>        return;
>      }
> @@ -5403,6 +5419,10 @@ c_parser_statement_after_labels (c_parser *parser, 
> bool *if_p,
>    parser->in_if_block = false;
>    if (if_p != NULL)
>      *if_p = false;
> +
> +  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
> +    add_debug_begin_stmt (loc);
> +
>    switch (c_parser_peek_token (parser)->type)
>      {
>      case CPP_OPEN_BRACE:
> 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 <gcall *> (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<basic_block, rtx_code_label *>;
>    FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
>                   next_bb)
> diff --git a/gcc/cp/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<constructor_elt, va_gc> **vec)
>        tree_stmt_iterator i;
>        for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>         {
> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +           /* ??? Can we retain this information somehow?  */
> +           continue;
>           if (! build_data_member_initialization (tsi_stmt (i), vec))
>             return false;
>         }
> @@ -448,6 +451,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
>
>      case USING_STMT:
>      case STATIC_ASSERT:
> +    case DEBUG_BEGIN_STMT:
>        return true;
>
>      default:
> @@ -586,6 +590,9 @@ build_constexpr_constructor_member_initializers (tree 
> type, tree body)
>        tree_stmt_iterator i;
>        for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
>         {
> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +           /* ??? Can we retain this information somehow?  */
> +           continue;
>           ok = build_data_member_initialization (tsi_stmt (i), &vec);
>           if (!ok)
>             break;
> @@ -673,6 +680,7 @@ constexpr_fn_retval (tree body)
>        return constexpr_fn_retval (BIND_EXPR_BODY (body));
>
>      case USING_STMT:
> +    case DEBUG_BEGIN_STMT:
>        return NULL_TREE;
>
>      default:
> @@ -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 <gdebug *> (
> +        gimple_build_with_ops_stat (GIMPLE_DEBUG,
> +                                   (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
> +                                   PASS_MEM_STAT));
> +
> +  gimple_set_location (p, location);
> +  gimple_set_block (p, block);
> +  cfun->debug_marker_count++;
> +
> +  return p;
> +}
> +
> +
>  /* Build a GIMPLE_OMP_CRITICAL statement.
>
>     BODY is the sequence of statements for which only one thread can execute.
> @@ -1874,6 +1895,9 @@ gimple_copy (gimple *stmt)
>        gimple_set_modified (copy, true);
>      }
>
> +  if (gimple_debug_nonbind_marker_p (stmt))
> +    cfun->debug_marker_count++;
> +
>    return copy;
>  }
>
> 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<tree> );
>  geh_dispatch *gimple_build_eh_dispatch (int);
>  gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
>  gdebug *gimple_build_debug_source_bind (tree, tree, gimple * 
> CXX_MEM_STAT_INFO);
> +gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
>  gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
>  gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
>  gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 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 <rtx_insn *> (usage_insn));
>        if (lra_dump_file != NULL)
>         {
> +         basic_block bb = BLOCK_FOR_INSN (usage_insn);
>           fprintf (lra_dump_file,
>                    "    Inheritance reuse change %d->%d (bb%d):\n",
>                    original_regno, REGNO (new_reg),
> -                  BLOCK_FOR_INSN (usage_insn)->index);
> +                  bb ? bb->index : -1);
>           dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
>         }
>      }
> @@ -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 <gdebug *> (gimple_copy (stmt));
> +         id->debug_stmts.safe_push (copy);
> +         gimple_seq_add_stmt (&stmts, copy);
> +         return stmts;
> +       }
> +      gcc_checking_assert (!is_gimple_debug (stmt));
>
>        /* Create a new deep copy of the statement.  */
>        copy = gimple_copy (stmt);
> @@ -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 <gdebug *> (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
>

Reply via email to