This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views)
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Alexandre Oliva <aoliva at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 21 Aug 2017 14:01:19 +0200
- Subject: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views)
- Authentication-results: sourceware.org; auth=none
- References: <or8tk2eaij.fsf@lxoliva.fsfla.org> <orshi0lbmo.fsf@lxoliva.fsfla.org> <ork22060a6.fsf_-_@lxoliva.fsfla.org>
..
On Fri, Aug 18, 2017 at 11:20 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Jul 13, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:
>
>> On Jul 5, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:
>>> This patch implements statement frontier notes and location views,
>>> concepts originally proposed in the GCC Summit back in 2010. See
>>> https://people.redhat.com/aoliva/papers/sfn/ for details on the
>>> original design.
>
>> There's a newer blog post about these features that provides further
>> context and motivation.
>> https://developers.redhat.com/blog/2017/07/11/statement-frontier-notes-and-location-views/#more-437095
>
>
>> I wonder if it would be useful to break up the patch into smaller
>> pieces, for purposes of review. The changes are mostly interdependent,
>> though it is possible to break it up into major features, say one patch
>> introducing statement frontier notes, one or more patches fixing new
>> -fcompare-debug failures, and one patch introducing location views. The
>> changes are largely split up like that in the aoliva/SFN branch, though
>> I don't think it would be appropriate to install these changes as such a
>> sequence of patches, though, because I don't think it's adequate to have
>> known regressions, even if temporarily, and the initial SFN patch,
>> without the subsequent -fcompare-debug fixes, would do just that.
>
>> Thoughts? Advice?
>
> Here's a refreshed/retested/improved version of the patchset. It
> changes the representation of debug begin stmt insns, and introduces
> inlined entry point markers, combining them into nonbind markers
> (earlier debug stmts, insns and notes all bind decls besides just
> marking a point in the program). All the changes are visible in smaller
> (but not consolidated) logical changes in the GIT branch aoliva/SFN.
> FWIW, I'm speaking about this project at the upcoming GNU Tools Cauldron.
>
>
> This was successfully regstrapped (before a few cosmetic changes; almost
> done with them too) on x86_64-linux-gnu and i686-linux-gnu; I'm
> repeating the test plan described in the original patch, retained at the
> end of the patch description. Ok to install?
>
>
> ----
>
> This patch implements statement frontier notes and location views,
> concepts originally proposed in the GCC Summit back in 2010. See
> https://people.redhat.com/aoliva/papers/sfn/ for details on the
> original design. It also introduces markers for entry points of
> inlined functions as a variation of statement frontier markers.
>
> Statement Frontier Notes are implemented very much as described in the
> original paper. Early in compilation (when both optimization and
> debug info are enabled), we emit markers denoting the beginning of
> each source-level statement (currently supported languages are those
> in the C and C++ families; parsers of other languages have to be
> adjusted to emit frontier markers). These markers are initially
> emitted as trees, lowered to gimple debug stmts, expanded to debug
> insns, and finally converted to notes. Throughout compilation, they
> remain in place, just like VTA's debug stmts and insns, and as such
> they provide reliable for the generation of DWARF's is_stmt flag in
> line number tables. This flag indicates recommended breakpoints.
>
> Alas, because of optimization, such recommended breakpoints may pile
> up at instructions associated with different line numbers. Debug
> information consumers had no way to distinguish the multiple source
> program states that all map to the same executable instruction.
>
> Location views introduce a means for the compiler to name and refer to
> such overlapping states, so that variable location lists can indicate
> which of multiple states at the same instruction starts or ends each
> range, and debug information consumers can then stop at the desired
> state and inspect variables at it.
>
> The naming of overlapping source program states is introduced by means
> of a reinterpretation of line number programs, so no additional
> encoding is necessary. The line number programs can still be emitted
> internally by GCC or by an assembler, through ".loc" directives. If
> GCC finds the assembler to support "view" labels at configure time, it
> will rely on the assembler for line number generation in compilations
> that have location views enabled. Otherwise, it will resort to
> internally-generated line number programs. A patch about to be
> contributed to binutils will add support for "view" labels in ".loc"
> directives to the assembler.
>
> Location views are NOT emitted as proposed in the original paper.
> Location lists have been significantly revamped in DWARF5, and we have
> a proposal for DWARF6 that extends them with location views (see
> dwarf6-sfn-lvu.txt in the same papers/sfn/ directory mentioned above).
> Since location lists are not extensible in DWARF, for DWARF<=5 we emit
> them as a separate list, as proposed in the original paper, but
> pointed to by a DW_AT_GNU_locviews attribute rather than just having
> its presence indicated by a flag. With -gdwarf-6, we emit DWARF5
> (warning that this is the version we're using, in spite of the
> option), with loclists extended as proposed for DWARF6.
>
>
> Inlined entry points could already be represented with DW_AT_entry_pc
> for inlined subroutines, but we didn't always ensure it was at the
> exact place. With statement frontier notes infrastructure, we emit a
> marker right after binding the incoming arguments, before entering the
> inlined blocks. We can then emit DW_AT_entry_pc, and also
> DW_AT_entry_view, if the entry point is at a nonzero view number, if
> we it does not seem that they coincide with DW_AT_low_pc.
>
> In some cases, the inlined entry point is replicated within a
> function, say by loop unrolling, or by other forms of basic block
> duplication. There is no way to represent such replicated entry
> points, unfortunately, but we are investigating the possibilities of
> accomplishing that through further DWARF extensions.
>
>
> Statement Frontier Notes makes is_stmt generation more precise and
> predictable, no matter how much instructions are shuffled by
> optimization. This feature is enabled by default in optimized builds,
> when emitting DWARF2+ debug information at normal or higher level. It
> can be explicitly enabled in any other situations with
> -gstatement-frontiers, or disabled with -gno-statement-frontiers.
> This also enables inlined entry point markers.
>
> Location views, in turn, avoid regressions when a recommended
> breakpoint is one of multiple states at the same instruction. This
> feature is enabled by default in var-tracking compilations, when
> emitting non-strict DWARF2+ debug information at normal or higher
> level. It can be explicitly enabled with -gvariable-location-views,
> or disabled with -gno-variable-location-views.
>
> Combined, these two features make it more likely that there is a
> usable inspection point for every statement, and that single stepping
> can reliably advance to a subsequent statement, instead of bouncing to
> earlier statements, as we used to do in optimized programs. They also
> make room for such advanced features as single-stepping from one
> source statement to another and inspecting changes to variables, even
> when no executable instructions separate the recommended breakpoints
> for these two states.
>
>
> Besides implementing these new features, the patch contains multiple
> fixes for -fcompare-debug errors detected at various optimization
> levels, arising mainly from the introduction of begin stmt and inlined
> entry point markers.
Can you try to split those out?
> Earlier debug position markers (namely stmts,
> insns and notes) are now referred as bind debug markers, since they
> all bind a declaration to an expression, whereas the newly-introduced
> ones are now referenced as nonbind markers.
>
>
> This patch was tested at multiple optimization levels and
> configurations, such as:
>
> - with or without assembler support for loc views
>
> - default (bootstrap-O2), bootstrap-O1 and bootstrap-O3
>
> - -O0 -g -fcompare-debug=-gstatement-frontiers in stage4
>
> - bootstrap-debug-lean bootstrap-debug-lib to exercise -fcompare-debug
> for stage3, target libs, and tests
>
Few comments (mostly on middle-end, non-RTL stuff, leaving the rest
to others):
+gno-statement-frontiers
+Common Driver RejectNegative Var(debug_nonbind_markers_p, 0) Init(2)
+Don't enforce progressive recommended breakpoint locations.
+
+gstatement-frontiers
+Common Driver RejectNegative Var(debug_nonbind_markers_p, 1)
+Emit progressive recommended breakpoint locations.
others get away with a single flag and Init(-1). That is, -gstatement-frontiers
should set it to 1 already and -gno- to 0. Why do you need the explicit
entry for gno-..?
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (DEBUG_INSN_P (insn))
+ if (BIND_DEBUG_INSN_P (insn))
{
DEBUG_BIND_INSN_P? GIMPLE has gimple_debug_bind_p ...
+ /* 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;
+
if they are not a problem up until here why care now? That said,
what's the number
of markers per GIMPLE stmt for optimized builds of tramp3d-v4.cpp? [it has
around 10 original function calls per generated assembler line]
Would a better option be to condense multiple adjacent notes to a single one?
That way we'd have a natural bound as fallback.
I expect heavily abstracted C++ to blow up GIMPLE IL considerably that way...
Did you see what these do to memory/compile-time use with a LTO bootstrap?
+ if (MARKER_DEBUG_INSN_P (insn))
+ return true;
+
DEBUG_MARKER_INSN_P
+/* Return the next insn after INSN that is not a DEBUG_INSN. This
+ routine does not look inside SEQUENCEs. */
rtx_insn *
-next_nonnote_insn_bb (rtx_insn *insn)
+next_nondebug_insn (rtx_insn *insn)
{
while (insn)
{
sometimes I hate unified diffs .... this and the part following is
unreadable.
@@ -573,6 +573,8 @@ gsi_remove (gimple_stmt_iterator *i, bool
remove_permanently)
if (remove_permanently)
{
+ if (gimple_debug_nonbind_marker_p (stmt))
+ cfun->debug_marker_count--;
require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
gimple_remove_stmt_histograms (cfun, stmt);
}
hmm, you're now relying on remove_permanently to tell the truth.
I do remember ggc_free ()ing the gimple here doesn't work.
+ gdebug *p
+ = as_a <gdebug *> (
+ gimple_build_with_ops_stat (GIMPLE_DEBUG,
+ (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+ PASS_MEM_STAT));
heh, we need a gimple_build <gdebug> (....) abstraction to make all this
nicer (well, probably overkill, just used in internal gimple.c)
Reading the patch both BEGIN_STMT and INLINE_ENTRY are just
free-floating notes in GIMPLE to be not re-ordered. This means
they could use gimple as base instead of gimple_statement_with_ops, no?
Saving two pointers or nearly half size? Could it also hold a vector of
locations so we can optimize adjacent stmt-start stmts, maybe even
also cover the inline thing? We'd have a maximum of 1 such stmt
per other stmt in GIMPLE (and also RTL?).
+static location_t
+expr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
...
+static inline bool
+expr_has_location (tree expr)
...
_please_ do not just use lower-case names for sth subtly different
from their upper-case part...
It would be nice to split out some of the mechanical changes, like
function renaming or gsi_last_bb to gsi_last_nondebug_bb for example
to shrink the parts that need "real" review. I'll happily ack those split
out parts quickly.
+ else if (gimple_debug_nonbind_marker_p (stmt))
+ {
+ new_stmt = as_a <gdebug *> (gimple_copy (stmt));
+ }
extra braces
Skimmed over the whole patch now, I think it looks reasonably ok.
Let's get rid of the noise and acks from the DWARF people.
Btw, just asking as I helped to get the GIMPLE FE in, did you
consider adding GIMPLE FE support for the various debug stmts
we then have? First thing would be arriving at a syntax I guess.
__DEBUG x = ...; for binds, __STMT; __INLINE; for the other two?
Not sure how to express they encode some location though...
(binds have no location, right?)
Thanks,
Richard.
>
> for include/ChangeLog
>
> * dwarf2.def (DW_AT_GNU_locviews, DW_AT_GNU_entry_view): New.
> * dwarf2.h (enum dwarf_location_list_entry_type): Add
> DW_LLE_GNU_view_pair.
> (DW_LLE_view_pair): Define.
>
> for gcc/ChangeLog
>
> * cfgbuild.c (find_bb_boundaries): Skip debug insns.
> * cfgexpand.c (label_rtx_for_bb): Likewise.
> (expand_gimple_basic_block): Likewise. Handle begin stmt and
> inline entry markers.
> (expand_debug_locations): Handle bind debug insns only.
> (pass_expand::execute): Check debug marker limit.
> * cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
> (rtl_tidy_fallthru_edge): Likewise.
> (get_last_bb_insn): Likewise.
> (rtl_verify_fallthru): Likewise.
> (rtl_verify_bb_layout): Likewise.
> (skip_insns_after_block): Likewise.
> (duplicate_insn_chain): Use BIND_DEBUG_INSN_P.
> * common.opt (gstatement-frontiers): New, setting
> debug_nonbind_markers_p.
> (gvariable-location-views): New.
> * config.in: Rebuilt.
> * config/aarch64/aarch64.c (aarch64_output_mi_thunk): Adjust.
> * config/alpha/alpha.c (alpha_output_mi_thunk_osf): Likewise.
> * config/arm/arm.c (arm_thumb1_mi_thunk): Likewise.
> (arm32_output_mi_thunk): Likewise.
> * config/cris/cris.c (cris_asm_output_mi_thunk): Likewise.
> * config/i386/i386.c (ix86_code_end): Likewise.
> (x86_output_mi_thunk): Likewise.
> * config/ia64/ia64.c (ia64_output_mi_thunk): Likewise.
> * config/m68k/m68k.c (m68k_output_mi_thunk): Likewise.
> * config/microblaze/microblaze.c (microblaze_asm_output_mi_thunk):
> Likewise.
> * config/mips/mips.c (mips_output_mi_thunk): Likewise.
> * config/nds32/nds32.c (nds32_asm_output_mi_thunk): Likewise.
> * config/nios2/nios2.c (nios2_asm_output_mi_thunk): Likewise.
> * config/pa/pa.c (pa_asm_output_mi_thunk): Likewise.
> * config/rs6000/rs6000.c (rs6000_output_mi_thunk): Likewise.
> (rs6000_code_end): Likewise.
> * config/s390/s390.c (s390_output_mi_thunk): Likewise.
> * config/sh/sh.c (sh_output_mi_thunk): Likewise.
> * config/sparc/sparc.c (sparc_output_mi_thunk): Likewise.
> * config/spu/spu.c (spu_output_mi_thunk): Likewise.
> * config/tilegx/tilegx.c (tilegx_output_mi_thunk): Likewise.
> * config/tilepro/tilepro.c (tilepro_asm_output_mi_thunk): Likewise.
> * configure: Rebuilt.
> * configure.ac: Test assembler for view support.
> * cse.c (insn_live_p): Keep nonbind markers and debug bindings
> followed by them.
> (delete_trivially_dead_insns): Handle debug bindings.
> * debug.h (gcc_debug_hooks): Add inline_entry.
> * dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
> * debug.c (do_nothing_debug_hooks): Likewise.
> * sdbout.c (sdb_debug_hooks): Likewise.
> * vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
> * df-scan.c (df_insn_delete): Accept out-of-block debug insn.
> * doc/generic.texi (DEBUG_BEGIN_STMT): Document.
> * doc/gimple.texi (gimple_debug_begin_stmt_p): New.
> (gimple_build_debug_bind): Adjust.
> (gimple_build_debug_begin_stmt): New.
> * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
> (gvariable-location-views, gno-variable-location-views): New.
> (max-debug-marker-count): New param.
> * doc/rtl.texi (NOTE_INSN_BEGIN_STMT): New.
> (DEBUG_INSN): Describe begin stmt markers.
> * dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
> * dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
> * dwarf2out.c: Include print-rtl.h.
> (var_loc_view): New typedef.
> (struct dw_loc_list_struct): Add vl_symbol, vbegin, vend.
> (dwarf2out_locviews_in_attribute): New.
> (dwarf2out_locviews_in_loclist): New.
> (dw_val_equal_p): Compare val_view_list of dw_val_class_view_lists.
> (dwarf2_debug_hooks, dwarf2_lineno_debug_hooks): Add
> inline_entry.
> (BLOCK_INLINE_ENTRY_LABEL): New.
> (enum dw_line_info_opcode): Add LI_adv_address.
> (struct dw_line_info_table): Add view.
> (RESET_NEXT_VIEW, RESETTING_VIEW_P): New macros.
> (DWARF2_ASM_VIEW_DEBUG_INFO): Define default.
> (zero_view_p): New variable.
> (ZERO_VIEW_P): New macro.
> (output_asm_line_debug_info): New.
> (struct var_loc_node): Add view.
> (add_AT_view_list, AT_loc_list): New.
> (add_var_loc_to_decl): Add view param. Test it against last.
> (new_loc_list): Add view params. Record them.
> (AT_loc_list_ptr): Handle loc and view lists.
> (view_list_to_loc_list_val_node): New.
> (print_dw_val): Handle dw_val_class_view_list.
> (size_of_die): Likewise.
> (value_format): Likewise.
> (loc_list_has_views): New.
> (gen_llsym): Set vl_symbol too.
> (maybe_gen_llsym, skip_loc_list_entry): New.
> (dwarf2out_maybe_output_loclist_view_pair): New.
> (output_loc_list): Output view list or entries too.
> (output_view_list_offset): New.
> (output_die): Handle dw_val_class_view_list.
> (output_dwarf_version): New.
> (output_compilation_unit_header): Use it.
> (output_skeleton_debug_sections): Likewise.
> (output_rnglists, output_line_info): Likewise.
> (output_pubnames, output_aranges): Update version comments.
> (output_one_line_info_table): Output view numbers in asm comments.
> (dw_loc_list): Determine current endview, pass it to new_loc_list.
> Call maybe_gen_llsym.
> (loc_list_from_tree_1): Adjust.
> (add_AT_location_description): Create view list attribute if
> needed, check it's absent otherwise.
> (convert_cfa_to_fb_loc_list): Adjust.
> (inline_entry_data): New struct.
> (inline_entry_data_hasher): New hashtable type.
> (inline_entry_data_hasher::hash): New.
> (inline_entry_data_hasher::equal): New.
> (inline_entry_data_table): New variable.
> (add_high_low_attributes): Add DW_AT_entry_pc and
> DW_AT_GNU_entry_view attributes if a pending entry is found
> in inline_entry_data_table. Add old entry_pc attribute only
> if debug nonbinding markers are disabled.
> (gen_inlined_subroutine_die): Set BLOCK_DIE if nonbinding
> markers are enabled.
> (maybe_emit_file): Call output_asm_line_debug_info for test.
> (dwarf2out_next_real_insn): New.
> (dwarf2out_var_location): Call it. Reset views as needed. Disregard
> begin stmt and inline entry markers. Precompute
> add_var_loc_to_decl args. Call get_attr_min_length only if we
> have the attribute. Set view. Dump debug binds in asm comments.
> (block_within_block_p, dwarf2out_inline_entry): New.
> (new_line_info_table): Reset next view.
> (set_cur_line_info_table): Call output_asm_line_debug_info for test.
> (dwarf2out_source_line): Likewise. Output view resets and labels to
> the assembler, or select appropriate line info opcodes.
> (prune_unused_types_walk_attribs): Handle dw_val_class_view_list.
> (optimize_string_length): Catch it. Adjust.
> (resolve_addr): Copy vl_symbol along with ll_symbol. Handle
> dw_val_class_view_list, and remove it if no longer needed.
> (hash_loc_list): Hash view numbers.
> (loc_list_hasher::equal): Compare them.
> (optimize_location_lists): Check whether a view list symbol is
> needed, and whether the locview attribute is present, and
> whether they match. Remove the locview attribute if no longer
> needed.
> (index_location_lists): Call skip_loc_list_entry for test.
> (dwarf2out_finish): Call output_asm_line_debug_info for test.
> Check that no entries remained in inline_entry_data_table.
> Use output_dwarf_version.
> * dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
> (struct dw_val_node): Add val_view_list.
> * emit-rtl.c (next_nondebug_insn, prev_nondebug_insn): Reorder.
> (next_nonnote_nondebug_insn, prev_nonnote_nondebug_insn): Reorder.
> (next_nonnote_nondebug_insn_bb): New.
> (prev_nonnote_nondebug_insn_bb): New.
> (prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove.
> * final.c: Include langhooks.h.
> (SEEN_NEXT_VIEW): New.
> (reemit_insn_block_notes): Take current block from nonbind
> markers. Declare note where it's first set.
> (set_next_view_needed): New.
> (clear_next_view_needed): New.
> (maybe_output_next_view): New.
> (final_start_function): Rename to...
> (final_start_function_1): ... this. Take pointer to FIRST,
> add SEEN parameter. Emit param bindings in the initial view.
> (final_start_function): Reintroduce SEEN-less interface.
> (final): Rename to...
> (final_1): ... this. Take SEEN parameter. Output final pending
> next view at the end.
> (final): Reintroduce seen-less interface.
> (final_scan_insn): Output pending next view before switching
> sections or ending a block. Mark the next view as needed when
> outputting variable locations. Handle begin stmt and inline
> entry markers. Emit is_stmt according to begin stmt markers
> if enabled. Notify debug backend of section changes, and of
> location view changes.
> (notify_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. Adjust.
> (rest_of_clean_state): Skip begin stmt and inline entry markers.
> * function.c (instantiate_virtual_regs): Skip debug markers,
> adjust handling of debug binds.
> (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_find_edge_insert_loc): Skip gimple debug stmts.
> * gimple-iterator.h (gsi_start_bb_nondebug): Remove; adjust
> callers to use gsi_start_nondebug_bb instead.
> (gsi_after_labels): Skip gimple debug stmts.
> (gsi_start_nondebug): New.
> * 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_seq_may_fallthru): Take last nondebug stmt.
> * gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
> and inline entry markers.
> * gimple.c (gimple_build_debug_begin_stmt): New.
> (gimple_build_debug_inline_entry): New.
> (gimple_copy): Increment debug_marker_count if copying one.
> * gimple.h (enum gimple_debug_subcode): Add
> GIMPLE_DEBUG_BEGIN_STMT and GIMPLE_DEBUG_INLINE_ENTRY.
> (gimple_build_debug_begin_stmt): Declare.
> (gimple_build_debug_inline_entry): Declare.
> (gimple_seq_last_nondebug_stmt): New.
> (gimple_debug_begin_stmt_p): New.
> (gimple_debug_inline_entry_p): New.
> (gimple_debug_nonbind_marker_p): New.
> * gimplify.c (expr_location): New.
> (expr_has_location): New.
> (warn_switch_unreachable_r): Handle gimple debug stmts.
> (last_stmt_in_scope): Skip debug stmts.
> (collect_fallthrough_labels): Likewise.
> (should_warn_for_implicit_fallthrough): Likewise.
> (warn_implicit_fallthrough_r): Likewise.
> (expand_FALLTHROUGH_r): Likewise.
> (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.
> * graphite-isl-ast-to-gimple.c (gsi_insert_earliest): Adjust.
> (rename_uses): Skip nonbind markers.
> * graphite-scop-detection.c (trivially_empty_bb_p): Call
> is_gimple_debug in test.
> * haifa-sched.c (sched_extend_bb): Skip debug insns.
> * insn-notes.def (BEGIN_STMT, INLINE_ENTRY): New.
> * ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
> * ira.c (combine_and_move_insns): Adjust bind debug insns only.
> * jump.c (clean_barriers): Skip debug insns.
> * langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New. Add to...
> (LANG_HOOKS_INITIALIZER): ... this.
> * langhooks.h (struct lang_hooks): Add emits_begin_stmt.
> * loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
> debug insns.
> * 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): Adjust
> debug_nonbind_markers.
> * omp-expand.c (expand_parallel_call): Skip debug insns.
> (expand_cilk_for_call): Likewise.
> (expand_task_call): Likewise.
> (remove_exit_barrier): Likewise.
> (expand_omp_taskreg): Likewise.
> (expand_omp_for_init_counts): Likewise.
> (expand_omp_for_generic): Likewise.
> (expand_omp_for_static_nochunk): Likewise.
> (expand_omp_for_static_chunk): Likewise.
> (expand_cilk_for): Likewise.
> (expand_omp_simd): Likewise.
> (expand_omp_taskloop_for_outer): Likewise.
> (expand_omp_taskloop_for_inner): Likewise.
> (expand_oacc_for): Likewise.
> (expand_omp_sections): Likewise.
> (expand_omp_single): Likewise.
> (expand_omp_synch): Likewise.
> (expand_omp_atomic_load): Likewise.
> (expand_omp_atomic_store): Likewise.
> (expand_omp_atomic_fetch_op): Likewise.
> (expand_omp_atomic_pipeline): Likewise.
> (expand_omp_atomic_mutex): Likewise.
> (expand_omp_target): Likewise.
> (grid_expand_omp_for_loop): Likewise.
> (grid_expand_target_grid_body): Likewise.
> (build_omp_regions_1): Likewise.
> * omp-low.c (check_combined_parallel): Skip debug stmts.
> * opts.c (common_handle_option): Accept -gdwarf version 6.
> * output.h (final_start_function): Adjust.
> * params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
> * postreload.c (fixup_debug_insns): Skip nonbind debug insns.
> * print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
> begin stmt and inline entry marker notes.
> (print_insn): Likewise.
> * recog.c (extract_insn): Recognize rtl for begin stmt and
> inline entry markers.
> * reg-stack.c (convert_regs_1): Use BIND_DEBUG_INSN_P.
> * regrename.c (build_def_use): Likewise.
> * regcprop.c (copyprop_hardreg_forward_1): Likewise.
> (find_oldest_value_reg): Ensure REGNO is not a pseudo.
> * rtl.def (BEGIN_STMT_MARKER, LEXICAL_BLOCK): New.
> * rtl.h (MAY_HAVE_DEBUG_INSNS): Check debug_nonbind_markers_p.
> (NOTE_MARKER_LOCATION): New.
> (BIND_DEBUG_INSN_P, MARKER_DEBUG_INSN_P): New.
> (INSN_DEBUG_MARKER_KIND): New.
> (INSN_VAR_LOCATION): Check for VAR_LOCATION.
> (INSN_VAR_LOCATION_PTR): New.
> (LEXICAL_BLOCK_TREE): New.
> (prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
> (prev_nonnote_nondebug_insn_bb): Declare.
> (next_nonnote_nondebug_insn_bb): Declare.
> * toplev.c (process_options): Autodetect value for debug statement
> frontiers and debug variable location views.
> * tree-cfg.c (make_blobs_1): Skip debug stmts.
> (make_edges): Likewise.
> (cleanup_dead_labels): Likewise.
> (gimple_can_merge_blocks_p): Likewise.
> (stmt_starts_bb_p): Likewise.
> (gimple_block_label): Likewise.
> (gimple_redirect_edge_and_branch): Likewise.
> * tree-cfgcleanup.c (remove_forwarder_block): Rearrange skipping
> of debug stmts.
> (execute_cleanup_cfg_post_optimizing): Dump enumerated decls with
> TDF_SLIM.
> * tree-inline.c: Include params.h.
> (remap_gimple_stmt): Handle nonbind markers.
> (maybe_move_debug_stmts_to_successors): Likewise.
> (copy_debug_stmt): Likewise.
> (expand_call_inline): Build and insert debug_inline_entry stmt.
> * 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): Hnadle begin stmt markers.
> (print_declaration): Omit initializer in slim dumps.
> * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Mark begin stmt
> markers.
> (eliminate_unnecessary_stmts): Stabilize block removal order.
> * tree-ssa-live.c (remove_unused_scope_block_p): Preserve
> inline entry blocks early, if nonbind markers are enabled.
> (dump_scope_block): Dump fragment info.
> * tree-ssa-tail-merge.c (find_duplicate): Skip debug stmts.
> * tree-ssa-threadedge.c (propagate_threaded_block_debug_info): Handle
> 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 (MAY_HAVE_DEBUG_STMTS): Check debug_nonbind_markers_p.
> (GOTO_DESTINATION): Require a GOTO_EXPR.
> * valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
> * var-tracking.c (get_first_insn): New.
> (vt_emit_notes): Call it.
> (reemit_marker_as_note): New.
> (vt_initialize): Reemit markers. Walk any insns before the first BB.
> (delete_debug_insns): Renamed to...
> (delete_vta_debug_insns): ... this. Likewise.
> (vt_debug_insns_local): Reemit or delete markers.
> (variable_tracking_main_1): Likewise.
>
> 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.
> ---
> 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/cfgbuild.c | 14 +
> gcc/cfgexpand.c | 154 ++++--
> gcc/cfgrtl.c | 22 +
> gcc/common.opt | 16 +
> gcc/config.in | 6
> gcc/config/aarch64/aarch64.c | 2
> gcc/config/alpha/alpha.c | 2
> gcc/config/arm/arm.c | 5
> gcc/config/cris/cris.c | 3
> gcc/config/i386/i386.c | 5
> gcc/config/ia64/ia64.c | 2
> gcc/config/m68k/m68k.c | 2
> gcc/config/microblaze/microblaze.c | 2
> gcc/config/mips/mips.c | 2
> gcc/config/nds32/nds32.c | 3
> gcc/config/nios2/nios2.c | 2
> gcc/config/pa/pa.c | 3
> gcc/config/rs6000/rs6000.c | 5
> gcc/config/s390/s390.c | 3
> gcc/config/sh/sh.c | 2
> gcc/config/sparc/sparc.c | 2
> gcc/config/spu/spu.c | 3
> gcc/config/tilegx/tilegx.c | 2
> gcc/config/tilepro/tilepro.c | 2
> gcc/configure | 46 ++
> gcc/configure.ac | 18 +
> 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 | 11
> gcc/dbxout.c | 2
> gcc/debug.c | 1
> gcc/debug.h | 3
> gcc/df-scan.c | 2
> gcc/doc/generic.texi | 5
> gcc/doc/gimple.texi | 16 +
> gcc/doc/invoke.texi | 46 ++
> gcc/doc/rtl.texi | 33 +
> gcc/dwarf2asm.c | 25 +
> gcc/dwarf2asm.h | 4
> gcc/dwarf2out.c | 869 +++++++++++++++++++++++++++++++++---
> gcc/dwarf2out.h | 4
> gcc/emit-rtl.c | 69 ++-
> gcc/final.c | 236 +++++++++-
> gcc/function.c | 13 -
> gcc/function.h | 10
> gcc/gimple-iterator.c | 26 +
> gcc/gimple-iterator.h | 46 +-
> gcc/gimple-low.c | 28 +
> gcc/gimple-pretty-print.c | 20 +
> gcc/gimple.c | 45 ++
> gcc/gimple.h | 62 ++-
> gcc/gimplify.c | 179 ++++++-
> gcc/graphite-isl-ast-to-gimple.c | 7
> gcc/graphite-scop-detection.c | 2
> gcc/haifa-sched.c | 2
> gcc/insn-notes.def | 7
> gcc/ipa-icf-gimple.c | 4
> gcc/ira.c | 2
> gcc/jump.c | 2
> gcc/langhooks-def.h | 2
> gcc/langhooks.h | 3
> gcc/loop-unroll.c | 6
> gcc/lra-constraints.c | 10
> gcc/lra.c | 38 +-
> gcc/lto-streamer-in.c | 7
> gcc/omp-expand.c | 161 +++----
> gcc/omp-low.c | 2
> gcc/opts.c | 2
> gcc/output.h | 2
> gcc/params.def | 9
> gcc/postreload.c | 2
> gcc/print-rtl.c | 29 +
> gcc/recog.c | 2
> gcc/reg-stack.c | 4
> gcc/regcprop.c | 4
> gcc/regrename.c | 2
> gcc/rtl.def | 6
> gcc/rtl.h | 45 ++
> gcc/sdbout.c | 1
> gcc/toplev.c | 12
> gcc/tree-cfg.c | 52 ++
> gcc/tree-cfgcleanup.c | 31 -
> gcc/tree-inline.c | 41 ++
> gcc/tree-iterator.c | 48 ++
> gcc/tree-pretty-print.c | 9
> gcc/tree-ssa-dce.c | 6
> gcc/tree-ssa-live.c | 27 +
> gcc/tree-ssa-tail-merge.c | 4
> gcc/tree-ssa-threadedge.c | 8
> gcc/tree.c | 8
> gcc/tree.def | 3
> gcc/tree.h | 5
> gcc/valtrack.c | 2
> gcc/var-tracking.c | 125 +++++
> gcc/vmsdbgout.c | 1
> include/dwarf2.def | 2
> include/dwarf2.h | 8
> 104 files changed, 2467 insertions(+), 492 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 1402ba6..684bc82 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 (!debug_nonbind_markers_p)
> + 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 c33601f..d378470 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -10681,6 +10681,10 @@ c_finish_stmt_expr (location_t loc, tree body)
> }
> else
> i = tsi_last (last);
> + if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> + do
> + tsi_prev (&i);
> + while (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT);
> last_p = tsi_stmt_ptr (i);
> last = *last_p;
> }
> @@ -10700,7 +10704,9 @@ c_finish_stmt_expr (location_t loc, tree body)
>
> /* In the case that the BIND_EXPR is not necessary, return the
> expression out from inside it. */
> - if (last == BIND_EXPR_BODY (body)
> + if ((last == BIND_EXPR_BODY (body)
> + /* Skip nested debug stmts. */
> + || last == expr_first (BIND_EXPR_BODY (body)))
> && BIND_EXPR_VARS (body) == NULL)
> {
> /* Even if this looks constant, do not allow it in a constant
> diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
> index 2fe74c4..dde6c2d 100644
> --- a/gcc/cfgbuild.c
> +++ b/gcc/cfgbuild.c
> @@ -443,6 +443,7 @@ find_bb_boundaries (basic_block bb)
> rtx_jump_table_data *table;
> rtx_insn *flow_transfer_insn = NULL;
> edge fallthru = NULL;
> + bool only_header_debug_insns_p = true;
>
> if (insn == BB_END (bb))
> return;
> @@ -460,6 +461,13 @@ find_bb_boundaries (basic_block bb)
> if ((flow_transfer_insn || code == CODE_LABEL)
> && inside_basic_block_p (insn))
> {
> + if (only_header_debug_insns_p)
> + {
> + gcc_assert (!flow_transfer_insn);
> + BB_HEAD (bb) = insn;
> + goto end;
> + }
> +
> fallthru = split_block (bb, PREV_INSN (insn));
> if (flow_transfer_insn)
> {
> @@ -471,6 +479,7 @@ find_bb_boundaries (basic_block bb)
> x = NEXT_INSN (x))
> if (!BARRIER_P (x))
> set_block_for_insn (x, NULL);
> + only_header_debug_insns_p = true;
> }
>
> bb = fallthru->dest;
> @@ -489,13 +498,16 @@ find_bb_boundaries (basic_block bb)
> the middle of a BB. We need to split it in the same manner as
> if the barrier were preceded by a control_flow_insn_p insn. */
> if (!flow_transfer_insn)
> - flow_transfer_insn = prev_nonnote_insn_bb (insn);
> + flow_transfer_insn = prev_nonnote_nondebug_insn_bb (insn);
> }
>
> if (control_flow_insn_p (insn))
> flow_transfer_insn = insn;
> + end:
> if (insn == end)
> break;
> + if (!DEBUG_INSN_P (insn))
> + only_header_debug_insns_p = false;
> insn = NEXT_INSN (insn);
> }
>
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index 7f0130d..e920639 100644
> --- a/gcc/cfgexpand.c
> +++ b/gcc/cfgexpand.c
> @@ -2319,6 +2319,9 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
> {
> glabel *lab_stmt;
>
> + if (is_gimple_debug (gsi_stmt (gsi)))
> + continue;
> +
> lab_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
> if (!lab_stmt)
> break;
> @@ -5288,7 +5291,7 @@ expand_debug_locations (void)
> flag_strict_aliasing = 0;
>
> for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> {
> tree value = (tree)INSN_VAR_LOCATION_LOC (insn);
> rtx val;
> @@ -5435,7 +5438,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
> gimple_stmt_iterator gsi;
> gimple_seq stmts;
> gimple *stmt = NULL;
> - rtx_note *note;
> + rtx_note *note = NULL;
> rtx_insn *last;
> edge e;
> edge_iterator ei;
> @@ -5476,18 +5479,26 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
> }
> }
>
> - gsi = gsi_start (stmts);
> + gsi = gsi_start_nondebug (stmts);
> if (!gsi_end_p (gsi))
> {
> stmt = gsi_stmt (gsi);
> if (gimple_code (stmt) != GIMPLE_LABEL)
> stmt = NULL;
> }
> + gsi = gsi_start (stmts);
>
> + gimple *label_stmt = stmt;
> rtx_code_label **elt = lab_rtx_for_bb->get (bb);
>
> - if (stmt || elt)
> + if (stmt)
> + /* We'll get to it in the loop below, and get back to
> + emit_label_and_note then. */
> + ;
> + else if (stmt || elt)
> {
> + emit_label_and_note:
> + gcc_checking_assert (!note);
> last = get_last_insn ();
>
> if (stmt)
> @@ -5502,6 +5513,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
> BB_HEAD (bb) = NEXT_INSN (last);
> if (NOTE_P (BB_HEAD (bb)))
> BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb));
> + gcc_assert (LABEL_P (BB_HEAD (bb)));
> note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb));
>
> maybe_dump_rtl_for_gimple_stmt (stmt, last);
> @@ -5509,7 +5521,8 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
> else
> BB_HEAD (bb) = note = emit_note (NOTE_INSN_BASIC_BLOCK);
>
> - NOTE_BASIC_BLOCK (note) = bb;
> + if (note)
> + NOTE_BASIC_BLOCK (note) = bb;
>
> for (; !gsi_end_p (gsi); gsi_next (&gsi))
> {
> @@ -5517,6 +5530,9 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>
> stmt = gsi_stmt (gsi);
>
> + if (stmt == label_stmt)
> + goto emit_label_and_note;
> +
> /* If this statement is a non-debug one, and we generate debug
> insns, then this one might be the last real use of a TERed
> SSA_NAME, but where there are still some debug uses further
> @@ -5622,39 +5638,89 @@ 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 (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 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))
> + if (gimple_debug_bind_p (stmt))
> + {
> + var = gimple_debug_bind_get_var (stmt);
> +
> + if (TREE_CODE (var) != DEBUG_EXPR_DECL
> + && TREE_CODE (var) != LABEL_DECL
> + && !target_for_debug_bind (var))
> + goto delink_debug_stmt;
> +
> + if (DECL_P (var))
> + mode = DECL_MODE (var);
> + else
> + mode = TYPE_MODE (TREE_TYPE (var));
> +
> + if (gimple_debug_bind_has_value_p (stmt))
> + value = gimple_debug_bind_get_value (stmt);
> + }
> + else if (gimple_debug_nonbind_marker_p (stmt)
> + && !cfun->debug_nonbind_markers)
> goto delink_debug_stmt;
> + else if (gimple_debug_begin_stmt_p (stmt))
> + val = gen_rtx_BEGIN_STMT_MARKER (VOIDmode);
> + else if (gimple_debug_inline_entry_p (stmt))
> + {
> + tree block = gimple_block (stmt);
>
> - if (gimple_debug_bind_has_value_p (stmt))
> - value = gimple_debug_bind_get_value (stmt);
> + if (block)
> + val = gen_rtx_LEXICAL_BLOCK (VOIDmode, block);
> + else
> + goto delink_debug_stmt;
> + }
> else
> - value = NULL_TREE;
> + gcc_unreachable ();
>
> last = get_last_insn ();
>
> set_curr_insn_location (gimple_location (stmt));
>
> - if (DECL_P (var))
> - mode = DECL_MODE (var);
> - else
> - mode = TYPE_MODE (TREE_TYPE (var));
> -
> - val = gen_rtx_VAR_LOCATION
> - (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
> + if (!val)
> + val = gen_rtx_VAR_LOCATION
> + (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
>
> emit_debug_insn (val);
>
> @@ -5662,9 +5728,11 @@ 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)
> + 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:
> @@ -5680,42 +5748,13 @@ 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 (!gimple_debug_bind_p (stmt)
> + && !gimple_debug_nonbind_marker_p (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);
> @@ -6354,6 +6393,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/cfgrtl.c b/gcc/cfgrtl.c
> index 6ef47b7..fde4128 100644
> --- a/gcc/cfgrtl.c
> +++ b/gcc/cfgrtl.c
> @@ -1117,7 +1117,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
> if (tablejump_p (insn, &label, &table))
> delete_insn_chain (label, table, false);
>
> - barrier = next_nonnote_insn (BB_END (src));
> + barrier = next_nonnote_nondebug_insn (BB_END (src));
> if (!barrier || !BARRIER_P (barrier))
> emit_barrier_after (BB_END (src));
> else
> @@ -1753,7 +1753,7 @@ rtl_tidy_fallthru_edge (edge e)
> the head of block C and assert that we really do fall through. */
>
> for (q = NEXT_INSN (BB_END (b)); q != BB_HEAD (c); q = NEXT_INSN (q))
> - if (INSN_P (q))
> + if (NONDEBUG_INSN_P (q))
> return;
>
> /* Remove what will soon cease being the jump insn from the source block.
> @@ -2274,11 +2274,11 @@ get_last_bb_insn (basic_block bb)
> end = table;
>
> /* Include any barriers that may follow the basic block. */
> - tmp = next_nonnote_insn_bb (end);
> + tmp = next_nonnote_nondebug_insn_bb (end);
> while (tmp && BARRIER_P (tmp))
> {
> end = tmp;
> - tmp = next_nonnote_insn_bb (end);
> + tmp = next_nonnote_nondebug_insn_bb (end);
> }
>
> return end;
> @@ -2894,7 +2894,7 @@ rtl_verify_fallthru (void)
> else
> for (insn = NEXT_INSN (BB_END (e->src)); insn != BB_HEAD (e->dest);
> insn = NEXT_INSN (insn))
> - if (BARRIER_P (insn) || INSN_P (insn))
> + if (BARRIER_P (insn) || NONDEBUG_INSN_P (insn))
> {
> error ("verify_flow_info: Incorrect fallthru %i->%i",
> e->src->index, e->dest->index);
> @@ -2916,7 +2916,7 @@ rtl_verify_bb_layout (void)
> {
> basic_block bb;
> int err = 0;
> - rtx_insn *x;
> + rtx_insn *x, *y;
> int num_bb_notes;
> rtx_insn * const rtx_first = get_insns ();
> basic_block last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun), curr_bb = NULL;
> @@ -2943,6 +2943,7 @@ rtl_verify_bb_layout (void)
> {
> case BARRIER:
> case NOTE:
> + case DEBUG_INSN:
> break;
>
> case CODE_LABEL:
> @@ -2961,7 +2962,8 @@ rtl_verify_bb_layout (void)
>
> if (JUMP_P (x)
> && returnjump_p (x) && ! condjump_p (x)
> - && ! (next_nonnote_insn (x) && BARRIER_P (next_nonnote_insn (x))))
> + && ! ((y = next_nonnote_nondebug_insn (x))
> + && BARRIER_P (y)))
> fatal_insn ("return not followed by barrier", x);
>
> if (curr_bb && x == BB_END (curr_bb))
> @@ -3382,6 +3384,9 @@ skip_insns_after_block (basic_block bb)
> last_insn = insn;
> continue;
>
> + case DEBUG_INSN:
> + continue;
> +
> case NOTE:
> switch (NOTE_KIND (insn))
> {
> @@ -4135,7 +4140,8 @@ duplicate_insn_chain (rtx_insn *from, rtx_insn *to)
> {
> case DEBUG_INSN:
> /* Don't duplicate label debug insns. */
> - if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
> + if (BIND_DEBUG_INSN_P (insn)
> + && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
> break;
> /* FALLTHRU */
> case INSN:
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 1cb1c83..7d5e5624 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2882,6 +2882,14 @@ gstabs+
> Common Driver JoinedOrMissing Negative(gvms)
> Generate debug information in extended STABS format.
>
> +gno-statement-frontiers
> +Common Driver RejectNegative Var(debug_nonbind_markers_p, 0) Init(2)
> +Don't enforce progressive recommended breakpoint locations.
> +
> +gstatement-frontiers
> +Common Driver RejectNegative Var(debug_nonbind_markers_p, 1)
> +Emit progressive recommended breakpoint locations.
> +
> gno-strict-dwarf
> Common Driver RejectNegative Var(dwarf_strict,0) Init(0)
> Emit DWARF additions beyond selected version.
> @@ -2894,6 +2902,14 @@ gtoggle
> Common Driver Report Var(flag_gtoggle)
> Toggle debug information generation.
>
> +gno-variable-location-views
> +Common Driver RejectNegative Var(debug_variable_location_views, 0) Init(2)
> +Don't augment variable location lists with progressive views.
> +
> +gvariable-location-views
> +Common Driver RejectNegative Var(debug_variable_location_views, 1)
> +Augment variable location lists with progressive views.
> +
> gvms
> Common Driver JoinedOrMissing Negative(gxcoff)
> Generate debug information in VMS format.
> diff --git a/gcc/config.in b/gcc/config.in
> index 89d7108..8c33967 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -358,6 +358,12 @@
> #endif
>
>
> +/* Define if your assembler supports views in dwarf2 .loc directives. */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_AS_DWARF2_DEBUG_VIEW
> +#endif
> +
> +
> /* Define if your assembler supports the R_PPC64_ENTRY relocation. */
> #ifndef USED_FOR_TARGET
> #undef HAVE_AS_ENTRY_MARKERS
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index 28c4e0e..51584f5 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c
> @@ -3936,7 +3936,7 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
>
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
> index e13c5f9..c158f7a 100644
> --- a/gcc/config/alpha/alpha.c
> +++ b/gcc/config/alpha/alpha.c
> @@ -8461,7 +8461,7 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> assemble_start_function and assemble_end_function. */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
> }
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index fa3e2fa..71a0d2d 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -26357,7 +26357,8 @@ arm_thumb1_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
> if (mi_delta < 0)
> mi_delta = - mi_delta;
>
> - final_start_function (emit_barrier (), file, 1);
> + rtx_insn *first = emit_barrier ();
> + final_start_function (&first, file, 1);
>
> if (TARGET_THUMB1)
> {
> @@ -26534,7 +26535,7 @@ arm32_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
>
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
> index b57881a..376c1eb 100644
> --- a/gcc/config/cris/cris.c
> +++ b/gcc/config/cris/cris.c
> @@ -2744,7 +2744,8 @@ cris_asm_output_mi_thunk (FILE *stream,
> tree funcdecl)
> {
> /* Make sure unwind info is emitted for the thunk if needed. */
> - final_start_function (emit_barrier (), stream, 1);
> + rtx_insn *first = emit_barrier ();
> + final_start_function (&first, stream, 1);
>
> if (delta > 0)
> fprintf (stream, "\tadd%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index 1d88e4f..86320a7 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -12492,8 +12492,9 @@ ix86_code_end (void)
> emitting it directly; tell them we're a thunk, if they care. */
> cfun->is_thunk = true;
> first_function_block_is_cold = false;
> + rtx_insn *first = emit_barrier ();
> /* Make sure unwind info is emitted for the thunk if needed. */
> - final_start_function (emit_barrier (), asm_out_file, 1);
> + final_start_function (&first, asm_out_file, 1);
>
> /* Pad stack IP move with 4 instructions (two NOPs count
> as one instruction). */
> @@ -42615,7 +42616,7 @@ x86_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
> Note that use_thunk calls assemble_start_function et al. */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
> }
> diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
> index 79c323f..2a05293 100644
> --- a/gcc/config/ia64/ia64.c
> +++ b/gcc/config/ia64/ia64.c
> @@ -10944,7 +10944,7 @@ ia64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
> emit_all_insn_group_barriers (NULL);
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c
> index 8972665..3b656c7 100644
> --- a/gcc/config/m68k/m68k.c
> +++ b/gcc/config/m68k/m68k.c
> @@ -5131,7 +5131,7 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
> /* Run just enough of rest_of_compilation. */
> insn = get_insns ();
> split_all_insns_noflow ();
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c
> index 2cdd240..9f862292 100644
> --- a/gcc/config/microblaze/microblaze.c
> +++ b/gcc/config/microblaze/microblaze.c
> @@ -3233,7 +3233,7 @@ microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> "borrowed" from rs6000.c. */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
> index d2737a6..7dcc835 100644
> --- a/gcc/config/mips/mips.c
> +++ b/gcc/config/mips/mips.c
> @@ -19353,7 +19353,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> split_all_insns_noflow ();
> mips16_lay_out_constants (true);
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c
> index 14310de..478824f 100644
> --- a/gcc/config/nds32/nds32.c
> +++ b/gcc/config/nds32/nds32.c
> @@ -1635,7 +1635,8 @@ nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
> int this_regno;
>
> /* Make sure unwind info is emitted for the thunk if needed. */
> - final_start_function (emit_barrier (), file, 1);
> + rtx_insn *first = emit_barrier ();
> + final_start_function (&first, file, 1);
>
> this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
> ? 1
> diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c
> index 884b1dc..89600ee 100644
> --- a/gcc/config/nios2/nios2.c
> +++ b/gcc/config/nios2/nios2.c
> @@ -4060,7 +4060,7 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> assemble_start_function and assemble_end_function. */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
> index 52f76cf..fd28213 100644
> --- a/gcc/config/pa/pa.c
> +++ b/gcc/config/pa/pa.c
> @@ -8379,7 +8379,8 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
> xoperands[1] = XEXP (DECL_RTL (thunk_fndecl), 0);
> xoperands[2] = GEN_INT (delta);
>
> - final_start_function (emit_barrier (), file, 1);
> + rtx_insn *first = emit_barrier ();
> + final_start_function (&first, file, 1);
>
> /* Output the thunk. We know that the function is in the same
> translation unit (i.e., the same space) as the thunk, and that
> diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
> index f9aa13b..298f07a 100644
> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -29292,7 +29292,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> assemble_start_function and assemble_end_function. */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> @@ -37758,7 +37758,8 @@ rs6000_code_end (void)
> init_function_start (decl);
> first_function_block_is_cold = false;
> /* Make sure unwind info is emitted for the thunk if needed. */
> - final_start_function (emit_barrier (), asm_out_file, 1);
> + rtx_insn *first = emit_barrier ();
> + final_start_function (&first, asm_out_file, 1);
>
> fputs ("\tblr\n", asm_out_file);
>
> diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
> index deced95..ce98673 100644
> --- a/gcc/config/s390/s390.c
> +++ b/gcc/config/s390/s390.c
> @@ -12872,7 +12872,8 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
> int nonlocal = 0;
>
> /* Make sure unwind info is emitted for the thunk if needed. */
> - final_start_function (emit_barrier (), file, 1);
> + rtx_insn *first = emit_barrier ();
> + final_start_function (&first, file, 1);
>
> /* Operand 0 is the target function. */
> op[0] = XEXP (DECL_RTL (function), 0);
> diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
> index c31776f..875d931 100644
> --- a/gcc/config/sh/sh.c
> +++ b/gcc/config/sh/sh.c
> @@ -10891,7 +10891,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
>
> sh_reorg ();
> shorten_branches (insns);
> - final_start_function (insns, file, 1);
> + final_start_function (&insns, file, 1);
> final (insns, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
> index d494ecf2..5d92080 100644
> --- a/gcc/config/sparc/sparc.c
> +++ b/gcc/config/sparc/sparc.c
> @@ -12074,7 +12074,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> assemble_start_function and assemble_end_function. */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
> index b6d03d7..e005077 100644
> --- a/gcc/config/spu/spu.c
> +++ b/gcc/config/spu/spu.c
> @@ -7020,7 +7020,8 @@ spu_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
> rtx op[8];
>
> /* Make sure unwind info is emitted for the thunk if needed. */
> - final_start_function (emit_barrier (), file, 1);
> + rtx_insn *insn = emit_barrier ();
> + final_start_function (&insn, file, 1);
>
> /* Operand 0 is the target function. */
> op[0] = XEXP (DECL_RTL (function), 0);
> diff --git a/gcc/config/tilegx/tilegx.c b/gcc/config/tilegx/tilegx.c
> index 81559ac..ac4a5ff 100644
> --- a/gcc/config/tilegx/tilegx.c
> +++ b/gcc/config/tilegx/tilegx.c
> @@ -4998,7 +4998,7 @@ tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/config/tilepro/tilepro.c b/gcc/config/tilepro/tilepro.c
> index f03f067..34b68b8 100644
> --- a/gcc/config/tilepro/tilepro.c
> +++ b/gcc/config/tilepro/tilepro.c
> @@ -4421,7 +4421,7 @@ tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
> */
> insn = get_insns ();
> shorten_branches (insn);
> - final_start_function (insn, file, 1);
> + final_start_function (&insn, file, 1);
> final (insn, file, 1);
> final_end_function ();
>
> diff --git a/gcc/configure b/gcc/configure
> index 9cee670..da0f277 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -27756,6 +27756,52 @@ $as_echo "$gcc_cv_as_dwarf2_file_buggy" >&6; }
>
> $as_echo "#define HAVE_AS_DWARF2_DEBUG_LINE 1" >>confdefs.h
>
> +
> + if test $gcc_cv_as_leb128 = yes; then
> + conftest_s="\
> + .file 1 \"conftest.s\"
> + .loc 1 3 0 view .LVU1
> + $insn
> + .data
> + .uleb128 .LVU1
> + .uleb128 .LVU1
> +"
> + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for dwarf2 debug_view support" >&5
> +$as_echo_n "checking assembler for dwarf2 debug_view support... " >&6; }
> +if test "${gcc_cv_as_dwarf2_debug_view+set}" = set; then :
> + $as_echo_n "(cached) " >&6
> +else
> + gcc_cv_as_dwarf2_debug_view=no
> + if test $in_tree_gas = yes; then
> + if test $in_tree_gas_is_elf = yes \
> + && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 27 \) \* 1000 + 0`
> + then gcc_cv_as_dwarf2_debug_view=yes
> +fi
> + elif test x$gcc_cv_as != x; then
> + $as_echo "$conftest_s" > conftest.s
> + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
> + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> + (eval $ac_try) 2>&5
> + ac_status=$?
> + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> + test $ac_status = 0; }; }
> + then
> + gcc_cv_as_dwarf2_debug_view=yes
> + else
> + echo "configure: failed program was" >&5
> + cat conftest.s >&5
> + fi
> + rm -f conftest.o conftest.s
> + fi
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_dwarf2_debug_view" >&5
> +$as_echo "$gcc_cv_as_dwarf2_debug_view" >&6; }
> +if test $gcc_cv_as_dwarf2_debug_view = yes; then
> +
> +$as_echo "#define HAVE_AS_DWARF2_DEBUG_VIEW 1" >>confdefs.h
> +
> +fi
> + fi
> fi
>
> { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for --gdwarf2 option" >&5
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index 0c0e359..d00ef86 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -4847,9 +4847,25 @@ if test x"$insn" != x; then
>
> if test $gcc_cv_as_dwarf2_debug_line = yes \
> && test $gcc_cv_as_dwarf2_file_buggy = no; then
> - AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1,
> + AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1,
> [Define if your assembler supports dwarf2 .file/.loc directives,
> and preserves file table indices exactly as given.])
> +
> + if test $gcc_cv_as_leb128 = yes; then
> + conftest_s="\
> + .file 1 \"conftest.s\"
> + .loc 1 3 0 view .LVU1
> + $insn
> + .data
> + .uleb128 .LVU1
> + .uleb128 .LVU1
> +"
> + gcc_GAS_CHECK_FEATURE([dwarf2 debug_view support],
> + gcc_cv_as_dwarf2_debug_view,
> + [elf,2,27,0],,[$conftest_s],,
> + [AC_DEFINE(HAVE_AS_DWARF2_DEBUG_VIEW, 1,
> + [Define if your assembler supports views in dwarf2 .loc directives.])])
> + fi
> fi
>
> gcc_GAS_CHECK_FEATURE([--gdwarf2 option],
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 29ba2c3..c8f1255 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:
> @@ -3765,6 +3773,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
> for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
> {
> tree stmt = tsi_stmt (i);
> + if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
> + continue;
> r = cxx_eval_constant_expression (ctx, stmt, false,
> non_constant_p, overflow_p,
> jump_target);
> @@ -5096,6 +5106,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
> case CONTINUE_STMT:
> case REQUIRES_EXPR:
> case STATIC_ASSERT:
> + case DEBUG_BEGIN_STMT:
> return true;
>
> case AGGR_INIT_EXPR:
> 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 10fcdf3..e98c5c5 100644
> --- a/gcc/cp/cp-objcp-common.h
> +++ b/gcc/cp/cp-objcp-common.h
> @@ -103,6 +103,8 @@ extern void cp_register_dumps (gcc::dump_manager *);
> #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
> #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
> #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
> +#undef LANG_HOOKS_EMITS_BEGIN_STMT
> +#define LANG_HOOKS_EMITS_BEGIN_STMT true
>
> /* Attribute hooks. */
> #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index b849824..a25582e 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -10712,6 +10712,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
>
> /* Statements [gram.stmt.stmt] */
>
> +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
> +
> +static void
> +add_debug_begin_stmt (location_t loc)
> +{
> + if (!debug_nonbind_markers_p)
> + return;
> +
> + tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
> + SET_EXPR_LOCATION (stmt, loc);
> + add_stmt (stmt);
> +}
> +
> /* Parse a statement.
>
> statement:
> @@ -10787,6 +10800,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
> token = cp_lexer_peek_token (parser->lexer);
> /* Remember the location of the first token in the statement. */
> statement_location = token->location;
> + add_debug_begin_stmt (statement_location);
> /* If this is a keyword, then that will often determine what kind of
> statement we have. */
> if (token->type == CPP_KEYWORD)
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index bf1f75d..ced7ec6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -15120,6 +15120,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
> case PREDICT_EXPR:
> return t;
>
> + case DEBUG_BEGIN_STMT:
> + /* ??? There's no point in copying it for now, but maybe some
> + day it will contain more information, such as a pointer back
> + to the containing function, inlined copy or so. */
> + return t;
> +
> default:
> /* We shouldn't get here, but keep going if !flag_checking. */
> if (flag_checking)
> diff --git a/gcc/cse.c b/gcc/cse.c
> index 6a968d1..c98e3f2 100644
> --- a/gcc/cse.c
> +++ b/gcc/cse.c
> @@ -6953,11 +6953,18 @@ insn_live_p (rtx_insn *insn, int *counts)
> {
> rtx_insn *next;
>
> + if (MARKER_DEBUG_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 (MARKER_DEBUG_INSN_P (next))
> + return true;
> else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
> return false;
>
> @@ -7044,7 +7051,7 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
> {
> counts = XCNEWVEC (int, nreg * 3);
> for (insn = insns; insn; insn = NEXT_INSN (insn))
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
> NULL_RTX, 1);
> else if (INSN_P (insn))
> @@ -7150,7 +7157,7 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
> if (MAY_HAVE_DEBUG_INSNS)
> {
> for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> {
> /* If this debug insn references a dead register that wasn't replaced
> with an DEBUG_EXPR, reset the DEBUG_INSN. */
> diff --git a/gcc/dbxout.c b/gcc/dbxout.c
> index 3d9268c3..f1c80c5 100644
> --- a/gcc/dbxout.c
> +++ b/gcc/dbxout.c
> @@ -377,6 +377,7 @@ const struct gcc_debug_hooks dbx_debug_hooks =
> debug_nothing_rtx_code_label, /* label */
> dbxout_handle_pch, /* handle_pch */
> debug_nothing_rtx_insn, /* var_location */
> + debug_nothing_tree, /* inline_entry */
> debug_nothing_tree, /* size_function */
> debug_nothing_void, /* switch_text_section */
> debug_nothing_tree_tree, /* set_name */
> @@ -417,6 +418,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
> debug_nothing_rtx_code_label, /* label */
> dbxout_handle_pch, /* handle_pch */
> debug_nothing_rtx_insn, /* var_location */
> + debug_nothing_tree, /* inline_entry */
> debug_nothing_tree, /* size_function */
> debug_nothing_void, /* switch_text_section */
> debug_nothing_tree_tree, /* set_name */
> diff --git a/gcc/debug.c b/gcc/debug.c
> index d68c30ff..5deec2c 100644
> --- a/gcc/debug.c
> +++ b/gcc/debug.c
> @@ -53,6 +53,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
> debug_nothing_rtx_code_label, /* label */
> debug_nothing_int, /* handle_pch */
> debug_nothing_rtx_insn, /* var_location */
> + debug_nothing_tree, /* inline_entry */
> debug_nothing_tree, /* size_function */
> debug_nothing_void, /* switch_text_section */
> debug_nothing_tree_tree, /* set_name */
> diff --git a/gcc/debug.h b/gcc/debug.h
> index bfb7221..78bb401 100644
> --- a/gcc/debug.h
> +++ b/gcc/debug.h
> @@ -168,6 +168,9 @@ struct gcc_debug_hooks
> /* Called from final_scan_insn for any NOTE_INSN_VAR_LOCATION note. */
> void (* var_location) (rtx_insn *);
>
> + /* Called from final_scan_insn for any NOTE_INSN_INLINE_ENTRY note. */
> + void (* inline_entry) (tree block);
> +
> /* Called from finalize_size_functions for size functions so that their body
> can be encoded in the debug info to describe the layout of variable-length
> structures. */
> diff --git a/gcc/df-scan.c b/gcc/df-scan.c
> index dde6d15..a7b04e7 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 874d464..c938be8 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..8d93e99 100644
> --- a/gcc/doc/gimple.texi
> +++ b/gcc/doc/gimple.texi
> @@ -831,6 +831,11 @@ 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
> +
> @node Manipulating GIMPLE statements
> @section Manipulating GIMPLE statements
> @cindex Manipulating GIMPLE statements
> @@ -1528,10 +1533,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 +1608,14 @@ 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.
> +@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 ec29f1d..04b8835 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -344,10 +344,12 @@ Objective-C and Objective-C++ Dialects}.
> -ggdb -grecord-gcc-switches -gno-record-gcc-switches @gol
> -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol
> -gcolumn-info -gno-column-info @gol
> --gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol
> --fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol
> --feliminate-dwarf2-dups -fno-eliminate-unused-debug-types @gol
> --femit-struct-debug-baseonly -femit-struct-debug-reduced @gol
> +-gstatement-frontiers -gno-statement-frontiers @gol
> +-gvariable-location-views -gno-variable-location-views @gol
> +-gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol
> +-fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol
> +-feliminate-dwarf2-dups -fno-eliminate-unused-debug-types @gol
> +-femit-struct-debug-baseonly -femit-struct-debug-reduced @gol
> -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} @gol
> -feliminate-unused-debug-symbols -femit-class-debug-always @gol
> -fno-merge-debug-strings -fno-dwarf2-cfi-asm @gol
> @@ -6988,6 +6990,35 @@ Emit location column information into DWARF debugging information, rather
> than just file and line.
> This option is disabled by default.
>
> +@item -gstatement-frontiers
> +@item -gno-statement-frontiers
> +@opindex gstatement-frontiers
> +@opindex gno-statement-frontiers
> +This option causes GCC to create markers in the internal representation
> +at the beginning of statements, and to keep them roughly in place
> +throughout compilation, using them to guide the output of @code{is_stmt}
> +markers in the line number table. This is enabled by default when
> +compiling with optimization (@option{-Os}, @option{-O}, @option{-O2},
> +@dots{}), and outputting DWARF 2 debug information at the normal level.
> +
> +@item -gvariable-location-views
> +@item -gno-variable-location-views
> +@opindex gvariable-location-views
> +@opindex gno-variable-location-views
> +Augment variable location lists with progressive view numbers implied
> +from the line number table. This enables debug information consumers to
> +inspect state at certain points of the program, even if no instructions
> +associated with the corresponding source locations are present at that
> +point. If the assembler lacks support for view numbers in line number
> +tables, this will cause the compiler to emit the line number table,
> +which generally makes them somewhat less compact. The augmented line
> +number tables and location lists are fully backward-compatible, so they
> +can be consumed by debug information consumers that are not aware of
> +these augmentations, but they won't derive any benefit from them either.
> +This is enabled by default when outputting DWARF 2 debug information at
> +the normal level, as long as @code{-fvar-tracking-assignments} is
> +enabled and @code{-gstrict-dwarf} is not.
> +
> @item -gz@r{[}=@var{type}@r{]}
> @opindex gz
> Produce compressed debug sections in DWARF format, if that is supported.
> @@ -10419,6 +10450,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 6e2799a..2189446 100644
> --- a/gcc/doc/rtl.texi
> +++ b/gcc/doc/rtl.texi
> @@ -3689,6 +3689,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.
> @@ -3704,17 +3710,22 @@ representation of @code{GIMPLE_DEBUG} statements
> binds a user variable tree to an RTL representation of the
> @code{value} in the corresponding statement. A @code{DEBUG_EXPR} in
> 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{DEBUG_EXPR_DECL}. A @code{GIMPLE_DEBUG_BEGIN_STMT} is expanded
> +to RTL as a @code{DEBUG_INSN} with a @code{NULL_TREE} in
> +@code{INSN_VAR_LOCATION_DECL}.
> +
> +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/dwarf2asm.c b/gcc/dwarf2asm.c
> index 8e3e86f..f19e6d6 100644
> --- a/gcc/dwarf2asm.c
> +++ b/gcc/dwarf2asm.c
> @@ -768,6 +768,31 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
> }
>
> void
> +dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
> + const char *comment, ...)
> +{
> + va_list ap;
> +
> + va_start (ap, comment);
> +
> +#ifdef HAVE_AS_LEB128
> + fputs ("\t.uleb128 ", asm_out_file);
> + assemble_name (asm_out_file, lab1);
> +#else
> + gcc_unreachable ();
> +#endif
> +
> + if (flag_debug_asm && comment)
> + {
> + fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
> + vfprintf (asm_out_file, comment, ap);
> + }
> + fputc ('\n', asm_out_file);
> +
> + va_end (ap);
> +}
> +
> +void
> dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
> const char *lab2 ATTRIBUTE_UNUSED,
> const char *comment, ...)
> diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
> index 7fc87a0..d8370df 100644
> --- a/gcc/dwarf2asm.h
> +++ b/gcc/dwarf2asm.h
> @@ -70,6 +70,10 @@ extern void dw2_asm_output_data_sleb128 (HOST_WIDE_INT,
> const char *, ...)
> ATTRIBUTE_NULL_PRINTF_2;
>
> +extern void dw2_asm_output_symname_uleb128 (const char *,
> + const char *, ...)
> + ATTRIBUTE_NULL_PRINTF_2;
> +
> extern void dw2_asm_output_delta_uleb128 (const char *, const char *,
> const char *, ...)
> ATTRIBUTE_NULL_PRINTF_3;
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 917ab9f..cb11c98 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see
> #include "toplev.h"
> #include "md5.h"
> #include "tree-pretty-print.h"
> +#include "print-rtl.h"
> #include "debug.h"
> #include "common/common-target.h"
> #include "langhooks.h"
> @@ -1274,6 +1275,8 @@ struct GTY((for_user)) addr_table_entry {
> GTY ((desc ("%1.kind"))) addr;
> };
>
> +typedef unsigned int var_loc_view;
> +
> /* Location lists are ranges + location descriptions for that range,
> so you can track variables that are in different places over
> their entire life. */
> @@ -1283,9 +1286,11 @@ typedef struct GTY(()) dw_loc_list_struct {
> addr_table_entry *begin_entry;
> const char *end; /* Label for end of range */
> char *ll_symbol; /* Label for beginning of location list.
> - Only on head of list */
> + Only on head of list. */
> + char *vl_symbol; /* Label for beginning of view list. Ditto. */
> const char *section; /* Section this loclist is relative to */
> dw_loc_descr_ref expr;
> + var_loc_view vbegin, vend;
> hashval_t hash;
> /* True if all addresses in this and subsequent lists are known to be
> resolved. */
> @@ -1322,6 +1327,31 @@ dwarf_stack_op_name (unsigned int op)
> return "OP_<unknown>";
> }
>
> +/* Return TRUE iff we're to output location view lists as a separate
> + attribute next to the location lists, as an extension compatible
> + with DWARF 2 and above. */
> +
> +static inline bool
> +dwarf2out_locviews_in_attribute ()
> +{
> + return debug_variable_location_views
> + && dwarf_version <= 5;
> +}
> +
> +/* Return TRUE iff we're to output location view lists as part of the
> + location lists, as proposed for standardization after DWARF 5. */
> +
> +static inline bool
> +dwarf2out_locviews_in_loclist ()
> +{
> +#ifndef DW_LLE_view_pair
> + return false;
> +#else
> + return debug_variable_location_views
> + && dwarf_version >= 6;
> +#endif
> +}
> +
> /* Return a pointer to a newly allocated location description. Location
> descriptions are simple expression terms that can be strung
> together to form more complicated location (address) descriptions. */
> @@ -1397,6 +1427,8 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
> return a->v.val_loc == b->v.val_loc;
> case dw_val_class_loc_list:
> return a->v.val_loc_list == b->v.val_loc_list;
> + case dw_val_class_view_list:
> + return a->v.val_view_list == b->v.val_view_list;
> case dw_val_class_die_ref:
> return a->v.val_die_ref.die == b->v.val_die_ref.die;
> case dw_val_class_fde_ref:
> @@ -2687,6 +2719,7 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
> dw_die_ref);
> static void dwarf2out_abstract_function (tree);
> static void dwarf2out_var_location (rtx_insn *);
> +static void dwarf2out_inline_entry (tree);
> static void dwarf2out_size_function (tree);
> static void dwarf2out_begin_function (tree);
> static void dwarf2out_end_function (unsigned int);
> @@ -2734,6 +2767,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
> debug_nothing_rtx_code_label, /* label */
> debug_nothing_int, /* handle_pch */
> dwarf2out_var_location,
> + dwarf2out_inline_entry, /* inline_entry */
> dwarf2out_size_function, /* size_function */
> dwarf2out_switch_text_section,
> dwarf2out_set_name,
> @@ -2772,6 +2806,7 @@ const struct gcc_debug_hooks dwarf2_lineno_debug_hooks =
> debug_nothing_rtx_code_label, /* label */
> debug_nothing_int, /* handle_pch */
> debug_nothing_rtx_insn, /* var_location */
> + debug_nothing_tree, /* inline_entry */
> debug_nothing_tree, /* size_function */
> debug_nothing_void, /* switch_text_section */
> debug_nothing_tree_tree, /* set_name */
> @@ -2834,7 +2869,15 @@ enum dw_line_info_opcode {
> LI_set_epilogue_begin,
>
> /* Emit a DW_LNE_set_discriminator. */
> - LI_set_discriminator
> + LI_set_discriminator,
> +
> + /* Output a Fixed Advance PC; the target PC is the label index; the
> + base PC is the previous LI_adv_address or LI_set_address entry.
> + We only use this when emitting debug views without assembler
> + support, at explicit user request. Ideally, we should only use
> + it when the offset might be zero but we can't tell: it's the only
> + way to maybe change the PC without resetting the view number. */
> + LI_adv_address
> };
>
> typedef struct GTY(()) dw_line_info_struct {
> @@ -2856,6 +2899,25 @@ struct GTY(()) dw_line_info_table {
> bool is_stmt;
> bool in_use;
>
> + /* This denotes the NEXT view number.
> +
> + If it is 0, it is known that the NEXT view will be the first view
> + at the given PC.
> +
> + If it is -1, we've advanced PC but we haven't emitted a line location yet,
> + so we shouldn't use this view number.
> +
> + The meaning of other nonzero values depends on whether we're
> + computing views internally or leaving it for the assembler to do
> + so. If we're emitting them internally, view denotes the view
> + number since the last known advance of PC. If we're leaving it
> + for the assembler, it denotes the LVU label number that we're
> + going to ask the assembler to assign. */
> + var_loc_view view;
> +
> +#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
> +#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
> +
> vec<dw_line_info_entry, va_gc> *entries;
> };
>
> @@ -3054,6 +3116,41 @@ skeleton_chain_node;
> #endif
> #endif
>
> +/* Use assembler views in line directives if available. */
> +#ifndef DWARF2_ASM_VIEW_DEBUG_INFO
> +#ifdef HAVE_AS_DWARF2_DEBUG_VIEW
> +#define DWARF2_ASM_VIEW_DEBUG_INFO 1
> +#else
> +#define DWARF2_ASM_VIEW_DEBUG_INFO 0
> +#endif
> +#endif
> +
> +/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
> + view computation, and it is refers to a view identifier for which
> + will not emit a label because it is known to map to a view number
> + zero. We won't allocate the bitmap if we're not using assembler
> + support for location views, but we have to make the variable
> + visible for GGC and for code that will be optimized out for lack of
> + support but that's still parsed and compiled. We could abstract it
> + out with macros, but it's not worth it. */
> +static GTY(()) bitmap zero_view_p;
> +
> +/* Evaluate to TRUE iff N is known to identify the first location view
> + at its PC. When not using assembler location view computation,
> + that must be view number zero. Otherwise, ZERO_VIEW_P is allocated
> + and views label numbers recorded in it are the ones known to be
> + zero. */
> +#define ZERO_VIEW_P(N) (zero_view_p \
> + ? bitmap_bit_p (zero_view_p, (N)) \
> + : (N) == 0)
> +
> +static bool
> +output_asm_line_debug_info (void)
> +{
> + return DWARF2_ASM_VIEW_DEBUG_INFO
> + || (DWARF2_ASM_LINE_DEBUG_INFO && !debug_variable_location_views);
> +}
> +
> /* Minimum line offset in a special line info. opcode.
> This value was chosen to give a reasonable range of values. */
> #define DWARF_LINE_BASE -10
> @@ -3163,6 +3260,7 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node {
> rtx GTY (()) loc;
> const char * GTY (()) label;
> struct var_loc_node * GTY (()) next;
> + var_loc_view view;
> };
>
> /* Variable location list. */
> @@ -3371,6 +3469,8 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_node *);
> static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
> dw_loc_list_ref);
> static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
> +static void add_AT_view_list (dw_die_ref, enum dwarf_attribute);
> +static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
> static addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
> static void remove_addr_table_entry (addr_table_entry *);
> static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
> @@ -3407,7 +3507,7 @@ static void equate_type_number_to_die (tree, dw_die_ref);
> static dw_die_ref lookup_decl_die (tree);
> static var_loc_list *lookup_decl_loc (const_tree);
> static void equate_decl_number_to_die (tree, dw_die_ref);
> -static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
> +static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *, var_loc_view);
> static void print_spaces (FILE *);
> static void print_die (dw_die_ref, FILE *);
> static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
> @@ -3615,8 +3715,8 @@ static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage);
> static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
> static void splice_child_die (dw_die_ref, dw_die_ref);
> static int file_info_cmp (const void *, const void *);
> -static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
> - const char *, const char *);
> +static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, var_loc_view,
> + const char *, var_loc_view, const char *);
> static void output_loc_list (dw_loc_list_ref);
> static char *gen_internal_sym (const char *);
> static bool want_pubnames (void);
> @@ -3862,6 +3962,9 @@ static char ranges_base_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
> #ifndef BLOCK_BEGIN_LABEL
> #define BLOCK_BEGIN_LABEL "LBB"
> #endif
> +#ifndef BLOCK_INLINE_ENTRY_LABEL
> +#define BLOCK_INLINE_ENTRY_LABEL "LBI"
> +#endif
> #ifndef BLOCK_END_LABEL
> #define BLOCK_END_LABEL "LBE"
> #endif
> @@ -4538,11 +4641,55 @@ AT_loc_list (dw_attr_node *a)
> return a->dw_attr_val.v.val_loc_list;
> }
>
> +static inline void
> +add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind)
> +{
> + dw_attr_node attr;
> +
> + if (XCOFF_DEBUGGING_INFO && !HAVE_XCOFF_DWARF_EXTRAS)
> + return;
> +
> + attr.dw_attr = attr_kind;
> + attr.dw_attr_val.val_class = dw_val_class_view_list;
> + attr.dw_attr_val.val_entry = NULL;
> + attr.dw_attr_val.v.val_view_list = die;
> + add_dwarf_attr (die, &attr);
> + gcc_checking_assert (get_AT (die, DW_AT_location));
> + gcc_assert (have_location_lists);
> +}
> +
> static inline dw_loc_list_ref *
> AT_loc_list_ptr (dw_attr_node *a)
> {
> - gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
> - return &a->dw_attr_val.v.val_loc_list;
> + gcc_assert (a);
> + switch (AT_class (a))
> + {
> + case dw_val_class_loc_list:
> + return &a->dw_attr_val.v.val_loc_list;
> + case dw_val_class_view_list:
> + {
> + dw_attr_node *l;
> + l = get_AT (a->dw_attr_val.v.val_view_list, DW_AT_location);
> + if (!l)
> + return NULL;
> + gcc_checking_assert (l + 1 == a);
> + return AT_loc_list_ptr (l);
> + }
> + default:
> + gcc_unreachable ();
> + }
> +}
> +
> +static inline dw_val_node *
> +view_list_to_loc_list_val_node (dw_val_node *val)
> +{
> + gcc_assert (val->val_class == dw_val_class_view_list);
> + dw_attr_node *loc = get_AT (val->v.val_view_list, DW_AT_location);
> + if (!loc)
> + return NULL;
> + gcc_checking_assert (&(loc + 1)->dw_attr_val == val);
> + gcc_assert (AT_class (loc) == dw_val_class_loc_list);
> + return &loc->dw_attr_val;
> }
>
> struct addr_hasher : ggc_ptr_hash<addr_table_entry>
> @@ -5604,7 +5751,7 @@ adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
> /* Add a variable location node to the linked list for DECL. */
>
> static struct var_loc_node *
> -add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
> +add_var_loc_to_decl (tree decl, rtx loc_note, const char *label, var_loc_view view)
> {
> unsigned int decl_id;
> var_loc_list *temp;
> @@ -5695,7 +5842,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
> /* TEMP->LAST here is either pointer to the last but one or
> last element in the chained list, LAST is pointer to the
> last element. */
> - if (label && strcmp (last->label, label) == 0)
> + if (label && strcmp (last->label, label) == 0 && last->view == view)
> {
> /* For SRA optimized variables if there weren't any real
> insns since last note, just modify the last node. */
> @@ -5711,7 +5858,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
> temp->last->next = NULL;
> unused = last;
> last = temp->last;
> - gcc_assert (strcmp (last->label, label) != 0);
> + gcc_assert (strcmp (last->label, label) != 0 || last->view != view);
> }
> else
> {
> @@ -5846,6 +5993,12 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
> fprintf (outfile, "location list -> label:%s",
> val->v.val_loc_list->ll_symbol);
> break;
> + case dw_val_class_view_list:
> + val = view_list_to_loc_list_val_node (val);
> + fprintf (outfile, "location list with views -> labels:%s and %s",
> + val->v.val_loc_list->ll_symbol,
> + val->v.val_loc_list->vl_symbol);
> + break;
> case dw_val_class_range_list:
> fprintf (outfile, "range list");
> break;
> @@ -8945,6 +9098,7 @@ size_of_die (dw_die_ref die)
> }
> break;
> case dw_val_class_loc_list:
> + case dw_val_class_view_list:
> if (dwarf_split_debug_info && dwarf_version >= 5)
> {
> gcc_assert (AT_loc_list (a)->num_assigned);
> @@ -9316,6 +9470,7 @@ value_format (dw_attr_node *a)
> gcc_unreachable ();
> }
> case dw_val_class_loc_list:
> + case dw_val_class_view_list:
> if (dwarf_split_debug_info
> && dwarf_version >= 5
> && AT_loc_list (a)->num_assigned)
> @@ -9611,7 +9766,8 @@ output_die_symbol (dw_die_ref die)
> expression. */
>
> static inline dw_loc_list_ref
> -new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
> +new_loc_list (dw_loc_descr_ref expr, const char *begin, var_loc_view vbegin,
> + const char *end, var_loc_view vend,
> const char *section)
> {
> dw_loc_list_ref retlist = ggc_cleared_alloc<dw_loc_list_node> ();
> @@ -9621,10 +9777,28 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
> retlist->end = end;
> retlist->expr = expr;
> retlist->section = section;
> + retlist->vbegin = vbegin;
> + retlist->vend = vend;
>
> return retlist;
> }
>
> +/* Return true iff there's any nonzero view number in the loc list. */
> +
> +static bool
> +loc_list_has_views (dw_loc_list_ref list)
> +{
> + if (!debug_variable_location_views)
> + return false;
> +
> + for (dw_loc_list_ref loc = list;
> + loc != NULL; loc = loc->dw_loc_next)
> + if (!ZERO_VIEW_P (loc->vbegin) || !ZERO_VIEW_P (loc->vend))
> + return true;
> +
> + return false;
> +}
> +
> /* Generate a new internal symbol for this location list node, if it
> hasn't got one yet. */
>
> @@ -9633,6 +9807,99 @@ gen_llsym (dw_loc_list_ref list)
> {
> gcc_assert (!list->ll_symbol);
> list->ll_symbol = gen_internal_sym ("LLST");
> +
> + if (!loc_list_has_views (list))
> + return;
> +
> + if (dwarf2out_locviews_in_attribute ())
> + {
> + /* Use the same label_num for the view list. */
> + label_num--;
> + list->vl_symbol = gen_internal_sym ("LVUS");
> + }
> + else
> + list->vl_symbol = list->ll_symbol;
> +}
> +
> +/* Generate a symbol for the list, but only if we really want to emit
> + it as a list. */
> +
> +static inline void
> +maybe_gen_llsym (dw_loc_list_ref list)
> +{
> + if (!list || (!list->dw_loc_next && !loc_list_has_views (list)))
> + return;
> +
> + gen_llsym (list);
> +}
> +
> +/* Determine whether or not to skip loc_list entry CURR. If we're not
> + to skip it, and SIZEP is non-null, store the size of CURR->expr's
> + representation in *SIZEP. */
> +
> +static bool
> +skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0)
> +{
> + /* Don't output an entry that starts and ends at the same address. */
> + if (strcmp (curr->begin, curr->end) == 0
> + && curr->vbegin == curr->vend && !curr->force)
> + return true;
> +
> + unsigned long size = size_of_locs (curr->expr);
> +
> + /* If the expression is too large, drop it on the floor. We could
> + perhaps put it into DW_TAG_dwarf_procedure and refer to that
> + in the expression, but >= 64KB expressions for a single value
> + in a single range are unlikely very useful. */
> + if (dwarf_version < 5 && size > 0xffff)
> + return true;
> +
> + if (sizep)
> + *sizep = size;
> +
> + return false;
> +}
> +
> +/* Output a view pair loclist entry for CURR, if it requires one. */
> +
> +static void
> +dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr)
> +{
> + if (!dwarf2out_locviews_in_loclist ())
> + return;
> +
> + if (ZERO_VIEW_P (curr->vbegin) && ZERO_VIEW_P (curr->vend))
> + return;
> +
> +#ifdef DW_LLE_view_pair
> + dw2_asm_output_data (1, DW_LLE_view_pair,
> + "DW_LLE_view_pair");
> +
> +# if DWARF2_ASM_VIEW_DEBUG_INFO
> + if (ZERO_VIEW_P (curr->vbegin))
> + dw2_asm_output_data_uleb128 (0, "Location view begin");
> + else
> + {
> + char label[MAX_ARTIFICIAL_LABEL_BYTES];
> + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
> + dw2_asm_output_symname_uleb128 (label, "Location view begin");
> + }
> +
> + if (ZERO_VIEW_P (curr->vend))
> + dw2_asm_output_data_uleb128 (0, "Location view end");
> + else
> + {
> + char label[MAX_ARTIFICIAL_LABEL_BYTES];
> + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
> + dw2_asm_output_symname_uleb128 (label, "Location view end");
> + }
> +# else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
> + dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
> + dw2_asm_output_data_uleb128 (curr->vend, "Location view end");
> +# endif /* DWARF2_ASM_VIEW_DEBUG_INFO */
> +#endif /* DW_LLE_view_pair */
> +
> + return;
> }
>
> /* Output the location list given to us. */
> @@ -9640,34 +9907,85 @@ gen_llsym (dw_loc_list_ref list)
> static void
> output_loc_list (dw_loc_list_ref list_head)
> {
> + int vcount = 0, lcount = 0;
> +
> if (list_head->emitted)
> return;
> list_head->emitted = true;
>
> + if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
> + {
> + ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);
> +
> + for (dw_loc_list_ref curr = list_head; curr != NULL;
> + curr = curr->dw_loc_next)
> + {
> + if (skip_loc_list_entry (curr))
> + continue;
> +
> + vcount++;
> +
> + /* ?? dwarf_split_debug_info? */
> +#if DWARF2_ASM_VIEW_DEBUG_INFO
> + char label[MAX_ARTIFICIAL_LABEL_BYTES];
> +
> + if (!ZERO_VIEW_P (curr->vbegin))
> + {
> + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
> + dw2_asm_output_symname_uleb128 (label,
> + "View list begin (%s)",
> + list_head->vl_symbol);
> + }
> + else
> + dw2_asm_output_data_uleb128 (0,
> + "View list begin (%s)",
> + list_head->vl_symbol);
> +
> + if (!ZERO_VIEW_P (curr->vend))
> + {
> + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
> + dw2_asm_output_symname_uleb128 (label,
> + "View list end (%s)",
> + list_head->vl_symbol);
> + }
> + else
> + dw2_asm_output_data_uleb128 (0,
> + "View list end (%s)",
> + list_head->vl_symbol);
> +#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
> + dw2_asm_output_data_uleb128 (curr->vbegin,
> + "View list begin (%s)",
> + list_head->vl_symbol);
> + dw2_asm_output_data_uleb128 (curr->vend,
> + "View list end (%s)",
> + list_head->vl_symbol);
> +#endif
> + }
> + }
> +
> ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
>
> - dw_loc_list_ref curr = list_head;
> const char *last_section = NULL;
> const char *base_label = NULL;
>
> /* Walk the location list, and output each range + expression. */
> - for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
> + for (dw_loc_list_ref curr = list_head; curr != NULL;
> + curr = curr->dw_loc_next)
> {
> unsigned long size;
> - /* Don't output an entry that starts and ends at the same address. */
> - if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
> - continue;
> - size = size_of_locs (curr->expr);
> - /* If the expression is too large, drop it on the floor. We could
> - perhaps put it into DW_TAG_dwarf_procedure and refer to that
> - in the expression, but >= 64KB expressions for a single value
> - in a single range are unlikely very useful. */
> - if (dwarf_version < 5 && size > 0xffff)
> +
> + /* Skip this entry? If we skip it here, we must skip it in the
> + view list above as well. */
> + if (skip_loc_list_entry (curr, &size))
> continue;
> +
> + lcount++;
> +
> if (dwarf_version >= 5)
> {
> if (dwarf_split_debug_info)
> {
> + dwarf2out_maybe_output_loclist_view_pair (curr);
> /* For -gsplit-dwarf, emit DW_LLE_starx_length, which has
> uleb128 index into .debug_addr and uleb128 length. */
> dw2_asm_output_data (1, DW_LLE_startx_length,
> @@ -9685,6 +10003,7 @@ output_loc_list (dw_loc_list_ref list_head)
> }
> else if (!have_multiple_function_sections && HAVE_AS_LEB128)
> {
> + dwarf2out_maybe_output_loclist_view_pair (curr);
> /* If all code is in .text section, the base address is
> already provided by the CU attributes. Use
> DW_LLE_offset_pair where both addresses are uleb128 encoded
> @@ -9735,6 +10054,7 @@ output_loc_list (dw_loc_list_ref list_head)
> length. */
> if (last_section == NULL)
> {
> + dwarf2out_maybe_output_loclist_view_pair (curr);
> dw2_asm_output_data (1, DW_LLE_start_length,
> "DW_LLE_start_length (%s)",
> list_head->ll_symbol);
> @@ -9749,6 +10069,7 @@ output_loc_list (dw_loc_list_ref list_head)
> DW_LLE_base_address. */
> else
> {
> + dwarf2out_maybe_output_loclist_view_pair (curr);
> dw2_asm_output_data (1, DW_LLE_offset_pair,
> "DW_LLE_offset_pair (%s)",
> list_head->ll_symbol);
> @@ -9764,6 +10085,7 @@ output_loc_list (dw_loc_list_ref list_head)
> DW_LLE_start_end with a pair of absolute addresses. */
> else
> {
> + dwarf2out_maybe_output_loclist_view_pair (curr);
> dw2_asm_output_data (1, DW_LLE_start_end,
> "DW_LLE_start_end (%s)",
> list_head->ll_symbol);
> @@ -9842,6 +10164,9 @@ output_loc_list (dw_loc_list_ref list_head)
> "Location list terminator end (%s)",
> list_head->ll_symbol);
> }
> +
> + gcc_assert (!list_head->vl_symbol
> + || vcount == lcount * (dwarf2out_locviews_in_attribute () ? 1 : 0));
> }
>
> /* Output a range_list offset into the .debug_ranges or .debug_rnglists
> @@ -9906,6 +10231,22 @@ output_loc_list_offset (dw_attr_node *a)
> "%s", dwarf_attr_name (a->dw_attr));
> }
>
> +/* Output the offset into the debug_loc section. */
> +
> +static void
> +output_view_list_offset (dw_attr_node *a)
> +{
> + char *sym = (*AT_loc_list_ptr (a))->vl_symbol;
> +
> + gcc_assert (sym);
> + if (dwarf_split_debug_info)
> + dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
> + "%s", dwarf_attr_name (a->dw_attr));
> + else
> + dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> + "%s", dwarf_attr_name (a->dw_attr));
> +}
> +
> /* Output an attribute's index or value appropriately. */
>
> static void
> @@ -10136,6 +10477,10 @@ output_die (dw_die_ref die)
> output_loc_list_offset (a);
> break;
>
> + case dw_val_class_view_list:
> + output_view_list_offset (a);
> + break;
> +
> case dw_val_class_die_ref:
> if (AT_ref_external (a))
> {
> @@ -10308,6 +10653,28 @@ output_die (dw_die_ref die)
> (unsigned long) die->die_offset);
> }
>
> +/* Output the dwarf version number. */
> +
> +static void
> +output_dwarf_version ()
> +{
> + /* ??? For now, if -gdwarf-6 is specified, we output version 5 with
> + views in loclist. That will change eventually. */
> + if (dwarf_version == 6)
> + {
> + static bool once;
> + if (!once)
> + {
> + warning (0,
> + "-gdwarf-6 is output as version 5 with incompatibilities");
> + once = true;
> + }
> + dw2_asm_output_data (2, 5, "DWARF version number");
> + }
> + else
> + dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +}
> +
> /* Output the compilation unit that appears at the beginning of the
> .debug_info section, and precedes the DIE descriptions. */
>
> @@ -10324,7 +10691,7 @@ output_compilation_unit_header (enum dwarf_unit_type ut)
> "Length of Compilation Unit Info");
> }
>
> - dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> + output_dwarf_version ();
> if (dwarf_version >= 5)
> {
> const char *name;
> @@ -10513,7 +10880,7 @@ output_skeleton_debug_sections (dw_die_ref comp_unit,
> - DWARF_INITIAL_LENGTH_SIZE
> + size_of_die (comp_unit),
> "Length of Compilation Unit Info");
> - dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> + output_dwarf_version ();
> if (dwarf_version >= 5)
> {
> dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton");
> @@ -10812,7 +11179,7 @@ output_pubnames (vec<pubname_entry, va_gc> *names)
> }
>
> /* Version number for pubnames/pubtypes is independent of dwarf version. */
> - dw2_asm_output_data (2, 2, "DWARF Version");
> + dw2_asm_output_data (2, 2, "DWARF pubnames/pubtypes version");
>
> if (dwarf_split_debug_info)
> dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> @@ -10894,7 +11261,7 @@ output_aranges (void)
> }
>
> /* Version number for aranges is still 2, even up to DWARF5. */
> - dw2_asm_output_data (2, 2, "DWARF Version");
> + dw2_asm_output_data (2, 2, "DWARF aranges version");
> if (dwarf_split_debug_info)
> dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> debug_skeleton_info_section,
> @@ -11155,7 +11522,7 @@ output_rnglists (void)
> dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
> "Length of Range Lists");
> ASM_OUTPUT_LABEL (asm_out_file, l1);
> - dw2_asm_output_data (2, dwarf_version, "DWARF Version");
> + output_dwarf_version ();
> dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
> dw2_asm_output_data (1, 0, "Segment Size");
> /* Emit the offset table only for -gsplit-dwarf. If we don't care
> @@ -11789,8 +12156,11 @@ output_one_line_info_table (dw_line_info_table *table)
> char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
> unsigned int current_line = 1;
> bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
> - dw_line_info_entry *ent;
> + dw_line_info_entry *ent, *prev_addr;
> size_t i;
> + unsigned int view;
> +
> + view = 0;
>
> FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent)
> {
> @@ -11805,14 +12175,36 @@ output_one_line_info_table (dw_line_info_table *table)
> to determine when it is safe to use DW_LNS_fixed_advance_pc. */
> ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
>
> + view = 0;
> +
> /* This can handle any delta. This takes
> 4+DWARF2_ADDR_SIZE bytes. */
> - dw2_asm_output_data (1, 0, "set address %s", line_label);
> + dw2_asm_output_data (1, 0, "set address %s%s", line_label,
> + debug_variable_location_views
> + ? ", reset view to 0" : "");
> dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
> dw2_asm_output_data (1, DW_LNE_set_address, NULL);
> dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
> +
> + prev_addr = ent;
> break;
>
> + case LI_adv_address:
> + {
> + ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
> + char prev_label[MAX_ARTIFICIAL_LABEL_BYTES];
> + ASM_GENERATE_INTERNAL_LABEL (prev_label, LINE_CODE_LABEL, prev_addr->val);
> +
> + view++;
> +
> + dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, "fixed advance PC, increment view to %i", view);
> + dw2_asm_output_delta (2, line_label, prev_label,
> + "from %s to %s", prev_label, line_label);
> +
> + prev_addr = ent;
> + break;
> + }
> +
> case LI_set_line:
> if (ent->val == current_line)
> {
> @@ -11920,7 +12312,7 @@ output_line_info (bool prologue_only)
>
> ASM_OUTPUT_LABEL (asm_out_file, l1);
>
> - dw2_asm_output_data (2, dwarf_version, "DWARF Version");
> + output_dwarf_version ();
> if (dwarf_version >= 5)
> {
> dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
> @@ -16213,6 +16605,7 @@ static dw_loc_list_ref
> dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
> {
> const char *endname, *secname;
> + var_loc_view endview;
> rtx varloc;
> enum var_init_status initialized;
> struct var_loc_node *node;
> @@ -16268,24 +16661,27 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
> && current_function_decl)
> {
> endname = cfun->fde->dw_fde_end;
> + endview = 0;
> range_across_switch = true;
> }
> /* The variable has a location between NODE->LABEL and
> NODE->NEXT->LABEL. */
> else if (node->next)
> - endname = node->next->label;
> + endname = node->next->label, endview = node->next->view;
> /* If the variable has a location at the last label
> it keeps its location until the end of function. */
> else if (!current_function_decl)
> - endname = text_end_label;
> + endname = text_end_label, endview = 0;
> else
> {
> ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
> current_function_funcdef_no);
> endname = ggc_strdup (label_id);
> + endview = 0;
> }
>
> - *listp = new_loc_list (descr, node->label, endname, secname);
> + *listp = new_loc_list (descr, node->label, node->view,
> + endname, endview, secname);
> if (TREE_CODE (decl) == PARM_DECL
> && node == loc_list->first
> && NOTE_P (node->loc)
> @@ -16308,12 +16704,12 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
> /* The variable has a location between NODE->LABEL and
> NODE->NEXT->LABEL. */
> if (node->next)
> - endname = node->next->label;
> + endname = node->next->label, endview = node->next->view;
> else
> - endname = cfun->fde->dw_fde_second_end;
> + endname = cfun->fde->dw_fde_second_end, endview = 0;
> *listp = new_loc_list (descr,
> - cfun->fde->dw_fde_second_begin,
> - endname, secname);
> + cfun->fde->dw_fde_second_begin, 0,
> + endname, endview, secname);
> listp = &(*listp)->dw_loc_next;
> }
> }
> @@ -16325,8 +16721,7 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
> representable, we don't want to pretend a single entry that was
> applies to the entire scope in which the variable is
> available. */
> - if (list && loc_list->first->next)
> - gen_llsym (list);
> + maybe_gen_llsym (list);
>
> return list;
> }
> @@ -17146,7 +17541,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
> {
> if (dwarf_version >= 3 || !dwarf_strict)
> return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
> - NULL, NULL, NULL);
> + NULL, 0, NULL, 0, NULL);
> else
> return NULL;
> }
> @@ -17959,7 +18354,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
> add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
> }
> if (ret)
> - list_ret = new_loc_list (ret, NULL, NULL, NULL);
> + list_ret = new_loc_list (ret, NULL, 0, NULL, 0, NULL);
>
> return list_ret;
> }
> @@ -18283,12 +18678,25 @@ static inline void
> add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
> dw_loc_list_ref descr)
> {
> + bool check_no_locviews = true;
> if (descr == 0)
> return;
> if (single_element_loc_list_p (descr))
> add_AT_loc (die, attr_kind, descr->expr);
> else
> - add_AT_loc_list (die, attr_kind, descr);
> + {
> + add_AT_loc_list (die, attr_kind, descr);
> + gcc_assert (descr->ll_symbol);
> + if (attr_kind == DW_AT_location && descr->vl_symbol
> + && dwarf2out_locviews_in_attribute ())
> + {
> + add_AT_view_list (die, DW_AT_GNU_locviews);
> + check_no_locviews = false;
> + }
> + }
> +
> + if (check_no_locviews)
> + gcc_assert (!get_AT (die, DW_AT_GNU_locviews));
> }
>
> /* Add DW_AT_accessibility attribute to DIE if needed. */
> @@ -19458,7 +19866,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
> /* If the first partition contained no CFI adjustments, the
> CIE opcodes apply to the whole first partition. */
> *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
> - fde->dw_fde_begin, fde->dw_fde_end, section);
> + fde->dw_fde_begin, 0, fde->dw_fde_end, 0, section);
> list_tail =&(*list_tail)->dw_loc_next;
> start_label = last_label = fde->dw_fde_second_begin;
> }
> @@ -19474,7 +19882,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
> if (!cfa_equal_p (&last_cfa, &next_cfa))
> {
> *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
> - start_label, last_label, section);
> + start_label, 0, last_label, 0, section);
>
> list_tail = &(*list_tail)->dw_loc_next;
> last_cfa = next_cfa;
> @@ -19496,14 +19904,14 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
> if (!cfa_equal_p (&last_cfa, &next_cfa))
> {
> *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
> - start_label, last_label, section);
> + start_label, 0, last_label, 0, section);
>
> list_tail = &(*list_tail)->dw_loc_next;
> last_cfa = next_cfa;
> start_label = last_label;
> }
> *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
> - start_label, fde->dw_fde_end, section);
> + start_label, 0, fde->dw_fde_end, 0, section);
> list_tail = &(*list_tail)->dw_loc_next;
> start_label = last_label = fde->dw_fde_second_begin;
> }
> @@ -19512,19 +19920,18 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
> if (!cfa_equal_p (&last_cfa, &next_cfa))
> {
> *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
> - start_label, last_label, section);
> + start_label, 0, last_label, 0, section);
> list_tail = &(*list_tail)->dw_loc_next;
> start_label = last_label;
> }
>
> *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
> - start_label,
> + start_label, 0,
> fde->dw_fde_second_begin
> - ? fde->dw_fde_second_end : fde->dw_fde_end,
> + ? fde->dw_fde_second_end : fde->dw_fde_end, 0,
> section);
>
> - if (list && list->dw_loc_next)
> - gen_llsym (list);
> + maybe_gen_llsym (list);
>
> return list;
> }
> @@ -22636,6 +23043,48 @@ block_die_hasher::equal (die_struct *x, die_struct *y)
> return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
> }
>
> +/* Hold information about markers for inlined entry points. */
> +struct GTY ((for_user)) inline_entry_data
> +{
> + /* The block that's the inlined_function_outer_scope for an inlined
> + function. */
> + tree block;
> +
> + /* The label at the inlined entry point. */
> + const char *label_pfx;
> + unsigned int label_num;
> +
> + /* The view number to be used as the inlined entry point. */
> + var_loc_view view;
> +};
> +
> +struct inline_entry_data_hasher : ggc_ptr_hash <inline_entry_data>
> +{
> + typedef tree compare_type;
> + static inline hashval_t hash (const inline_entry_data *);
> + static inline bool equal (const inline_entry_data *, const_tree);
> +};
> +
> +/* Hash table routines for inline_entry_data. */
> +
> +inline hashval_t
> +inline_entry_data_hasher::hash (const inline_entry_data *data)
> +{
> + return htab_hash_pointer (data->block);
> +}
> +
> +inline bool
> +inline_entry_data_hasher::equal (const inline_entry_data *data,
> + const_tree block)
> +{
> + return data->block == block;
> +}
> +
> +/* Inlined entry points pending DIE creation in this compilation unit. */
> +
> +static GTY(()) hash_table<inline_entry_data_hasher> *inline_entry_data_table;
> +
> +
> /* Return TRUE if DECL, which may have been previously generated as
> OLD_DIE, is a candidate for a DW_AT_specification. DECLARATION is
> true if decl (or its origin) is either an extern declaration or a
> @@ -23072,6 +23521,42 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
> {
> char label[MAX_ARTIFICIAL_LABEL_BYTES];
>
> + if (inline_entry_data **iedp
> + = !inline_entry_data_table ? NULL
> + : inline_entry_data_table->find_slot_with_hash (stmt,
> + htab_hash_pointer (stmt),
> + NO_INSERT))
> + {
> + inline_entry_data *ied = *iedp;
> + gcc_assert (debug_nonbind_markers_p);
> + gcc_assert (inlined_function_outer_scope_p (stmt));
> + ASM_GENERATE_INTERNAL_LABEL (label, ied->label_pfx, ied->label_num);
> + add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +
> + if (debug_variable_location_views && !ZERO_VIEW_P (ied->view))
> + {
> + if (!output_asm_line_debug_info ())
> + add_AT_unsigned (die, DW_AT_GNU_entry_view, ied->view);
> + else
> + {
> + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", ied->view);
> + /* FIXME: this will resolve to a small number. Could we
> + possibly emit smaller data? Ideally we'd emit a
> + uleb128, but that would make the size of DIEs
> + impossible for the compiler to compute, since it's
> + the assembler that computes the value of the view
> + label in this case. Ideally, we'd have a single form
> + encompassing both the address and the view, and
> + indirecting them through a table might make things
> + easier, but even that would be more wasteful,
> + space-wise, than what we have now. */
> + add_AT_lbl_id (die, DW_AT_GNU_entry_view, label);
> + }
> + }
> +
> + inline_entry_data_table->clear_slot (iedp);
> + }
> +
> if (BLOCK_FRAGMENT_CHAIN (stmt)
> && (dwarf_version >= 3 || !dwarf_strict))
> {
> @@ -23079,7 +23564,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
> dw_die_ref pdie;
> dw_attr_node *attr = NULL;
>
> - if (inlined_function_outer_scope_p (stmt))
> + if (!debug_nonbind_markers_p && inlined_function_outer_scope_p (stmt))
> {
> ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
> BLOCK_NUMBER (stmt));
> @@ -23250,7 +23735,7 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
> dw_die_ref subr_die
> = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
>
> - if (call_arg_locations)
> + if (call_arg_locations || debug_nonbind_markers_p)
> BLOCK_DIE (stmt) = subr_die;
> add_abstract_origin_attribute (subr_die, decl);
> if (TREE_ASM_WRITTEN (stmt))
> @@ -25922,7 +26407,7 @@ maybe_emit_file (struct dwarf_file_data * fd)
> fd->emitted_number = 1;
> last_emitted_file = fd;
>
> - if (DWARF2_ASM_LINE_DEBUG_INFO)
> + if (output_asm_line_debug_info ())
> {
> fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
> output_quoted_string (asm_out_file,
> @@ -26082,6 +26567,22 @@ static bool maybe_at_text_label_p = true;
> /* One above highest N where .LVLN label might be equal to .Ltext0 label. */
> static unsigned int first_loclabel_num_not_at_text_label;
>
> +/* Look ahead for a real insn, or for a begin stmt marker. */
> +
> +static rtx_insn *
> +dwarf2out_next_real_insn (rtx_insn *loc_note)
> +{
> + rtx_insn *next_real = NEXT_INSN (loc_note);
> +
> + while (next_real)
> + if (INSN_P (next_real))
> + break;
> + else
> + next_real = NEXT_INSN (next_real);
> +
> + return next_real;
> +}
> +
> /* Called by the final INSN scan whenever we see a var location. We
> use it to drop labels in the right places, and throw the location in
> our lookup table. */
> @@ -26099,11 +26600,13 @@ dwarf2out_var_location (rtx_insn *loc_note)
> static rtx_insn *expected_next_loc_note;
> tree decl;
> bool var_loc_p;
> + var_loc_view view = 0;
>
> if (!NOTE_P (loc_note))
> {
> if (CALL_P (loc_note))
> {
> + RESET_NEXT_VIEW (cur_line_info_table->view);
> call_site_count++;
> if (SIBLING_CALL_P (loc_note))
> tail_call_site_count++;
> @@ -26130,13 +26633,25 @@ dwarf2out_var_location (rtx_insn *loc_note)
> loc_note = NULL;
> var_loc_p = false;
>
> - next_real = next_real_insn (call_insn);
> + next_real = dwarf2out_next_real_insn (call_insn);
> next_note = NULL;
> cached_next_real_insn = NULL;
> goto create_label;
> }
> }
> }
> + else if (!debug_variable_location_views)
> + gcc_unreachable ();
> + else if (JUMP_TABLE_DATA_P (loc_note))
> + RESET_NEXT_VIEW (cur_line_info_table->view);
> + else if (GET_CODE (loc_note) == USE
> + || GET_CODE (loc_note) == CLOBBER
> + || GET_CODE (loc_note) == ASM_INPUT
> + || asm_noperands (loc_note) >= 0)
> + ;
> + else if (get_attr_min_length (loc_note) > 0)
> + RESET_NEXT_VIEW (cur_line_info_table->view);
> +
> return;
> }
>
> @@ -26160,11 +26675,13 @@ dwarf2out_var_location (rtx_insn *loc_note)
> || next_note->deleted ()
> || ! NOTE_P (next_note)
> || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
> + && NOTE_KIND (next_note) != NOTE_INSN_BEGIN_STMT
> + && NOTE_KIND (next_note) != NOTE_INSN_INLINE_ENTRY
> && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
> next_note = NULL;
>
> if (! next_real)
> - next_real = next_real_insn (loc_note);
> + next_real = dwarf2out_next_real_insn (loc_note);
>
> if (next_note)
> {
> @@ -26199,10 +26716,11 @@ create_label:
>
> if (var_loc_p)
> {
> + const char *label = NOTE_DURING_CALL_P (loc_note)
> + ? last_postcall_label : last_label;
> + view = cur_line_info_table->view;
> decl = NOTE_VAR_LOCATION_DECL (loc_note);
> - newloc = add_var_loc_to_decl (decl, loc_note,
> - NOTE_DURING_CALL_P (loc_note)
> - ? last_postcall_label : last_label);
> + newloc = add_var_loc_to_decl (decl, loc_note, label, view);
> if (newloc == NULL)
> return;
> }
> @@ -26243,8 +26761,8 @@ create_label:
> else if (GET_CODE (body) == ASM_INPUT
> || asm_noperands (body) >= 0)
> continue;
> -#ifdef HAVE_attr_length
> - else if (get_attr_min_length (insn) == 0)
> +#ifdef HAVE_ATTR_length /* ??? We don't include insn-attr.h. */
> + else if (HAVE_ATTR_length && get_attr_min_length (insn) == 0)
> continue;
> #endif
> else
> @@ -26312,7 +26830,10 @@ create_label:
> call_arg_loc_last = ca_loc;
> }
> else if (loc_note != NULL_RTX && !NOTE_DURING_CALL_P (loc_note))
> - newloc->label = last_label;
> + {
> + newloc->label = last_label;
> + newloc->view = view;
> + }
> else
> {
> if (!last_postcall_label)
> @@ -26321,12 +26842,123 @@ create_label:
> last_postcall_label = ggc_strdup (loclabel);
> }
> newloc->label = last_postcall_label;
> + newloc->view = view;
> + }
> +
> + if (var_loc_p && flag_debug_asm)
> + {
> + const char *name = NULL, *sep = " => ", *patstr = NULL;
> + if (decl && DECL_NAME (decl))
> + name = IDENTIFIER_POINTER (DECL_NAME (decl));
> + if (NOTE_VAR_LOCATION_LOC (loc_note))
> + patstr = str_pattern_slim (NOTE_VAR_LOCATION_LOC (loc_note));
> + else
> + {
> + sep = " ";
> + patstr = "RESET";
> + }
> + fprintf (asm_out_file, "\t%s DEBUG %s%s%s\n", ASM_COMMENT_START,
> + name, sep, patstr);
> }
>
> last_var_location_insn = next_real;
> last_in_cold_section_p = in_cold_section_p;
> }
>
> +/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
> + OUTER itself. */
> +static bool
> +block_within_block_p (tree block, tree outer)
> +{
> + if (block == outer)
> + return true;
> +
> + /* Quickly check that OUTER is up BLOCK's supercontext chain. */
> + for (tree context = BLOCK_SUPERCONTEXT (block);
> + context != outer;
> + context = BLOCK_SUPERCONTEXT (context))
> + if (!context || TREE_CODE (context) != BLOCK)
> + return false;
> +
> + /* Now check that each block is actually referenced by its
> + parent. */
> + for (tree context = BLOCK_SUPERCONTEXT (block); ;
> + context = BLOCK_SUPERCONTEXT (context))
> + {
> + if (BLOCK_FRAGMENT_ORIGIN (context))
> + {
> + gcc_assert (!BLOCK_SUBBLOCKS (context));
> + context = BLOCK_FRAGMENT_ORIGIN (context);
> + }
> + for (tree sub = BLOCK_SUBBLOCKS (context);
> + sub != block;
> + sub = BLOCK_CHAIN (sub))
> + if (!sub)
> + return false;
> + if (context == outer)
> + return true;
> + else
> + block = context;
> + }
> +}
> +
> +/* Called during final while assembling the marker of the entry point
> + for an inlined function. */
> +
> +static void
> +dwarf2out_inline_entry (tree block)
> +{
> + gcc_assert (DECL_P (block_ultimate_origin (block)));
> +
> + gcc_checking_assert (block_within_block_p (block,
> + DECL_INITIAL
> + (current_function_decl)));
> +
> + gcc_assert (inlined_function_outer_scope_p (block));
> + gcc_assert (!BLOCK_DIE (block));
> +
> + /* If we can't represent it, don't bother. */
> + if (!(dwarf_version >= 3 || !dwarf_strict))
> + return;
> +
> + if (BLOCK_FRAGMENT_ORIGIN (block))
> + block = BLOCK_FRAGMENT_ORIGIN (block);
> + /* Can the entry point ever not be at the beginning of an
> + unfragmented lexical block? */
> + else if (!(BLOCK_FRAGMENT_CHAIN (block)
> + || (cur_line_info_table
> + && !ZERO_VIEW_P (cur_line_info_table->view))))
> + return;
> +
> + if (!inline_entry_data_table)
> + inline_entry_data_table
> + = hash_table<inline_entry_data_hasher>::create_ggc (10);
> +
> +
> + inline_entry_data **iedp
> + = inline_entry_data_table->find_slot_with_hash (block,
> + htab_hash_pointer (block),
> + INSERT);
> + if (*iedp)
> + /* ??? Ideally, we'd record all entry points for the same inlined
> + function (some may have been duplicated by e.g. unrolling), but
> + we have no way to represent that ATM. */
> + return;
> +
> + inline_entry_data *ied = *iedp = ggc_cleared_alloc<inline_entry_data> ();
> + ied->block = block;
> + ied->label_pfx = BLOCK_INLINE_ENTRY_LABEL;
> + ied->label_num = BLOCK_NUMBER (block);
> + if (cur_line_info_table)
> + ied->view = cur_line_info_table->view;
> +
> + char label[MAX_ARTIFICIAL_LABEL_BYTES];
> +
> + ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_INLINE_ENTRY_LABEL,
> + BLOCK_NUMBER (block));
> + ASM_OUTPUT_LABEL (asm_out_file, label);
> +}
> +
> /* Called from finalize_size_functions for size functions so that their body
> can be encoded in the debug info to describe the layout of variable-length
> structures. */
> @@ -26371,6 +27003,7 @@ new_line_info_table (void)
> table->file_num = 1;
> table->line_num = 1;
> table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
> + RESET_NEXT_VIEW (table->view);
>
> return table;
> }
> @@ -26419,7 +27052,7 @@ set_cur_line_info_table (section *sec)
> vec_safe_push (separate_line_info, table);
> }
>
> - if (DWARF2_ASM_LINE_DEBUG_INFO)
> + if (output_asm_line_debug_info ())
> table->is_stmt = (cur_line_info_table
> ? cur_line_info_table->is_stmt
> : DWARF_LINE_DEFAULT_IS_STMT_START);
> @@ -26600,7 +27233,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
> filename, line);
> }
>
> - if (DWARF2_ASM_LINE_DEBUG_INFO)
> + if (output_asm_line_debug_info ())
> {
> /* Emit the .loc directive understood by GNU as. */
> /* "\t.loc %u %u 0 is_stmt %u discriminator %u",
> @@ -26626,6 +27259,33 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
> fputs (" discriminator ", asm_out_file);
> fprint_ul (asm_out_file, (unsigned long) discriminator);
> }
> + if (debug_variable_location_views)
> + {
> + static var_loc_view lvugid;
> + if (!lvugid)
> + {
> + gcc_assert (!zero_view_p);
> + zero_view_p = BITMAP_GGC_ALLOC ();
> + bitmap_set_bit (zero_view_p, 0);
> + }
> + if (RESETTING_VIEW_P (table->view))
> + {
> + if (!table->in_use)
> + fputs (" view -0", asm_out_file);
> + else
> + fputs (" view 0", asm_out_file);
> + bitmap_set_bit (zero_view_p, lvugid);
> + table->view = ++lvugid;
> + }
> + else
> + {
> + fputs (" view ", asm_out_file);
> + char label[MAX_ARTIFICIAL_LABEL_BYTES];
> + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
> + assemble_name (asm_out_file, label);
> + table->view = ++lvugid;
> + }
> + }
> putc ('\n', asm_out_file);
> }
> else
> @@ -26634,7 +27294,19 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>
> targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
>
> - push_dw_line_info_entry (table, LI_set_address, label_num);
> + if (debug_variable_location_views && table->view)
> + push_dw_line_info_entry (table, LI_adv_address, label_num);
> + else
> + push_dw_line_info_entry (table, LI_set_address, label_num);
> + if (debug_variable_location_views)
> + {
> + if (flag_debug_asm)
> + fprintf (asm_out_file, "\t%s view %s%d\n",
> + ASM_COMMENT_START,
> + table->in_use ? "" : "-",
> + table->view);
> + table->view++;
> + }
> if (file_num != table->file_num)
> push_dw_line_info_entry (table, LI_set_file, file_num);
> if (discriminator != table->discrim_num)
> @@ -27223,7 +27895,7 @@ init_sections_and_labels (void)
> SECTION_DEBUG, NULL);
> debug_str_section = get_section (DEBUG_STR_SECTION,
> DEBUG_STR_SECTION_FLAGS, NULL);
> - if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
> + if (!dwarf_split_debug_info && !output_asm_line_debug_info ())
> debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
> DEBUG_STR_SECTION_FLAGS, NULL);
>
> @@ -27608,6 +28280,11 @@ prune_unused_types_walk_attribs (dw_die_ref die)
> prune_unused_types_walk_loc_descr (list->expr);
> break;
>
> + case dw_val_class_view_list:
> + /* This points to a loc_list in another attribute, so it's
> + already covered. */
> + break;
> +
> case dw_val_class_die_ref:
> /* A reference to another DIE.
> Make sure that it will get emitted.
> @@ -28707,6 +29384,8 @@ optimize_string_length (dw_attr_node *a)
> if (d->expr && non_dwarf_expression (d->expr))
> non_dwarf_expr = true;
> break;
> + case dw_val_class_view_list:
> + gcc_unreachable ();
> case dw_val_class_loc:
> lv = AT_loc (av);
> if (lv == NULL)
> @@ -28751,7 +29430,7 @@ optimize_string_length (dw_attr_node *a)
> lv = copy_deref_exprloc (d->expr);
> if (lv)
> {
> - *p = new_loc_list (lv, d->begin, d->end, d->section);
> + *p = new_loc_list (lv, d->begin, d->vbegin, d->end, d->vend, d->section);
> p = &(*p)->dw_loc_next;
> }
> else if (!dwarf_strict && d->expr)
> @@ -28821,6 +29500,7 @@ resolve_addr (dw_die_ref die)
> {
> gcc_assert (!next->ll_symbol);
> next->ll_symbol = (*curr)->ll_symbol;
> + next->vl_symbol = (*curr)->vl_symbol;
> }
> if (dwarf_split_debug_info)
> remove_loc_list_addr_table_entries (l);
> @@ -28846,6 +29526,21 @@ resolve_addr (dw_die_ref die)
> ix--;
> }
> break;
> + case dw_val_class_view_list:
> + {
> + gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
> + gcc_checking_assert (dwarf2out_locviews_in_attribute ());
> + dw_val_node *llnode
> + = view_list_to_loc_list_val_node (&a->dw_attr_val);
> + /* If we no longer have a loclist, or it no longer needs
> + views, drop this attribute. */
> + if (!llnode || !llnode->v.val_loc_list->vl_symbol)
> + {
> + remove_AT (die, a->dw_attr);
> + ix--;
> + }
> + break;
> + }
> case dw_val_class_loc:
> {
> dw_loc_descr_ref l = AT_loc (a);
> @@ -29242,6 +29937,8 @@ hash_loc_list (dw_loc_list_ref list_head)
> {
> hstate.add (curr->begin, strlen (curr->begin) + 1);
> hstate.add (curr->end, strlen (curr->end) + 1);
> + hstate.add_object (curr->vbegin);
> + hstate.add_object (curr->vend);
> if (curr->section)
> hstate.add (curr->section, strlen (curr->section) + 1);
> hash_locs (curr->expr, hstate);
> @@ -29463,6 +30160,7 @@ loc_list_hasher::equal (const dw_loc_list_struct *a,
> || strcmp (a->end, b->end) != 0
> || (a->section == NULL) != (b->section == NULL)
> || (a->section && strcmp (a->section, b->section) != 0)
> + || a->vbegin != b->vbegin || a->vend != b->vend
> || !compare_locs (a->expr, b->expr))
> break;
> return a == NULL && b == NULL;
> @@ -29481,6 +30179,8 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab)
> dw_attr_node *a;
> unsigned ix;
> dw_loc_list_struct **slot;
> + bool drop_locviews = false;
> + bool has_locviews = false;
>
> FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
> if (AT_class (a) == dw_val_class_loc_list)
> @@ -29491,10 +30191,32 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab)
> hash_loc_list (list);
> slot = htab->find_slot_with_hash (list, list->hash, INSERT);
> if (*slot == NULL)
> - *slot = list;
> + {
> + *slot = list;
> + if (loc_list_has_views (list))
> + gcc_assert (list->vl_symbol);
> + else if (list->vl_symbol)
> + {
> + drop_locviews = true;
> + list->vl_symbol = NULL;
> + }
> + }
> else
> - a->dw_attr_val.v.val_loc_list = *slot;
> + {
> + if (list->vl_symbol && !(*slot)->vl_symbol)
> + drop_locviews = true;
> + a->dw_attr_val.v.val_loc_list = *slot;
> + }
> }
> + else if (AT_class (a) == dw_val_class_view_list)
> + {
> + gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
> + has_locviews = true;
> + }
> +
> +
> + if (drop_locviews && has_locviews)
> + remove_AT (die, DW_AT_GNU_locviews);
>
> FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
> }
> @@ -29520,7 +30242,7 @@ index_location_lists (dw_die_ref die)
> /* Don't index an entry that has already been indexed
> or won't be output. */
> if (curr->begin_entry != NULL
> - || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
> + || skip_loc_list_entry (curr))
> continue;
>
> curr->begin_entry
> @@ -29612,6 +30334,9 @@ dwarf2out_finish (const char *)
> /* Flush out any latecomers to the limbo party. */
> flush_limbo_die_list ();
>
> + if (inline_entry_data_table)
> + gcc_assert (inline_entry_data_table->elements () == 0);
> +
> if (flag_checking)
> {
> verify_die (comp_unit_die ());
> @@ -29897,7 +30622,7 @@ dwarf2out_finish (const char *)
> dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
> "Length of Location Lists");
> ASM_OUTPUT_LABEL (asm_out_file, l1);
> - dw2_asm_output_data (2, dwarf_version, "DWARF Version");
> + output_dwarf_version ();
> dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
> dw2_asm_output_data (1, 0, "Segment Size");
> dw2_asm_output_data (4, dwarf_split_debug_info ? loc_list_idx : 0,
> @@ -29955,7 +30680,7 @@ dwarf2out_finish (const char *)
> used by the debug_info section are marked as 'used'. */
> switch_to_section (debug_line_section);
> ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
> - if (! DWARF2_ASM_LINE_DEBUG_INFO)
> + if (! output_asm_line_debug_info ())
> output_line_info (false);
>
> if (dwarf_split_debug_info && info_section_emitted)
> diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
> index 9402473..a7653ce 100644
> --- a/gcc/dwarf2out.h
> +++ b/gcc/dwarf2out.h
> @@ -157,7 +157,8 @@ enum dw_val_class
> dw_val_class_discr_list,
> dw_val_class_const_implicit,
> dw_val_class_unsigned_const_implicit,
> - dw_val_class_file_implicit
> + dw_val_class_file_implicit,
> + dw_val_class_view_list
> };
>
> /* Describe a floating point constant value, or a vector constant value. */
> @@ -200,6 +201,7 @@ struct GTY(()) dw_val_node {
> rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
> unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
> dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
> + dw_die_ref GTY ((tag ("dw_val_class_view_list"))) val_view_list;
> dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
> HOST_WIDE_INT GTY ((default)) val_int;
> unsigned HOST_WIDE_INT
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index 6951f61..a6efdd8 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -3346,20 +3346,17 @@ next_nonnote_insn (rtx_insn *insn)
> return insn;
> }
>
> -/* Return the next insn after INSN that is not a NOTE, but stop the
> - search before we enter another basic block. This routine does not
> - look inside SEQUENCEs. */
> +/* Return the next insn after INSN that is not a DEBUG_INSN. This
> + routine does not look inside SEQUENCEs. */
>
> rtx_insn *
> -next_nonnote_insn_bb (rtx_insn *insn)
> +next_nondebug_insn (rtx_insn *insn)
> {
> while (insn)
> {
> insn = NEXT_INSN (insn);
> - if (insn == 0 || !NOTE_P (insn))
> + if (insn == 0 || !DEBUG_INSN_P (insn))
> break;
> - if (NOTE_INSN_BASIC_BLOCK_P (insn))
> - return NULL;
> }
>
> return insn;
> @@ -3381,67 +3378,70 @@ prev_nonnote_insn (rtx_insn *insn)
> return insn;
> }
>
> -/* Return the previous insn before INSN that is not a NOTE, but stop
> - the search before we enter another basic block. This routine does
> - not look inside SEQUENCEs. */
> +/* Return the previous insn before INSN that is not a DEBUG_INSN.
> + This routine does not look inside SEQUENCEs. */
>
> rtx_insn *
> -prev_nonnote_insn_bb (rtx_insn *insn)
> +prev_nondebug_insn (rtx_insn *insn)
> {
> -
> while (insn)
> {
> insn = PREV_INSN (insn);
> - if (insn == 0 || !NOTE_P (insn))
> + if (insn == 0 || !DEBUG_INSN_P (insn))
> break;
> - if (NOTE_INSN_BASIC_BLOCK_P (insn))
> - return NULL;
> }
>
> return insn;
> }
>
> -/* Return the next insn after INSN that is not a DEBUG_INSN. This
> - routine does not look inside SEQUENCEs. */
> +/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN.
> + This routine does not look inside SEQUENCEs. */
>
> rtx_insn *
> -next_nondebug_insn (rtx_insn *insn)
> +next_nonnote_nondebug_insn (rtx_insn *insn)
> {
> while (insn)
> {
> insn = NEXT_INSN (insn);
> - if (insn == 0 || !DEBUG_INSN_P (insn))
> + if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn)))
> break;
> }
>
> return insn;
> }
>
> -/* Return the previous insn before INSN that is not a DEBUG_INSN.
> - This routine does not look inside SEQUENCEs. */
> +/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN,
> + but stop the search before we enter another basic block. This
> + routine does not look inside SEQUENCEs. */
>
> rtx_insn *
> -prev_nondebug_insn (rtx_insn *insn)
> +next_nonnote_nondebug_insn_bb (rtx_insn *insn)
> {
> while (insn)
> {
> - insn = PREV_INSN (insn);
> - if (insn == 0 || !DEBUG_INSN_P (insn))
> + insn = NEXT_INSN (insn);
> + if (insn == 0)
> + break;
> + if (DEBUG_INSN_P (insn))
> + continue;
> + if (!NOTE_P (insn))
> break;
> + if (NOTE_INSN_BASIC_BLOCK_P (insn))
> + return NULL;
> }
>
> return insn;
> }
>
> -/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN.
> +/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN.
> This routine does not look inside SEQUENCEs. */
>
> rtx_insn *
> -next_nonnote_nondebug_insn (rtx_insn *insn)
> +prev_nonnote_nondebug_insn (rtx_insn *insn)
> {
> while (insn)
> {
> - insn = NEXT_INSN (insn);
> + insn = PREV_INSN (insn);
> if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn)))
> break;
> }
> @@ -3449,17 +3449,24 @@ next_nonnote_nondebug_insn (rtx_insn *insn)
> return insn;
> }
>
> -/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN.
> - This routine does not look inside SEQUENCEs. */
> +/* Return the previous insn before INSN that is not a NOTE nor
> + DEBUG_INSN, but stop the search before we enter another basic
> + block. This routine does not look inside SEQUENCEs. */
>
> rtx_insn *
> -prev_nonnote_nondebug_insn (rtx_insn *insn)
> +prev_nonnote_nondebug_insn_bb (rtx_insn *insn)
> {
> while (insn)
> {
> insn = PREV_INSN (insn);
> - if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn)))
> + if (insn == 0)
> break;
> + if (DEBUG_INSN_P (insn))
> + continue;
> + if (!NOTE_P (insn))
> + break;
> + if (NOTE_INSN_BASIC_BLOCK_P (insn))
> + return NULL;
> }
>
> return insn;
> diff --git a/gcc/final.c b/gcc/final.c
> index ad999f7..cfe615e 100644
> --- a/gcc/final.c
> +++ b/gcc/final.c
> @@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
> #include "asan.h"
> #include "rtl-iter.h"
> #include "print-rtl.h"
> +#include "langhooks.h"
>
> #ifdef XCOFF_DEBUGGING_INFO
> #include "xcoffout.h" /* Needed for external data declarations. */
> @@ -112,6 +113,7 @@ along with GCC; see the file COPYING3. If not see
> /* Bitflags used by final_scan_insn. */
> #define SEEN_NOTE 1
> #define SEEN_EMITTED 2
> +#define SEEN_NEXT_VIEW 4
>
> /* Last insn processed by final_scan_insn. */
> static rtx_insn *debug_insn;
> @@ -1653,7 +1655,6 @@ reemit_insn_block_notes (void)
> {
> tree cur_block = DECL_INITIAL (cfun->decl);
> rtx_insn *insn;
> - rtx_note *note;
>
> insn = get_insns ();
> for (; insn; insn = NEXT_INSN (insn))
> @@ -1661,17 +1662,30 @@ 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:
> + case NOTE_INSN_INLINE_ENTRY:
> + this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
> + goto set_cur_block_to_this_block;
> +
> + default:
> + continue;
> + }
>
> if (!active_insn_p (insn))
> continue;
> @@ -1692,6 +1706,7 @@ reemit_insn_block_notes (void)
> this_block = choose_inner_scope (this_block,
> insn_scope (body->insn (i)));
> }
> + set_cur_block_to_this_block:
> if (! this_block)
> {
> if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
> @@ -1708,7 +1723,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);
>
> @@ -1747,6 +1762,44 @@ get_some_local_dynamic_name ()
> return 0;
> }
>
> +/* Arrange for us to emit a source location note before any further
> + real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
> + *SEEN, as long as we are keeping track of location views. The bit
> + indicates we have referenced the next view at the current PC, so we
> + have to emit it. This should be called next to the var_location
> + debug hook. */
> +
> +static inline void
> +set_next_view_needed (int *seen)
> +{
> + if (debug_variable_location_views)
> + *seen |= SEEN_NEXT_VIEW;
> +}
> +
> +/* Clear the flag in *SEEN indicating we need to emit the next view.
> + This should be called next to the source_line debug hook. */
> +
> +static inline void
> +clear_next_view_needed (int *seen)
> +{
> + *seen &= ~SEEN_NEXT_VIEW;
> +}
> +
> +/* Test whether we have a pending request to emit the next view in
> + *SEEN, and emit it if needed, clearing the request bit. */
> +
> +static inline void
> +maybe_output_next_view (int *seen)
> +{
> + if ((*seen & SEEN_NEXT_VIEW) != 0)
> + {
> + clear_next_view_needed (seen);
> + (*debug_hooks->source_line) (last_linenum, last_columnnum,
> + last_filename, last_discriminator,
> + false);
> + }
> +}
> +
> /* Output assembler code for the start of a function,
> and initialize some of the variables in this file
> for the new function. The label for the function and associated
> @@ -1754,13 +1807,18 @@ get_some_local_dynamic_name ()
>
> FIRST is the first insn of the rtl for the function being compiled.
> FILE is the file to write assembler code to.
> + SEEN should be initially set to zero, and it may be updated to
> + indicate we have references to the next location view, that would
> + require us to emit it at the current PC.
> OPTIMIZE_P is nonzero if we should eliminate redundant
> test and compare insns. */
>
> -void
> -final_start_function (rtx_insn *first, FILE *file,
> - int optimize_p ATTRIBUTE_UNUSED)
> +static void
> +final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
> + int optimize_p ATTRIBUTE_UNUSED)
> {
> + rtx_insn *first = *firstp;
> +
> block_depth = 0;
>
> this_is_asm_operands = 0;
> @@ -1778,7 +1836,28 @@ final_start_function (rtx_insn *first, FILE *file,
> asan_function_start ();
>
> if (!DECL_IGNORED_P (current_function_decl))
> - debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
> + {
> + /* Emit param bindings (before the first begin_stmt) in the
> + initial view. We don't test whether the DECLs are
> + PARM_DECLs: the assumption is that there will be a
> + NOTE_INSN_BEGIN_STMT marker before any non-parameter
> + NOTE_INSN_VAR_LOCATION. It's ok if the marker is not there,
> + we'll just have more variable locations bound in the initial
> + view, which is consistent with their being bound without any
> + code that would give them a value. */
> + if (debug_variable_location_views)
> + {
> + rtx_insn *insn;
> + for (insn = first;
> + insn && GET_CODE (insn) == NOTE
> + && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
> + insn = NEXT_INSN (insn))
> + final_scan_insn (insn, file, 0, 0, seen);
> + *firstp = insn;
> + }
> + debug_hooks->begin_prologue (last_linenum, last_columnnum,
> + last_filename);
> + }
>
> if (!dwarf2_debug_info_emitted_p (current_function_decl))
> dwarf2out_begin_prologue (0, 0, NULL);
> @@ -1853,6 +1932,17 @@ final_start_function (rtx_insn *first, FILE *file,
> profile_after_prologue (file);
> }
>
> +/* This is an exported final_start_function_1, callable without SEEN. */
> +
> +void
> +final_start_function (rtx_insn **firstp, FILE *file,
> + int optimize_p ATTRIBUTE_UNUSED)
> +{
> + int seen = 0;
> + final_start_function_1 (firstp, file, &seen, optimize_p);
> + gcc_assert (seen == 0);
> +}
> +
> static void
> profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
> {
> @@ -1984,11 +2074,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
> /* Output assembler code for some insns: all or part of a function.
> For description of args, see `final_start_function', above. */
>
> -void
> -final (rtx_insn *first, FILE *file, int optimize_p)
> +static void
> +final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
> {
> rtx_insn *insn, *next;
> - int seen = 0;
>
> /* Used for -dA dump. */
> basic_block *start_to_bb = NULL;
> @@ -2055,6 +2144,8 @@ final (rtx_insn *first, FILE *file, int optimize_p)
> insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
> }
>
> + maybe_output_next_view (&seen);
> +
> if (flag_debug_asm)
> {
> free (start_to_bb);
> @@ -2071,6 +2162,14 @@ final (rtx_insn *first, FILE *file, int optimize_p)
> delete_insn (insn);
> }
> }
> +
> +/* This is an exported final_1, callable without SEEN. */
> +
> +void
> +final (rtx_insn *first, FILE *file, int optimize_p)
> +{
> + final_1 (first, file, 0, optimize_p);
> +}
>
> const char *
> get_insn_template (int code, rtx insn)
> @@ -2210,6 +2309,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
> break;
>
> case NOTE_INSN_SWITCH_TEXT_SECTIONS:
> + maybe_output_next_view (seen);
> +
> in_cold_section_p = !in_cold_section_p;
>
> if (dwarf2out_do_frame ())
> @@ -2350,6 +2451,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
> break;
>
> case NOTE_INSN_BLOCK_END:
> + maybe_output_next_view (seen);
> +
> if (debug_info_level == DINFO_LEVEL_NORMAL
> || debug_info_level == DINFO_LEVEL_VERBOSE
> || write_symbols == DWARF2_DEBUG
> @@ -2407,7 +2510,35 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
> case NOTE_INSN_VAR_LOCATION:
> case NOTE_INSN_CALL_ARG_LOCATION:
> if (!DECL_IGNORED_P (current_function_decl))
> - debug_hooks->var_location (insn);
> + {
> + debug_hooks->var_location (insn);
> + set_next_view_needed (seen);
> + }
> + 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))
> + {
> + output_source_line:
> + (*debug_hooks->source_line) (last_linenum, last_columnnum,
> + last_filename, last_discriminator,
> + true);
> + clear_next_view_needed (seen);
> + }
> + break;
> +
> + case NOTE_INSN_INLINE_ENTRY:
> + gcc_checking_assert (cfun->debug_nonbind_markers);
> + if (!DECL_IGNORED_P (current_function_decl))
> + {
> + if (!notice_source_line (insn, NULL))
> + break;
> + (*debug_hooks->inline_entry) (LOCATION_BLOCK
> + (NOTE_MARKER_LOCATION (insn)));
> + goto output_source_line;
> + }
> break;
>
> default:
> @@ -2497,7 +2628,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_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;
> @@ -2595,19 +2734,28 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>
> switch_to_section (current_function_section ());
>
> + if (debug_variable_location_views
> + && !DECL_IGNORED_P (current_function_decl))
> + debug_hooks->var_location (insn);
> +
> break;
> }
> /* 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);
> (*debug_hooks->source_line) (last_linenum, last_columnnum,
> last_filename, last_discriminator,
> is_stmt);
> + clear_next_view_needed (seen);
> }
> + else
> + maybe_output_next_view (seen);
> +
> + gcc_checking_assert (!DEBUG_INSN_P (insn));
>
> if (GET_CODE (body) == PARALLEL
> && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
> @@ -3074,7 +3222,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
> /* Let the debug info back-end know about this call. We do this only
> after the instruction has been emitted because labels that may be
> created to reference the call instruction must appear after it. */
> - if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl))
> + if ((debug_variable_location_views || call_insn != NULL)
> + && !DECL_IGNORED_P (current_function_decl))
> debug_hooks->var_location (insn);
>
> current_output_insn = debug_insn = 0;
> @@ -3093,7 +3242,26 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
> const char *filename;
> int linenum, columnnum;
>
> - if (override_filename)
> + if (NOTE_MARKER_P (insn))
> + {
> + expanded_location xloc
> + = expand_location (NOTE_MARKER_LOCATION (insn));
> + if (xloc.line == 0)
> + {
> + gcc_checking_assert ((UNKNOWN_LOCATION
> + == LOCATION_LOCUS (NOTE_MARKER_LOCATION
> + (insn)))
> + || (BUILTINS_LOCATION
> + == LOCATION_LOCUS (NOTE_MARKER_LOCATION
> + (insn))));
> + return false;
> + }
> + filename = xloc.file;
> + linenum = xloc.line;
> + columnnum = xloc.column;
> + force_source_line = true;
> + }
> + else if (override_filename)
> {
> filename = override_filename;
> linenum = override_linenum;
> @@ -3126,7 +3294,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
> last_linenum = linenum;
> last_columnnum = columnnum;
> last_discriminator = discriminator;
> - *is_stmt = true;
> + if (is_stmt)
> + *is_stmt = true;
> high_block_linenum = MAX (last_linenum, high_block_linenum);
> high_function_linenum = MAX (last_linenum, high_function_linenum);
> return true;
> @@ -3138,7 +3307,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
> output the line table entry with is_stmt false so the
> debugger does not treat this as a breakpoint location. */
> last_discriminator = discriminator;
> - *is_stmt = false;
> + if (is_stmt)
> + *is_stmt = false;
> return true;
> }
>
> @@ -4491,9 +4661,15 @@ rest_of_handle_final (void)
> {
> const char *fnname = get_fnname_from_decl (current_function_decl);
>
> + /* Turn debug markers into notes. */
> + if (!flag_var_tracking && MAY_HAVE_DEBUG_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);
> + rtx_insn *first = get_insns ();
> + int seen = 0;
> + final_start_function_1 (&first, asm_out_file, &seen, optimize);
> + final_1 (first, asm_out_file, seen, optimize);
> if (flag_ipa_ra
> && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
> collect_fn_hard_reg_usage ();
> @@ -4678,6 +4854,8 @@ 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_INLINE_ENTRY
> && 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 20c287b..8de335e 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -1951,10 +1951,11 @@ instantiate_virtual_regs (void)
> Fortunately, they shouldn't contain virtual registers either. */
> if (GET_CODE (PATTERN (insn)) == USE
> || GET_CODE (PATTERN (insn)) == CLOBBER
> - || GET_CODE (PATTERN (insn)) == ASM_INPUT)
> + || GET_CODE (PATTERN (insn)) == ASM_INPUT
> + || MARKER_DEBUG_INSN_P (insn))
> continue;
> - else if (DEBUG_INSN_P (insn))
> - instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
> + else if (BIND_DEBUG_INSN_P (insn))
> + instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
> else
> instantiate_virtual_regs_in_insn (insn);
>
> @@ -4940,6 +4941,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
> if (!profile_flag && !flag_instrument_function_entry_exit)
> DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
> }
> +
> + /* Don't enable begin stmt markers if var-tracking at assignments is
> + disabled. The markers make little sense without the variable
> + binding annotations among them. */
> + cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
> + && debug_nonbind_markers_p && MAY_HAVE_DEBUG_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 0f34bcd..2c2e622 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 3b74cc5..f0d96f9 100644
> --- a/gcc/gimple-iterator.c
> +++ b/gcc/gimple-iterator.c
> @@ -573,6 +573,8 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
>
> if (remove_permanently)
> {
> + if (gimple_debug_nonbind_marker_p (stmt))
> + cfun->debug_marker_count--;
> require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
> gimple_remove_stmt_histograms (cfun, stmt);
> }
> @@ -744,9 +746,13 @@ gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi,
> if (gsi_end_p (*gsi))
> return true;
>
> - /* Make sure we insert after any leading labels. */
> + /* Make sure we insert after any leading labels. We have to
> + skip debug stmts before or among them, though. We didn't
> + have to skip debug stmts after the last label, but it
> + shouldn't hurt if we do. */
> tmp = gsi_stmt (*gsi);
> - while (gimple_code (tmp) == GIMPLE_LABEL)
> + while (gimple_code (tmp) == GIMPLE_LABEL
> + || is_gimple_debug (tmp))
> {
> gsi_next (gsi);
> if (gsi_end_p (*gsi))
> @@ -776,7 +782,21 @@ gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi,
> return true;
>
> tmp = gsi_stmt (*gsi);
> - if (!stmt_ends_bb_p (tmp))
> + if (is_gimple_debug (tmp))
> + {
> + gimple_stmt_iterator si = *gsi;
> + gsi_prev_nondebug (&si);
> + if (!gsi_end_p (si))
> + tmp = gsi_stmt (si);
> + /* If we don't have a BB-ending nondebug stmt, we want to
> + insert after the trailing debug stmts. Otherwise, we may
> + insert before the BB-ending nondebug stmt, or split the
> + edge. */
> + if (!stmt_ends_bb_p (tmp))
> + return true;
> + *gsi = si;
> + }
> + else if (!stmt_ends_bb_p (tmp))
> return true;
>
> switch (gimple_code (tmp))
> diff --git a/gcc/gimple-iterator.h b/gcc/gimple-iterator.h
> index 70f18be..167edc1 100644
> --- a/gcc/gimple-iterator.h
> +++ b/gcc/gimple-iterator.h
> @@ -212,29 +212,28 @@ gsi_stmt (gimple_stmt_iterator i)
> return i.ptr;
> }
>
> -/* Return a new iterator pointing to the first non-debug statement
> - in basic block BB. */
> -
> -static inline gimple_stmt_iterator
> -gsi_start_bb_nondebug (basic_block bb)
> -{
> - gimple_stmt_iterator gsi = gsi_start_bb (bb);
> - while (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
> - gsi_next (&gsi);
> -
> - return gsi;
> -}
> -
> -/* Return a block statement iterator that points to the first non-label
> - statement in block BB. */
> +/* Return a block statement iterator that points to the first
> + non-label statement in block BB. Skip debug stmts only if they
> + precede labels. */
>
> static inline gimple_stmt_iterator
> gsi_after_labels (basic_block bb)
> {
> gimple_stmt_iterator gsi = gsi_start_bb (bb);
>
> - while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
> - gsi_next (&gsi);
> + for (gimple_stmt_iterator gskip = gsi;
> + !gsi_end_p (gskip); )
> + {
> + if (is_gimple_debug (gsi_stmt (gskip)))
> + gsi_next (&gskip);
> + else if (gimple_code (gsi_stmt (gskip)) == GIMPLE_LABEL)
> + {
> + gsi_next (&gskip);
> + gsi = gskip;
> + }
> + else
> + break;
> + }
>
> return gsi;
> }
> @@ -264,6 +263,19 @@ gsi_prev_nondebug (gimple_stmt_iterator *i)
> }
>
> /* Return a new iterator pointing to the first non-debug statement in
> + SEQ. */
> +
> +static inline gimple_stmt_iterator
> +gsi_start_nondebug (gimple_seq seq)
> +{
> + gimple_stmt_iterator gsi = gsi_start (seq);
> + if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
> + gsi_next_nondebug (&gsi);
> +
> + return gsi;
> +}
> +
> +/* Return a new iterator pointing to the first non-debug statement in
> basic block BB. */
>
> static inline gimple_stmt_iterator
> diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
> index 4ea6c35..d74a33f6b 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_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,17 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
> }
> break;
>
> + case GIMPLE_DEBUG:
> + gcc_checking_assert (cfun->debug_nonbind_markers);
> + /* 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_STMTS)
> + gsi_remove (gsi, true);
> + else
> + gsi_next (gsi);
> + return;
> +
> case GIMPLE_NOP:
> case GIMPLE_ASM:
> case GIMPLE_ASSIGN:
> @@ -503,6 +525,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
> @@ -645,7 +671,7 @@ gimple_stmt_may_fallthru (gimple *stmt)
> bool
> gimple_seq_may_fallthru (gimple_seq seq)
> {
> - return gimple_stmt_may_fallthru (gimple_seq_last_stmt (seq));
> + return gimple_stmt_may_fallthru (gimple_seq_last_nondebug_stmt (seq));
> }
>
>
> diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
> index ed8e51c..7c9c754 100644
> --- a/gcc/gimple-pretty-print.c
> +++ b/gcc/gimple-pretty-print.c
> @@ -1370,6 +1370,26 @@ 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;
> +
> + case GIMPLE_DEBUG_INLINE_ENTRY:
> + if (flags & TDF_RAW)
> + dump_gimple_fmt (buffer, spc, flags, "%G INLINE_ENTRY %T", gs,
> + gimple_block (gs)
> + ? block_ultimate_origin (gimple_block (gs))
> + : NULL_TREE);
> + else
> + dump_gimple_fmt (buffer, spc, flags, "# DEBUG INLINE_ENTRY %T",
> + gimple_block (gs)
> + ? block_ultimate_origin (gimple_block (gs))
> + : NULL_TREE);
> + break;
> +
> default:
> gcc_unreachable ();
> }
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index c4e6f81..71ff292 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -836,6 +836,48 @@ 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 new GIMPLE_DEBUG_INLINE_ENTRY statement in BLOCK at
> + LOCATION. The BLOCK links to the inlined function. */
> +
> +gdebug *
> +gimple_build_debug_inline_entry (tree block, location_t location
> + MEM_STAT_DECL)
> +{
> + gdebug *p
> + = as_a <gdebug *> (
> + gimple_build_with_ops_stat (GIMPLE_DEBUG,
> + (unsigned)GIMPLE_DEBUG_INLINE_ENTRY, 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 +1916,9 @@ gimple_copy (gimple *stmt)
> gimple_set_modified (copy, true);
> }
>
> + if (gimple_debug_begin_stmt_p (stmt))
> + cfun->debug_marker_count++;
> +
> return copy;
> }
>
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 6213c49..909807f 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -198,13 +198,13 @@ enum gf_mask {
> GF_PREDICT_TAKEN = 1 << 15
> };
>
> -/* Currently, there are only two types of gimple debug stmt. Others are
> - envisioned, for example, to enable the generation of is_stmt notes
> - in line number information, to mark sequence points, etc. This
> - subcode is to be used to tell them apart. */
> +/* This subcode tells apart different kinds of stmts that are not used
> + for codegen, but rather to retain debug information. */
> enum gimple_debug_subcode {
> GIMPLE_DEBUG_BIND = 0,
> - GIMPLE_DEBUG_SOURCE_BIND = 1
> + GIMPLE_DEBUG_SOURCE_BIND = 1,
> + GIMPLE_DEBUG_BEGIN_STMT = 2,
> + GIMPLE_DEBUG_INLINE_ENTRY = 3
> };
>
> /* Masks for selecting a pass local flag (PLF) to work on. These
> @@ -1455,6 +1455,8 @@ 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);
> +gdebug *gimple_build_debug_inline_entry (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);
> @@ -4583,6 +4585,22 @@ is_gimple_debug (const gimple *gs)
> return gimple_code (gs) == GIMPLE_DEBUG;
> }
>
> +
> +/* Return the last nondebug statement in GIMPLE sequence S. */
> +
> +static inline gimple *
> +gimple_seq_last_nondebug_stmt (gimple_seq s)
> +{
> + gimple_seq_node n;
> + for (n = gimple_seq_last (s);
> + n && is_gimple_debug (n);
> + n = n->prev)
> + if (n->prev == s)
> + return NULL;
> + return n;
> +}
> +
> +
> /* Return true if S is a GIMPLE_DEBUG BIND statement. */
>
> static inline bool
> @@ -4739,6 +4757,40 @@ gimple_debug_source_bind_set_value (gimple *dbg, tree value)
> gimple_set_op (dbg, 1, value);
> }
>
> +/* Return true if S is a GIMPLE_DEBUG BEGIN_STMT statement. */
> +
> +static inline bool
> +gimple_debug_begin_stmt_p (const gimple *s)
> +{
> + if (is_gimple_debug (s))
> + return s->subcode == GIMPLE_DEBUG_BEGIN_STMT;
> +
> + return false;
> +}
> +
> +/* Return true if S is a GIMPLE_DEBUG INLINE_ENTRY statement. */
> +
> +static inline bool
> +gimple_debug_inline_entry_p (const gimple *s)
> +{
> + if (is_gimple_debug (s))
> + return s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
> +
> + return false;
> +}
> +
> +/* Return true if S is a GIMPLE_DEBUG non-binding marker statement. */
> +
> +static inline bool
> +gimple_debug_nonbind_marker_p (const gimple *s)
> +{
> + if (is_gimple_debug (s))
> + return s->subcode == GIMPLE_DEBUG_BEGIN_STMT
> + || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
> +
> + return false;
> +}
> +
> /* Return the line number for EXPR, or return -1 if we have no line
> number information for it. */
> static inline int
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 86623e0..9acb4c2 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
> +expr_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 expr_location (tsi_stmt (i), or_else);
> +}
> +
> +/* Return TRUE iff EXPR (maybe recursively) has a location; see
> + expr_location for the potential recursion. */
> +
> +static inline bool
> +expr_has_location (tree expr)
> +{
> + return expr_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))
> {
> @@ -1855,7 +1904,7 @@ case_label_p (const vec<tree> *cases, tree label)
> return false;
> }
>
> -/* Find the last statement in a scope STMT. */
> +/* Find the last nondebug statement in a scope STMT. */
>
> static gimple *
> last_stmt_in_scope (gimple *stmt)
> @@ -1868,27 +1917,30 @@ last_stmt_in_scope (gimple *stmt)
> case GIMPLE_BIND:
> {
> gbind *bind = as_a <gbind *> (stmt);
> - stmt = gimple_seq_last_stmt (gimple_bind_body (bind));
> + stmt = gimple_seq_last_nondebug_stmt (gimple_bind_body (bind));
> return last_stmt_in_scope (stmt);
> }
>
> case GIMPLE_TRY:
> {
> gtry *try_stmt = as_a <gtry *> (stmt);
> - stmt = gimple_seq_last_stmt (gimple_try_eval (try_stmt));
> + stmt = gimple_seq_last_nondebug_stmt (gimple_try_eval (try_stmt));
> gimple *last_eval = last_stmt_in_scope (stmt);
> if (gimple_stmt_may_fallthru (last_eval)
> && (last_eval == NULL
> || !gimple_call_internal_p (last_eval, IFN_FALLTHROUGH))
> && gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
> {
> - stmt = gimple_seq_last_stmt (gimple_try_cleanup (try_stmt));
> + stmt = gimple_seq_last_nondebug_stmt (gimple_try_cleanup (try_stmt));
> return last_stmt_in_scope (stmt);
> }
> else
> return last_eval;
> }
>
> + case GIMPLE_DEBUG:
> + gcc_unreachable ();
> +
> default:
> return stmt;
> }
> @@ -1992,7 +2044,7 @@ collect_fallthrough_labels (gimple_stmt_iterator *gsi_p,
> }
> else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK))
> ;
> - else
> + else if (!is_gimple_debug (gsi_stmt (*gsi_p)))
> prev = gsi_stmt (*gsi_p);
> gsi_next (gsi_p);
> }
> @@ -2029,7 +2081,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
> && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
> && (l = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi))))
> && !case_label_p (&gimplify_ctxp->case_labels, l))
> - gsi_next (&gsi);
> + gsi_next_nondebug (&gsi);
> if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
> return false;
> }
> @@ -2042,7 +2094,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
> while (!gsi_end_p (gsi)
> && (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
> || gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT))
> - gsi_next (&gsi);
> + gsi_next_nondebug (&gsi);
>
> /* { ... something; default:; } */
> if (gsi_end_p (gsi)
> @@ -2089,7 +2141,7 @@ warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
> /* Found a label. Skip all immediately following labels. */
> while (!gsi_end_p (*gsi_p)
> && gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL)
> - gsi_next (gsi_p);
> + gsi_next_nondebug (gsi_p);
>
> /* There might be no more statements. */
> if (gsi_end_p (*gsi_p))
> @@ -2230,7 +2282,7 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
> break;
> }
> }
> - else
> + else if (!is_gimple_debug (stmt))
> /* Something other than a label. That's not expected. */
> break;
> gsi_next (&gsi2);
> @@ -3437,7 +3489,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
> append_to_statement_list (t, &expr);
>
> /* Set the source location of the && on the second 'if'. */
> - new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
> + new_locus = expr_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);
> @@ -3460,7 +3512,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
> append_to_statement_list (t, &expr);
>
> /* Set the source location of the || on the second 'if'. */
> - new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
> + new_locus = expr_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);
> @@ -3482,7 +3534,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
>
> /* Keep the original source location on the first 'if'. Set the source
> location of the ? on the second 'if'. */
> - new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
> + new_locus = expr_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),
> @@ -3506,6 +3558,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
> return expr;
> }
>
> +/* If EXPR is a GOTO_EXPR, return it. If it is a STATEMENT_LIST, skip
> + any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent
> + statement, if it is the last one. Otherwise, return NULL. */
> +
> +static tree
> +find_goto (tree expr)
> +{
> + if (!expr)
> + return NULL_TREE;
> +
> + if (TREE_CODE (expr) == GOTO_EXPR)
> + return expr;
> +
> + if (TREE_CODE (expr) != STATEMENT_LIST)
> + return NULL_TREE;
> +
> + tree_stmt_iterator i = tsi_start (expr);
> +
> + while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> + tsi_next (&i);
> +
> + if (!tsi_one_before_end_p (i))
> + return NULL_TREE;
> +
> + return find_goto (tsi_stmt (i));
> +}
> +
> +/* Same as find_goto, except that it returns NULL if the destination
> + is not a LABEL_DECL. */
> +
> +static inline tree
> +find_goto_label (tree expr)
> +{
> + tree dest = find_goto (expr);
> + if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)
> + return dest;
> + return NULL_TREE;
> +}
> +
> /* Given a conditional expression EXPR with short-circuit boolean
> predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the
> predicate apart into the equivalent sequence of conditionals. */
> @@ -3536,8 +3627,8 @@ shortcut_cond_expr (tree expr)
> location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
> TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
> /* Set the source location of the && on the second 'if'. */
> - if (EXPR_HAS_LOCATION (pred))
> - SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
> + if (expr_has_location (pred))
> + SET_EXPR_LOCATION (expr, expr_location (pred));
> then_ = shortcut_cond_expr (expr);
> then_se = then_ && TREE_SIDE_EFFECTS (then_);
> pred = TREE_OPERAND (pred, 0);
> @@ -3558,8 +3649,8 @@ shortcut_cond_expr (tree expr)
> location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
> TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
> /* Set the source location of the || on the second 'if'. */
> - if (EXPR_HAS_LOCATION (pred))
> - SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
> + if (expr_has_location (pred))
> + SET_EXPR_LOCATION (expr, expr_location (pred));
> else_ = shortcut_cond_expr (expr);
> else_se = else_ && TREE_SIDE_EFFECTS (else_);
> pred = TREE_OPERAND (pred, 0);
> @@ -3586,20 +3677,16 @@ shortcut_cond_expr (tree expr)
> /* If our arms just jump somewhere, hijack those labels so we don't
> generate jumps to jumps. */
>
> - if (then_
> - && TREE_CODE (then_) == GOTO_EXPR
> - && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
> + if (tree then_goto = find_goto_label (then_))
> {
> - true_label = GOTO_DESTINATION (then_);
> + true_label = GOTO_DESTINATION (then_goto);
> then_ = NULL;
> then_se = false;
> }
>
> - if (else_
> - && TREE_CODE (else_) == GOTO_EXPR
> - && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
> + if (tree else_goto = find_goto_label (else_))
> {
> - false_label = GOTO_DESTINATION (else_);
> + false_label = GOTO_DESTINATION (else_goto);
> else_ = NULL;
> else_se = false;
> }
> @@ -3663,8 +3750,8 @@ shortcut_cond_expr (tree expr)
> {
> tree last = expr_last (expr);
> t = build_and_jump (&end_label);
> - if (EXPR_HAS_LOCATION (last))
> - SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
> + if (expr_has_location (last))
> + SET_EXPR_LOCATION (t, expr_location (last));
> append_to_statement_list (t, &expr);
> }
> if (emit_false)
> @@ -3957,39 +4044,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
> gimple_push_condition ();
>
> have_then_clause_p = have_else_clause_p = false;
> - if (TREE_OPERAND (expr, 1) != NULL
> - && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
> - && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
> - && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
> - == current_function_decl)
> + label_true = find_goto_label (TREE_OPERAND (expr, 1));
> + if (label_true
> + && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
> /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
> have different locations, otherwise we end up with incorrect
> location information on the branches. */
> && (optimize
> || !EXPR_HAS_LOCATION (expr)
> - || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
> - || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
> + || !expr_has_location (label_true)
> + || EXPR_LOCATION (expr) == expr_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))))
> + || !expr_has_location (label_false)
> + || EXPR_LOCATION (expr) == expr_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);
> @@ -11779,6 +11862,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
> ret = GS_ALL_DONE;
> break;
>
> + case DEBUG_EXPR_DECL:
> + gcc_unreachable ();
> +
> + case DEBUG_BEGIN_STMT:
> + gimplify_seq_add_stmt (pre_p,
> + gimple_build_debug_begin_stmt
> + (TREE_BLOCK (*expr_p),
> + EXPR_LOCATION (*expr_p)));
> + ret = GS_ALL_DONE;
> + *expr_p = NULL;
> + break;
> +
> case SSA_NAME:
> /* Allow callbacks into the gimplifier during optimization. */
> ret = GS_ALL_DONE;
> diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
> index 5b2bc1c..d7e8861 100644
> --- a/gcc/graphite-isl-ast-to-gimple.c
> +++ b/gcc/graphite-isl-ast-to-gimple.c
> @@ -1331,7 +1331,7 @@ gsi_insert_earliest (gimple_seq seq)
> FOR_EACH_VEC_ELT (stmts, i, use_stmt)
> {
> gcc_assert (gimple_code (use_stmt) != GIMPLE_PHI);
> - gimple_stmt_iterator gsi_def_stmt = gsi_start_bb_nondebug (begin_bb);
> + gimple_stmt_iterator gsi_def_stmt = gsi_start_nondebug_bb (begin_bb);
>
> use_operand_p use_p;
> ssa_op_iter op_iter;
> @@ -1363,7 +1363,7 @@ gsi_insert_earliest (gimple_seq seq)
> else if (gimple_code (gsi_stmt (gsi_def_stmt)) == GIMPLE_PHI)
> {
> gimple_stmt_iterator bsi
> - = gsi_start_bb_nondebug (gsi_bb (gsi_def_stmt));
> + = gsi_start_nondebug_bb (gsi_bb (gsi_def_stmt));
> /* Insert right after the PHI statements. */
> gsi_insert_before (&bsi, use_stmt, GSI_NEW_STMT);
> }
> @@ -1646,7 +1646,8 @@ rename_uses (gimple *copy, gimple_stmt_iterator *gsi_tgt, basic_block old_bb,
> {
> if (gimple_debug_bind_p (copy))
> gimple_debug_bind_reset_value (copy);
> - else if (gimple_debug_source_bind_p (copy))
> + else if (gimple_debug_source_bind_p (copy)
> + || gimple_debug_nonbind_marker_p (copy))
> return false;
> else
> gcc_unreachable ();
> diff --git a/gcc/graphite-scop-detection.c b/gcc/graphite-scop-detection.c
> index e17d58a..15b15f7 100644
> --- a/gcc/graphite-scop-detection.c
> +++ b/gcc/graphite-scop-detection.c
> @@ -261,7 +261,7 @@ trivially_empty_bb_p (basic_block bb)
> gimple_stmt_iterator gsi;
>
> for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> - if (gimple_code (gsi_stmt (gsi)) != GIMPLE_DEBUG)
> + if (!is_gimple_debug (gsi_stmt (gsi)))
> return false;
>
> return true;
> diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
> index af0ed27..f9dc774 100644
> --- a/gcc/haifa-sched.c
> +++ b/gcc/haifa-sched.c
> @@ -8160,7 +8160,7 @@ sched_extend_bb (void)
> || (!NOTE_P (insn)
> && !LABEL_P (insn)
> /* Don't emit a NOTE if it would end up before a BARRIER. */
> - && !BARRIER_P (NEXT_INSN (end))))
> + && !BARRIER_P (next_nondebug_insn (end))))
> {
> rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end);
> /* Make note appear outside BB. */
> diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
> index f96ce18..252e957 100644
> --- a/gcc/insn-notes.def
> +++ b/gcc/insn-notes.def
> @@ -68,6 +68,13 @@ INSN_NOTE (VAR_LOCATION)
> /* The values passed to callee. */
> INSN_NOTE (CALL_ARG_LOCATION)
>
> +/* The beginning of a statement. */
> +INSN_NOTE (BEGIN_STMT)
> +
> +/* The entry point for an inlined function. Its NOTE_BLOCK references
> + the lexical block whose abstract origin is the inlined function. */
> +INSN_NOTE (INLINE_ENTRY)
> +
> /* Record the struct for the following basic block. Uses
> NOTE_BASIC_BLOCK. FIXME: Redundant with the basic block pointer
> now included in every insn. NOTE: If there's no CFG anymore, in other words,
> diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
> index f44a995..d0c9d78 100644
> --- a/gcc/ipa-icf-gimple.c
> +++ b/gcc/ipa-icf-gimple.c
> @@ -633,8 +633,8 @@ func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
> gimple_stmt_iterator gsi1, gsi2;
> gimple *s1, *s2;
>
> - gsi1 = gsi_start_bb_nondebug (bb1->bb);
> - gsi2 = gsi_start_bb_nondebug (bb2->bb);
> + gsi1 = gsi_start_nondebug_bb (bb1->bb);
> + gsi2 = gsi_start_nondebug_bb (bb2->bb);
>
> while (!gsi_end_p (gsi1))
> {
> diff --git a/gcc/ira.c b/gcc/ira.c
> index 08a1cc5..0a6d73a 100644
> --- a/gcc/ira.c
> +++ b/gcc/ira.c
> @@ -3844,7 +3844,7 @@ combine_and_move_insns (void)
> /* Last pass - adjust debug insns referencing cleared regs. */
> if (MAY_HAVE_DEBUG_INSNS)
> for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> {
> rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
> INSN_VAR_LOCATION_LOC (insn)
> diff --git a/gcc/jump.c b/gcc/jump.c
> index fc4b434..e60a6c6 100644
> --- a/gcc/jump.c
> +++ b/gcc/jump.c
> @@ -123,7 +123,7 @@ cleanup_barriers (void)
> {
> if (BARRIER_P (insn))
> {
> - rtx_insn *prev = prev_nonnote_insn (insn);
> + rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
> if (!prev)
> continue;
>
> diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
> index ea2006c..fa6f247 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
>
> @@ -341,6 +342,7 @@ extern void lhd_end_section (void);
> LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
> LANG_HOOKS_DEEP_UNSHARING, \
> LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \
> + LANG_HOOKS_EMITS_BEGIN_STMT, \
> LANG_HOOKS_RUN_LANG_SELFTESTS, \
> LANG_HOOKS_GET_SUBSTRING_LOCATION \
> }
> diff --git a/gcc/langhooks.h b/gcc/langhooks.h
> index 88f6f71..8d91cfc 100644
> --- a/gcc/langhooks.h
> +++ b/gcc/langhooks.h
> @@ -524,6 +524,9 @@ struct lang_hooks
> instead of trampolines. */
> bool custom_function_descriptors;
>
> + /* True if this language emits begin stmt notes. */
> + bool emits_begin_stmt;
> +
> /* Run all lang-specific selftests. */
> void (*run_lang_selftests) (void);
>
> diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
> index 84145bb..01db753 100644
> --- a/gcc/loop-unroll.c
> +++ b/gcc/loop-unroll.c
> @@ -2024,12 +2024,14 @@ apply_opt_in_copies (struct opt_info *opt_info,
> FOR_BB_INSNS_SAFE (bb, insn, next)
> {
> if (!INSN_P (insn)
> - || (DEBUG_INSN_P (insn)
> + || (BIND_DEBUG_INSN_P (insn)
> + && INSN_VAR_LOCATION_DECL (insn)
> && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL))
> continue;
>
> while (!INSN_P (orig_insn)
> - || (DEBUG_INSN_P (orig_insn)
> + || (BIND_DEBUG_INSN_P (orig_insn)
> + && INSN_VAR_LOCATION_DECL (orig_insn)
> && (TREE_CODE (INSN_VAR_LOCATION_DECL (orig_insn))
> == LABEL_DECL)))
> orig_insn = NEXT_INSN (orig_insn);
> diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
> index b1d864f..e70537d 100644
> --- a/gcc/lra-constraints.c
> +++ b/gcc/lra-constraints.c
> @@ -5269,10 +5269,11 @@ inherit_reload_reg (bool def_p, int original_regno,
> lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
> if (lra_dump_file != NULL)
> {
> + basic_block bb = BLOCK_FOR_INSN (usage_insn);
> fprintf (lra_dump_file,
> " Inheritance reuse change %d->%d (bb%d):\n",
> original_regno, REGNO (new_reg),
> - BLOCK_FOR_INSN (usage_insn)->index);
> + bb ? bb->index : -1);
> dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
> }
> }
> @@ -5816,6 +5817,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
> if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
> continue;
> curr_bb = BLOCK_FOR_INSN (curr_insn);
> + if (!curr_bb)
> + {
> + gcc_assert (DEBUG_INSN_P (curr_insn));
> + if (MARKER_DEBUG_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 1230b25..64abe54 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
> @@ -951,12 +967,20 @@ lra_set_insn_recog_data (rtx_insn *insn)
> data->regs = NULL;
> if (DEBUG_INSN_P (insn))
> {
> - data->insn_static_data = &debug_insn_static_data;
> data->dup_loc = NULL;
> data->arg_hard_regs = NULL;
> data->preferred_alternatives = ALL_ALTERNATIVES;
> - data->operand_loc = XNEWVEC (rtx *, 1);
> - data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
> + if (BIND_DEBUG_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 (MARKER_DEBUG_INSN_P (insn))
> + {
> + data->insn_static_data = &debug_marker_static_data;
> + data->operand_loc = NULL;
> + }
> return data;
> }
> if (icode < 0)
> @@ -1602,7 +1626,7 @@ lra_update_insn_regno_info (rtx_insn *insn)
> return;
> data = lra_get_insn_recog_data (insn);
> static_data = data->insn_static_data;
> - freq = get_insn_freq (insn);
> + freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
> invalidate_insn_data_regno_info (data, insn, freq);
> uid = INSN_UID (insn);
> for (i = static_data->n_operands - 1; i >= 0; i--)
> @@ -1812,7 +1836,7 @@ push_insns (rtx_insn *from, rtx_insn *to)
> static void
> setup_sp_offset (rtx_insn *from, rtx_insn *last)
> {
> - rtx_insn *before = next_nonnote_insn_bb (last);
> + rtx_insn *before = next_nonnote_nondebug_insn_bb (last);
> HOST_WIDE_INT offset = (before == NULL_RTX || ! INSN_P (before)
> ? 0 : lra_get_insn_recog_data (before)->sp_offset);
>
> diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
> index 5710e8f..1834df0 100644
> --- a/gcc/lto-streamer-in.c
> +++ b/gcc/lto-streamer-in.c
> @@ -1173,6 +1173,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/omp-expand.c b/gcc/omp-expand.c
> index ac83ba1..cd6b765 100644
> --- a/gcc/omp-expand.c
> +++ b/gcc/omp-expand.c
> @@ -659,7 +659,7 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
> false, GSI_CONTINUE_LINKING);
> }
>
> - gsi = gsi_last_bb (bb);
> + gsi = gsi_last_nondebug_bb (bb);
> t = gimple_omp_parallel_data_arg (entry_stmt);
> if (t == NULL)
> t1 = null_pointer_node;
> @@ -710,7 +710,7 @@ expand_cilk_for_call (basic_block bb, gomp_parallel *entry_stmt,
> gcc_assert (count != NULL_TREE);
> count = OMP_CLAUSE_OPERAND (count, 0);
>
> - gsi = gsi_last_bb (bb);
> + gsi = gsi_last_nondebug_bb (bb);
> t = gimple_omp_parallel_data_arg (entry_stmt);
> if (t == NULL)
> t1 = null_pointer_node;
> @@ -836,7 +836,7 @@ expand_task_call (struct omp_region *region, basic_block bb,
> else
> priority = integer_zero_node;
>
> - gsi = gsi_last_bb (bb);
> + gsi = gsi_last_nondebug_bb (bb);
> tree t = gimple_omp_task_data_arg (entry_stmt);
> if (t == NULL)
> t2 = null_pointer_node;
> @@ -913,15 +913,15 @@ remove_exit_barrier (struct omp_region *region)
> statements that can appear in between are extremely limited -- no
> memory operations at all. Here, we allow nothing at all, so the
> only thing we allow to precede this GIMPLE_OMP_RETURN is a label. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> - gsi_prev (&gsi);
> + gsi_prev_nondebug (&gsi);
> if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
> return;
>
> FOR_EACH_EDGE (e, ei, exit_bb->preds)
> {
> - gsi = gsi_last_bb (e->src);
> + gsi = gsi_last_nondebug_bb (e->src);
> if (gsi_end_p (gsi))
> continue;
> stmt = gsi_stmt (gsi);
> @@ -1148,7 +1148,7 @@ expand_omp_taskreg (struct omp_region *region)
>
> entry_succ_e = single_succ_edge (entry_bb);
>
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL
> || gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
> gsi_remove (&gsi, true);
> @@ -1261,7 +1261,7 @@ expand_omp_taskreg (struct omp_region *region)
>
> /* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK,
> so that it can be moved to the child function. */
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
> || gimple_code (stmt) == GIMPLE_OMP_TASK));
> @@ -1277,7 +1277,7 @@ expand_omp_taskreg (struct omp_region *region)
> gcc_assert (e2->dest == region->exit);
> remove_edge (BRANCH_EDGE (entry_bb));
> set_immediate_dominator (CDI_DOMINATORS, e2->dest, e->src);
> - gsi = gsi_last_bb (region->exit);
> + gsi = gsi_last_nondebug_bb (region->exit);
> gcc_assert (!gsi_end_p (gsi)
> && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> gsi_remove (&gsi, true);
> @@ -1286,7 +1286,7 @@ expand_omp_taskreg (struct omp_region *region)
> /* Convert GIMPLE_OMP_{RETURN,CONTINUE} into a RETURN_EXPR. */
> if (exit_bb)
> {
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gcc_assert (!gsi_end_p (gsi)
> && (gimple_code (gsi_stmt (gsi))
> == (e2 ? GIMPLE_OMP_CONTINUE : GIMPLE_OMP_RETURN)));
> @@ -1748,7 +1748,7 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
> if (l2_dom_bb == NULL)
> l2_dom_bb = entry_bb;
> entry_bb = e->dest;
> - *gsi = gsi_last_bb (entry_bb);
> + *gsi = gsi_last_nondebug_bb (entry_bb);
> }
>
> if (POINTER_TYPE_P (itype))
> @@ -2553,7 +2553,7 @@ expand_omp_for_generic (struct omp_region *region,
> l3_bb = BRANCH_EDGE (entry_bb)->dest;
> exit_bb = region->exit;
>
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
>
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
> if (fd->ordered
> @@ -2583,7 +2583,7 @@ expand_omp_for_generic (struct omp_region *region,
> e = split_block (entry_bb, gsi_stmt (gsi));
> entry_bb = e->dest;
> make_edge (zero_iter1_bb, entry_bb, EDGE_FALLTHRU);
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> set_immediate_dominator (CDI_DOMINATORS, entry_bb,
> get_immediate_dominator (CDI_DOMINATORS,
> zero_iter1_bb));
> @@ -2604,7 +2604,7 @@ expand_omp_for_generic (struct omp_region *region,
> e = split_block (entry_bb, gsi_stmt (gsi));
> entry_bb = e->dest;
> make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU);
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> set_immediate_dominator (CDI_DOMINATORS, entry_bb,
> get_immediate_dominator
> (CDI_DOMINATORS, zero_iter2_bb));
> @@ -3022,7 +3022,7 @@ expand_omp_for_generic (struct omp_region *region,
> {
> /* Code to control the increment and predicate for the sequential
> loop goes in the CONT_BB. */
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
> gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
> vmain = gimple_omp_continue_control_use (cont_stmt);
> @@ -3088,7 +3088,7 @@ expand_omp_for_generic (struct omp_region *region,
> }
>
> /* Add the loop cleanup function. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> if (gimple_omp_return_nowait_p (gsi_stmt (gsi)))
> t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT);
> else if (gimple_omp_return_lhs (gsi_stmt (gsi)))
> @@ -3308,7 +3308,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
> exit_bb = region->exit;
>
> /* Iteration space partitioning goes in ENTRY_BB. */
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> if (fd->collapse > 1)
> @@ -3440,7 +3440,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
> gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
>
> second_bb = split_block (entry_bb, cond_stmt)->dest;
> - gsi = gsi_last_bb (second_bb);
> + gsi = gsi_last_nondebug_bb (second_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> gsi_insert_before (&gsi, gimple_build_assign (tt, build_int_cst (itype, 0)),
> @@ -3450,7 +3450,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
> gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
>
> third_bb = split_block (second_bb, assign_stmt)->dest;
> - gsi = gsi_last_bb (third_bb);
> + gsi = gsi_last_nondebug_bb (third_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> t = build2 (MULT_EXPR, itype, q, threadid);
> @@ -3592,7 +3592,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
> {
> /* The code controlling the sequential loop replaces the
> GIMPLE_OMP_CONTINUE. */
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
> gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
> vmain = gimple_omp_continue_control_use (cont_stmt);
> @@ -3625,7 +3625,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
> }
>
> /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
> {
> t = gimple_omp_return_lhs (gsi_stmt (gsi));
> @@ -3792,7 +3792,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
> exit_bb = region->exit;
>
> /* Trip and adjustment setup goes in ENTRY_BB. */
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> if (fd->collapse > 1)
> @@ -4098,7 +4098,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
> {
> /* The code controlling the sequential loop goes in CONT_BB,
> replacing the GIMPLE_OMP_CONTINUE. */
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
> vmain = gimple_omp_continue_control_use (cont_stmt);
> vback = gimple_omp_continue_control_def (cont_stmt);
> @@ -4142,7 +4142,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
> }
>
> /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
> {
> t = gimple_omp_return_lhs (gsi_stmt (gsi));
> @@ -4353,7 +4353,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd)
> basic_block exit_bb = region->exit;
> basic_block l2_dom_bb = NULL;
>
> - gimple_stmt_iterator gsi = gsi_last_bb (entry_bb);
> + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (entry_bb);
>
> /* Below statements until the "tree high_val = ..." are pseudo statements
> used to pass information to be used by expand_omp_taskreg.
> @@ -4398,7 +4398,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd)
> if (!broken_loop)
> {
> /* Code to control the increment goes in the CONT_BB. */
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
> stmt = gimple_build_assign (ind_var, PLUS_EXPR, ind_var,
> @@ -4428,7 +4428,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd)
> gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
>
> /* Remove GIMPLE_OMP_RETURN. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gsi_remove (&gsi, true);
>
> /* Connect the new blocks. */
> @@ -4602,7 +4602,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
> exit_bb = region->exit;
> l2_dom_bb = NULL;
>
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
>
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
> /* Not needed in SSA form right now. */
> @@ -4697,7 +4697,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
> if (!broken_loop)
> {
> /* Code to control the increment goes in the CONT_BB. */
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
>
> @@ -4791,7 +4791,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
> }
>
> /* Remove GIMPLE_OMP_RETURN. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gsi_remove (&gsi, true);
>
> /* Connect the new blocks. */
> @@ -4917,7 +4917,7 @@ expand_omp_taskloop_for_outer (struct omp_region *region,
> gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
> exit_bb = region->exit;
>
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> gimple *for_stmt = gsi_stmt (gsi);
> gcc_assert (gimple_code (for_stmt) == GIMPLE_OMP_FOR);
> if (fd->collapse > 1)
> @@ -5018,10 +5018,10 @@ expand_omp_taskloop_for_outer (struct omp_region *region,
> gsi = gsi_for_stmt (for_stmt);
> gsi_remove (&gsi, true);
>
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gsi_remove (&gsi, true);
>
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gsi_remove (&gsi, true);
>
> FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always ();
> @@ -5095,7 +5095,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region,
> exit_bb = region->exit;
>
> /* Iteration space partitioning goes in ENTRY_BB. */
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
>
> if (fd->collapse > 1)
> @@ -5174,7 +5174,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region,
> {
> /* The code controlling the sequential loop replaces the
> GIMPLE_OMP_CONTINUE. */
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
> gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
> vmain = gimple_omp_continue_control_use (cont_stmt);
> @@ -5211,7 +5211,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region,
> gsi_remove (&gsi, true);
>
> /* Remove the GIMPLE_OMP_RETURN statement. */
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gsi_remove (&gsi, true);
>
> FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always ();
> @@ -5394,7 +5394,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
> entry_bb = split->src;
>
> /* Chunk setup goes at end of entry_bb, replacing the omp_for. */
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> gomp_for *for_stmt = as_a <gomp_for *> (gsi_stmt (gsi));
> loc = gimple_location (for_stmt);
>
> @@ -5521,7 +5521,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
>
> if (gimple_in_ssa_p (cfun))
> {
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
>
> offset = gimple_omp_continue_control_use (cont_stmt);
> @@ -5645,7 +5645,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
> occur, especially when noreturn routines are involved. */
> if (cont_bb)
> {
> - gsi = gsi_last_bb (cont_bb);
> + gsi = gsi_last_nondebug_bb (cont_bb);
> gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
> loc = gimple_location (cont_stmt);
>
> @@ -5734,7 +5734,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
> }
> }
>
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> loc = gimple_location (gsi_stmt (gsi));
>
> @@ -5961,7 +5961,7 @@ expand_omp_sections (struct omp_region *region)
> len = EDGE_COUNT (l0_bb->succs);
> gcc_assert (len > 0);
> e = EDGE_SUCC (l0_bb, len - 1);
> - si = gsi_last_bb (e->dest);
> + si = gsi_last_nondebug_bb (e->dest);
> l2 = NULL_TREE;
> if (gsi_end_p (si)
> || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
> @@ -5969,7 +5969,7 @@ expand_omp_sections (struct omp_region *region)
> else
> FOR_EACH_EDGE (e, ei, l0_bb->succs)
> {
> - si = gsi_last_bb (e->dest);
> + si = gsi_last_nondebug_bb (e->dest);
> if (gsi_end_p (si)
> || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
> {
> @@ -5994,7 +5994,7 @@ expand_omp_sections (struct omp_region *region)
>
> /* The call to GOMP_sections_start goes in ENTRY_BB, replacing the
> GIMPLE_OMP_SECTIONS statement. */
> - si = gsi_last_bb (entry_bb);
> + si = gsi_last_nondebug_bb (entry_bb);
> sections_stmt = as_a <gomp_sections *> (gsi_stmt (si));
> gcc_assert (gimple_code (sections_stmt) == GIMPLE_OMP_SECTIONS);
> vin = gimple_omp_sections_control (sections_stmt);
> @@ -6018,7 +6018,7 @@ expand_omp_sections (struct omp_region *region)
>
> /* The switch() statement replacing GIMPLE_OMP_SECTIONS_SWITCH goes in
> L0_BB. */
> - switch_si = gsi_last_bb (l0_bb);
> + switch_si = gsi_last_nondebug_bb (l0_bb);
> gcc_assert (gimple_code (gsi_stmt (switch_si)) == GIMPLE_OMP_SECTIONS_SWITCH);
> if (exit_reachable)
> {
> @@ -6060,7 +6060,7 @@ expand_omp_sections (struct omp_region *region)
> u = build_case_label (u, NULL, t);
> label_vec.quick_push (u);
>
> - si = gsi_last_bb (s_entry_bb);
> + si = gsi_last_nondebug_bb (s_entry_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SECTION);
> gcc_assert (i < len || gimple_omp_section_last_p (gsi_stmt (si)));
> gsi_remove (&si, true);
> @@ -6069,7 +6069,7 @@ expand_omp_sections (struct omp_region *region)
> if (s_exit_bb == NULL)
> continue;
>
> - si = gsi_last_bb (s_exit_bb);
> + si = gsi_last_nondebug_bb (s_exit_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
> gsi_remove (&si, true);
>
> @@ -6095,7 +6095,7 @@ expand_omp_sections (struct omp_region *region)
> tree bfn_decl;
>
> /* Code to get the next section goes in L1_BB. */
> - si = gsi_last_bb (l1_bb);
> + si = gsi_last_nondebug_bb (l1_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CONTINUE);
>
> bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT);
> @@ -6108,7 +6108,7 @@ expand_omp_sections (struct omp_region *region)
> }
>
> /* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */
> - si = gsi_last_bb (l2_bb);
> + si = gsi_last_nondebug_bb (l2_bb);
> if (gimple_omp_return_nowait_p (gsi_stmt (si)))
> t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
> else if (gimple_omp_return_lhs (gsi_stmt (si)))
> @@ -6136,12 +6136,12 @@ expand_omp_single (struct omp_region *region)
> entry_bb = region->entry;
> exit_bb = region->exit;
>
> - si = gsi_last_bb (entry_bb);
> + si = gsi_last_nondebug_bb (entry_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE);
> gsi_remove (&si, true);
> single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
>
> - si = gsi_last_bb (exit_bb);
> + si = gsi_last_nondebug_bb (exit_bb);
> if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
> {
> tree t = gimple_omp_return_lhs (gsi_stmt (si));
> @@ -6164,7 +6164,7 @@ expand_omp_synch (struct omp_region *region)
> entry_bb = region->entry;
> exit_bb = region->exit;
>
> - si = gsi_last_bb (entry_bb);
> + si = gsi_last_nondebug_bb (entry_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
> || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
> || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
> @@ -6176,7 +6176,7 @@ expand_omp_synch (struct omp_region *region)
>
> if (exit_bb)
> {
> - si = gsi_last_bb (exit_bb);
> + si = gsi_last_nondebug_bb (exit_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
> gsi_remove (&si, true);
> single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
> @@ -6197,7 +6197,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr,
> gimple *stmt;
> tree decl, call, type, itype;
>
> - gsi = gsi_last_bb (load_bb);
> + gsi = gsi_last_nondebug_bb (load_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
> loc = gimple_location (stmt);
> @@ -6227,7 +6227,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr,
> gsi_remove (&gsi, true);
>
> store_bb = single_succ (load_bb);
> - gsi = gsi_last_bb (store_bb);
> + gsi = gsi_last_nondebug_bb (store_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
> gsi_remove (&gsi, true);
>
> @@ -6253,14 +6253,14 @@ expand_omp_atomic_store (basic_block load_bb, tree addr,
> machine_mode imode;
> bool exchange;
>
> - gsi = gsi_last_bb (load_bb);
> + gsi = gsi_last_nondebug_bb (load_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
>
> /* If the load value is needed, then this isn't a store but an exchange. */
> exchange = gimple_omp_atomic_need_value_p (stmt);
>
> - gsi = gsi_last_bb (store_bb);
> + gsi = gsi_last_nondebug_bb (store_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_STORE);
> loc = gimple_location (stmt);
> @@ -6305,7 +6305,7 @@ expand_omp_atomic_store (basic_block load_bb, tree addr,
> gsi_remove (&gsi, true);
>
> /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */
> - gsi = gsi_last_bb (load_bb);
> + gsi = gsi_last_nondebug_bb (load_bb);
> gsi_remove (&gsi, true);
>
> if (gimple_in_ssa_p (cfun))
> @@ -6352,10 +6352,17 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
>
> gsi = gsi_after_labels (store_bb);
> stmt = gsi_stmt (gsi);
> + if (is_gimple_debug (stmt))
> + {
> + gsi_next_nondebug (&gsi);
> + if (gsi_end_p (gsi))
> + return false;
> + stmt = gsi_stmt (gsi);
> + }
> loc = gimple_location (stmt);
> if (!is_gimple_assign (stmt))
> return false;
> - gsi_next (&gsi);
> + gsi_next_nondebug (&gsi);
> if (gimple_code (gsi_stmt (gsi)) != GIMPLE_OMP_ATOMIC_STORE)
> return false;
> need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
> @@ -6419,7 +6426,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
> if (!can_compare_and_swap_p (imode, true) || !can_atomic_load_p (imode))
> return false;
>
> - gsi = gsi_last_bb (load_bb);
> + gsi = gsi_last_nondebug_bb (load_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD);
>
> /* OpenMP does not imply any barrier-like semantics on its atomic ops.
> @@ -6442,10 +6449,10 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
> force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
> gsi_remove (&gsi, true);
>
> - gsi = gsi_last_bb (store_bb);
> + gsi = gsi_last_nondebug_bb (store_bb);
> gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
> gsi_remove (&gsi, true);
> - gsi = gsi_last_bb (store_bb);
> + gsi = gsi_last_nondebug_bb (store_bb);
> stmt = gsi_stmt (gsi);
> gsi_remove (&gsi, true);
>
> @@ -6498,7 +6505,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
> return false;
>
> /* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */
> - si = gsi_last_bb (load_bb);
> + si = gsi_last_nondebug_bb (load_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
>
> /* For floating-point values, we'll need to view-convert them to integers
> @@ -6578,7 +6585,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
> }
> gsi_remove (&si, true);
>
> - si = gsi_last_bb (store_bb);
> + si = gsi_last_nondebug_bb (store_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
>
> if (iaddr == addr)
> @@ -6681,7 +6688,7 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
> gassign *stmt;
> tree t;
>
> - si = gsi_last_bb (load_bb);
> + si = gsi_last_nondebug_bb (load_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
>
> t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
> @@ -6692,7 +6699,7 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
> gsi_insert_before (&si, stmt, GSI_SAME_STMT);
> gsi_remove (&si, true);
>
> - si = gsi_last_bb (store_bb);
> + si = gsi_last_nondebug_bb (store_bb);
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
>
> stmt = gimple_build_assign (build_simple_mem_ref (unshare_expr (addr)),
> @@ -7190,7 +7197,7 @@ expand_omp_target (struct omp_region *region)
>
> /* Split ENTRY_BB at GIMPLE_*,
> so that it can be moved to the child function. */
> - gsi = gsi_last_bb (entry_bb);
> + gsi = gsi_last_nondebug_bb (entry_bb);
> stmt = gsi_stmt (gsi);
> gcc_assert (stmt
> && gimple_code (stmt) == gimple_code (entry_stmt));
> @@ -7202,7 +7209,7 @@ expand_omp_target (struct omp_region *region)
> /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */
> if (exit_bb)
> {
> - gsi = gsi_last_bb (exit_bb);
> + gsi = gsi_last_nondebug_bb (exit_bb);
> gcc_assert (!gsi_end_p (gsi)
> && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> stmt = gimple_build_return (NULL);
> @@ -7384,7 +7391,7 @@ expand_omp_target (struct omp_region *region)
> e = split_block_after_labels (new_bb);
> else
> {
> - gsi = gsi_last_bb (new_bb);
> + gsi = gsi_last_nondebug_bb (new_bb);
> gsi_prev (&gsi);
> e = split_block (new_bb, gsi_stmt (gsi));
> }
> @@ -7419,11 +7426,11 @@ expand_omp_target (struct omp_region *region)
> make_edge (else_bb, new_bb, EDGE_FALLTHRU);
>
> device = tmp_var;
> - gsi = gsi_last_bb (new_bb);
> + gsi = gsi_last_nondebug_bb (new_bb);
> }
> else
> {
> - gsi = gsi_last_bb (new_bb);
> + gsi = gsi_last_nondebug_bb (new_bb);
> device = force_gimple_operand_gsi (&gsi, device, true, NULL_TREE,
> true, GSI_SAME_STMT);
> }
> @@ -7567,7 +7574,7 @@ expand_omp_target (struct omp_region *region)
> }
> if (data_region && region->exit)
> {
> - gsi = gsi_last_bb (region->exit);
> + gsi = gsi_last_nondebug_bb (region->exit);
> g = gsi_stmt (gsi);
> gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
> gsi_remove (&gsi, true);
> @@ -7648,17 +7655,17 @@ grid_expand_omp_for_loop (struct omp_region *kfor, bool intra_group)
> gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
> }
> /* Remove the omp for statement. */
> - gsi = gsi_last_bb (kfor->entry);
> + gsi = gsi_last_nondebug_bb (kfor->entry);
> gsi_remove (&gsi, true);
>
> /* Remove the GIMPLE_OMP_CONTINUE statement. */
> - gsi = gsi_last_bb (kfor->cont);
> + gsi = gsi_last_nondebug_bb (kfor->cont);
> gcc_assert (!gsi_end_p (gsi)
> && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_CONTINUE);
> gsi_remove (&gsi, true);
>
> /* Replace the GIMPLE_OMP_RETURN with a barrier, if necessary. */
> - gsi = gsi_last_bb (kfor->exit);
> + gsi = gsi_last_nondebug_bb (kfor->exit);
> gcc_assert (!gsi_end_p (gsi)
> && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> if (intra_group)
> @@ -7802,11 +7809,11 @@ grid_expand_target_grid_body (struct omp_region *target)
> grid_expand_omp_for_loop (kfor, false);
>
> /* Remove the omp for statement. */
> - gimple_stmt_iterator gsi = gsi_last_bb (gpukernel->entry);
> + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (gpukernel->entry);
> gsi_remove (&gsi, true);
> /* Replace the GIMPLE_OMP_RETURN at the end of the kernel region with a real
> return. */
> - gsi = gsi_last_bb (gpukernel->exit);
> + gsi = gsi_last_nondebug_bb (gpukernel->exit);
> gcc_assert (!gsi_end_p (gsi)
> && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
> gimple *ret_stmt = gimple_build_return (NULL);
> @@ -7990,7 +7997,7 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
> gimple *stmt;
> basic_block son;
>
> - gsi = gsi_last_bb (bb);
> + gsi = gsi_last_nondebug_bb (bb);
> if (!gsi_end_p (gsi) && is_gimple_omp (gsi_stmt (gsi)))
> {
> struct omp_region *region;
> diff --git a/gcc/omp-low.c b/gcc/omp-low.c
> index dffdb77..83f7975 100644
> --- a/gcc/omp-low.c
> +++ b/gcc/omp-low.c
> @@ -7019,6 +7019,8 @@ check_combined_parallel (gimple_stmt_iterator *gsi_p,
> {
> WALK_SUBSTMTS;
>
> + case GIMPLE_DEBUG:
> + break;
> case GIMPLE_OMP_FOR:
> case GIMPLE_OMP_SECTIONS:
> *info = *info == 0 ? 1 : -1;
> diff --git a/gcc/opts.c b/gcc/opts.c
> index 19e8c7f..dd36835 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2329,7 +2329,7 @@ common_handle_option (struct gcc_options *opts,
>
> /* FALLTHRU */
> case OPT_gdwarf_:
> - if (value < 2 || value > 5)
> + if (value < 2 || value > 6)
> error_at (loc, "dwarf version %d is not supported", value);
> else
> opts->x_dwarf_version = value;
> diff --git a/gcc/output.h b/gcc/output.h
> index 7a93fa8..278315f 100644
> --- a/gcc/output.h
> +++ b/gcc/output.h
> @@ -59,7 +59,7 @@ const char *get_some_local_dynamic_name ();
> for the new function. The label for the function and associated
> assembler pseudo-ops have already been output in
> `assemble_start_function'. */
> -extern void final_start_function (rtx_insn *, FILE *, int);
> +extern void final_start_function (rtx_insn **, FILE *, int);
>
> /* Output assembler code for the end of a function.
> For clarity, args are same as those of `final_start_function'
> diff --git a/gcc/params.def b/gcc/params.def
> index 805302b..1d6a494 100644
> --- a/gcc/params.def
> +++ b/gcc/params.def
> @@ -960,6 +960,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
> "Max. size of loc list for which reverse ops should be added.",
> 50, 0, 0)
>
> +/* Set a threshold to discard debug markers (e.g. debug begin stmt
> + markers) when expanding a function to RTL, or inlining it into
> + another function. */
> +
> +DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
> + "max-debug-marker-count",
> + "Max. count of debug markers to expand or inline.",
> + 100000, 0, 0)
> +
> /* Set minimum insn uid for non-debug insns. */
>
> DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
> diff --git a/gcc/postreload.c b/gcc/postreload.c
> index e721f2f..7476102 100644
> --- a/gcc/postreload.c
> +++ b/gcc/postreload.c
> @@ -839,7 +839,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to)
> {
> rtx t;
>
> - if (!DEBUG_INSN_P (insn))
> + if (!BIND_DEBUG_INSN_P (insn))
> continue;
>
> t = INSN_VAR_LOCATION_LOC (insn);
> diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
> index 79ec463..d206831 100644
> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
> @@ -258,6 +258,17 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
> fputc ('\t', m_outfile);
> break;
>
> + case NOTE_INSN_BEGIN_STMT:
> + case NOTE_INSN_INLINE_ENTRY:
> +#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 +1802,24 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
>
> case DEBUG_INSN:
> {
> + if (MARKER_DEBUG_INSN_P (x))
> + {
> + switch (INSN_DEBUG_MARKER_KIND (x))
> + {
> + case NOTE_INSN_BEGIN_STMT:
> + pp_string (pp, "debug begin stmt marker");
> + break;
> +
> + case NOTE_INSN_INLINE_ENTRY:
> + pp_string (pp, "debug inline entry 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 fd4e460..08d1330 100644
> --- a/gcc/recog.c
> +++ b/gcc/recog.c
> @@ -2258,6 +2258,8 @@ extract_insn (rtx_insn *insn)
> case ADDR_VEC:
> case ADDR_DIFF_VEC:
> case VAR_LOCATION:
> + case BEGIN_STMT_MARKER:
> + case LEXICAL_BLOCK:
> return;
>
> case SET:
> diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
> index 41ae7e4..097952c 100644
> --- a/gcc/reg-stack.c
> +++ b/gcc/reg-stack.c
> @@ -3028,7 +3028,7 @@ convert_regs_1 (basic_block block)
>
> /* Don't bother processing unless there is a stack reg
> mentioned or if it's a CALL_INSN. */
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> {
> if (starting_stack_p)
> debug_insns_with_starting_stack++;
> @@ -3068,7 +3068,7 @@ convert_regs_1 (basic_block block)
> for (insn = BB_HEAD (block); debug_insns_with_starting_stack;
> insn = NEXT_INSN (insn))
> {
> - if (!DEBUG_INSN_P (insn))
> + if (!BIND_DEBUG_INSN_P (insn))
> continue;
>
> debug_insns_with_starting_stack--;
> diff --git a/gcc/regcprop.c b/gcc/regcprop.c
> index 367d85a..0bfe691 100644
> --- a/gcc/regcprop.c
> +++ b/gcc/regcprop.c
> @@ -436,6 +436,8 @@ find_oldest_value_reg (enum reg_class cl, rtx reg, struct value_data *vd)
> machine_mode mode = GET_MODE (reg);
> unsigned int i;
>
> + gcc_assert (regno < FIRST_PSEUDO_REGISTER);
> +
> /* If we are accessing REG in some mode other that what we set it in,
> make sure that the replacement is valid. In particular, consider
> (set (reg:DI r11) (...))
> @@ -763,7 +765,7 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
> next = NEXT_INSN (insn);
> if (!NONDEBUG_INSN_P (insn))
> {
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> {
> rtx loc = INSN_VAR_LOCATION_LOC (insn);
> if (!VAR_LOC_UNKNOWN_P (loc))
> diff --git a/gcc/regrename.c b/gcc/regrename.c
> index 5803664..bd73b53 100644
> --- a/gcc/regrename.c
> +++ b/gcc/regrename.c
> @@ -1876,7 +1876,7 @@ build_def_use (basic_block bb)
> if (REG_NOTE_KIND (note) == REG_CFA_RESTORE)
> scan_rtx (insn, &XEXP (note, 0), NO_REGS, mark_all_read, OP_IN);
> }
> - else if (DEBUG_INSN_P (insn)
> + else if (BIND_DEBUG_INSN_P (insn)
> && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
> {
> scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
> diff --git a/gcc/rtl.def b/gcc/rtl.def
> index 4c2607a..77047c1 100644
> --- a/gcc/rtl.def
> +++ b/gcc/rtl.def
> @@ -761,6 +761,12 @@ 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(BEGIN_STMT_MARKER, "begin_stmt_marker", "", RTX_OBJ)
> +
> +/* Used in marker DEBUG_INSNs to refer to a lexical block. */
> +DEF_RTL_EXPR(LEXICAL_BLOCK, "lexical_block", "t", RTX_OBJ)
> +
> /* All expressions from this point forward appear only in machine
> descriptions. */
> #ifdef GENERATOR_FILE
> diff --git a/gcc/rtl.h b/gcc/rtl.h
> index 8a68bb1..dd5a74f1 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -815,7 +815,8 @@ struct GTY(()) rtvec_def {
> #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
>
> /* Nonzero if DEBUG_INSN_P may possibly hold. */
> -#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
> +#define MAY_HAVE_DEBUG_INSNS \
> + (flag_var_tracking_assignments || debug_nonbind_markers_p)
>
> /* Predicate yielding nonzero iff X is a real insn. */
> #define INSN_P(X) \
> @@ -1585,6 +1586,7 @@ extern const char * const reg_note_name[];
> #define NOTE_EH_HANDLER(INSN) XCINT (INSN, 3, NOTE)
> #define NOTE_BASIC_BLOCK(INSN) XCBBDEF (INSN, 3, NOTE)
> #define NOTE_VAR_LOCATION(INSN) XCEXP (INSN, 3, NOTE)
> +#define NOTE_MARKER_LOCATION(INSN) XCUINT (INSN, 3, NOTE)
> #define NOTE_CFI(INSN) XCCFI (INSN, 3, NOTE)
> #define NOTE_LABEL_NUMBER(INSN) XCINT (INSN, 3, NOTE)
>
> @@ -1596,6 +1598,13 @@ extern const char * const reg_note_name[];
> #define NOTE_INSN_BASIC_BLOCK_P(INSN) \
> (NOTE_P (INSN) && NOTE_KIND (INSN) == NOTE_INSN_BASIC_BLOCK)
>
> +/* Nonzero if INSN is a debug nonbind marker note,
> + for which NOTE_MARKER_LOCATION can be used. */
> +#define NOTE_MARKER_P(INSN) \
> + (NOTE_P (INSN) && \
> + (NOTE_KIND (INSN) == NOTE_INSN_BEGIN_STMT \
> + || NOTE_KIND (INSN) == NOTE_INSN_INLINE_ENTRY))
> +
> /* Variable declaration and the location of a variable. */
> #define PAT_VAR_LOCATION_DECL(PAT) (XCTREE ((PAT), 0, VAR_LOCATION))
> #define PAT_VAR_LOCATION_LOC(PAT) (XCEXP ((PAT), 1, VAR_LOCATION))
> @@ -1615,8 +1624,33 @@ extern const char * const reg_note_name[];
> #define NOTE_VAR_LOCATION_STATUS(NOTE) \
> PAT_VAR_LOCATION_STATUS (NOTE_VAR_LOCATION (NOTE))
>
> +/* Evaluate to TRUE if INSN is a debug insn that denotes a variable
> + location/value tracking annotation. */
> +#define BIND_DEBUG_INSN_P(INSN) \
> + (DEBUG_INSN_P (INSN) \
> + && (GET_CODE (PATTERN (INSN)) \
> + == VAR_LOCATION))
> +/* Evaluate to TRUE if INSN is a debug insn that denotes a program
> + source location marker. */
> +#define MARKER_DEBUG_INSN_P(INSN) \
> + (DEBUG_INSN_P (INSN) \
> + && (GET_CODE (PATTERN (INSN)) \
> + != VAR_LOCATION))
> +/* Evaluate to the marker kind. Currently the only kind is
> + BEGIN_STMT. */
> +#define INSN_DEBUG_MARKER_KIND(INSN) \
> + (GET_CODE (PATTERN (INSN)) == BEGIN_STMT_MARKER \
> + ? NOTE_INSN_BEGIN_STMT \
> + : GET_CODE (PATTERN (INSN)) == LEXICAL_BLOCK \
> + ? NOTE_INSN_INLINE_ENTRY \
> + : (enum insn_note)-1)
> +
> /* The VAR_LOCATION rtx in a DEBUG_INSN. */
> -#define INSN_VAR_LOCATION(INSN) PATTERN (INSN)
> +#define INSN_VAR_LOCATION(INSN) \
> + (RTL_FLAG_CHECK1 ("INSN_VAR_LOCATION", PATTERN (INSN), VAR_LOCATION))
> +/* A pointer to the VAR_LOCATION rtx in a DEBUG_INSN. */
> +#define INSN_VAR_LOCATION_PTR(INSN) \
> + (&PATTERN (INSN))
>
> /* Accessors for a tree-expanded var location debug insn. */
> #define INSN_VAR_LOCATION_DECL(INSN) \
> @@ -1648,6 +1682,9 @@ extern const char * const reg_note_name[];
> /* PARM_DECL DEBUG_PARAMETER_REF references. */
> #define DEBUG_PARAMETER_REF_DECL(RTX) XCTREE (RTX, 0, DEBUG_PARAMETER_REF)
>
> +/* The lexical block referenced by the LEXICAL_BLOCK RTX. */
> +#define LEXICAL_BLOCK_TREE(RTX) XCTREE (RTX, 0, LEXICAL_BLOCK)
> +
> /* Codes that appear in the NOTE_KIND field for kinds of notes
> that are not line numbers. These codes are all negative.
>
> @@ -2898,13 +2935,13 @@ extern rtx_call_insn *last_call_insn (void);
> extern rtx_insn *previous_insn (rtx_insn *);
> extern rtx_insn *next_insn (rtx_insn *);
> extern rtx_insn *prev_nonnote_insn (rtx_insn *);
> -extern rtx_insn *prev_nonnote_insn_bb (rtx_insn *);
> extern rtx_insn *next_nonnote_insn (rtx_insn *);
> -extern rtx_insn *next_nonnote_insn_bb (rtx_insn *);
> extern rtx_insn *prev_nondebug_insn (rtx_insn *);
> extern rtx_insn *next_nondebug_insn (rtx_insn *);
> extern rtx_insn *prev_nonnote_nondebug_insn (rtx_insn *);
> +extern rtx_insn *prev_nonnote_nondebug_insn_bb (rtx_insn *);
> extern rtx_insn *next_nonnote_nondebug_insn (rtx_insn *);
> +extern rtx_insn *next_nonnote_nondebug_insn_bb (rtx_insn *);
> extern rtx_insn *prev_real_insn (rtx_insn *);
> extern rtx_insn *next_real_insn (rtx);
> extern rtx_insn *prev_active_insn (rtx_insn *);
> diff --git a/gcc/sdbout.c b/gcc/sdbout.c
> index a67f9d6..e21a65d 100644
> --- a/gcc/sdbout.c
> +++ b/gcc/sdbout.c
> @@ -307,6 +307,7 @@ const struct gcc_debug_hooks sdb_debug_hooks =
> sdbout_label, /* label */
> debug_nothing_int, /* handle_pch */
> debug_nothing_rtx_insn, /* var_location */
> + debug_nothing_tree, /* inline_entry */
> debug_nothing_tree, /* size_function */
> debug_nothing_void, /* switch_text_section */
> debug_nothing_tree_tree, /* set_name */
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index d23714c..cf6d3e6 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -1534,6 +1534,18 @@ process_options (void)
> warning_at (UNKNOWN_LOCATION, 0,
> "var-tracking-assignments changes selective scheduling");
>
> + if (debug_nonbind_markers_p == AUTODETECT_VALUE)
> + debug_nonbind_markers_p = optimize && debug_info_level >= DINFO_LEVEL_NORMAL
> + && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG);
> +
> + if (debug_variable_location_views == AUTODETECT_VALUE)
> + {
> + debug_variable_location_views = flag_var_tracking
> + && debug_info_level >= DINFO_LEVEL_NORMAL
> + && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
> + && !dwarf_strict;
> + }
> +
> if (flag_tree_cselim == AUTODETECT_VALUE)
> {
> if (HAVE_conditional_move)
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index f26b12f..3a045d9 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -545,14 +545,22 @@ make_blocks_1 (gimple_seq seq, basic_block bb)
> {
> gimple_stmt_iterator i = gsi_start (seq);
> gimple *stmt = NULL;
> + gimple *prev_stmt = NULL;
> bool start_new_block = true;
> bool first_stmt_of_seq = true;
>
> while (!gsi_end_p (i))
> {
> - gimple *prev_stmt;
> -
> - prev_stmt = stmt;
> + /* PREV_STMT should only be set to a debug stmt if the debug
> + stmt is before nondebug stmts. Once stmt reaches a nondebug
> + nonlabel, prev_stmt will be set to it, so that
> + stmt_starts_bb_p will know to start a new block if a label is
> + found. However, if stmt was a label after debug stmts only,
> + keep the label in prev_stmt even if we find further debug
> + stmts, for there may be other labels after them, and they
> + should land in the same block. */
> + if (!prev_stmt || !stmt || !is_gimple_debug (stmt))
> + prev_stmt = stmt;
> stmt = gsi_stmt (i);
>
> if (stmt && is_gimple_call (stmt))
> @@ -567,6 +575,7 @@ make_blocks_1 (gimple_seq seq, basic_block bb)
> gsi_split_seq_before (&i, &seq);
> bb = create_basic_block (seq, bb);
> start_new_block = false;
> + prev_stmt = NULL;
> }
>
> /* Now add STMT to BB and create the subgraphs for special statement
> @@ -980,7 +989,11 @@ make_edges (void)
> tree target;
>
> if (!label_stmt)
> - break;
> + {
> + if (is_gimple_debug (gsi_stmt (gsi)))
> + continue;
> + break;
> + }
>
> target = gimple_label_label (label_stmt);
>
> @@ -1495,6 +1508,9 @@ cleanup_dead_labels (void)
>
> for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
> {
> + if (is_gimple_debug (gsi_stmt (i)))
> + continue;
> +
> tree label;
> glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (i));
>
> @@ -1655,6 +1671,12 @@ cleanup_dead_labels (void)
>
> for (i = gsi_start_bb (bb); !gsi_end_p (i); )
> {
> + if (is_gimple_debug (gsi_stmt (i)))
> + {
> + gsi_next (&i);
> + continue;
> + }
> +
> tree label;
> glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (i));
>
> @@ -1823,6 +1845,8 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
> gsi_next (&gsi))
> {
> tree lab;
> + if (is_gimple_debug (gsi_stmt (gsi)))
> + continue;
> glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
> if (!label_stmt)
> break;
> @@ -2625,6 +2649,13 @@ stmt_starts_bb_p (gimple *stmt, gimple *prev_stmt)
> if (stmt == NULL)
> return false;
>
> + /* PREV_STMT is only set to a debug stmt if the debug stmt is before
> + any nondebug stmts in the block. We don't want to start another
> + block in this case: the debug stmt will already have started the
> + one STMT would start if we weren't outputting debug stmts. */
> + if (prev_stmt && is_gimple_debug (prev_stmt))
> + return false;
> +
> /* Labels start a new basic block only if the preceding statement
> wasn't a label of the same type. This prevents the creation of
> consecutive blocks that have nothing but a single label. */
> @@ -5357,6 +5388,10 @@ gimple_verify_flow_info (void)
> for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> {
> tree label;
> +
> + if (is_gimple_debug (gsi_stmt (gsi)))
> + continue;
> +
> gimple *prev_stmt = stmt;
>
> stmt = gsi_stmt (gsi);
> @@ -5426,7 +5461,7 @@ gimple_verify_flow_info (void)
> }
> }
>
> - gsi = gsi_last_bb (bb);
> + gsi = gsi_last_nondebug_bb (bb);
> if (gsi_end_p (gsi))
> continue;
>
> @@ -5681,8 +5716,10 @@ gimple_block_label (basic_block bb)
> tree label;
> glabel *stmt;
>
> - for (i = s; !gsi_end_p (i); first = false, gsi_next (&i))
> + for (i = s; !gsi_end_p (i); gsi_next (&i))
> {
> + if (is_gimple_debug (gsi_stmt (i)))
> + continue;
> stmt = dyn_cast <glabel *> (gsi_stmt (i));
> if (!stmt)
> break;
> @@ -5693,6 +5730,7 @@ gimple_block_label (basic_block bb)
> gsi_move_before (&i, &s);
> return label;
> }
> + first = false;
> }
>
> label = create_artificial_label (UNKNOWN_LOCATION);
> @@ -5768,7 +5806,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
> return ret;
> }
>
> - gsi = gsi_last_bb (bb);
> + gsi = gsi_last_nondebug_bb (bb);
> stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi);
>
> switch (stmt ? gimple_code (stmt) : GIMPLE_ERROR_MARK)
> diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
> index c6e5c8d..3ba760f 100644
> --- a/gcc/tree-cfgcleanup.c
> +++ b/gcc/tree-cfgcleanup.c
> @@ -506,13 +506,13 @@ remove_forwarder_block (basic_block bb)
> {
> tree decl;
> label = gsi_stmt (gsi);
> - if (is_gimple_debug (label))
> - break;
> - decl = gimple_label_label (as_a <glabel *> (label));
> - if (EH_LANDING_PAD_NR (decl) != 0
> - || DECL_NONLOCAL (decl)
> - || FORCED_LABEL (decl)
> - || !DECL_ARTIFICIAL (decl))
> + if (is_gimple_debug (label)
> + ? can_move_debug_stmts
> + : ((decl = gimple_label_label (as_a <glabel *> (label))),
> + EH_LANDING_PAD_NR (decl) != 0
> + || DECL_NONLOCAL (decl)
> + || FORCED_LABEL (decl)
> + || !DECL_ARTIFICIAL (decl)))
> {
> gsi_remove (&gsi, false);
> gsi_insert_before (&gsi_to, label, GSI_SAME_STMT);
> @@ -521,20 +521,6 @@ remove_forwarder_block (basic_block bb)
> gsi_next (&gsi);
> }
>
> - /* Move debug statements if the destination has a single predecessor. */
> - if (can_move_debug_stmts)
> - {
> - gsi_to = gsi_after_labels (dest);
> - for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); )
> - {
> - gimple *debug = gsi_stmt (gsi);
> - if (!is_gimple_debug (debug))
> - break;
> - gsi_remove (&gsi, false);
> - gsi_insert_before (&gsi_to, debug, GSI_SAME_STMT);
> - }
> - }
> -
> bitmap_set_bit (cfgcleanup_altered_bbs, dest->index);
>
> /* Update the dominators. */
> @@ -1236,7 +1222,8 @@ execute_cleanup_cfg_post_optimizing (void)
>
> flag_dump_noaddr = flag_dump_unnumbered = 1;
> fprintf (final_output, "\n");
> - dump_enumerated_decls (final_output, dump_flags | TDF_NOUID);
> + dump_enumerated_decls (final_output,
> + dump_flags | TDF_SLIM | TDF_NOUID);
> flag_dump_noaddr = save_noaddr;
> flag_dump_unnumbered = save_unnumbered;
> if (fclose (final_output))
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index affde64..f1c94ac 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"
> @@ -1347,7 +1348,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
> gimple_seq stmts = NULL;
>
> if (is_gimple_debug (stmt)
> - && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
> + && (gimple_debug_nonbind_marker_p (stmt)
> + ? !cfun->debug_nonbind_markers
> + : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
> return stmts;
>
> /* Begin by recognizing trees that we'll completely rewrite for the
> @@ -1630,6 +1633,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
> gimple_seq_add_stmt (&stmts, copy);
> return stmts;
> }
> + if (gimple_debug_nonbind_marker_p (stmt))
> + {
> + /* If the inlined function has too many debug markers,
> + don't copy them. */
> + if (id->src_cfun->debug_marker_count
> + > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
> + return stmts;
> +
> + gdebug *copy = as_a <gdebug *> (gimple_copy (stmt));
> + id->debug_stmts.safe_push (copy);
> + gimple_seq_add_stmt (&stmts, copy);
> + return stmts;
> + }
> + gcc_checking_assert (!is_gimple_debug (stmt));
>
> /* Create a new deep copy of the statement. */
> copy = gimple_copy (stmt);
> @@ -1725,7 +1742,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
> gimple_set_block (copy, *n);
> }
>
> - if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
> + if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)
> + || gimple_debug_nonbind_marker_p (copy))
> {
> gimple_seq_add_stmt (&stmts, copy);
> return stmts;
> @@ -2599,6 +2617,10 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
> value = gimple_debug_source_bind_get_value (stmt);
> new_stmt = gimple_build_debug_source_bind (var, value, stmt);
> }
> + else if (gimple_debug_nonbind_marker_p (stmt))
> + {
> + new_stmt = as_a <gdebug *> (gimple_copy (stmt));
> + }
> else
> gcc_unreachable ();
> gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
> @@ -2915,6 +2937,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
> gimple_set_block (stmt, n ? *n : id->block);
> }
>
> + if (gimple_debug_nonbind_marker_p (stmt))
> + return;
> +
> /* Remap all the operands in COPY. */
> memset (&wi, 0, sizeof (wi));
> wi.info = id;
> @@ -2923,8 +2948,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)))
> @@ -4672,6 +4699,14 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
> GSI_NEW_STMT);
> }
> initialize_inlined_parameters (id, stmt, fn, bb);
> + if (debug_nonbind_markers_p && id->block
> + && inlined_function_outer_scope_p (id->block))
> + {
> + gimple_stmt_iterator si = gsi_last_bb (bb);
> + gsi_insert_after (&si, gimple_build_debug_inline_entry
> + (id->block, DECL_SOURCE_LOCATION (fn)),
> + GSI_NEW_STMT);
> + }
>
> if (DECL_INITIAL (fn))
> {
> 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 c7509af..255f84c 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;
> }
> @@ -3386,7 +3390,10 @@ print_declaration (pretty_printer *pp, tree t, int spc, dump_flags_t flags)
> pp_space (pp);
> pp_equal (pp);
> pp_space (pp);
> - dump_generic_node (pp, DECL_INITIAL (t), spc, flags, false);
> + if (!(flags & TDF_SLIM))
> + dump_generic_node (pp, DECL_INITIAL (t), spc, flags, false);
> + else
> + pp_string (pp, "<<< omitted >>>");
> }
> }
>
> diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
> index e62afad..703c359 100644
> --- a/gcc/tree-ssa-dce.c
> +++ b/gcc/tree-ssa-dce.c
> @@ -257,7 +257,8 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
> easily locate the debug temp bind stmt for a use thereof,
> would could refrain from marking all debug temps here, and
> mark them only if they're used. */
> - if (!gimple_debug_bind_p (stmt)
> + if (gimple_debug_nonbind_marker_p (stmt)
> + || !gimple_debug_bind_p (stmt)
> || gimple_debug_bind_has_value_p (stmt)
> || TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL)
> mark_stmt_necessary (stmt, false);
> @@ -1448,8 +1449,7 @@ eliminate_unnecessary_stmts (void)
> dominate others. Walking backwards, this should
> be the common case. ??? Do we need to recompute
> dominators because of cfg_altered? */
> - if (!MAY_HAVE_DEBUG_STMTS
> - || !first_dom_son (CDI_DOMINATORS, bb))
> + if (!first_dom_son (CDI_DOMINATORS, bb))
> delete_basic_block (bb);
> else
> {
> diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
> index 8738fe2..734d15d 100644
> --- a/gcc/tree-ssa-live.c
> +++ b/gcc/tree-ssa-live.c
> @@ -520,6 +520,11 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
> else if (!BLOCK_SUPERCONTEXT (scope)
> || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL)
> unused = false;
> + /* Preserve the block, it is referenced by at least the inline
> + entry point marker. */
> + else if (debug_nonbind_markers_p
> + && inlined_function_outer_scope_p (scope))
> + unused = false;
> /* Innermost blocks with no live variables nor statements can be always
> eliminated. */
> else if (!nsubblocks)
> @@ -548,11 +553,13 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
> }
> else if (BLOCK_VARS (scope) || BLOCK_NUM_NONLOCALIZED_VARS (scope))
> unused = false;
> - /* See if this block is important for representation of inlined function.
> - Inlined functions are always represented by block with
> - block_ultimate_origin being set to FUNCTION_DECL and DECL_SOURCE_LOCATION
> - set... */
> - else if (inlined_function_outer_scope_p (scope))
> + /* See if this block is important for representation of inlined
> + function. Inlined functions are always represented by block
> + with block_ultimate_origin being set to FUNCTION_DECL and
> + DECL_SOURCE_LOCATION set, unless they expand to nothing... But
> + see above for the case of statement frontiers. */
> + else if (!debug_nonbind_markers_p
> + && inlined_function_outer_scope_p (scope))
> unused = false;
> else
> /* Verfify that only blocks with source location set
> @@ -640,6 +647,16 @@ dump_scope_block (FILE *file, int indent, tree scope, dump_flags_t flags)
> fprintf (file, "#%i", BLOCK_NUMBER (origin));
> }
> }
> + if (BLOCK_FRAGMENT_ORIGIN (scope))
> + fprintf (file, " Fragment of : #%i",
> + BLOCK_NUMBER (BLOCK_FRAGMENT_ORIGIN (scope)));
> + else if (BLOCK_FRAGMENT_CHAIN (scope))
> + {
> + fprintf (file, " Fragment chain :");
> + for (t = BLOCK_FRAGMENT_CHAIN (scope); t ;
> + t = BLOCK_FRAGMENT_CHAIN (t))
> + fprintf (file, " #%i", BLOCK_NUMBER (t));
> + }
> fprintf (file, " \n");
> for (var = BLOCK_VARS (scope); var; var = DECL_CHAIN (var))
> {
> diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
> index a65ff31..6771606 100644
> --- a/gcc/tree-ssa-tail-merge.c
> +++ b/gcc/tree-ssa-tail-merge.c
> @@ -1295,14 +1295,14 @@ find_duplicate (same_succ *same_succ, basic_block bb1, basic_block bb2)
> tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi1)));
> if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
> return;
> - gsi_prev (&gsi1);
> + gsi_prev_nondebug (&gsi1);
> }
> while (!gsi_end_p (gsi2) && gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL)
> {
> tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2)));
> if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
> return;
> - gsi_prev (&gsi2);
> + gsi_prev_nondebug (&gsi2);
> }
> if (!(gsi_end_p (gsi1) && gsi_end_p (gsi2)))
> return;
> diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
> index 536c471..1c221e2 100644
> --- a/gcc/tree-ssa-threadedge.c
> +++ b/gcc/tree-ssa-threadedge.c
> @@ -739,6 +739,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,6 +768,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))
> + var = NULL;
> else
> gcc_unreachable ();
>
> @@ -777,7 +781,9 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
> or somesuch. Adding `&& bb == src' to the condition
> below will preserve all potentially relevant debug
> notes. */
> - if (vars && vars->add (var))
> + if (!var)
> + /* Just copy the stmt. */;
> + else if (vars && vars->add (var))
> continue;
> else if (!vars)
> {
> diff --git a/gcc/tree.c b/gcc/tree.c
> index c493edd5..5e98e46 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -1013,7 +1013,8 @@ make_node (enum tree_code code MEM_STAT_DECL)
> switch (type)
> {
> case tcc_statement:
> - TREE_SIDE_EFFECTS (t) = 1;
> + if (code != DEBUG_BEGIN_STMT)
> + TREE_SIDE_EFFECTS (t) = 1;
> break;
>
> case tcc_declaration:
> @@ -4405,7 +4406,10 @@ build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)
> }
>
> if (TREE_CODE_CLASS (code) == tcc_statement)
> - TREE_SIDE_EFFECTS (t) = 1;
> + {
> + if (code != DEBUG_BEGIN_STMT)
> + TREE_SIDE_EFFECTS (t) = 1;
> + }
> else switch (code)
> {
> case VA_ARG_EXPR:
> 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 46debc1..eaa4962 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -1127,7 +1127,8 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
> ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
>
> /* Nonzero if is_gimple_debug() may possibly hold. */
> -#define MAY_HAVE_DEBUG_STMTS (flag_var_tracking_assignments)
> +#define MAY_HAVE_DEBUG_STMTS \
> + (flag_var_tracking_assignments || debug_nonbind_markers_p)
>
> /* In a LOOP_EXPR node. */
> #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
> @@ -1219,7 +1220,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/valtrack.c b/gcc/valtrack.c
> index 9e28d4b..2135458 100644
> --- a/gcc/valtrack.c
> +++ b/gcc/valtrack.c
> @@ -211,7 +211,7 @@ propagate_for_debug (rtx_insn *insn, rtx_insn *last, rtx dest, rtx src,
> {
> insn = next;
> next = NEXT_INSN (insn);
> - if (DEBUG_INSN_P (insn))
> + if (BIND_DEBUG_INSN_P (insn))
> {
> loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
> dest, propagate_for_debug_subst, &p);
> diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
> index 5c38c1d..d359517 100644
> --- a/gcc/var-tracking.c
> +++ b/gcc/var-tracking.c
> @@ -9471,6 +9471,24 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
> }
> }
>
> +/* Return BB's head, unless BB is the block that succeeds ENTRY_BLOCK,
> + in which case it searches back from BB's head for the very first
> + insn. Use [get_first_insn (bb), BB_HEAD (bb->next_bb)[ as a range
> + to iterate over all insns of a function while iterating over its
> + BBs. */
> +
> +static rtx_insn *
> +get_first_insn (basic_block bb)
> +{
> + rtx_insn *insn = BB_HEAD (bb);
> +
> + if (bb->prev_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
> + while (rtx_insn *prev = PREV_INSN (insn))
> + insn = prev;
> +
> + return insn;
> +}
> +
> /* Emit notes for the whole function. */
>
> static void
> @@ -9501,7 +9519,8 @@ vt_emit_notes (void)
> {
> /* Emit the notes for changes of variable locations between two
> subsequent basic blocks. */
> - emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
> + emit_notes_for_differences (get_first_insn (bb),
> + &cur, &VTI (bb)->in);
>
> if (MAY_HAVE_DEBUG_INSNS)
> local_get_addr_cache = new hash_map<rtx, rtx>;
> @@ -9901,6 +9920,37 @@ 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 (MARKER_DEBUG_INSN_P (insn));
> +
> + enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
> +
> + switch (kind)
> + {
> + case NOTE_INSN_BEGIN_STMT:
> + case NOTE_INSN_INLINE_ENTRY:
> + {
> + 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. */
>
> @@ -10097,11 +10147,34 @@ vt_initialize (void)
> {
> HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
> VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
> - for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
> - insn = NEXT_INSN (insn))
> +
> + /* If we are walking the first basic block, walk any HEADER
> + insns that might be before it too. Unfortunately,
> + BB_HEADER and BB_FOOTER are not set while we run this
> + pass. */
> + insn = get_first_insn (bb);
> + for (rtx_insn *next;
> + insn != BB_HEAD (bb->next_bb)
> + ? next = NEXT_INSN (insn), true : false;
> + insn = next)
> {
> if (INSN_P (insn))
> {
> + basic_block save_bb = BLOCK_FOR_INSN (insn);
> + if (!BLOCK_FOR_INSN (insn))
> + {
> + BLOCK_FOR_INSN (insn) = bb;
> + gcc_assert (DEBUG_INSN_P (insn));
> + /* Reset debug insns between basic blocks.
> + Their location is not reliable, because they
> + were probably not maintained up to date. */
> + if (BIND_DEBUG_INSN_P (insn))
> + INSN_VAR_LOCATION_LOC (insn)
> + = gen_rtx_UNKNOWN_VAR_LOC ();
> + }
> + else
> + gcc_assert (BLOCK_FOR_INSN (insn) == bb);
> +
> if (!frame_pointer_needed)
> {
> insn_stack_adjust_offset_pre_post (insn, &pre, &post);
> @@ -10123,6 +10196,12 @@ vt_initialize (void)
> adjust_insn (bb, insn);
> if (MAY_HAVE_DEBUG_INSNS)
> {
> + if (MARKER_DEBUG_INSN_P (insn))
> + {
> + insn = reemit_marker_as_note (insn, &save_bb);
> + continue;
> + }
> +
> if (CALL_P (insn))
> prepare_call_arguments (bb, insn);
> cselib_process_insn (insn);
> @@ -10169,6 +10248,7 @@ vt_initialize (void)
> }
> }
> }
> + BLOCK_FOR_INSN (insn) = save_bb;
> }
> }
> gcc_assert (offset == VTI (bb)->out.stack_adjust);
> @@ -10196,10 +10276,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;
> @@ -10209,9 +10290,18 @@ delete_debug_insns (void)
>
> FOR_EACH_BB_FN (bb, cfun)
> {
> - FOR_BB_INSNS_SAFE (bb, insn, next)
> + for (insn = get_first_insn (bb);
> + insn != BB_HEAD (bb->next_bb)
> + ? next = NEXT_INSN (insn), true : false;
> + insn = next)
> if (DEBUG_INSN_P (insn))
> {
> + if (MARKER_DEBUG_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)
> @@ -10237,10 +10327,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. */
> @@ -10305,15 +10398,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)
> {
> @@ -10335,7 +10434,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;
> diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
> index 42300e2..557b76e 100644
> --- a/gcc/vmsdbgout.c
> +++ b/gcc/vmsdbgout.c
> @@ -203,6 +203,7 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks
> debug_nothing_rtx_code_label, /* label */
> debug_nothing_int, /* handle_pch */
> debug_nothing_rtx_insn, /* var_location */
> + debug_nothing_tree, /* inline_entry */
> debug_nothing_tree, /* size_function */
> debug_nothing_void, /* switch_text_section */
> debug_nothing_tree_tree, /* set_name */
> diff --git a/include/dwarf2.def b/include/dwarf2.def
> index a91e943..1d6d13b 100644
> --- a/include/dwarf2.def
> +++ b/include/dwarf2.def
> @@ -443,6 +443,8 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
> /* Attribute for discriminator.
> See http://gcc.gnu.org/wiki/Discriminator */
> DW_AT (DW_AT_GNU_discriminator, 0x2136)
> +DW_AT (DW_AT_GNU_locviews, 0x2137)
> +DW_AT (DW_AT_GNU_entry_view, 0x2138)
> /* VMS extensions. */
> DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
> /* GNAT extensions. */
> diff --git a/include/dwarf2.h b/include/dwarf2.h
> index 14b6f22e..c6d410e3 100644
> --- a/include/dwarf2.h
> +++ b/include/dwarf2.h
> @@ -296,6 +296,14 @@ enum dwarf_location_list_entry_type
> DW_LLE_start_end = 0x07,
> DW_LLE_start_length = 0x08,
>
> + /* <http://lists.dwarfstd.org/private.cgi/dwarf-discuss-dwarfstd.org/2017-April/004347.html>
> + has the proposal for now; only available to list members.
> +
> + A (possibly updated) copy of the proposal is available at
> + <http://people.redhat.com/aoliva/papers/sfn/dwarf6-sfn-lvu.txt>. */
> + DW_LLE_GNU_view_pair = 0x09,
> +#define DW_LLE_view_pair DW_LLE_GNU_view_pair
> +
> /* Former extension for Fission.
> See http://gcc.gnu.org/wiki/DebugFission. */
> DW_LLE_GNU_end_of_list_entry = 0x00,
>
>
> --
> Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/
> You must be the change you wish to see in the world. -- Gandhi
> Be Free! -- http://FSFLA.org/ FSF Latin America board member
> Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer