diff mbox

Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views)

Message ID ork22060a6.fsf_-_@lxoliva.fsfla.org
State New
Headers show

Commit Message

Alexandre Oliva Aug. 18, 2017, 9:20 p.m. UTC
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.  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



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(-)

Comments

Richard Biener Aug. 21, 2017, 12:01 p.m. UTC | #1
..
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
Alexandre Oliva Aug. 22, 2017, 8:43 p.m. UTC | #2
On Aug 21, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> On Fri, Aug 18, 2017 at 11:20 PM, Alexandre Oliva <aoliva@redhat.com> wrote:

>> 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?

I'm pretty sure I split out before the ones that were not triggered by
the introduction of the new debug position markers.  The remaining ones
thus don't necessarily stand on their own, since the conditions needed
to trigger them are not necessarily exercised by the compiler.  Plus,
most of the fixes introduce references to the new classification of
debug stmts and insns.

Would it be sensible and acceptable to bring the bits that introduce the
new classification along with their new uses, rather than make two
revisions at the same spots?

> +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-..?

Good question.  I vaguely recall wondering about that myself when
copying from some other option.  Will investigate.


>    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 ...

Yeah, gimple notation seems to go from most general to most specific
(first gimple, then debug, then bind), whereas we go from specific to
general in the rtl macro names (insn at the end, debug just before it,
and now bind just before it).  I suppose debug bind insn would work, as
well, though it feels as awkward and inconsistent as e.g. Brazil, São
Paulo, Earth to me.  Or, for that matter, Aug 22, 2017, ;-) so I guess
one could get used to it ;-)


> +  /* 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?

IIRC we do have a limit for VTA notes too, but there's a C++ testcase
(g++.dg/tree-ssa/pr14703.C) that expands and inlines fibonacci template
functions so deep, more than doubling the number of statements at all
but the base recursion levels, so we'd end up with over 2^{85+} debug
stmts if we didn't cut them off somehow.

> 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]

I'm not sure how to count gimple stmts precisely, but I can count DEBUG
ones exactly.  Compiling tramp3d-v4 with -O2 -g and either -g0, -g, or
-gno-statement-frontiers, respectively, the 228t.optimized dump contains:

$ grep -c '^ *# DEBUG ' tramp3d-v4.ii.228t.optimized-*
tramp3d-v4.ii.228t.optimized-g0:0
tramp3d-v4.ii.228t.optimized-markers:982493
tramp3d-v4.ii.228t.optimized-noSFN:743940

$ wc -l tramp3d-v4.ii.228t.optimized-*
  238038 tramp3d-v4.ii.228t.optimized-g0
 1220531 tramp3d-v4.ii.228t.optimized-markers
  981978 tramp3d-v4.ii.228t.optimized-noSFN

So it seems like SFN and IEPM add a little over one extra debug stmt per
real stmt, whereas VTA added 3.  For this testcase, anyway.

That's not surprising.  Most useful statements have at least one
(variable-binding) side effect, and quite often more than one, so VTA
notes tend to dominate the begin_stmt markers.

Even inlined calls, that might have a different ratio, it's still one
inlined entry point and possibly one begin stmt marker, vs one bind stmt
per parameter, plus the inlined code.


> Would a better option be to condense multiple adjacent notes to a single one?
> That way we'd have a natural bound as fallback.

That wouldn't help with the fibonacci testcase, I'm afraid, but it's an
interesting idea I had not explored.

I guess it wouldn't help much in typical code, since typical code has
side effects and thus binding stmts, so we wouldn't find long streams of
nonbinding markers.  Even the atypical case of the fibonacci template
function set would end up being cut-off once I get to adding bindings
for return values, which is in my list of things to explore.


> 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?

I haven't observed any notable changes.  I'll be glad to collect and
supply any specific measurements you choose.


> +      if (MARKER_DEBUG_INSN_P (insn))
> +       return true;
> +

> DEBUG_MARKER_INSN_P

See above.


> +/* 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.

*nod*; I recall having gone carefully over this part while preparing the
 ChangeLog.  Here it is, much easier to read: :-)

	* 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.


> @@ -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.

We don't really need to it to be exact.  A rough estimate will do.


> +  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)

*nod* (as in, yeah, would be nice, but likely overkill, and more so
considering the reorg suggested below)

> 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?

Interesting thought.  Yeah, I guess that could be done.  I'll give it a shot.

> Saving two pointers or nearly half size?  Could it also hold a vector of
> locations so we can optimize adjacent stmt-start stmts,

As mentioned earlier in this message, I don't see that this occurs often
enough to make sense.  In tramp3d-v4.ii.228t.optimized-markers, there
are only 2165 sequences with 2+ begin stmt markers one right after the
other; 92 with 3+, and only 2 with 4.


> maybe even also cover the inline thing?

Considering that the inlined entry point marker is most likely just
before the begin stmt marker of the first stmt of a function, it would
seem to very well make sense to combine them, or just set a flag in the
stmt to indicate what it is.

However, their locations are different, and they should ideally remain
so.  I don't think growing the far more frequent begin stmt marker to
make room for an additional location for the infrequent inlined entry
point marker would make sense in general.

> +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...

'k


> 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

Thanks, will fix.


> 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.

*nod*


> 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?)

I confess I hadn't considered any of that.  I'll give it some thought.
Binds don't refer to a (program) location, yeah, whereas that's all the
new markers do.  Inline markers actually reference the lexical block
containing the entire inlined copy of the function, and there's code
that depends on it, so we'd have to figure out some way to express that
sort of thing, in case the GIMPLE FE can't.  Once we have that, the
syntax for debug stmts is just a breeze.


Thanks,
Alexandre Oliva Aug. 22, 2017, 10:29 p.m. UTC | #3
On Aug 21, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> +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-..?

All debug options that support negation seem to have adopted this idiom;
without it, the negated options end up misparsed as -g with an argument,
and then set_debug_level complains that "no-..." is not a number.

The logic of matching the longest option name prefix doesn't seem to
work very well when options have a prefix that is also a valid option
with a Joined(OrMissing) argument.

The same problem applies to -O: -Ono-fast is not parsed as a negative of
-Ofast, but as -O with no-fast as the argument, even though no
RejectNegative flag is present under Ofast.
Richard Biener Aug. 23, 2017, 10:59 a.m. UTC | #4
On Tue, Aug 22, 2017 at 10:43 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Aug 21, 2017, Richard Biener <richard.guenther@gmail.com> wrote:
>
>> On Fri, Aug 18, 2017 at 11:20 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
>
>>> 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?
>
> I'm pretty sure I split out before the ones that were not triggered by
> the introduction of the new debug position markers.  The remaining ones
> thus don't necessarily stand on their own, since the conditions needed
> to trigger them are not necessarily exercised by the compiler.  Plus,
> most of the fixes introduce references to the new classification of
> debug stmts and insns.
>
> Would it be sensible and acceptable to bring the bits that introduce the
> new classification along with their new uses, rather than make two
> revisions at the same spots?

Just separating the boilerplate changes out from the "meat" of the change
into a separate patch for easier reviewing would be nice.

>> +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-..?
>
> Good question.  I vaguely recall wondering about that myself when
> copying from some other option.  Will investigate.
>
>
>>    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 ...
>
> Yeah, gimple notation seems to go from most general to most specific
> (first gimple, then debug, then bind), whereas we go from specific to
> general in the rtl macro names (insn at the end, debug just before it,
> and now bind just before it).  I suppose debug bind insn would work, as
> well, though it feels as awkward and inconsistent as e.g. Brazil, São
> Paulo, Earth to me.  Or, for that matter, Aug 22, 2017, ;-) so I guess
> one could get used to it ;-)
>
>
>> +  /* 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?
>
> IIRC we do have a limit for VTA notes too, but there's a C++ testcase
> (g++.dg/tree-ssa/pr14703.C) that expands and inlines fibonacci template
> functions so deep, more than doubling the number of statements at all
> but the base recursion levels, so we'd end up with over 2^{85+} debug
> stmts if we didn't cut them off somehow.

Yeah, but I meant we've kept them throughout GIMPLE (for all functions!)
but are dropping them here at RTL expansion (which we'll have only a
single live RTL function at a time).  That looks odd ;)  You're already
dropping them at inlining as well so the RTL expansion check should
be superfluous IMHO (yeah, unrolling might push it over the edge for example
but all real issues should come from inlining).

>> 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]
>
> I'm not sure how to count gimple stmts precisely, but I can count DEBUG
> ones exactly.  Compiling tramp3d-v4 with -O2 -g and either -g0, -g, or
> -gno-statement-frontiers, respectively, the 228t.optimized dump contains:
>
> $ grep -c '^ *# DEBUG ' tramp3d-v4.ii.228t.optimized-*
> tramp3d-v4.ii.228t.optimized-g0:0
> tramp3d-v4.ii.228t.optimized-markers:982493
> tramp3d-v4.ii.228t.optimized-noSFN:743940
>
> $ wc -l tramp3d-v4.ii.228t.optimized-*
>   238038 tramp3d-v4.ii.228t.optimized-g0
>  1220531 tramp3d-v4.ii.228t.optimized-markers
>   981978 tramp3d-v4.ii.228t.optimized-noSFN
>
> So it seems like SFN and IEPM add a little over one extra debug stmt per
> real stmt, whereas VTA added 3.  For this testcase, anyway.

Ok, thanks for the number ;)

> That's not surprising.  Most useful statements have at least one
> (variable-binding) side effect, and quite often more than one, so VTA
> notes tend to dominate the begin_stmt markers.
>
> Even inlined calls, that might have a different ratio, it's still one
> inlined entry point and possibly one begin stmt marker, vs one bind stmt
> per parameter, plus the inlined code.
>
>
>> Would a better option be to condense multiple adjacent notes to a single one?
>> That way we'd have a natural bound as fallback.
>
> That wouldn't help with the fibonacci testcase, I'm afraid, but it's an
> interesting idea I had not explored.
>
> I guess it wouldn't help much in typical code, since typical code has
> side effects and thus binding stmts, so we wouldn't find long streams of
> nonbinding markers.  Even the atypical case of the fibonacci template
> function set would end up being cut-off once I get to adding bindings
> for return values, which is in my list of things to explore.

Hmm, yeah.  I guess we'd have to have a multi-DEBUG_STMT that covers
not only multiple markers but also multiple binds.  High GIMPLE has
nested stmts so it might be tempting to wrap adjacent debug-stmts into
a single one (basically make the IL walking overhead with debug stmts smaller).
Costs extra memory instead of less when compared to my idea of course.

>
>> 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?
>
> I haven't observed any notable changes.  I'll be glad to collect and
> supply any specific measurements you choose.

Just curious if, for example, --with-build-config=bootstrap-lto
--enable-languages=c
--disable-multilib and make -j1 shows any difference in time and/or peak memory
use (the interesting peak memory use is that of the WPA phase).

>
>> +      if (MARKER_DEBUG_INSN_P (insn))
>> +       return true;
>> +
>
>> DEBUG_MARKER_INSN_P
>
> See above.

Yeah, please change those.

>
>> +/* 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.
>
> *nod*; I recall having gone carefully over this part while preparing the
>  ChangeLog.  Here it is, much easier to read: :-)
>
>         * 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.

;)  Btw, this looked like part of the boilerplate that could be split out and
committed separately even?  That is, the effective renaming this does
and changing users?

>
>> @@ -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.
>
> We don't really need to it to be exact.  A rough estimate will do.

Ok.

>
>> +  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)
>
> *nod* (as in, yeah, would be nice, but likely overkill, and more so
> considering the reorg suggested below)
>
>> 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?
>
> Interesting thought.  Yeah, I guess that could be done.  I'll give it a shot.

Thanks.  Will result in a somewhat awkward class hierarchy as those
can't be gdebug * then, but well ...

>> Saving two pointers or nearly half size?  Could it also hold a vector of
>> locations so we can optimize adjacent stmt-start stmts,
>
> As mentioned earlier in this message, I don't see that this occurs often
> enough to make sense.  In tramp3d-v4.ii.228t.optimized-markers, there
> are only 2165 sequences with 2+ begin stmt markers one right after the
> other; 92 with 3+, and only 2 with 4.

Ok, thanks for checking.

>
>> maybe even also cover the inline thing?
>
> Considering that the inlined entry point marker is most likely just
> before the begin stmt marker of the first stmt of a function, it would
> seem to very well make sense to combine them, or just set a flag in the
> stmt to indicate what it is.
>
> However, their locations are different, and they should ideally remain
> so.  I don't think growing the far more frequent begin stmt marker to
> make room for an additional location for the infrequent inlined entry
> point marker would make sense in general.

Agreed.

>> +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...
>
> 'k
>
>
>> 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
>
> Thanks, will fix.
>
>
>> 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.
>
> *nod*
>
>
>> 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?)
>
> I confess I hadn't considered any of that.  I'll give it some thought.
> Binds don't refer to a (program) location, yeah, whereas that's all the
> new markers do.  Inline markers actually reference the lexical block
> containing the entire inlined copy of the function, and there's code
> that depends on it, so we'd have to figure out some way to express that
> sort of thing, in case the GIMPLE FE can't.  Once we have that, the
> syntax for debug stmts is just a breeze.

Ah, lexical blocks.  Yeah, we'd have to add a syntactic way to
name them and refer to them.  At least BINDS look easily doable ;)
For blocks there's the additional issue that the GIMPLE FE doesn't
really have them as GIMPLE doesn't really care unless you start
introducing locations and debug info ;)  So with the GIMPLE FE
there's just the functions outermost scope/BLOCK.  It shouldn't be
too hard to add though if we think it's useful.

Richard.

>
> Thanks,
>
> --
> 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
Richard Biener Aug. 23, 2017, 11:01 a.m. UTC | #5
On Wed, Aug 23, 2017 at 12:29 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Aug 21, 2017, Richard Biener <richard.guenther@gmail.com> wrote:
>
>> +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-..?
>
> All debug options that support negation seem to have adopted this idiom;
> without it, the negated options end up misparsed as -g with an argument,
> and then set_debug_level complains that "no-..." is not a number.
>
> The logic of matching the longest option name prefix doesn't seem to
> work very well when options have a prefix that is also a valid option
> with a Joined(OrMissing) argument.
>
> The same problem applies to -O: -Ono-fast is not parsed as a negative of
> -Ofast, but as -O with no-fast as the argument, even though no
> RejectNegative flag is present under Ofast.

Ah, like we don't have -no-g but only -g0.  I guess that there's -fno-
is somewhere hardcoded and -g isn't handled that way.  Would need
to amend the options machinery somehow (new flag, Negatable?).
Thus ok as in your patch for now.

Richard.

> --
> 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
Alexandre Oliva Aug. 25, 2017, 2:26 p.m. UTC | #6
On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

>>> if they are not a problem up until here why care now?

>> IIRC we do have a limit for VTA notes too, but there's a C++ testcase
>> (g++.dg/tree-ssa/pr14703.C) that expands and inlines fibonacci template
>> functions so deep, more than doubling the number of statements at all
>> but the base recursion levels, so we'd end up with over 2^{85+} debug
>> stmts if we didn't cut them off somehow.

> Yeah, but I meant we've kept them throughout GIMPLE (for all functions!)
> but are dropping them here at RTL expansion (which we'll have only a
> single live RTL function at a time).  That looks odd ;)

Aah, yeah, the point is, if we find we exceeded the limit, we don't
bother to clean up the gimple, we just refrain from wasting further time
with it, which we would if we converted them to RTL (and then threw them
away), or copied them all when inlining into some other function.  We
could clean up at some point, just as we could stop emitting further
markers once the limit is reached, but it didn't seem important enough
to do so.  Should it prove to be, I guess it wouldn't be too hard to add
it to gimple verification passes that walk over all stmts.

> You're already dropping them at inlining as well so the RTL expansion
> check should be superfluous IMHO (yeah, unrolling might push it over
> the edge for example but all real issues should come from inlining).

The RTL expansion check is indeed not essential, but if we're over the
limit, we'll to throw it all away, so why bother expanding it and
carrying it through all RTL passes just to throw away at the end?  Or
should we not throw it away in this case, and make the limit apply only
to inlining?  But then, what if we inline lots of very large functions
into a single one, do we still want to use markers for that function?
That's not how I designed it, but I guess it might work that way too.


> Hmm, yeah.  I guess we'd have to have a multi-DEBUG_STMT that covers
> not only multiple markers but also multiple binds.  High GIMPLE has
> nested stmts so it might be tempting to wrap adjacent debug-stmts into
> a single one (basically make the IL walking overhead with debug stmts smaller).
> Costs extra memory instead of less when compared to my idea of course.

Yeah.  I guess that's doable and it won't make gimple passes much
trickier: in most cases all that matters are the SSA uses in bind value
expressions, so as long as the update function can efficiently pick the
SSA uses from the op array, it could be a significant win.  

We may need some way to reset one specific bind given a use that is no
longer valid, which I don't immediately see how to implement efficiently
in a multi-debug pack .

Now, I spent some time trying to think of how to pack multiple debug
stmts in a way that made them also save memory.

For each packed stmt, we need at least one bit to indicate whether it's
a bind or just a marker.  Markers then need a locus, and another bit
indicating whether it's a begin stmt marker or an inline entry point
marker.  Debug bind stmts need one bit to indicate tell src binds from
regular ones, and two trees (no locus).

It is unlikely that it would make sense to allocate extra memory, be it
trees holding integral values, be it other arrays to hold them.  I'm
thinking we'd be better off storing some of these bits in an analogous
of the trailing op VLA, that would be present in gdebug but that would
deal with GGC and ssa updates in its own way.

For packs with few stmts, we could use bits from the subcode to indicate
the count and the kinds.  We could use the gimple locus for the first
marker, and then perhaps pack pairs of loci in tree pointer operands (if
their sizes are 1:2, as in lp64).

When packing more than few stmts, we could then define a format for a
32-bit word to hold the bits for an additional set of stmts, possibly
packed in the same word as a locus or another such bit pack.  Ideally,
should we need more than one of these, we should indicate upfront how
many of these there are, or at least how many ops are used.

I was thinking it would be ideal if combining two many-stmts debug stmts
could require little more than allocating a gimple with a larger ops
array and copying (most of) the original op arrays to the right places.

But...  this all feels far too hackish and not very maintainable or
forward-looking.  E.g., if we add more kinds of debug stmts, the bit
counting suddenly no longer applies, and needs to be reworked.

So I guess that's also doable, and would save some memory indeed,
but...  do you think it's worth it?


>>> 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?)
>> 
>> I confess I hadn't considered any of that.  I'll give it some thought.
>> Binds don't refer to a (program) location, yeah, whereas that's all the
>> new markers do.  Inline markers actually reference the lexical block
>> containing the entire inlined copy of the function, and there's code
>> that depends on it, so we'd have to figure out some way to express that
>> sort of thing, in case the GIMPLE FE can't.  Once we have that, the
>> syntax for debug stmts is just a breeze.

> Ah, lexical blocks.  Yeah, we'd have to add a syntactic way to
> name them and refer to them.  At least BINDS look easily doable ;)
> For blocks there's the additional issue that the GIMPLE FE doesn't
> really have them as GIMPLE doesn't really care unless you start
> introducing locations and debug info ;)  So with the GIMPLE FE
> there's just the functions outermost scope/BLOCK.  It shouldn't be
> too hard to add though if we think it's useful.

I've given this some more thought too.  I'm a bit confused as to the
role of debug info in this FE.  If it is to be regarded as a source
language, then you'll want at least begin stmt and inline entry markers
to be introduced in the normal way, namely, by the front end, while
parsing statements, and by the inliner, when performing the inlining.
This would address the problem of representation of lexical blocks, too.

It would not, however, deal with the more traditional debug stmts, the
bind ones.  Those are introduced during gimplification, when going into
SSA.  Presumably you don't go through that with GIMPLE FE input, and at
most run some SSA verification and update pass.  If that is so, then it
makes a lot of sense to have explicit debug bind stmts, even as a means
of associating SSA names with variables (how do you do that otherwise?)
Alexandre Oliva Aug. 25, 2017, 6:12 p.m. UTC | #7
On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> Just curious if, for example, --with-build-config=bootstrap-lto
> --enable-languages=c
> --disable-multilib and make -j1 shows any difference in time and/or peak memory
> use (the interesting peak memory use is that of the WPA phase).

$ ../configure --enable-languages=c --disable-multilib \
  --with-build-config=bootstrap-lto -C
$ make -jN
$ cd gcc
$ make clean
$ /bin/time make -j1
3860.82user 92.39system 1:06:12elapsed 99%CPU (0avgtext+0avgdata 952460maxresident)k
0inputs+2338008outputs (0major+53550802minor)pagefaults 0swaps

$ make clean
$ /usr/bin/time make -j1 \
  C{,XX}FLAGS='-g -gno-statement-frontiers -O2 -flto=jobserver -frandom-seed=1'
-> error, lto fails to drop inline entry stmts from libiberty.a; will fix, meanwhile:

$ cd ..
$ make stage1-start
$ rm -rf stage3-*
$ echo > ../config/bootstrap-noSFN3.mk 'STAGE3_CFLAGS += -gno-statement-frontiers'
$ make -jN BUILD_CONFIG='bootstrap-noSFN3 bootstrap-lto'
$ cd gcc
$ make clean
$ /bin/time make -j1
3587.09user 88.11system 1:01:46elapsed 99%CPU (0avgtext+0avgdata 948800maxresident)k
0inputs+1937200outputs (0major+46685269minor)pagefaults 0swaps
Richard Biener Aug. 28, 2017, 12:11 p.m. UTC | #8
On Fri, Aug 25, 2017 at 4:26 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:
>
>>>> if they are not a problem up until here why care now?
>
>>> IIRC we do have a limit for VTA notes too, but there's a C++ testcase
>>> (g++.dg/tree-ssa/pr14703.C) that expands and inlines fibonacci template
>>> functions so deep, more than doubling the number of statements at all
>>> but the base recursion levels, so we'd end up with over 2^{85+} debug
>>> stmts if we didn't cut them off somehow.
>
>> Yeah, but I meant we've kept them throughout GIMPLE (for all functions!)
>> but are dropping them here at RTL expansion (which we'll have only a
>> single live RTL function at a time).  That looks odd ;)
>
> Aah, yeah, the point is, if we find we exceeded the limit, we don't
> bother to clean up the gimple, we just refrain from wasting further time
> with it, which we would if we converted them to RTL (and then threw them
> away), or copied them all when inlining into some other function.  We
> could clean up at some point, just as we could stop emitting further
> markers once the limit is reached, but it didn't seem important enough
> to do so.  Should it prove to be, I guess it wouldn't be too hard to add
> it to gimple verification passes that walk over all stmts.
>
>> You're already dropping them at inlining as well so the RTL expansion
>> check should be superfluous IMHO (yeah, unrolling might push it over
>> the edge for example but all real issues should come from inlining).
>
> The RTL expansion check is indeed not essential, but if we're over the
> limit, we'll to throw it all away, so why bother expanding it and
> carrying it through all RTL passes just to throw away at the end?  Or
> should we not throw it away in this case, and make the limit apply only
> to inlining?  But then, what if we inline lots of very large functions
> into a single one, do we still want to use markers for that function?
> That's not how I designed it, but I guess it might work that way too.

Hmm, all existing markers should be valid, no?  So throwing them away
at RTL expansion time will only make the function "consistent" but drop
still useful stuff?

>
>> Hmm, yeah.  I guess we'd have to have a multi-DEBUG_STMT that covers
>> not only multiple markers but also multiple binds.  High GIMPLE has
>> nested stmts so it might be tempting to wrap adjacent debug-stmts into
>> a single one (basically make the IL walking overhead with debug stmts smaller).
>> Costs extra memory instead of less when compared to my idea of course.
>
> Yeah.  I guess that's doable and it won't make gimple passes much
> trickier: in most cases all that matters are the SSA uses in bind value
> expressions, so as long as the update function can efficiently pick the
> SSA uses from the op array, it could be a significant win.
>
> We may need some way to reset one specific bind given a use that is no
> longer valid, which I don't immediately see how to implement efficiently
> in a multi-debug pack .
>
> Now, I spent some time trying to think of how to pack multiple debug
> stmts in a way that made them also save memory.
>
> For each packed stmt, we need at least one bit to indicate whether it's
> a bind or just a marker.  Markers then need a locus, and another bit
> indicating whether it's a begin stmt marker or an inline entry point
> marker.  Debug bind stmts need one bit to indicate tell src binds from
> regular ones, and two trees (no locus).
>
> It is unlikely that it would make sense to allocate extra memory, be it
> trees holding integral values, be it other arrays to hold them.  I'm
> thinking we'd be better off storing some of these bits in an analogous
> of the trailing op VLA, that would be present in gdebug but that would
> deal with GGC and ssa updates in its own way.
>
> For packs with few stmts, we could use bits from the subcode to indicate
> the count and the kinds.  We could use the gimple locus for the first
> marker, and then perhaps pack pairs of loci in tree pointer operands (if
> their sizes are 1:2, as in lp64).
>
> When packing more than few stmts, we could then define a format for a
> 32-bit word to hold the bits for an additional set of stmts, possibly
> packed in the same word as a locus or another such bit pack.  Ideally,
> should we need more than one of these, we should indicate upfront how
> many of these there are, or at least how many ops are used.
>
> I was thinking it would be ideal if combining two many-stmts debug stmts
> could require little more than allocating a gimple with a larger ops
> array and copying (most of) the original op arrays to the right places.
>
> But...  this all feels far too hackish and not very maintainable or
> forward-looking.  E.g., if we add more kinds of debug stmts, the bit
> counting suddenly no longer applies, and needs to be reworked.
>
> So I guess that's also doable, and would save some memory indeed,
> but...  do you think it's worth it?

Given all the complication I wouldn't bother initially at least.  GIMPLE
memory use isn't so much an issue.  I suppose if we end up with
many adjacent debug insns doing the nesting sounds more appealing
to me given it might remove stmt walking overhead in passes.

>
>>>> 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?)
>>>
>>> I confess I hadn't considered any of that.  I'll give it some thought.
>>> Binds don't refer to a (program) location, yeah, whereas that's all the
>>> new markers do.  Inline markers actually reference the lexical block
>>> containing the entire inlined copy of the function, and there's code
>>> that depends on it, so we'd have to figure out some way to express that
>>> sort of thing, in case the GIMPLE FE can't.  Once we have that, the
>>> syntax for debug stmts is just a breeze.
>
>> Ah, lexical blocks.  Yeah, we'd have to add a syntactic way to
>> name them and refer to them.  At least BINDS look easily doable ;)
>> For blocks there's the additional issue that the GIMPLE FE doesn't
>> really have them as GIMPLE doesn't really care unless you start
>> introducing locations and debug info ;)  So with the GIMPLE FE
>> there's just the functions outermost scope/BLOCK.  It shouldn't be
>> too hard to add though if we think it's useful.
>
> I've given this some more thought too.  I'm a bit confused as to the
> role of debug info in this FE.  If it is to be regarded as a source
> language, then you'll want at least begin stmt and inline entry markers
> to be introduced in the normal way, namely, by the front end, while
> parsing statements, and by the inliner, when performing the inlining.
> This would address the problem of representation of lexical blocks, too.

Yeah.  But the FE was meant as a unit-test input framework which means
for FE diagnostics we indeed want GIMPLE input locations but for
the actual testcase not.  Weird :)

> It would not, however, deal with the more traditional debug stmts, the
> bind ones.  Those are introduced during gimplification, when going into
> SSA.  Presumably you don't go through that with GIMPLE FE input, and at
> most run some SSA verification and update pass.  If that is so, then it
> makes a lot of sense to have explicit debug bind stmts, even as a means
> of associating SSA names with variables (how do you do that otherwise?)

Yes, I think debug binds would be worthwhile to add given their presence
has in the past caused issues (when looking from a unit-testing perspective).

Richard.

> --
> 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
Alexandre Oliva Sept. 1, 2017, 1:07 a.m. UTC | #9
On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> Just separating the boilerplate changes out from the "meat" of the change
> into a separate patch for easier reviewing would be nice.

I've broken up the patch into a patchset with 10 patches.  I've already
posted the one that makes -g options negatable the other day; I'll post
the other 9 as a follow up to this message.
Alexandre Oliva Sept. 30, 2017, 9:04 a.m. UTC | #10
On Aug 31, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:
>> Just separating the boilerplate changes out from the "meat" of the change
>> into a separate patch for easier reviewing would be nice.

> I've broken up the patch into a patchset with 10 patches.  I've already
> posted the one that makes -g options negatable the other day;

That one was approved and checked in.

> I'll post the other 9 as a follow up to this message.

I've refreshed and retested the others.  There was a conflict in
find_bb_boundaries, and the changes for compare-debug made there seem to
have obviated what was in the patchset, so I dropped mine.

I'm posting the refreshed patchset as a followup to this message.

Regstrapped on x86_64-linux-gnu and i686-linux-gnu, tested with -O1 (*1),
-O2 and -O3 (*2), with and without -fcompare-debug (*3).  Ok to install?

(*1) -O1 required this initializer to silence a warning:

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d4d9490..38e87b7 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -6598,7 +6598,7 @@ ix86_option_override_internal (bool main_args_p,
     {
       char *p = ASTRDUP (opts->x_ix86_recip_name);
       char *q;
-      unsigned int mask, i;
+      unsigned int mask = 0, i;
       bool invert;
 
       while ((q = strtok (p, ",")) != NULL)


(*2) -O3 required this initializer to silence a warning:

diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index 22fdb88..4e87e42 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -4325,7 +4325,7 @@ allocno_reload_assign (ira_allocno_t a, HARD_REG_SET forbidden_regs)
   int hard_regno;
   enum reg_class aclass;
   int regno = ALLOCNO_REGNO (a);
-  HARD_REG_SET saved[2];
+  HARD_REG_SET saved[2] = {};
   int i, n;
 
   n = ALLOCNO_NUM_OBJECTS (a);


(*3) bootstrap-debug works, but bootstrap-debug-lean fails compare,
because stage2 gets '-fcompare-debug= ' in the producer string, whereas
stage3 gets '-fcompare-debug=-gtoggle -frandom-seed=0x... '.  it is the
compiler driver that supplies the same -frandom-seed for both
-fcompare-debug compilations that take place in stage3 under
bootstrap-debug-lean.  This used to work, but now that we add them to
the producer string, it fails.  I'm inclined to change
gen_producer_string to ignore -fcompare-debug and -frandom-seed, but
dropping the latter is probably not a good idea if it was explicitly
added by the user.  Perhaps we should only drop it from the producer if
it follows the -fcompare-debug option?  Or should we use the stripping
logic from contrib/compare-debug under bootstrap-debug-lean too?
Alexandre Oliva Nov. 10, 2017, 2:30 a.m. UTC | #11
On Sep 30, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Aug 31, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:
>> On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:
>>> Just separating the boilerplate changes out from the "meat" of the change
>>> into a separate patch for easier reviewing would be nice.

>> I've broken up the patch into a patchset with 10 patches.  I've already
>> posted the one that makes -g options negatable the other day;

> That one was approved and checked in.

>> I'll post the other 9 as a follow up to this message.

> I've refreshed and retested the others.  There was a conflict in
> find_bb_boundaries, and the changes for compare-debug made there seem to
> have obviated what was in the patchset, so I dropped mine.

As a followup to this message, I'll post an updated, fixed and refreshed
patchset.

The main changes to this patchset, aside from trivial conclift
resolution (e.g. SDB removal, various instances of code movement), are:

- the reversal of the final.c API changes that had required changes to
  many targets; they API changes are now kept internal to final.c

- the changes to gcc/cp/constprop.c requested by jason

- more comments before block_within_block_p and its caller, and an
  additional argument to decide whether to execute the test both ways

- new macros to create RTL patterns for markers, so that all of the
  decisions about their representation are at a single place

- stabilize find_bb_boundaries, fixes -fcompare-debug errors

Most of the patchset is already approved, part by richi, part by jeff.
The only points still requiring changes, AFAIK, are the ones mentioned
above.  So, I'd appreciate if richi, jeff and jason would let me know
whether these changes are enough to earn their approval.  Of course, if
anyone would like to raise any other issues and concerns, I'll do my
best to address them.

Nevertheless, for reference, I post the entire patchset.  The
incremental changes, aside from the trivial ones made in merges, can be
identified for inspection with git log trunk..aoliva/SFN (that's the
branch where I'm making incremental changes and merges, unlike
aoliva/SLI, where the patchset is being maintained with rebased
consolidated changes).  If there's interest in my posting the
incremental changes, I'd be glad to post them as well, just let me know.



There are a couple of compare-debug errors I'm aware of, but that are
preexisting problems unrelated with this patchset, so I'm not delaying
the posting of the patchset further so as to include fixes for those.
(they come up in unusual testing scenarios; I've already posted on Oct 5
to gcc-patches about adding different compiler flags to debug info in
different stages; the other shows up in a -fcompare-debug run of the
libstdc++-v3 testsuite, and it's an artifact of dumping rtl for
-fcompare-debug rather than an actual codegen difference)
Alexandre Oliva Nov. 10, 2017, 8:41 p.m. UTC | #12
On Nov 10, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> Most of the patchset is already approved, part by richi, part by jeff.
> The only points still requiring changes, AFAIK, are the ones mentioned
> above.

Actually, I've just noticed that there's one big patch in the set that's
still missing review and approval, namely:
7/9 [LVU] Introduce location views
diff mbox

Patch

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,