public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Introduce Statement Frontier Notes and Location Views
@ 2017-07-05 23:21 Alexandre Oliva
  2017-07-13 13:17 ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-07-05 23:21 UTC (permalink / raw)
  To: gcc-patches

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.

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.


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.

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 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): 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 markers.
	(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): Don't dereference NULL
	INSN_VAR_LOCATION_DECL.
	* common.opt (gstatement-frontiers): New.
	(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 begin stmt markers and debug bindings
	followed by them.
	* 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.
	(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_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.
	(convert_cfa_to_fb_loc_list): Adjust.
	(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 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.
	(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.
	(hash_loc_list): Hash view numbers.
	(loc_list_hasher::equal): Compare them.
	(index_location_lists): Call skip_loc_list_entry for test.
	(dwarf2out_finish): Call output_asm_line_debug_info for test.
	* 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.
	(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 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 begin stmt markers.
	(rest_of_handle_final): Convert begin stmt markers to notes if
	var-tracking didn't run.  Adjust.
	(rest_of_clean_state): Skip begin stmt markers.
	* function.c (allocate_struct_function): Set begin_stmt_markers.
	* function.h (struct function): Add debug_marker_count counter
	and begin_stmt_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 begin_stmt_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: Handle begin stmt markers.
	* gimple.c (gimple_build_debug_begin_stmt_stat): New.
	(gimple_copy): Increment debug_marker_count if copying one.
	* gimple.h (enum gimple_debug_subcode): Add GIMPLE_DEBUG_BEGIN_STMT.
	(gimple_build_debug_begin_stmt_stat): Declare.
	(gimple_build_debug_begin_stmt): Define.
	(gimple_seq_last_nondebug_stmt): New.
	(gimple_debug_begin_stmt_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 begin stmt 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): New.
	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
	* 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): Don't dereference NULL
	INSN_VAR_LOCATION_DECL.
	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
	debug insns.
	(update_ebb_live_info): Skip debug insn markers.
	* lra.c (lra_update_isn_regno_info): Don't assume debug insns have
	freqs.
	(push_insns): Skip debug insns.
	* lto-streamer-in.c (input_function): Adjust begin_stmt_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.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	begin stmt marker notes.
	(rtx_writer::print_rtx): Handle begin stmt marker insns.
	(print_insn): Likewise.
	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
	* rtl.h (MAY_HAVE_DEBUG_INSNS): Check debug_statement_frontiers.
	(NOTE_BEGIN_STMT_LOCATION): 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 begin stmt markers.
	(maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.
	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
	markers regardless of no side effects.
	(tsi_link_before): Don't update container's side effects when adding
	a begin stmt marker.
	(tsi_link_after): Likewise.
	(expr_first): Skip begin stmt markers.
	(expr_last): Likewise.
	* tree-pretty-print (dump_generic_node): 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-tail-merge.c (find_duplicate): Skip debug stmts.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info): Handle
	begin stmt 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_statement_frontiers.
	(GOTO_DESTINATION): Require a GOTO_EXPR.
	* var-tracking.c (get_first_insn): New.
	(vt_emit_notes): Call it.
	(VTA_DEBUG_INSN_P): New.
	(MARKER_DEBUG_INSN_P): New.
	(INSN_DEBUG_MARKER_KIND): New.
	(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                    |  134 +++++---
 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                          |    8 
 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                    |  603 ++++++++++++++++++++++++++++++++----
 gcc/dwarf2out.h                    |    4 
 gcc/emit-rtl.c                     |   69 ++--
 gcc/final.c                        |  173 +++++++++-
 gcc/function.c                     |    6 
 gcc/function.h                     |   10 +
 gcc/gimple-iterator.c              |   26 +-
 gcc/gimple-iterator.h              |   46 ++-
 gcc/gimple-low.c                   |   28 ++
 gcc/gimple-pretty-print.c          |    7 
 gcc/gimple.c                       |   24 +
 gcc/gimple.h                       |   39 ++
 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                 |    3 
 gcc/ipa-icf-gimple.c               |    4 
 gcc/jump.c                         |    2 
 gcc/langhooks-def.h                |    2 
 gcc/langhooks.h                    |    3 
 gcc/loop-unroll.c                  |    2 
 gcc/lra-constraints.c              |   10 +
 gcc/lra.c                          |    4 
 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/print-rtl.c                    |   20 +
 gcc/regcprop.c                     |    2 
 gcc/rtl.h                          |    8 
 gcc/toplev.c                       |   12 +
 gcc/tree-cfg.c                     |   52 +++
 gcc/tree-cfgcleanup.c              |   31 +-
 gcc/tree-inline.c                  |   36 ++
 gcc/tree-iterator.c                |   48 ++-
 gcc/tree-pretty-print.c            |    9 -
 gcc/tree-ssa-dce.c                 |    6 
 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/var-tracking.c                 |  141 ++++++++
 include/dwarf2.def                 |    1 
 include/dwarf2.h                   |    8 
 91 files changed, 1970 insertions(+), 438 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 f8fbc92..b0332ea 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1476,6 +1476,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_statement_frontiers)
+    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
@@ -1576,6 +1589,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))
     {
@@ -4777,6 +4792,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;
     }
@@ -5231,6 +5247,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 4d067e9..d2bd65c 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10573,6 +10573,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;
     }
@@ -10592,7 +10596,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 56a2cb9..69dcb24 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 3b5f2fe..47a796b 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2312,6 +2312,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;
@@ -5428,7 +5431,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;
@@ -5469,18 +5472,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)
@@ -5497,6 +5508,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);
@@ -5504,7 +5516,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))
     {
@@ -5512,6 +5525,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
@@ -5617,37 +5633,81 @@ 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 var;
 	      tree value;
 	      rtx val;
 	      machine_mode mode;
 
-	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
-		  && TREE_CODE (var) != LABEL_DECL
-		  && !target_for_debug_bind (var))
-		goto delink_debug_stmt;
+	      if (gimple_debug_bind_p (stmt))
+		{
+		  var = gimple_debug_bind_get_var (stmt);
 
-	      if (gimple_debug_bind_has_value_p (stmt))
-		value = gimple_debug_bind_get_value (stmt);
+		  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
+		    value = NULL_TREE;
+		}
+	      else if (gimple_debug_begin_stmt_p (stmt)
+		       && !cfun->begin_stmt_markers)
+		goto delink_debug_stmt;
 	      else
-		value = NULL_TREE;
+		{
+		  gcc_assert (gimple_debug_begin_stmt_p (stmt));
+		  var = value = NULL_TREE;
+		  mode = VOIDmode;
+		}
 
 	      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);
 
@@ -5675,42 +5735,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_begin_stmt_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);
@@ -6349,6 +6380,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->begin_stmt_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 c78cb8e..cfe3d3e 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.
@@ -2272,11 +2272,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;
@@ -2893,7 +2893,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);
@@ -2915,7 +2915,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;
@@ -2942,6 +2942,7 @@ rtl_verify_bb_layout (void)
 	    {
 	    case BARRIER:
 	    case NOTE:
+	    case DEBUG_INSN:
 	      break;
 
 	    case CODE_LABEL:
@@ -2960,7 +2961,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))
@@ -3381,6 +3383,9 @@ skip_insns_after_block (basic_block bb)
 	  last_insn = insn;
 	  continue;
 
+	case DEBUG_INSN:
+	  continue;
+
 	case NOTE:
 	  switch (NOTE_KIND (insn))
 	    {
@@ -4133,7 +4138,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 (INSN_VAR_LOCATION_DECL (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 e81165c..2ccdbb32 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2870,6 +2870,14 @@ gstabs+
 Common Driver JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format.
 
+gno-statement-frontiers
+Common Driver RejectNegative Var(debug_statement_frontiers, 0) Init(2)
+Don't enforce progressive recommended breakpoint locations.
+
+gstatement-frontiers
+Common Driver RejectNegative Var(debug_statement_frontiers, 1)
+Emit progressive recommended breakpoint locations.
+
 gno-strict-dwarf
 Common Driver RejectNegative Var(dwarf_strict,0) Init(0)
 Emit DWARF additions beyond selected version.
@@ -2882,6 +2890,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 bf2aa7b..48628fdd 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -352,6 +352,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 037339d..a1835f7 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -3958,7 +3958,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 00a69c1..125f3bc 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -8459,7 +8459,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 d3a40b9..a809a7c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -26336,7 +26336,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)
     {
@@ -26513,7 +26514,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 8c134a6..8513db7 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -2742,7 +2742,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 2c4479e..2972e38 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -12399,8 +12399,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).  */
@@ -42532,7 +42533,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 617d188..6e334d7 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -10942,7 +10942,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 c14ce86..7f7a173 100644
--- a/gcc/config/m68k/m68k.c
+++ b/gcc/config/m68k/m68k.c
@@ -5129,7 +5129,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 d0f86fd..73a0bdf 100644
--- a/gcc/config/microblaze/microblaze.c
+++ b/gcc/config/microblaze/microblaze.c
@@ -3231,7 +3231,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 6bfd86a..8cc6eec 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -19352,7 +19352,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 705d223..ce9d5bf 100644
--- a/gcc/config/nds32/nds32.c
+++ b/gcc/config/nds32/nds32.c
@@ -1633,7 +1633,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 2fc9a08..4c58e99 100644
--- a/gcc/config/nios2/nios2.c
+++ b/gcc/config/nios2/nios2.c
@@ -4058,7 +4058,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 2a78018..e289528 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -8378,7 +8378,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 fde1673..b72e6f3 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -29485,7 +29485,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 ();
 
@@ -37976,7 +37976,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 958ee3b..5601661 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -12825,7 +12825,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 ff79b93..6340158 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -10882,7 +10882,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 790a0367..c30e4eb 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -11694,7 +11694,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 fcb85c0..322dbb6 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -7019,7 +7019,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 e070e7e..89f9714 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 81019c1..6529799 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 317517c..6810ee1 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27680,6 +27680,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 e1b03a9..21588fd 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4825,9 +4825,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 32180a7..caa67db 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 36d6624..d9da37e 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 dbe0052..d9b6136 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10618,6 +10618,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_statement_frontiers)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a statement.
 
    statement:
@@ -10693,6 +10706,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 bd02951..9ad393a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15106,6 +15106,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case BINARY_RIGHT_FOLD_EXPR:
       return tsubst_binary_right_fold (t, args, complain, in_decl);
 
+    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..a64da2f 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -6953,11 +6953,19 @@ insn_live_p (rtx_insn *insn, int *counts)
     {
       rtx_insn *next;
 
+      /* This is a debug begin stmt.  */
+      if (!INSN_VAR_LOCATION_DECL (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 (!INSN_VAR_LOCATION_DECL (next))
+	  return true;
 	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
 	  return false;
 
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 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 8585216..1930d4c 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 3e5cee8..0bc892f 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
@@ -6987,6 +6989,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.
@@ -10406,6 +10437,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 b02e5a1..e32896c 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 3f42040..35a8f11 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -766,6 +766,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 c277d27..bdabea7 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"
@@ -1272,6 +1273,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.  */
@@ -1281,9 +1284,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.  */
@@ -1320,6 +1325,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.  */
@@ -1395,6 +1425,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:
@@ -2832,7 +2864,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 {
@@ -2854,6 +2894,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;
 };
 
@@ -3052,6 +3111,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
@@ -3161,6 +3255,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.  */
@@ -3369,6 +3464,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);
@@ -3405,7 +3502,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);
@@ -3613,8 +3710,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);
@@ -4536,11 +4633,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>
@@ -5612,7 +5753,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;
@@ -5703,7 +5844,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.  */
@@ -5719,7 +5860,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
 	    {
@@ -5854,6 +5995,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;
@@ -8953,6 +9100,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);
@@ -9324,6 +9472,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)
@@ -9619,7 +9768,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> ();
@@ -9629,10 +9779,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.  */
 
@@ -9641,6 +9809,94 @@ 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 (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");
+    }
+#endif
+
+  return;
 }
 
 /* Output the location list given to us.  */
@@ -9648,34 +9904,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,
@@ -9693,6 +10000,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
@@ -9743,6 +10051,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);
@@ -9757,6 +10066,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);
@@ -9772,6 +10082,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);
@@ -9850,6 +10161,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
@@ -9914,6 +10228,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
@@ -10144,6 +10474,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))
 	    {
@@ -11797,8 +12131,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)
     {
@@ -11813,14 +12150,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)
 	    {
@@ -16212,6 +16571,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;
@@ -16267,24 +16627,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)
@@ -16307,12 +16670,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;
 	      }
 	  }
@@ -16324,8 +16687,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;
 }
@@ -17145,7 +17507,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;
     }
@@ -17958,7 +18320,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;
 }
@@ -18287,7 +18649,13 @@ add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
   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);
+    }
 }
 
 /* Add DW_AT_accessibility attribute to DIE if needed.  */
@@ -19457,7 +19825,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;
     }
@@ -19473,7 +19841,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;
@@ -19495,14 +19863,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;
 	}
@@ -19511,19 +19879,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;
 }
@@ -25946,7 +26313,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,
@@ -26106,6 +26473,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.  */
@@ -26123,11 +26506,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++;
@@ -26154,13 +26539,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;
     }
 
@@ -26184,11 +26581,12 @@ 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_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)
     {
@@ -26223,10 +26621,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;
     }
@@ -26267,8 +26666,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
@@ -26336,7 +26735,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)
@@ -26345,6 +26747,23 @@ 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;
@@ -26395,6 +26814,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;
 }
@@ -26443,7 +26863,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);
@@ -26624,7 +27044,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",
@@ -26650,6 +27070,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
@@ -26658,7 +27105,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)
@@ -27240,7 +27699,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);
 
@@ -27625,6 +28084,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.
@@ -28724,6 +29188,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)
@@ -28768,7 +29234,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)
@@ -28838,6 +29304,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);
@@ -28863,6 +29330,17 @@ 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 ());
+	  if (!view_list_to_loc_list_val_node (&a->dw_attr_val))
+	    {
+	      remove_AT (die, a->dw_attr);
+	      ix--;
+	    }
+	  break;
+	}
       case dw_val_class_loc:
 	{
 	  dw_loc_descr_ref l = AT_loc (a);
@@ -29259,6 +29737,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);
@@ -29480,6 +29960,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;
@@ -29537,7 +30018,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
@@ -29972,7 +30453,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 041f2a7..13424c5 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 356c923..b9a99c8 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -79,6 +79,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.  */
@@ -110,6 +111,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;
@@ -1745,6 +1747,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
@@ -1752,13 +1792,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;
@@ -1776,7 +1821,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);
@@ -1851,6 +1917,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)
 {
@@ -1982,11 +2059,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;
@@ -2053,6 +2129,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);
@@ -2069,6 +2147,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);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2208,6 +2294,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 ())
@@ -2348,6 +2436,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
@@ -2405,7 +2495,22 @@ 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->begin_stmt_markers);
+	  if (!DECL_IGNORED_P (current_function_decl)
+	      && notice_source_line (insn, NULL))
+	    {
+	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
+					   last_filename, last_discriminator,
+					   true);
+	      clear_next_view_needed (seen);
+	    }
 	  break;
 
 	default:
@@ -2495,7 +2600,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->begin_stmt_markers)
+	  {
+	    is_stmt = false;
+	    is_stmt_p = NULL;
+	  }
+	else
+	  is_stmt_p = &is_stmt;
 
 	/* Reset this early so it is correct for ASM statements.  */
 	current_insn_predicate = NULL_RTX;
@@ -2593,19 +2706,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)
@@ -3072,7 +3194,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;
@@ -3091,7 +3214,16 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   const char *filename;
   int linenum, columnnum;
 
-  if (override_filename)
+  if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_BEGIN_STMT)
+    {
+      expanded_location xloc
+	= expand_location (NOTE_BEGIN_STMT_LOCATION (insn));
+      filename = xloc.file;
+      linenum = xloc.line;
+      columnnum = xloc.column;
+      force_source_line = true;
+    }
+  else if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
@@ -3124,7 +3256,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;
@@ -3136,7 +3269,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;
     }
 
@@ -4489,9 +4623,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)
     collect_fn_hard_reg_usage ();
   final_end_function ();
@@ -4675,6 +4815,7 @@ rest_of_clean_state (void)
       if (final_output
 	  && (!NOTE_P (insn) ||
 	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
 	       && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
diff --git a/gcc/function.c b/gcc/function.c
index f625489..512c674a 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4947,6 +4947,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->begin_stmt_markers = lang_hooks.emits_begin_stmt
+    && debug_statement_frontiers && 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..c4cebc8a 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 markers enabled.  */
+  unsigned int begin_stmt_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..435148c 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_begin_stmt_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..0e3899c 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->begin_stmt_markers)
+    {
+      /* This counter needs not be exact, but before lowering it will
+	 most certainly be.  */
+      gcc_assert (cfun->debug_marker_count == 0);
+      cfun->begin_stmt_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->begin_stmt_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 4012b3b..6e0e6e6 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1371,6 +1371,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 			 gimple_debug_source_bind_get_value (gs));
       break;
 
+    case GIMPLE_DEBUG_BEGIN_STMT:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+      break;
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 488f8c8..bfb6417 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -834,6 +834,27 @@ gimple_build_debug_source_bind_stat (tree var, tree value,
 }
 
 
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+   LOCATION.  */
+
+gdebug *
+gimple_build_debug_begin_stmt_stat (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_block (p, block);
+  gimple_set_location (p, location);
+  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.
@@ -1872,6 +1893,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 575babe..cb49983 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -198,13 +198,12 @@ 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
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -1460,6 +1459,9 @@ gdebug *gimple_build_debug_bind_stat (tree, tree, gimple * MEM_STAT_DECL);
 gdebug *gimple_build_debug_source_bind_stat (tree, tree, gimple * MEM_STAT_DECL);
 #define gimple_build_debug_source_bind(var,val,stmt)			\
   gimple_build_debug_source_bind_stat ((var), (val), (stmt) MEM_STAT_INFO)
+gdebug *gimple_build_debug_begin_stmt_stat (tree, location_t MEM_STAT_DECL);
+#define gimple_build_debug_begin_stmt(block,loc)			\
+  gimple_build_debug_begin_stmt_stat ((block), (loc) 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);
@@ -4564,6 +4566,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
@@ -4720,6 +4738,17 @@ 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 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 641a821..ff08565 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -985,6 +985,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;
+}
+
 \f
 /* 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
@@ -1775,6 +1817,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))
 	{
@@ -1858,7 +1907,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)
@@ -1871,27 +1920,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;
     }
@@ -1995,7 +2047,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);
     }
@@ -2032,7 +2084,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;
     }
@@ -2043,7 +2095,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
 
   /* Skip all immediately following labels.  */
   while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
-    gsi_next (&gsi);
+    gsi_next_nondebug (&gsi);
 
   /* { ... something; default:; } */
   if (gsi_end_p (gsi)
@@ -2090,7 +2142,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))
@@ -2231,7 +2283,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);
@@ -3438,7 +3490,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the && on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = 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);
@@ -3461,7 +3513,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the || on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = 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);
@@ -3483,7 +3535,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
 
       /* Keep the original source location on the first 'if'.  Set the source
 	 location of the ? on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = 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),
@@ -3507,6 +3559,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
   return expr;
 }
 
+/* If EXPR is a GOTO_EXPR, return it.  If it is a STATEMENT_LIST, skip
+   any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent
+   statement, if it is the last one.  Otherwise, return NULL.  */
+
+static tree
+find_goto (tree expr)
+{
+  if (!expr)
+    return NULL_TREE;
+
+  if (TREE_CODE (expr) == GOTO_EXPR)
+    return expr;
+
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    return NULL_TREE;
+
+  tree_stmt_iterator i = tsi_start (expr);
+
+  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+    tsi_next (&i);
+
+  if (!tsi_one_before_end_p (i))
+    return NULL_TREE;
+
+  return find_goto (tsi_stmt (i));
+}
+
+/* Same as find_goto, except that it returns NULL if the destination
+   is not a LABEL_DECL.  */
+
+static inline tree
+find_goto_label (tree expr)
+{
+  tree dest = find_goto (expr);
+  if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)
+    return dest;
+  return NULL_TREE;
+}
+
 /* Given a conditional expression EXPR with short-circuit boolean
    predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the
    predicate apart into the equivalent sequence of conditionals.  */
@@ -3537,8 +3628,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the && on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (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);
@@ -3559,8 +3650,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the || on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (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);
@@ -3587,20 +3678,16 @@ shortcut_cond_expr (tree expr)
   /* If our arms just jump somewhere, hijack those labels so we don't
      generate jumps to jumps.  */
 
-  if (then_
-      && TREE_CODE (then_) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
+  if (tree then_goto = find_goto_label (then_))
     {
-      true_label = GOTO_DESTINATION (then_);
+      true_label = GOTO_DESTINATION (then_goto);
       then_ = NULL;
       then_se = false;
     }
 
-  if (else_
-      && TREE_CODE (else_) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
+  if (tree else_goto = find_goto_label (else_))
     {
-      false_label = GOTO_DESTINATION (else_);
+      false_label = GOTO_DESTINATION (else_goto);
       else_ = NULL;
       else_se = false;
     }
@@ -3664,8 +3751,8 @@ shortcut_cond_expr (tree expr)
 	{
 	  tree last = expr_last (expr);
 	  t = build_and_jump (&end_label);
-	  if (EXPR_HAS_LOCATION (last))
-	    SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
+	  if (expr_has_location (last))
+	    SET_EXPR_LOCATION (t, expr_location (last));
 	  append_to_statement_list (t, &expr);
 	}
       if (emit_false)
@@ -3958,39 +4045,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   gimple_push_condition ();
 
   have_then_clause_p = have_else_clause_p = false;
-  if (TREE_OPERAND (expr, 1) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
-	  == current_function_decl)
+  label_true = find_goto_label (TREE_OPERAND (expr, 1));
+  if (label_true
+      && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
+	  || !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);
@@ -11775,6 +11858,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..d985018 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_begin_stmt_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..960487b 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
 /* The values passed to callee.  */
 INSN_NOTE (CALL_ARG_LOCATION)
 
+/* The beginning of a statement.  */
+INSN_NOTE (BEGIN_STMT)
+
 /* 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 08dd980..cc393c8 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -629,8 +629,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/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 b2f0f92..1c68936 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 5e2e77a..56b4859 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -2025,11 +2025,13 @@ apply_opt_in_copies (struct opt_info *opt_info,
         {
 	  if (!INSN_P (insn)
 	      || (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)
+		     && 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 2bb6826..9176a42 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 (!INSN_VAR_LOCATION_DECL (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..9a50754 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1602,7 +1602,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 +1812,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 ec47fe4..a976c7b 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1169,6 +1169,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->begin_stmt_markers
+		  && gimple_debug_begin_stmt_p (stmt))
+		cfun->begin_stmt_markers = true;
 	    }
 	}
     }
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 929c530..7f79460 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -658,7 +658,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;
@@ -709,7 +709,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;
@@ -835,7 +835,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;
@@ -912,15 +912,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);
@@ -1147,7 +1147,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);
@@ -1260,7 +1260,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));
@@ -1276,7 +1276,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);
@@ -1285,7 +1285,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)));
@@ -1747,7 +1747,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))
@@ -2552,7 +2552,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
@@ -2582,7 +2582,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));
@@ -2603,7 +2603,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));
@@ -3021,7 +3021,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);
@@ -3087,7 +3087,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)))
@@ -3307,7 +3307,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)
@@ -3439,7 +3439,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)),
@@ -3449,7 +3449,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);
@@ -3591,7 +3591,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);
@@ -3624,7 +3624,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));
@@ -3791,7 +3791,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)
@@ -4097,7 +4097,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);
@@ -4141,7 +4141,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));
@@ -4348,7 +4348,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.
@@ -4393,7 +4393,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,
@@ -4423,7 +4423,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.  */
@@ -4597,7 +4597,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.  */
@@ -4692,7 +4692,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);
 
@@ -4786,7 +4786,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.  */
@@ -4913,7 +4913,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)
@@ -5014,10 +5014,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 ();
@@ -5091,7 +5091,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)
@@ -5170,7 +5170,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);
@@ -5207,7 +5207,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 ();
@@ -5388,7 +5388,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);
 
@@ -5515,7 +5515,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);
@@ -5639,7 +5639,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);
 
@@ -5719,7 +5719,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));
 
@@ -5946,7 +5946,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)
@@ -5954,7 +5954,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)
 	      {
@@ -5979,7 +5979,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);
@@ -6003,7 +6003,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)
     {
@@ -6045,7 +6045,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);
@@ -6054,7 +6054,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);
 
@@ -6080,7 +6080,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);
@@ -6093,7 +6093,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)))
@@ -6121,12 +6121,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));
@@ -6149,7 +6149,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
@@ -6161,7 +6161,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;
@@ -6182,7 +6182,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);
@@ -6212,7 +6212,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);
 
@@ -6238,14 +6238,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);
@@ -6290,7 +6290,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))
@@ -6337,10 +6337,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));
@@ -6404,7 +6411,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.
@@ -6427,10 +6434,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);
 
@@ -6483,7 +6490,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
@@ -6563,7 +6570,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)
@@ -6666,7 +6673,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);
@@ -6677,7 +6684,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)),
@@ -7175,7 +7182,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));
@@ -7187,7 +7194,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);
@@ -7369,7 +7376,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));
 	}
@@ -7404,11 +7411,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);
     }
@@ -7552,7 +7559,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);
@@ -7633,17 +7640,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)
@@ -7787,11 +7794,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);
@@ -7975,7 +7982,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 dd4a092..f95fd7e 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -7015,6 +7015,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 7460c2b..667dcab 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2293,7 +2293,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 6b07518..44dccd5 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/print-rtl.c b/gcc/print-rtl.c
index dc8d980..88c19fb 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  fputc ('\t', m_outfile);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+	  {
+	    expanded_location xloc
+	      = expand_location (NOTE_BEGIN_STMT_LOCATION (in_rtx));
+	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+	  }
+#endif
+	  break;
+
 	default:
 	  break;
 	}
@@ -806,7 +816,9 @@ rtx_writer::print_rtx (const_rtx in_rtx)
 #ifndef GENERATOR_FILE
       if (GET_CODE (in_rtx) == VAR_LOCATION)
 	{
-	  if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
+	  if (!PAT_VAR_LOCATION_DECL (in_rtx))
+	    fputs (" <begin stmt marker>", m_outfile);
+	  else if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
 	    fputs (" <debug string placeholder>", m_outfile);
 	  else
 	    print_mem_expr (m_outfile, PAT_VAR_LOCATION_DECL (in_rtx));
@@ -1791,6 +1803,12 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 
     case DEBUG_INSN:
       {
+	if (!INSN_VAR_LOCATION_DECL (x))
+	  {
+	    pp_string (pp, "debug begin stmt marker");
+	    break;
+	  }
+
 	const char *name = "?";
 
 	if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 367d85a..361ad3e 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) (...))
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 59da995..873d729 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_statement_frontiers)
 
 /* 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_BEGIN_STMT_LOCATION(INSN) XCINT (INSN, 3, NOTE)
 #define NOTE_CFI(INSN)		XCCFI (INSN, 3, NOTE)
 #define NOTE_LABEL_NUMBER(INSN)	XCINT (INSN, 3, NOTE)
 
@@ -2900,13 +2902,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/toplev.c b/gcc/toplev.c
index e6c69a4..f1da67f 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1520,6 +1520,18 @@ process_options (void)
     warning_at (UNKNOWN_LOCATION, 0,
 		"var-tracking-assignments changes selective scheduling");
 
+  if (debug_statement_frontiers == AUTODETECT_VALUE)
+    debug_statement_frontiers = 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 2483731..02c4226 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));
 
@@ -1822,6 +1844,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;
@@ -2624,6 +2648,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.  */
@@ -5355,6 +5386,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);
@@ -5424,7 +5459,7 @@ gimple_verify_flow_info (void)
 	    }
 	}
 
-      gsi = gsi_last_bb (bb);
+      gsi = gsi_last_nondebug_bb (bb);
       if (gsi_end_p (gsi))
 	continue;
 
@@ -5679,8 +5714,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;
@@ -5691,6 +5728,7 @@ gimple_block_label (basic_block bb)
 	    gsi_move_before (&i, &s);
 	  return label;
 	}
+      first = false;
     }
 
   label = create_artificial_label (UNKNOWN_LOCATION);
@@ -5766,7 +5804,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 d4e4ef1..814f756 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"
@@ -1346,7 +1347,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_begin_stmt_p (stmt)
+	  ? !cfun->begin_stmt_markers
+	  : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return stmts;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
@@ -1629,6 +1632,22 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
 	  gimple_seq_add_stmt (&stmts, copy);
 	  return stmts;
 	}
+      if (gimple_debug_begin_stmt_p (stmt))
+	{
+	  /* If the inlined function is 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
+	    = gimple_build_debug_begin_stmt (gimple_block (stmt),
+					     gimple_location (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);
@@ -1724,7 +1743,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_begin_stmt_p (copy))
     {
       gimple_seq_add_stmt (&stmts, copy);
       return stmts;
@@ -2598,6 +2618,11 @@ 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_begin_stmt_p (stmt))
+	    {
+	      new_stmt = gimple_build_debug_begin_stmt (gimple_block (stmt),
+							gimple_location (stmt));
+	    }
 	  else
 	    gcc_unreachable ();
 	  gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2914,6 +2939,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
       gimple_set_block (stmt, n ? *n : id->block);
     }
 
+  if (gimple_debug_begin_stmt_p (stmt))
+    return;
+
   /* Remap all the operands in COPY.  */
   memset (&wi, 0, sizeof (wi));
   wi.info = id;
@@ -2922,8 +2950,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
 
   if (gimple_debug_source_bind_p (stmt))
     t = gimple_debug_source_bind_get_var (stmt);
-  else
+  else if (gimple_debug_bind_p (stmt))
     t = gimple_debug_bind_get_var (stmt);
+  else
+    gcc_unreachable ();
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = id->debug_map->get (t)))
diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
index c485413..10e510d 100644
--- a/gcc/tree-iterator.c
+++ b/gcc/tree-iterator.c
@@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)
 void
 append_to_statement_list (tree t, tree *list_p)
 {
-  if (t && TREE_SIDE_EFFECTS (t))
+  if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
     append_to_statement_list_1 (t, list_p);
 }
 
@@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
       tail = head;
     }
 
-  TREE_SIDE_EFFECTS (i->container) = 1;
+  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+    TREE_SIDE_EFFECTS (i->container) = 1;
 
   cur = i->ptr;
 
@@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
       tail = head;
     }
 
-  TREE_SIDE_EFFECTS (i->container) = 1;
+  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+    TREE_SIDE_EFFECTS (i->container) = 1;
 
   cur = i->ptr;
 
@@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)
   i->ptr = next;
 }
 
-/* Return the first expression in a sequence of COMPOUND_EXPRs,
-   or in a STATEMENT_LIST.  */
+/* Return the first expression in a sequence of COMPOUND_EXPRs, or in
+   a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+   STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT.  */
 
 tree
 expr_first (tree expr)
@@ -291,7 +294,20 @@ expr_first (tree expr)
   if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
-      return n ? n->stmt : NULL_TREE;
+      if (!n)
+	return NULL_TREE;
+      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+	{
+	  n = n->next;
+	  if (!n)
+	    return NULL_TREE;
+	}
+      /* If the first non-debug stmt is not a statement list, we
+	 already know it's what we're looking for.  */
+      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+	return n->stmt;
+
+      return expr_first (n->stmt);
     }
 
   while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -300,8 +316,9 @@ expr_first (tree expr)
   return expr;
 }
 
-/* Return the last expression in a sequence of COMPOUND_EXPRs,
-   or in a STATEMENT_LIST.  */
+/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
+   STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+   STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT.  */
 
 tree
 expr_last (tree expr)
@@ -312,7 +329,20 @@ expr_last (tree expr)
   if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
-      return n ? n->stmt : NULL_TREE;
+      if (!n)
+	return NULL_TREE;
+      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+	{
+	  n = n->prev;
+	  if (!n)
+	    return NULL_TREE;
+	}
+      /* If the last non-debug stmt is not a statement list, we
+	 already know it's what we're looking for.  */
+      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+	return n->stmt;
+
+      return expr_last (n->stmt);
     }
 
   while (TREE_CODE (expr) == COMPOUND_EXPR)
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index b70e3257..67df721 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3303,6 +3303,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;
     }
@@ -3398,7 +3402,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..6206cd6 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_begin_stmt_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-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index b11911b..59c4b6c 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1294,14 +1294,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..94c6432 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_begin_stmt_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_begin_stmt_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 ca28afa..7ae7b98 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1011,7 +1011,8 @@ make_node_stat (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:
@@ -4403,7 +4404,10 @@ build1_stat (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 0ec8059..63e7b6f 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -384,6 +384,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 91cf253..36616e5 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1130,7 +1130,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_statement_frontiers)
 
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
@@ -1222,7 +1223,7 @@ extern void protected_set_expr_location (tree, location_t);
 
 /* GOTO_EXPR accessor. This gives access to the label associated with
    a goto statement.  */
-#define GOTO_DESTINATION(NODE)  TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE)  TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
 
 /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
    instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 5c38c1d..9a9f8da 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,51 @@ vt_init_cfa_base (void)
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
 }
 
+/* Evaluate to TRUE if INSN is a debug insn that denotes a variable
+   location/value tracking annotation.  */
+#define VTA_DEBUG_INSN_P(INSN)			\
+  (DEBUG_INSN_P (INSN)				\
+   && INSN_VAR_LOCATION_DECL (insn))
+/* 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)				\
+   && !INSN_VAR_LOCATION_DECL (insn))
+/* Evaluate to the marker kind.  Currently the only kind is
+   BEGIN_STMT.  */
+#define INSN_DEBUG_MARKER_KIND(insn) 0
+
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn)
+{
+  gcc_checking_assert (MARKER_DEBUG_INSN_P (insn));
+  /* FIXME: we could use loc and status for other kinds of markers, or
+     for additional information in them.  */
+  gcc_checking_assert (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)));
+  gcc_checking_assert (INSN_VAR_LOCATION_STATUS (insn)
+		       == VAR_INIT_STATUS_INITIALIZED);
+
+  switch (INSN_DEBUG_MARKER_KIND (insn))
+    {
+    case 0:
+      {
+	rtx_insn *note = NULL;
+	if (cfun->begin_stmt_markers)
+	  {
+	    note = emit_note_before (NOTE_INSN_BEGIN_STMT, insn);
+	    NOTE_BEGIN_STMT_LOCATION (note) = INSN_LOCATION (insn);
+	  }
+	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 +10161,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 (VTA_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 +10210,14 @@ vt_initialize (void)
 		  adjust_insn (bb, insn);
 		  if (MAY_HAVE_DEBUG_INSNS)
 		    {
+		      if (MARKER_DEBUG_INSN_P (insn))
+			{
+			  insn = reemit_marker_as_note (insn);
+			  if (insn)
+			    BLOCK_FOR_INSN (insn) = save_bb;
+			  continue;
+			}
+
 		      if (CALL_P (insn))
 			prepare_call_arguments (bb, insn);
 		      cselib_process_insn (insn);
@@ -10169,6 +10264,7 @@ vt_initialize (void)
 			    }
 			}
 		    }
+		  BLOCK_FOR_INSN (insn) = save_bb;
 		}
 	    }
 	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
@@ -10196,10 +10292,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 +10306,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);
+		continue;
+	      }
+
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
 	    if (TREE_CODE (decl) == LABEL_DECL
 		&& DECL_NAME (decl)
@@ -10237,10 +10343,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->begin_stmt_markers = 0;
+  delete_vta_debug_insns ();
 }
 
 /* Free the data structures needed for variable tracking.  */
@@ -10305,15 +10414,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 +10450,9 @@ variable_tracking_main_1 (void)
     {
       vt_finalize ();
 
-      delete_debug_insns ();
+      cfun->begin_stmt_markers = 0;
+
+      delete_vta_debug_insns ();
 
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
diff --git a/include/dwarf2.def b/include/dwarf2.def
index a91e943..d4fbcb3 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Introduce Statement Frontier Notes and Location Views
  2017-07-05 23:21 Introduce Statement Frontier Notes and Location Views Alexandre Oliva
@ 2017-07-13 13:17 ` Alexandre Oliva
  2017-08-18 22:49   ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views) Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-07-13 13:17 UTC (permalink / raw)
  To: gcc-patches

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?

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Statement Frontier Notes, Location Views, and Inlined Entry Point Markers         (was: Re: Introduce Statement Frontier Notes and Location Views)
  2017-07-13 13:17 ` Alexandre Oliva
@ 2017-08-18 22:49   ` Alexandre Oliva
  2017-08-21 12:35     ` Richard Biener
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-08-18 22:49 UTC (permalink / raw)
  To: gcc-patches

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

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);
+}
 \f
 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;
+}
+
 \f
 /* 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views)
  2017-08-18 22:49   ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views) Alexandre Oliva
@ 2017-08-21 12:35     ` Richard Biener
  2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  0 siblings, 2 replies; 156+ messages in thread
From: Richard Biener @ 2017-08-21 12:35 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-21 12:35     ` Richard Biener
@ 2017-08-22 22:44       ` Alexandre Oliva
  2017-08-23 12:12         ` Richard Biener
  2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-08-22 22:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-21 12:35     ` Richard Biener
  2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
@ 2017-08-22 22:44       ` Alexandre Oliva
  2017-08-23 12:33         ` Richard Biener
  1 sibling, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-08-22 22:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

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.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
@ 2017-08-23 12:12         ` Richard Biener
  2017-08-25 15:26           ` Alexandre Oliva
                             ` (2 more replies)
  0 siblings, 3 replies; 156+ messages in thread
From: Richard Biener @ 2017-08-23 12:12 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
@ 2017-08-23 12:33         ` Richard Biener
  2017-08-25 16:41           ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Richard Biener @ 2017-08-23 12:33 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-23 12:12         ` Richard Biener
@ 2017-08-25 15:26           ` Alexandre Oliva
  2017-08-28 12:41             ` Richard Biener
  2017-08-25 19:22           ` Alexandre Oliva
  2017-09-01  1:07           ` Alexandre Oliva
  2 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-08-25 15:26 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-23 12:33         ` Richard Biener
@ 2017-08-25 16:41           ` Alexandre Oliva
  2017-09-07 21:44             ` Joseph Myers
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-08-25 16:41 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On Aug 23, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> On Wed, Aug 23, 2017 at 12:29 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
>> 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.

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

This patch that adds -g to the set of negatable prefixes along with -f,
-m and -W.  Besides the mapping from -gno- to negated -g in option_map
and adding g to the [fmW] matches for negatable options, I had to
introduce gno- as an remapping prefix, for the option searching
machinery to backtrack to and recognize as a remapping prefix, instead
of backtracking to -g and stopping at it as if no-* was its Joined
argument.  Adding such remapping prefixes to preempt further
backtracking can be accomplished by introducing the prefix as an
Undocumented option with a Joined argument and without Driver, Target,
Common, or any language-specific option.  Whenever we match such a fake
options prefix, we abandon further backtracking (it matches, after all),
but find_opt returns the same code it would if it hadn't found any
match, so that we resort to option mapping.

I've arranged for such remapping prefixes to not be considered when
looking for and suggesting a correct spelling for misspelled options.
While testing that, I found a few -W-started options that were not
marked as RejectNegative but should (-Wno-a, is not something we'd like
to suggest ;-)  I've also marked as such -g-started options that
it makes no sense to negate, and removed the explicit -gno- ones,
allowing their opposites to be negated.

Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?

for  gcc/ChangeLog

	* common.opt (Wa, Wl, Wp, g, gz=): Add
	RejectNegative.
	(gno-column-info): Remove.
	(gcolumn-info): Drop RejectNegative.
	(gno-): New prefix.
	(gno-record-gcc-switches): Remove.
	(grecord-gcc-switches): Drop RejectNegative.
	(gno-split-dwarf): Remove.
	(gsplit-dwarf): Drop RejectNegative.
	(gno-strict-dwarf): Remove.
	(gstrict-dwarf): Drop RejectNegative.
	* config/darwin.opt (gfull, gused): Add RejectNegative.
	* dwarf2out.c (gen_producer_string): Drop
	gno-record-gcc-switches handler.
	* optc-gen.awk: Add g to prefixes with negative forms.
	* opts-common.c (remapping_prefix_p): New.
	(find_opt): Check it.
	(generate_canonical_option): Test g prefix.
	(option_map): Add -gno- mapping.
	(add_misspelling_candidates): Check remapping_prefix_p.

for  gcc/ada/ChangeLog

	* gcc-interface/lang.opt (gant, gnatO, gnat): Add
        RejectNegative.

for  gcc/c-family/ChangeLog

	* c.opt (gen-decls): Add RejectNegative.
---
 gcc/ada/gcc-interface/lang.opt |    6 +++---
 gcc/c-family/c.opt             |    2 +-
 gcc/common.opt                 |   38 +++++++++++++-------------------------
 gcc/config/darwin.opt          |    4 ++--
 gcc/dwarf2out.c                |    1 -
 gcc/optc-gen.awk               |    4 ++--
 gcc/opts-common.c              |   27 ++++++++++++++++++++++++++-
 7 files changed, 47 insertions(+), 35 deletions(-)

diff --git a/gcc/ada/gcc-interface/lang.opt b/gcc/ada/gcc-interface/lang.opt
index 241eafc..17c6dc8 100644
--- a/gcc/ada/gcc-interface/lang.opt
+++ b/gcc/ada/gcc-interface/lang.opt
@@ -81,15 +81,15 @@ Ada AdaWhy AdaSCIL
 Make \"char\" signed by default.
 
 gant
-Ada AdaWhy AdaSCIL Driver Joined Undocumented
+Ada AdaWhy AdaSCIL Driver Joined Undocumented RejectNegative
 Catch typos.
 
 gnatO
-Ada AdaWhy AdaSCIL Driver Separate
+Ada AdaWhy AdaSCIL Driver Separate RejectNegative
 Set name of output ALI file (internal switch).
 
 gnat
-Ada AdaWhy AdaSCIL Driver Joined
+Ada AdaWhy AdaSCIL Driver Joined RejectNegative
 -gnat<options>	Specify options to GNAT.
 
 fbuiltin-printf
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index e0ad3ab..55d9405 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1802,7 +1802,7 @@ ObjC ObjC++ Var(flag_zero_link)
 Generate lazy class lookup (via objc_getClass()) for use in Zero-Link mode.
 
 gen-decls
-ObjC ObjC++ Driver Var(flag_gen_declaration)
+ObjC ObjC++ Driver Var(flag_gen_declaration) RejectNegative
 Dump declarations to a .decl file.
 
 femit-struct-debug-baseonly
diff --git a/gcc/common.opt b/gcc/common.opt
index 1cb1c83..d18559a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -532,13 +532,13 @@ Common RejectNegative Warning Alias(Wextra)
 This switch is deprecated; use -Wextra instead.
 
 Wa,
-Driver JoinedOrMissing
+Driver JoinedOrMissing RejectNegative
 
 Wl,
-Driver JoinedOrMissing
+Driver JoinedOrMissing RejectNegative
 
 Wp,
-Driver JoinedOrMissing
+Driver JoinedOrMissing RejectNegative
 
 Waggregate-return
 Common Var(warn_aggregate_return) Warning
@@ -2819,19 +2819,15 @@ Common Report Var(flag_zero_initialized_in_bss) Init(1)
 Put zero initialized data in the bss section.
 
 g
-Common Driver JoinedOrMissing
+Common Driver RejectNegative JoinedOrMissing
 Generate debug information in default format.
 
 gcoff
 Common Driver JoinedOrMissing Negative(gdwarf)
 Generate debug information in COFF format.
 
-gno-column-info
-Common Driver RejectNegative Var(debug_column_info,0) Init(0)
-Don't record DW_AT_decl_column and DW_AT_call_column in DWARF.
-
 gcolumn-info
-Common Driver RejectNegative Var(debug_column_info,1)
+Common Driver Var(debug_column_info,1) Init(0)
 Record DW_AT_decl_column and DW_AT_call_column in DWARF.
 
 gdwarf
@@ -2846,6 +2842,10 @@ ggdb
 Common Driver JoinedOrMissing
 Generate debug information in default extended format.
 
+gno-
+RejectNegative Joined Undocumented
+; Catch the gno- prefix, so it doesn't backtrack to g<level>.
+
 gno-pubnames
 Common Driver Negative(gpubnames) Var(debug_generate_pub_sections, 0) Init(-1)
 Don't generate DWARF pubnames and pubtypes sections.
@@ -2858,20 +2858,12 @@ ggnu-pubnames
 Common Driver Negative(gno-pubnames) Var(debug_generate_pub_sections, 2)
 Generate DWARF pubnames and pubtypes sections with GNU extensions.
 
-gno-record-gcc-switches
-Common Driver RejectNegative Var(dwarf_record_gcc_switches,0) Init(1)
-Don't record gcc command line switches in DWARF DW_AT_producer.
-
 grecord-gcc-switches
-Common Driver RejectNegative Var(dwarf_record_gcc_switches,1)
+Common Driver Var(dwarf_record_gcc_switches) Init(1)
 Record gcc command line switches in DWARF DW_AT_producer.
 
-gno-split-dwarf
-Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
-Don't generate debug information in separate .dwo files.
-
 gsplit-dwarf
-Common Driver RejectNegative Var(dwarf_split_debug_info,1)
+Common Driver Var(dwarf_split_debug_info) Init(0)
 Generate debug information in separate .dwo files.
 
 gstabs
@@ -2882,12 +2874,8 @@ gstabs+
 Common Driver JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format.
 
-gno-strict-dwarf
-Common Driver RejectNegative Var(dwarf_strict,0) Init(0)
-Emit DWARF additions beyond selected version.
-
 gstrict-dwarf
-Common Driver Report RejectNegative Var(dwarf_strict,1)
+Common Driver Report Var(dwarf_strict) Init(0)
 Don't emit DWARF additions beyond selected version.
 
 gtoggle
@@ -2925,7 +2913,7 @@ Common Driver
 Generate compressed debug sections.
 
 gz=
-Common Driver Joined Enum(compressed_debug_sections)
+Common Driver RejectNegative Joined Enum(compressed_debug_sections)
 -gz=<format>	Generate compressed debug sections in format <format>.
 
 h
diff --git a/gcc/config/darwin.opt b/gcc/config/darwin.opt
index 135a9c0..48710142 100644
--- a/gcc/config/darwin.opt
+++ b/gcc/config/darwin.opt
@@ -92,10 +92,10 @@ fterminated-vtables
 Driver RejectNegative
 
 gfull
-Driver
+Driver RejectNegative
 
 gused
-Driver
+Driver RejectNegative
 
 headerpad_max_install_names
 Driver
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 917ab9f..82f2a50 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -23370,7 +23370,6 @@ gen_producer_string (void)
       case OPT_SPECIAL_program_name:
       case OPT_SPECIAL_input_file:
       case OPT_grecord_gcc_switches:
-      case OPT_gno_record_gcc_switches:
       case OPT__output_pch_:
       case OPT_fdiagnostics_show_location_:
       case OPT_fdiagnostics_show_option:
diff --git a/gcc/optc-gen.awk b/gcc/optc-gen.awk
index 3cb0005..295bae1 100644
--- a/gcc/optc-gen.awk
+++ b/gcc/optc-gen.awk
@@ -328,7 +328,7 @@ for (i = 0; i < n_opts; i++) {
 			alias_data = "NULL, NULL, N_OPTS"
 		if (flag_set_p("Enum.*", flags[i])) {
 			if (!flag_set_p("RejectNegative", flags[i]) \
-			    && opts[i] ~ "^[Wfm]")
+			    && opts[i] ~ "^[Wfgm]")
 				print "#error Enum allowing negative form"
 		}
 	} else {
@@ -370,7 +370,7 @@ for (i = 0; i < n_opts; i++) {
 		if (flag_set_p("RejectNegative", flags[i]))
 			idx = -1;
 		else {
-			if (opts[i] ~ "^[Wfm]")
+			if (opts[i] ~ "^[Wfgm]")
 				idx = indices[opts[i]];
 			else
 				idx = -1;
diff --git a/gcc/opts-common.c b/gcc/opts-common.c
index 0cab42a0..dede33c 100644
--- a/gcc/opts-common.c
+++ b/gcc/opts-common.c
@@ -28,6 +28,24 @@ along with GCC; see the file COPYING3.  If not see
 
 static void prune_options (struct cl_decoded_option **, unsigned int *);
 
+/* An option that is undocumented, that takes a joined argument, and
+   that doesn't fit any of the classes of uses (language/common,
+   driver, target) is assumed to be a prefix used to catch
+   e.g. negated options, and stop them from being further shortened to
+   a prefix that could use the negated option as an argument.  For
+   example, we want -gno-statement-frontiers to be taken as a negation
+   of -gstatement-frontiers, but without catching the gno- prefix and
+   signaling it's to be used for option remapping, it would end up
+   backtracked to g with no-statemnet-frontiers as the debug level.  */
+
+static bool
+remapping_prefix_p (const struct cl_option *opt)
+{
+  return opt->flags & CL_UNDOCUMENTED
+    && opt->flags & CL_JOINED
+    && !(opt->flags & (CL_DRIVER | CL_TARGET | CL_COMMON | CL_LANG_ALL));
+}
+
 /* Perform a binary search to find which option the command-line INPUT
    matches.  Returns its index in the option array, and
    OPT_SPECIAL_unknown on failure.
@@ -98,6 +116,9 @@ find_opt (const char *input, unsigned int lang_mask)
 	  if (opt->flags & lang_mask)
 	    return mn;
 
+	  if (remapping_prefix_p (opt))
+	    return OPT_SPECIAL_unknown;
+
 	  /* If we haven't remembered a prior match, remember this
 	     one.  Any prior match is necessarily better.  */
 	  if (match_wrong_lang == OPT_SPECIAL_unknown)
@@ -286,7 +307,8 @@ generate_canonical_option (size_t opt_index, const char *arg, int value,
 
   if (value == 0
       && !option->cl_reject_negative
-      && (opt_text[1] == 'W' || opt_text[1] == 'f' || opt_text[1] == 'm'))
+      && (opt_text[1] == 'W' || opt_text[1] == 'f'
+	  || opt_text[1] == 'g' || opt_text[1] == 'm'))
     {
       char *t = XOBNEWVEC (&opts_obstack, char, option->opt_len + 5);
       t[0] = '-';
@@ -349,6 +371,7 @@ static const struct option_map option_map[] =
   {
     { "-Wno-", NULL, "-W", false, true },
     { "-fno-", NULL, "-f", false, true },
+    { "-gno-", NULL, "-g", false, true },
     { "-mno-", NULL, "-m", false, true },
     { "--debug=", NULL, "-g", false, false },
     { "--machine-", NULL, "-m", true, false },
@@ -394,6 +417,8 @@ add_misspelling_candidates (auto_vec<char *> *candidates,
   gcc_assert (candidates);
   gcc_assert (option);
   gcc_assert (opt_text);
+  if (remapping_prefix_p (option))
+    return;
   candidates->safe_push (xstrdup (opt_text + 1));
   for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++)
     {


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-23 12:12         ` Richard Biener
  2017-08-25 15:26           ` Alexandre Oliva
@ 2017-08-25 19:22           ` Alexandre Oliva
  2017-09-01  1:07           ` Alexandre Oliva
  2 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-08-25 19:22 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

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


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-25 15:26           ` Alexandre Oliva
@ 2017-08-28 12:41             ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2017-08-28 12:41 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-23 12:12         ` Richard Biener
  2017-08-25 15:26           ` Alexandre Oliva
  2017-08-25 19:22           ` Alexandre Oliva
@ 2017-09-01  1:07           ` Alexandre Oliva
  2017-09-01  1:15             ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
                               ` (9 more replies)
  2 siblings, 10 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:07 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers
  2017-09-01  1:07           ` Alexandre Oliva
  2017-09-01  1:15             ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
@ 2017-09-01  1:15             ` Alexandre Oliva
  2017-09-01  1:15             ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
                               ` (7 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:15 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch introduces a number of new macros and functions that will
be used to distinguish between different kinds of debug stmts, insns
and notes, namely, preexisting debug bind ones and to-be-introduced
nonbind markers.

In a seemingly mechanical way, it adjusts several uses of the macros
and functions, so that they refer to narrower categories when
appropriate.

These changes, by themselves, should not have any visible effect in
the compiler behavior, since the upcoming debug markers are never
created with this patch alone.

for  gcc/ChangeLog

	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_BEGIN_STMT.
	(gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
	(MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
	(MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
	* insn-notes.def (BEGIN_STMT): New.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
	(MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
	(MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
	(NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
	(DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
	(INSN_DEBUG_MARKER_KIND): New.
	(INSN_VAR_LOCATION): Check for VAR_LOCATION.
	(INSN_VAR_LOCATION_PTR): New.
	* cfgexpand.c (expand_debug_locations): Handle debug bind insns
	only.
	(expand_gimple_basic_block): Likewise.  Emit debug temps for TER
	deps only if debug bind insns are enabled.
	(pass_expand::execute): Avoid deep TER and expand
	debug locations for debug bind insns only.
	* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
	debug stmts special handling down to debug bind stmts.
	* combine.c (try_combine): Narrow debug insns special handling
	down to debug bind insns.
	* cse.c (delete_trivially_dead_insns): Handle debug bindings.
	Narrow debug insns preexisting special handling down to debug
	bind insns.
	* dce.c (rest_of_handle_ud_dce): Narrow debug insns special
	handling down to debug bind insns.
	* function.c (instantiate_virtual_regs): Skip debug markers,
	adjust handling of debug binds.
	* gimple-ssa-backprop.c (backprop::prepare_change): Try debug
	temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
	* haifa-sched.c (schedule_insn): Narrow special handling of debug
	insns to debug bind insns.
	* ipa-prop.c (ipa_modify_call_arguments): Narrow special
	handling of debug insns to debug bind insns.
	* ipa-split.c (split_function): Likewise.
	* ira.c (combine_and_move_insns): Adjust debug bind insns only.
	* loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
	debug insns.
	* reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
	* regrename.c (build_def_use): Likewise.
	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
	(pass_cprop_hardreg): Narrow special casing of debug insns to
	debug bind insns.
	* regstat.c (regstat_init_n_sets_and_refs): Likewise.
	* reload1.c (reload): Likewise.
	* sese.c (sese_build_liveouts): Narrow special casing of debug
	stmts to debug bind stmts.
	* shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
	* ssa-iterators.h (num_imm_uses): Likewise.
	* tree-cfg.c (gimple_merge_blocks): Narrow special casing of
	debug stmts to debug bind stmts.
	* tree-inline.c	(tree_function_versioning): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-loop-distribution.c (generate_loops_for_partition):
	Narrow special casing of debug stmts to debug bind stmts.
	* tree-sra.c (analyze_access_subtree): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
	stmts to debug bind stmts.
	* tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
	* tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Likewise.
	* tree-ssa.c (flush_pending_stmts): Narrow special casing of
	debug stmts to debug bind stmts.
	(gimple_replace_ssa_lhs): Likewise.
	(insert_debug_temp_for_var_def): Likewise.
	(insert_debug_temps_for_defs): Likewise.
	(reset_debug_uses): Likewise.
	* tree-ssanames.c (release_ssa_name_fn): Likewise.
	* tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
	(adjust_debug_stmts): Likewise.
	(adjust_phi_and_debug_stmts): Likewise.
	(vect_do_peeling): Likewise.
	* tree-vect-loop.c (vect_transform_loop): Likewise.
	* valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
	* var-tracking.c (adjust_mems): Narrow special casing of debug
	insns to debug bind insns.
	(dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
	(compute_bb_dataflow, vt_find_locations): Likewise.
	(vt_expand_loc, emit_notes_for_changes): Likewise.
	(vt_init_cfa_base): Likewise.
	(vt_emit_notes): Likewise.
	(vt_initialize): Likewise.
	(vt_finalize): Likewise.
---
 gcc/cfgexpand.c              |  8 +++----
 gcc/cgraph.c                 |  2 +-
 gcc/combine.c                | 12 +++++------
 gcc/cse.c                    | 17 ++++++++-------
 gcc/dce.c                    |  2 +-
 gcc/function.c               |  7 ++++---
 gcc/gimple-ssa-backprop.c    |  2 +-
 gcc/gimple.h                 | 31 ++++++++++++++++++++++-----
 gcc/haifa-sched.c            |  4 ++--
 gcc/insn-notes.def           |  3 +++
 gcc/ipa-prop.c               |  2 +-
 gcc/ipa-split.c              | 11 +++++-----
 gcc/ira.c                    |  4 ++--
 gcc/loop-unroll.c            |  6 ++++--
 gcc/reg-stack.c              |  4 ++--
 gcc/regcprop.c               |  4 ++--
 gcc/regrename.c              |  2 +-
 gcc/regstat.c                |  2 +-
 gcc/reload1.c                |  4 ++--
 gcc/rtl.h                    | 40 +++++++++++++++++++++++++++++++++--
 gcc/sese.c                   |  2 +-
 gcc/shrink-wrap.c            |  4 ++--
 gcc/ssa-iterators.h          |  2 +-
 gcc/tree-cfg.c               |  2 +-
 gcc/tree-inline.c            |  4 ++--
 gcc/tree-loop-distribution.c |  2 +-
 gcc/tree-sra.c               |  2 +-
 gcc/tree-ssa-dce.c           |  2 +-
 gcc/tree-ssa-loop-ivopts.c   |  2 +-
 gcc/tree-ssa-reassoc.c       |  2 +-
 gcc/tree-ssa-tail-merge.c    |  2 +-
 gcc/tree-ssa-threadedge.c    |  2 +-
 gcc/tree-ssa.c               | 10 ++++-----
 gcc/tree-ssanames.c          |  2 +-
 gcc/tree-vect-loop-manip.c   |  8 +++----
 gcc/tree-vect-loop.c         |  4 ++--
 gcc/tree.h                   |  8 ++++++-
 gcc/valtrack.c               |  2 +-
 gcc/var-tracking.c           | 50 +++++++++++++++++++++-----------------------
 39 files changed, 175 insertions(+), 104 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 7f0130d..0442c29 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5288,7 +5288,7 @@ expand_debug_locations (void)
   flag_strict_aliasing = 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (DEBUG_INSN_P (insn))
+    if (DEBUG_BIND_INSN_P (insn))
       {
 	tree value = (tree)INSN_VAR_LOCATION_LOC (insn);
 	rtx val;
@@ -5541,7 +5541,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	   a_2 = ...
            #DEBUG ... => #D1
 	 */
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && SA.values
 	  && !is_gimple_debug (stmt))
 	{
@@ -6168,7 +6168,7 @@ pass_expand::execute (function *fun)
   timevar_pop (TV_OUT_OF_SSA);
   SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions);
 
-  if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter)
+  if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter)
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, cfun)
@@ -6359,7 +6359,7 @@ pass_expand::execute (function *fun)
 		  next_bb)
     bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     expand_debug_locations ();
 
   if (deep_ter_debug_map)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 69aa6c5..ab171f71 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1451,7 +1451,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
 	 stmts and associate D#X with parm in decl_debug_args_lookup
 	 vector to say for debug info that if parameter parm had been passed,
 	 it would have value parm_Y(D).  */
-      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  vec<tree, va_gc> **debug_args
 	    = decl_debug_args_lookup (e->callee->decl);
diff --git a/gcc/combine.c b/gcc/combine.c
index 8dc62b5..0c09bf6 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3705,7 +3705,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 	  /* *SPLIT may be part of I2SRC, so make sure we have the
 	     original expression around for later debug processing.
 	     We should not need I2SRC any more in other cases.  */
-	  if (MAY_HAVE_DEBUG_INSNS)
+	  if (MAY_HAVE_DEBUG_BIND_INSNS)
 	    i2src = copy_rtx (i2src);
 	  else
 	    i2src = NULL;
@@ -4062,7 +4062,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       struct undo *undo;
 
@@ -4375,7 +4375,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
     if (newi2pat)
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2scratch)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	INSN_CODE (i2) = i2_code_number;
@@ -4383,7 +4383,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       }
     else
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2src)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2src)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	SET_INSN_DELETED (i2);
@@ -4393,7 +4393,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i1) = NULL;
 	REG_NOTES (i1) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
 			       this_basic_block);
 	SET_INSN_DELETED (i1);
@@ -4403,7 +4403,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i0) = NULL;
 	REG_NOTES (i0) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
 			       this_basic_block);
 	SET_INSN_DELETED (i0);
diff --git a/gcc/cse.c b/gcc/cse.c
index 6a968d1..e51fcd9 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -7040,11 +7040,11 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       counts = XCNEWVEC (int, nreg * 3);
       for (insn = insns; insn; insn = NEXT_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_INSN_P (insn))
 	  count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
 			   NULL_RTX, 1);
 	else if (INSN_P (insn))
@@ -7102,12 +7102,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
       if (! live_insn && dbg_cnt (delete_trivial_dead))
 	{
 	  if (DEBUG_INSN_P (insn))
-	    count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-			     NULL_RTX, -1);
+	    {
+	      if (DEBUG_BIND_INSN_P (insn))
+		count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+				 NULL_RTX, -1);
+	    }
 	  else
 	    {
 	      rtx set;
-	      if (MAY_HAVE_DEBUG_INSNS
+	      if (MAY_HAVE_DEBUG_BIND_INSNS
 		  && (set = single_set (insn)) != NULL_RTX
 		  && is_dead_reg (SET_DEST (set), counts)
 		  /* Used at least once in some DEBUG_INSN.  */
@@ -7147,10 +7150,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_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/dce.c b/gcc/dce.c
index 7534d2a..6fd9548 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -777,7 +777,7 @@ rest_of_handle_ud_dce (void)
     }
   worklist.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     reset_unmarked_insns_debug_uses ();
 
   /* Before any insns are deleted, we must remove the chains since
diff --git a/gcc/function.c b/gcc/function.c
index 20c287b..f42227a 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
+	    || DEBUG_MARKER_INSN_P (insn))
 	  continue;
-	else if (DEBUG_INSN_P (insn))
-	  instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
+	else if (DEBUG_BIND_INSN_P (insn))
+	  instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
 	else
 	  instantiate_virtual_regs_in_insn (insn);
 
diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c
index f321ebb..b6e11c4 100644
--- a/gcc/gimple-ssa-backprop.c
+++ b/gcc/gimple-ssa-backprop.c
@@ -726,7 +726,7 @@ strip_sign_op (tree rhs)
 void
 backprop::prepare_change (tree var)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     insert_debug_temp_for_var_def (NULL, var);
   reset_flow_sensitive_info (var);
 }
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 6213c49..1783e11 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -198,13 +198,12 @@ 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
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -4739,6 +4738,28 @@ 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 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;
+
+  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/haifa-sched.c b/gcc/haifa-sched.c
index af0ed27..ae741fc 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -4010,7 +4010,7 @@ schedule_insn (rtx_insn *insn)
   gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK));
 
   /* Reset debug insns invalidated by moving this insn.  */
-  if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn))
+  if (MAY_HAVE_DEBUG_BIND_INSNS && !DEBUG_INSN_P (insn))
     for (sd_it = sd_iterator_start (insn, SD_LIST_BACK);
 	 sd_iterator_cond (&sd_it, &dep);)
       {
@@ -4023,7 +4023,7 @@ schedule_insn (rtx_insn *insn)
 	    continue;
 	  }
 
-	gcc_assert (DEBUG_INSN_P (dbg));
+	gcc_assert (DEBUG_BIND_INSN_P (dbg));
 
 	if (sched_verbose >= 6)
 	  fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n",
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index f96ce18..960487b 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
 /* The values passed to callee.  */
 INSN_NOTE (CALL_ARG_LOCATION)
 
+/* The beginning of a statement.  */
+INSN_NOTE (BEGIN_STMT)
+
 /* 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-prop.c b/gcc/ipa-prop.c
index 51f6221..2d15504 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -4410,7 +4410,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
 	    }
 	  vargs.quick_push (expr);
 	}
-      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
+      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  unsigned int ix;
 	  tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index e3759d6..d45e951 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1471,7 +1471,7 @@ split_function (basic_block return_bb, struct split_point *split_point,
     {
       vec<tree, va_gc> **debug_args = NULL;
       unsigned i = 0, len = 0;
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  debug_args = decl_debug_args_lookup (node->decl);
 	  if (debug_args)
@@ -1484,11 +1484,12 @@ split_function (basic_block return_bb, struct split_point *split_point,
 	    tree ddecl;
 	    gimple *def_temp;
 
-	    /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
-	       otherwise if it didn't exist before, we'd end up with
-	       different SSA_NAME_VERSIONs between -g and -g0.  */
+	    /* This needs to be done even without
+	       MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist
+	       before, we'd end up with different SSA_NAME_VERSIONs
+	       between -g and -g0.  */
 	    arg = get_or_create_ssa_default_def (cfun, parm);
-	    if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL)
+	    if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL)
 	      continue;
 
 	    while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
diff --git a/gcc/ira.c b/gcc/ira.c
index 08a1cc5..53c3f90 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3842,9 +3842,9 @@ combine_and_move_insns (void)
 	}
 
       /* Last pass - adjust debug insns referencing cleared regs.  */
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
-	  if (DEBUG_INSN_P (insn))
+	  if (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
 	      INSN_VAR_LOCATION_LOC (insn)
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 84145bb..2a97e2d 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)
+	      || (DEBUG_BIND_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)
+		 || (DEBUG_BIND_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/reg-stack.c b/gcc/reg-stack.c
index 41ae7e4..01df70e 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 (DEBUG_BIND_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 (!DEBUG_BIND_INSN_P (insn))
 	    continue;
 
 	  debug_insns_with_starting_stack--;
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 367d85a..e657733 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -763,7 +763,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 (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx loc = INSN_VAR_LOCATION_LOC (insn);
 	      if (!VAR_LOC_UNKNOWN_P (loc))
@@ -1308,7 +1308,7 @@ pass_cprop_hardreg::execute (function *fun)
       copyprop_hardreg_forward_1 (bb, all_vd + bb->index);
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       FOR_EACH_BB_FN (bb, fun)
 	if (bitmap_bit_p (visited, bb->index)
diff --git a/gcc/regrename.c b/gcc/regrename.c
index 5803664..3e820297 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 (DEBUG_BIND_INSN_P (insn)
 	       && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
 	{
 	  scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
diff --git a/gcc/regstat.c b/gcc/regstat.c
index 3fd26fd..fd3d3a8 100644
--- a/gcc/regstat.c
+++ b/gcc/regstat.c
@@ -54,7 +54,7 @@ regstat_init_n_sets_and_refs (void)
 
   regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     for (i = 0; i < max_regno; i++)
       {
 	int use_count;
diff --git a/gcc/reload1.c b/gcc/reload1.c
index e993749..61f0867 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1114,7 +1114,7 @@ reload (rtx_insn *first, int global)
       /* We don't want complex addressing modes in debug insns
 	 if simpler ones will do, so delegitimize equivalences
 	 in debug insns.  */
-      if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0)
+      if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0)
 	{
 	  rtx reg = regno_reg_rtx[i];
 	  rtx equiv = 0;
@@ -1142,7 +1142,7 @@ reload (rtx_insn *first, int global)
 	      while (next && DF_REF_INSN (next) == insn)
 		next = DF_REF_NEXT_REG (next);
 
-	      if (DEBUG_INSN_P (insn))
+	      if (DEBUG_BIND_INSN_P (insn))
 		{
 		  if (!equiv)
 		    {
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 9884b17..f7aa5fb 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -814,8 +814,13 @@ struct GTY(()) rtvec_def {
 /* Predicate yielding nonzero iff X is an insn that is not a debug insn.  */
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
+/* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+/* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_INSNS					\
+  (MAY_HAVE_DEBUG_MARKER_INSNS || MAY_HAVE_DEBUG_BIND_INSNS)
 
 /* Predicate yielding nonzero iff X is a real insn.  */
 #define INSN_P(X) \
@@ -1585,6 +1590,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 +1602,12 @@ 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))
+
 /* 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 +1627,32 @@ 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 DEBUG_BIND_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 DEBUG_MARKER_INSN_P(INSN)		\
+  (DEBUG_INSN_P (INSN)				\
+   && (GET_CODE (PATTERN (INSN))		\
+       != VAR_LOCATION))
+/* Evaluate to the marker kind.  */
+#define INSN_DEBUG_MARKER_KIND(INSN)		  \
+  (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
+   ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
+      ? NOTE_INSN_BEGIN_STMT			  \
+      : (enum insn_note)-1) 			  \
+   : (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) \
diff --git a/gcc/sese.c b/gcc/sese.c
index 3279ead..87f01d37 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -163,7 +163,7 @@ sese_build_liveouts (sese_info_p region, bitmap liveouts)
       sese_build_liveouts_bb (region, liveouts, bb);
 
   /* FIXME: We could start iterating form the successor of sese.  */
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     FOR_EACH_BB_FN (bb, cfun)
       if (!bb_in_sese_p (bb, region->region))
 	sese_reset_debug_liveouts_bb (region, liveouts, bb);
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index 3cad776..85fe81d 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -309,10 +309,10 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
      move it as far as we can.  */
   do
     {
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  FOR_BB_INSNS_REVERSE (bb, dinsn)
-	    if (DEBUG_INSN_P (dinsn))
+	    if (DEBUG_BIND_INSN_P (dinsn))
 	      {
 		df_ref use;
 		FOR_EACH_INSN_USE (use, dinsn)
diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h
index c8aa77b..dca0439 100644
--- a/gcc/ssa-iterators.h
+++ b/gcc/ssa-iterators.h
@@ -447,7 +447,7 @@ num_imm_uses (const_tree var)
   const ssa_use_operand_t *ptr;
   unsigned int num = 0;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     {
       for (ptr = start->next; ptr != start; ptr = ptr->next)
 	if (USE_STMT (ptr))
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index f26b12f..731c384 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -2054,7 +2054,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
 	      gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
 	    }
 	  /* Other user labels keep around in a form of a debug stmt.  */
-	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
+	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      gimple *dbg = gimple_build_debug_bind (label,
 						     integer_zero_node,
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index affde64..097a893 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5973,7 +5973,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 					    &vars);
 		if (init)
 		  init_stmts.safe_push (init);
-		if (MAY_HAVE_DEBUG_STMTS && args_to_skip)
+		if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip)
 		  {
 		    if (parm_num == -1)
 		      {
@@ -6119,7 +6119,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 	}
     }
 
-  if (debug_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+  if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree parm;
       vec<tree, va_gc> **debug_args = NULL;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index b1b2934..dd5e292 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -808,7 +808,7 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
   /* Remove stmts not in the PARTITION bitmap.  */
   bbs = get_loop_body_in_dom_order (loop);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     for (i = 0; i < loop->num_nodes; i++)
       {
 	basic_block bb = bbs[i];
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 68edbce2..c11b5f1 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -2454,7 +2454,7 @@ analyze_access_subtree (struct access *root, struct access *parent,
 	  gcc_checking_assert (!root->grp_scalar_read
 			       && !root->grp_assignment_read);
 	  sth_created = true;
-	  if (MAY_HAVE_DEBUG_STMTS)
+	  if (MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      root->grp_to_be_debug_replaced = 1;
 	      root->replacement_decl = create_access_replacement (root);
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index e62afad..f60670f 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1086,7 +1086,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
 
   /* If this is a store into a variable that is being optimized away,
      add a debug bind stmt if possible.  */
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && gimple_assign_single_p (stmt)
       && is_gimple_val (gimple_assign_rhs1 (stmt)))
     {
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index b65cd96..cf6094f 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -7146,7 +7146,7 @@ remove_unused_ivs (struct ivopts_data *data)
 
 	  tree def = info->iv->ssa_name;
 
-	  if (MAY_HAVE_DEBUG_STMTS && SSA_NAME_DEF_STMT (def))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def))
 	    {
 	      imm_use_iterator imm_iter;
 	      use_operand_p use_p;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 561acea..3dc1b69 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -232,7 +232,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
-  if (!MAY_HAVE_DEBUG_STMTS || gimple_code (stmt) == GIMPLE_PHI)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI)
     return gsi_remove (gsi, true);
 
   gimple_stmt_iterator prev = *gsi;
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a65ff31..a3d5074 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1802,7 +1802,7 @@ tail_merge_optimize (unsigned int todo)
 
   if (nr_bbs_removed_total > 0)
     {
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  calculate_dominance_info (CDI_DOMINATORS);
 	  update_debug_stmts ();
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 536c471..70675e4 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -692,7 +692,7 @@ simplify_control_stmt_condition_1 (edge e,
 void
 propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   if (!single_pred_p (dest))
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 8b6da96..151f544 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -220,7 +220,7 @@ flush_pending_stmts (edge e)
 void
 gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree lhs = gimple_get_lhs (stmt);
 
@@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 tree
 target_for_debug_bind (tree var)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return NULL_TREE;
 
   if (TREE_CODE (var) == SSA_NAME)
@@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
   int usecount = 0;
   tree value = NULL;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   /* If this name has already been registered for replacement, do nothing
@@ -495,7 +495,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
   ssa_op_iter op_iter;
   def_operand_p def_p;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   stmt = gsi_stmt (*gsi);
@@ -521,7 +521,7 @@ reset_debug_uses (gimple *stmt)
   imm_use_iterator imm_iter;
   gimple *use_stmt;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 676c806..49492c1 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -560,7 +560,7 @@ release_ssa_name_fn (struct function *fn, tree var)
       int saved_ssa_name_version = SSA_NAME_VERSION (var);
       use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
 
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	insert_debug_temp_for_var_def (NULL, var);
 
       if (flag_checking)
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index f78e4b42..67221b2 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -194,7 +194,7 @@ adjust_debug_stmts_now (adjust_info *ai)
 static void
 adjust_vec_debug_stmts (void)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   gcc_assert (adjust_vec.exists ());
@@ -216,7 +216,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb)
 {
   adjust_info ai;
 
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && TREE_CODE (from) == SSA_NAME
       && ! SSA_NAME_IS_DEFAULT_DEF (from)
       && ! virtual_operand_p (from))
@@ -244,7 +244,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def)
 
   SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     adjust_debug_stmts (orig_def, PHI_RESULT (update_phi),
 			gimple_bb (update_phi));
 }
@@ -1682,7 +1682,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
   create_lcssa_for_virtual_phi (loop);
   update_ssa (TODO_update_ssa_only_virtuals);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       gcc_assert (!adjust_vec.exists ());
       adjust_vec.create (32);
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index 906323b..3ecc5c9 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -7424,7 +7424,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	  if (!stmt_info)
 	    continue;
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, phi);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
@@ -7487,7 +7487,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	      continue;
 	    }
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, stmt);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
diff --git a/gcc/tree.h b/gcc/tree.h
index 46debc1..be299b9 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1126,8 +1126,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define VL_EXP_OPERAND_LENGTH(NODE) \
   ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
 
+/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+/* Nonzero if gimple_debug_bind_p() (and thus
+   gimple_debug_source_bind_p()) may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
 /* Nonzero if is_gimple_debug() may possibly hold.  */
-#define MAY_HAVE_DEBUG_STMTS    (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_STMTS					\
+  (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS)
 
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
diff --git a/gcc/valtrack.c b/gcc/valtrack.c
index 9e28d4b..6bd0946 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 (DEBUG_BIND_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..a7bdc80 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -1116,7 +1116,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
       if (tem == NULL_RTX)
 	tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
     finish_subreg:
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && GET_CODE (tem) == SUBREG
 	  && (GET_CODE (SUBREG_REG (tem)) == PLUS
 	      || GET_CODE (SUBREG_REG (tem)) == MINUS
@@ -1330,7 +1330,7 @@ dv_onepart_p (decl_or_value dv)
 {
   tree decl;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return NOT_ONEPART;
 
   if (dv_is_value_p (dv))
@@ -4854,7 +4854,7 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
   EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
     var_regno_delete (set, r);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       set->traversed_vars = set->vars;
       shared_hash_htab (set->vars)
@@ -5528,7 +5528,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
 		  variable names such as VALUEs (never happens) or
 		  DEBUG_EXPRs (only happens in the presence of debug
 		  insns).  */
-	       && (!MAY_HAVE_DEBUG_INSNS
+	       && (!MAY_HAVE_DEBUG_BIND_INSNS
 		   || !rtx_debug_expr_p (XEXP (loc, 0))))
 	return MO_USE;
       else
@@ -6691,7 +6691,7 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     local_get_addr_cache = new hash_map<rtx, rtx>;
 
   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
@@ -6973,7 +6973,7 @@ compute_bb_dataflow (basic_block bb)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       delete local_get_addr_cache;
       local_get_addr_cache = NULL;
@@ -7060,7 +7060,7 @@ vt_find_locations (void)
 	      else
 		oldinsz = oldoutsz = 0;
 
-	      if (MAY_HAVE_DEBUG_INSNS)
+	      if (MAY_HAVE_DEBUG_BIND_INSNS)
 		{
 		  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
 		  bool first = true, adjust = false;
@@ -7121,7 +7121,7 @@ vt_find_locations (void)
 
 	      if (htabmax && htabsz > htabmax)
 		{
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    inform (DECL_SOURCE_LOCATION (cfun->decl),
 			    "variable tracking size limit exceeded with "
 			    "-fvar-tracking-assignments, retrying without");
@@ -7181,7 +7181,7 @@ vt_find_locations (void)
 	}
     }
 
-  if (success && MAY_HAVE_DEBUG_INSNS)
+  if (success && MAY_HAVE_DEBUG_BIND_INSNS)
     FOR_EACH_BB_FN (bb, cfun)
       gcc_assert (VTI (bb)->flooded);
 
@@ -8570,7 +8570,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars)
   struct expand_loc_callback_data data;
   rtx result;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return loc;
 
   INIT_ELCD (data, vars);
@@ -9006,7 +9006,7 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
   if (!changed_variables->elements ())
     return;
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     process_changed_values (htab);
 
   data.insn = insn;
@@ -9490,10 +9490,8 @@ vt_emit_notes (void)
      delete_variable_part).  */
   emit_notes = true;
 
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
-    }
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
+    dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
 
   dataflow_set_init (&cur);
 
@@ -9503,13 +9501,13 @@ vt_emit_notes (void)
 	 subsequent basic blocks.  */
       emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
 
       /* Emit the notes for the changes in the basic block itself.  */
       emit_notes_in_bb (bb, &cur);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	delete local_get_addr_cache;
       local_get_addr_cache = NULL;
 
@@ -9525,7 +9523,7 @@ vt_emit_notes (void)
 
   dataflow_set_destroy (&cur);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     delete dropped_values;
   dropped_values = NULL;
 
@@ -9885,7 +9883,7 @@ vt_init_cfa_base (void)
       cfa_base_rtx = NULL_RTX;
       return;
     }
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return;
 
   /* Tell alias analysis that cfa_base_rtx should share
@@ -9927,7 +9925,7 @@ vt_initialize (void)
       VTI (bb)->permp = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
@@ -9940,7 +9938,7 @@ vt_initialize (void)
       global_get_addr_cache = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       rtx reg, expr;
       int ofst;
@@ -10070,7 +10068,7 @@ vt_initialize (void)
       HOST_WIDE_INT pre, post = 0;
       basic_block first_bb, last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_record_sets_hook = add_with_sets;
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10121,7 +10119,7 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
 			prepare_call_arguments (bb, insn);
@@ -10156,7 +10154,7 @@ vt_initialize (void)
 		      vt_init_cfa_base ();
 		      hard_frame_pointer_adjustment = fp_cfa_offset;
 		      /* Disassociate sp from fp now.  */
-		      if (MAY_HAVE_DEBUG_INSNS)
+		      if (MAY_HAVE_DEBUG_BIND_INSNS)
 			{
 			  cselib_val *v;
 			  cselib_invalidate_rtx (stack_pointer_rtx);
@@ -10176,7 +10174,7 @@ vt_initialize (void)
 
       bb = last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_preserve_only_values ();
 	  cselib_reset_table (cselib_get_next_uid ());
@@ -10275,7 +10273,7 @@ vt_finalize (void)
   location_chain_pool.release ();
   shared_hash_pool.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       if (global_get_addr_cache)
 	delete global_get_addr_cache;
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 1/9] [SFN] adjust RTL insn-walking API
  2017-09-01  1:07           ` Alexandre Oliva
  2017-09-01  1:15             ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
  2017-09-01  1:15             ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-09-01  1:15             ` Alexandre Oliva
  2017-09-01  1:16             ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
                               ` (6 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:15 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch removes unused RTL functions, introduces alternate ones for
use in a later SFN patch, and regroups other related functions so that
they appear in a more consistent order.

for  gcc/ChangeLog

	* 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.
	* rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
	(prev_nonnote_nondebug_insn_bb): Declare.
	(next_nonnote_nondebug_insn_bb): Declare.
	* cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
	* cfgrtl.c (get_last_bb_insn): Likewise.
	* lra.c (push_insns): Likewise.
---
 gcc/cfgbuild.c |  2 +-
 gcc/cfgrtl.c   |  4 ++--
 gcc/emit-rtl.c | 69 ++++++++++++++++++++++++++++++++--------------------------
 gcc/lra.c      |  2 +-
 gcc/rtl.h      |  4 ++--
 5 files changed, 44 insertions(+), 37 deletions(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 2fe74c4..4a3d903 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -489,7 +489,7 @@ 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))
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 6ef47b7..bce56b4 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -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;
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/lra.c b/gcc/lra.c
index 1230b25..236cef7 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1812,7 +1812,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/rtl.h b/gcc/rtl.h
index 8a68bb1..9884b17 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2898,13 +2898,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 *);
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-09-01  1:07           ` Alexandre Oliva
@ 2017-09-01  1:15             ` Alexandre Oliva
  2017-09-01  1:15             ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
                               ` (8 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:15 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

Introduce a command line option to enable statement frontiers, enabled
by default in optimized builds with DWARF2+ debug information.

This patch depends on an earlier patch that completed the
infrastructure for debug markers, and on another patch that turns -g
into a negatable option prefix.

gcc/ChangeLog

	* common.opt (gstatement-frontiers): New, setting
	debug_nonbind_markers_p.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
	* toplev.c (process_options): Autodetect value for debug statement
	frontiers option.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
---
 gcc/common.opt      |  4 ++++
 gcc/doc/invoke.texi | 12 ++++++++++++
 gcc/rtl.h           |  2 +-
 gcc/toplev.c        |  4 ++++
 gcc/tree.h          |  2 +-
 5 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index d18559a..b0748a2 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2874,6 +2874,10 @@ gstabs+
 Common Driver JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format.
 
+gstatement-frontiers
+Common Driver Var(debug_nonbind_markers_p) Init(2)
+Emit progressive recommended breakpoint locations.
+
 gstrict-dwarf
 Common Driver Report Var(dwarf_strict) Init(0)
 Don't emit DWARF additions beyond selected version.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 6dbc362..082f122 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -344,6 +344,7 @@ 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
+-gstatement-frontiers  -gno-statement-frontiers @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
@@ -6988,6 +6989,17 @@ 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 -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
diff --git a/gcc/rtl.h b/gcc/rtl.h
index f7aa5fb..6ca6ecf 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -815,7 +815,7 @@ struct GTY(()) rtvec_def {
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
 /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p
 /* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d23714c..dea6f82 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1534,6 +1534,10 @@ 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 (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/gcc/tree.h b/gcc/tree.h
index 379efa8..bd4a5bc 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1127,7 +1127,7 @@ 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 gimple_debug_nonbind_marker_p() may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p
 /* Nonzero if gimple_debug_bind_p() (and thus
    gimple_debug_source_bind_p()) may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (6 preceding siblings ...)
  2017-09-01  1:16             ` [PATCH 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
@ 2017-09-01  1:16             ` Alexandre Oliva
  2017-09-01  1:16             ` [PATCH 7/9] [LVU] Introduce location views Alexandre Oliva
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This API change will enable final_start_function() to "consume"
initial insns, and choose the first insn to be passed to final().

Many ports call final_start_function() and final() when creating
thunks and whatnot, so they needed adjusting.

for  gcc/ChangeLog

	* output.h (final_start_function): Adjust.
	* final.c (final_start_function): Take pointer to FIRST.
	(rest_of_handle_final): Adjust.
	* 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.
---
 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/final.c                        | 9 ++++++---
 gcc/output.h                       | 2 +-
 21 files changed, 37 insertions(+), 26 deletions(-)

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/final.c b/gcc/final.c
index 401cfb6..15a301b 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1770,9 +1770,11 @@ get_some_local_dynamic_name ()
      test and compare insns.  */
 
 void
-final_start_function (rtx_insn *first, FILE *file,
+final_start_function (rtx_insn **firstp, FILE *file,
 		      int optimize_p ATTRIBUTE_UNUSED)
 {
+  rtx_insn *first = *firstp;
+
   block_depth = 0;
 
   this_is_asm_operands = 0;
@@ -4544,8 +4546,9 @@ rest_of_handle_final (void)
     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 ();
+  final_start_function (&first, asm_out_file, optimize);
+  final (first, asm_out_file, optimize);
   if (flag_ipa_ra
       && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
     collect_fn_hard_reg_usage ();
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'
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (4 preceding siblings ...)
  2017-09-01  1:16             ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-09-01  1:16             ` Alexandre Oliva
  2017-09-01  1:16             ` [PATCH 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
                               ` (3 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch completes the infrastructure for the introduction of
statement frontiers in C-family languages.

It brings in all the code remaining code needed to introduce and
transform begin stmt trees, gimple stmts, insns and notes, and
ultimately use them to generate the is_stmt column in DWARF2+ line
number tables/programs, however none of it is activated: the option
that would do so will be introduced in a subsequent patch.

This patch depends on an earlier patch with not-quite-boilerplate
changes towards SFN.

for  gcc/c-family/ChangeLog

	* c-semantics.c (pop_stmt_list): Move begin stmt marker into
	subsequent statement list.

for  gcc/c/ChangeLog

	* c-objc-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
	* c-parser.c (add_debug_begin_stmt): New.
	(c_parser_declaration_or_fndef): Call it.
	(c_parser_compound_statement_nostart): Likewise.
	(c_parser_statement_after_labels): Likewise.
	* c-typeck (c_finish_stmt_expr): Skip begin stmts markers.

for  gcc/cp/ChangeLog

	* constexpr.c (build_data_member_initialization): Skip begin stmt
	markers.
	(check_constexpr_ctor_body_1): Likewise.
	(build_constexpr_constructor_member_initializers): Likewise.
	(constexpr_fn_retval): Likewise.
	(cxx_eval_statement_list): Likewise.
	(potential_constant_expression_1): Likewise.
	* cp-array-notation.c (stmt_location): New.
	(cp_expand_cond_array_notations): Use it.
	* cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
	* parser.c (add_debug_begin_stmt): New.
	(cp_parser_statement): Call it.
	* pt.c (tsubst_copy): Handle begin stmt markers.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
	markers.  Integrate source bind into debug stmt expand loop.
	(pass_expand::execute): Check debug marker limit.  Avoid deep
	TER and expand debug locations for debug bind insns only.
	* cse.c (insn_live_p): Keep nonbind markers and debug bindings
	followed by them.
	* df-scan.c (df_insn_delete): Accept out-of-block debug insn.
	* final.c (reemit_insn_block_notes): Take current block from
	nonbind markers.  Declare note where it's first set.
	(final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
	begin stmt markers if enabled.
	(notice_source_line): Handle nonbind markers.  Fail if their
	location is unknown or that of builtins.
	(rest_of_handle_final): Convert begin stmt markers to notes if
	var-tracking didn't run.
	(rest_of_clean_state): Skip begin stmt markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
	markers.
	* function.c (allocate_struct_function): Set begin_stmt_markers.
	* function.h (struct function): Add debug_marker_count counter
	and debug_nonbind_markers flag.
	* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
	* gimple-low.c (lower_function_body): Adjust
	debug_nonbind_markers.
	(lower_stmt): Drop or skip gimple debug stmts.
	(lower_try_catch): Skip debug stmts.
	* gimple.c (gimple_build_debug_begin_stmt): New.
	(gimple_copy): Increment debug_marker_count if copying one.
	* gimple.h (gimple_build_debug_begin_stmt): Declare.
	* gimplify.c (rexpr_location): New.
	(rexpr_has_location): New.
	(warn_switch_unreachable_r): Handle gimple debug stmts.
	(shortcut_cond_r): Call expr_location.
	(find_goto): New.
	(find_goto_label): New.
	(shortcut_cond_expr): Call expr_has_location, expr_location, and
	find_goto_label.
	(gimplify_cond_expr): Call find_goto_label, expr_has_location, and
	expr_location.
	(gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
	* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
	(LANG_HOOKS_INITIALIZER): ... this.
	* langhooks.h (struct lang_hooks): Add emits_begin_stmt.
	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
	debug insns.
	(update_ebb_live_info): Skip debug insn markers.
	* lra.c (debug_insn_static_data): Rename to...
	(debug_bind_static_data): ... this.
	(debug_marker_static_data): New.
	(lra_set_insn_recog_data): Select one of the above depending
	on debug insn kind.
	(lra_update_isn_regno_info): Don't assume debug insns have
	freqs.
	(push_insns): Skip debug insns.
	* lto-streamer-in.c (input_function): Drop debug stmts
	depending on active options.  Adjust debug_nonbind_markers.
	* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	begin stmt marker notes.
	(print_insn): Likewise.
	* recog.c (extract_insn): Recognize rtl for debug markers.
	* rtl.def (DEBUG_MARKER): New.
	* tree-inline.c: Include params.h.
	(remap_gimple_stmt): Handle nonbind markers.
	(maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.
	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
	markers regardless of no side effects.
	(tsi_link_before): Don't update container's side effects when adding
	a begin stmt marker.
	(tsi_link_after): Likewise.
	(expr_first): Skip begin stmt markers.
	(expr_last): Likewise.
	* tree-pretty-print (dump_generic_node): Handle begin stmt markers.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Disregard nonbind markers.
	* tree.c (make_node_stat): Don't set side effects for begin stmt
	markers.
	(build1_stat): Likewise.
	* tree.def (DEBUG_BEGIN_STMT): New.
	* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
	* var-tracking.c (delete_debug_insns): Renamed to...
	(delete_vta_debug_insns): ... this.
	(reemit_marker_as_note): New.
	(vt_initialize): Reemit markers.
	(delete_vta_debug_insns): Likewise.
	(vt_debug_insns_local): Reemit or delete markers.
	(variable_tracking_main_1): Likewise.
	* doc/generic.texi (DEBUG_BEGIN_STMT): Document.
	* doc/gimple.texi (gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	(gimple_build_debug_bind): Adjust.
	(gimple_build_debug_begin_stmt): New.
	* doc/invoke.texi (max-debug-marker-count): New param.
	* doc/rtl.texi (debug_implicit_ptr, entry_value): New.
	(debug_parameter_ref, debug_marker): New.
	(NOTE_INSN_BEGIN_STMT): New.
	(DEBUG_INSN): Describe begin stmt markers.
---
 gcc/c-family/c-semantics.c |  21 ++++++
 gcc/c/c-objc-common.h      |   2 +
 gcc/c/c-parser.c           |  20 ++++++
 gcc/c/c-typeck.c           |   8 ++-
 gcc/cfgexpand.c            | 113 +++++++++++++++++---------------
 gcc/cp/constexpr.c         |  11 ++++
 gcc/cp/cp-array-notation.c |  37 +++++++++--
 gcc/cp/cp-objcp-common.h   |   2 +
 gcc/cp/parser.c            |  14 ++++
 gcc/cp/pt.c                |   6 ++
 gcc/cse.c                  |   7 ++
 gcc/df-scan.c              |   2 +-
 gcc/doc/generic.texi       |   5 ++
 gcc/doc/gimple.texi        |  24 ++++++-
 gcc/doc/invoke.texi        |   7 ++
 gcc/doc/rtl.texi           |  53 ++++++++++++---
 gcc/final.c                |  89 +++++++++++++++++++------
 gcc/function.c             |   6 ++
 gcc/function.h             |  10 +++
 gcc/gimple-iterator.c      |   4 ++
 gcc/gimple-low.c           |  29 +++++++++
 gcc/gimple-pretty-print.c  |   7 ++
 gcc/gimple.c               |  24 +++++++
 gcc/gimple.h               |   1 +
 gcc/gimplify.c             | 158 +++++++++++++++++++++++++++++++++++----------
 gcc/langhooks-def.h        |   2 +
 gcc/langhooks.h            |   3 +
 gcc/lra-constraints.c      |  10 ++-
 gcc/lra.c                  |  36 +++++++++--
 gcc/lto-streamer-in.c      |  12 +++-
 gcc/params.def             |   9 +++
 gcc/print-rtl.c            |  24 +++++++
 gcc/recog.c                |   1 +
 gcc/rtl.def                |   3 +
 gcc/tree-inline.c          |  31 ++++++++-
 gcc/tree-iterator.c        |  48 +++++++++++---
 gcc/tree-pretty-print.c    |   4 ++
 gcc/tree-ssa-threadedge.c  |  25 ++++---
 gcc/tree.c                 |   8 ++-
 gcc/tree.def               |   3 +
 gcc/tree.h                 |   2 +-
 gcc/var-tracking.c         |  70 +++++++++++++++++---
 42 files changed, 793 insertions(+), 158 deletions(-)

diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 3ceb714..cd872d8 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -76,6 +76,27 @@ pop_stmt_list (tree t)
 	  free_stmt_list (t);
 	  t = u;
 	}
+      /* If the statement list contained a debug begin stmt and a
+	 statement list, move the debug begin stmt into the statement
+	 list and return it.  */
+      else if (!tsi_end_p (i)
+	       && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+	{
+	  u = tsi_stmt (i);
+	  tsi_next (&i);
+	  if (tsi_one_before_end_p (i)
+	      && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST)
+	    {
+	      tree l = tsi_stmt (i);
+	      tsi_prev (&i);
+	      tsi_delink (&i);
+	      tsi_delink (&i);
+	      i = tsi_start (l);
+	      free_stmt_list (t);
+	      t = l;
+	      tsi_link_before (&i, u, TSI_SAME_STMT);
+	    }
+	}
     }
 
   return t;
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index bee06e9..27ceabc 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
 #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
 #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
 
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 1402ba6..f3dd887 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1640,6 +1640,19 @@ c_parser_external_declaration (c_parser *parser)
 static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
    6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
    is accepted; otherwise (old-style parameter declarations) only other
@@ -1740,6 +1753,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   bool diagnosed_no_specs = false;
   location_t here = c_parser_peek_token (parser)->location;
 
+  add_debug_begin_stmt (c_parser_peek_token (parser)->location);
+
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
     {
@@ -4949,6 +4964,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
   location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
   if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
     {
+      add_debug_begin_stmt (c_parser_peek_token (parser)->location);
       c_parser_consume_token (parser);
       return;
     }
@@ -5403,6 +5419,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
   parser->in_if_block = false;
   if (if_p != NULL)
     *if_p = false;
+
+  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+    add_debug_begin_stmt (loc);
+
   switch (c_parser_peek_token (parser)->type)
     {
     case CPP_OPEN_BRACE:
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 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/cfgexpand.c b/gcc/cfgexpand.c
index 93e0f10..8b25e9f 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5638,39 +5638,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	  if (new_bb)
 	    return new_bb;
 	}
-      else if (gimple_debug_bind_p (stmt))
+      else if (is_gimple_debug (stmt))
 	{
 	  location_t sloc = curr_insn_location ();
 	  gimple_stmt_iterator nsi = gsi;
 
 	  for (;;)
 	    {
-	      tree var = gimple_debug_bind_get_var (stmt);
-	      tree value;
-	      rtx val;
+	      tree var;
+	      tree value = NULL_TREE;
+	      rtx val = NULL_RTX;
 	      machine_mode mode;
 
-	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
-		  && TREE_CODE (var) != LABEL_DECL
-		  && !target_for_debug_bind (var))
-		goto delink_debug_stmt;
+	      if (!gimple_debug_nonbind_marker_p (stmt))
+		{
+		  if (gimple_debug_bind_p (stmt))
+		    {
+		      var = gimple_debug_bind_get_var (stmt);
 
-	      if (gimple_debug_bind_has_value_p (stmt))
-		value = gimple_debug_bind_get_value (stmt);
-	      else
-		value = NULL_TREE;
+		      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+			  && TREE_CODE (var) != LABEL_DECL
+			  && !target_for_debug_bind (var))
+			goto delink_debug_stmt;
 
-	      last = get_last_insn ();
+		      if (DECL_P (var))
+			mode = DECL_MODE (var);
+		      else
+			mode = TYPE_MODE (TREE_TYPE (var));
 
-	      set_curr_insn_location (gimple_location (stmt));
+		      if (gimple_debug_bind_has_value_p (stmt))
+			value = gimple_debug_bind_get_value (stmt);
+
+		      val = gen_rtx_VAR_LOCATION
+			(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+		    }
+		  else if (gimple_debug_source_bind_p (stmt))
+		    {
+		      var = gimple_debug_source_bind_get_var (stmt);
+
+		      value = gimple_debug_source_bind_get_value (stmt);
+
+		      mode = DECL_MODE (var);
 
-	      if (DECL_P (var))
-		mode = DECL_MODE (var);
+		      val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+						  VAR_INIT_STATUS_UNINITIALIZED);
+		    }
+		  else
+		    gcc_unreachable ();
+		}
+	      /* If this function was first compiled with markers
+		 enabled, but they're now disable (e.g. LTO), drop
+		 them on the floor.  */
+	      else if (gimple_debug_nonbind_marker_p (stmt)
+		       && !MAY_HAVE_DEBUG_MARKER_INSNS)
+		goto delink_debug_stmt;
+	      else if (gimple_debug_begin_stmt_p (stmt))
+		val = gen_rtx_DEBUG_MARKER (VOIDmode);
 	      else
-		mode = TYPE_MODE (TREE_TYPE (var));
+		gcc_unreachable ();
 
-	      val = gen_rtx_VAR_LOCATION
-		(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+	      last = get_last_insn ();
+
+	      set_curr_insn_location (gimple_location (stmt));
 
 	      emit_debug_insn (val);
 
@@ -5678,9 +5707,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		{
 		  /* We can't dump the insn with a TREE where an RTX
 		     is expected.  */
-		  PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    {
+		      gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);
+		      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		    }
 		  maybe_dump_rtl_for_gimple_stmt (stmt, last);
-		  PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    PAT_VAR_LOCATION_LOC (val) = (rtx)value;
 		}
 
 	    delink_debug_stmt:
@@ -5696,42 +5730,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	      if (gsi_end_p (nsi))
 		break;
 	      stmt = gsi_stmt (nsi);
-	      if (!gimple_debug_bind_p (stmt))
+	      if (!is_gimple_debug (stmt))
 		break;
 	    }
 
 	  set_curr_insn_location (sloc);
 	}
-      else if (gimple_debug_source_bind_p (stmt))
-	{
-	  location_t sloc = curr_insn_location ();
-	  tree var = gimple_debug_source_bind_get_var (stmt);
-	  tree value = gimple_debug_source_bind_get_value (stmt);
-	  rtx val;
-	  machine_mode mode;
-
-	  last = get_last_insn ();
-
-	  set_curr_insn_location (gimple_location (stmt));
-
-	  mode = DECL_MODE (var);
-
-	  val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
-				      VAR_INIT_STATUS_UNINITIALIZED);
-
-	  emit_debug_insn (val);
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      /* We can't dump the insn with a TREE where an RTX
-		 is expected.  */
-	      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
-	      maybe_dump_rtl_for_gimple_stmt (stmt, last);
-	      PAT_VAR_LOCATION_LOC (val) = (rtx)value;
-	    }
-
-	  set_curr_insn_location (sloc);
-	}
       else
 	{
 	  gcall *call_stmt = dyn_cast <gcall *> (stmt);
@@ -6370,6 +6374,11 @@ pass_expand::execute (function *fun)
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
     e->flags &= ~EDGE_EXECUTABLE;
 
+  /* If the function has too many markers, drop them while expanding.  */
+  if (cfun->debug_marker_count
+      >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+    cfun->debug_nonbind_markers = false;
+
   lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
   FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
 		  next_bb)
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 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..c1be6b8 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 (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a statement.
 
    statement:
@@ -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 e51fcd9..97d9852 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 (DEBUG_MARKER_INSN_P (insn))
+	return true;
+
       for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
 	if (NOTE_P (next))
 	  continue;
 	else if (!DEBUG_INSN_P (next))
 	  return true;
+	/* If we find an inspection point, such as a debug begin stmt,
+	   we want to keep the earlier debug insn.  */
+	else if (DEBUG_MARKER_INSN_P (next))
+	  return true;
 	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
 	  return false;
 
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 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..6c9c4789 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -831,6 +831,16 @@ expression to a variable.
 Return true if g is any of the OpenMP codes.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
+a source statement.
+@end deftypefn
+
+@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
+without any variable binding.
+@end deftypefn
+
 @node Manipulating GIMPLE statements
 @section Manipulating GIMPLE statements
 @cindex Manipulating GIMPLE statements
@@ -1528,10 +1538,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @subsection @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
+@cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
-Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of
+Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND}
 @code{subcode}.  The effect of this statement is to tell debug
 information generation machinery that the value of user variable
 @code{var} is given by @code{value} at that point, and to remain with
@@ -1602,6 +1613,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
 and @code{FALSE} if it unbinds the variable.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that the
+user statement at the given @code{location} and @code{block} starts at
+the point at which the statement is inserted.  The intent is that side
+effects (e.g. variable bindings) of all prior user statements are
+observable, and that none of the side effects of subsequent user
+statements are.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ec29f1d..6dbc362 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10419,6 +10419,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..e58f0ab 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3413,6 +3413,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},
 that points back to it, within value expressions in
 @code{VAR_LOCATION} nodes.
 
+@findex debug_implicit_ptr
+@item (debug_implicit_ptr:@var{mode} @var{decl})
+Stands for the location of a @var{decl} that is no longer addressable.
+
+@findex entry_value
+@item (entry_value:@var{mode} @var{decl})
+Stands for the value a @var{decl} had at the entry point of the
+containing function.
+
+@findex debug_parameter_ref
+@item (debug_parameter_ref:@var{mode} @var{decl})
+Refers to a parameter that was completely optimized out.
+
+@findex debug_marker
+@item (debug_marker:@var{mode})
+Marks a program location.  With @code{VOIDmode}, it stands for the
+beginning of a statement, a recommended inspection point logically after
+all prior side effects, and before any subsequent side effects.
+
 @end table
 
 @node Insns
@@ -3689,6 +3708,12 @@ can be computed by evaluating the RTL expression from that static
 point in the program up to the next such note for the same user
 variable.
 
+@findex NOTE_INSN_BEGIN_STMT
+@item NOTE_INSN_BEGIN_STMT
+This note is used to generate @code{is_stmt} markers in line number
+debuggign information.  It indicates the beginning of a user
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3706,15 +3731,25 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-Throughout optimization passes, binding information is kept in
-pseudo-instruction form, so that, unlike notes, it gets the same
-treatment and adjustments that regular instructions would.  It is the
-variable tracking pass that turns these pseudo-instructions into var
-location notes, analyzing control flow, value equivalences and changes
-to registers and memory referenced in value expressions, propagating
-the values of debug temporaries and determining expressions that can
-be used to compute the value of each user variable at as many points
-(ranges, actually) in the program as possible.
+@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
+with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
+just @code{DEBUG_MARKER}s, can be detected by testing
+@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
+@code{DEBUG_BIND_INSN_P}.
+
+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
+with respect to each other, particularly during scheduling.  Binding
+information is kept in pseudo-instruction form, so that, unlike notes,
+it gets the same treatment and adjustments that regular instructions
+would.  It is the variable tracking pass that turns these
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
+@code{NOTE_INSN_BEGIN_STMT} notes,
+analyzing control flow, value equivalences and changes to registers and
+memory referenced in value expressions, propagating the values of debug
+temporaries and determining expressions that can be used to compute the
+value of each user variable at as many points (ranges, actually) in the
+program as possible.
 
 Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
 @code{INSN_VAR_LOCATION} denotes a value at that specific point in the
diff --git a/gcc/final.c b/gcc/final.c
index ad999f7..401cfb6 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1653,7 +1653,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 +1660,29 @@ reemit_insn_block_notes (void)
       tree this_block;
 
       /* Prevent lexical blocks from straddling section boundaries.  */
-      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
-        {
-          for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
-               s = BLOCK_SUPERCONTEXT (s))
-            {
-              rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
-              NOTE_BLOCK (note) = s;
-              note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
-              NOTE_BLOCK (note) = s;
-            }
-        }
+      if (NOTE_P (insn))
+	switch (NOTE_KIND (insn))
+	  {
+	  case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+	    {
+	      for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
+		   s = BLOCK_SUPERCONTEXT (s))
+		{
+		  rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+		  NOTE_BLOCK (note) = s;
+		  note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
+		  NOTE_BLOCK (note) = s;
+		}
+	    }
+	    break;
+
+	  case NOTE_INSN_BEGIN_STMT:
+	    this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
+	    goto set_cur_block_to_this_block;
+
+	  default:
+	    continue;
+	}
 
       if (!active_insn_p (insn))
         continue;
@@ -1692,6 +1703,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 +1720,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);
 
@@ -2410,6 +2422,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    debug_hooks->var_location (insn);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+	  gcc_checking_assert (cfun->debug_nonbind_markers);
+	  if (!DECL_IGNORED_P (current_function_decl)
+	      && notice_source_line (insn, NULL))
+	    {
+	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
+					   last_filename, last_discriminator,
+					   true);
+	    }
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	  break;
@@ -2497,7 +2520,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	rtx body = PATTERN (insn);
 	int insn_code_number;
 	const char *templ;
-	bool is_stmt;
+	bool is_stmt, *is_stmt_p;
+
+	if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
+	  {
+	    is_stmt = false;
+	    is_stmt_p = NULL;
+	  }
+	else
+	  is_stmt_p = &is_stmt;
 
 	/* Reset this early so it is correct for ASM statements.  */
 	current_insn_predicate = NULL_RTX;
@@ -2600,7 +2631,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	/* Output this line note if it is the first or the last line
 	   note in a row.  */
 	if (!DECL_IGNORED_P (current_function_decl)
-	    && notice_source_line (insn, &is_stmt))
+	    && notice_source_line (insn, is_stmt_p))
 	  {
 	    if (flag_verbose_asm)
 	      asm_show_source (last_filename, last_linenum);
@@ -3093,7 +3124,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   const char *filename;
   int linenum, columnnum;
 
-  if (override_filename)
+  if (NOTE_MARKER_P (insn))
+    {
+      location_t loc = NOTE_MARKER_LOCATION (insn);
+      expanded_location xloc = expand_location (loc);
+      if (xloc.line == 0)
+	{
+	  gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
+			       || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
+	  return false;
+	}
+      filename = xloc.file;
+      linenum = xloc.line;
+      columnnum = xloc.column;
+      force_source_line = true;
+    }
+  else if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
@@ -3126,7 +3172,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 +3185,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,6 +4539,10 @@ rest_of_handle_final (void)
 {
   const char *fnname = get_fnname_from_decl (current_function_decl);
 
+  /* Turn debug markers into notes.  */
+  if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)
+    variable_tracking_main ();
+
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
@@ -4678,6 +4730,7 @@ rest_of_clean_state (void)
       if (final_output
 	  && (!NOTE_P (insn) ||
 	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
 	       && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
diff --git a/gcc/function.c b/gcc/function.c
index f42227a..e29cbde 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4941,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
+    && MAY_HAVE_DEBUG_MARKER_STMTS;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 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 fb75f99..2359760 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
 
   if (remove_permanently)
     {
+      if (gimple_debug_nonbind_marker_p (stmt))
+	/* We don't need this to be exact, but try to keep it at least
+	   close.  */
+	cfun->debug_marker_count--;
       require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
       gimple_remove_stmt_histograms (cfun, stmt);
     }
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 22db61b..95f3f45 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -110,6 +110,17 @@ lower_function_body (void)
 
   i = gsi_last (lowered_body);
 
+  /* If we had begin stmt markers from e.g. PCH, but this compilation
+     doesn't want them, lower_stmt will have cleaned them up; we can
+     now clear the flag that indicates we had them.  */
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
+    {
+      /* This counter needs not be exact, but before lowering it will
+	 most certainly be.  */
+      gcc_assert (cfun->debug_marker_count == 0);
+      cfun->debug_nonbind_markers = false;
+    }
+
   /* If the function falls off the end, we need a null return statement.
      If we've already got one in the return_statements vector, we don't
      need to do anything special.  Otherwise build one by hand.  */
@@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (cfun->debug_nonbind_markers);
+      /* We can't possibly have debug bind stmts before lowering, we
+	 first emit them when entering SSA.  */
+      gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
+      /* Propagate fallthruness.  */
+      /* If the function (e.g. from PCH) had debug stmts, but they're
+	 disabled for this compilation, remove them.  */
+      if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+	gsi_remove (gsi, true);
+      else
+	gsi_next (gsi);
+      return;
+
     case GIMPLE_NOP:
     case GIMPLE_ASM:
     case GIMPLE_ASSIGN:
@@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
 	cannot_fallthru = false;
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
+      break;
+
     default:
       /* This case represents statements to be executed when an
 	 exception occurs.  Those statements are implicitly followed
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index ed8e51c..2702854 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1370,6 +1370,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 			 gimple_debug_source_bind_get_value (gs));
       break;
 
+    case GIMPLE_DEBUG_BEGIN_STMT:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+      break;
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c4e6f81..dc9aa79 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -836,6 +836,27 @@ gimple_build_debug_source_bind (tree var, tree value,
 }
 
 
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+   LOCATION.  */
+
+gdebug *
+gimple_build_debug_begin_stmt (tree block, location_t location
+				    MEM_STAT_DECL)
+{
+  gdebug *p
+    = as_a <gdebug *> (
+        gimple_build_with_ops_stat (GIMPLE_DEBUG,
+				    (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+				    PASS_MEM_STAT));
+
+  gimple_set_location (p, location);
+  gimple_set_block (p, block);
+  cfun->debug_marker_count++;
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1874,6 +1895,9 @@ gimple_copy (gimple *stmt)
       gimple_set_modified (copy, true);
     }
 
+  if (gimple_debug_nonbind_marker_p (stmt))
+    cfun->debug_marker_count++;
+
   return copy;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 8f289ac..68cd34f 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1454,6 +1454,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
+gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
 gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
 gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
 gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index d391039..8c5804b 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -982,6 +982,48 @@ unshare_expr_without_location (tree expr)
     walk_tree (&expr, prune_expr_location, NULL, NULL);
   return expr;
 }
+
+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
+   one, OR_ELSE otherwise.  The location of a STATEMENT_LISTs
+   comprising at least one DEBUG_BEGIN_STMT followed by exactly one
+   EXPR is the location of the EXPR.  */
+
+static location_t
+rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
+  if (!expr)
+    return or_else;
+
+  if (EXPR_HAS_LOCATION (expr))
+    return EXPR_LOCATION (expr);
+
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    return or_else;
+
+  tree_stmt_iterator i = tsi_start (expr);
+
+  bool found = false;
+  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+    {
+      found = true;
+      tsi_next (&i);
+    }
+
+  if (!found || !tsi_one_before_end_p (i))
+    return or_else;
+
+  return rexpr_location (tsi_stmt (i), or_else);
+}
+
+/* Return TRUE iff EXPR (maybe recursively) has a location; see
+   rexpr_location for the potential recursion.  */
+
+static inline bool
+rexpr_has_location (tree expr)
+{
+  return rexpr_location (expr) != UNKNOWN_LOCATION;
+}
+
 \f
 /* 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))
 	{
@@ -3440,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 = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3463,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 = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3485,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 = rexpr_location (pred, locus);
       expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
 		     shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
 				      false_label_p, locus),
@@ -3509,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.  */
@@ -3539,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 (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  then_ = shortcut_cond_expr (expr);
 	  then_se = then_ && TREE_SIDE_EFFECTS (then_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3561,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 (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  else_ = shortcut_cond_expr (expr);
 	  else_se = else_ && TREE_SIDE_EFFECTS (else_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3589,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;
     }
@@ -3666,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 (rexpr_has_location (last))
+	    SET_EXPR_LOCATION (t, rexpr_location (last));
 	  append_to_statement_list (t, &expr);
 	}
       if (emit_false)
@@ -3960,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))))
+	  || !rexpr_has_location (label_true)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_true)))
     {
-      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
       have_then_clause_p = true;
+      label_true = GOTO_DESTINATION (label_true);
     }
   else
     label_true = create_artificial_label (UNKNOWN_LOCATION);
-  if (TREE_OPERAND (expr, 2) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
-	  == current_function_decl)
+  label_false = find_goto_label (TREE_OPERAND (expr, 2));
+  if (label_false
+      && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
+	  || !rexpr_has_location (label_false)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_false)))
     {
-      label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
       have_else_clause_p = true;
+      label_false = GOTO_DESTINATION (label_false);
     }
   else
     label_false = create_artificial_label (UNKNOWN_LOCATION);
@@ -11782,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/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/lra-constraints.c b/gcc/lra-constraints.c
index b1d864f..497a7cf 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 (DEBUG_MARKER_INSN_P (curr_insn))
+	    continue;
+	  curr_bb = prev_bb;
+	}
       if (curr_bb != prev_bb)
 	{
 	  if (prev_bb != NULL)
diff --git a/gcc/lra.c b/gcc/lra.c
index 236cef7..4e81d5d 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 (DEBUG_BIND_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_bind_static_data;
+	  data->operand_loc = XNEWVEC (rtx *, 1);
+	  data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+	}
+      else if (DEBUG_MARKER_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_marker_static_data;
+	  data->operand_loc = NULL;
+	}
       return data;
     }
   if (icode < 0)
@@ -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--)
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 5710e8f..6ffa5f0 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1119,7 +1119,10 @@ input_function (tree fn_decl, struct data_in *data_in,
 	     Similarly remove all IFN_*SAN_* internal calls   */
 	  if (!flag_wpa)
 	    {
-	      if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+	      if (is_gimple_debug (stmt)
+		  && (gimple_debug_nonbind_marker_p (stmt)
+		      ? !MAY_HAVE_DEBUG_MARKER_STMTS
+		      : !MAY_HAVE_DEBUG_BIND_STMTS))
 		remove = true;
 	      if (is_gimple_call (stmt)
 		  && gimple_call_internal_p (stmt))
@@ -1173,6 +1176,13 @@ input_function (tree fn_decl, struct data_in *data_in,
 	    {
 	      gsi_next (&bsi);
 	      stmts[gimple_uid (stmt)] = stmt;
+
+	      /* Remember that the input function has begin stmt
+		 markers, so that we know to expect them when emitting
+		 debug info.  */
+	      if (!cfun->debug_nonbind_markers
+		  && gimple_debug_nonbind_marker_p (stmt))
+		cfun->debug_nonbind_markers = true;
 	    }
 	}
     }
diff --git a/gcc/params.def b/gcc/params.def
index 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/print-rtl.c b/gcc/print-rtl.c
index 79ec463..0d36a42 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  fputc ('\t', m_outfile);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+	  {
+	    expanded_location xloc
+	      = expand_location (NOTE_MARKER_LOCATION (in_rtx));
+	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+	  }
+#endif
+	  break;
+
 	default:
 	  break;
 	}
@@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 
     case DEBUG_INSN:
       {
+	if (DEBUG_MARKER_INSN_P (x))
+	  {
+	    switch (INSN_DEBUG_MARKER_KIND (x))
+	      {
+	      case NOTE_INSN_BEGIN_STMT:
+		pp_string (pp, "debug begin stmt marker");
+		break;
+
+	      default:
+		gcc_unreachable ();
+	      }
+	    break;
+	  }
+
 	const char *name = "?";
 
 	if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
diff --git a/gcc/recog.c b/gcc/recog.c
index fd4e460..4b4d8f1 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -2258,6 +2258,7 @@ extract_insn (rtx_insn *insn)
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
     case VAR_LOCATION:
+    case DEBUG_MARKER:
       return;
 
     case SET:
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 4c2607a..ccdaa82 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -761,6 +761,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
    been optimized away completely.  */
 DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
 
+/* Used in marker DEBUG_INSNs to avoid being recognized as an insn.  */
+DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_OBJ)
+
 /* All expressions from this point forward appear only in machine
    descriptions.  */
 #ifdef GENERATOR_FILE
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 097a893..76c23ad 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)
+	  ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers
+	  : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return stmts;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
@@ -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,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
 	      value = gimple_debug_source_bind_get_value (stmt);
 	      new_stmt = gimple_build_debug_source_bind (var, value, stmt);
 	    }
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    new_stmt = as_a <gdebug *> (gimple_copy (stmt));
 	  else
 	    gcc_unreachable ();
 	  gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2915,6 +2935,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 +2946,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
 
   if (gimple_debug_source_bind_p (stmt))
     t = gimple_debug_source_bind_get_var (stmt);
-  else
+  else if (gimple_debug_bind_p (stmt))
     t = gimple_debug_bind_get_var (stmt);
+  else
+    gcc_unreachable ();
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = id->debug_map->get (t)))
diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
index c485413..10e510d 100644
--- a/gcc/tree-iterator.c
+++ b/gcc/tree-iterator.c
@@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)
 void
 append_to_statement_list (tree t, tree *list_p)
 {
-  if (t && TREE_SIDE_EFFECTS (t))
+  if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
     append_to_statement_list_1 (t, list_p);
 }
 
@@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
       tail = head;
     }
 
-  TREE_SIDE_EFFECTS (i->container) = 1;
+  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+    TREE_SIDE_EFFECTS (i->container) = 1;
 
   cur = i->ptr;
 
@@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
       tail = head;
     }
 
-  TREE_SIDE_EFFECTS (i->container) = 1;
+  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+    TREE_SIDE_EFFECTS (i->container) = 1;
 
   cur = i->ptr;
 
@@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)
   i->ptr = next;
 }
 
-/* Return the first expression in a sequence of COMPOUND_EXPRs,
-   or in a STATEMENT_LIST.  */
+/* Return the first expression in a sequence of COMPOUND_EXPRs, or in
+   a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+   STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT.  */
 
 tree
 expr_first (tree expr)
@@ -291,7 +294,20 @@ expr_first (tree expr)
   if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
-      return n ? n->stmt : NULL_TREE;
+      if (!n)
+	return NULL_TREE;
+      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+	{
+	  n = n->next;
+	  if (!n)
+	    return NULL_TREE;
+	}
+      /* If the first non-debug stmt is not a statement list, we
+	 already know it's what we're looking for.  */
+      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+	return n->stmt;
+
+      return expr_first (n->stmt);
     }
 
   while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -300,8 +316,9 @@ expr_first (tree expr)
   return expr;
 }
 
-/* Return the last expression in a sequence of COMPOUND_EXPRs,
-   or in a STATEMENT_LIST.  */
+/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
+   STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+   STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT.  */
 
 tree
 expr_last (tree expr)
@@ -312,7 +329,20 @@ expr_last (tree expr)
   if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
-      return n ? n->stmt : NULL_TREE;
+      if (!n)
+	return NULL_TREE;
+      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+	{
+	  n = n->prev;
+	  if (!n)
+	    return NULL_TREE;
+	}
+      /* If the last non-debug stmt is not a statement list, we
+	 already know it's what we're looking for.  */
+      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+	return n->stmt;
+
+      return expr_last (n->stmt);
     }
 
   while (TREE_CODE (expr) == COMPOUND_EXPR)
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index c6af413..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;
     }
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 70675e4..91793bf 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
       gimple *stmt = gsi_stmt (si);
       if (!is_gimple_debug (stmt))
 	break;
+      if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       i++;
     }
 
@@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	var = gimple_debug_bind_get_var (stmt);
       else if (gimple_debug_source_bind_p (stmt))
 	var = gimple_debug_source_bind_get_var (stmt);
+      else if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       else
 	gcc_unreachable ();
 
@@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	    var = gimple_debug_bind_get_var (stmt);
 	  else if (gimple_debug_source_bind_p (stmt))
 	    var = gimple_debug_source_bind_get_var (stmt);
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    continue;
 	  else
 	    gcc_unreachable ();
 
-	  /* Discard debug bind overlaps.  ??? Unlike stmts from src,
+	  /* Discard debug bind overlaps.  Unlike stmts from src,
 	     copied into a new block that will precede BB, debug bind
 	     stmts in bypassed BBs may actually be discarded if
-	     they're overwritten by subsequent debug bind stmts, which
-	     might be a problem once we introduce stmt frontier notes
-	     or somesuch.  Adding `&& bb == src' to the condition
-	     below will preserve all potentially relevant debug
-	     notes.  */
+	     they're overwritten by subsequent debug bind stmts.  We
+	     want to copy binds for all modified variables, so that we
+	     retain a bind to the shared def if there is one, or to a
+	     newly introduced PHI node if there is one.  Our bind will
+	     end up reset if the value is dead, but that implies the
+	     variable couldn't have survived, so it's fine.  We are
+	     not actually running the code that performed the binds at
+	     this point, we're just adding binds so that they survive
+	     the new confluence, so markers should not be copied.  */
 	  if (vars && vars->add (var))
 	    continue;
 	  else if (!vars)
@@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 		  break;
 	      if (i >= 0)
 		continue;
-
-	      if (fewvars.length () < (unsigned) alloc_count)
+	      else if (fewvars.length () < (unsigned) alloc_count)
 		fewvars.quick_push (var);
 	      else
 		{
diff --git a/gcc/tree.c b/gcc/tree.c
index 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 be299b9..379efa8 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1225,7 +1225,7 @@ extern void protected_set_expr_location (tree, location_t);
 
 /* GOTO_EXPR accessor. This gives access to the label associated with
    a goto statement.  */
-#define GOTO_DESTINATION(NODE)  TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE)  TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
 
 /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
    instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index d554a35..8f283b7 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9918,6 +9918,36 @@ vt_init_cfa_base (void)
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
 }
 
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
+{
+  gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
+
+  enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
+
+  switch (kind)
+    {
+    case NOTE_INSN_BEGIN_STMT:
+      {
+	rtx_insn *note = NULL;
+	if (cfun->debug_nonbind_markers)
+	  {
+	    note = emit_note_before (kind, insn);
+	    NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
+	    if (bb)
+	      BLOCK_FOR_INSN (note) = *bb;
+	  }
+	delete_insn (insn);
+	return note;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
@@ -10161,6 +10191,12 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
+		  if (DEBUG_MARKER_INSN_P (insn))
+		    {
+		      insn = reemit_marker_as_note (insn, &save_bb);
+		      continue;
+		    }
+
 		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
@@ -10237,10 +10273,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;
@@ -10256,6 +10293,12 @@ delete_debug_insns (void)
 	   insn = next)
 	if (DEBUG_INSN_P (insn))
 	  {
+	    if (DEBUG_MARKER_INSN_P (insn))
+	      {
+		insn = reemit_marker_as_note (insn, NULL);
+		continue;
+	      }
+
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
 	    if (TREE_CODE (decl) == LABEL_DECL
 		&& DECL_NAME (decl)
@@ -10281,10 +10324,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.  */
@@ -10349,15 +10395,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)
     {
@@ -10379,7 +10431,9 @@ variable_tracking_main_1 (void)
     {
       vt_finalize ();
 
-      delete_debug_insns ();
+      cfun->debug_nonbind_markers = 0;
+
+      delete_vta_debug_insns ();
 
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 9/9] [IEPM] Introduce inline entry point markers
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (5 preceding siblings ...)
  2017-09-01  1:16             ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
@ 2017-09-01  1:16             ` Alexandre Oliva
  2017-09-01  1:16             ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
                               ` (2 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

Output DW_AT_entry_pc based on markers.

Introduce DW_AT_GNU_entry_view as a DWARF extension.

If views are enabled are we're not in strict compliance mode, output
DW_AT_GNU_entry_view if it might be nonzero.

This patch depends on SFN and LVU patchsets, and on the IEPM patch that
introduces the inline_entry debug hook.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_entry_view): New.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
	markers.
	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
	(BLOCK_INLINE_ENTRY_LABEL): New.
	(dwarf2out_var_location): Disregard inline entry markers.
	(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.
	(block_within_block_p, dwarf2out_inline_entry): New.
	(dwarf2out_finish): Check that no entries remained in
	inline_entry_data_table.
	* final.c (reemit_insn_block_notes): Handle inline entry notes.
	(final_scan_insn, notice_source_line): Likewise.
	(rest_of_clean_state): Skip inline entry markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
	markers.
	* gimple.c (gimple_build_debug_inline_entry): New.
	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_INLINE_ENTRY.
	(gimple_build_debug_inline_entry): Declare.
	(gimple_debug_inline_entry_p): New.
	(gimple_debug_nonbind_marker_p): Adjust.
	* insn-notes.def (INLINE_ENTRY): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	inline entry marker notes.
	(print_insn): Likewise.
	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
	(INSN_DEBUG_MARKER_KIND): Likewise.
	* tree-inline.c	(expand_call_inline): Build and insert
	debug_inline_entry stmt.
	* 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.
	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
	(gimple_build_debug_inline_entry): New.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
	Enable/disable inline entry points too.
	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
	(DEBUG_INSN): Describe inline entry markers.
---
 gcc/cfgexpand.c           |   9 +++
 gcc/doc/gimple.texi       |  18 +++++
 gcc/doc/rtl.texi          |  24 ++++--
 gcc/dwarf2out.c           | 186 +++++++++++++++++++++++++++++++++++++++++++++-
 gcc/final.c               |  26 +++++++
 gcc/gimple-pretty-print.c |  13 ++++
 gcc/gimple.c              |  21 ++++++
 gcc/gimple.h              |  18 ++++-
 gcc/insn-notes.def        |   4 +
 gcc/print-rtl.c           |   5 ++
 gcc/rtl.h                 |   5 +-
 gcc/tree-inline.c         |   7 ++
 gcc/tree-ssa-live.c       |  27 +++++--
 gcc/var-tracking.c        |   1 +
 include/dwarf2.def        |   1 +
 15 files changed, 349 insertions(+), 16 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 8b25e9f..74c5c1f 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5694,6 +5694,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		goto delink_debug_stmt;
 	      else if (gimple_debug_begin_stmt_p (stmt))
 		val = gen_rtx_DEBUG_MARKER (VOIDmode);
+	      else if (gimple_debug_inline_entry_p (stmt))
+		{
+		  tree block = gimple_block (stmt);
+
+		  if (block)
+		    val = gen_rtx_DEBUG_MARKER (BLKmode);
+		  else
+		    goto delink_debug_stmt;
+		}
 	      else
 		gcc_unreachable ();
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 6c9c4789..af39d75 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -836,6 +836,11 @@ Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
 a source statement.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_inline_entry_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the entry
+point of an inlined function.
+@end deftypefn
+
 @deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
 Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
 without any variable binding.
@@ -1539,6 +1544,7 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
 @cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
+@cindex @code{GIMPLE_DEBUG_INLINE_ENTRY}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
@@ -1624,6 +1630,18 @@ observable, and that none of the side effects of subsequent user
 statements are.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_inline_entry (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_INLINE_ENTRY} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that a
+function call at @code{location} underwent inline substitution, that
+@code{block} is the enclosing lexical block created for the
+substitution, and that at the point of the program in which the stmt is
+inserted, all parameters for the inlined function are bound to the
+respective arguments, and none of the side effects of its stmts are
+observable.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index e58f0ab..6e588a07 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3430,7 +3430,10 @@ Refers to a parameter that was completely optimized out.
 @item (debug_marker:@var{mode})
 Marks a program location.  With @code{VOIDmode}, it stands for the
 beginning of a statement, a recommended inspection point logically after
-all prior side effects, and before any subsequent side effects.
+all prior side effects, and before any subsequent side effects.  With
+@code{BLKmode}, it indicates an inline entry point: the lexical block
+encoded in the @code{INSN_LOCATION} is the enclosing block that encloses
+the inlined function.
 
 @end table
 
@@ -3714,6 +3717,13 @@ This note is used to generate @code{is_stmt} markers in line number
 debuggign information.  It indicates the beginning of a user
 statement.
 
+@findex NOTE_INSN_INLINE_ENTRY
+@item NOTE_INSN_INLINE_ENTRY
+This note is used to generate @code{entry_pc} for inlined subroutines in
+debugging information.  It indicates an inspection point at which all
+arguments for the inlined function have been bound, and before its first
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3731,8 +3741,12 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
-with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{GIMPLE_DEBUG_BEGIN_STMT} and @code{GIMPLE_DEBUG_INLINE_ENTRY} are
+expanded to RTL as a @code{DEBUG_INSN} with a @code{DEBUG_MARKER}
+@code{PATTERN}; the difference is the RTL mode: the former's
+@code{DEBUG_MARKER} is @code{VOIDmode}, whereas the latter is
+@code{BLKmode}; information about the inlined function can be taken from
+the lexical block encoded in the @code{INSN_LOCATION}.  These
 @code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
 just @code{DEBUG_MARKER}s, can be detected by testing
 @code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
@@ -3743,8 +3757,8 @@ 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,
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION},
+@code{NOTE_INSN_BEGIN_STMT} and @code{NOTE_INSN_INLINE_ENTRY} 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
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 839b153..62e6decc 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2719,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);
@@ -2766,7 +2767,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
-  debug_nothing_tree,		/* inline_entry */
+  dwarf2out_inline_entry,	/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -3961,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
@@ -23039,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
@@ -23475,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 (MAY_HAVE_DEBUG_MARKER_INSNS);
+      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))
     {
@@ -23482,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 (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23653,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26593,6 +26675,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
       || ! 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;
 
@@ -26781,6 +26864,100 @@ create_label:
   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.  */
@@ -30156,6 +30333,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 ());
diff --git a/gcc/final.c b/gcc/final.c
index 4ca4aaa..2c7f8be 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1679,6 +1679,7 @@ reemit_insn_block_notes (void)
 	    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;
 
@@ -2520,6 +2521,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  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);
@@ -2527,6 +2529,18 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    }
 	  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:
 	  gcc_unreachable ();
 	  break;
@@ -3231,6 +3245,17 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   if (NOTE_MARKER_P (insn))
     {
       location_t loc = NOTE_MARKER_LOCATION (insn);
+      /* The inline entry markers (gimple, insn, note) carry the
+	 location of the call, because that's what we want to carry
+	 during compilation, but the location we want to output in
+	 debug information for the inline entry point is the location
+	 of the function itself.  */
+      if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY)
+	{
+	  tree block = LOCATION_BLOCK (loc);
+	  tree fn = block_ultimate_origin (block);
+	  loc = DECL_SOURCE_LOCATION (fn);
+	}
       expanded_location xloc = expand_location (loc);
       if (xloc.line == 0)
 	{
@@ -4837,6 +4862,7 @@ rest_of_clean_state (void)
 	  && (!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/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 2702854..7c9c754 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1377,6 +1377,19 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 	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 dc9aa79..01ddc65 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -857,6 +857,27 @@ gimple_build_debug_begin_stmt (tree block, location_t location
 }
 
 
+/* 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.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 68cd34f..909807f 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -203,7 +203,8 @@ enum gf_mask {
 enum gimple_debug_subcode {
   GIMPLE_DEBUG_BIND = 0,
   GIMPLE_DEBUG_SOURCE_BIND = 1,
-  GIMPLE_DEBUG_BEGIN_STMT = 2
+  GIMPLE_DEBUG_BEGIN_STMT = 2,
+  GIMPLE_DEBUG_INLINE_ENTRY = 3
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -1455,6 +1456,7 @@ 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);
@@ -4766,13 +4768,25 @@ gimple_debug_begin_stmt_p (const gimple *s)
   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;
+    return s->subcode == GIMPLE_DEBUG_BEGIN_STMT
+      || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
 
   return false;
 }
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index 960487b..252e957 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -71,6 +71,10 @@ 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/print-rtl.c b/gcc/print-rtl.c
index 0d36a42..cca8798 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -259,6 +259,7 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_BEGIN_STMT:
+	case NOTE_INSN_INLINE_ENTRY:
 #ifndef GENERATOR_FILE
 	  {
 	    expanded_location xloc
@@ -1809,6 +1810,10 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 		pp_string (pp, "debug begin stmt marker");
 		break;
 
+	      case NOTE_INSN_INLINE_ENTRY:
+		pp_string (pp, "debug inline entry marker");
+		break;
+
 	      default:
 		gcc_unreachable ();
 	      }
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 6ca6ecf..8a525c1 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1606,7 +1606,8 @@ extern const char * const reg_note_name[];
    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_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))
@@ -1644,6 +1645,8 @@ extern const char * const reg_note_name[];
   (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
    ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
       ? NOTE_INSN_BEGIN_STMT			  \
+      : GET_MODE (PATTERN (INSN)) == BLKmode	  \
+      ? NOTE_INSN_INLINE_ENTRY			  \
       : (enum insn_note)-1) 			  \
    : (enum insn_note)-1)
 
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 76c23ad..304f984 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4697,6 +4697,13 @@ 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, input_location), GSI_NEW_STMT);
+    }
 
   if (DECL_INITIAL (fn))
     {
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/var-tracking.c b/gcc/var-tracking.c
index 8f283b7..c973bdc 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9930,6 +9930,7 @@ reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
   switch (kind)
     {
     case NOTE_INSN_BEGIN_STMT:
+    case NOTE_INSN_INLINE_ENTRY:
       {
 	rtx_insn *note = NULL;
 	if (cfun->debug_nonbind_markers)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index d4fbcb3..1d6d13b 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -444,6 +444,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
    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.  */
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (3 preceding siblings ...)
  2017-09-01  1:16             ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
@ 2017-09-01  1:16             ` Alexandre Oliva
  2017-09-01  1:16             ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
                               ` (4 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch adjusts numerous parts of the compiler that would
malfunction should they find debug markers at points where they may be
introduced.  The changes purport to allow the compiler to pass
bootstrap-debug-lean (-fcompare-debug in stage3) at various
optimization levels, as well as bootstrap-debug-lib (-fcompare-debug
for target libraries), even after the compiler is changed so that
debug markers are introduced in code streams at spots where earlier
debug stmts, insns and notes wouldn't normally appear.

This patch depends on an earlier SFN boilerplate patch, and on another
SFN patch that introduces new RTL insn-walking functions.

for  gcc/ChangeLog

	* cfgbuild.c (find_bb_boundaries): Skip debug insns.
	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
	* cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
	(rtl_tidy_fallthru_edge): Likewise.
	(rtl_verify_fallthru): Likewise.
	(rtl_verify_bb_layout): Likewise.
	(skip_insns_after_block): Likewise.
	(duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
	* dwarf2out.c: Include print-rtl.h.
	(dwarf2out_next_real_insn): New.
	(dwarf2out_var_location): Call it.  Disregard begin stmt markers.
	Dump debug binds in asm comments.
	* gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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 (gimple_seq_may_fallthru): Take last nondebug stmt.
	* gimple.h (gimple_seq_last_nondebug_stmt): New.
	* gimplify.c (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.
	* 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.
	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
	* jump.c (clean_barriers): Skip debug insns.
	* 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.
	* postreload.c (fixup_debug_insns): Skip nonbind debug insns.
	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
	* 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
	* var-tracking.c (get_first_insn): New.
	(vt_emit_notes): Call it.
	(vt_initialize): Walk any insns before the first BB.
	(delete_debug_insns): Likewise.
---
 gcc/cfgbuild.c                   |  12 +++
 gcc/cfgcleanup.c                 |  12 +--
 gcc/cfgexpand.c                  |  24 +++++-
 gcc/cfgrtl.c                     |  18 +++--
 gcc/dwarf2out.c                  |  38 ++++++++-
 gcc/gimple-iterator.c            |  24 +++++-
 gcc/gimple-iterator.h            |  46 ++++++-----
 gcc/gimple-low.c                 |   2 +-
 gcc/gimple.h                     |  16 ++++
 gcc/gimplify.c                   |  21 ++---
 gcc/graphite-isl-ast-to-gimple.c |   7 +-
 gcc/graphite-scop-detection.c    |   2 +-
 gcc/haifa-sched.c                |   2 +-
 gcc/ipa-icf-gimple.c             |   4 +-
 gcc/jump.c                       |   2 +-
 gcc/omp-expand.c                 | 161 ++++++++++++++++++++-------------------
 gcc/omp-low.c                    |   2 +
 gcc/postreload.c                 |   2 +-
 gcc/regcprop.c                   |   2 +
 gcc/tree-cfg.c                   |  52 +++++++++++--
 gcc/tree-cfgcleanup.c            |  31 +++-----
 gcc/tree-pretty-print.c          |   5 +-
 gcc/tree-ssa-dce.c               |   6 +-
 gcc/tree-ssa-tail-merge.c        |   4 +-
 gcc/var-tracking.c               |  54 ++++++++++++-
 25 files changed, 376 insertions(+), 173 deletions(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 4a3d903..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;
@@ -494,8 +503,11 @@ find_bb_boundaries (basic_block bb)
 
       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/cfgcleanup.c b/gcc/cfgcleanup.c
index 365c971..be88fdd 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -3060,13 +3060,13 @@ delete_unreachable_blocks (void)
 
   find_unreachable_blocks ();
 
-  /* When we're in GIMPLE mode and there may be debug insns, we should
-     delete blocks in reverse dominator order, so as to get a chance
-     to substitute all released DEFs into debug stmts.  If we don't
-     have dominators information, walking blocks backward gets us a
-     better chance of retaining most debug information than
+  /* When we're in GIMPLE mode and there may be debug bind insns, we
+     should delete blocks in reverse dominator order, so as to get a
+     chance to substitute all released DEFs into debug bind stmts.  If
+     we don't have dominators information, walking blocks backward
+     gets us a better chance of retaining most debug information than
      otherwise.  */
-  if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE
+  if (MAY_HAVE_DEBUG_BIND_INSNS && current_ir_type () == IR_GIMPLE
       && dom_info_available_p (CDI_DOMINATORS))
     {
       for (b = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 0442c29..93e0f10 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;
@@ -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
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index bce56b4..d43e38c 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.
@@ -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 (DEBUG_BIND_INSN_P (insn)
+	      && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
 	    break;
 	  /* FALLTHRU */
 	case INSN:
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 82f2a50..71c4739 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"
@@ -26081,6 +26082,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.  */
@@ -26129,7 +26146,7 @@ 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;
@@ -26159,11 +26176,12 @@ 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_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)
     {
@@ -26322,6 +26340,22 @@ create_label:
       newloc->label = last_postcall_label;
     }
 
+  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;
 }
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 3b74cc5..fb75f99 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -744,9 +744,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 +780,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..22db61b 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -645,7 +645,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.h b/gcc/gimple.h
index 1783e11..8f289ac 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -4582,6 +4582,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
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 86623e0..d391039 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1855,7 +1855,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 +1868,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 +1995,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 +2032,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 +2045,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 +2092,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 +2233,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);
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 ae741fc..088e690 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/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/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/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/postreload.c b/gcc/postreload.c
index e721f2f..4e52832 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 (!DEBUG_BIND_INSN_P (insn))
 	continue;
       
       t = INSN_VAR_LOCATION_LOC (insn);
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index e657733..e4cd8ae 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) (...))
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 731c384..649d446 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-pretty-print.c b/gcc/tree-pretty-print.c
index c7509af..c6af413 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3386,7 +3386,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 f60670f..28cf643 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-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a3d5074..01b8821 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/var-tracking.c b/gcc/var-tracking.c
index a7bdc80..d554a35 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
@@ -9499,7 +9517,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_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
@@ -10095,11 +10114,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 (DEBUG_BIND_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);
@@ -10167,6 +10209,7 @@ vt_initialize (void)
 			    }
 			}
 		    }
+		  BLOCK_FOR_INSN (insn) = save_bb;
 		}
 	    }
 	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
@@ -10207,7 +10250,10 @@ 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))
 	  {
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (2 preceding siblings ...)
  2017-09-01  1:15             ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
@ 2017-09-01  1:16             ` Alexandre Oliva
  2017-09-01  1:16             ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
                               ` (5 subsequent siblings)
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

The inline_entry hook will be given a definition in a later patch.

for  gcc/ChangeLog

	* 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.
	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
	(dwarf2_lineno_debug_hooks): Likewise.
---
 gcc/dbxout.c    | 2 ++
 gcc/debug.c     | 1 +
 gcc/debug.h     | 3 +++
 gcc/dwarf2out.c | 2 ++
 gcc/sdbout.c    | 1 +
 gcc/vmsdbgout.c | 1 +
 6 files changed, 10 insertions(+)

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/dwarf2out.c b/gcc/dwarf2out.c
index ff97715..839b153 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2766,6 +2766,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
+  debug_nothing_tree,		/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -2804,6 +2805,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 */
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/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 */
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 7/9] [LVU] Introduce location views
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (7 preceding siblings ...)
  2017-09-01  1:16             ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
@ 2017-09-01  1:16             ` Alexandre Oliva
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-01  1:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch introduces an option to enable the generation of location
views along with location lists.  The exact format depends on the
DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
(DW_LLE_view_pair) entries in DWARF5+ loclists.

Line number tables are also affected.  If the assembler is found, at
compiler build time, to support .loc views, we use them and
assembler-computed view labels, otherwise we output compiler-generated
line number programs with conservatively-computed view labels.  In
either case, we output view information next to line number changes
when verbose assembly output is requested.

This patch requires an LVU patch that modifies the exported API of
final_scan_insn.  It also expects the entire SFN patchset to be
installed first, although SFN is not a requirement for LVU.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_locviews): New.
	* dwarf2.h (enum dwarf_location_list_entry_type): Add
	DW_LLE_GNU_view_pair.
	(DW_LLE_view_pair): Define.

for  gcc/ChangeLog

	* common.opt (gvariable-location-views): New.
	* config.in: Rebuilt.
	* configure: Rebuilt.
	* configure.ac: Test assembler for view support.
	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
	* dwarf2out.c (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.
	(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.
	(maybe_emit_file): Call output_asm_line_debug_info for test.
	(dwarf2out_var_location): Reset views as needed.  Precompute
	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
	attribute.  Set view.
	(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.
	Use output_dwarf_version.
	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
	(struct dw_val_node): Add val_view_list.
	* final.c: Include langhooks.h.
	(SEEN_NEXT_VIEW): New.
	(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.  Notify debug backend of section
	changes, and of location view changes.
	(rest_of_handle_final): Adjust.
	* opts.c (common_handle_option): Accept -gdwarf version 6.
	* toplev.c (process_options): Autodetect value for debug variable
	location views option.
	* doc/invoke.texi (gvariable-location-views): New.
	(gno-variable-location-views): New.
---
 gcc/common.opt      |   4 +
 gcc/config.in       |   6 +
 gcc/configure       |  46 ++++
 gcc/configure.ac    |  18 +-
 gcc/doc/invoke.texi |  19 ++
 gcc/dwarf2asm.c     |  25 ++
 gcc/dwarf2asm.h     |   4 +
 gcc/dwarf2out.c     | 645 ++++++++++++++++++++++++++++++++++++++++++++++------
 gcc/dwarf2out.h     |   4 +-
 gcc/final.c         | 125 +++++++++-
 gcc/opts.c          |   2 +-
 gcc/toplev.c        |   8 +
 include/dwarf2.def  |   1 +
 include/dwarf2.h    |   8 +
 14 files changed, 833 insertions(+), 82 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index b0748a2..e4ab189 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2886,6 +2886,10 @@ gtoggle
 Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
+gvariable-location-views
+Common Driver Var(debug_variable_location_views) Init(2)
+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/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/doc/invoke.texi b/gcc/doc/invoke.texi
index 082f122..588bd6b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -345,6 +345,7 @@ Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gcolumn-info  -gno-column-info @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
@@ -7000,6 +7001,24 @@ 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.
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 71c4739..ff97715 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1275,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.  */
@@ -1284,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.  */
@@ -1323,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.  */
@@ -1398,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:
@@ -2835,7 +2866,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 {
@@ -2857,6 +2896,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;
 };
 
@@ -3055,6 +3113,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
@@ -3164,6 +3257,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.  */
@@ -3372,6 +3466,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);
@@ -3408,7 +3504,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);
@@ -3616,8 +3712,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);
@@ -4539,11 +4635,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>
@@ -5605,7 +5745,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;
@@ -5696,7 +5836,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.  */
@@ -5712,7 +5852,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
 	    {
@@ -5847,6 +5987,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;
@@ -8946,6 +9092,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);
@@ -9317,6 +9464,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)
@@ -9612,7 +9760,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> ();
@@ -9622,10 +9771,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.  */
 
@@ -9634,6 +9801,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.  */
@@ -9641,34 +9901,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,
@@ -9686,6 +9997,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
@@ -9736,6 +10048,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);
@@ -9750,6 +10063,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);
@@ -9765,6 +10079,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);
@@ -9843,6 +10158,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
@@ -9907,6 +10225,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
@@ -10137,6 +10471,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))
 	    {
@@ -10309,6 +10647,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.  */
 
@@ -10325,7 +10685,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;
@@ -10514,7 +10874,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");
@@ -10813,7 +11173,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,
@@ -10895,7 +11255,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,
@@ -11156,7 +11516,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
@@ -11790,8 +12150,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)
     {
@@ -11806,14 +12169,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)
 	    {
@@ -11921,7 +12306,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");
@@ -16214,6 +16599,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;
@@ -16269,24 +16655,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)
@@ -16309,12 +16698,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;
 	      }
 	  }
@@ -16326,8 +16715,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;
 }
@@ -17147,7 +17535,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;
     }
@@ -17960,7 +18348,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;
 }
@@ -18284,12 +18672,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.  */
@@ -19459,7 +19860,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;
     }
@@ -19475,7 +19876,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;
@@ -19497,14 +19898,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;
 	}
@@ -19513,19 +19914,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;
 }
@@ -25922,7 +26322,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,
@@ -26115,11 +26515,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++;
@@ -26153,6 +26555,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
 		}
 	    }
 	}
+      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;
     }
 
@@ -26216,10 +26630,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;
     }
@@ -26260,8 +26675,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
@@ -26329,7 +26744,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)
@@ -26338,6 +26756,7 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      newloc->view = view;
     }
 
   if (var_loc_p && flag_debug_asm)
@@ -26404,6 +26823,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;
 }
@@ -26452,7 +26872,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);
@@ -26633,7 +27053,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",
@@ -26659,6 +27079,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
@@ -26667,7 +27114,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)
@@ -27256,7 +27715,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);
 
@@ -27641,6 +28100,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.
@@ -28740,6 +29204,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)
@@ -28784,7 +29250,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)
@@ -28854,6 +29320,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);
@@ -28879,6 +29346,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);
@@ -29275,6 +29757,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);
@@ -29496,6 +29980,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;
@@ -29514,6 +29999,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)
@@ -29524,11 +30011,33 @@ 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));
 }
 
@@ -29553,7 +30062,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
@@ -29930,7 +30439,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,
@@ -29988,7 +30497,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/final.c b/gcc/final.c
index 15a301b..4ca4aaa 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;
@@ -1759,6 +1761,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
@@ -1766,12 +1806,15 @@ 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 **firstp, 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;
 
@@ -1792,7 +1835,28 @@ final_start_function (rtx_insn **firstp, 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);
@@ -1867,6 +1931,17 @@ final_start_function (rtx_insn **firstp, 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)
 {
@@ -1998,11 +2073,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;
@@ -2069,6 +2143,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);
@@ -2085,6 +2161,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);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2224,6 +2308,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 ())
@@ -2364,6 +2450,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
@@ -2421,7 +2509,10 @@ 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:
@@ -2432,6 +2523,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
 					   last_filename, last_discriminator,
 					   true);
+	      clear_next_view_needed (seen);
 	    }
 	  break;
 
@@ -2628,6 +2720,10 @@ 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
@@ -2640,7 +2736,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    (*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)
@@ -3107,7 +3208,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;
@@ -4547,8 +4649,9 @@ rest_of_handle_final (void)
 
   assemble_start_function (current_function_decl, fnname);
   rtx_insn *first = get_insns ();
-  final_start_function (&first, asm_out_file, optimize);
-  final (first, asm_out_file, optimize);
+  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 ();
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/toplev.c b/gcc/toplev.c
index dea6f82..cf6d3e6 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1538,6 +1538,14 @@ process_options (void)
     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/include/dwarf2.def b/include/dwarf2.def
index a91e943..d4fbcb3 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* 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,
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-08-25 16:41           ` Alexandre Oliva
@ 2017-09-07 21:44             ` Joseph Myers
  2017-09-21  2:24               ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Joseph Myers @ 2017-09-07 21:44 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Richard Biener, GCC Patches

On Fri, 25 Aug 2017, Alexandre Oliva wrote:

> for  gcc/ChangeLog
> 
> 	* common.opt (Wa, Wl, Wp, g, gz=): Add
> 	RejectNegative.
> 	(gno-column-info): Remove.
> 	(gcolumn-info): Drop RejectNegative.
> 	(gno-): New prefix.
> 	(gno-record-gcc-switches): Remove.
> 	(grecord-gcc-switches): Drop RejectNegative.
> 	(gno-split-dwarf): Remove.
> 	(gsplit-dwarf): Drop RejectNegative.
> 	(gno-strict-dwarf): Remove.
> 	(gstrict-dwarf): Drop RejectNegative.
> 	* config/darwin.opt (gfull, gused): Add RejectNegative.
> 	* dwarf2out.c (gen_producer_string): Drop
> 	gno-record-gcc-switches handler.
> 	* optc-gen.awk: Add g to prefixes with negative forms.
> 	* opts-common.c (remapping_prefix_p): New.
> 	(find_opt): Check it.
> 	(generate_canonical_option): Test g prefix.
> 	(option_map): Add -gno- mapping.
> 	(add_misspelling_candidates): Check remapping_prefix_p.
> 
> for  gcc/ada/ChangeLog
> 
> 	* gcc-interface/lang.opt (gant, gnatO, gnat): Add
>         RejectNegative.
> 
> for  gcc/c-family/ChangeLog
> 
> 	* c.opt (gen-decls): Add RejectNegative.

OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-09-07 21:44             ` Joseph Myers
@ 2017-09-21  2:24               ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-21  2:24 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Richard Biener, GCC Patches

On Sep  7, 2017, Joseph Myers <joseph@codesourcery.com> wrote:

> On Fri, 25 Aug 2017, Alexandre Oliva wrote:
>> for  gcc/ChangeLog
>> 
>> * common.opt (Wa, Wl, Wp, g, gz=): Add
>> RejectNegative.
>> (gno-column-info): Remove.
>> (gcolumn-info): Drop RejectNegative.
>> (gno-): New prefix.
[...]

> OK.

Thanks, I've finally checked this in.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers
  2017-09-01  1:07           ` Alexandre Oliva
                               ` (8 preceding siblings ...)
  2017-09-01  1:16             ` [PATCH 7/9] [LVU] Introduce location views Alexandre Oliva
@ 2017-09-30  9:04             ` Alexandre Oliva
  2017-09-30  9:09               ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
                                 ` (9 more replies)
  9 siblings, 10 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:04 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 1/9] [SFN] adjust RTL insn-walking API
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
@ 2017-09-30  9:09               ` Alexandre Oliva
  2017-10-09 13:24                 ` Richard Biener
  2017-09-30  9:09               ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
                                 ` (8 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch removes unused RTL functions, introduces alternate ones for
use in a later SFN patch, and regroups other related functions so that
they appear in a more consistent order.

for  gcc/ChangeLog

	* 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.
	* rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
	(prev_nonnote_nondebug_insn_bb): Declare.
	(next_nonnote_nondebug_insn_bb): Declare.
	* cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
	* cfgrtl.c (get_last_bb_insn): Likewise.
	* lra.c (push_insns): Likewise.
---
 gcc/cfgbuild.c |  2 +-
 gcc/cfgrtl.c   |  4 ++--
 gcc/emit-rtl.c | 69 ++++++++++++++++++++++++++++++++--------------------------
 gcc/lra.c      |  2 +-
 gcc/rtl.h      |  4 ++--
 5 files changed, 44 insertions(+), 37 deletions(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 62956b2..76c21d7 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -512,7 +512,7 @@ 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))
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 6ef47b7..bce56b4 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -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;
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index e790cbc..68c1f11 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -3355,20 +3355,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;
@@ -3390,67 +3387,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;
     }
@@ -3458,17 +3458,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/lra.c b/gcc/lra.c
index a473777..9037495 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1810,7 +1810,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/rtl.h b/gcc/rtl.h
index a63f33e..3bda77c 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2980,13 +2980,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 *);
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (3 preceding siblings ...)
  2017-09-30  9:09               ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
@ 2017-09-30  9:09               ` Alexandre Oliva
  2017-10-19 11:07                 ` Richard Biener
  2017-10-31  5:23                 ` Jeff Law
  2017-09-30  9:10               ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
                                 ` (4 subsequent siblings)
  9 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This API change will enable final_start_function() to "consume"
initial insns, and choose the first insn to be passed to final().

Many ports call final_start_function() and final() when creating
thunks and whatnot, so they needed adjusting.

for  gcc/ChangeLog

	* output.h (final_start_function): Adjust.
	* final.c (final_start_function): Take pointer to FIRST.
	(rest_of_handle_final): Adjust.
	* 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.
---
 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/final.c                        | 9 ++++++---
 gcc/output.h                       | 2 +-
 21 files changed, 37 insertions(+), 26 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 23f5aff..73872dd 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -3961,7 +3961,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 41f3e3a..56b6f04 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -8480,7 +8480,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 4cddf3b..9301d58 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -26410,7 +26410,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)
     {
@@ -26587,7 +26588,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 fe80a27..3581d2d 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -2755,7 +2755,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 98fb1ce..d4d9490 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -12499,8 +12499,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).  */
@@ -43001,7 +43002,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 fce3006..a94ab67 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -11035,7 +11035,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 cd2e15e..48b9c4a 100644
--- a/gcc/config/m68k/m68k.c
+++ b/gcc/config/m68k/m68k.c
@@ -5142,7 +5142,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 53ca016..4ebe023 100644
--- a/gcc/config/microblaze/microblaze.c
+++ b/gcc/config/microblaze/microblaze.c
@@ -3257,7 +3257,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 4133375..d1f7bd8 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -19394,7 +19394,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 65095ff..f6d5f06 100644
--- a/gcc/config/nds32/nds32.c
+++ b/gcc/config/nds32/nds32.c
@@ -1633,7 +1633,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 2602605..6ab2c24 100644
--- a/gcc/config/nios2/nios2.c
+++ b/gcc/config/nios2/nios2.c
@@ -4061,7 +4061,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 5e945fc..418a017 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -8404,7 +8404,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 1e794a0..cf1a7bf 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -29699,7 +29699,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 ();
 
@@ -38165,7 +38165,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 52a82df..0bea709 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -13202,7 +13202,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 3c6d525..284fb81 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -10936,7 +10936,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 d3f002d..9432a66 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -12140,7 +12140,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 b9af9a9..d22cf3e 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -7045,7 +7045,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 63fe340..861577eca 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 ee9bc0a..e261400 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/final.c b/gcc/final.c
index 49cfbfb..d2b8523d 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1763,9 +1763,11 @@ get_some_local_dynamic_name ()
      test and compare insns.  */
 
 void
-final_start_function (rtx_insn *first, FILE *file,
+final_start_function (rtx_insn **firstp, FILE *file,
 		      int optimize_p ATTRIBUTE_UNUSED)
 {
+  rtx_insn *first = *firstp;
+
   block_depth = 0;
 
   this_is_asm_operands = 0;
@@ -4536,8 +4538,9 @@ rest_of_handle_final (void)
     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 ();
+  final_start_function (&first, asm_out_file, optimize);
+  final (first, asm_out_file, optimize);
   if (flag_ipa_ra
       && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
     collect_fn_hard_reg_usage ();
diff --git a/gcc/output.h b/gcc/output.h
index e98a911..62a405d 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'
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (2 preceding siblings ...)
  2017-09-30  9:09               ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-09-30  9:09               ` Alexandre Oliva
  2017-10-09 13:11                 ` Richard Biener
  2017-10-24 18:11                 ` Jason Merrill
  2017-09-30  9:09               ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
                                 ` (5 subsequent siblings)
  9 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch completes the infrastructure for the introduction of
statement frontiers in C-family languages.

It brings in all the code remaining code needed to introduce and
transform begin stmt trees, gimple stmts, insns and notes, and
ultimately use them to generate the is_stmt column in DWARF2+ line
number tables/programs, however none of it is activated: the option
that would do so will be introduced in a subsequent patch.

This patch depends on an earlier patch with not-quite-boilerplate
changes towards SFN.

for  gcc/c-family/ChangeLog

	* c-semantics.c (pop_stmt_list): Move begin stmt marker into
	subsequent statement list.

for  gcc/c/ChangeLog

	* c-objc-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
	* c-parser.c (add_debug_begin_stmt): New.
	(c_parser_declaration_or_fndef): Call it.
	(c_parser_compound_statement_nostart): Likewise.
	(c_parser_statement_after_labels): Likewise.
	* c-typeck (c_finish_stmt_expr): Skip begin stmts markers.

for  gcc/cp/ChangeLog

	* constexpr.c (build_data_member_initialization): Skip begin stmt
	markers.
	(check_constexpr_ctor_body_1): Likewise.
	(build_constexpr_constructor_member_initializers): Likewise.
	(constexpr_fn_retval): Likewise.
	(cxx_eval_statement_list): Likewise.
	(potential_constant_expression_1): Likewise.
	* cp-array-notation.c (stmt_location): New.
	(cp_expand_cond_array_notations): Use it.
	* cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
	* parser.c (add_debug_begin_stmt): New.
	(cp_parser_statement): Call it.
	* pt.c (tsubst_copy): Handle begin stmt markers.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
	markers.  Integrate source bind into debug stmt expand loop.
	(pass_expand::execute): Check debug marker limit.  Avoid deep
	TER and expand debug locations for debug bind insns only.
	* cse.c (insn_live_p): Keep nonbind markers and debug bindings
	followed by them.
	* df-scan.c (df_insn_delete): Accept out-of-block debug insn.
	* final.c (reemit_insn_block_notes): Take current block from
	nonbind markers.  Declare note where it's first set.
	(final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
	begin stmt markers if enabled.
	(notice_source_line): Handle nonbind markers.  Fail if their
	location is unknown or that of builtins.
	(rest_of_handle_final): Convert begin stmt markers to notes if
	var-tracking didn't run.
	(rest_of_clean_state): Skip begin stmt markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
	markers.
	* function.c (allocate_struct_function): Set begin_stmt_markers.
	* function.h (struct function): Add debug_marker_count counter
	and debug_nonbind_markers flag.
	* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
	* gimple-low.c (lower_function_body): Adjust
	debug_nonbind_markers.
	(lower_stmt): Drop or skip gimple debug stmts.
	(lower_try_catch): Skip debug stmts.
	* gimple.c (gimple_build_debug_begin_stmt): New.
	(gimple_copy): Increment debug_marker_count if copying one.
	* gimple.h (gimple_build_debug_begin_stmt): Declare.
	* gimplify.c (rexpr_location): New.
	(rexpr_has_location): New.
	(warn_switch_unreachable_r): Handle gimple debug stmts.
	(shortcut_cond_r): Call expr_location.
	(find_goto): New.
	(find_goto_label): New.
	(shortcut_cond_expr): Call expr_has_location, expr_location, and
	find_goto_label.
	(gimplify_cond_expr): Call find_goto_label, expr_has_location, and
	expr_location.
	(gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
	* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
	(LANG_HOOKS_INITIALIZER): ... this.
	* langhooks.h (struct lang_hooks): Add emits_begin_stmt.
	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
	debug insns.
	(update_ebb_live_info): Skip debug insn markers.
	* lra.c (debug_insn_static_data): Rename to...
	(debug_bind_static_data): ... this.
	(debug_marker_static_data): New.
	(lra_set_insn_recog_data): Select one of the above depending
	on debug insn kind.
	(lra_update_isn_regno_info): Don't assume debug insns have
	freqs.
	(push_insns): Skip debug insns.
	* lto-streamer-in.c (input_function): Drop debug stmts
	depending on active options.  Adjust debug_nonbind_markers.
	* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	begin stmt marker notes.
	(print_insn): Likewise.
	* recog.c (extract_insn): Recognize rtl for debug markers.
	* rtl.def (DEBUG_MARKER): New.
	* tree-inline.c: Include params.h.
	(remap_gimple_stmt): Handle nonbind markers.
	(maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.
	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
	markers regardless of no side effects.
	(tsi_link_before): Don't update container's side effects when adding
	a begin stmt marker.
	(tsi_link_after): Likewise.
	(expr_first): Skip begin stmt markers.
	(expr_last): Likewise.
	* tree-pretty-print (dump_generic_node): Handle begin stmt markers.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Disregard nonbind markers.
	* tree.c (make_node_stat): Don't set side effects for begin stmt
	markers.
	(build1_stat): Likewise.
	* tree.def (DEBUG_BEGIN_STMT): New.
	* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
	* var-tracking.c (delete_debug_insns): Renamed to...
	(delete_vta_debug_insns): ... this.
	(reemit_marker_as_note): New.
	(vt_initialize): Reemit markers.
	(delete_vta_debug_insns): Likewise.
	(vt_debug_insns_local): Reemit or delete markers.
	(variable_tracking_main_1): Likewise.
	* doc/generic.texi (DEBUG_BEGIN_STMT): Document.
	* doc/gimple.texi (gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	(gimple_build_debug_bind): Adjust.
	(gimple_build_debug_begin_stmt): New.
	* doc/invoke.texi (max-debug-marker-count): New param.
	* doc/rtl.texi (debug_implicit_ptr, entry_value): New.
	(debug_parameter_ref, debug_marker): New.
	(NOTE_INSN_BEGIN_STMT): New.
	(DEBUG_INSN): Describe begin stmt markers.
---
 gcc/c-family/c-semantics.c |  21 ++++++
 gcc/c/c-objc-common.h      |   2 +
 gcc/c/c-parser.c           |  20 ++++++
 gcc/c/c-typeck.c           |   8 ++-
 gcc/cfgexpand.c            | 113 +++++++++++++++++---------------
 gcc/cp/constexpr.c         |  11 ++++
 gcc/cp/cp-array-notation.c |  37 +++++++++--
 gcc/cp/cp-objcp-common.h   |   2 +
 gcc/cp/parser.c            |  14 ++++
 gcc/cp/pt.c                |   6 ++
 gcc/cse.c                  |   7 ++
 gcc/df-scan.c              |   2 +-
 gcc/doc/generic.texi       |   5 ++
 gcc/doc/gimple.texi        |  24 ++++++-
 gcc/doc/invoke.texi        |   7 ++
 gcc/doc/rtl.texi           |  53 ++++++++++++---
 gcc/final.c                |  89 +++++++++++++++++++------
 gcc/function.c             |   6 ++
 gcc/function.h             |  10 +++
 gcc/gimple-iterator.c      |   4 ++
 gcc/gimple-low.c           |  29 +++++++++
 gcc/gimple-pretty-print.c  |   7 ++
 gcc/gimple.c               |  24 +++++++
 gcc/gimple.h               |   1 +
 gcc/gimplify.c             | 158 +++++++++++++++++++++++++++++++++++----------
 gcc/langhooks-def.h        |   2 +
 gcc/langhooks.h            |   3 +
 gcc/lra-constraints.c      |  10 ++-
 gcc/lra.c                  |  36 +++++++++--
 gcc/lto-streamer-in.c      |  12 +++-
 gcc/params.def             |   9 +++
 gcc/print-rtl.c            |  24 +++++++
 gcc/recog.c                |   1 +
 gcc/rtl.def                |   3 +
 gcc/tree-inline.c          |  31 ++++++++-
 gcc/tree-iterator.c        |  48 +++++++++++---
 gcc/tree-pretty-print.c    |   4 ++
 gcc/tree-ssa-threadedge.c  |  25 ++++---
 gcc/tree.c                 |   8 ++-
 gcc/tree.def               |   3 +
 gcc/tree.h                 |   2 +-
 gcc/var-tracking.c         |  70 +++++++++++++++++---
 42 files changed, 793 insertions(+), 158 deletions(-)

diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 3ceb714..cd872d8 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -76,6 +76,27 @@ pop_stmt_list (tree t)
 	  free_stmt_list (t);
 	  t = u;
 	}
+      /* If the statement list contained a debug begin stmt and a
+	 statement list, move the debug begin stmt into the statement
+	 list and return it.  */
+      else if (!tsi_end_p (i)
+	       && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+	{
+	  u = tsi_stmt (i);
+	  tsi_next (&i);
+	  if (tsi_one_before_end_p (i)
+	      && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST)
+	    {
+	      tree l = tsi_stmt (i);
+	      tsi_prev (&i);
+	      tsi_delink (&i);
+	      tsi_delink (&i);
+	      i = tsi_start (l);
+	      free_stmt_list (t);
+	      t = l;
+	      tsi_link_before (&i, u, TSI_SAME_STMT);
+	    }
+	}
     }
 
   return t;
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index bee06e9..27ceabc 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
 #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
 #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
 
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index a36397b..aa70c91 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1640,6 +1640,19 @@ c_parser_external_declaration (c_parser *parser)
 static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
    6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
    is accepted; otherwise (old-style parameter declarations) only other
@@ -1740,6 +1753,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   bool diagnosed_no_specs = false;
   location_t here = c_parser_peek_token (parser)->location;
 
+  add_debug_begin_stmt (c_parser_peek_token (parser)->location);
+
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
     {
@@ -4949,6 +4964,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
   location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
   if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
     {
+      add_debug_begin_stmt (c_parser_peek_token (parser)->location);
       c_parser_consume_token (parser);
       return;
     }
@@ -5403,6 +5419,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
   parser->in_if_block = false;
   if (if_p != NULL)
     *if_p = false;
+
+  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+    add_debug_begin_stmt (loc);
+
   switch (c_parser_peek_token (parser)->type)
     {
     case CPP_OPEN_BRACE:
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 73e7460..33bd4b8 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10740,6 +10740,10 @@ c_finish_stmt_expr (location_t loc, tree body)
 	}
       else
 	i = tsi_last (last);
+      if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+	do
+	  tsi_prev (&i);
+	while (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT);
       last_p = tsi_stmt_ptr (i);
       last = *last_p;
     }
@@ -10759,7 +10763,9 @@ c_finish_stmt_expr (location_t loc, tree body)
 
   /* In the case that the BIND_EXPR is not necessary, return the
      expression out from inside it.  */
-  if (last == BIND_EXPR_BODY (body)
+  if ((last == BIND_EXPR_BODY (body)
+       /* Skip nested debug stmts.  */
+       || last == expr_first (BIND_EXPR_BODY (body)))
       && BIND_EXPR_VARS (body) == NULL)
     {
       /* Even if this looks constant, do not allow it in a constant
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 5a46b5e..c854ffd 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5635,39 +5635,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	  if (new_bb)
 	    return new_bb;
 	}
-      else if (gimple_debug_bind_p (stmt))
+      else if (is_gimple_debug (stmt))
 	{
 	  location_t sloc = curr_insn_location ();
 	  gimple_stmt_iterator nsi = gsi;
 
 	  for (;;)
 	    {
-	      tree var = gimple_debug_bind_get_var (stmt);
-	      tree value;
-	      rtx val;
+	      tree var;
+	      tree value = NULL_TREE;
+	      rtx val = NULL_RTX;
 	      machine_mode mode;
 
-	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
-		  && TREE_CODE (var) != LABEL_DECL
-		  && !target_for_debug_bind (var))
-		goto delink_debug_stmt;
+	      if (!gimple_debug_nonbind_marker_p (stmt))
+		{
+		  if (gimple_debug_bind_p (stmt))
+		    {
+		      var = gimple_debug_bind_get_var (stmt);
 
-	      if (gimple_debug_bind_has_value_p (stmt))
-		value = gimple_debug_bind_get_value (stmt);
-	      else
-		value = NULL_TREE;
+		      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+			  && TREE_CODE (var) != LABEL_DECL
+			  && !target_for_debug_bind (var))
+			goto delink_debug_stmt;
 
-	      last = get_last_insn ();
+		      if (DECL_P (var))
+			mode = DECL_MODE (var);
+		      else
+			mode = TYPE_MODE (TREE_TYPE (var));
 
-	      set_curr_insn_location (gimple_location (stmt));
+		      if (gimple_debug_bind_has_value_p (stmt))
+			value = gimple_debug_bind_get_value (stmt);
+
+		      val = gen_rtx_VAR_LOCATION
+			(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+		    }
+		  else if (gimple_debug_source_bind_p (stmt))
+		    {
+		      var = gimple_debug_source_bind_get_var (stmt);
+
+		      value = gimple_debug_source_bind_get_value (stmt);
+
+		      mode = DECL_MODE (var);
 
-	      if (DECL_P (var))
-		mode = DECL_MODE (var);
+		      val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+						  VAR_INIT_STATUS_UNINITIALIZED);
+		    }
+		  else
+		    gcc_unreachable ();
+		}
+	      /* If this function was first compiled with markers
+		 enabled, but they're now disable (e.g. LTO), drop
+		 them on the floor.  */
+	      else if (gimple_debug_nonbind_marker_p (stmt)
+		       && !MAY_HAVE_DEBUG_MARKER_INSNS)
+		goto delink_debug_stmt;
+	      else if (gimple_debug_begin_stmt_p (stmt))
+		val = gen_rtx_DEBUG_MARKER (VOIDmode);
 	      else
-		mode = TYPE_MODE (TREE_TYPE (var));
+		gcc_unreachable ();
 
-	      val = gen_rtx_VAR_LOCATION
-		(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+	      last = get_last_insn ();
+
+	      set_curr_insn_location (gimple_location (stmt));
 
 	      emit_debug_insn (val);
 
@@ -5675,9 +5704,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		{
 		  /* We can't dump the insn with a TREE where an RTX
 		     is expected.  */
-		  PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    {
+		      gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);
+		      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		    }
 		  maybe_dump_rtl_for_gimple_stmt (stmt, last);
-		  PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    PAT_VAR_LOCATION_LOC (val) = (rtx)value;
 		}
 
 	    delink_debug_stmt:
@@ -5693,42 +5727,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	      if (gsi_end_p (nsi))
 		break;
 	      stmt = gsi_stmt (nsi);
-	      if (!gimple_debug_bind_p (stmt))
+	      if (!is_gimple_debug (stmt))
 		break;
 	    }
 
 	  set_curr_insn_location (sloc);
 	}
-      else if (gimple_debug_source_bind_p (stmt))
-	{
-	  location_t sloc = curr_insn_location ();
-	  tree var = gimple_debug_source_bind_get_var (stmt);
-	  tree value = gimple_debug_source_bind_get_value (stmt);
-	  rtx val;
-	  machine_mode mode;
-
-	  last = get_last_insn ();
-
-	  set_curr_insn_location (gimple_location (stmt));
-
-	  mode = DECL_MODE (var);
-
-	  val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
-				      VAR_INIT_STATUS_UNINITIALIZED);
-
-	  emit_debug_insn (val);
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      /* We can't dump the insn with a TREE where an RTX
-		 is expected.  */
-	      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
-	      maybe_dump_rtl_for_gimple_stmt (stmt, last);
-	      PAT_VAR_LOCATION_LOC (val) = (rtx)value;
-	    }
-
-	  set_curr_insn_location (sloc);
-	}
       else
 	{
 	  gcall *call_stmt = dyn_cast <gcall *> (stmt);
@@ -6367,6 +6371,11 @@ pass_expand::execute (function *fun)
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
     e->flags &= ~EDGE_EXECUTABLE;
 
+  /* If the function has too many markers, drop them while expanding.  */
+  if (cfun->debug_marker_count
+      >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+    cfun->debug_nonbind_markers = false;
+
   lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
   FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
 		  next_bb)
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index a89ee49..f9209ac 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
       tree_stmt_iterator i;
       for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
 	{
+	  if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+	    /* ??? Can we retain this information somehow?  */
+	    continue;
 	  if (! build_data_member_initialization (tsi_stmt (i), vec))
 	    return false;
 	}
@@ -448,6 +451,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
 
     case USING_STMT:
     case STATIC_ASSERT:
+    case DEBUG_BEGIN_STMT:
       return true;
 
     default:
@@ -586,6 +590,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
       tree_stmt_iterator i;
       for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
 	{
+	  if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+	    /* ??? Can we retain this information somehow?  */
+	    continue;
 	  ok = build_data_member_initialization (tsi_stmt (i), &vec);
 	  if (!ok)
 	    break;
@@ -673,6 +680,7 @@ constexpr_fn_retval (tree body)
       return constexpr_fn_retval (BIND_EXPR_BODY (body));
 
     case USING_STMT:
+    case DEBUG_BEGIN_STMT:
       return NULL_TREE;
 
     default:
@@ -3783,6 +3791,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
   for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
     {
       tree stmt = tsi_stmt (i);
+      if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
+	continue;
       r = cxx_eval_constant_expression (ctx, stmt, false,
 					non_constant_p, overflow_p,
 					jump_target);
@@ -5119,6 +5129,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case CONTINUE_STMT:
     case REQUIRES_EXPR:
     case STATIC_ASSERT:
+    case DEBUG_BEGIN_STMT:
       return true;
 
     case PARM_DECL:
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index 31be7d6..17f0b35c 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -780,6 +780,31 @@ error:
   return error_mark_node;
 }
 
+/* Return a location associated with stmt.  If it is an expresion,
+   that's the expression's location.  If it is a STATEMENT_LIST,
+   instead of no location, use expr_first to skip any debug stmts and
+   take the location of the first nondebug stmt found.  */
+
+static location_t
+stmt_location (tree stmt)
+{
+  location_t loc = UNKNOWN_LOCATION;
+
+  if (!stmt)
+    return loc;
+
+  loc = EXPR_LOCATION (stmt);
+
+  if (loc != UNKNOWN_LOCATION || TREE_CODE (stmt) != STATEMENT_LIST)
+    return loc;
+
+  stmt = expr_first (stmt);
+  if (stmt)
+    loc = EXPR_LOCATION (stmt);
+
+  return loc;
+}
+
 /* Helper function for expand_conditonal_array_notations.  Encloses the
    conditional statement passed in ORIG_STMT with a loop around it and
    replaces the condition in STMT with a ARRAY_REF tree-node to the array.  
@@ -835,10 +860,12 @@ cp_expand_cond_array_notations (tree orig_stmt)
       tree cond = IF_COND (orig_stmt);
       if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
 	  || (yes_expr
-	      && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
+	      && !find_rank (stmt_location (yes_expr),
+			     yes_expr, yes_expr, true,
 			     &yes_rank))
 	  || (no_expr
-	      && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
+	      && !find_rank (stmt_location (no_expr),
+			     no_expr, no_expr, true,
 			     &no_rank)))
 	return error_mark_node;
 
@@ -847,13 +874,15 @@ cp_expand_cond_array_notations (tree orig_stmt)
 	return orig_stmt;
       else if (cond_rank != yes_rank && yes_rank != 0)
 	{
-	  error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
+	  error_at (stmt_location (yes_expr),
+		    "rank mismatch with controlling"
 		    " expression of parent if-statement");
 	  return error_mark_node;
 	}
       else if (cond_rank != no_rank && no_rank != 0)
 	{
-	  error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
+	  error_at (stmt_location (no_expr),
+		    "rank mismatch with controlling "
 		    "expression of parent if-statement");
 	  return error_mark_node;
 	}
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 3e4cc9c5..c1c82b6 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -105,6 +105,8 @@ extern void cp_register_dumps (gcc::dump_manager *);
 #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
 #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
 #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
 
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6e817cb..1b31182 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10661,6 +10661,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 
 /* Statements [gram.stmt.stmt]  */
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a statement.
 
    statement:
@@ -10736,6 +10749,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
   token = cp_lexer_peek_token (parser->lexer);
   /* Remember the location of the first token in the statement.  */
   statement_location = token->location;
+  add_debug_begin_stmt (statement_location);
   /* If this is a keyword, then that will often determine what kind of
      statement we have.  */
   if (token->type == CPP_KEYWORD)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c29c779..4714b53 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15289,6 +15289,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case PREDICT_EXPR:
       return t;
 
+    case DEBUG_BEGIN_STMT:
+      /* ??? There's no point in copying it for now, but maybe some
+	 day it will contain more information, such as a pointer back
+	 to the containing function, inlined copy or so.  */
+      return t;
+
     default:
       /* We shouldn't get here, but keep going if !flag_checking.  */
       if (flag_checking)
diff --git a/gcc/cse.c b/gcc/cse.c
index d1577a6..bb9b317 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -6967,11 +6967,18 @@ insn_live_p (rtx_insn *insn, int *counts)
     {
       rtx_insn *next;
 
+      if (DEBUG_MARKER_INSN_P (insn))
+	return true;
+
       for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
 	if (NOTE_P (next))
 	  continue;
 	else if (!DEBUG_INSN_P (next))
 	  return true;
+	/* If we find an inspection point, such as a debug begin stmt,
+	   we want to keep the earlier debug insn.  */
+	else if (DEBUG_MARKER_INSN_P (next))
+	  return true;
 	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
 	  return false;
 
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 8ab3d71..429dab8 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -945,7 +945,7 @@ df_insn_delete (rtx_insn *insn)
      In any case, we expect BB to be non-NULL at least up to register
      allocation, so disallow a non-NULL BB up to there.  Not perfect
      but better than nothing...  */
-  gcc_checking_assert (bb != NULL || reload_completed);
+  gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed);
 
   df_grow_bb_info (df_scan);
   df_grow_reg_info ();
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index a51cfd6e..a13bce9 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -1930,6 +1930,11 @@ case 2 ... 5:
 The first value will be @code{CASE_LOW}, while the second will be
 @code{CASE_HIGH}.
 
+@item DEBUG_BEGIN_STMT
+
+Marks the beginning of a source statement, for purposes of debug
+information generation.
+
 @end table
 
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 635abd39..6c9c4789 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -831,6 +831,16 @@ expression to a variable.
 Return true if g is any of the OpenMP codes.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
+a source statement.
+@end deftypefn
+
+@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
+without any variable binding.
+@end deftypefn
+
 @node Manipulating GIMPLE statements
 @section Manipulating GIMPLE statements
 @cindex Manipulating GIMPLE statements
@@ -1528,10 +1538,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @subsection @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
+@cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
-Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of
+Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND}
 @code{subcode}.  The effect of this statement is to tell debug
 information generation machinery that the value of user variable
 @code{var} is given by @code{value} at that point, and to remain with
@@ -1602,6 +1613,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
 and @code{FALSE} if it unbinds the variable.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that the
+user statement at the given @code{location} and @code{block} starts at
+the point at which the statement is inserted.  The intent is that side
+effects (e.g. variable bindings) of all prior user statements are
+observable, and that none of the side effects of subsequent user
+statements are.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f862b7f..108d730 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10480,6 +10480,13 @@ debug information may end up not being used; setting this higher may
 enable the compiler to find more complex debug expressions, but compile
 time and memory use may grow.  The default is 12.
 
+@item max-debug-marker-count
+Sets a threshold on the number of debug markers (e.g. begin stmt
+markers) to avoid complexity explosion at inlining or expanding to RTL.
+If a function has more such gimple stmts than the set limit, such stmts
+will be dropped from the inlined copy of a function, and from its RTL
+expansion.  The default is 100000.
+
 @item min-nondebug-insn-uid
 Use uids starting at this parameter for nondebug insns.  The range below
 the parameter is reserved exclusively for debug insns created by
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 3b2b247..888ab02 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3413,6 +3413,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},
 that points back to it, within value expressions in
 @code{VAR_LOCATION} nodes.
 
+@findex debug_implicit_ptr
+@item (debug_implicit_ptr:@var{mode} @var{decl})
+Stands for the location of a @var{decl} that is no longer addressable.
+
+@findex entry_value
+@item (entry_value:@var{mode} @var{decl})
+Stands for the value a @var{decl} had at the entry point of the
+containing function.
+
+@findex debug_parameter_ref
+@item (debug_parameter_ref:@var{mode} @var{decl})
+Refers to a parameter that was completely optimized out.
+
+@findex debug_marker
+@item (debug_marker:@var{mode})
+Marks a program location.  With @code{VOIDmode}, it stands for the
+beginning of a statement, a recommended inspection point logically after
+all prior side effects, and before any subsequent side effects.
+
 @end table
 
 @node Insns
@@ -3689,6 +3708,12 @@ can be computed by evaluating the RTL expression from that static
 point in the program up to the next such note for the same user
 variable.
 
+@findex NOTE_INSN_BEGIN_STMT
+@item NOTE_INSN_BEGIN_STMT
+This note is used to generate @code{is_stmt} markers in line number
+debuggign information.  It indicates the beginning of a user
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3706,15 +3731,25 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-Throughout optimization passes, binding information is kept in
-pseudo-instruction form, so that, unlike notes, it gets the same
-treatment and adjustments that regular instructions would.  It is the
-variable tracking pass that turns these pseudo-instructions into var
-location notes, analyzing control flow, value equivalences and changes
-to registers and memory referenced in value expressions, propagating
-the values of debug temporaries and determining expressions that can
-be used to compute the value of each user variable at as many points
-(ranges, actually) in the program as possible.
+@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
+with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
+just @code{DEBUG_MARKER}s, can be detected by testing
+@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
+@code{DEBUG_BIND_INSN_P}.
+
+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
+with respect to each other, particularly during scheduling.  Binding
+information is kept in pseudo-instruction form, so that, unlike notes,
+it gets the same treatment and adjustments that regular instructions
+would.  It is the variable tracking pass that turns these
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
+@code{NOTE_INSN_BEGIN_STMT} notes,
+analyzing control flow, value equivalences and changes to registers and
+memory referenced in value expressions, propagating the values of debug
+temporaries and determining expressions that can be used to compute the
+value of each user variable at as many points (ranges, actually) in the
+program as possible.
 
 Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
 @code{INSN_VAR_LOCATION} denotes a value at that specific point in the
diff --git a/gcc/final.c b/gcc/final.c
index eff2ee6..49cfbfb 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1646,7 +1646,6 @@ reemit_insn_block_notes (void)
 {
   tree cur_block = DECL_INITIAL (cfun->decl);
   rtx_insn *insn;
-  rtx_note *note;
 
   insn = get_insns ();
   for (; insn; insn = NEXT_INSN (insn))
@@ -1654,17 +1653,29 @@ reemit_insn_block_notes (void)
       tree this_block;
 
       /* Prevent lexical blocks from straddling section boundaries.  */
-      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
-        {
-          for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
-               s = BLOCK_SUPERCONTEXT (s))
-            {
-              rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
-              NOTE_BLOCK (note) = s;
-              note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
-              NOTE_BLOCK (note) = s;
-            }
-        }
+      if (NOTE_P (insn))
+	switch (NOTE_KIND (insn))
+	  {
+	  case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+	    {
+	      for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
+		   s = BLOCK_SUPERCONTEXT (s))
+		{
+		  rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+		  NOTE_BLOCK (note) = s;
+		  note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
+		  NOTE_BLOCK (note) = s;
+		}
+	    }
+	    break;
+
+	  case NOTE_INSN_BEGIN_STMT:
+	    this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
+	    goto set_cur_block_to_this_block;
+
+	  default:
+	    continue;
+	}
 
       if (!active_insn_p (insn))
         continue;
@@ -1685,6 +1696,7 @@ reemit_insn_block_notes (void)
 	    this_block = choose_inner_scope (this_block,
 					     insn_scope (body->insn (i)));
 	}
+    set_cur_block_to_this_block:
       if (! this_block)
 	{
 	  if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
@@ -1701,7 +1713,7 @@ reemit_insn_block_notes (void)
     }
 
   /* change_scope emits before the insn, not after.  */
-  note = emit_note (NOTE_INSN_DELETED);
+  rtx_note *note = emit_note (NOTE_INSN_DELETED);
   change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
   delete_insn (note);
 
@@ -2404,6 +2416,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    debug_hooks->var_location (insn);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+	  gcc_checking_assert (cfun->debug_nonbind_markers);
+	  if (!DECL_IGNORED_P (current_function_decl)
+	      && notice_source_line (insn, NULL))
+	    {
+	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
+					   last_filename, last_discriminator,
+					   true);
+	    }
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	  break;
@@ -2490,7 +2513,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	rtx body = PATTERN (insn);
 	int insn_code_number;
 	const char *templ;
-	bool is_stmt;
+	bool is_stmt, *is_stmt_p;
+
+	if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
+	  {
+	    is_stmt = false;
+	    is_stmt_p = NULL;
+	  }
+	else
+	  is_stmt_p = &is_stmt;
 
 	/* Reset this early so it is correct for ASM statements.  */
 	current_insn_predicate = NULL_RTX;
@@ -2593,7 +2624,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	/* Output this line note if it is the first or the last line
 	   note in a row.  */
 	if (!DECL_IGNORED_P (current_function_decl)
-	    && notice_source_line (insn, &is_stmt))
+	    && notice_source_line (insn, is_stmt_p))
 	  {
 	    if (flag_verbose_asm)
 	      asm_show_source (last_filename, last_linenum);
@@ -3086,7 +3117,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   const char *filename;
   int linenum, columnnum;
 
-  if (override_filename)
+  if (NOTE_MARKER_P (insn))
+    {
+      location_t loc = NOTE_MARKER_LOCATION (insn);
+      expanded_location xloc = expand_location (loc);
+      if (xloc.line == 0)
+	{
+	  gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
+			       || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
+	  return false;
+	}
+      filename = xloc.file;
+      linenum = xloc.line;
+      columnnum = xloc.column;
+      force_source_line = true;
+    }
+  else if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
@@ -3119,7 +3165,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       last_linenum = linenum;
       last_columnnum = columnnum;
       last_discriminator = discriminator;
-      *is_stmt = true;
+      if (is_stmt)
+	*is_stmt = true;
       high_block_linenum = MAX (last_linenum, high_block_linenum);
       high_function_linenum = MAX (last_linenum, high_function_linenum);
       return true;
@@ -3131,7 +3178,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
          output the line table entry with is_stmt false so the
          debugger does not treat this as a breakpoint location.  */
       last_discriminator = discriminator;
-      *is_stmt = false;
+      if (is_stmt)
+	*is_stmt = false;
       return true;
     }
 
@@ -4483,6 +4531,10 @@ rest_of_handle_final (void)
 {
   const char *fnname = get_fnname_from_decl (current_function_decl);
 
+  /* Turn debug markers into notes.  */
+  if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)
+    variable_tracking_main ();
+
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
@@ -4670,6 +4722,7 @@ rest_of_clean_state (void)
       if (final_output
 	  && (!NOTE_P (insn) ||
 	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
 	       && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
diff --git a/gcc/function.c b/gcc/function.c
index ae61d3d..468dc9a 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4933,6 +4933,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
     }
+
+  /* Don't enable begin stmt markers if var-tracking at assignments is
+     disabled.  The markers make little sense without the variable
+     binding annotations among them.  */
+  cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
+    && MAY_HAVE_DEBUG_MARKER_STMTS;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 76434cd..1186116 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -284,6 +284,12 @@ struct GTY(()) function {
   /* Last statement uid.  */
   int last_stmt_uid;
 
+  /* Debug marker counter.  Count begin stmt markers.  We don't have
+     to keep it exact, it's more of a rough estimate to enable us to
+     decide whether they are too many to copy during inlining, or when
+     expanding to RTL.  */
+  int debug_marker_count;
+
   /* Function sequence number for profiling, debugging, etc.  */
   int funcdef_no;
 
@@ -387,6 +393,10 @@ struct GTY(()) function {
 
   /* Set when the tail call has been identified.  */
   unsigned int tail_call_marked : 1;
+
+  /* Set when the function was compiled with generation of debug
+     (begin stmt, inline entry, ...) markers enabled.  */
+  unsigned int debug_nonbind_markers : 1;
 };
 
 /* Add the decl D to the local_decls list of FUN.  */
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index fb75f99..2359760 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
 
   if (remove_permanently)
     {
+      if (gimple_debug_nonbind_marker_p (stmt))
+	/* We don't need this to be exact, but try to keep it at least
+	   close.  */
+	cfun->debug_marker_count--;
       require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
       gimple_remove_stmt_histograms (cfun, stmt);
     }
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 22db61b..95f3f45 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -110,6 +110,17 @@ lower_function_body (void)
 
   i = gsi_last (lowered_body);
 
+  /* If we had begin stmt markers from e.g. PCH, but this compilation
+     doesn't want them, lower_stmt will have cleaned them up; we can
+     now clear the flag that indicates we had them.  */
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
+    {
+      /* This counter needs not be exact, but before lowering it will
+	 most certainly be.  */
+      gcc_assert (cfun->debug_marker_count == 0);
+      cfun->debug_nonbind_markers = false;
+    }
+
   /* If the function falls off the end, we need a null return statement.
      If we've already got one in the return_statements vector, we don't
      need to do anything special.  Otherwise build one by hand.  */
@@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (cfun->debug_nonbind_markers);
+      /* We can't possibly have debug bind stmts before lowering, we
+	 first emit them when entering SSA.  */
+      gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
+      /* Propagate fallthruness.  */
+      /* If the function (e.g. from PCH) had debug stmts, but they're
+	 disabled for this compilation, remove them.  */
+      if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+	gsi_remove (gsi, true);
+      else
+	gsi_next (gsi);
+      return;
+
     case GIMPLE_NOP:
     case GIMPLE_ASM:
     case GIMPLE_ASSIGN:
@@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
 	cannot_fallthru = false;
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
+      break;
+
     default:
       /* This case represents statements to be executed when an
 	 exception occurs.  Those statements are implicitly followed
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index ed8e51c..2702854 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1370,6 +1370,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 			 gimple_debug_source_bind_get_value (gs));
       break;
 
+    case GIMPLE_DEBUG_BEGIN_STMT:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+      break;
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c4e6f81..dc9aa79 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -836,6 +836,27 @@ gimple_build_debug_source_bind (tree var, tree value,
 }
 
 
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+   LOCATION.  */
+
+gdebug *
+gimple_build_debug_begin_stmt (tree block, location_t location
+				    MEM_STAT_DECL)
+{
+  gdebug *p
+    = as_a <gdebug *> (
+        gimple_build_with_ops_stat (GIMPLE_DEBUG,
+				    (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+				    PASS_MEM_STAT));
+
+  gimple_set_location (p, location);
+  gimple_set_block (p, block);
+  cfun->debug_marker_count++;
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1874,6 +1895,9 @@ gimple_copy (gimple *stmt)
       gimple_set_modified (copy, true);
     }
 
+  if (gimple_debug_nonbind_marker_p (stmt))
+    cfun->debug_marker_count++;
+
   return copy;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 8f289ac..68cd34f 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1454,6 +1454,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
+gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
 gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
 gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
 gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index e9dffc3..6c80a81 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -982,6 +982,48 @@ unshare_expr_without_location (tree expr)
     walk_tree (&expr, prune_expr_location, NULL, NULL);
   return expr;
 }
+
+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
+   one, OR_ELSE otherwise.  The location of a STATEMENT_LISTs
+   comprising at least one DEBUG_BEGIN_STMT followed by exactly one
+   EXPR is the location of the EXPR.  */
+
+static location_t
+rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
+  if (!expr)
+    return or_else;
+
+  if (EXPR_HAS_LOCATION (expr))
+    return EXPR_LOCATION (expr);
+
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    return or_else;
+
+  tree_stmt_iterator i = tsi_start (expr);
+
+  bool found = false;
+  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+    {
+      found = true;
+      tsi_next (&i);
+    }
+
+  if (!found || !tsi_one_before_end_p (i))
+    return or_else;
+
+  return rexpr_location (tsi_stmt (i), or_else);
+}
+
+/* Return TRUE iff EXPR (maybe recursively) has a location; see
+   rexpr_location for the potential recursion.  */
+
+static inline bool
+rexpr_has_location (tree expr)
+{
+  return rexpr_location (expr) != UNKNOWN_LOCATION;
+}
+
 \f
 /* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
    contain statements and have a value.  Assign its value to a temporary
@@ -1772,6 +1814,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
       /* Walk the sub-statements.  */
       *handled_ops_p = false;
       break;
+
+    case GIMPLE_DEBUG:
+      /* Ignore these.  We may generate them before declarations that
+	 are never executed.  If there's something to warn about,
+	 there will be non-debug stmts too, and we'll catch those.  */
+      break;
+
     case GIMPLE_CALL:
       if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
 	{
@@ -3441,7 +3490,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the && on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3464,7 +3513,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the || on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3486,7 +3535,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
 
       /* Keep the original source location on the first 'if'.  Set the source
 	 location of the ? on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
 		     shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
 				      false_label_p, locus),
@@ -3510,6 +3559,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
   return expr;
 }
 
+/* If EXPR is a GOTO_EXPR, return it.  If it is a STATEMENT_LIST, skip
+   any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent
+   statement, if it is the last one.  Otherwise, return NULL.  */
+
+static tree
+find_goto (tree expr)
+{
+  if (!expr)
+    return NULL_TREE;
+
+  if (TREE_CODE (expr) == GOTO_EXPR)
+    return expr;
+
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    return NULL_TREE;
+
+  tree_stmt_iterator i = tsi_start (expr);
+
+  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+    tsi_next (&i);
+
+  if (!tsi_one_before_end_p (i))
+    return NULL_TREE;
+
+  return find_goto (tsi_stmt (i));
+}
+
+/* Same as find_goto, except that it returns NULL if the destination
+   is not a LABEL_DECL.  */
+
+static inline tree
+find_goto_label (tree expr)
+{
+  tree dest = find_goto (expr);
+  if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)
+    return dest;
+  return NULL_TREE;
+}
+
 /* Given a conditional expression EXPR with short-circuit boolean
    predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the
    predicate apart into the equivalent sequence of conditionals.  */
@@ -3540,8 +3628,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the && on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  then_ = shortcut_cond_expr (expr);
 	  then_se = then_ && TREE_SIDE_EFFECTS (then_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3562,8 +3650,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the || on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  else_ = shortcut_cond_expr (expr);
 	  else_se = else_ && TREE_SIDE_EFFECTS (else_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3590,20 +3678,16 @@ shortcut_cond_expr (tree expr)
   /* If our arms just jump somewhere, hijack those labels so we don't
      generate jumps to jumps.  */
 
-  if (then_
-      && TREE_CODE (then_) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
+  if (tree then_goto = find_goto_label (then_))
     {
-      true_label = GOTO_DESTINATION (then_);
+      true_label = GOTO_DESTINATION (then_goto);
       then_ = NULL;
       then_se = false;
     }
 
-  if (else_
-      && TREE_CODE (else_) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
+  if (tree else_goto = find_goto_label (else_))
     {
-      false_label = GOTO_DESTINATION (else_);
+      false_label = GOTO_DESTINATION (else_goto);
       else_ = NULL;
       else_se = false;
     }
@@ -3667,8 +3751,8 @@ shortcut_cond_expr (tree expr)
 	{
 	  tree last = expr_last (expr);
 	  t = build_and_jump (&end_label);
-	  if (EXPR_HAS_LOCATION (last))
-	    SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
+	  if (rexpr_has_location (last))
+	    SET_EXPR_LOCATION (t, rexpr_location (last));
 	  append_to_statement_list (t, &expr);
 	}
       if (emit_false)
@@ -3961,39 +4045,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   gimple_push_condition ();
 
   have_then_clause_p = have_else_clause_p = false;
-  if (TREE_OPERAND (expr, 1) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
-	  == current_function_decl)
+  label_true = find_goto_label (TREE_OPERAND (expr, 1));
+  if (label_true
+      && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
+	  || !rexpr_has_location (label_true)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_true)))
     {
-      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
       have_then_clause_p = true;
+      label_true = GOTO_DESTINATION (label_true);
     }
   else
     label_true = create_artificial_label (UNKNOWN_LOCATION);
-  if (TREE_OPERAND (expr, 2) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
-	  == current_function_decl)
+  label_false = find_goto_label (TREE_OPERAND (expr, 2));
+  if (label_false
+      && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
+	  || !rexpr_has_location (label_false)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_false)))
     {
-      label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
       have_else_clause_p = true;
+      label_false = GOTO_DESTINATION (label_false);
     }
   else
     label_false = create_artificial_label (UNKNOWN_LOCATION);
@@ -11789,6 +11869,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case DEBUG_EXPR_DECL:
+	  gcc_unreachable ();
+
+	case DEBUG_BEGIN_STMT:
+	  gimplify_seq_add_stmt (pre_p,
+				 gimple_build_debug_begin_stmt
+				 (TREE_BLOCK (*expr_p),
+				  EXPR_LOCATION (*expr_p)));
+	  ret = GS_ALL_DONE;
+	  *expr_p = NULL;
+	  break;
+
 	case SSA_NAME:
 	  /* Allow callbacks into the gimplifier during optimization.  */
 	  ret = GS_ALL_DONE;
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 61b081b..a3f02b2 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int);
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP	false
 #define LANG_HOOKS_DEEP_UNSHARING	false
 #define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS	false
+#define LANG_HOOKS_EMITS_BEGIN_STMT	false
 #define LANG_HOOKS_RUN_LANG_SELFTESTS   lhd_do_nothing
 #define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
 
@@ -343,6 +344,7 @@ extern void lhd_end_section (void);
   LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
   LANG_HOOKS_DEEP_UNSHARING, \
   LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \
+  LANG_HOOKS_EMITS_BEGIN_STMT, \
   LANG_HOOKS_RUN_LANG_SELFTESTS, \
   LANG_HOOKS_GET_SUBSTRING_LOCATION \
 }
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index b0c9829..3493ff3 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -528,6 +528,9 @@ struct lang_hooks
      instead of trampolines.  */
   bool custom_function_descriptors;
 
+  /* True if this language emits begin stmt notes.  */
+  bool emits_begin_stmt;
+
   /* Run all lang-specific selftests.  */
   void (*run_lang_selftests) (void);
 
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 4734c072..47527b0 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -5253,10 +5253,11 @@ inherit_reload_reg (bool def_p, int original_regno,
       lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
       if (lra_dump_file != NULL)
 	{
+	  basic_block bb = BLOCK_FOR_INSN (usage_insn);
 	  fprintf (lra_dump_file,
 		   "    Inheritance reuse change %d->%d (bb%d):\n",
 		   original_regno, REGNO (new_reg),
-		   BLOCK_FOR_INSN (usage_insn)->index);
+		   bb ? bb->index : -1);
 	  dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
 	}
     }
@@ -5796,6 +5797,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
       if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
 	continue;
       curr_bb = BLOCK_FOR_INSN (curr_insn);
+      if (!curr_bb)
+	{
+	  gcc_assert (DEBUG_INSN_P (curr_insn));
+	  if (DEBUG_MARKER_INSN_P (curr_insn))
+	    continue;
+	  curr_bb = prev_bb;
+	}
       if (curr_bb != prev_bb)
 	{
 	  if (prev_bb != NULL)
diff --git a/gcc/lra.c b/gcc/lra.c
index 9037495..ac99d5e 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -602,9 +602,9 @@ static struct lra_operand_data debug_operand_data =
   };
 
 /* The following data are used as static insn data for all debug
-   insns.  If structure lra_static_insn_data is changed, the
+   bind insns.  If structure lra_static_insn_data is changed, the
    initializer should be changed too.  */
-static struct lra_static_insn_data debug_insn_static_data =
+static struct lra_static_insn_data debug_bind_static_data =
   {
     &debug_operand_data,
     0,	/* Duplication operands #.  */
@@ -618,6 +618,22 @@ static struct lra_static_insn_data debug_insn_static_data =
     NULL  /* Descriptions of operands in alternatives.	*/
   };
 
+/* The following data are used as static insn data for all debug
+   marker insns.  If structure lra_static_insn_data is changed, the
+   initializer should be changed too.  */
+static struct lra_static_insn_data debug_marker_static_data =
+  {
+    &debug_operand_data,
+    0,	/* Duplication operands #.  */
+    -1, /* Commutative operand #.  */
+    0,	/* Operands #.	There isn't any operand.  */
+    0,	/* Duplications #.  */
+    0,	/* Alternatives #.  We are not interesting in alternatives
+	   because we does not proceed debug_insns for reloads.	 */
+    NULL, /* Hard registers referenced in machine description.	*/
+    NULL  /* Descriptions of operands in alternatives.	*/
+  };
+
 /* Called once per compiler work to initialize some LRA data related
    to insns.  */
 static void
@@ -949,12 +965,20 @@ lra_set_insn_recog_data (rtx_insn *insn)
   data->regs = NULL;
   if (DEBUG_INSN_P (insn))
     {
-      data->insn_static_data = &debug_insn_static_data;
       data->dup_loc = NULL;
       data->arg_hard_regs = NULL;
       data->preferred_alternatives = ALL_ALTERNATIVES;
-      data->operand_loc = XNEWVEC (rtx *, 1);
-      data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+      if (DEBUG_BIND_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_bind_static_data;
+	  data->operand_loc = XNEWVEC (rtx *, 1);
+	  data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+	}
+      else if (DEBUG_MARKER_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_marker_static_data;
+	  data->operand_loc = NULL;
+	}
       return data;
     }
   if (icode < 0)
@@ -1600,7 +1624,7 @@ lra_update_insn_regno_info (rtx_insn *insn)
     return;
   data = lra_get_insn_recog_data (insn);
   static_data = data->insn_static_data;
-  freq = get_insn_freq (insn);
+  freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
   invalidate_insn_data_regno_info (data, insn, freq);
   uid = INSN_UID (insn);
   for (i = static_data->n_operands - 1; i >= 0; i--)
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 51d9a7b..37fa14e 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1130,7 +1130,10 @@ input_function (tree fn_decl, struct data_in *data_in,
 	     Similarly remove all IFN_*SAN_* internal calls   */
 	  if (!flag_wpa)
 	    {
-	      if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+	      if (is_gimple_debug (stmt)
+		  && (gimple_debug_nonbind_marker_p (stmt)
+		      ? !MAY_HAVE_DEBUG_MARKER_STMTS
+		      : !MAY_HAVE_DEBUG_BIND_STMTS))
 		remove = true;
 	      if (is_gimple_call (stmt)
 		  && gimple_call_internal_p (stmt))
@@ -1184,6 +1187,13 @@ input_function (tree fn_decl, struct data_in *data_in,
 	    {
 	      gsi_next (&bsi);
 	      stmts[gimple_uid (stmt)] = stmt;
+
+	      /* Remember that the input function has begin stmt
+		 markers, so that we know to expect them when emitting
+		 debug info.  */
+	      if (!cfun->debug_nonbind_markers
+		  && gimple_debug_nonbind_marker_p (stmt))
+		cfun->debug_nonbind_markers = true;
 	    }
 	}
     }
diff --git a/gcc/params.def b/gcc/params.def
index 136f927..9f63e63 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -963,6 +963,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
 	  "Max. size of loc list for which reverse ops should be added.",
 	  50, 0, 0)
 
+/* Set a threshold to discard debug markers (e.g. debug begin stmt
+   markers) when expanding a function to RTL, or inlining it into
+   another function.  */
+
+DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
+	  "max-debug-marker-count",
+	  "Max. count of debug markers to expand or inline.",
+	  100000, 0, 0)
+
 /* Set minimum insn uid for non-debug insns.  */
 
 DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 79ec463..0d36a42 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  fputc ('\t', m_outfile);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+	  {
+	    expanded_location xloc
+	      = expand_location (NOTE_MARKER_LOCATION (in_rtx));
+	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+	  }
+#endif
+	  break;
+
 	default:
 	  break;
 	}
@@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 
     case DEBUG_INSN:
       {
+	if (DEBUG_MARKER_INSN_P (x))
+	  {
+	    switch (INSN_DEBUG_MARKER_KIND (x))
+	      {
+	      case NOTE_INSN_BEGIN_STMT:
+		pp_string (pp, "debug begin stmt marker");
+		break;
+
+	      default:
+		gcc_unreachable ();
+	      }
+	    break;
+	  }
+
 	const char *name = "?";
 
 	if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
diff --git a/gcc/recog.c b/gcc/recog.c
index cfce029..566425d 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -2251,6 +2251,7 @@ extract_insn (rtx_insn *insn)
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
     case VAR_LOCATION:
+    case DEBUG_MARKER:
       return;
 
     case SET:
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 4c2607a..ccdaa82 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -761,6 +761,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
    been optimized away completely.  */
 DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
 
+/* Used in marker DEBUG_INSNs to avoid being recognized as an insn.  */
+DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_OBJ)
+
 /* All expressions from this point forward appear only in machine
    descriptions.  */
 #ifdef GENERATOR_FILE
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index a142488..a99e975 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "except.h"
 #include "debug.h"
+#include "params.h"
 #include "value-prof.h"
 #include "cfgloop.h"
 #include "builtins.h"
@@ -1354,7 +1355,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
   gimple_seq stmts = NULL;
 
   if (is_gimple_debug (stmt)
-      && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
+      && (gimple_debug_nonbind_marker_p (stmt)
+	  ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers
+	  : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return stmts;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
@@ -1637,6 +1640,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
 	  gimple_seq_add_stmt (&stmts, copy);
 	  return stmts;
 	}
+      if (gimple_debug_nonbind_marker_p (stmt))
+	{
+	  /* If the inlined function has too many debug markers,
+	     don't copy them.  */
+	  if (id->src_cfun->debug_marker_count
+	      > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+	    return stmts;
+
+	  gdebug *copy = as_a <gdebug *> (gimple_copy (stmt));
+	  id->debug_stmts.safe_push (copy);
+	  gimple_seq_add_stmt (&stmts, copy);
+	  return stmts;
+	}
+      gcc_checking_assert (!is_gimple_debug (stmt));
 
       /* Create a new deep copy of the statement.  */
       copy = gimple_copy (stmt);
@@ -1732,7 +1749,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
       gimple_set_block (copy, *n);
     }
 
-  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
+  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)
+      || gimple_debug_nonbind_marker_p (copy))
     {
       gimple_seq_add_stmt (&stmts, copy);
       return stmts;
@@ -2606,6 +2624,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
 	      value = gimple_debug_source_bind_get_value (stmt);
 	      new_stmt = gimple_build_debug_source_bind (var, value, stmt);
 	    }
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    new_stmt = as_a <gdebug *> (gimple_copy (stmt));
 	  else
 	    gcc_unreachable ();
 	  gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2922,6 +2942,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
       gimple_set_block (stmt, n ? *n : id->block);
     }
 
+  if (gimple_debug_nonbind_marker_p (stmt))
+    return;
+
   /* Remap all the operands in COPY.  */
   memset (&wi, 0, sizeof (wi));
   wi.info = id;
@@ -2930,8 +2953,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
 
   if (gimple_debug_source_bind_p (stmt))
     t = gimple_debug_source_bind_get_var (stmt);
-  else
+  else if (gimple_debug_bind_p (stmt))
     t = gimple_debug_bind_get_var (stmt);
+  else
+    gcc_unreachable ();
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = id->debug_map->get (t)))
diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
index c485413..10e510d 100644
--- a/gcc/tree-iterator.c
+++ b/gcc/tree-iterator.c
@@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)
 void
 append_to_statement_list (tree t, tree *list_p)
 {
-  if (t && TREE_SIDE_EFFECTS (t))
+  if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
     append_to_statement_list_1 (t, list_p);
 }
 
@@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
       tail = head;
     }
 
-  TREE_SIDE_EFFECTS (i->container) = 1;
+  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+    TREE_SIDE_EFFECTS (i->container) = 1;
 
   cur = i->ptr;
 
@@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
       tail = head;
     }
 
-  TREE_SIDE_EFFECTS (i->container) = 1;
+  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+    TREE_SIDE_EFFECTS (i->container) = 1;
 
   cur = i->ptr;
 
@@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)
   i->ptr = next;
 }
 
-/* Return the first expression in a sequence of COMPOUND_EXPRs,
-   or in a STATEMENT_LIST.  */
+/* Return the first expression in a sequence of COMPOUND_EXPRs, or in
+   a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+   STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT.  */
 
 tree
 expr_first (tree expr)
@@ -291,7 +294,20 @@ expr_first (tree expr)
   if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
-      return n ? n->stmt : NULL_TREE;
+      if (!n)
+	return NULL_TREE;
+      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+	{
+	  n = n->next;
+	  if (!n)
+	    return NULL_TREE;
+	}
+      /* If the first non-debug stmt is not a statement list, we
+	 already know it's what we're looking for.  */
+      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+	return n->stmt;
+
+      return expr_first (n->stmt);
     }
 
   while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -300,8 +316,9 @@ expr_first (tree expr)
   return expr;
 }
 
-/* Return the last expression in a sequence of COMPOUND_EXPRs,
-   or in a STATEMENT_LIST.  */
+/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
+   STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+   STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT.  */
 
 tree
 expr_last (tree expr)
@@ -312,7 +329,20 @@ expr_last (tree expr)
   if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
-      return n ? n->stmt : NULL_TREE;
+      if (!n)
+	return NULL_TREE;
+      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+	{
+	  n = n->prev;
+	  if (!n)
+	    return NULL_TREE;
+	}
+      /* If the last non-debug stmt is not a statement list, we
+	 already know it's what we're looking for.  */
+      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+	return n->stmt;
+
+      return expr_last (n->stmt);
     }
 
   while (TREE_CODE (expr) == COMPOUND_EXPR)
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 1fe3e63..22c6667 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3291,6 +3291,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
       pp_string (pp, "_Cilk_sync");
       break;
 
+    case DEBUG_BEGIN_STMT:
+      pp_string (pp, "# DEBUG BEGIN STMT");
+      break;
+
     default:
       NIY;
     }
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 70675e4..91793bf 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
       gimple *stmt = gsi_stmt (si);
       if (!is_gimple_debug (stmt))
 	break;
+      if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       i++;
     }
 
@@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	var = gimple_debug_bind_get_var (stmt);
       else if (gimple_debug_source_bind_p (stmt))
 	var = gimple_debug_source_bind_get_var (stmt);
+      else if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       else
 	gcc_unreachable ();
 
@@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	    var = gimple_debug_bind_get_var (stmt);
 	  else if (gimple_debug_source_bind_p (stmt))
 	    var = gimple_debug_source_bind_get_var (stmt);
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    continue;
 	  else
 	    gcc_unreachable ();
 
-	  /* Discard debug bind overlaps.  ??? Unlike stmts from src,
+	  /* Discard debug bind overlaps.  Unlike stmts from src,
 	     copied into a new block that will precede BB, debug bind
 	     stmts in bypassed BBs may actually be discarded if
-	     they're overwritten by subsequent debug bind stmts, which
-	     might be a problem once we introduce stmt frontier notes
-	     or somesuch.  Adding `&& bb == src' to the condition
-	     below will preserve all potentially relevant debug
-	     notes.  */
+	     they're overwritten by subsequent debug bind stmts.  We
+	     want to copy binds for all modified variables, so that we
+	     retain a bind to the shared def if there is one, or to a
+	     newly introduced PHI node if there is one.  Our bind will
+	     end up reset if the value is dead, but that implies the
+	     variable couldn't have survived, so it's fine.  We are
+	     not actually running the code that performed the binds at
+	     this point, we're just adding binds so that they survive
+	     the new confluence, so markers should not be copied.  */
 	  if (vars && vars->add (var))
 	    continue;
 	  else if (!vars)
@@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 		  break;
 	      if (i >= 0)
 		continue;
-
-	      if (fewvars.length () < (unsigned) alloc_count)
+	      else if (fewvars.length () < (unsigned) alloc_count)
 		fewvars.quick_push (var);
 	      else
 		{
diff --git a/gcc/tree.c b/gcc/tree.c
index e379940..30cadd7 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1015,7 +1015,8 @@ make_node (enum tree_code code MEM_STAT_DECL)
   switch (type)
     {
     case tcc_statement:
-      TREE_SIDE_EFFECTS (t) = 1;
+      if (code != DEBUG_BEGIN_STMT)
+	TREE_SIDE_EFFECTS (t) = 1;
       break;
 
     case tcc_declaration:
@@ -4412,7 +4413,10 @@ build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)
     }
 
   if (TREE_CODE_CLASS (code) == tcc_statement)
-    TREE_SIDE_EFFECTS (t) = 1;
+    {
+      if (code != DEBUG_BEGIN_STMT)
+	TREE_SIDE_EFFECTS (t) = 1;
+    }
   else switch (code)
     {
     case VA_ARG_EXPR:
diff --git a/gcc/tree.def b/gcc/tree.def
index 9f80c4d..e30e950 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -382,6 +382,9 @@ DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
    DEBUG stmts.  */
 DEFTREECODE (DEBUG_EXPR_DECL, "debug_expr_decl", tcc_declaration, 0)
 
+/* A stmt that marks the beginning of a source statement.  */
+DEFTREECODE (DEBUG_BEGIN_STMT, "debug_begin_stmt", tcc_statement, 0)
+
 /* A namespace declaration.  Namespaces appear in DECL_CONTEXT of other
    _DECLs, providing a hierarchy of names.  */
 DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
diff --git a/gcc/tree.h b/gcc/tree.h
index 2e8b3e9..62a85ea 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1225,7 +1225,7 @@ extern void protected_set_expr_location (tree, location_t);
 
 /* GOTO_EXPR accessor. This gives access to the label associated with
    a goto statement.  */
-#define GOTO_DESTINATION(NODE)  TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE)  TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
 
 /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
    instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 974b4ea..d3850af 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9919,6 +9919,36 @@ vt_init_cfa_base (void)
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
 }
 
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
+{
+  gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
+
+  enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
+
+  switch (kind)
+    {
+    case NOTE_INSN_BEGIN_STMT:
+      {
+	rtx_insn *note = NULL;
+	if (cfun->debug_nonbind_markers)
+	  {
+	    note = emit_note_before (kind, insn);
+	    NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
+	    if (bb)
+	      BLOCK_FOR_INSN (note) = *bb;
+	  }
+	delete_insn (insn);
+	return note;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
@@ -10162,6 +10192,12 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
+		  if (DEBUG_MARKER_INSN_P (insn))
+		    {
+		      insn = reemit_marker_as_note (insn, &save_bb);
+		      continue;
+		    }
+
 		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
@@ -10238,10 +10274,11 @@ vt_initialize (void)
 
 static int debug_label_num = 1;
 
-/* Get rid of all debug insns from the insn stream.  */
+/* Remove from the insn stream all debug insns used for variable
+   tracking at assignments.  */
 
 static void
-delete_debug_insns (void)
+delete_vta_debug_insns (void)
 {
   basic_block bb;
   rtx_insn *insn, *next;
@@ -10257,6 +10294,12 @@ delete_debug_insns (void)
 	   insn = next)
 	if (DEBUG_INSN_P (insn))
 	  {
+	    if (DEBUG_MARKER_INSN_P (insn))
+	      {
+		insn = reemit_marker_as_note (insn, NULL);
+		continue;
+	      }
+
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
 	    if (TREE_CODE (decl) == LABEL_DECL
 		&& DECL_NAME (decl)
@@ -10282,10 +10325,13 @@ delete_debug_insns (void)
    handled as well..  */
 
 static void
-vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
+vt_debug_insns_local (bool skipped)
 {
-  /* ??? Just skip it all for now.  */
-  delete_debug_insns ();
+  /* ??? Just skip it all for now.  If we skipped the global pass,
+     arrange for stmt markers to be dropped as well.  */
+  if (skipped)
+    cfun->debug_nonbind_markers = 0;
+  delete_vta_debug_insns ();
 }
 
 /* Free the data structures needed for variable tracking.  */
@@ -10350,15 +10396,21 @@ variable_tracking_main_1 (void)
 {
   bool success;
 
-  if (flag_var_tracking_assignments < 0
+  /* We won't be called as a separate pass if flag_var_tracking is not
+     set, but final may call us to turn debug markers into notes.  */
+  if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
+      || flag_var_tracking_assignments < 0
       /* Var-tracking right now assumes the IR doesn't contain
 	 any pseudos at this point.  */
       || targetm.no_register_allocation)
     {
-      delete_debug_insns ();
+      delete_vta_debug_insns ();
       return 0;
     }
 
+  if (!flag_var_tracking)
+    return 0;
+
   if (n_basic_blocks_for_fn (cfun) > 500 &&
       n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
     {
@@ -10380,7 +10432,9 @@ variable_tracking_main_1 (void)
     {
       vt_finalize ();
 
-      delete_debug_insns ();
+      cfun->debug_nonbind_markers = 0;
+
+      delete_vta_debug_insns ();
 
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  2017-09-30  9:09               ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
  2017-09-30  9:09               ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
@ 2017-09-30  9:09               ` Alexandre Oliva
  2017-10-09 13:02                 ` Richard Biener
  2017-09-30  9:09               ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
                                 ` (6 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch introduces a number of new macros and functions that will
be used to distinguish between different kinds of debug stmts, insns
and notes, namely, preexisting debug bind ones and to-be-introduced
nonbind markers.

In a seemingly mechanical way, it adjusts several uses of the macros
and functions, so that they refer to narrower categories when
appropriate.

These changes, by themselves, should not have any visible effect in
the compiler behavior, since the upcoming debug markers are never
created with this patch alone.

for  gcc/ChangeLog

	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_BEGIN_STMT.
	(gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
	(MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
	(MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
	* insn-notes.def (BEGIN_STMT): New.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
	(MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
	(MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
	(NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
	(DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
	(INSN_DEBUG_MARKER_KIND): New.
	(INSN_VAR_LOCATION): Check for VAR_LOCATION.
	(INSN_VAR_LOCATION_PTR): New.
	* cfgexpand.c (expand_debug_locations): Handle debug bind insns
	only.
	(expand_gimple_basic_block): Likewise.  Emit debug temps for TER
	deps only if debug bind insns are enabled.
	(pass_expand::execute): Avoid deep TER and expand
	debug locations for debug bind insns only.
	* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
	debug stmts special handling down to debug bind stmts.
	* combine.c (try_combine): Narrow debug insns special handling
	down to debug bind insns.
	* cse.c (delete_trivially_dead_insns): Handle debug bindings.
	Narrow debug insns preexisting special handling down to debug
	bind insns.
	* dce.c (rest_of_handle_ud_dce): Narrow debug insns special
	handling down to debug bind insns.
	* function.c (instantiate_virtual_regs): Skip debug markers,
	adjust handling of debug binds.
	* gimple-ssa-backprop.c (backprop::prepare_change): Try debug
	temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
	* haifa-sched.c (schedule_insn): Narrow special handling of debug
	insns to debug bind insns.
	* ipa-prop.c (ipa_modify_call_arguments): Narrow special
	handling of debug insns to debug bind insns.
	* ipa-split.c (split_function): Likewise.
	* ira.c (combine_and_move_insns): Adjust debug bind insns only.
	* loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
	debug insns.
	* reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
	* regrename.c (build_def_use): Likewise.
	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
	(pass_cprop_hardreg): Narrow special casing of debug insns to
	debug bind insns.
	* regstat.c (regstat_init_n_sets_and_refs): Likewise.
	* reload1.c (reload): Likewise.
	* sese.c (sese_build_liveouts): Narrow special casing of debug
	stmts to debug bind stmts.
	* shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
	* ssa-iterators.h (num_imm_uses): Likewise.
	* tree-cfg.c (gimple_merge_blocks): Narrow special casing of
	debug stmts to debug bind stmts.
	* tree-inline.c	(tree_function_versioning): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-loop-distribution.c (generate_loops_for_partition):
	Narrow special casing of debug stmts to debug bind stmts.
	* tree-sra.c (analyze_access_subtree): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
	stmts to debug bind stmts.
	* tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
	* tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Likewise.
	* tree-ssa.c (flush_pending_stmts): Narrow special casing of
	debug stmts to debug bind stmts.
	(gimple_replace_ssa_lhs): Likewise.
	(insert_debug_temp_for_var_def): Likewise.
	(insert_debug_temps_for_defs): Likewise.
	(reset_debug_uses): Likewise.
	* tree-ssanames.c (release_ssa_name_fn): Likewise.
	* tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
	(adjust_debug_stmts): Likewise.
	(adjust_phi_and_debug_stmts): Likewise.
	(vect_do_peeling): Likewise.
	* tree-vect-loop.c (vect_transform_loop): Likewise.
	* valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
	* var-tracking.c (adjust_mems): Narrow special casing of debug
	insns to debug bind insns.
	(dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
	(compute_bb_dataflow, vt_find_locations): Likewise.
	(vt_expand_loc, emit_notes_for_changes): Likewise.
	(vt_init_cfa_base): Likewise.
	(vt_emit_notes): Likewise.
	(vt_initialize): Likewise.
	(vt_finalize): Likewise.
---
 gcc/cfgexpand.c              |  8 +++----
 gcc/cgraph.c                 |  2 +-
 gcc/combine.c                | 12 +++++------
 gcc/cse.c                    | 17 ++++++++-------
 gcc/dce.c                    |  2 +-
 gcc/function.c               |  7 ++++---
 gcc/gimple-ssa-backprop.c    |  2 +-
 gcc/gimple.h                 | 31 ++++++++++++++++++++++-----
 gcc/haifa-sched.c            |  4 ++--
 gcc/insn-notes.def           |  3 +++
 gcc/ipa-prop.c               |  2 +-
 gcc/ipa-split.c              | 11 +++++-----
 gcc/ira.c                    |  4 ++--
 gcc/loop-unroll.c            |  6 ++++--
 gcc/reg-stack.c              |  4 ++--
 gcc/regcprop.c               |  4 ++--
 gcc/regrename.c              |  2 +-
 gcc/regstat.c                |  2 +-
 gcc/reload1.c                |  4 ++--
 gcc/rtl.h                    | 40 +++++++++++++++++++++++++++++++++--
 gcc/sese.c                   |  2 +-
 gcc/shrink-wrap.c            |  4 ++--
 gcc/ssa-iterators.h          |  2 +-
 gcc/tree-cfg.c               |  2 +-
 gcc/tree-inline.c            |  4 ++--
 gcc/tree-loop-distribution.c |  2 +-
 gcc/tree-sra.c               |  2 +-
 gcc/tree-ssa-dce.c           |  2 +-
 gcc/tree-ssa-loop-ivopts.c   |  2 +-
 gcc/tree-ssa-reassoc.c       |  2 +-
 gcc/tree-ssa-tail-merge.c    |  2 +-
 gcc/tree-ssa-threadedge.c    |  2 +-
 gcc/tree-ssa.c               | 10 ++++-----
 gcc/tree-ssanames.c          |  2 +-
 gcc/tree-vect-loop-manip.c   |  8 +++----
 gcc/tree-vect-loop.c         |  4 ++--
 gcc/tree.h                   |  8 ++++++-
 gcc/valtrack.c               |  2 +-
 gcc/var-tracking.c           | 50 +++++++++++++++++++++-----------------------
 39 files changed, 175 insertions(+), 104 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index bd3312e..cb866aa 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5285,7 +5285,7 @@ expand_debug_locations (void)
   flag_strict_aliasing = 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (DEBUG_INSN_P (insn))
+    if (DEBUG_BIND_INSN_P (insn))
       {
 	tree value = (tree)INSN_VAR_LOCATION_LOC (insn);
 	rtx val;
@@ -5538,7 +5538,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	   a_2 = ...
            #DEBUG ... => #D1
 	 */
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && SA.values
 	  && !is_gimple_debug (stmt))
 	{
@@ -6165,7 +6165,7 @@ pass_expand::execute (function *fun)
   timevar_pop (TV_OUT_OF_SSA);
   SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions);
 
-  if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter)
+  if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter)
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, cfun)
@@ -6356,7 +6356,7 @@ pass_expand::execute (function *fun)
 		  next_bb)
     bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     expand_debug_locations ();
 
   if (deep_ter_debug_map)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 3d0cefb..cd60193 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1459,7 +1459,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
 	 stmts and associate D#X with parm in decl_debug_args_lookup
 	 vector to say for debug info that if parameter parm had been passed,
 	 it would have value parm_Y(D).  */
-      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  vec<tree, va_gc> **debug_args
 	    = decl_debug_args_lookup (e->callee->decl);
diff --git a/gcc/combine.c b/gcc/combine.c
index e502fa1..86d710d 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3726,7 +3726,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 	  /* *SPLIT may be part of I2SRC, so make sure we have the
 	     original expression around for later debug processing.
 	     We should not need I2SRC any more in other cases.  */
-	  if (MAY_HAVE_DEBUG_INSNS)
+	  if (MAY_HAVE_DEBUG_BIND_INSNS)
 	    i2src = copy_rtx (i2src);
 	  else
 	    i2src = NULL;
@@ -4083,7 +4083,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       struct undo *undo;
 
@@ -4396,7 +4396,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
     if (newi2pat)
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2scratch)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	INSN_CODE (i2) = i2_code_number;
@@ -4404,7 +4404,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       }
     else
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2src)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2src)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	SET_INSN_DELETED (i2);
@@ -4414,7 +4414,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i1) = NULL;
 	REG_NOTES (i1) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
 			       this_basic_block);
 	SET_INSN_DELETED (i1);
@@ -4424,7 +4424,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i0) = NULL;
 	REG_NOTES (i0) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
 			       this_basic_block);
 	SET_INSN_DELETED (i0);
diff --git a/gcc/cse.c b/gcc/cse.c
index 672fd2e..d1577a6 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -7054,11 +7054,11 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       counts = XCNEWVEC (int, nreg * 3);
       for (insn = insns; insn; insn = NEXT_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_INSN_P (insn))
 	  count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
 			   NULL_RTX, 1);
 	else if (INSN_P (insn))
@@ -7116,12 +7116,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
       if (! live_insn && dbg_cnt (delete_trivial_dead))
 	{
 	  if (DEBUG_INSN_P (insn))
-	    count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-			     NULL_RTX, -1);
+	    {
+	      if (DEBUG_BIND_INSN_P (insn))
+		count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+				 NULL_RTX, -1);
+	    }
 	  else
 	    {
 	      rtx set;
-	      if (MAY_HAVE_DEBUG_INSNS
+	      if (MAY_HAVE_DEBUG_BIND_INSNS
 		  && (set = single_set (insn)) != NULL_RTX
 		  && is_dead_reg (SET_DEST (set), counts)
 		  /* Used at least once in some DEBUG_INSN.  */
@@ -7161,10 +7164,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_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/dce.c b/gcc/dce.c
index 7534d2a..6fd9548 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -777,7 +777,7 @@ rest_of_handle_ud_dce (void)
     }
   worklist.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     reset_unmarked_insns_debug_uses ();
 
   /* Before any insns are deleted, we must remove the chains since
diff --git a/gcc/function.c b/gcc/function.c
index c03e2ac..ae61d3d 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
+	    || DEBUG_MARKER_INSN_P (insn))
 	  continue;
-	else if (DEBUG_INSN_P (insn))
-	  instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
+	else if (DEBUG_BIND_INSN_P (insn))
+	  instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
 	else
 	  instantiate_virtual_regs_in_insn (insn);
 
diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c
index f321ebb..b6e11c4 100644
--- a/gcc/gimple-ssa-backprop.c
+++ b/gcc/gimple-ssa-backprop.c
@@ -726,7 +726,7 @@ strip_sign_op (tree rhs)
 void
 backprop::prepare_change (tree var)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     insert_debug_temp_for_var_def (NULL, var);
   reset_flow_sensitive_info (var);
 }
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 6213c49..1783e11 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -198,13 +198,12 @@ 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
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -4739,6 +4738,28 @@ 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 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;
+
+  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/haifa-sched.c b/gcc/haifa-sched.c
index 549e896..34cc46b 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -4010,7 +4010,7 @@ schedule_insn (rtx_insn *insn)
   gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK));
 
   /* Reset debug insns invalidated by moving this insn.  */
-  if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn))
+  if (MAY_HAVE_DEBUG_BIND_INSNS && !DEBUG_INSN_P (insn))
     for (sd_it = sd_iterator_start (insn, SD_LIST_BACK);
 	 sd_iterator_cond (&sd_it, &dep);)
       {
@@ -4023,7 +4023,7 @@ schedule_insn (rtx_insn *insn)
 	    continue;
 	  }
 
-	gcc_assert (DEBUG_INSN_P (dbg));
+	gcc_assert (DEBUG_BIND_INSN_P (dbg));
 
 	if (sched_verbose >= 6)
 	  fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n",
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index f96ce18..960487b 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
 /* The values passed to callee.  */
 INSN_NOTE (CALL_ARG_LOCATION)
 
+/* The beginning of a statement.  */
+INSN_NOTE (BEGIN_STMT)
+
 /* 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-prop.c b/gcc/ipa-prop.c
index 51f6221..2d15504 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -4410,7 +4410,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
 	    }
 	  vargs.quick_push (expr);
 	}
-      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
+      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  unsigned int ix;
 	  tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index e3759d6..d45e951 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1471,7 +1471,7 @@ split_function (basic_block return_bb, struct split_point *split_point,
     {
       vec<tree, va_gc> **debug_args = NULL;
       unsigned i = 0, len = 0;
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  debug_args = decl_debug_args_lookup (node->decl);
 	  if (debug_args)
@@ -1484,11 +1484,12 @@ split_function (basic_block return_bb, struct split_point *split_point,
 	    tree ddecl;
 	    gimple *def_temp;
 
-	    /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
-	       otherwise if it didn't exist before, we'd end up with
-	       different SSA_NAME_VERSIONs between -g and -g0.  */
+	    /* This needs to be done even without
+	       MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist
+	       before, we'd end up with different SSA_NAME_VERSIONs
+	       between -g and -g0.  */
 	    arg = get_or_create_ssa_default_def (cfun, parm);
-	    if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL)
+	    if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL)
 	      continue;
 
 	    while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
diff --git a/gcc/ira.c b/gcc/ira.c
index 046ce3b..17f54a0 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3842,9 +3842,9 @@ combine_and_move_insns (void)
 	}
 
       /* Last pass - adjust debug insns referencing cleared regs.  */
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
-	  if (DEBUG_INSN_P (insn))
+	  if (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
 	      INSN_VAR_LOCATION_LOC (insn)
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 322f151..923be72 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -2026,12 +2026,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)
+	      || (DEBUG_BIND_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)
+		 || (DEBUG_BIND_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/reg-stack.c b/gcc/reg-stack.c
index f238106..e62ccda 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 (DEBUG_BIND_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 (!DEBUG_BIND_INSN_P (insn))
 	    continue;
 
 	  debug_insns_with_starting_stack--;
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 73e945d4..0ce64d7 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -757,7 +757,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 (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx loc = INSN_VAR_LOCATION_LOC (insn);
 	      if (!VAR_LOC_UNKNOWN_P (loc))
@@ -1302,7 +1302,7 @@ pass_cprop_hardreg::execute (function *fun)
       copyprop_hardreg_forward_1 (bb, all_vd + bb->index);
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       FOR_EACH_BB_FN (bb, fun)
 	if (bitmap_bit_p (visited, bb->index)
diff --git a/gcc/regrename.c b/gcc/regrename.c
index 7fbfa31..89380a8 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 (DEBUG_BIND_INSN_P (insn)
 	       && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
 	{
 	  scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
diff --git a/gcc/regstat.c b/gcc/regstat.c
index 3fd26fd..fd3d3a8 100644
--- a/gcc/regstat.c
+++ b/gcc/regstat.c
@@ -54,7 +54,7 @@ regstat_init_n_sets_and_refs (void)
 
   regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     for (i = 0; i < max_regno; i++)
       {
 	int use_count;
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 5e200b9..cf18b30 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1112,7 +1112,7 @@ reload (rtx_insn *first, int global)
       /* We don't want complex addressing modes in debug insns
 	 if simpler ones will do, so delegitimize equivalences
 	 in debug insns.  */
-      if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0)
+      if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0)
 	{
 	  rtx reg = regno_reg_rtx[i];
 	  rtx equiv = 0;
@@ -1140,7 +1140,7 @@ reload (rtx_insn *first, int global)
 	      while (next && DF_REF_INSN (next) == insn)
 		next = DF_REF_NEXT_REG (next);
 
-	      if (DEBUG_INSN_P (insn))
+	      if (DEBUG_BIND_INSN_P (insn))
 		{
 		  if (!equiv)
 		    {
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3bda77c..c79a277 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -815,8 +815,13 @@ struct GTY(()) rtvec_def {
 /* Predicate yielding nonzero iff X is an insn that is not a debug insn.  */
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
+/* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+/* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_INSNS					\
+  (MAY_HAVE_DEBUG_MARKER_INSNS || MAY_HAVE_DEBUG_BIND_INSNS)
 
 /* Predicate yielding nonzero iff X is a real insn.  */
 #define INSN_P(X) \
@@ -1604,6 +1609,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)
 
@@ -1615,6 +1621,12 @@ 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))
+
 /* 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))
@@ -1634,8 +1646,32 @@ 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 DEBUG_BIND_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 DEBUG_MARKER_INSN_P(INSN)		\
+  (DEBUG_INSN_P (INSN)				\
+   && (GET_CODE (PATTERN (INSN))		\
+       != VAR_LOCATION))
+/* Evaluate to the marker kind.  */
+#define INSN_DEBUG_MARKER_KIND(INSN)		  \
+  (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
+   ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
+      ? NOTE_INSN_BEGIN_STMT			  \
+      : (enum insn_note)-1) 			  \
+   : (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) \
diff --git a/gcc/sese.c b/gcc/sese.c
index ad85aa4..a24688f 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -164,7 +164,7 @@ sese_build_liveouts (sese_info_p region, bitmap liveouts)
       sese_build_liveouts_bb (region, liveouts, bb);
 
   /* FIXME: We could start iterating form the successor of sese.  */
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     FOR_EACH_BB_FN (bb, cfun)
       if (!bb_in_sese_p (bb, region->region))
 	sese_reset_debug_liveouts_bb (region, liveouts, bb);
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index 3cad776..85fe81d 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -309,10 +309,10 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
      move it as far as we can.  */
   do
     {
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  FOR_BB_INSNS_REVERSE (bb, dinsn)
-	    if (DEBUG_INSN_P (dinsn))
+	    if (DEBUG_BIND_INSN_P (dinsn))
 	      {
 		df_ref use;
 		FOR_EACH_INSN_USE (use, dinsn)
diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h
index c8aa77b..dca0439 100644
--- a/gcc/ssa-iterators.h
+++ b/gcc/ssa-iterators.h
@@ -447,7 +447,7 @@ num_imm_uses (const_tree var)
   const ssa_use_operand_t *ptr;
   unsigned int num = 0;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     {
       for (ptr = start->next; ptr != start; ptr = ptr->next)
 	if (USE_STMT (ptr))
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 99d1f1e..dc9ce3c 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -2054,7 +2054,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
 	      gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
 	    }
 	  /* Other user labels keep around in a form of a debug stmt.  */
-	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
+	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      gimple *dbg = gimple_build_debug_bind (label,
 						     integer_zero_node,
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index a226096..a142488 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -6032,7 +6032,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 					    &vars);
 		if (init)
 		  init_stmts.safe_push (init);
-		if (MAY_HAVE_DEBUG_STMTS && args_to_skip)
+		if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip)
 		  {
 		    if (parm_num == -1)
 		      {
@@ -6178,7 +6178,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 	}
     }
 
-  if (debug_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+  if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree parm;
       vec<tree, va_gc> **debug_args = NULL;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 26b8b9a..65ccd71 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -807,7 +807,7 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
   /* Remove stmts not in the PARTITION bitmap.  */
   bbs = get_loop_body_in_dom_order (loop);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     for (i = 0; i < loop->num_nodes; i++)
       {
 	basic_block bb = bbs[i];
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index f5675ed..e7167e7 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -2477,7 +2477,7 @@ analyze_access_subtree (struct access *root, struct access *parent,
 	  gcc_checking_assert (!root->grp_scalar_read
 			       && !root->grp_assignment_read);
 	  sth_created = true;
-	  if (MAY_HAVE_DEBUG_STMTS)
+	  if (MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      root->grp_to_be_debug_replaced = 1;
 	      root->replacement_decl = create_access_replacement (root);
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index e62afad..f60670f 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1086,7 +1086,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
 
   /* If this is a store into a variable that is being optimized away,
      add a debug bind stmt if possible.  */
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && gimple_assign_single_p (stmt)
       && is_gimple_val (gimple_assign_rhs1 (stmt)))
     {
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index bbea619..f8fe317 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -7148,7 +7148,7 @@ remove_unused_ivs (struct ivopts_data *data)
 
 	  tree def = info->iv->ssa_name;
 
-	  if (MAY_HAVE_DEBUG_STMTS && SSA_NAME_DEF_STMT (def))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def))
 	    {
 	      imm_use_iterator imm_iter;
 	      use_operand_p use_p;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index b2d0f57..a671a16 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -232,7 +232,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
-  if (!MAY_HAVE_DEBUG_STMTS || gimple_code (stmt) == GIMPLE_PHI)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI)
     return gsi_remove (gsi, true);
 
   gimple_stmt_iterator prev = *gsi;
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a65ff31..a3d5074 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1802,7 +1802,7 @@ tail_merge_optimize (unsigned int todo)
 
   if (nr_bbs_removed_total > 0)
     {
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  calculate_dominance_info (CDI_DOMINATORS);
 	  update_debug_stmts ();
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 536c471..70675e4 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -692,7 +692,7 @@ simplify_control_stmt_condition_1 (edge e,
 void
 propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   if (!single_pred_p (dest))
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 8b6da96..151f544 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -220,7 +220,7 @@ flush_pending_stmts (edge e)
 void
 gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree lhs = gimple_get_lhs (stmt);
 
@@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 tree
 target_for_debug_bind (tree var)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return NULL_TREE;
 
   if (TREE_CODE (var) == SSA_NAME)
@@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
   int usecount = 0;
   tree value = NULL;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   /* If this name has already been registered for replacement, do nothing
@@ -495,7 +495,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
   ssa_op_iter op_iter;
   def_operand_p def_p;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   stmt = gsi_stmt (*gsi);
@@ -521,7 +521,7 @@ reset_debug_uses (gimple *stmt)
   imm_use_iterator imm_iter;
   gimple *use_stmt;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 5c96075..4318adc 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -562,7 +562,7 @@ release_ssa_name_fn (struct function *fn, tree var)
       int saved_ssa_name_version = SSA_NAME_VERSION (var);
       use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
 
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	insert_debug_temp_for_var_def (NULL, var);
 
       if (flag_checking)
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index 5787d53..20d1962 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -194,7 +194,7 @@ adjust_debug_stmts_now (adjust_info *ai)
 static void
 adjust_vec_debug_stmts (void)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   gcc_assert (adjust_vec.exists ());
@@ -216,7 +216,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb)
 {
   adjust_info ai;
 
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && TREE_CODE (from) == SSA_NAME
       && ! SSA_NAME_IS_DEFAULT_DEF (from)
       && ! virtual_operand_p (from))
@@ -244,7 +244,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def)
 
   SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     adjust_debug_stmts (orig_def, PHI_RESULT (update_phi),
 			gimple_bb (update_phi));
 }
@@ -1685,7 +1685,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
   create_lcssa_for_virtual_phi (loop);
   update_ssa (TODO_update_ssa_only_virtuals);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       gcc_assert (!adjust_vec.exists ());
       adjust_vec.create (32);
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index bf49e26..07f666e 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -7386,7 +7386,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	  if (!stmt_info)
 	    continue;
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, phi);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
@@ -7449,7 +7449,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	      continue;
 	    }
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, stmt);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
diff --git a/gcc/tree.h b/gcc/tree.h
index caa4a69..2e8b3e9 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1126,8 +1126,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define VL_EXP_OPERAND_LENGTH(NODE) \
   ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
 
+/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+/* Nonzero if gimple_debug_bind_p() (and thus
+   gimple_debug_source_bind_p()) may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
 /* Nonzero if is_gimple_debug() may possibly hold.  */
-#define MAY_HAVE_DEBUG_STMTS    (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_STMTS					\
+  (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS)
 
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
diff --git a/gcc/valtrack.c b/gcc/valtrack.c
index 38af3f0..8d864c9 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 (DEBUG_BIND_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 51e519a..43fc71a 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -1118,7 +1118,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
       if (tem == NULL_RTX)
 	tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
     finish_subreg:
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && GET_CODE (tem) == SUBREG
 	  && (GET_CODE (SUBREG_REG (tem)) == PLUS
 	      || GET_CODE (SUBREG_REG (tem)) == MINUS
@@ -1330,7 +1330,7 @@ dv_onepart_p (decl_or_value dv)
 {
   tree decl;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return NOT_ONEPART;
 
   if (dv_is_value_p (dv))
@@ -4854,7 +4854,7 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
   EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
     var_regno_delete (set, r);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       set->traversed_vars = set->vars;
       shared_hash_htab (set->vars)
@@ -5528,7 +5528,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
 		  variable names such as VALUEs (never happens) or
 		  DEBUG_EXPRs (only happens in the presence of debug
 		  insns).  */
-	       && (!MAY_HAVE_DEBUG_INSNS
+	       && (!MAY_HAVE_DEBUG_BIND_INSNS
 		   || !rtx_debug_expr_p (XEXP (loc, 0))))
 	return MO_USE;
       else
@@ -6693,7 +6693,7 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     local_get_addr_cache = new hash_map<rtx, rtx>;
 
   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
@@ -6975,7 +6975,7 @@ compute_bb_dataflow (basic_block bb)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       delete local_get_addr_cache;
       local_get_addr_cache = NULL;
@@ -7062,7 +7062,7 @@ vt_find_locations (void)
 	      else
 		oldinsz = oldoutsz = 0;
 
-	      if (MAY_HAVE_DEBUG_INSNS)
+	      if (MAY_HAVE_DEBUG_BIND_INSNS)
 		{
 		  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
 		  bool first = true, adjust = false;
@@ -7123,7 +7123,7 @@ vt_find_locations (void)
 
 	      if (htabmax && htabsz > htabmax)
 		{
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    inform (DECL_SOURCE_LOCATION (cfun->decl),
 			    "variable tracking size limit exceeded with "
 			    "-fvar-tracking-assignments, retrying without");
@@ -7183,7 +7183,7 @@ vt_find_locations (void)
 	}
     }
 
-  if (success && MAY_HAVE_DEBUG_INSNS)
+  if (success && MAY_HAVE_DEBUG_BIND_INSNS)
     FOR_EACH_BB_FN (bb, cfun)
       gcc_assert (VTI (bb)->flooded);
 
@@ -8572,7 +8572,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars)
   struct expand_loc_callback_data data;
   rtx result;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return loc;
 
   INIT_ELCD (data, vars);
@@ -9007,7 +9007,7 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
   if (!changed_variables->elements ())
     return;
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     process_changed_values (htab);
 
   data.insn = insn;
@@ -9491,10 +9491,8 @@ vt_emit_notes (void)
      delete_variable_part).  */
   emit_notes = true;
 
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
-    }
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
+    dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
 
   dataflow_set_init (&cur);
 
@@ -9504,13 +9502,13 @@ vt_emit_notes (void)
 	 subsequent basic blocks.  */
       emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
 
       /* Emit the notes for the changes in the basic block itself.  */
       emit_notes_in_bb (bb, &cur);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	delete local_get_addr_cache;
       local_get_addr_cache = NULL;
 
@@ -9526,7 +9524,7 @@ vt_emit_notes (void)
 
   dataflow_set_destroy (&cur);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     delete dropped_values;
   dropped_values = NULL;
 
@@ -9886,7 +9884,7 @@ vt_init_cfa_base (void)
       cfa_base_rtx = NULL_RTX;
       return;
     }
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return;
 
   /* Tell alias analysis that cfa_base_rtx should share
@@ -9928,7 +9926,7 @@ vt_initialize (void)
       VTI (bb)->permp = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
@@ -9941,7 +9939,7 @@ vt_initialize (void)
       global_get_addr_cache = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       rtx reg, expr;
       int ofst;
@@ -10071,7 +10069,7 @@ vt_initialize (void)
       HOST_WIDE_INT pre, post = 0;
       basic_block first_bb, last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_record_sets_hook = add_with_sets;
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10122,7 +10120,7 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
 			prepare_call_arguments (bb, insn);
@@ -10157,7 +10155,7 @@ vt_initialize (void)
 		      vt_init_cfa_base ();
 		      hard_frame_pointer_adjustment = fp_cfa_offset;
 		      /* Disassociate sp from fp now.  */
-		      if (MAY_HAVE_DEBUG_INSNS)
+		      if (MAY_HAVE_DEBUG_BIND_INSNS)
 			{
 			  cselib_val *v;
 			  cselib_invalidate_rtx (stack_pointer_rtx);
@@ -10177,7 +10175,7 @@ vt_initialize (void)
 
       bb = last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_preserve_only_values ();
 	  cselib_reset_table (cselib_get_next_uid ());
@@ -10276,7 +10274,7 @@ vt_finalize (void)
   location_chain_pool.release ();
   shared_hash_pool.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       if (global_get_addr_cache)
 	delete global_get_addr_cache;
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
  2017-09-30  9:09               ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
@ 2017-09-30  9:09               ` Alexandre Oliva
  2017-10-09 13:12                 ` Richard Biener
  2017-09-30  9:09               ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
                                 ` (7 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

Introduce a command line option to enable statement frontiers, enabled
by default in optimized builds with DWARF2+ debug information.

This patch depends on an earlier patch that completed the
infrastructure for debug markers, and on another patch that turns -g
into a negatable option prefix.

gcc/ChangeLog

	* common.opt (gstatement-frontiers): New, setting
	debug_nonbind_markers_p.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
	* toplev.c (process_options): Autodetect value for debug statement
	frontiers option.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
---
 gcc/common.opt      |  4 ++++
 gcc/doc/invoke.texi | 12 ++++++++++++
 gcc/rtl.h           |  2 +-
 gcc/toplev.c        |  4 ++++
 gcc/tree.h          |  2 +-
 5 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index dfde6ad..a12c11c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2889,6 +2889,10 @@ gstabs+
 Common Driver JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format.
 
+gstatement-frontiers
+Common Driver Var(debug_nonbind_markers_p) Init(2)
+Emit progressive recommended breakpoint locations.
+
 gstrict-dwarf
 Common Driver Report Var(dwarf_strict) Init(0)
 Don't emit DWARF additions beyond selected version.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 108d730..85e41e4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -346,6 +346,7 @@ 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
+-gstatement-frontiers  -gno-statement-frontiers @gol
 -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
 -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
 -fno-eliminate-unused-debug-types @gol
@@ -7040,6 +7041,17 @@ 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 -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
diff --git a/gcc/rtl.h b/gcc/rtl.h
index c79a277..a0c27fc 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -816,7 +816,7 @@ struct GTY(()) rtvec_def {
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
 /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p
 /* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index bee79d3..0ef46da 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1514,6 +1514,10 @@ 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 (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/gcc/tree.h b/gcc/tree.h
index 62a85ea..8c3bda1 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1127,7 +1127,7 @@ 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 gimple_debug_nonbind_marker_p() may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p
 /* Nonzero if gimple_debug_bind_p() (and thus
    gimple_debug_source_bind_p()) may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 9/9] [IEPM] Introduce inline entry point markers
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (6 preceding siblings ...)
  2017-09-30  9:10               ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
@ 2017-09-30  9:10               ` Alexandre Oliva
  2017-10-31  6:22                 ` Jeff Law
  2017-09-30  9:10               ` [PATCH 7/9] [LVU] Introduce location views Alexandre Oliva
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

Output DW_AT_entry_pc based on markers.

Introduce DW_AT_GNU_entry_view as a DWARF extension.

If views are enabled are we're not in strict compliance mode, output
DW_AT_GNU_entry_view if it might be nonzero.

This patch depends on SFN and LVU patchsets, and on the IEPM patch that
introduces the inline_entry debug hook.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_entry_view): New.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
	markers.
	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
	(BLOCK_INLINE_ENTRY_LABEL): New.
	(dwarf2out_var_location): Disregard inline entry markers.
	(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.
	(block_within_block_p, dwarf2out_inline_entry): New.
	(dwarf2out_finish): Check that no entries remained in
	inline_entry_data_table.
	* final.c (reemit_insn_block_notes): Handle inline entry notes.
	(final_scan_insn, notice_source_line): Likewise.
	(rest_of_clean_state): Skip inline entry markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
	markers.
	* gimple.c (gimple_build_debug_inline_entry): New.
	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_INLINE_ENTRY.
	(gimple_build_debug_inline_entry): Declare.
	(gimple_debug_inline_entry_p): New.
	(gimple_debug_nonbind_marker_p): Adjust.
	* insn-notes.def (INLINE_ENTRY): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	inline entry marker notes.
	(print_insn): Likewise.
	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
	(INSN_DEBUG_MARKER_KIND): Likewise.
	* tree-inline.c	(expand_call_inline): Build and insert
	debug_inline_entry stmt.
	* 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.
	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
	(gimple_build_debug_inline_entry): New.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
	Enable/disable inline entry points too.
	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
	(DEBUG_INSN): Describe inline entry markers.
---
 gcc/cfgexpand.c           |   9 +++
 gcc/doc/gimple.texi       |  18 +++++
 gcc/doc/rtl.texi          |  24 ++++--
 gcc/dwarf2out.c           | 186 +++++++++++++++++++++++++++++++++++++++++++++-
 gcc/final.c               |  26 +++++++
 gcc/gimple-pretty-print.c |  13 ++++
 gcc/gimple.c              |  21 ++++++
 gcc/gimple.h              |  18 ++++-
 gcc/insn-notes.def        |   4 +
 gcc/print-rtl.c           |   5 ++
 gcc/rtl.h                 |   5 +-
 gcc/tree-inline.c         |   7 ++
 gcc/tree-ssa-live.c       |  27 +++++--
 gcc/var-tracking.c        |   1 +
 include/dwarf2.def        |   1 +
 15 files changed, 349 insertions(+), 16 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c854ffd..8ccdafd 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5691,6 +5691,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		goto delink_debug_stmt;
 	      else if (gimple_debug_begin_stmt_p (stmt))
 		val = gen_rtx_DEBUG_MARKER (VOIDmode);
+	      else if (gimple_debug_inline_entry_p (stmt))
+		{
+		  tree block = gimple_block (stmt);
+
+		  if (block)
+		    val = gen_rtx_DEBUG_MARKER (BLKmode);
+		  else
+		    goto delink_debug_stmt;
+		}
 	      else
 		gcc_unreachable ();
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 6c9c4789..af39d75 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -836,6 +836,11 @@ Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
 a source statement.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_inline_entry_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the entry
+point of an inlined function.
+@end deftypefn
+
 @deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
 Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
 without any variable binding.
@@ -1539,6 +1544,7 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
 @cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
+@cindex @code{GIMPLE_DEBUG_INLINE_ENTRY}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
@@ -1624,6 +1630,18 @@ observable, and that none of the side effects of subsequent user
 statements are.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_inline_entry (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_INLINE_ENTRY} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that a
+function call at @code{location} underwent inline substitution, that
+@code{block} is the enclosing lexical block created for the
+substitution, and that at the point of the program in which the stmt is
+inserted, all parameters for the inlined function are bound to the
+respective arguments, and none of the side effects of its stmts are
+observable.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 888ab02..a2f6e7a 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3430,7 +3430,10 @@ Refers to a parameter that was completely optimized out.
 @item (debug_marker:@var{mode})
 Marks a program location.  With @code{VOIDmode}, it stands for the
 beginning of a statement, a recommended inspection point logically after
-all prior side effects, and before any subsequent side effects.
+all prior side effects, and before any subsequent side effects.  With
+@code{BLKmode}, it indicates an inline entry point: the lexical block
+encoded in the @code{INSN_LOCATION} is the enclosing block that encloses
+the inlined function.
 
 @end table
 
@@ -3714,6 +3717,13 @@ This note is used to generate @code{is_stmt} markers in line number
 debuggign information.  It indicates the beginning of a user
 statement.
 
+@findex NOTE_INSN_INLINE_ENTRY
+@item NOTE_INSN_INLINE_ENTRY
+This note is used to generate @code{entry_pc} for inlined subroutines in
+debugging information.  It indicates an inspection point at which all
+arguments for the inlined function have been bound, and before its first
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3731,8 +3741,12 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
-with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{GIMPLE_DEBUG_BEGIN_STMT} and @code{GIMPLE_DEBUG_INLINE_ENTRY} are
+expanded to RTL as a @code{DEBUG_INSN} with a @code{DEBUG_MARKER}
+@code{PATTERN}; the difference is the RTL mode: the former's
+@code{DEBUG_MARKER} is @code{VOIDmode}, whereas the latter is
+@code{BLKmode}; information about the inlined function can be taken from
+the lexical block encoded in the @code{INSN_LOCATION}.  These
 @code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
 just @code{DEBUG_MARKER}s, can be detected by testing
 @code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
@@ -3743,8 +3757,8 @@ 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,
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION},
+@code{NOTE_INSN_BEGIN_STMT} and @code{NOTE_INSN_INLINE_ENTRY} 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
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index f435b5a..ed7a85a 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2720,6 +2720,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);
@@ -2773,7 +2774,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
-  debug_nothing_tree,		/* inline_entry */
+  dwarf2out_inline_entry,	/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -4011,6 +4012,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
@@ -23004,6 +23008,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
@@ -23458,6 +23504,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 (MAY_HAVE_DEBUG_MARKER_INSNS);
+      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))
     {
@@ -23465,7 +23547,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 (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23630,7 +23712,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26656,6 +26738,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
       || ! 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;
 
@@ -26844,6 +26927,100 @@ create_label:
   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.  */
@@ -30315,6 +30492,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 ());
diff --git a/gcc/final.c b/gcc/final.c
index c52c950..6c3a73b 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1672,6 +1672,7 @@ reemit_insn_block_notes (void)
 	    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;
 
@@ -2514,6 +2515,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  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);
@@ -2521,6 +2523,18 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    }
 	  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:
 	  gcc_unreachable ();
 	  break;
@@ -3224,6 +3238,17 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   if (NOTE_MARKER_P (insn))
     {
       location_t loc = NOTE_MARKER_LOCATION (insn);
+      /* The inline entry markers (gimple, insn, note) carry the
+	 location of the call, because that's what we want to carry
+	 during compilation, but the location we want to output in
+	 debug information for the inline entry point is the location
+	 of the function itself.  */
+      if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY)
+	{
+	  tree block = LOCATION_BLOCK (loc);
+	  tree fn = block_ultimate_origin (block);
+	  loc = DECL_SOURCE_LOCATION (fn);
+	}
       expanded_location xloc = expand_location (loc);
       if (xloc.line == 0)
 	{
@@ -4829,6 +4854,7 @@ rest_of_clean_state (void)
 	  && (!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/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 2702854..7c9c754 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1377,6 +1377,19 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 	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 dc9aa79..01ddc65 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -857,6 +857,27 @@ gimple_build_debug_begin_stmt (tree block, location_t location
 }
 
 
+/* 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.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 68cd34f..909807f 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -203,7 +203,8 @@ enum gf_mask {
 enum gimple_debug_subcode {
   GIMPLE_DEBUG_BIND = 0,
   GIMPLE_DEBUG_SOURCE_BIND = 1,
-  GIMPLE_DEBUG_BEGIN_STMT = 2
+  GIMPLE_DEBUG_BEGIN_STMT = 2,
+  GIMPLE_DEBUG_INLINE_ENTRY = 3
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -1455,6 +1456,7 @@ 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);
@@ -4766,13 +4768,25 @@ gimple_debug_begin_stmt_p (const gimple *s)
   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;
+    return s->subcode == GIMPLE_DEBUG_BEGIN_STMT
+      || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
 
   return false;
 }
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index 960487b..252e957 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -71,6 +71,10 @@ 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/print-rtl.c b/gcc/print-rtl.c
index 0d36a42..cca8798 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -259,6 +259,7 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_BEGIN_STMT:
+	case NOTE_INSN_INLINE_ENTRY:
 #ifndef GENERATOR_FILE
 	  {
 	    expanded_location xloc
@@ -1809,6 +1810,10 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 		pp_string (pp, "debug begin stmt marker");
 		break;
 
+	      case NOTE_INSN_INLINE_ENTRY:
+		pp_string (pp, "debug inline entry marker");
+		break;
+
 	      default:
 		gcc_unreachable ();
 	      }
diff --git a/gcc/rtl.h b/gcc/rtl.h
index a0c27fc..cd177c7 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1625,7 +1625,8 @@ extern const char * const reg_note_name[];
    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_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))
@@ -1663,6 +1664,8 @@ extern const char * const reg_note_name[];
   (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
    ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
       ? NOTE_INSN_BEGIN_STMT			  \
+      : GET_MODE (PATTERN (INSN)) == BLKmode	  \
+      ? NOTE_INSN_INLINE_ENTRY			  \
       : (enum insn_note)-1) 			  \
    : (enum insn_note)-1)
 
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index a99e975..41b4fd9 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4704,6 +4704,13 @@ 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, input_location), GSI_NEW_STMT);
+    }
 
   if (DECL_INITIAL (fn))
     {
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/var-tracking.c b/gcc/var-tracking.c
index d3850af..21ffe57 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9931,6 +9931,7 @@ reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
   switch (kind)
     {
     case NOTE_INSN_BEGIN_STMT:
+    case NOTE_INSN_INLINE_ENTRY:
       {
 	rtx_insn *note = NULL;
 	if (cfun->debug_nonbind_markers)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index f3fa400..8e731a3 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -444,6 +444,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
    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.  */
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 7/9] [LVU] Introduce location views
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (7 preceding siblings ...)
  2017-09-30  9:10               ` [PATCH 9/9] [IEPM] Introduce " Alexandre Oliva
@ 2017-09-30  9:10               ` Alexandre Oliva
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch introduces an option to enable the generation of location
views along with location lists.  The exact format depends on the
DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
(DW_LLE_view_pair) entries in DWARF5+ loclists.

Line number tables are also affected.  If the assembler is found, at
compiler build time, to support .loc views, we use them and
assembler-computed view labels, otherwise we output compiler-generated
line number programs with conservatively-computed view labels.  In
either case, we output view information next to line number changes
when verbose assembly output is requested.

This patch requires an LVU patch that modifies the exported API of
final_scan_insn.  It also expects the entire SFN patchset to be
installed first, although SFN is not a requirement for LVU.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_locviews): New.
	* dwarf2.h (enum dwarf_location_list_entry_type): Add
	DW_LLE_GNU_view_pair.
	(DW_LLE_view_pair): Define.

for  gcc/ChangeLog

	* common.opt (gvariable-location-views): New.
	* config.in: Rebuilt.
	* configure: Rebuilt.
	* configure.ac: Test assembler for view support.
	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
	* dwarf2out.c (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.
	(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.
	(maybe_emit_file): Call output_asm_line_debug_info for test.
	(dwarf2out_var_location): Reset views as needed.  Precompute
	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
	attribute.  Set view.
	(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.
	Use output_dwarf_version.
	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
	(struct dw_val_node): Add val_view_list.
	* final.c: Include langhooks.h.
	(SEEN_NEXT_VIEW): New.
	(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.  Notify debug backend of section
	changes, and of location view changes.
	(rest_of_handle_final): Adjust.
	* opts.c (common_handle_option): Accept -gdwarf version 6.
	* toplev.c (process_options): Autodetect value for debug variable
	location views option.
	* doc/invoke.texi (gvariable-location-views): New.
	(gno-variable-location-views): New.
---
 gcc/common.opt      |   4 +
 gcc/config.in       |   6 +
 gcc/configure       |  46 ++++
 gcc/configure.ac    |  18 +-
 gcc/doc/invoke.texi |  19 ++
 gcc/dwarf2asm.c     |  25 ++
 gcc/dwarf2asm.h     |   4 +
 gcc/dwarf2out.c     | 646 ++++++++++++++++++++++++++++++++++++++++++++++------
 gcc/dwarf2out.h     |   4 +-
 gcc/final.c         | 125 +++++++++-
 gcc/opts.c          |   2 +-
 gcc/toplev.c        |   8 +
 include/dwarf2.def  |   1 +
 include/dwarf2.h    |   8 +
 14 files changed, 834 insertions(+), 82 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index a12c11c..5bfcd4b 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2901,6 +2901,10 @@ gtoggle
 Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
+gvariable-location-views
+Common Driver Var(debug_variable_location_views) Init(2)
+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/configure b/gcc/configure
index 13f97cd..6484f6a 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 8271138..ba37496 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/doc/invoke.texi b/gcc/doc/invoke.texi
index 85e41e4..7fb40d5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -347,6 +347,7 @@ Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gcolumn-info  -gno-column-info @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
 -fno-eliminate-unused-debug-types @gol
@@ -7052,6 +7053,24 @@ 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.
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 f4e5947..6b19c4a 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1276,6 +1276,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.  */
@@ -1285,9 +1287,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.  */
@@ -1324,6 +1328,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.  */
@@ -1399,6 +1428,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:
@@ -2844,7 +2875,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 {
@@ -2866,6 +2905,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;
 };
 
@@ -3067,6 +3125,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
@@ -3176,6 +3269,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.  */
@@ -3384,6 +3478,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);
@@ -3420,7 +3516,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 void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -3620,8 +3716,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);
@@ -4617,11 +4713,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>
@@ -5884,7 +6024,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;
@@ -5975,7 +6115,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.  */
@@ -5991,7 +6131,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
 	    {
@@ -6126,6 +6266,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;
@@ -8990,6 +9136,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);
@@ -9361,6 +9508,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)
@@ -9635,7 +9783,8 @@ output_abbrev_section (void)
    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> ();
@@ -9645,10 +9794,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.  */
 
@@ -9657,6 +9824,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.  */
@@ -9664,34 +9924,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,
@@ -9709,6 +10020,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
@@ -9759,6 +10071,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);
@@ -9773,6 +10086,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);
@@ -9788,6 +10102,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);
@@ -9866,6 +10181,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
@@ -9930,6 +10248,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
@@ -10155,6 +10489,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))
 	    {
@@ -10339,6 +10677,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.  */
 
@@ -10355,7 +10715,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;
@@ -10567,7 +10927,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");
@@ -10866,7 +11226,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,
@@ -10948,7 +11308,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,
@@ -11209,7 +11569,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
@@ -11843,8 +12203,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)
     {
@@ -11859,14 +12222,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)
 	    {
@@ -11974,7 +12359,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");
@@ -16298,6 +16683,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;
@@ -16353,24 +16739,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)
@@ -16393,12 +16782,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;
 	      }
 	  }
@@ -16410,8 +16799,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;
 }
@@ -17231,7 +17619,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;
     }
@@ -18044,7 +18432,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;
 }
@@ -18368,12 +18756,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.  */
@@ -19557,7 +19958,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;
     }
@@ -19573,7 +19974,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;
@@ -19595,14 +19996,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;
 	}
@@ -19611,19 +20012,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;
 }
@@ -25984,7 +26384,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,
@@ -26178,11 +26578,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++;
@@ -26216,6 +26618,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
 		}
 	    }
 	}
+      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;
     }
 
@@ -26279,10 +26693,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;
     }
@@ -26323,8 +26738,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
@@ -26392,7 +26807,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)
@@ -26401,6 +26819,7 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      newloc->view = view;
     }
 
   if (var_loc_p && flag_debug_asm)
@@ -26467,6 +26886,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;
 }
@@ -26515,7 +26935,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);
@@ -26696,7 +27116,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",
@@ -26719,6 +27139,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
@@ -26727,7 +27174,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)
@@ -27402,9 +27861,10 @@ init_sections_and_labels (bool early_lto_debug)
 					    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);
+
       debug_ranges_section = get_section (dwarf_version >= 5
 					  ? DEBUG_RNGLISTS_SECTION
 					  : DEBUG_RANGES_SECTION,
@@ -27783,6 +28243,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.
@@ -28882,6 +29347,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)
@@ -28926,7 +29393,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)
@@ -28996,6 +29463,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);
@@ -29021,6 +29489,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);
@@ -29417,6 +29900,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);
@@ -29638,6 +30123,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;
@@ -29656,6 +30142,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)
@@ -29666,11 +30154,33 @@ 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));
 }
 
@@ -29695,7 +30205,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
@@ -30119,7 +30629,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,
@@ -30178,7 +30688,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/final.c b/gcc/final.c
index d2b8523d..c52c950 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;
@@ -1752,6 +1754,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
@@ -1759,12 +1799,15 @@ 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 **firstp, 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;
 
@@ -1785,7 +1828,28 @@ final_start_function (rtx_insn **firstp, 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);
@@ -1860,6 +1924,17 @@ final_start_function (rtx_insn **firstp, 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)
 {
@@ -1991,11 +2066,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;
@@ -2062,6 +2136,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);
@@ -2078,6 +2154,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);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2218,6 +2302,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 ())
@@ -2358,6 +2444,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
@@ -2415,7 +2503,10 @@ 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:
@@ -2426,6 +2517,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
 					   last_filename, last_discriminator,
 					   true);
+	      clear_next_view_needed (seen);
 	    }
 	  break;
 
@@ -2621,6 +2713,10 @@ 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
@@ -2633,7 +2729,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    (*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)
@@ -3100,7 +3201,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;
@@ -4539,8 +4641,9 @@ rest_of_handle_final (void)
 
   assemble_start_function (current_function_decl, fnname);
   rtx_insn *first = get_insns ();
-  final_start_function (&first, asm_out_file, optimize);
-  final (first, asm_out_file, optimize);
+  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 ();
diff --git a/gcc/opts.c b/gcc/opts.c
index 5aa5d06..179a20b 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2367,7 +2367,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/toplev.c b/gcc/toplev.c
index 0ef46da..25d46b5 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1518,6 +1518,14 @@ process_options (void)
     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/include/dwarf2.def b/include/dwarf2.def
index 2a3b23f..f3fa400 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* VMS extensions.  */
 DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
 /* GNAT extensions.  */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index a2e022d..fd76d82 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -298,6 +298,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,
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (4 preceding siblings ...)
  2017-09-30  9:09               ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
@ 2017-09-30  9:10               ` Alexandre Oliva
  2017-10-09 13:07                 ` Richard Biener
  2017-09-30  9:10               ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
                                 ` (3 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

This patch adjusts numerous parts of the compiler that would
malfunction should they find debug markers at points where they may be
introduced.  The changes purport to allow the compiler to pass
bootstrap-debug-lean (-fcompare-debug in stage3) at various
optimization levels, as well as bootstrap-debug-lib (-fcompare-debug
for target libraries), even after the compiler is changed so that
debug markers are introduced in code streams at spots where earlier
debug stmts, insns and notes wouldn't normally appear.

This patch depends on an earlier SFN boilerplate patch, and on another
SFN patch that introduces new RTL insn-walking functions.

for  gcc/ChangeLog

	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
	* cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
	(rtl_tidy_fallthru_edge): Likewise.
	(rtl_verify_fallthru): Likewise.
	(rtl_verify_bb_layout): Likewise.
	(skip_insns_after_block): Likewise.
	(duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
	* dwarf2out.c: Include print-rtl.h.
	(dwarf2out_next_real_insn): New.
	(dwarf2out_var_location): Call it.  Disregard begin stmt markers.
	Dump debug binds in asm comments.
	* gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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 (gimple_seq_may_fallthru): Take last nondebug stmt.
	* gimple.h (gimple_seq_last_nondebug_stmt): New.
	* gimplify.c (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.
	* 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.
	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
	* jump.c (clean_barriers): Skip debug insns.
	* 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.
	* postreload.c (fixup_debug_insns): Skip nonbind debug insns.
	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
	* 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
	* var-tracking.c (get_first_insn): New.
	(vt_emit_notes): Call it.
	(vt_initialize): Walk any insns before the first BB.
	(delete_debug_insns): Likewise.
---
 gcc/cfgbuild.c                   |   1 +
 gcc/cfgcleanup.c                 |  12 +--
 gcc/cfgexpand.c                  |  24 +++++-
 gcc/cfgrtl.c                     |  18 +++--
 gcc/dwarf2out.c                  |  38 ++++++++-
 gcc/gimple-iterator.c            |  24 +++++-
 gcc/gimple-iterator.h            |  46 ++++++-----
 gcc/gimple-low.c                 |   2 +-
 gcc/gimple.h                     |  16 ++++
 gcc/gimplify.c                   |  21 ++---
 gcc/graphite-isl-ast-to-gimple.c |   7 +-
 gcc/graphite-scop-detection.c    |   2 +-
 gcc/haifa-sched.c                |   2 +-
 gcc/ipa-icf-gimple.c             |   4 +-
 gcc/jump.c                       |   2 +-
 gcc/omp-expand.c                 | 161 ++++++++++++++++++++-------------------
 gcc/omp-low.c                    |   2 +
 gcc/postreload.c                 |   2 +-
 gcc/regcprop.c                   |   2 +
 gcc/tree-cfg.c                   |  52 +++++++++++--
 gcc/tree-cfgcleanup.c            |  31 +++-----
 gcc/tree-pretty-print.c          |   5 +-
 gcc/tree-ssa-dce.c               |   6 +-
 gcc/tree-ssa-tail-merge.c        |   4 +-
 gcc/var-tracking.c               |  54 ++++++++++++-
 25 files changed, 365 insertions(+), 173 deletions(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 76c21d7..a2e467c 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -475,6 +475,7 @@ find_bb_boundaries (basic_block bb)
 	  if (debug_insn && code != CODE_LABEL && code != BARRIER)
 	    prev = PREV_INSN (debug_insn);
 	  fallthru = split_block (bb, prev);
+
 	  if (flow_transfer_insn)
 	    {
 	      BB_END (bb) = flow_transfer_insn;
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 365c971..be88fdd 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -3060,13 +3060,13 @@ delete_unreachable_blocks (void)
 
   find_unreachable_blocks ();
 
-  /* When we're in GIMPLE mode and there may be debug insns, we should
-     delete blocks in reverse dominator order, so as to get a chance
-     to substitute all released DEFs into debug stmts.  If we don't
-     have dominators information, walking blocks backward gets us a
-     better chance of retaining most debug information than
+  /* When we're in GIMPLE mode and there may be debug bind insns, we
+     should delete blocks in reverse dominator order, so as to get a
+     chance to substitute all released DEFs into debug bind stmts.  If
+     we don't have dominators information, walking blocks backward
+     gets us a better chance of retaining most debug information than
      otherwise.  */
-  if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE
+  if (MAY_HAVE_DEBUG_BIND_INSNS && current_ir_type () == IR_GIMPLE
       && dom_info_available_p (CDI_DOMINATORS))
     {
       for (b = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index cb866aa..5a46b5e 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;
@@ -5432,7 +5435,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;
@@ -5473,18 +5476,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)
@@ -5499,6 +5510,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);
@@ -5506,7 +5518,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))
     {
@@ -5514,6 +5527,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
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index bce56b4..d43e38c 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.
@@ -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 (DEBUG_BIND_INSN_P (insn)
+	      && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
 	    break;
 	  /* FALLTHRU */
 	case INSN:
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index e97ceb6..f4e5947 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"
@@ -26144,6 +26145,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.  */
@@ -26192,7 +26209,7 @@ 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;
@@ -26222,11 +26239,12 @@ 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_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)
     {
@@ -26385,6 +26403,22 @@ create_label:
       newloc->label = last_postcall_label;
     }
 
+  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;
 }
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 3b74cc5..fb75f99 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -744,9 +744,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 +780,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..22db61b 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -645,7 +645,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.h b/gcc/gimple.h
index 1783e11..8f289ac 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -4582,6 +4582,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
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index c3fd6ac..e9dffc3 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1855,7 +1855,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 +1868,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 +1995,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 +2032,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 +2045,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 +2092,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 +2233,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);
diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
index 820e14e..3e3d5531 100644
--- a/gcc/graphite-isl-ast-to-gimple.c
+++ b/gcc/graphite-isl-ast-to-gimple.c
@@ -1252,7 +1252,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;
@@ -1284,7 +1284,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);
 	}
@@ -1567,7 +1567,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 b374ee1..23da9cc 100644
--- a/gcc/graphite-scop-detection.c
+++ b/gcc/graphite-scop-detection.c
@@ -262,7 +262,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))
 	&& gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
       return false;
 
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 34cc46b..e99aa69 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/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index b40dd865..be8c709 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -640,8 +640,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/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/omp-expand.c b/gcc/omp-expand.c
index 4bdcf19..fe25b83 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);
 
@@ -4795,7 +4795,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.  */
@@ -4921,7 +4921,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)
@@ -5022,10 +5022,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 ();
@@ -5099,7 +5099,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)
@@ -5178,7 +5178,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);
@@ -5215,7 +5215,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 ();
@@ -5398,7 +5398,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);
 
@@ -5525,7 +5525,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);
@@ -5649,7 +5649,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);
 
@@ -5738,7 +5738,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));
 
@@ -5965,7 +5965,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)
@@ -5973,7 +5973,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)
 	      {
@@ -5998,7 +5998,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);
@@ -6022,7 +6022,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)
     {
@@ -6064,7 +6064,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);
@@ -6073,7 +6073,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);
 
@@ -6099,7 +6099,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);
@@ -6112,7 +6112,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)))
@@ -6140,12 +6140,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));
@@ -6168,7 +6168,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
@@ -6180,7 +6180,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;
@@ -6201,7 +6201,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);
@@ -6231,7 +6231,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);
 
@@ -6257,14 +6257,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);
@@ -6309,7 +6309,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))
@@ -6356,10 +6356,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));
@@ -6423,7 +6430,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.
@@ -6446,10 +6453,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);
 
@@ -6502,7 +6509,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
@@ -6582,7 +6589,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)
@@ -6685,7 +6692,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);
@@ -6696,7 +6703,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)),
@@ -7195,7 +7202,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));
@@ -7207,7 +7214,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);
@@ -7389,7 +7396,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));
 	}
@@ -7424,11 +7431,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);
     }
@@ -7572,7 +7579,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);
@@ -7653,17 +7660,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)
@@ -7807,11 +7814,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);
@@ -7995,7 +8002,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 8ed8f7c..8852798 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -7023,6 +7023,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/postreload.c b/gcc/postreload.c
index 000ed34..8e4a8190 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -836,7 +836,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to)
     {
       rtx t;
 
-      if (!DEBUG_INSN_P (insn))
+      if (!DEBUG_BIND_INSN_P (insn))
 	continue;
       
       t = INSN_VAR_LOCATION_LOC (insn);
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 0ce64d7..ee9b119 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -433,6 +433,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) (...))
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index dc9ce3c..1796850 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.  */
@@ -5444,6 +5475,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);
@@ -5513,7 +5548,7 @@ gimple_verify_flow_info (void)
 	    }
 	}
 
-      gsi = gsi_last_bb (bb);
+      gsi = gsi_last_nondebug_bb (bb);
       if (gsi_end_p (gsi))
 	continue;
 
@@ -5768,8 +5803,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;
@@ -5780,6 +5817,7 @@ gimple_block_label (basic_block bb)
 	    gsi_move_before (&i, &s);
 	  return label;
 	}
+      first = false;
     }
 
   label = create_artificial_label (UNKNOWN_LOCATION);
@@ -5855,7 +5893,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 a7053d7..3c4d573 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -555,13 +555,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);
@@ -570,20 +570,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.  */
@@ -1285,7 +1271,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-pretty-print.c b/gcc/tree-pretty-print.c
index 14c7caa..1fe3e63 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3386,7 +3386,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 f60670f..28cf643 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-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a3d5074..01b8821 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/var-tracking.c b/gcc/var-tracking.c
index 43fc71a..974b4ea 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9472,6 +9472,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
@@ -9500,7 +9518,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_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
@@ -10096,11 +10115,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 (DEBUG_BIND_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);
@@ -10168,6 +10210,7 @@ vt_initialize (void)
 			    }
 			}
 		    }
+		  BLOCK_FOR_INSN (insn) = save_bb;
 		}
 	    }
 	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
@@ -10208,7 +10251,10 @@ 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))
 	  {
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (5 preceding siblings ...)
  2017-09-30  9:10               ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-09-30  9:10               ` Alexandre Oliva
  2017-10-31  5:58                 ` Jeff Law
  2017-09-30  9:10               ` [PATCH 9/9] [IEPM] Introduce " Alexandre Oliva
                                 ` (2 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-09-30  9:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Alexandre Oliva

The inline_entry hook will be given a definition in a later patch.

for  gcc/ChangeLog

	* 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.
	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
	(dwarf2_lineno_debug_hooks): Likewise.
---
 gcc/dbxout.c    | 2 ++
 gcc/debug.c     | 1 +
 gcc/debug.h     | 3 +++
 gcc/dwarf2out.c | 2 ++
 gcc/sdbout.c    | 1 +
 gcc/vmsdbgout.c | 1 +
 6 files changed, 10 insertions(+)

diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index ea7c97c..6ba0471 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -379,6 +379,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 */
@@ -421,6 +422,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 4db94c3..c0bc667 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -55,6 +55,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 915420b..8c888b6 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -176,6 +176,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/dwarf2out.c b/gcc/dwarf2out.c
index 6b19c4a..f435b5a 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2773,6 +2773,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
+  debug_nothing_tree,		/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -2813,6 +2814,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 */
diff --git a/gcc/sdbout.c b/gcc/sdbout.c
index acd25a3..ba64432 100644
--- a/gcc/sdbout.c
+++ b/gcc/sdbout.c
@@ -309,6 +309,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/vmsdbgout.c b/gcc/vmsdbgout.c
index 580dd28..83ba2ae 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -205,6 +205,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 */
-- 
2.9.5

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers
  2017-09-30  9:09               ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-10-09 13:02                 ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2017-10-09 13:02 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> This patch introduces a number of new macros and functions that will
> be used to distinguish between different kinds of debug stmts, insns
> and notes, namely, preexisting debug bind ones and to-be-introduced
> nonbind markers.
>
> In a seemingly mechanical way, it adjusts several uses of the macros
> and functions, so that they refer to narrower categories when
> appropriate.
>
> These changes, by themselves, should not have any visible effect in
> the compiler behavior, since the upcoming debug markers are never
> created with this patch alone.

Ok.

Thanks,
Richard.

> for  gcc/ChangeLog
>
>         * gimple.h (enum gimple_debug_subcode): Add
>         GIMPLE_DEBUG_BEGIN_STMT.
>         (gimple_debug_begin_stmt_p): New.
>         (gimple_debug_nonbind_marker_p): New.
>         * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
>         (MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
>         (MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
>         * insn-notes.def (BEGIN_STMT): New.
>         * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
>         (MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
>         (MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
>         (NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
>         (DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
>         (INSN_DEBUG_MARKER_KIND): New.
>         (INSN_VAR_LOCATION): Check for VAR_LOCATION.
>         (INSN_VAR_LOCATION_PTR): New.
>         * cfgexpand.c (expand_debug_locations): Handle debug bind insns
>         only.
>         (expand_gimple_basic_block): Likewise.  Emit debug temps for TER
>         deps only if debug bind insns are enabled.
>         (pass_expand::execute): Avoid deep TER and expand
>         debug locations for debug bind insns only.
>         * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
>         debug stmts special handling down to debug bind stmts.
>         * combine.c (try_combine): Narrow debug insns special handling
>         down to debug bind insns.
>         * cse.c (delete_trivially_dead_insns): Handle debug bindings.
>         Narrow debug insns preexisting special handling down to debug
>         bind insns.
>         * dce.c (rest_of_handle_ud_dce): Narrow debug insns special
>         handling down to debug bind insns.
>         * function.c (instantiate_virtual_regs): Skip debug markers,
>         adjust handling of debug binds.
>         * gimple-ssa-backprop.c (backprop::prepare_change): Try debug
>         temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
>         * haifa-sched.c (schedule_insn): Narrow special handling of debug
>         insns to debug bind insns.
>         * ipa-prop.c (ipa_modify_call_arguments): Narrow special
>         handling of debug insns to debug bind insns.
>         * ipa-split.c (split_function): Likewise.
>         * ira.c (combine_and_move_insns): Adjust debug bind insns only.
>         * loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
>         debug insns.
>         * reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
>         * regrename.c (build_def_use): Likewise.
>         * regcprop.c (copyprop_hardreg_forward_1): Likewise.
>         (pass_cprop_hardreg): Narrow special casing of debug insns to
>         debug bind insns.
>         * regstat.c (regstat_init_n_sets_and_refs): Likewise.
>         * reload1.c (reload): Likewise.
>         * sese.c (sese_build_liveouts): Narrow special casing of debug
>         stmts to debug bind stmts.
>         * shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
>         * ssa-iterators.h (num_imm_uses): Likewise.
>         * tree-cfg.c (gimple_merge_blocks): Narrow special casing of
>         debug stmts to debug bind stmts.
>         * tree-inline.c (tree_function_versioning): Narrow special casing
>         of debug stmts to debug bind stmts.
>         * tree-loop-distribution.c (generate_loops_for_partition):
>         Narrow special casing of debug stmts to debug bind stmts.
>         * tree-sra.c (analyze_access_subtree): Narrow special casing
>         of debug stmts to debug bind stmts.
>         * tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
>         stmts to debug bind stmts.
>         * tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
>         casing of debug stmts to debug bind stmts.
>         * tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
>         * tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
>         casing of debug stmts to debug bind stmts.
>         * tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
>         Likewise.
>         * tree-ssa.c (flush_pending_stmts): Narrow special casing of
>         debug stmts to debug bind stmts.
>         (gimple_replace_ssa_lhs): Likewise.
>         (insert_debug_temp_for_var_def): Likewise.
>         (insert_debug_temps_for_defs): Likewise.
>         (reset_debug_uses): Likewise.
>         * tree-ssanames.c (release_ssa_name_fn): Likewise.
>         * tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
>         (adjust_debug_stmts): Likewise.
>         (adjust_phi_and_debug_stmts): Likewise.
>         (vect_do_peeling): Likewise.
>         * tree-vect-loop.c (vect_transform_loop): Likewise.
>         * valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
>         * var-tracking.c (adjust_mems): Narrow special casing of debug
>         insns to debug bind insns.
>         (dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
>         (compute_bb_dataflow, vt_find_locations): Likewise.
>         (vt_expand_loc, emit_notes_for_changes): Likewise.
>         (vt_init_cfa_base): Likewise.
>         (vt_emit_notes): Likewise.
>         (vt_initialize): Likewise.
>         (vt_finalize): Likewise.
> ---
>  gcc/cfgexpand.c              |  8 +++----
>  gcc/cgraph.c                 |  2 +-
>  gcc/combine.c                | 12 +++++------
>  gcc/cse.c                    | 17 ++++++++-------
>  gcc/dce.c                    |  2 +-
>  gcc/function.c               |  7 ++++---
>  gcc/gimple-ssa-backprop.c    |  2 +-
>  gcc/gimple.h                 | 31 ++++++++++++++++++++++-----
>  gcc/haifa-sched.c            |  4 ++--
>  gcc/insn-notes.def           |  3 +++
>  gcc/ipa-prop.c               |  2 +-
>  gcc/ipa-split.c              | 11 +++++-----
>  gcc/ira.c                    |  4 ++--
>  gcc/loop-unroll.c            |  6 ++++--
>  gcc/reg-stack.c              |  4 ++--
>  gcc/regcprop.c               |  4 ++--
>  gcc/regrename.c              |  2 +-
>  gcc/regstat.c                |  2 +-
>  gcc/reload1.c                |  4 ++--
>  gcc/rtl.h                    | 40 +++++++++++++++++++++++++++++++++--
>  gcc/sese.c                   |  2 +-
>  gcc/shrink-wrap.c            |  4 ++--
>  gcc/ssa-iterators.h          |  2 +-
>  gcc/tree-cfg.c               |  2 +-
>  gcc/tree-inline.c            |  4 ++--
>  gcc/tree-loop-distribution.c |  2 +-
>  gcc/tree-sra.c               |  2 +-
>  gcc/tree-ssa-dce.c           |  2 +-
>  gcc/tree-ssa-loop-ivopts.c   |  2 +-
>  gcc/tree-ssa-reassoc.c       |  2 +-
>  gcc/tree-ssa-tail-merge.c    |  2 +-
>  gcc/tree-ssa-threadedge.c    |  2 +-
>  gcc/tree-ssa.c               | 10 ++++-----
>  gcc/tree-ssanames.c          |  2 +-
>  gcc/tree-vect-loop-manip.c   |  8 +++----
>  gcc/tree-vect-loop.c         |  4 ++--
>  gcc/tree.h                   |  8 ++++++-
>  gcc/valtrack.c               |  2 +-
>  gcc/var-tracking.c           | 50 +++++++++++++++++++++-----------------------
>  39 files changed, 175 insertions(+), 104 deletions(-)
>
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index bd3312e..cb866aa 100644
> --- a/gcc/cfgexpand.c
> +++ b/gcc/cfgexpand.c
> @@ -5285,7 +5285,7 @@ expand_debug_locations (void)
>    flag_strict_aliasing = 0;
>
>    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
> -    if (DEBUG_INSN_P (insn))
> +    if (DEBUG_BIND_INSN_P (insn))
>        {
>         tree value = (tree)INSN_VAR_LOCATION_LOC (insn);
>         rtx val;
> @@ -5538,7 +5538,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>            a_2 = ...
>             #DEBUG ... => #D1
>          */
> -      if (MAY_HAVE_DEBUG_INSNS
> +      if (MAY_HAVE_DEBUG_BIND_INSNS
>           && SA.values
>           && !is_gimple_debug (stmt))
>         {
> @@ -6165,7 +6165,7 @@ pass_expand::execute (function *fun)
>    timevar_pop (TV_OUT_OF_SSA);
>    SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions);
>
> -  if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter)
>      {
>        gimple_stmt_iterator gsi;
>        FOR_EACH_BB_FN (bb, cfun)
> @@ -6356,7 +6356,7 @@ pass_expand::execute (function *fun)
>                   next_bb)
>      bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      expand_debug_locations ();
>
>    if (deep_ter_debug_map)
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index 3d0cefb..cd60193 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -1459,7 +1459,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
>          stmts and associate D#X with parm in decl_debug_args_lookup
>          vector to say for debug info that if parameter parm had been passed,
>          it would have value parm_Y(D).  */
> -      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS)
> +      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
>         {
>           vec<tree, va_gc> **debug_args
>             = decl_debug_args_lookup (e->callee->decl);
> diff --git a/gcc/combine.c b/gcc/combine.c
> index e502fa1..86d710d 100644
> --- a/gcc/combine.c
> +++ b/gcc/combine.c
> @@ -3726,7 +3726,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>           /* *SPLIT may be part of I2SRC, so make sure we have the
>              original expression around for later debug processing.
>              We should not need I2SRC any more in other cases.  */
> -         if (MAY_HAVE_DEBUG_INSNS)
> +         if (MAY_HAVE_DEBUG_BIND_INSNS)
>             i2src = copy_rtx (i2src);
>           else
>             i2src = NULL;
> @@ -4083,7 +4083,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>        return 0;
>      }
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        struct undo *undo;
>
> @@ -4396,7 +4396,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>
>      if (newi2pat)
>        {
> -       if (MAY_HAVE_DEBUG_INSNS && i2scratch)
> +       if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch)
>           propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
>                                this_basic_block);
>         INSN_CODE (i2) = i2_code_number;
> @@ -4404,7 +4404,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>        }
>      else
>        {
> -       if (MAY_HAVE_DEBUG_INSNS && i2src)
> +       if (MAY_HAVE_DEBUG_BIND_INSNS && i2src)
>           propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
>                                this_basic_block);
>         SET_INSN_DELETED (i2);
> @@ -4414,7 +4414,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>        {
>         LOG_LINKS (i1) = NULL;
>         REG_NOTES (i1) = 0;
> -       if (MAY_HAVE_DEBUG_INSNS)
> +       if (MAY_HAVE_DEBUG_BIND_INSNS)
>           propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
>                                this_basic_block);
>         SET_INSN_DELETED (i1);
> @@ -4424,7 +4424,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
>        {
>         LOG_LINKS (i0) = NULL;
>         REG_NOTES (i0) = 0;
> -       if (MAY_HAVE_DEBUG_INSNS)
> +       if (MAY_HAVE_DEBUG_BIND_INSNS)
>           propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
>                                this_basic_block);
>         SET_INSN_DELETED (i0);
> diff --git a/gcc/cse.c b/gcc/cse.c
> index 672fd2e..d1577a6 100644
> --- a/gcc/cse.c
> +++ b/gcc/cse.c
> @@ -7054,11 +7054,11 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
>
>    timevar_push (TV_DELETE_TRIVIALLY_DEAD);
>    /* First count the number of times each register is used.  */
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        counts = XCNEWVEC (int, nreg * 3);
>        for (insn = insns; insn; insn = NEXT_INSN (insn))
> -       if (DEBUG_INSN_P (insn))
> +       if (DEBUG_BIND_INSN_P (insn))
>           count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
>                            NULL_RTX, 1);
>         else if (INSN_P (insn))
> @@ -7116,12 +7116,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
>        if (! live_insn && dbg_cnt (delete_trivial_dead))
>         {
>           if (DEBUG_INSN_P (insn))
> -           count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
> -                            NULL_RTX, -1);
> +           {
> +             if (DEBUG_BIND_INSN_P (insn))
> +               count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
> +                                NULL_RTX, -1);
> +           }
>           else
>             {
>               rtx set;
> -             if (MAY_HAVE_DEBUG_INSNS
> +             if (MAY_HAVE_DEBUG_BIND_INSNS
>                   && (set = single_set (insn)) != NULL_RTX
>                   && is_dead_reg (SET_DEST (set), counts)
>                   /* Used at least once in some DEBUG_INSN.  */
> @@ -7161,10 +7164,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
>         }
>      }
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
> -       if (DEBUG_INSN_P (insn))
> +       if (DEBUG_BIND_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/dce.c b/gcc/dce.c
> index 7534d2a..6fd9548 100644
> --- a/gcc/dce.c
> +++ b/gcc/dce.c
> @@ -777,7 +777,7 @@ rest_of_handle_ud_dce (void)
>      }
>    worklist.release ();
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      reset_unmarked_insns_debug_uses ();
>
>    /* Before any insns are deleted, we must remove the chains since
> diff --git a/gcc/function.c b/gcc/function.c
> index c03e2ac..ae61d3d 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
> +           || DEBUG_MARKER_INSN_P (insn))
>           continue;
> -       else if (DEBUG_INSN_P (insn))
> -         instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
> +       else if (DEBUG_BIND_INSN_P (insn))
> +         instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
>         else
>           instantiate_virtual_regs_in_insn (insn);
>
> diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c
> index f321ebb..b6e11c4 100644
> --- a/gcc/gimple-ssa-backprop.c
> +++ b/gcc/gimple-ssa-backprop.c
> @@ -726,7 +726,7 @@ strip_sign_op (tree rhs)
>  void
>  backprop::prepare_change (tree var)
>  {
> -  if (MAY_HAVE_DEBUG_STMTS)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
>      insert_debug_temp_for_var_def (NULL, var);
>    reset_flow_sensitive_info (var);
>  }
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 6213c49..1783e11 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -198,13 +198,12 @@ 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
>  };
>
>  /* Masks for selecting a pass local flag (PLF) to work on.  These
> @@ -4739,6 +4738,28 @@ 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 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;
> +
> +  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/haifa-sched.c b/gcc/haifa-sched.c
> index 549e896..34cc46b 100644
> --- a/gcc/haifa-sched.c
> +++ b/gcc/haifa-sched.c
> @@ -4010,7 +4010,7 @@ schedule_insn (rtx_insn *insn)
>    gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK));
>
>    /* Reset debug insns invalidated by moving this insn.  */
> -  if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn))
> +  if (MAY_HAVE_DEBUG_BIND_INSNS && !DEBUG_INSN_P (insn))
>      for (sd_it = sd_iterator_start (insn, SD_LIST_BACK);
>          sd_iterator_cond (&sd_it, &dep);)
>        {
> @@ -4023,7 +4023,7 @@ schedule_insn (rtx_insn *insn)
>             continue;
>           }
>
> -       gcc_assert (DEBUG_INSN_P (dbg));
> +       gcc_assert (DEBUG_BIND_INSN_P (dbg));
>
>         if (sched_verbose >= 6)
>           fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n",
> diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
> index f96ce18..960487b 100644
> --- a/gcc/insn-notes.def
> +++ b/gcc/insn-notes.def
> @@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
>  /* The values passed to callee.  */
>  INSN_NOTE (CALL_ARG_LOCATION)
>
> +/* The beginning of a statement.  */
> +INSN_NOTE (BEGIN_STMT)
> +
>  /* 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-prop.c b/gcc/ipa-prop.c
> index 51f6221..2d15504 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -4410,7 +4410,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
>             }
>           vargs.quick_push (expr);
>         }
> -      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
> +      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS)
>         {
>           unsigned int ix;
>           tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
> diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
> index e3759d6..d45e951 100644
> --- a/gcc/ipa-split.c
> +++ b/gcc/ipa-split.c
> @@ -1471,7 +1471,7 @@ split_function (basic_block return_bb, struct split_point *split_point,
>      {
>        vec<tree, va_gc> **debug_args = NULL;
>        unsigned i = 0, len = 0;
> -      if (MAY_HAVE_DEBUG_STMTS)
> +      if (MAY_HAVE_DEBUG_BIND_STMTS)
>         {
>           debug_args = decl_debug_args_lookup (node->decl);
>           if (debug_args)
> @@ -1484,11 +1484,12 @@ split_function (basic_block return_bb, struct split_point *split_point,
>             tree ddecl;
>             gimple *def_temp;
>
> -           /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
> -              otherwise if it didn't exist before, we'd end up with
> -              different SSA_NAME_VERSIONs between -g and -g0.  */
> +           /* This needs to be done even without
> +              MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist
> +              before, we'd end up with different SSA_NAME_VERSIONs
> +              between -g and -g0.  */
>             arg = get_or_create_ssa_default_def (cfun, parm);
> -           if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL)
> +           if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL)
>               continue;
>
>             while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
> diff --git a/gcc/ira.c b/gcc/ira.c
> index 046ce3b..17f54a0 100644
> --- a/gcc/ira.c
> +++ b/gcc/ira.c
> @@ -3842,9 +3842,9 @@ combine_and_move_insns (void)
>         }
>
>        /* Last pass - adjust debug insns referencing cleared regs.  */
> -      if (MAY_HAVE_DEBUG_INSNS)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS)
>         for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
> -         if (DEBUG_INSN_P (insn))
> +         if (DEBUG_BIND_INSN_P (insn))
>             {
>               rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
>               INSN_VAR_LOCATION_LOC (insn)
> diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
> index 322f151..923be72 100644
> --- a/gcc/loop-unroll.c
> +++ b/gcc/loop-unroll.c
> @@ -2026,12 +2026,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)
> +             || (DEBUG_BIND_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)
> +                || (DEBUG_BIND_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/reg-stack.c b/gcc/reg-stack.c
> index f238106..e62ccda 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 (DEBUG_BIND_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 (!DEBUG_BIND_INSN_P (insn))
>             continue;
>
>           debug_insns_with_starting_stack--;
> diff --git a/gcc/regcprop.c b/gcc/regcprop.c
> index 73e945d4..0ce64d7 100644
> --- a/gcc/regcprop.c
> +++ b/gcc/regcprop.c
> @@ -757,7 +757,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 (DEBUG_BIND_INSN_P (insn))
>             {
>               rtx loc = INSN_VAR_LOCATION_LOC (insn);
>               if (!VAR_LOC_UNKNOWN_P (loc))
> @@ -1302,7 +1302,7 @@ pass_cprop_hardreg::execute (function *fun)
>        copyprop_hardreg_forward_1 (bb, all_vd + bb->index);
>      }
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        FOR_EACH_BB_FN (bb, fun)
>         if (bitmap_bit_p (visited, bb->index)
> diff --git a/gcc/regrename.c b/gcc/regrename.c
> index 7fbfa31..89380a8 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 (DEBUG_BIND_INSN_P (insn)
>                && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
>         {
>           scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
> diff --git a/gcc/regstat.c b/gcc/regstat.c
> index 3fd26fd..fd3d3a8 100644
> --- a/gcc/regstat.c
> +++ b/gcc/regstat.c
> @@ -54,7 +54,7 @@ regstat_init_n_sets_and_refs (void)
>
>    regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      for (i = 0; i < max_regno; i++)
>        {
>         int use_count;
> diff --git a/gcc/reload1.c b/gcc/reload1.c
> index 5e200b9..cf18b30 100644
> --- a/gcc/reload1.c
> +++ b/gcc/reload1.c
> @@ -1112,7 +1112,7 @@ reload (rtx_insn *first, int global)
>        /* We don't want complex addressing modes in debug insns
>          if simpler ones will do, so delegitimize equivalences
>          in debug insns.  */
> -      if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0)
>         {
>           rtx reg = regno_reg_rtx[i];
>           rtx equiv = 0;
> @@ -1140,7 +1140,7 @@ reload (rtx_insn *first, int global)
>               while (next && DF_REF_INSN (next) == insn)
>                 next = DF_REF_NEXT_REG (next);
>
> -             if (DEBUG_INSN_P (insn))
> +             if (DEBUG_BIND_INSN_P (insn))
>                 {
>                   if (!equiv)
>                     {
> diff --git a/gcc/rtl.h b/gcc/rtl.h
> index 3bda77c..c79a277 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -815,8 +815,13 @@ struct GTY(()) rtvec_def {
>  /* Predicate yielding nonzero iff X is an insn that is not a debug insn.  */
>  #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
>
> +/* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
> +#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
> +/* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
> +#define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
>  /* Nonzero if DEBUG_INSN_P may possibly hold.  */
> -#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
> +#define MAY_HAVE_DEBUG_INSNS                                   \
> +  (MAY_HAVE_DEBUG_MARKER_INSNS || MAY_HAVE_DEBUG_BIND_INSNS)
>
>  /* Predicate yielding nonzero iff X is a real insn.  */
>  #define INSN_P(X) \
> @@ -1604,6 +1609,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)
>
> @@ -1615,6 +1621,12 @@ 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))
> +
>  /* 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))
> @@ -1634,8 +1646,32 @@ 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 DEBUG_BIND_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 DEBUG_MARKER_INSN_P(INSN)              \
> +  (DEBUG_INSN_P (INSN)                         \
> +   && (GET_CODE (PATTERN (INSN))               \
> +       != VAR_LOCATION))
> +/* Evaluate to the marker kind.  */
> +#define INSN_DEBUG_MARKER_KIND(INSN)             \
> +  (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER     \
> +   ? (GET_MODE (PATTERN (INSN)) == VOIDmode      \
> +      ? NOTE_INSN_BEGIN_STMT                     \
> +      : (enum insn_note)-1)                      \
> +   : (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) \
> diff --git a/gcc/sese.c b/gcc/sese.c
> index ad85aa4..a24688f 100644
> --- a/gcc/sese.c
> +++ b/gcc/sese.c
> @@ -164,7 +164,7 @@ sese_build_liveouts (sese_info_p region, bitmap liveouts)
>        sese_build_liveouts_bb (region, liveouts, bb);
>
>    /* FIXME: We could start iterating form the successor of sese.  */
> -  if (MAY_HAVE_DEBUG_STMTS)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
>      FOR_EACH_BB_FN (bb, cfun)
>        if (!bb_in_sese_p (bb, region->region))
>         sese_reset_debug_liveouts_bb (region, liveouts, bb);
> diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
> index 3cad776..85fe81d 100644
> --- a/gcc/shrink-wrap.c
> +++ b/gcc/shrink-wrap.c
> @@ -309,10 +309,10 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
>       move it as far as we can.  */
>    do
>      {
> -      if (MAY_HAVE_DEBUG_INSNS)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS)
>         {
>           FOR_BB_INSNS_REVERSE (bb, dinsn)
> -           if (DEBUG_INSN_P (dinsn))
> +           if (DEBUG_BIND_INSN_P (dinsn))
>               {
>                 df_ref use;
>                 FOR_EACH_INSN_USE (use, dinsn)
> diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h
> index c8aa77b..dca0439 100644
> --- a/gcc/ssa-iterators.h
> +++ b/gcc/ssa-iterators.h
> @@ -447,7 +447,7 @@ num_imm_uses (const_tree var)
>    const ssa_use_operand_t *ptr;
>    unsigned int num = 0;
>
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      {
>        for (ptr = start->next; ptr != start; ptr = ptr->next)
>         if (USE_STMT (ptr))
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index 99d1f1e..dc9ce3c 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -2054,7 +2054,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
>               gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
>             }
>           /* Other user labels keep around in a form of a debug stmt.  */
> -         else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
> +         else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS)
>             {
>               gimple *dbg = gimple_build_debug_bind (label,
>                                                      integer_zero_node,
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index a226096..a142488 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -6032,7 +6032,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
>                                             &vars);
>                 if (init)
>                   init_stmts.safe_push (init);
> -               if (MAY_HAVE_DEBUG_STMTS && args_to_skip)
> +               if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip)
>                   {
>                     if (parm_num == -1)
>                       {
> @@ -6178,7 +6178,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
>         }
>      }
>
> -  if (debug_args_to_skip && MAY_HAVE_DEBUG_STMTS)
> +  if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
>      {
>        tree parm;
>        vec<tree, va_gc> **debug_args = NULL;
> diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
> index 26b8b9a..65ccd71 100644
> --- a/gcc/tree-loop-distribution.c
> +++ b/gcc/tree-loop-distribution.c
> @@ -807,7 +807,7 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
>    /* Remove stmts not in the PARTITION bitmap.  */
>    bbs = get_loop_body_in_dom_order (loop);
>
> -  if (MAY_HAVE_DEBUG_STMTS)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
>      for (i = 0; i < loop->num_nodes; i++)
>        {
>         basic_block bb = bbs[i];
> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
> index f5675ed..e7167e7 100644
> --- a/gcc/tree-sra.c
> +++ b/gcc/tree-sra.c
> @@ -2477,7 +2477,7 @@ analyze_access_subtree (struct access *root, struct access *parent,
>           gcc_checking_assert (!root->grp_scalar_read
>                                && !root->grp_assignment_read);
>           sth_created = true;
> -         if (MAY_HAVE_DEBUG_STMTS)
> +         if (MAY_HAVE_DEBUG_BIND_STMTS)
>             {
>               root->grp_to_be_debug_replaced = 1;
>               root->replacement_decl = create_access_replacement (root);
> diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
> index e62afad..f60670f 100644
> --- a/gcc/tree-ssa-dce.c
> +++ b/gcc/tree-ssa-dce.c
> @@ -1086,7 +1086,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
>
>    /* If this is a store into a variable that is being optimized away,
>       add a debug bind stmt if possible.  */
> -  if (MAY_HAVE_DEBUG_STMTS
> +  if (MAY_HAVE_DEBUG_BIND_STMTS
>        && gimple_assign_single_p (stmt)
>        && is_gimple_val (gimple_assign_rhs1 (stmt)))
>      {
> diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
> index bbea619..f8fe317 100644
> --- a/gcc/tree-ssa-loop-ivopts.c
> +++ b/gcc/tree-ssa-loop-ivopts.c
> @@ -7148,7 +7148,7 @@ remove_unused_ivs (struct ivopts_data *data)
>
>           tree def = info->iv->ssa_name;
>
> -         if (MAY_HAVE_DEBUG_STMTS && SSA_NAME_DEF_STMT (def))
> +         if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def))
>             {
>               imm_use_iterator imm_iter;
>               use_operand_p use_p;
> diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
> index b2d0f57..a671a16 100644
> --- a/gcc/tree-ssa-reassoc.c
> +++ b/gcc/tree-ssa-reassoc.c
> @@ -232,7 +232,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi)
>  {
>    gimple *stmt = gsi_stmt (*gsi);
>
> -  if (!MAY_HAVE_DEBUG_STMTS || gimple_code (stmt) == GIMPLE_PHI)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI)
>      return gsi_remove (gsi, true);
>
>    gimple_stmt_iterator prev = *gsi;
> diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
> index a65ff31..a3d5074 100644
> --- a/gcc/tree-ssa-tail-merge.c
> +++ b/gcc/tree-ssa-tail-merge.c
> @@ -1802,7 +1802,7 @@ tail_merge_optimize (unsigned int todo)
>
>    if (nr_bbs_removed_total > 0)
>      {
> -      if (MAY_HAVE_DEBUG_STMTS)
> +      if (MAY_HAVE_DEBUG_BIND_STMTS)
>         {
>           calculate_dominance_info (CDI_DOMINATORS);
>           update_debug_stmts ();
> diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
> index 536c471..70675e4 100644
> --- a/gcc/tree-ssa-threadedge.c
> +++ b/gcc/tree-ssa-threadedge.c
> @@ -692,7 +692,7 @@ simplify_control_stmt_condition_1 (edge e,
>  void
>  propagate_threaded_block_debug_into (basic_block dest, basic_block src)
>  {
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      return;
>
>    if (!single_pred_p (dest))
> diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
> index 8b6da96..151f544 100644
> --- a/gcc/tree-ssa.c
> +++ b/gcc/tree-ssa.c
> @@ -220,7 +220,7 @@ flush_pending_stmts (edge e)
>  void
>  gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
>  {
> -  if (MAY_HAVE_DEBUG_STMTS)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
>      {
>        tree lhs = gimple_get_lhs (stmt);
>
> @@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
>  tree
>  target_for_debug_bind (tree var)
>  {
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      return NULL_TREE;
>
>    if (TREE_CODE (var) == SSA_NAME)
> @@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
>    int usecount = 0;
>    tree value = NULL;
>
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      return;
>
>    /* If this name has already been registered for replacement, do nothing
> @@ -495,7 +495,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
>    ssa_op_iter op_iter;
>    def_operand_p def_p;
>
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      return;
>
>    stmt = gsi_stmt (*gsi);
> @@ -521,7 +521,7 @@ reset_debug_uses (gimple *stmt)
>    imm_use_iterator imm_iter;
>    gimple *use_stmt;
>
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      return;
>
>    FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
> diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
> index 5c96075..4318adc 100644
> --- a/gcc/tree-ssanames.c
> +++ b/gcc/tree-ssanames.c
> @@ -562,7 +562,7 @@ release_ssa_name_fn (struct function *fn, tree var)
>        int saved_ssa_name_version = SSA_NAME_VERSION (var);
>        use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
>
> -      if (MAY_HAVE_DEBUG_STMTS)
> +      if (MAY_HAVE_DEBUG_BIND_STMTS)
>         insert_debug_temp_for_var_def (NULL, var);
>
>        if (flag_checking)
> diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
> index 5787d53..20d1962 100644
> --- a/gcc/tree-vect-loop-manip.c
> +++ b/gcc/tree-vect-loop-manip.c
> @@ -194,7 +194,7 @@ adjust_debug_stmts_now (adjust_info *ai)
>  static void
>  adjust_vec_debug_stmts (void)
>  {
> -  if (!MAY_HAVE_DEBUG_STMTS)
> +  if (!MAY_HAVE_DEBUG_BIND_STMTS)
>      return;
>
>    gcc_assert (adjust_vec.exists ());
> @@ -216,7 +216,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb)
>  {
>    adjust_info ai;
>
> -  if (MAY_HAVE_DEBUG_STMTS
> +  if (MAY_HAVE_DEBUG_BIND_STMTS
>        && TREE_CODE (from) == SSA_NAME
>        && ! SSA_NAME_IS_DEFAULT_DEF (from)
>        && ! virtual_operand_p (from))
> @@ -244,7 +244,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def)
>
>    SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def);
>
> -  if (MAY_HAVE_DEBUG_STMTS)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
>      adjust_debug_stmts (orig_def, PHI_RESULT (update_phi),
>                         gimple_bb (update_phi));
>  }
> @@ -1685,7 +1685,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
>    create_lcssa_for_virtual_phi (loop);
>    update_ssa (TODO_update_ssa_only_virtuals);
>
> -  if (MAY_HAVE_DEBUG_STMTS)
> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
>      {
>        gcc_assert (!adjust_vec.exists ());
>        adjust_vec.create (32);
> diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
> index bf49e26..07f666e 100644
> --- a/gcc/tree-vect-loop.c
> +++ b/gcc/tree-vect-loop.c
> @@ -7386,7 +7386,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
>           if (!stmt_info)
>             continue;
>
> -         if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
> +         if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
>             vect_loop_kill_debug_uses (loop, phi);
>
>           if (!STMT_VINFO_RELEVANT_P (stmt_info)
> @@ -7449,7 +7449,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
>               continue;
>             }
>
> -         if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
> +         if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
>             vect_loop_kill_debug_uses (loop, stmt);
>
>           if (!STMT_VINFO_RELEVANT_P (stmt_info)
> diff --git a/gcc/tree.h b/gcc/tree.h
> index caa4a69..2e8b3e9 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -1126,8 +1126,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
>  #define VL_EXP_OPERAND_LENGTH(NODE) \
>    ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
>
> +/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold.  */
> +#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
> +/* Nonzero if gimple_debug_bind_p() (and thus
> +   gimple_debug_source_bind_p()) may possibly hold.  */
> +#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
>  /* Nonzero if is_gimple_debug() may possibly hold.  */
> -#define MAY_HAVE_DEBUG_STMTS    (flag_var_tracking_assignments)
> +#define MAY_HAVE_DEBUG_STMTS                                   \
> +  (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS)
>
>  /* In a LOOP_EXPR node.  */
>  #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
> diff --git a/gcc/valtrack.c b/gcc/valtrack.c
> index 38af3f0..8d864c9 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 (DEBUG_BIND_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 51e519a..43fc71a 100644
> --- a/gcc/var-tracking.c
> +++ b/gcc/var-tracking.c
> @@ -1118,7 +1118,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
>        if (tem == NULL_RTX)
>         tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
>      finish_subreg:
> -      if (MAY_HAVE_DEBUG_INSNS
> +      if (MAY_HAVE_DEBUG_BIND_INSNS
>           && GET_CODE (tem) == SUBREG
>           && (GET_CODE (SUBREG_REG (tem)) == PLUS
>               || GET_CODE (SUBREG_REG (tem)) == MINUS
> @@ -1330,7 +1330,7 @@ dv_onepart_p (decl_or_value dv)
>  {
>    tree decl;
>
> -  if (!MAY_HAVE_DEBUG_INSNS)
> +  if (!MAY_HAVE_DEBUG_BIND_INSNS)
>      return NOT_ONEPART;
>
>    if (dv_is_value_p (dv))
> @@ -4854,7 +4854,7 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
>    EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
>      var_regno_delete (set, r);
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        set->traversed_vars = set->vars;
>        shared_hash_htab (set->vars)
> @@ -5528,7 +5528,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
>                   variable names such as VALUEs (never happens) or
>                   DEBUG_EXPRs (only happens in the presence of debug
>                   insns).  */
> -              && (!MAY_HAVE_DEBUG_INSNS
> +              && (!MAY_HAVE_DEBUG_BIND_INSNS
>                    || !rtx_debug_expr_p (XEXP (loc, 0))))
>         return MO_USE;
>        else
> @@ -6693,7 +6693,7 @@ compute_bb_dataflow (basic_block bb)
>    dataflow_set_copy (&old_out, out);
>    dataflow_set_copy (out, in);
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      local_get_addr_cache = new hash_map<rtx, rtx>;
>
>    FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
> @@ -6975,7 +6975,7 @@ compute_bb_dataflow (basic_block bb)
>         }
>      }
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        delete local_get_addr_cache;
>        local_get_addr_cache = NULL;
> @@ -7062,7 +7062,7 @@ vt_find_locations (void)
>               else
>                 oldinsz = oldoutsz = 0;
>
> -             if (MAY_HAVE_DEBUG_INSNS)
> +             if (MAY_HAVE_DEBUG_BIND_INSNS)
>                 {
>                   dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
>                   bool first = true, adjust = false;
> @@ -7123,7 +7123,7 @@ vt_find_locations (void)
>
>               if (htabmax && htabsz > htabmax)
>                 {
> -                 if (MAY_HAVE_DEBUG_INSNS)
> +                 if (MAY_HAVE_DEBUG_BIND_INSNS)
>                     inform (DECL_SOURCE_LOCATION (cfun->decl),
>                             "variable tracking size limit exceeded with "
>                             "-fvar-tracking-assignments, retrying without");
> @@ -7183,7 +7183,7 @@ vt_find_locations (void)
>         }
>      }
>
> -  if (success && MAY_HAVE_DEBUG_INSNS)
> +  if (success && MAY_HAVE_DEBUG_BIND_INSNS)
>      FOR_EACH_BB_FN (bb, cfun)
>        gcc_assert (VTI (bb)->flooded);
>
> @@ -8572,7 +8572,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars)
>    struct expand_loc_callback_data data;
>    rtx result;
>
> -  if (!MAY_HAVE_DEBUG_INSNS)
> +  if (!MAY_HAVE_DEBUG_BIND_INSNS)
>      return loc;
>
>    INIT_ELCD (data, vars);
> @@ -9007,7 +9007,7 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
>    if (!changed_variables->elements ())
>      return;
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      process_changed_values (htab);
>
>    data.insn = insn;
> @@ -9491,10 +9491,8 @@ vt_emit_notes (void)
>       delete_variable_part).  */
>    emit_notes = true;
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> -    {
> -      dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
> -    }
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
> +    dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
>
>    dataflow_set_init (&cur);
>
> @@ -9504,13 +9502,13 @@ vt_emit_notes (void)
>          subsequent basic blocks.  */
>        emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
>
> -      if (MAY_HAVE_DEBUG_INSNS)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS)
>         local_get_addr_cache = new hash_map<rtx, rtx>;
>
>        /* Emit the notes for the changes in the basic block itself.  */
>        emit_notes_in_bb (bb, &cur);
>
> -      if (MAY_HAVE_DEBUG_INSNS)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS)
>         delete local_get_addr_cache;
>        local_get_addr_cache = NULL;
>
> @@ -9526,7 +9524,7 @@ vt_emit_notes (void)
>
>    dataflow_set_destroy (&cur);
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      delete dropped_values;
>    dropped_values = NULL;
>
> @@ -9886,7 +9884,7 @@ vt_init_cfa_base (void)
>        cfa_base_rtx = NULL_RTX;
>        return;
>      }
> -  if (!MAY_HAVE_DEBUG_INSNS)
> +  if (!MAY_HAVE_DEBUG_BIND_INSNS)
>      return;
>
>    /* Tell alias analysis that cfa_base_rtx should share
> @@ -9928,7 +9926,7 @@ vt_initialize (void)
>        VTI (bb)->permp = NULL;
>      }
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
>        scratch_regs = BITMAP_ALLOC (NULL);
> @@ -9941,7 +9939,7 @@ vt_initialize (void)
>        global_get_addr_cache = NULL;
>      }
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        rtx reg, expr;
>        int ofst;
> @@ -10071,7 +10069,7 @@ vt_initialize (void)
>        HOST_WIDE_INT pre, post = 0;
>        basic_block first_bb, last_bb;
>
> -      if (MAY_HAVE_DEBUG_INSNS)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS)
>         {
>           cselib_record_sets_hook = add_with_sets;
>           if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -10122,7 +10120,7 @@ vt_initialize (void)
>
>                   cselib_hook_called = false;
>                   adjust_insn (bb, insn);
> -                 if (MAY_HAVE_DEBUG_INSNS)
> +                 if (MAY_HAVE_DEBUG_BIND_INSNS)
>                     {
>                       if (CALL_P (insn))
>                         prepare_call_arguments (bb, insn);
> @@ -10157,7 +10155,7 @@ vt_initialize (void)
>                       vt_init_cfa_base ();
>                       hard_frame_pointer_adjustment = fp_cfa_offset;
>                       /* Disassociate sp from fp now.  */
> -                     if (MAY_HAVE_DEBUG_INSNS)
> +                     if (MAY_HAVE_DEBUG_BIND_INSNS)
>                         {
>                           cselib_val *v;
>                           cselib_invalidate_rtx (stack_pointer_rtx);
> @@ -10177,7 +10175,7 @@ vt_initialize (void)
>
>        bb = last_bb;
>
> -      if (MAY_HAVE_DEBUG_INSNS)
> +      if (MAY_HAVE_DEBUG_BIND_INSNS)
>         {
>           cselib_preserve_only_values ();
>           cselib_reset_table (cselib_get_next_uid ());
> @@ -10276,7 +10274,7 @@ vt_finalize (void)
>    location_chain_pool.release ();
>    shared_hash_pool.release ();
>
> -  if (MAY_HAVE_DEBUG_INSNS)
> +  if (MAY_HAVE_DEBUG_BIND_INSNS)
>      {
>        if (global_get_addr_cache)
>         delete global_get_addr_cache;
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers
  2017-09-30  9:10               ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-10-09 13:07                 ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2017-10-09 13:07 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> This patch adjusts numerous parts of the compiler that would
> malfunction should they find debug markers at points where they may be
> introduced.  The changes purport to allow the compiler to pass
> bootstrap-debug-lean (-fcompare-debug in stage3) at various
> optimization levels, as well as bootstrap-debug-lib (-fcompare-debug
> for target libraries), even after the compiler is changed so that
> debug markers are introduced in code streams at spots where earlier
> debug stmts, insns and notes wouldn't normally appear.
>
> This patch depends on an earlier SFN boilerplate patch, and on another
> SFN patch that introduces new RTL insn-walking functions.

Ok.

Thanks,
Richard.

> for  gcc/ChangeLog
>
>         * cfgcleanup.c (delete_unreachable_blocks): Use alternate
>         block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
>         * cfgexpand.c (label_rtx_for_bb): Skip debug insns.
>         * cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
>         (rtl_tidy_fallthru_edge): Likewise.
>         (rtl_verify_fallthru): Likewise.
>         (rtl_verify_bb_layout): Likewise.
>         (skip_insns_after_block): Likewise.
>         (duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
>         * dwarf2out.c: Include print-rtl.h.
>         (dwarf2out_next_real_insn): New.
>         (dwarf2out_var_location): Call it.  Disregard begin stmt markers.
>         Dump debug binds in asm comments.
>         * gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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 (gimple_seq_may_fallthru): Take last nondebug stmt.
>         * gimple.h (gimple_seq_last_nondebug_stmt): New.
>         * gimplify.c (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.
>         * 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.
>         * ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
>         * jump.c (clean_barriers): Skip debug insns.
>         * 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.
>         * postreload.c (fixup_debug_insns): Skip nonbind debug insns.
>         * regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
>         * 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
>         * var-tracking.c (get_first_insn): New.
>         (vt_emit_notes): Call it.
>         (vt_initialize): Walk any insns before the first BB.
>         (delete_debug_insns): Likewise.
> ---
>  gcc/cfgbuild.c                   |   1 +
>  gcc/cfgcleanup.c                 |  12 +--
>  gcc/cfgexpand.c                  |  24 +++++-
>  gcc/cfgrtl.c                     |  18 +++--
>  gcc/dwarf2out.c                  |  38 ++++++++-
>  gcc/gimple-iterator.c            |  24 +++++-
>  gcc/gimple-iterator.h            |  46 ++++++-----
>  gcc/gimple-low.c                 |   2 +-
>  gcc/gimple.h                     |  16 ++++
>  gcc/gimplify.c                   |  21 ++---
>  gcc/graphite-isl-ast-to-gimple.c |   7 +-
>  gcc/graphite-scop-detection.c    |   2 +-
>  gcc/haifa-sched.c                |   2 +-
>  gcc/ipa-icf-gimple.c             |   4 +-
>  gcc/jump.c                       |   2 +-
>  gcc/omp-expand.c                 | 161 ++++++++++++++++++++-------------------
>  gcc/omp-low.c                    |   2 +
>  gcc/postreload.c                 |   2 +-
>  gcc/regcprop.c                   |   2 +
>  gcc/tree-cfg.c                   |  52 +++++++++++--
>  gcc/tree-cfgcleanup.c            |  31 +++-----
>  gcc/tree-pretty-print.c          |   5 +-
>  gcc/tree-ssa-dce.c               |   6 +-
>  gcc/tree-ssa-tail-merge.c        |   4 +-
>  gcc/var-tracking.c               |  54 ++++++++++++-
>  25 files changed, 365 insertions(+), 173 deletions(-)
>
> diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
> index 76c21d7..a2e467c 100644
> --- a/gcc/cfgbuild.c
> +++ b/gcc/cfgbuild.c
> @@ -475,6 +475,7 @@ find_bb_boundaries (basic_block bb)
>           if (debug_insn && code != CODE_LABEL && code != BARRIER)
>             prev = PREV_INSN (debug_insn);
>           fallthru = split_block (bb, prev);
> +
>           if (flow_transfer_insn)
>             {
>               BB_END (bb) = flow_transfer_insn;
> diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
> index 365c971..be88fdd 100644
> --- a/gcc/cfgcleanup.c
> +++ b/gcc/cfgcleanup.c
> @@ -3060,13 +3060,13 @@ delete_unreachable_blocks (void)
>
>    find_unreachable_blocks ();
>
> -  /* When we're in GIMPLE mode and there may be debug insns, we should
> -     delete blocks in reverse dominator order, so as to get a chance
> -     to substitute all released DEFs into debug stmts.  If we don't
> -     have dominators information, walking blocks backward gets us a
> -     better chance of retaining most debug information than
> +  /* When we're in GIMPLE mode and there may be debug bind insns, we
> +     should delete blocks in reverse dominator order, so as to get a
> +     chance to substitute all released DEFs into debug bind stmts.  If
> +     we don't have dominators information, walking blocks backward
> +     gets us a better chance of retaining most debug information than
>       otherwise.  */
> -  if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE
> +  if (MAY_HAVE_DEBUG_BIND_INSNS && current_ir_type () == IR_GIMPLE
>        && dom_info_available_p (CDI_DOMINATORS))
>      {
>        for (b = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index cb866aa..5a46b5e 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;
> @@ -5432,7 +5435,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;
> @@ -5473,18 +5476,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)
> @@ -5499,6 +5510,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);
> @@ -5506,7 +5518,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))
>      {
> @@ -5514,6 +5527,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
> diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
> index bce56b4..d43e38c 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.
> @@ -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 (DEBUG_BIND_INSN_P (insn)
> +             && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
>             break;
>           /* FALLTHRU */
>         case INSN:
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index e97ceb6..f4e5947 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"
> @@ -26144,6 +26145,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.  */
> @@ -26192,7 +26209,7 @@ 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;
> @@ -26222,11 +26239,12 @@ 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_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)
>      {
> @@ -26385,6 +26403,22 @@ create_label:
>        newloc->label = last_postcall_label;
>      }
>
> +  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;
>  }
> diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
> index 3b74cc5..fb75f99 100644
> --- a/gcc/gimple-iterator.c
> +++ b/gcc/gimple-iterator.c
> @@ -744,9 +744,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 +780,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..22db61b 100644
> --- a/gcc/gimple-low.c
> +++ b/gcc/gimple-low.c
> @@ -645,7 +645,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.h b/gcc/gimple.h
> index 1783e11..8f289ac 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -4582,6 +4582,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
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index c3fd6ac..e9dffc3 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -1855,7 +1855,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 +1868,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 +1995,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 +2032,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 +2045,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 +2092,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 +2233,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);
> diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
> index 820e14e..3e3d5531 100644
> --- a/gcc/graphite-isl-ast-to-gimple.c
> +++ b/gcc/graphite-isl-ast-to-gimple.c
> @@ -1252,7 +1252,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;
> @@ -1284,7 +1284,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);
>         }
> @@ -1567,7 +1567,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 b374ee1..23da9cc 100644
> --- a/gcc/graphite-scop-detection.c
> +++ b/gcc/graphite-scop-detection.c
> @@ -262,7 +262,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))
>         && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
>        return false;
>
> diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
> index 34cc46b..e99aa69 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/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
> index b40dd865..be8c709 100644
> --- a/gcc/ipa-icf-gimple.c
> +++ b/gcc/ipa-icf-gimple.c
> @@ -640,8 +640,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/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/omp-expand.c b/gcc/omp-expand.c
> index 4bdcf19..fe25b83 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);
>
> @@ -4795,7 +4795,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.  */
> @@ -4921,7 +4921,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)
> @@ -5022,10 +5022,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 ();
> @@ -5099,7 +5099,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)
> @@ -5178,7 +5178,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);
> @@ -5215,7 +5215,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 ();
> @@ -5398,7 +5398,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);
>
> @@ -5525,7 +5525,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);
> @@ -5649,7 +5649,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);
>
> @@ -5738,7 +5738,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));
>
> @@ -5965,7 +5965,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)
> @@ -5973,7 +5973,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)
>               {
> @@ -5998,7 +5998,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);
> @@ -6022,7 +6022,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)
>      {
> @@ -6064,7 +6064,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);
> @@ -6073,7 +6073,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);
>
> @@ -6099,7 +6099,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);
> @@ -6112,7 +6112,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)))
> @@ -6140,12 +6140,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));
> @@ -6168,7 +6168,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
> @@ -6180,7 +6180,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;
> @@ -6201,7 +6201,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);
> @@ -6231,7 +6231,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);
>
> @@ -6257,14 +6257,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);
> @@ -6309,7 +6309,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))
> @@ -6356,10 +6356,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));
> @@ -6423,7 +6430,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.
> @@ -6446,10 +6453,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);
>
> @@ -6502,7 +6509,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
> @@ -6582,7 +6589,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)
> @@ -6685,7 +6692,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);
> @@ -6696,7 +6703,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)),
> @@ -7195,7 +7202,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));
> @@ -7207,7 +7214,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);
> @@ -7389,7 +7396,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));
>         }
> @@ -7424,11 +7431,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);
>      }
> @@ -7572,7 +7579,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);
> @@ -7653,17 +7660,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)
> @@ -7807,11 +7814,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);
> @@ -7995,7 +8002,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 8ed8f7c..8852798 100644
> --- a/gcc/omp-low.c
> +++ b/gcc/omp-low.c
> @@ -7023,6 +7023,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/postreload.c b/gcc/postreload.c
> index 000ed34..8e4a8190 100644
> --- a/gcc/postreload.c
> +++ b/gcc/postreload.c
> @@ -836,7 +836,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to)
>      {
>        rtx t;
>
> -      if (!DEBUG_INSN_P (insn))
> +      if (!DEBUG_BIND_INSN_P (insn))
>         continue;
>
>        t = INSN_VAR_LOCATION_LOC (insn);
> diff --git a/gcc/regcprop.c b/gcc/regcprop.c
> index 0ce64d7..ee9b119 100644
> --- a/gcc/regcprop.c
> +++ b/gcc/regcprop.c
> @@ -433,6 +433,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) (...))
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index dc9ce3c..1796850 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.  */
> @@ -5444,6 +5475,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);
> @@ -5513,7 +5548,7 @@ gimple_verify_flow_info (void)
>             }
>         }
>
> -      gsi = gsi_last_bb (bb);
> +      gsi = gsi_last_nondebug_bb (bb);
>        if (gsi_end_p (gsi))
>         continue;
>
> @@ -5768,8 +5803,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;
> @@ -5780,6 +5817,7 @@ gimple_block_label (basic_block bb)
>             gsi_move_before (&i, &s);
>           return label;
>         }
> +      first = false;
>      }
>
>    label = create_artificial_label (UNKNOWN_LOCATION);
> @@ -5855,7 +5893,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 a7053d7..3c4d573 100644
> --- a/gcc/tree-cfgcleanup.c
> +++ b/gcc/tree-cfgcleanup.c
> @@ -555,13 +555,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);
> @@ -570,20 +570,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.  */
> @@ -1285,7 +1271,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-pretty-print.c b/gcc/tree-pretty-print.c
> index 14c7caa..1fe3e63 100644
> --- a/gcc/tree-pretty-print.c
> +++ b/gcc/tree-pretty-print.c
> @@ -3386,7 +3386,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 f60670f..28cf643 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-tail-merge.c b/gcc/tree-ssa-tail-merge.c
> index a3d5074..01b8821 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/var-tracking.c b/gcc/var-tracking.c
> index 43fc71a..974b4ea 100644
> --- a/gcc/var-tracking.c
> +++ b/gcc/var-tracking.c
> @@ -9472,6 +9472,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
> @@ -9500,7 +9518,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_BIND_INSNS)
>         local_get_addr_cache = new hash_map<rtx, rtx>;
> @@ -10096,11 +10115,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 (DEBUG_BIND_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);
> @@ -10168,6 +10210,7 @@ vt_initialize (void)
>                             }
>                         }
>                     }
> +                 BLOCK_FOR_INSN (insn) = save_bb;
>                 }
>             }
>           gcc_assert (offset == VTI (bb)->out.stack_adjust);
> @@ -10208,7 +10251,10 @@ 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))
>           {
>             tree decl = INSN_VAR_LOCATION_DECL (insn);
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-09-30  9:09               ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
@ 2017-10-09 13:11                 ` Richard Biener
  2017-10-13  7:25                   ` Alexandre Oliva
  2017-10-24 18:11                 ` Jason Merrill
  1 sibling, 1 reply; 156+ messages in thread
From: Richard Biener @ 2017-10-09 13:11 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> This patch completes the infrastructure for the introduction of
> statement frontiers in C-family languages.
>
> It brings in all the code remaining code needed to introduce and
> transform begin stmt trees, gimple stmts, insns and notes, and
> ultimately use them to generate the is_stmt column in DWARF2+ line
> number tables/programs, however none of it is activated: the option
> that would do so will be introduced in a subsequent patch.
>
> This patch depends on an earlier patch with not-quite-boilerplate
> changes towards SFN.

The middle-end changes are ok.   The C FE change looks reasonable,
I'd appreciate a 2nd look at the C++ FE changes by a maintainer.

Thanks,
Richard.

> for  gcc/c-family/ChangeLog
>
>         * c-semantics.c (pop_stmt_list): Move begin stmt marker into
>         subsequent statement list.
>
> for  gcc/c/ChangeLog
>
>         * c-objc-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
>         * c-parser.c (add_debug_begin_stmt): New.
>         (c_parser_declaration_or_fndef): Call it.
>         (c_parser_compound_statement_nostart): Likewise.
>         (c_parser_statement_after_labels): Likewise.
>         * c-typeck (c_finish_stmt_expr): Skip begin stmts markers.
>
> for  gcc/cp/ChangeLog
>
>         * constexpr.c (build_data_member_initialization): Skip begin stmt
>         markers.
>         (check_constexpr_ctor_body_1): Likewise.
>         (build_constexpr_constructor_member_initializers): Likewise.
>         (constexpr_fn_retval): Likewise.
>         (cxx_eval_statement_list): Likewise.
>         (potential_constant_expression_1): Likewise.
>         * cp-array-notation.c (stmt_location): New.
>         (cp_expand_cond_array_notations): Use it.
>         * cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
>         * parser.c (add_debug_begin_stmt): New.
>         (cp_parser_statement): Call it.
>         * pt.c (tsubst_copy): Handle begin stmt markers.
>
> for  gcc/ChangeLog
>
>         * cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
>         markers.  Integrate source bind into debug stmt expand loop.
>         (pass_expand::execute): Check debug marker limit.  Avoid deep
>         TER and expand debug locations for debug bind insns only.
>         * cse.c (insn_live_p): Keep nonbind markers and debug bindings
>         followed by them.
>         * df-scan.c (df_insn_delete): Accept out-of-block debug insn.
>         * final.c (reemit_insn_block_notes): Take current block from
>         nonbind markers.  Declare note where it's first set.
>         (final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
>         begin stmt markers if enabled.
>         (notice_source_line): Handle nonbind markers.  Fail if their
>         location is unknown or that of builtins.
>         (rest_of_handle_final): Convert begin stmt markers to notes if
>         var-tracking didn't run.
>         (rest_of_clean_state): Skip begin stmt markers.
>         * gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
>         markers.
>         * function.c (allocate_struct_function): Set begin_stmt_markers.
>         * function.h (struct function): Add debug_marker_count counter
>         and debug_nonbind_markers flag.
>         * gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
>         * gimple-low.c (lower_function_body): Adjust
>         debug_nonbind_markers.
>         (lower_stmt): Drop or skip gimple debug stmts.
>         (lower_try_catch): Skip debug stmts.
>         * gimple.c (gimple_build_debug_begin_stmt): New.
>         (gimple_copy): Increment debug_marker_count if copying one.
>         * gimple.h (gimple_build_debug_begin_stmt): Declare.
>         * gimplify.c (rexpr_location): New.
>         (rexpr_has_location): New.
>         (warn_switch_unreachable_r): Handle gimple debug stmts.
>         (shortcut_cond_r): Call expr_location.
>         (find_goto): New.
>         (find_goto_label): New.
>         (shortcut_cond_expr): Call expr_has_location, expr_location, and
>         find_goto_label.
>         (gimplify_cond_expr): Call find_goto_label, expr_has_location, and
>         expr_location.
>         (gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
>         * langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
>         (LANG_HOOKS_INITIALIZER): ... this.
>         * langhooks.h (struct lang_hooks): Add emits_begin_stmt.
>         * lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
>         debug insns.
>         (update_ebb_live_info): Skip debug insn markers.
>         * lra.c (debug_insn_static_data): Rename to...
>         (debug_bind_static_data): ... this.
>         (debug_marker_static_data): New.
>         (lra_set_insn_recog_data): Select one of the above depending
>         on debug insn kind.
>         (lra_update_isn_regno_info): Don't assume debug insns have
>         freqs.
>         (push_insns): Skip debug insns.
>         * lto-streamer-in.c (input_function): Drop debug stmts
>         depending on active options.  Adjust debug_nonbind_markers.
>         * params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
>         * print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
>         begin stmt marker notes.
>         (print_insn): Likewise.
>         * recog.c (extract_insn): Recognize rtl for debug markers.
>         * rtl.def (DEBUG_MARKER): New.
>         * tree-inline.c: Include params.h.
>         (remap_gimple_stmt): Handle nonbind markers.
>         (maybe_move_debug_stmts_to_successors): Likewise.
>         (copy_debug_stmt): Likewise.
>         * tree-iterator.c (append_to_statement_list_1): Append begin stmt
>         markers regardless of no side effects.
>         (tsi_link_before): Don't update container's side effects when adding
>         a begin stmt marker.
>         (tsi_link_after): Likewise.
>         (expr_first): Skip begin stmt markers.
>         (expr_last): Likewise.
>         * tree-pretty-print (dump_generic_node): Handle begin stmt markers.
>         * tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
>         Disregard nonbind markers.
>         * tree.c (make_node_stat): Don't set side effects for begin stmt
>         markers.
>         (build1_stat): Likewise.
>         * tree.def (DEBUG_BEGIN_STMT): New.
>         * tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
>         * var-tracking.c (delete_debug_insns): Renamed to...
>         (delete_vta_debug_insns): ... this.
>         (reemit_marker_as_note): New.
>         (vt_initialize): Reemit markers.
>         (delete_vta_debug_insns): Likewise.
>         (vt_debug_insns_local): Reemit or delete markers.
>         (variable_tracking_main_1): Likewise.
>         * doc/generic.texi (DEBUG_BEGIN_STMT): Document.
>         * doc/gimple.texi (gimple_debug_begin_stmt_p): New.
>         (gimple_debug_nonbind_marker_p): New.
>         (gimple_build_debug_bind): Adjust.
>         (gimple_build_debug_begin_stmt): New.
>         * doc/invoke.texi (max-debug-marker-count): New param.
>         * doc/rtl.texi (debug_implicit_ptr, entry_value): New.
>         (debug_parameter_ref, debug_marker): New.
>         (NOTE_INSN_BEGIN_STMT): New.
>         (DEBUG_INSN): Describe begin stmt markers.
> ---
>  gcc/c-family/c-semantics.c |  21 ++++++
>  gcc/c/c-objc-common.h      |   2 +
>  gcc/c/c-parser.c           |  20 ++++++
>  gcc/c/c-typeck.c           |   8 ++-
>  gcc/cfgexpand.c            | 113 +++++++++++++++++---------------
>  gcc/cp/constexpr.c         |  11 ++++
>  gcc/cp/cp-array-notation.c |  37 +++++++++--
>  gcc/cp/cp-objcp-common.h   |   2 +
>  gcc/cp/parser.c            |  14 ++++
>  gcc/cp/pt.c                |   6 ++
>  gcc/cse.c                  |   7 ++
>  gcc/df-scan.c              |   2 +-
>  gcc/doc/generic.texi       |   5 ++
>  gcc/doc/gimple.texi        |  24 ++++++-
>  gcc/doc/invoke.texi        |   7 ++
>  gcc/doc/rtl.texi           |  53 ++++++++++++---
>  gcc/final.c                |  89 +++++++++++++++++++------
>  gcc/function.c             |   6 ++
>  gcc/function.h             |  10 +++
>  gcc/gimple-iterator.c      |   4 ++
>  gcc/gimple-low.c           |  29 +++++++++
>  gcc/gimple-pretty-print.c  |   7 ++
>  gcc/gimple.c               |  24 +++++++
>  gcc/gimple.h               |   1 +
>  gcc/gimplify.c             | 158 +++++++++++++++++++++++++++++++++++----------
>  gcc/langhooks-def.h        |   2 +
>  gcc/langhooks.h            |   3 +
>  gcc/lra-constraints.c      |  10 ++-
>  gcc/lra.c                  |  36 +++++++++--
>  gcc/lto-streamer-in.c      |  12 +++-
>  gcc/params.def             |   9 +++
>  gcc/print-rtl.c            |  24 +++++++
>  gcc/recog.c                |   1 +
>  gcc/rtl.def                |   3 +
>  gcc/tree-inline.c          |  31 ++++++++-
>  gcc/tree-iterator.c        |  48 +++++++++++---
>  gcc/tree-pretty-print.c    |   4 ++
>  gcc/tree-ssa-threadedge.c  |  25 ++++---
>  gcc/tree.c                 |   8 ++-
>  gcc/tree.def               |   3 +
>  gcc/tree.h                 |   2 +-
>  gcc/var-tracking.c         |  70 +++++++++++++++++---
>  42 files changed, 793 insertions(+), 158 deletions(-)
>
> diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
> index 3ceb714..cd872d8 100644
> --- a/gcc/c-family/c-semantics.c
> +++ b/gcc/c-family/c-semantics.c
> @@ -76,6 +76,27 @@ pop_stmt_list (tree t)
>           free_stmt_list (t);
>           t = u;
>         }
> +      /* If the statement list contained a debug begin stmt and a
> +        statement list, move the debug begin stmt into the statement
> +        list and return it.  */
> +      else if (!tsi_end_p (i)
> +              && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +       {
> +         u = tsi_stmt (i);
> +         tsi_next (&i);
> +         if (tsi_one_before_end_p (i)
> +             && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST)
> +           {
> +             tree l = tsi_stmt (i);
> +             tsi_prev (&i);
> +             tsi_delink (&i);
> +             tsi_delink (&i);
> +             i = tsi_start (l);
> +             free_stmt_list (t);
> +             t = l;
> +             tsi_link_before (&i, u, TSI_SAME_STMT);
> +           }
> +       }
>      }
>
>    return t;
> diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
> index bee06e9..27ceabc 100644
> --- a/gcc/c/c-objc-common.h
> +++ b/gcc/c/c-objc-common.h
> @@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
>  #define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
>  #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
>  #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope
> +#undef LANG_HOOKS_EMITS_BEGIN_STMT
> +#define LANG_HOOKS_EMITS_BEGIN_STMT true
>
>  /* Attribute hooks.  */
>  #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index a36397b..aa70c91 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -1640,6 +1640,19 @@ c_parser_external_declaration (c_parser *parser)
>  static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
>  static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
>
> +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
> +
> +static void
> +add_debug_begin_stmt (location_t loc)
> +{
> +  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
> +    return;
> +
> +  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
> +  SET_EXPR_LOCATION (stmt, loc);
> +  add_stmt (stmt);
> +}
> +
>  /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
>     6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
>     is accepted; otherwise (old-style parameter declarations) only other
> @@ -1740,6 +1753,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>    bool diagnosed_no_specs = false;
>    location_t here = c_parser_peek_token (parser)->location;
>
> +  add_debug_begin_stmt (c_parser_peek_token (parser)->location);
> +
>    if (static_assert_ok
>        && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
>      {
> @@ -4949,6 +4964,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
>    location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
>    if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
>      {
> +      add_debug_begin_stmt (c_parser_peek_token (parser)->location);
>        c_parser_consume_token (parser);
>        return;
>      }
> @@ -5403,6 +5419,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
>    parser->in_if_block = false;
>    if (if_p != NULL)
>      *if_p = false;
> +
> +  if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
> +    add_debug_begin_stmt (loc);
> +
>    switch (c_parser_peek_token (parser)->type)
>      {
>      case CPP_OPEN_BRACE:
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index 73e7460..33bd4b8 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -10740,6 +10740,10 @@ c_finish_stmt_expr (location_t loc, tree body)
>         }
>        else
>         i = tsi_last (last);
> +      if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +       do
> +         tsi_prev (&i);
> +       while (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT);
>        last_p = tsi_stmt_ptr (i);
>        last = *last_p;
>      }
> @@ -10759,7 +10763,9 @@ c_finish_stmt_expr (location_t loc, tree body)
>
>    /* In the case that the BIND_EXPR is not necessary, return the
>       expression out from inside it.  */
> -  if (last == BIND_EXPR_BODY (body)
> +  if ((last == BIND_EXPR_BODY (body)
> +       /* Skip nested debug stmts.  */
> +       || last == expr_first (BIND_EXPR_BODY (body)))
>        && BIND_EXPR_VARS (body) == NULL)
>      {
>        /* Even if this looks constant, do not allow it in a constant
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index 5a46b5e..c854ffd 100644
> --- a/gcc/cfgexpand.c
> +++ b/gcc/cfgexpand.c
> @@ -5635,39 +5635,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>           if (new_bb)
>             return new_bb;
>         }
> -      else if (gimple_debug_bind_p (stmt))
> +      else if (is_gimple_debug (stmt))
>         {
>           location_t sloc = curr_insn_location ();
>           gimple_stmt_iterator nsi = gsi;
>
>           for (;;)
>             {
> -             tree var = gimple_debug_bind_get_var (stmt);
> -             tree value;
> -             rtx val;
> +             tree var;
> +             tree value = NULL_TREE;
> +             rtx val = NULL_RTX;
>               machine_mode mode;
>
> -             if (TREE_CODE (var) != DEBUG_EXPR_DECL
> -                 && TREE_CODE (var) != LABEL_DECL
> -                 && !target_for_debug_bind (var))
> -               goto delink_debug_stmt;
> +             if (!gimple_debug_nonbind_marker_p (stmt))
> +               {
> +                 if (gimple_debug_bind_p (stmt))
> +                   {
> +                     var = gimple_debug_bind_get_var (stmt);
>
> -             if (gimple_debug_bind_has_value_p (stmt))
> -               value = gimple_debug_bind_get_value (stmt);
> -             else
> -               value = NULL_TREE;
> +                     if (TREE_CODE (var) != DEBUG_EXPR_DECL
> +                         && TREE_CODE (var) != LABEL_DECL
> +                         && !target_for_debug_bind (var))
> +                       goto delink_debug_stmt;
>
> -             last = get_last_insn ();
> +                     if (DECL_P (var))
> +                       mode = DECL_MODE (var);
> +                     else
> +                       mode = TYPE_MODE (TREE_TYPE (var));
>
> -             set_curr_insn_location (gimple_location (stmt));
> +                     if (gimple_debug_bind_has_value_p (stmt))
> +                       value = gimple_debug_bind_get_value (stmt);
> +
> +                     val = gen_rtx_VAR_LOCATION
> +                       (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
> +                   }
> +                 else if (gimple_debug_source_bind_p (stmt))
> +                   {
> +                     var = gimple_debug_source_bind_get_var (stmt);
> +
> +                     value = gimple_debug_source_bind_get_value (stmt);
> +
> +                     mode = DECL_MODE (var);
>
> -             if (DECL_P (var))
> -               mode = DECL_MODE (var);
> +                     val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
> +                                                 VAR_INIT_STATUS_UNINITIALIZED);
> +                   }
> +                 else
> +                   gcc_unreachable ();
> +               }
> +             /* If this function was first compiled with markers
> +                enabled, but they're now disable (e.g. LTO), drop
> +                them on the floor.  */
> +             else if (gimple_debug_nonbind_marker_p (stmt)
> +                      && !MAY_HAVE_DEBUG_MARKER_INSNS)
> +               goto delink_debug_stmt;
> +             else if (gimple_debug_begin_stmt_p (stmt))
> +               val = gen_rtx_DEBUG_MARKER (VOIDmode);
>               else
> -               mode = TYPE_MODE (TREE_TYPE (var));
> +               gcc_unreachable ();
>
> -             val = gen_rtx_VAR_LOCATION
> -               (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
> +             last = get_last_insn ();
> +
> +             set_curr_insn_location (gimple_location (stmt));
>
>               emit_debug_insn (val);
>
> @@ -5675,9 +5704,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>                 {
>                   /* We can't dump the insn with a TREE where an RTX
>                      is expected.  */
> -                 PAT_VAR_LOCATION_LOC (val) = const0_rtx;
> +                 if (GET_CODE (val) == VAR_LOCATION)
> +                   {
> +                     gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);
> +                     PAT_VAR_LOCATION_LOC (val) = const0_rtx;
> +                   }
>                   maybe_dump_rtl_for_gimple_stmt (stmt, last);
> -                 PAT_VAR_LOCATION_LOC (val) = (rtx)value;
> +                 if (GET_CODE (val) == VAR_LOCATION)
> +                   PAT_VAR_LOCATION_LOC (val) = (rtx)value;
>                 }
>
>             delink_debug_stmt:
> @@ -5693,42 +5727,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>               if (gsi_end_p (nsi))
>                 break;
>               stmt = gsi_stmt (nsi);
> -             if (!gimple_debug_bind_p (stmt))
> +             if (!is_gimple_debug (stmt))
>                 break;
>             }
>
>           set_curr_insn_location (sloc);
>         }
> -      else if (gimple_debug_source_bind_p (stmt))
> -       {
> -         location_t sloc = curr_insn_location ();
> -         tree var = gimple_debug_source_bind_get_var (stmt);
> -         tree value = gimple_debug_source_bind_get_value (stmt);
> -         rtx val;
> -         machine_mode mode;
> -
> -         last = get_last_insn ();
> -
> -         set_curr_insn_location (gimple_location (stmt));
> -
> -         mode = DECL_MODE (var);
> -
> -         val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
> -                                     VAR_INIT_STATUS_UNINITIALIZED);
> -
> -         emit_debug_insn (val);
> -
> -         if (dump_file && (dump_flags & TDF_DETAILS))
> -           {
> -             /* We can't dump the insn with a TREE where an RTX
> -                is expected.  */
> -             PAT_VAR_LOCATION_LOC (val) = const0_rtx;
> -             maybe_dump_rtl_for_gimple_stmt (stmt, last);
> -             PAT_VAR_LOCATION_LOC (val) = (rtx)value;
> -           }
> -
> -         set_curr_insn_location (sloc);
> -       }
>        else
>         {
>           gcall *call_stmt = dyn_cast <gcall *> (stmt);
> @@ -6367,6 +6371,11 @@ pass_expand::execute (function *fun)
>    FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
>      e->flags &= ~EDGE_EXECUTABLE;
>
> +  /* If the function has too many markers, drop them while expanding.  */
> +  if (cfun->debug_marker_count
> +      >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
> +    cfun->debug_nonbind_markers = false;
> +
>    lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
>    FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
>                   next_bb)
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index a89ee49..f9209ac 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
>        tree_stmt_iterator i;
>        for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>         {
> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +           /* ??? Can we retain this information somehow?  */
> +           continue;
>           if (! build_data_member_initialization (tsi_stmt (i), vec))
>             return false;
>         }
> @@ -448,6 +451,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
>
>      case USING_STMT:
>      case STATIC_ASSERT:
> +    case DEBUG_BEGIN_STMT:
>        return true;
>
>      default:
> @@ -586,6 +590,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
>        tree_stmt_iterator i;
>        for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
>         {
> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +           /* ??? Can we retain this information somehow?  */
> +           continue;
>           ok = build_data_member_initialization (tsi_stmt (i), &vec);
>           if (!ok)
>             break;
> @@ -673,6 +680,7 @@ constexpr_fn_retval (tree body)
>        return constexpr_fn_retval (BIND_EXPR_BODY (body));
>
>      case USING_STMT:
> +    case DEBUG_BEGIN_STMT:
>        return NULL_TREE;
>
>      default:
> @@ -3783,6 +3791,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
>    for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>      {
>        tree stmt = tsi_stmt (i);
> +      if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
> +       continue;
>        r = cxx_eval_constant_expression (ctx, stmt, false,
>                                         non_constant_p, overflow_p,
>                                         jump_target);
> @@ -5119,6 +5129,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
>      case CONTINUE_STMT:
>      case REQUIRES_EXPR:
>      case STATIC_ASSERT:
> +    case DEBUG_BEGIN_STMT:
>        return true;
>
>      case PARM_DECL:
> diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
> index 31be7d6..17f0b35c 100644
> --- a/gcc/cp/cp-array-notation.c
> +++ b/gcc/cp/cp-array-notation.c
> @@ -780,6 +780,31 @@ error:
>    return error_mark_node;
>  }
>
> +/* Return a location associated with stmt.  If it is an expresion,
> +   that's the expression's location.  If it is a STATEMENT_LIST,
> +   instead of no location, use expr_first to skip any debug stmts and
> +   take the location of the first nondebug stmt found.  */
> +
> +static location_t
> +stmt_location (tree stmt)
> +{
> +  location_t loc = UNKNOWN_LOCATION;
> +
> +  if (!stmt)
> +    return loc;
> +
> +  loc = EXPR_LOCATION (stmt);
> +
> +  if (loc != UNKNOWN_LOCATION || TREE_CODE (stmt) != STATEMENT_LIST)
> +    return loc;
> +
> +  stmt = expr_first (stmt);
> +  if (stmt)
> +    loc = EXPR_LOCATION (stmt);
> +
> +  return loc;
> +}
> +
>  /* Helper function for expand_conditonal_array_notations.  Encloses the
>     conditional statement passed in ORIG_STMT with a loop around it and
>     replaces the condition in STMT with a ARRAY_REF tree-node to the array.
> @@ -835,10 +860,12 @@ cp_expand_cond_array_notations (tree orig_stmt)
>        tree cond = IF_COND (orig_stmt);
>        if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
>           || (yes_expr
> -             && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
> +             && !find_rank (stmt_location (yes_expr),
> +                            yes_expr, yes_expr, true,
>                              &yes_rank))
>           || (no_expr
> -             && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
> +             && !find_rank (stmt_location (no_expr),
> +                            no_expr, no_expr, true,
>                              &no_rank)))
>         return error_mark_node;
>
> @@ -847,13 +874,15 @@ cp_expand_cond_array_notations (tree orig_stmt)
>         return orig_stmt;
>        else if (cond_rank != yes_rank && yes_rank != 0)
>         {
> -         error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
> +         error_at (stmt_location (yes_expr),
> +                   "rank mismatch with controlling"
>                     " expression of parent if-statement");
>           return error_mark_node;
>         }
>        else if (cond_rank != no_rank && no_rank != 0)
>         {
> -         error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
> +         error_at (stmt_location (no_expr),
> +                   "rank mismatch with controlling "
>                     "expression of parent if-statement");
>           return error_mark_node;
>         }
> diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
> index 3e4cc9c5..c1c82b6 100644
> --- a/gcc/cp/cp-objcp-common.h
> +++ b/gcc/cp/cp-objcp-common.h
> @@ -105,6 +105,8 @@ extern void cp_register_dumps (gcc::dump_manager *);
>  #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
>  #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
>  #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
> +#undef LANG_HOOKS_EMITS_BEGIN_STMT
> +#define LANG_HOOKS_EMITS_BEGIN_STMT true
>
>  /* Attribute hooks.  */
>  #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 6e817cb..1b31182 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -10661,6 +10661,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
>
>  /* Statements [gram.stmt.stmt]  */
>
> +/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
> +
> +static void
> +add_debug_begin_stmt (location_t loc)
> +{
> +  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
> +    return;
> +
> +  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
> +  SET_EXPR_LOCATION (stmt, loc);
> +  add_stmt (stmt);
> +}
> +
>  /* Parse a statement.
>
>     statement:
> @@ -10736,6 +10749,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
>    token = cp_lexer_peek_token (parser->lexer);
>    /* Remember the location of the first token in the statement.  */
>    statement_location = token->location;
> +  add_debug_begin_stmt (statement_location);
>    /* If this is a keyword, then that will often determine what kind of
>       statement we have.  */
>    if (token->type == CPP_KEYWORD)
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index c29c779..4714b53 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -15289,6 +15289,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>      case PREDICT_EXPR:
>        return t;
>
> +    case DEBUG_BEGIN_STMT:
> +      /* ??? There's no point in copying it for now, but maybe some
> +        day it will contain more information, such as a pointer back
> +        to the containing function, inlined copy or so.  */
> +      return t;
> +
>      default:
>        /* We shouldn't get here, but keep going if !flag_checking.  */
>        if (flag_checking)
> diff --git a/gcc/cse.c b/gcc/cse.c
> index d1577a6..bb9b317 100644
> --- a/gcc/cse.c
> +++ b/gcc/cse.c
> @@ -6967,11 +6967,18 @@ insn_live_p (rtx_insn *insn, int *counts)
>      {
>        rtx_insn *next;
>
> +      if (DEBUG_MARKER_INSN_P (insn))
> +       return true;
> +
>        for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
>         if (NOTE_P (next))
>           continue;
>         else if (!DEBUG_INSN_P (next))
>           return true;
> +       /* If we find an inspection point, such as a debug begin stmt,
> +          we want to keep the earlier debug insn.  */
> +       else if (DEBUG_MARKER_INSN_P (next))
> +         return true;
>         else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
>           return false;
>
> diff --git a/gcc/df-scan.c b/gcc/df-scan.c
> index 8ab3d71..429dab8 100644
> --- a/gcc/df-scan.c
> +++ b/gcc/df-scan.c
> @@ -945,7 +945,7 @@ df_insn_delete (rtx_insn *insn)
>       In any case, we expect BB to be non-NULL at least up to register
>       allocation, so disallow a non-NULL BB up to there.  Not perfect
>       but better than nothing...  */
> -  gcc_checking_assert (bb != NULL || reload_completed);
> +  gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed);
>
>    df_grow_bb_info (df_scan);
>    df_grow_reg_info ();
> diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
> index a51cfd6e..a13bce9 100644
> --- a/gcc/doc/generic.texi
> +++ b/gcc/doc/generic.texi
> @@ -1930,6 +1930,11 @@ case 2 ... 5:
>  The first value will be @code{CASE_LOW}, while the second will be
>  @code{CASE_HIGH}.
>
> +@item DEBUG_BEGIN_STMT
> +
> +Marks the beginning of a source statement, for purposes of debug
> +information generation.
> +
>  @end table
>
>
> diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
> index 635abd39..6c9c4789 100644
> --- a/gcc/doc/gimple.texi
> +++ b/gcc/doc/gimple.texi
> @@ -831,6 +831,16 @@ expression to a variable.
>  Return true if g is any of the OpenMP codes.
>  @end deftypefn
>
> +@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
> +Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
> +a source statement.
> +@end deftypefn
> +
> +@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
> +Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
> +without any variable binding.
> +@end deftypefn
> +
>  @node Manipulating GIMPLE statements
>  @section Manipulating GIMPLE statements
>  @cindex Manipulating GIMPLE statements
> @@ -1528,10 +1538,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
>  @subsection @code{GIMPLE_DEBUG}
>  @cindex @code{GIMPLE_DEBUG}
>  @cindex @code{GIMPLE_DEBUG_BIND}
> +@cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
>
>  @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
>  tree value, gimple stmt)
> -Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of
> +Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND}
>  @code{subcode}.  The effect of this statement is to tell debug
>  information generation machinery that the value of user variable
>  @code{var} is given by @code{value} at that point, and to remain with
> @@ -1602,6 +1613,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
>  and @code{FALSE} if it unbinds the variable.
>  @end deftypefn
>
> +@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
> +Build a @code{GIMPLE_DEBUG} statement with
> +@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}.  The effect of this
> +statement is to tell debug information generation machinery that the
> +user statement at the given @code{location} and @code{block} starts at
> +the point at which the statement is inserted.  The intent is that side
> +effects (e.g. variable bindings) of all prior user statements are
> +observable, and that none of the side effects of subsequent user
> +statements are.
> +@end deftypefn
> +
>  @node @code{GIMPLE_EH_FILTER}
>  @subsection @code{GIMPLE_EH_FILTER}
>  @cindex @code{GIMPLE_EH_FILTER}
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index f862b7f..108d730 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -10480,6 +10480,13 @@ debug information may end up not being used; setting this higher may
>  enable the compiler to find more complex debug expressions, but compile
>  time and memory use may grow.  The default is 12.
>
> +@item max-debug-marker-count
> +Sets a threshold on the number of debug markers (e.g. begin stmt
> +markers) to avoid complexity explosion at inlining or expanding to RTL.
> +If a function has more such gimple stmts than the set limit, such stmts
> +will be dropped from the inlined copy of a function, and from its RTL
> +expansion.  The default is 100000.
> +
>  @item min-nondebug-insn-uid
>  Use uids starting at this parameter for nondebug insns.  The range below
>  the parameter is reserved exclusively for debug insns created by
> diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
> index 3b2b247..888ab02 100644
> --- a/gcc/doc/rtl.texi
> +++ b/gcc/doc/rtl.texi
> @@ -3413,6 +3413,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},
>  that points back to it, within value expressions in
>  @code{VAR_LOCATION} nodes.
>
> +@findex debug_implicit_ptr
> +@item (debug_implicit_ptr:@var{mode} @var{decl})
> +Stands for the location of a @var{decl} that is no longer addressable.
> +
> +@findex entry_value
> +@item (entry_value:@var{mode} @var{decl})
> +Stands for the value a @var{decl} had at the entry point of the
> +containing function.
> +
> +@findex debug_parameter_ref
> +@item (debug_parameter_ref:@var{mode} @var{decl})
> +Refers to a parameter that was completely optimized out.
> +
> +@findex debug_marker
> +@item (debug_marker:@var{mode})
> +Marks a program location.  With @code{VOIDmode}, it stands for the
> +beginning of a statement, a recommended inspection point logically after
> +all prior side effects, and before any subsequent side effects.
> +
>  @end table
>
>  @node Insns
> @@ -3689,6 +3708,12 @@ can be computed by evaluating the RTL expression from that static
>  point in the program up to the next such note for the same user
>  variable.
>
> +@findex NOTE_INSN_BEGIN_STMT
> +@item NOTE_INSN_BEGIN_STMT
> +This note is used to generate @code{is_stmt} markers in line number
> +debuggign information.  It indicates the beginning of a user
> +statement.
> +
>  @end table
>
>  These codes are printed symbolically when they appear in debugging dumps.
> @@ -3706,15 +3731,25 @@ binds a user variable tree to an RTL representation of the
>  it stands for the value bound to the corresponding
>  @code{DEBUG_EXPR_DECL}.
>
> -Throughout optimization passes, binding information is kept in
> -pseudo-instruction form, so that, unlike notes, it gets the same
> -treatment and adjustments that regular instructions would.  It is the
> -variable tracking pass that turns these pseudo-instructions into var
> -location notes, analyzing control flow, value equivalences and changes
> -to registers and memory referenced in value expressions, propagating
> -the values of debug temporaries and determining expressions that can
> -be used to compute the value of each user variable at as many points
> -(ranges, actually) in the program as possible.
> +@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
> +with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
> +@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
> +just @code{DEBUG_MARKER}s, can be detected by testing
> +@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
> +@code{DEBUG_BIND_INSN_P}.
> +
> +Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
> +with respect to each other, particularly during scheduling.  Binding
> +information is kept in pseudo-instruction form, so that, unlike notes,
> +it gets the same treatment and adjustments that regular instructions
> +would.  It is the variable tracking pass that turns these
> +pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
> +@code{NOTE_INSN_BEGIN_STMT} notes,
> +analyzing control flow, value equivalences and changes to registers and
> +memory referenced in value expressions, propagating the values of debug
> +temporaries and determining expressions that can be used to compute the
> +value of each user variable at as many points (ranges, actually) in the
> +program as possible.
>
>  Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
>  @code{INSN_VAR_LOCATION} denotes a value at that specific point in the
> diff --git a/gcc/final.c b/gcc/final.c
> index eff2ee6..49cfbfb 100644
> --- a/gcc/final.c
> +++ b/gcc/final.c
> @@ -1646,7 +1646,6 @@ reemit_insn_block_notes (void)
>  {
>    tree cur_block = DECL_INITIAL (cfun->decl);
>    rtx_insn *insn;
> -  rtx_note *note;
>
>    insn = get_insns ();
>    for (; insn; insn = NEXT_INSN (insn))
> @@ -1654,17 +1653,29 @@ reemit_insn_block_notes (void)
>        tree this_block;
>
>        /* Prevent lexical blocks from straddling section boundaries.  */
> -      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
> -        {
> -          for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
> -               s = BLOCK_SUPERCONTEXT (s))
> -            {
> -              rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
> -              NOTE_BLOCK (note) = s;
> -              note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
> -              NOTE_BLOCK (note) = s;
> -            }
> -        }
> +      if (NOTE_P (insn))
> +       switch (NOTE_KIND (insn))
> +         {
> +         case NOTE_INSN_SWITCH_TEXT_SECTIONS:
> +           {
> +             for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
> +                  s = BLOCK_SUPERCONTEXT (s))
> +               {
> +                 rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
> +                 NOTE_BLOCK (note) = s;
> +                 note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
> +                 NOTE_BLOCK (note) = s;
> +               }
> +           }
> +           break;
> +
> +         case NOTE_INSN_BEGIN_STMT:
> +           this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
> +           goto set_cur_block_to_this_block;
> +
> +         default:
> +           continue;
> +       }
>
>        if (!active_insn_p (insn))
>          continue;
> @@ -1685,6 +1696,7 @@ reemit_insn_block_notes (void)
>             this_block = choose_inner_scope (this_block,
>                                              insn_scope (body->insn (i)));
>         }
> +    set_cur_block_to_this_block:
>        if (! this_block)
>         {
>           if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
> @@ -1701,7 +1713,7 @@ reemit_insn_block_notes (void)
>      }
>
>    /* change_scope emits before the insn, not after.  */
> -  note = emit_note (NOTE_INSN_DELETED);
> +  rtx_note *note = emit_note (NOTE_INSN_DELETED);
>    change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
>    delete_insn (note);
>
> @@ -2404,6 +2416,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>             debug_hooks->var_location (insn);
>           break;
>
> +       case NOTE_INSN_BEGIN_STMT:
> +         gcc_checking_assert (cfun->debug_nonbind_markers);
> +         if (!DECL_IGNORED_P (current_function_decl)
> +             && notice_source_line (insn, NULL))
> +           {
> +             (*debug_hooks->source_line) (last_linenum, last_columnnum,
> +                                          last_filename, last_discriminator,
> +                                          true);
> +           }
> +         break;
> +
>         default:
>           gcc_unreachable ();
>           break;
> @@ -2490,7 +2513,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>         rtx body = PATTERN (insn);
>         int insn_code_number;
>         const char *templ;
> -       bool is_stmt;
> +       bool is_stmt, *is_stmt_p;
> +
> +       if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
> +         {
> +           is_stmt = false;
> +           is_stmt_p = NULL;
> +         }
> +       else
> +         is_stmt_p = &is_stmt;
>
>         /* Reset this early so it is correct for ASM statements.  */
>         current_insn_predicate = NULL_RTX;
> @@ -2593,7 +2624,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>         /* Output this line note if it is the first or the last line
>            note in a row.  */
>         if (!DECL_IGNORED_P (current_function_decl)
> -           && notice_source_line (insn, &is_stmt))
> +           && notice_source_line (insn, is_stmt_p))
>           {
>             if (flag_verbose_asm)
>               asm_show_source (last_filename, last_linenum);
> @@ -3086,7 +3117,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
>    const char *filename;
>    int linenum, columnnum;
>
> -  if (override_filename)
> +  if (NOTE_MARKER_P (insn))
> +    {
> +      location_t loc = NOTE_MARKER_LOCATION (insn);
> +      expanded_location xloc = expand_location (loc);
> +      if (xloc.line == 0)
> +       {
> +         gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
> +                              || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
> +         return false;
> +       }
> +      filename = xloc.file;
> +      linenum = xloc.line;
> +      columnnum = xloc.column;
> +      force_source_line = true;
> +    }
> +  else if (override_filename)
>      {
>        filename = override_filename;
>        linenum = override_linenum;
> @@ -3119,7 +3165,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
>        last_linenum = linenum;
>        last_columnnum = columnnum;
>        last_discriminator = discriminator;
> -      *is_stmt = true;
> +      if (is_stmt)
> +       *is_stmt = true;
>        high_block_linenum = MAX (last_linenum, high_block_linenum);
>        high_function_linenum = MAX (last_linenum, high_function_linenum);
>        return true;
> @@ -3131,7 +3178,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
>           output the line table entry with is_stmt false so the
>           debugger does not treat this as a breakpoint location.  */
>        last_discriminator = discriminator;
> -      *is_stmt = false;
> +      if (is_stmt)
> +       *is_stmt = false;
>        return true;
>      }
>
> @@ -4483,6 +4531,10 @@ rest_of_handle_final (void)
>  {
>    const char *fnname = get_fnname_from_decl (current_function_decl);
>
> +  /* Turn debug markers into notes.  */
> +  if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)
> +    variable_tracking_main ();
> +
>    assemble_start_function (current_function_decl, fnname);
>    final_start_function (get_insns (), asm_out_file, optimize);
>    final (get_insns (), asm_out_file, optimize);
> @@ -4670,6 +4722,7 @@ rest_of_clean_state (void)
>        if (final_output
>           && (!NOTE_P (insn) ||
>               (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
> +              && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
>                && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
>                && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
>                && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
> diff --git a/gcc/function.c b/gcc/function.c
> index ae61d3d..468dc9a 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -4933,6 +4933,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
>        if (!profile_flag && !flag_instrument_function_entry_exit)
>         DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
>      }
> +
> +  /* Don't enable begin stmt markers if var-tracking at assignments is
> +     disabled.  The markers make little sense without the variable
> +     binding annotations among them.  */
> +  cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
> +    && MAY_HAVE_DEBUG_MARKER_STMTS;
>  }
>
>  /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
> diff --git a/gcc/function.h b/gcc/function.h
> index 76434cd..1186116 100644
> --- a/gcc/function.h
> +++ b/gcc/function.h
> @@ -284,6 +284,12 @@ struct GTY(()) function {
>    /* Last statement uid.  */
>    int last_stmt_uid;
>
> +  /* Debug marker counter.  Count begin stmt markers.  We don't have
> +     to keep it exact, it's more of a rough estimate to enable us to
> +     decide whether they are too many to copy during inlining, or when
> +     expanding to RTL.  */
> +  int debug_marker_count;
> +
>    /* Function sequence number for profiling, debugging, etc.  */
>    int funcdef_no;
>
> @@ -387,6 +393,10 @@ struct GTY(()) function {
>
>    /* Set when the tail call has been identified.  */
>    unsigned int tail_call_marked : 1;
> +
> +  /* Set when the function was compiled with generation of debug
> +     (begin stmt, inline entry, ...) markers enabled.  */
> +  unsigned int debug_nonbind_markers : 1;
>  };
>
>  /* Add the decl D to the local_decls list of FUN.  */
> diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
> index fb75f99..2359760 100644
> --- a/gcc/gimple-iterator.c
> +++ b/gcc/gimple-iterator.c
> @@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
>
>    if (remove_permanently)
>      {
> +      if (gimple_debug_nonbind_marker_p (stmt))
> +       /* We don't need this to be exact, but try to keep it at least
> +          close.  */
> +       cfun->debug_marker_count--;
>        require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
>        gimple_remove_stmt_histograms (cfun, stmt);
>      }
> diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
> index 22db61b..95f3f45 100644
> --- a/gcc/gimple-low.c
> +++ b/gcc/gimple-low.c
> @@ -110,6 +110,17 @@ lower_function_body (void)
>
>    i = gsi_last (lowered_body);
>
> +  /* If we had begin stmt markers from e.g. PCH, but this compilation
> +     doesn't want them, lower_stmt will have cleaned them up; we can
> +     now clear the flag that indicates we had them.  */
> +  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
> +    {
> +      /* This counter needs not be exact, but before lowering it will
> +        most certainly be.  */
> +      gcc_assert (cfun->debug_marker_count == 0);
> +      cfun->debug_nonbind_markers = false;
> +    }
> +
>    /* If the function falls off the end, we need a null return statement.
>       If we've already got one in the return_statements vector, we don't
>       need to do anything special.  Otherwise build one by hand.  */
> @@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
>        }
>        break;
>
> +    case GIMPLE_DEBUG:
> +      gcc_checking_assert (cfun->debug_nonbind_markers);
> +      /* We can't possibly have debug bind stmts before lowering, we
> +        first emit them when entering SSA.  */
> +      gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
> +      /* Propagate fallthruness.  */
> +      /* If the function (e.g. from PCH) had debug stmts, but they're
> +        disabled for this compilation, remove them.  */
> +      if (!MAY_HAVE_DEBUG_MARKER_STMTS)
> +       gsi_remove (gsi, true);
> +      else
> +       gsi_next (gsi);
> +      return;
> +
>      case GIMPLE_NOP:
>      case GIMPLE_ASM:
>      case GIMPLE_ASSIGN:
> @@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
>         cannot_fallthru = false;
>        break;
>
> +    case GIMPLE_DEBUG:
> +      gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
> +      break;
> +
>      default:
>        /* This case represents statements to be executed when an
>          exception occurs.  Those statements are implicitly followed
> diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
> index ed8e51c..2702854 100644
> --- a/gcc/gimple-pretty-print.c
> +++ b/gcc/gimple-pretty-print.c
> @@ -1370,6 +1370,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
>                          gimple_debug_source_bind_get_value (gs));
>        break;
>
> +    case GIMPLE_DEBUG_BEGIN_STMT:
> +      if (flags & TDF_RAW)
> +       dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
> +      else
> +       dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
> +      break;
> +
>      default:
>        gcc_unreachable ();
>      }
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index c4e6f81..dc9aa79 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -836,6 +836,27 @@ gimple_build_debug_source_bind (tree var, tree value,
>  }
>
>
> +/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
> +   LOCATION.  */
> +
> +gdebug *
> +gimple_build_debug_begin_stmt (tree block, location_t location
> +                                   MEM_STAT_DECL)
> +{
> +  gdebug *p
> +    = as_a <gdebug *> (
> +        gimple_build_with_ops_stat (GIMPLE_DEBUG,
> +                                   (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
> +                                   PASS_MEM_STAT));
> +
> +  gimple_set_location (p, location);
> +  gimple_set_block (p, block);
> +  cfun->debug_marker_count++;
> +
> +  return p;
> +}
> +
> +
>  /* Build a GIMPLE_OMP_CRITICAL statement.
>
>     BODY is the sequence of statements for which only one thread can execute.
> @@ -1874,6 +1895,9 @@ gimple_copy (gimple *stmt)
>        gimple_set_modified (copy, true);
>      }
>
> +  if (gimple_debug_nonbind_marker_p (stmt))
> +    cfun->debug_marker_count++;
> +
>    return copy;
>  }
>
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 8f289ac..68cd34f 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -1454,6 +1454,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );
>  geh_dispatch *gimple_build_eh_dispatch (int);
>  gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
>  gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
> +gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
>  gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
>  gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
>  gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index e9dffc3..6c80a81 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -982,6 +982,48 @@ unshare_expr_without_location (tree expr)
>      walk_tree (&expr, prune_expr_location, NULL, NULL);
>    return expr;
>  }
> +
> +/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
> +   one, OR_ELSE otherwise.  The location of a STATEMENT_LISTs
> +   comprising at least one DEBUG_BEGIN_STMT followed by exactly one
> +   EXPR is the location of the EXPR.  */
> +
> +static location_t
> +rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
> +{
> +  if (!expr)
> +    return or_else;
> +
> +  if (EXPR_HAS_LOCATION (expr))
> +    return EXPR_LOCATION (expr);
> +
> +  if (TREE_CODE (expr) != STATEMENT_LIST)
> +    return or_else;
> +
> +  tree_stmt_iterator i = tsi_start (expr);
> +
> +  bool found = false;
> +  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +    {
> +      found = true;
> +      tsi_next (&i);
> +    }
> +
> +  if (!found || !tsi_one_before_end_p (i))
> +    return or_else;
> +
> +  return rexpr_location (tsi_stmt (i), or_else);
> +}
> +
> +/* Return TRUE iff EXPR (maybe recursively) has a location; see
> +   rexpr_location for the potential recursion.  */
> +
> +static inline bool
> +rexpr_has_location (tree expr)
> +{
> +  return rexpr_location (expr) != UNKNOWN_LOCATION;
> +}
> +
>
>  /* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
>     contain statements and have a value.  Assign its value to a temporary
> @@ -1772,6 +1814,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
>        /* Walk the sub-statements.  */
>        *handled_ops_p = false;
>        break;
> +
> +    case GIMPLE_DEBUG:
> +      /* Ignore these.  We may generate them before declarations that
> +        are never executed.  If there's something to warn about,
> +        there will be non-debug stmts too, and we'll catch those.  */
> +      break;
> +
>      case GIMPLE_CALL:
>        if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
>         {
> @@ -3441,7 +3490,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
>        append_to_statement_list (t, &expr);
>
>        /* Set the source location of the && on the second 'if'.  */
> -      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
> +      new_locus = rexpr_location (pred, locus);
>        t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
>                            new_locus);
>        append_to_statement_list (t, &expr);
> @@ -3464,7 +3513,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
>        append_to_statement_list (t, &expr);
>
>        /* Set the source location of the || on the second 'if'.  */
> -      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
> +      new_locus = rexpr_location (pred, locus);
>        t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
>                            new_locus);
>        append_to_statement_list (t, &expr);
> @@ -3486,7 +3535,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
>
>        /* Keep the original source location on the first 'if'.  Set the source
>          location of the ? on the second 'if'.  */
> -      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
> +      new_locus = rexpr_location (pred, locus);
>        expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
>                      shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
>                                       false_label_p, locus),
> @@ -3510,6 +3559,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
>    return expr;
>  }
>
> +/* If EXPR is a GOTO_EXPR, return it.  If it is a STATEMENT_LIST, skip
> +   any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent
> +   statement, if it is the last one.  Otherwise, return NULL.  */
> +
> +static tree
> +find_goto (tree expr)
> +{
> +  if (!expr)
> +    return NULL_TREE;
> +
> +  if (TREE_CODE (expr) == GOTO_EXPR)
> +    return expr;
> +
> +  if (TREE_CODE (expr) != STATEMENT_LIST)
> +    return NULL_TREE;
> +
> +  tree_stmt_iterator i = tsi_start (expr);
> +
> +  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +    tsi_next (&i);
> +
> +  if (!tsi_one_before_end_p (i))
> +    return NULL_TREE;
> +
> +  return find_goto (tsi_stmt (i));
> +}
> +
> +/* Same as find_goto, except that it returns NULL if the destination
> +   is not a LABEL_DECL.  */
> +
> +static inline tree
> +find_goto_label (tree expr)
> +{
> +  tree dest = find_goto (expr);
> +  if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)
> +    return dest;
> +  return NULL_TREE;
> +}
> +
>  /* Given a conditional expression EXPR with short-circuit boolean
>     predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the
>     predicate apart into the equivalent sequence of conditionals.  */
> @@ -3540,8 +3628,8 @@ shortcut_cond_expr (tree expr)
>           location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
>           TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
>           /* Set the source location of the && on the second 'if'.  */
> -         if (EXPR_HAS_LOCATION (pred))
> -           SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
> +         if (rexpr_has_location (pred))
> +           SET_EXPR_LOCATION (expr, rexpr_location (pred));
>           then_ = shortcut_cond_expr (expr);
>           then_se = then_ && TREE_SIDE_EFFECTS (then_);
>           pred = TREE_OPERAND (pred, 0);
> @@ -3562,8 +3650,8 @@ shortcut_cond_expr (tree expr)
>           location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
>           TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
>           /* Set the source location of the || on the second 'if'.  */
> -         if (EXPR_HAS_LOCATION (pred))
> -           SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
> +         if (rexpr_has_location (pred))
> +           SET_EXPR_LOCATION (expr, rexpr_location (pred));
>           else_ = shortcut_cond_expr (expr);
>           else_se = else_ && TREE_SIDE_EFFECTS (else_);
>           pred = TREE_OPERAND (pred, 0);
> @@ -3590,20 +3678,16 @@ shortcut_cond_expr (tree expr)
>    /* If our arms just jump somewhere, hijack those labels so we don't
>       generate jumps to jumps.  */
>
> -  if (then_
> -      && TREE_CODE (then_) == GOTO_EXPR
> -      && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
> +  if (tree then_goto = find_goto_label (then_))
>      {
> -      true_label = GOTO_DESTINATION (then_);
> +      true_label = GOTO_DESTINATION (then_goto);
>        then_ = NULL;
>        then_se = false;
>      }
>
> -  if (else_
> -      && TREE_CODE (else_) == GOTO_EXPR
> -      && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
> +  if (tree else_goto = find_goto_label (else_))
>      {
> -      false_label = GOTO_DESTINATION (else_);
> +      false_label = GOTO_DESTINATION (else_goto);
>        else_ = NULL;
>        else_se = false;
>      }
> @@ -3667,8 +3751,8 @@ shortcut_cond_expr (tree expr)
>         {
>           tree last = expr_last (expr);
>           t = build_and_jump (&end_label);
> -         if (EXPR_HAS_LOCATION (last))
> -           SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
> +         if (rexpr_has_location (last))
> +           SET_EXPR_LOCATION (t, rexpr_location (last));
>           append_to_statement_list (t, &expr);
>         }
>        if (emit_false)
> @@ -3961,39 +4045,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
>    gimple_push_condition ();
>
>    have_then_clause_p = have_else_clause_p = false;
> -  if (TREE_OPERAND (expr, 1) != NULL
> -      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
> -      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
> -      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
> -         == current_function_decl)
> +  label_true = find_goto_label (TREE_OPERAND (expr, 1));
> +  if (label_true
> +      && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
>        /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
>          have different locations, otherwise we end up with incorrect
>          location information on the branches.  */
>        && (optimize
>           || !EXPR_HAS_LOCATION (expr)
> -         || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
> -         || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
> +         || !rexpr_has_location (label_true)
> +         || EXPR_LOCATION (expr) == rexpr_location (label_true)))
>      {
> -      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
>        have_then_clause_p = true;
> +      label_true = GOTO_DESTINATION (label_true);
>      }
>    else
>      label_true = create_artificial_label (UNKNOWN_LOCATION);
> -  if (TREE_OPERAND (expr, 2) != NULL
> -      && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
> -      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
> -      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
> -         == current_function_decl)
> +  label_false = find_goto_label (TREE_OPERAND (expr, 2));
> +  if (label_false
> +      && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
>        /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
>          have different locations, otherwise we end up with incorrect
>          location information on the branches.  */
>        && (optimize
>           || !EXPR_HAS_LOCATION (expr)
> -         || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
> -         || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
> +         || !rexpr_has_location (label_false)
> +         || EXPR_LOCATION (expr) == rexpr_location (label_false)))
>      {
> -      label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
>        have_else_clause_p = true;
> +      label_false = GOTO_DESTINATION (label_false);
>      }
>    else
>      label_false = create_artificial_label (UNKNOWN_LOCATION);
> @@ -11789,6 +11869,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
>           ret = GS_ALL_DONE;
>           break;
>
> +       case DEBUG_EXPR_DECL:
> +         gcc_unreachable ();
> +
> +       case DEBUG_BEGIN_STMT:
> +         gimplify_seq_add_stmt (pre_p,
> +                                gimple_build_debug_begin_stmt
> +                                (TREE_BLOCK (*expr_p),
> +                                 EXPR_LOCATION (*expr_p)));
> +         ret = GS_ALL_DONE;
> +         *expr_p = NULL;
> +         break;
> +
>         case SSA_NAME:
>           /* Allow callbacks into the gimplifier during optimization.  */
>           ret = GS_ALL_DONE;
> diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
> index 61b081b..a3f02b2 100644
> --- a/gcc/langhooks-def.h
> +++ b/gcc/langhooks-def.h
> @@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int);
>  #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP      false
>  #define LANG_HOOKS_DEEP_UNSHARING      false
>  #define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS false
> +#define LANG_HOOKS_EMITS_BEGIN_STMT    false
>  #define LANG_HOOKS_RUN_LANG_SELFTESTS   lhd_do_nothing
>  #define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
>
> @@ -343,6 +344,7 @@ extern void lhd_end_section (void);
>    LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
>    LANG_HOOKS_DEEP_UNSHARING, \
>    LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \
> +  LANG_HOOKS_EMITS_BEGIN_STMT, \
>    LANG_HOOKS_RUN_LANG_SELFTESTS, \
>    LANG_HOOKS_GET_SUBSTRING_LOCATION \
>  }
> diff --git a/gcc/langhooks.h b/gcc/langhooks.h
> index b0c9829..3493ff3 100644
> --- a/gcc/langhooks.h
> +++ b/gcc/langhooks.h
> @@ -528,6 +528,9 @@ struct lang_hooks
>       instead of trampolines.  */
>    bool custom_function_descriptors;
>
> +  /* True if this language emits begin stmt notes.  */
> +  bool emits_begin_stmt;
> +
>    /* Run all lang-specific selftests.  */
>    void (*run_lang_selftests) (void);
>
> diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
> index 4734c072..47527b0 100644
> --- a/gcc/lra-constraints.c
> +++ b/gcc/lra-constraints.c
> @@ -5253,10 +5253,11 @@ inherit_reload_reg (bool def_p, int original_regno,
>        lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
>        if (lra_dump_file != NULL)
>         {
> +         basic_block bb = BLOCK_FOR_INSN (usage_insn);
>           fprintf (lra_dump_file,
>                    "    Inheritance reuse change %d->%d (bb%d):\n",
>                    original_regno, REGNO (new_reg),
> -                  BLOCK_FOR_INSN (usage_insn)->index);
> +                  bb ? bb->index : -1);
>           dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
>         }
>      }
> @@ -5796,6 +5797,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
>        if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
>         continue;
>        curr_bb = BLOCK_FOR_INSN (curr_insn);
> +      if (!curr_bb)
> +       {
> +         gcc_assert (DEBUG_INSN_P (curr_insn));
> +         if (DEBUG_MARKER_INSN_P (curr_insn))
> +           continue;
> +         curr_bb = prev_bb;
> +       }
>        if (curr_bb != prev_bb)
>         {
>           if (prev_bb != NULL)
> diff --git a/gcc/lra.c b/gcc/lra.c
> index 9037495..ac99d5e 100644
> --- a/gcc/lra.c
> +++ b/gcc/lra.c
> @@ -602,9 +602,9 @@ static struct lra_operand_data debug_operand_data =
>    };
>
>  /* The following data are used as static insn data for all debug
> -   insns.  If structure lra_static_insn_data is changed, the
> +   bind insns.  If structure lra_static_insn_data is changed, the
>     initializer should be changed too.  */
> -static struct lra_static_insn_data debug_insn_static_data =
> +static struct lra_static_insn_data debug_bind_static_data =
>    {
>      &debug_operand_data,
>      0, /* Duplication operands #.  */
> @@ -618,6 +618,22 @@ static struct lra_static_insn_data debug_insn_static_data =
>      NULL  /* Descriptions of operands in alternatives. */
>    };
>
> +/* The following data are used as static insn data for all debug
> +   marker insns.  If structure lra_static_insn_data is changed, the
> +   initializer should be changed too.  */
> +static struct lra_static_insn_data debug_marker_static_data =
> +  {
> +    &debug_operand_data,
> +    0, /* Duplication operands #.  */
> +    -1, /* Commutative operand #.  */
> +    0, /* Operands #.  There isn't any operand.  */
> +    0, /* Duplications #.  */
> +    0, /* Alternatives #.  We are not interesting in alternatives
> +          because we does not proceed debug_insns for reloads.  */
> +    NULL, /* Hard registers referenced in machine description. */
> +    NULL  /* Descriptions of operands in alternatives. */
> +  };
> +
>  /* Called once per compiler work to initialize some LRA data related
>     to insns.  */
>  static void
> @@ -949,12 +965,20 @@ lra_set_insn_recog_data (rtx_insn *insn)
>    data->regs = NULL;
>    if (DEBUG_INSN_P (insn))
>      {
> -      data->insn_static_data = &debug_insn_static_data;
>        data->dup_loc = NULL;
>        data->arg_hard_regs = NULL;
>        data->preferred_alternatives = ALL_ALTERNATIVES;
> -      data->operand_loc = XNEWVEC (rtx *, 1);
> -      data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
> +      if (DEBUG_BIND_INSN_P (insn))
> +       {
> +         data->insn_static_data = &debug_bind_static_data;
> +         data->operand_loc = XNEWVEC (rtx *, 1);
> +         data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
> +       }
> +      else if (DEBUG_MARKER_INSN_P (insn))
> +       {
> +         data->insn_static_data = &debug_marker_static_data;
> +         data->operand_loc = NULL;
> +       }
>        return data;
>      }
>    if (icode < 0)
> @@ -1600,7 +1624,7 @@ lra_update_insn_regno_info (rtx_insn *insn)
>      return;
>    data = lra_get_insn_recog_data (insn);
>    static_data = data->insn_static_data;
> -  freq = get_insn_freq (insn);
> +  freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
>    invalidate_insn_data_regno_info (data, insn, freq);
>    uid = INSN_UID (insn);
>    for (i = static_data->n_operands - 1; i >= 0; i--)
> diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
> index 51d9a7b..37fa14e 100644
> --- a/gcc/lto-streamer-in.c
> +++ b/gcc/lto-streamer-in.c
> @@ -1130,7 +1130,10 @@ input_function (tree fn_decl, struct data_in *data_in,
>              Similarly remove all IFN_*SAN_* internal calls   */
>           if (!flag_wpa)
>             {
> -             if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
> +             if (is_gimple_debug (stmt)
> +                 && (gimple_debug_nonbind_marker_p (stmt)
> +                     ? !MAY_HAVE_DEBUG_MARKER_STMTS
> +                     : !MAY_HAVE_DEBUG_BIND_STMTS))
>                 remove = true;
>               if (is_gimple_call (stmt)
>                   && gimple_call_internal_p (stmt))
> @@ -1184,6 +1187,13 @@ input_function (tree fn_decl, struct data_in *data_in,
>             {
>               gsi_next (&bsi);
>               stmts[gimple_uid (stmt)] = stmt;
> +
> +             /* Remember that the input function has begin stmt
> +                markers, so that we know to expect them when emitting
> +                debug info.  */
> +             if (!cfun->debug_nonbind_markers
> +                 && gimple_debug_nonbind_marker_p (stmt))
> +               cfun->debug_nonbind_markers = true;
>             }
>         }
>      }
> diff --git a/gcc/params.def b/gcc/params.def
> index 136f927..9f63e63 100644
> --- a/gcc/params.def
> +++ b/gcc/params.def
> @@ -963,6 +963,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
>           "Max. size of loc list for which reverse ops should be added.",
>           50, 0, 0)
>
> +/* Set a threshold to discard debug markers (e.g. debug begin stmt
> +   markers) when expanding a function to RTL, or inlining it into
> +   another function.  */
> +
> +DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
> +         "max-debug-marker-count",
> +         "Max. count of debug markers to expand or inline.",
> +         100000, 0, 0)
> +
>  /* Set minimum insn uid for non-debug insns.  */
>
>  DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
> diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
> index 79ec463..0d36a42 100644
> --- a/gcc/print-rtl.c
> +++ b/gcc/print-rtl.c
> @@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
>           fputc ('\t', m_outfile);
>           break;
>
> +       case NOTE_INSN_BEGIN_STMT:
> +#ifndef GENERATOR_FILE
> +         {
> +           expanded_location xloc
> +             = expand_location (NOTE_MARKER_LOCATION (in_rtx));
> +           fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
> +         }
> +#endif
> +         break;
> +
>         default:
>           break;
>         }
> @@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
>
>      case DEBUG_INSN:
>        {
> +       if (DEBUG_MARKER_INSN_P (x))
> +         {
> +           switch (INSN_DEBUG_MARKER_KIND (x))
> +             {
> +             case NOTE_INSN_BEGIN_STMT:
> +               pp_string (pp, "debug begin stmt marker");
> +               break;
> +
> +             default:
> +               gcc_unreachable ();
> +             }
> +           break;
> +         }
> +
>         const char *name = "?";
>
>         if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
> diff --git a/gcc/recog.c b/gcc/recog.c
> index cfce029..566425d 100644
> --- a/gcc/recog.c
> +++ b/gcc/recog.c
> @@ -2251,6 +2251,7 @@ extract_insn (rtx_insn *insn)
>      case ADDR_VEC:
>      case ADDR_DIFF_VEC:
>      case VAR_LOCATION:
> +    case DEBUG_MARKER:
>        return;
>
>      case SET:
> diff --git a/gcc/rtl.def b/gcc/rtl.def
> index 4c2607a..ccdaa82 100644
> --- a/gcc/rtl.def
> +++ b/gcc/rtl.def
> @@ -761,6 +761,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
>     been optimized away completely.  */
>  DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
>
> +/* Used in marker DEBUG_INSNs to avoid being recognized as an insn.  */
> +DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_OBJ)
> +
>  /* All expressions from this point forward appear only in machine
>     descriptions.  */
>  #ifdef GENERATOR_FILE
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index a142488..a99e975 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-ssa.h"
>  #include "except.h"
>  #include "debug.h"
> +#include "params.h"
>  #include "value-prof.h"
>  #include "cfgloop.h"
>  #include "builtins.h"
> @@ -1354,7 +1355,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
>    gimple_seq stmts = NULL;
>
>    if (is_gimple_debug (stmt)
> -      && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
> +      && (gimple_debug_nonbind_marker_p (stmt)
> +         ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers
> +         : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
>      return stmts;
>
>    /* Begin by recognizing trees that we'll completely rewrite for the
> @@ -1637,6 +1640,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
>           gimple_seq_add_stmt (&stmts, copy);
>           return stmts;
>         }
> +      if (gimple_debug_nonbind_marker_p (stmt))
> +       {
> +         /* If the inlined function has too many debug markers,
> +            don't copy them.  */
> +         if (id->src_cfun->debug_marker_count
> +             > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
> +           return stmts;
> +
> +         gdebug *copy = as_a <gdebug *> (gimple_copy (stmt));
> +         id->debug_stmts.safe_push (copy);
> +         gimple_seq_add_stmt (&stmts, copy);
> +         return stmts;
> +       }
> +      gcc_checking_assert (!is_gimple_debug (stmt));
>
>        /* Create a new deep copy of the statement.  */
>        copy = gimple_copy (stmt);
> @@ -1732,7 +1749,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
>        gimple_set_block (copy, *n);
>      }
>
> -  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
> +  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)
> +      || gimple_debug_nonbind_marker_p (copy))
>      {
>        gimple_seq_add_stmt (&stmts, copy);
>        return stmts;
> @@ -2606,6 +2624,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
>               value = gimple_debug_source_bind_get_value (stmt);
>               new_stmt = gimple_build_debug_source_bind (var, value, stmt);
>             }
> +         else if (gimple_debug_nonbind_marker_p (stmt))
> +           new_stmt = as_a <gdebug *> (gimple_copy (stmt));
>           else
>             gcc_unreachable ();
>           gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
> @@ -2922,6 +2942,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
>        gimple_set_block (stmt, n ? *n : id->block);
>      }
>
> +  if (gimple_debug_nonbind_marker_p (stmt))
> +    return;
> +
>    /* Remap all the operands in COPY.  */
>    memset (&wi, 0, sizeof (wi));
>    wi.info = id;
> @@ -2930,8 +2953,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
>
>    if (gimple_debug_source_bind_p (stmt))
>      t = gimple_debug_source_bind_get_var (stmt);
> -  else
> +  else if (gimple_debug_bind_p (stmt))
>      t = gimple_debug_bind_get_var (stmt);
> +  else
> +    gcc_unreachable ();
>
>    if (TREE_CODE (t) == PARM_DECL && id->debug_map
>        && (n = id->debug_map->get (t)))
> diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
> index c485413..10e510d 100644
> --- a/gcc/tree-iterator.c
> +++ b/gcc/tree-iterator.c
> @@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)
>  void
>  append_to_statement_list (tree t, tree *list_p)
>  {
> -  if (t && TREE_SIDE_EFFECTS (t))
> +  if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
>      append_to_statement_list_1 (t, list_p);
>  }
>
> @@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
>        tail = head;
>      }
>
> -  TREE_SIDE_EFFECTS (i->container) = 1;
> +  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
> +    TREE_SIDE_EFFECTS (i->container) = 1;
>
>    cur = i->ptr;
>
> @@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
>        tail = head;
>      }
>
> -  TREE_SIDE_EFFECTS (i->container) = 1;
> +  if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
> +    TREE_SIDE_EFFECTS (i->container) = 1;
>
>    cur = i->ptr;
>
> @@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)
>    i->ptr = next;
>  }
>
> -/* Return the first expression in a sequence of COMPOUND_EXPRs,
> -   or in a STATEMENT_LIST.  */
> +/* Return the first expression in a sequence of COMPOUND_EXPRs, or in
> +   a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
> +   STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT.  */
>
>  tree
>  expr_first (tree expr)
> @@ -291,7 +294,20 @@ expr_first (tree expr)
>    if (TREE_CODE (expr) == STATEMENT_LIST)
>      {
>        struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
> -      return n ? n->stmt : NULL_TREE;
> +      if (!n)
> +       return NULL_TREE;
> +      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
> +       {
> +         n = n->next;
> +         if (!n)
> +           return NULL_TREE;
> +       }
> +      /* If the first non-debug stmt is not a statement list, we
> +        already know it's what we're looking for.  */
> +      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
> +       return n->stmt;
> +
> +      return expr_first (n->stmt);
>      }
>
>    while (TREE_CODE (expr) == COMPOUND_EXPR)
> @@ -300,8 +316,9 @@ expr_first (tree expr)
>    return expr;
>  }
>
> -/* Return the last expression in a sequence of COMPOUND_EXPRs,
> -   or in a STATEMENT_LIST.  */
> +/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
> +   STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
> +   STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT.  */
>
>  tree
>  expr_last (tree expr)
> @@ -312,7 +329,20 @@ expr_last (tree expr)
>    if (TREE_CODE (expr) == STATEMENT_LIST)
>      {
>        struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
> -      return n ? n->stmt : NULL_TREE;
> +      if (!n)
> +       return NULL_TREE;
> +      while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
> +       {
> +         n = n->prev;
> +         if (!n)
> +           return NULL_TREE;
> +       }
> +      /* If the last non-debug stmt is not a statement list, we
> +        already know it's what we're looking for.  */
> +      if (TREE_CODE (n->stmt) != STATEMENT_LIST)
> +       return n->stmt;
> +
> +      return expr_last (n->stmt);
>      }
>
>    while (TREE_CODE (expr) == COMPOUND_EXPR)
> diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
> index 1fe3e63..22c6667 100644
> --- a/gcc/tree-pretty-print.c
> +++ b/gcc/tree-pretty-print.c
> @@ -3291,6 +3291,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
>        pp_string (pp, "_Cilk_sync");
>        break;
>
> +    case DEBUG_BEGIN_STMT:
> +      pp_string (pp, "# DEBUG BEGIN STMT");
> +      break;
> +
>      default:
>        NIY;
>      }
> diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
> index 70675e4..91793bf 100644
> --- a/gcc/tree-ssa-threadedge.c
> +++ b/gcc/tree-ssa-threadedge.c
> @@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
>        gimple *stmt = gsi_stmt (si);
>        if (!is_gimple_debug (stmt))
>         break;
> +      if (gimple_debug_nonbind_marker_p (stmt))
> +       continue;
>        i++;
>      }
>
> @@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
>         var = gimple_debug_bind_get_var (stmt);
>        else if (gimple_debug_source_bind_p (stmt))
>         var = gimple_debug_source_bind_get_var (stmt);
> +      else if (gimple_debug_nonbind_marker_p (stmt))
> +       continue;
>        else
>         gcc_unreachable ();
>
> @@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
>             var = gimple_debug_bind_get_var (stmt);
>           else if (gimple_debug_source_bind_p (stmt))
>             var = gimple_debug_source_bind_get_var (stmt);
> +         else if (gimple_debug_nonbind_marker_p (stmt))
> +           continue;
>           else
>             gcc_unreachable ();
>
> -         /* Discard debug bind overlaps.  ??? Unlike stmts from src,
> +         /* Discard debug bind overlaps.  Unlike stmts from src,
>              copied into a new block that will precede BB, debug bind
>              stmts in bypassed BBs may actually be discarded if
> -            they're overwritten by subsequent debug bind stmts, which
> -            might be a problem once we introduce stmt frontier notes
> -            or somesuch.  Adding `&& bb == src' to the condition
> -            below will preserve all potentially relevant debug
> -            notes.  */
> +            they're overwritten by subsequent debug bind stmts.  We
> +            want to copy binds for all modified variables, so that we
> +            retain a bind to the shared def if there is one, or to a
> +            newly introduced PHI node if there is one.  Our bind will
> +            end up reset if the value is dead, but that implies the
> +            variable couldn't have survived, so it's fine.  We are
> +            not actually running the code that performed the binds at
> +            this point, we're just adding binds so that they survive
> +            the new confluence, so markers should not be copied.  */
>           if (vars && vars->add (var))
>             continue;
>           else if (!vars)
> @@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
>                   break;
>               if (i >= 0)
>                 continue;
> -
> -             if (fewvars.length () < (unsigned) alloc_count)
> +             else if (fewvars.length () < (unsigned) alloc_count)
>                 fewvars.quick_push (var);
>               else
>                 {
> diff --git a/gcc/tree.c b/gcc/tree.c
> index e379940..30cadd7 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -1015,7 +1015,8 @@ make_node (enum tree_code code MEM_STAT_DECL)
>    switch (type)
>      {
>      case tcc_statement:
> -      TREE_SIDE_EFFECTS (t) = 1;
> +      if (code != DEBUG_BEGIN_STMT)
> +       TREE_SIDE_EFFECTS (t) = 1;
>        break;
>
>      case tcc_declaration:
> @@ -4412,7 +4413,10 @@ build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)
>      }
>
>    if (TREE_CODE_CLASS (code) == tcc_statement)
> -    TREE_SIDE_EFFECTS (t) = 1;
> +    {
> +      if (code != DEBUG_BEGIN_STMT)
> +       TREE_SIDE_EFFECTS (t) = 1;
> +    }
>    else switch (code)
>      {
>      case VA_ARG_EXPR:
> diff --git a/gcc/tree.def b/gcc/tree.def
> index 9f80c4d..e30e950 100644
> --- a/gcc/tree.def
> +++ b/gcc/tree.def
> @@ -382,6 +382,9 @@ DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
>     DEBUG stmts.  */
>  DEFTREECODE (DEBUG_EXPR_DECL, "debug_expr_decl", tcc_declaration, 0)
>
> +/* A stmt that marks the beginning of a source statement.  */
> +DEFTREECODE (DEBUG_BEGIN_STMT, "debug_begin_stmt", tcc_statement, 0)
> +
>  /* A namespace declaration.  Namespaces appear in DECL_CONTEXT of other
>     _DECLs, providing a hierarchy of names.  */
>  DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 2e8b3e9..62a85ea 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -1225,7 +1225,7 @@ extern void protected_set_expr_location (tree, location_t);
>
>  /* GOTO_EXPR accessor. This gives access to the label associated with
>     a goto statement.  */
> -#define GOTO_DESTINATION(NODE)  TREE_OPERAND ((NODE), 0)
> +#define GOTO_DESTINATION(NODE)  TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
>
>  /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
>     instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
> diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
> index 974b4ea..d3850af 100644
> --- a/gcc/var-tracking.c
> +++ b/gcc/var-tracking.c
> @@ -9919,6 +9919,36 @@ vt_init_cfa_base (void)
>    cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
>  }
>
> +/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
> +
> +static rtx_insn *
> +reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
> +{
> +  gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
> +
> +  enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
> +
> +  switch (kind)
> +    {
> +    case NOTE_INSN_BEGIN_STMT:
> +      {
> +       rtx_insn *note = NULL;
> +       if (cfun->debug_nonbind_markers)
> +         {
> +           note = emit_note_before (kind, insn);
> +           NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
> +           if (bb)
> +             BLOCK_FOR_INSN (note) = *bb;
> +         }
> +       delete_insn (insn);
> +       return note;
> +      }
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
>  /* Allocate and initialize the data structures for variable tracking
>     and parse the RTL to get the micro operations.  */
>
> @@ -10162,6 +10192,12 @@ vt_initialize (void)
>
>                   cselib_hook_called = false;
>                   adjust_insn (bb, insn);
> +                 if (DEBUG_MARKER_INSN_P (insn))
> +                   {
> +                     insn = reemit_marker_as_note (insn, &save_bb);
> +                     continue;
> +                   }
> +
>                   if (MAY_HAVE_DEBUG_BIND_INSNS)
>                     {
>                       if (CALL_P (insn))
> @@ -10238,10 +10274,11 @@ vt_initialize (void)
>
>  static int debug_label_num = 1;
>
> -/* Get rid of all debug insns from the insn stream.  */
> +/* Remove from the insn stream all debug insns used for variable
> +   tracking at assignments.  */
>
>  static void
> -delete_debug_insns (void)
> +delete_vta_debug_insns (void)
>  {
>    basic_block bb;
>    rtx_insn *insn, *next;
> @@ -10257,6 +10294,12 @@ delete_debug_insns (void)
>            insn = next)
>         if (DEBUG_INSN_P (insn))
>           {
> +           if (DEBUG_MARKER_INSN_P (insn))
> +             {
> +               insn = reemit_marker_as_note (insn, NULL);
> +               continue;
> +             }
> +
>             tree decl = INSN_VAR_LOCATION_DECL (insn);
>             if (TREE_CODE (decl) == LABEL_DECL
>                 && DECL_NAME (decl)
> @@ -10282,10 +10325,13 @@ delete_debug_insns (void)
>     handled as well..  */
>
>  static void
> -vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
> +vt_debug_insns_local (bool skipped)
>  {
> -  /* ??? Just skip it all for now.  */
> -  delete_debug_insns ();
> +  /* ??? Just skip it all for now.  If we skipped the global pass,
> +     arrange for stmt markers to be dropped as well.  */
> +  if (skipped)
> +    cfun->debug_nonbind_markers = 0;
> +  delete_vta_debug_insns ();
>  }
>
>  /* Free the data structures needed for variable tracking.  */
> @@ -10350,15 +10396,21 @@ variable_tracking_main_1 (void)
>  {
>    bool success;
>
> -  if (flag_var_tracking_assignments < 0
> +  /* We won't be called as a separate pass if flag_var_tracking is not
> +     set, but final may call us to turn debug markers into notes.  */
> +  if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
> +      || flag_var_tracking_assignments < 0
>        /* Var-tracking right now assumes the IR doesn't contain
>          any pseudos at this point.  */
>        || targetm.no_register_allocation)
>      {
> -      delete_debug_insns ();
> +      delete_vta_debug_insns ();
>        return 0;
>      }
>
> +  if (!flag_var_tracking)
> +    return 0;
> +
>    if (n_basic_blocks_for_fn (cfun) > 500 &&
>        n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
>      {
> @@ -10380,7 +10432,9 @@ variable_tracking_main_1 (void)
>      {
>        vt_finalize ();
>
> -      delete_debug_insns ();
> +      cfun->debug_nonbind_markers = 0;
> +
> +      delete_vta_debug_insns ();
>
>        /* This is later restored by our caller.  */
>        flag_var_tracking_assignments = 0;
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-09-30  9:09               ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
@ 2017-10-09 13:12                 ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2017-10-09 13:12 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> Introduce a command line option to enable statement frontiers, enabled
> by default in optimized builds with DWARF2+ debug information.
>
> This patch depends on an earlier patch that completed the
> infrastructure for debug markers, and on another patch that turns -g
> into a negatable option prefix.

Ok.

Richard.

> gcc/ChangeLog
>
>         * common.opt (gstatement-frontiers): New, setting
>         debug_nonbind_markers_p.
>         * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
>         * toplev.c (process_options): Autodetect value for debug statement
>         frontiers option.
>         * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
>         * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
> ---
>  gcc/common.opt      |  4 ++++
>  gcc/doc/invoke.texi | 12 ++++++++++++
>  gcc/rtl.h           |  2 +-
>  gcc/toplev.c        |  4 ++++
>  gcc/tree.h          |  2 +-
>  5 files changed, 22 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index dfde6ad..a12c11c 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2889,6 +2889,10 @@ gstabs+
>  Common Driver JoinedOrMissing Negative(gvms)
>  Generate debug information in extended STABS format.
>
> +gstatement-frontiers
> +Common Driver Var(debug_nonbind_markers_p) Init(2)
> +Emit progressive recommended breakpoint locations.
> +
>  gstrict-dwarf
>  Common Driver Report Var(dwarf_strict) Init(0)
>  Don't emit DWARF additions beyond selected version.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 108d730..85e41e4 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -346,6 +346,7 @@ 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
> +-gstatement-frontiers  -gno-statement-frontiers @gol
>  -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
>  -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
>  -fno-eliminate-unused-debug-types @gol
> @@ -7040,6 +7041,17 @@ 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 -gz@r{[}=@var{type}@r{]}
>  @opindex gz
>  Produce compressed debug sections in DWARF format, if that is supported.
> diff --git a/gcc/rtl.h b/gcc/rtl.h
> index c79a277..a0c27fc 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -816,7 +816,7 @@ struct GTY(()) rtvec_def {
>  #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
>
>  /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
> -#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
> +#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p
>  /* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
>  #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
>  /* Nonzero if DEBUG_INSN_P may possibly hold.  */
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index bee79d3..0ef46da 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -1514,6 +1514,10 @@ 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 (flag_tree_cselim == AUTODETECT_VALUE)
>      {
>        if (HAVE_conditional_move)
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 62a85ea..8c3bda1 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -1127,7 +1127,7 @@ 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 gimple_debug_nonbind_marker_p() may possibly hold.  */
> -#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
> +#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p
>  /* Nonzero if gimple_debug_bind_p() (and thus
>     gimple_debug_source_bind_p()) may possibly hold.  */
>  #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 1/9] [SFN] adjust RTL insn-walking API
  2017-09-30  9:09               ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
@ 2017-10-09 13:24                 ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2017-10-09 13:24 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: GCC Patches

On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> This patch removes unused RTL functions, introduces alternate ones for
> use in a later SFN patch, and regroups other related functions so that
> they appear in a more consistent order.

Ok.

Thanks,
Richard.

> for  gcc/ChangeLog
>
>         * 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.
>         * rtl.h (prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
>         (prev_nonnote_nondebug_insn_bb): Declare.
>         (next_nonnote_nondebug_insn_bb): Declare.
>         * cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
>         * cfgrtl.c (get_last_bb_insn): Likewise.
>         * lra.c (push_insns): Likewise.
> ---
>  gcc/cfgbuild.c |  2 +-
>  gcc/cfgrtl.c   |  4 ++--
>  gcc/emit-rtl.c | 69 ++++++++++++++++++++++++++++++++--------------------------
>  gcc/lra.c      |  2 +-
>  gcc/rtl.h      |  4 ++--
>  5 files changed, 44 insertions(+), 37 deletions(-)
>
> diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
> index 62956b2..76c21d7 100644
> --- a/gcc/cfgbuild.c
> +++ b/gcc/cfgbuild.c
> @@ -512,7 +512,7 @@ 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))
> diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
> index 6ef47b7..bce56b4 100644
> --- a/gcc/cfgrtl.c
> +++ b/gcc/cfgrtl.c
> @@ -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;
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index e790cbc..68c1f11 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -3355,20 +3355,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;
> @@ -3390,67 +3387,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;
>      }
> @@ -3458,17 +3458,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/lra.c b/gcc/lra.c
> index a473777..9037495 100644
> --- a/gcc/lra.c
> +++ b/gcc/lra.c
> @@ -1810,7 +1810,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/rtl.h b/gcc/rtl.h
> index a63f33e..3bda77c 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -2980,13 +2980,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 *);
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-10-09 13:11                 ` Richard Biener
@ 2017-10-13  7:25                   ` Alexandre Oliva
  2017-10-13  9:41                     ` Richard Biener
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-10-13  7:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: jason, nathan, GCC Patches

On Oct  9, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> The middle-end changes are ok.   The C FE change looks reasonable,
> I'd appreciate a 2nd look at the C++ FE changes by a maintainer.

https://gcc.gnu.org/ml/gcc-patches/2017-09/msg02026.html


Thanks a lot for the reviews!

I've held off installing the approved patches and parts of this patch
for the time being, awaiting the second look you requested (copying the
C++ maintainers to get their attention), and also reviews for the
subsequent patches (2 LVU and 2 IEPM).  Please let me know if you'd
prefer me to go ahead and install the approved bits.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-10-13  7:25                   ` Alexandre Oliva
@ 2017-10-13  9:41                     ` Richard Biener
  2017-10-17 22:06                       ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Richard Biener @ 2017-10-13  9:41 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jason Merrill, nathan, GCC Patches

On Fri, Oct 13, 2017 at 9:21 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Oct  9, 2017, Richard Biener <richard.guenther@gmail.com> wrote:
>
>> The middle-end changes are ok.   The C FE change looks reasonable,
>> I'd appreciate a 2nd look at the C++ FE changes by a maintainer.
>
> https://gcc.gnu.org/ml/gcc-patches/2017-09/msg02026.html
>
>
> Thanks a lot for the reviews!
>
> I've held off installing the approved patches and parts of this patch
> for the time being, awaiting the second look you requested (copying the
> C++ maintainers to get their attention), and also reviews for the
> subsequent patches (2 LVU and 2 IEPM).  Please let me know if you'd
> prefer me to go ahead and install the approved bits.

If the [SFN] is self-contained you can install that part once the approval
for the FE parts is in.  You can of course wait a bit for more reviews
(stopped short on LVU because of that all-targets touching patch ... ;))

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-10-13  9:41                     ` Richard Biener
@ 2017-10-17 22:06                       ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-10-17 22:06 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, nathan, GCC Patches

On Oct 13, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> If the [SFN] is self-contained you can install that part once the approval
> for the FE parts is in.

It is, so I'll do that.

> You can of course wait a bit for more reviews
> (stopped short on LVU because of that all-targets touching patch ... ;))

:-)

I could minimize the amount of visible changes in target code by using
'&' rather than '*' to make the parameter changeable.  This enables
final_start_function to consume the initial debug insns, so that
e.g. parm bindings are integrated in the initial view.

The per-target changes could also be avoided entirely, by having both
final_start_function and final skip initial debug insns, but I think
that is wasteful, cpu-wise, and error prone in the long term,
maintenance-wise.

Just throwing some options out, in case touching the code of so many
targets turns out to be a blocker...

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-09-30  9:09               ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
@ 2017-10-19 11:07                 ` Richard Biener
  2017-10-31  5:10                   ` Jeff Law
  2017-10-31  5:23                 ` Jeff Law
  1 sibling, 1 reply; 156+ messages in thread
From: Richard Biener @ 2017-10-19 11:07 UTC (permalink / raw)
  To: Alexandre Oliva, Jeff Law; +Cc: GCC Patches

On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> This API change will enable final_start_function() to "consume"
> initial insns, and choose the first insn to be passed to final().
>
> Many ports call final_start_function() and final() when creating
> thunks and whatnot, so they needed adjusting.

But for MI thunks (and whatnot) there's no debug info.  So why do we care?
Most of them ask for sth very low-level.

That is, almost all the time the sequence is final_start_function immediately
followed by a call to final.  So isn't better refactoring the answer here?
Some ports only call final_start_function and never final for their thunks
for example.

That said, what do we lose when you do not adjust these things?

After all final () does more stuff than calling final_scan_insn on all
insns but you only do that for those you handle in final_start_function.

It seems to me that the current split between start/final/end is too
artificial and that the few "raw" building blocks that backends maybe
need should be factored out for them?

That said, it looks like an ugly "layering" violation you are introducing.

But of course I don't know history or details around this part of the
compiler...

That said, all ports invoking final () invoke it in the
start/final/end sequence.

spu, s390, rs6000 (and thus powerpcspe), pa, nds32, i386, cris, arm
invoke final_start_function and not final in the next 3 lines.  They all
invoke final_end_function but not final inbetween (all invokers of final
do the 3-line dance).

So, refactor final() to do all three and provide the chunks targets
really care for?

Why can't we do the param locview handling from final ()?

Probably all remanents of targets with text prologues?

Anyway, don't feel like acking in its current state because of this,
maybe somebody else can chime in.

Thanks,
Richard.

> for  gcc/ChangeLog
>
>         * output.h (final_start_function): Adjust.
>         * final.c (final_start_function): Take pointer to FIRST.
>         (rest_of_handle_final): Adjust.
>         * 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.
> ---
>  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/final.c                        | 9 ++++++---
>  gcc/output.h                       | 2 +-
>  21 files changed, 37 insertions(+), 26 deletions(-)
>
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index 23f5aff..73872dd 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c
> @@ -3961,7 +3961,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 41f3e3a..56b6f04 100644
> --- a/gcc/config/alpha/alpha.c
> +++ b/gcc/config/alpha/alpha.c
> @@ -8480,7 +8480,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 4cddf3b..9301d58 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -26410,7 +26410,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)
>      {
> @@ -26587,7 +26588,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 fe80a27..3581d2d 100644
> --- a/gcc/config/cris/cris.c
> +++ b/gcc/config/cris/cris.c
> @@ -2755,7 +2755,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 98fb1ce..d4d9490 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -12499,8 +12499,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).  */
> @@ -43001,7 +43002,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 fce3006..a94ab67 100644
> --- a/gcc/config/ia64/ia64.c
> +++ b/gcc/config/ia64/ia64.c
> @@ -11035,7 +11035,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 cd2e15e..48b9c4a 100644
> --- a/gcc/config/m68k/m68k.c
> +++ b/gcc/config/m68k/m68k.c
> @@ -5142,7 +5142,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 53ca016..4ebe023 100644
> --- a/gcc/config/microblaze/microblaze.c
> +++ b/gcc/config/microblaze/microblaze.c
> @@ -3257,7 +3257,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 4133375..d1f7bd8 100644
> --- a/gcc/config/mips/mips.c
> +++ b/gcc/config/mips/mips.c
> @@ -19394,7 +19394,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 65095ff..f6d5f06 100644
> --- a/gcc/config/nds32/nds32.c
> +++ b/gcc/config/nds32/nds32.c
> @@ -1633,7 +1633,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 2602605..6ab2c24 100644
> --- a/gcc/config/nios2/nios2.c
> +++ b/gcc/config/nios2/nios2.c
> @@ -4061,7 +4061,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 5e945fc..418a017 100644
> --- a/gcc/config/pa/pa.c
> +++ b/gcc/config/pa/pa.c
> @@ -8404,7 +8404,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 1e794a0..cf1a7bf 100644
> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -29699,7 +29699,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 ();
>
> @@ -38165,7 +38165,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 52a82df..0bea709 100644
> --- a/gcc/config/s390/s390.c
> +++ b/gcc/config/s390/s390.c
> @@ -13202,7 +13202,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 3c6d525..284fb81 100644
> --- a/gcc/config/sh/sh.c
> +++ b/gcc/config/sh/sh.c
> @@ -10936,7 +10936,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 d3f002d..9432a66 100644
> --- a/gcc/config/sparc/sparc.c
> +++ b/gcc/config/sparc/sparc.c
> @@ -12140,7 +12140,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 b9af9a9..d22cf3e 100644
> --- a/gcc/config/spu/spu.c
> +++ b/gcc/config/spu/spu.c
> @@ -7045,7 +7045,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 63fe340..861577eca 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 ee9bc0a..e261400 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/final.c b/gcc/final.c
> index 49cfbfb..d2b8523d 100644
> --- a/gcc/final.c
> +++ b/gcc/final.c
> @@ -1763,9 +1763,11 @@ get_some_local_dynamic_name ()
>       test and compare insns.  */
>
>  void
> -final_start_function (rtx_insn *first, FILE *file,
> +final_start_function (rtx_insn **firstp, FILE *file,
>                       int optimize_p ATTRIBUTE_UNUSED)
>  {
> +  rtx_insn *first = *firstp;
> +
>    block_depth = 0;
>
>    this_is_asm_operands = 0;
> @@ -4536,8 +4538,9 @@ rest_of_handle_final (void)
>      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 ();
> +  final_start_function (&first, asm_out_file, optimize);
> +  final (first, asm_out_file, optimize);
>    if (flag_ipa_ra
>        && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
>      collect_fn_hard_reg_usage ();
> diff --git a/gcc/output.h b/gcc/output.h
> index e98a911..62a405d 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'
> --
> 2.9.5
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-09-30  9:09               ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
  2017-10-09 13:11                 ` Richard Biener
@ 2017-10-24 18:11                 ` Jason Merrill
  2017-11-01 19:14                   ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Jason Merrill @ 2017-10-24 18:11 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Richard Biener, GCC Patches

On Sat, Sep 30, 2017 at 5:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index a89ee49..f9209ac 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
>        tree_stmt_iterator i;
>        for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>         {
> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
> +           /* ??? Can we retain this information somehow?  */

There's no need; the result of this function isn't used for codegen
any more, just checking.

Why do you need a special case for this?  The existing code should
have the same effect.

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

Likewise.

> @@ -3783,6 +3791,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
>    for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>      {
>        tree stmt = tsi_stmt (i);
> +      if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
> +       continue;

Maybe instead of handling this here, add it to the sequence of codes
that are returned unchanged in cxx_eval_constant_expression, after
PREDICT_EXPR?

Jason

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-10-19 11:07                 ` Richard Biener
@ 2017-10-31  5:10                   ` Jeff Law
  0 siblings, 0 replies; 156+ messages in thread
From: Jeff Law @ 2017-10-31  5:10 UTC (permalink / raw)
  To: Richard Biener, Alexandre Oliva; +Cc: GCC Patches

On 10/19/2017 05:01 AM, Richard Biener wrote:
> On Sat, Sep 30, 2017 at 11:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
>> This API change will enable final_start_function() to "consume"
>> initial insns, and choose the first insn to be passed to final().
>>
>> Many ports call final_start_function() and final() when creating
>> thunks and whatnot, so they needed adjusting.
> 
> But for MI thunks (and whatnot) there's no debug info.  So why do we care?
> Most of them ask for sth very low-level.
True.

> 
> That is, almost all the time the sequence is final_start_function immediately
> followed by a call to final.  So isn't better refactoring the answer here?
> Some ports only call final_start_function and never final for their thunks
> for example.
> 
> That said, what do we lose when you do not adjust these things?
Good question.  And more generally when do we want to be able to do
something sensible of this kind of glue code and what *is* sensible to
do here?


> 
> After all final () does more stuff than calling final_scan_insn on all
> insns but you only do that for those you handle in final_start_function.
> 
> It seems to me that the current split between start/final/end is too
> artificial and that the few "raw" building blocks that backends maybe
> need should be factored out for them?
Perhaps.  I think we'd need to see this fleshed out a bit more.

> 
> That said, it looks like an ugly "layering" violation you are introducing.
> 
> But of course I don't know history or details around this part of the
> compiler...
> 
> That said, all ports invoking final () invoke it in the
> start/final/end sequence.
> 
> spu, s390, rs6000 (and thus powerpcspe), pa, nds32, i386, cris, arm
> invoke final_start_function and not final in the next 3 lines.  They all
> invoke final_end_function but not final inbetween (all invokers of final
> do the 3-line dance).
For the PA, thunks are emitted as pure assembly without generating RTL
for the thunk.  There is no RTL to pass to final (or if there is RTL
lying around, it's probably not the thunk).

There's a few things in the thunk that I don't think we can represent in
RTL, though obviously a few UNSPECs could do the trick.

One question in my mind is whether or not we can reasonably expect Alex
to do that work, then the analysis on the other ports and fix them as well.


Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-09-30  9:09               ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
  2017-10-19 11:07                 ` Richard Biener
@ 2017-10-31  5:23                 ` Jeff Law
  2017-11-01 18:20                   ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-10-31  5:23 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener; +Cc: GCC Patches

On 09/30/2017 03:08 AM, Alexandre Oliva wrote:
> This API change will enable final_start_function() to "consume"
> initial insns, and choose the first insn to be passed to final().
> 
> Many ports call final_start_function() and final() when creating
> thunks and whatnot, so they needed adjusting.
So I haven't really followed the discussion until now.  What's driving
the need to have some insns "consumed" and have more control over what
tthe first insn passed to final will be?

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers
  2017-09-30  9:10               ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
@ 2017-10-31  5:58                 ` Jeff Law
  0 siblings, 0 replies; 156+ messages in thread
From: Jeff Law @ 2017-10-31  5:58 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener; +Cc: GCC Patches

On 09/30/2017 03:08 AM, Alexandre Oliva wrote:
> The inline_entry hook will be given a definition in a later patch.
> 
> for  gcc/ChangeLog
> 
> 	* 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.
> 	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
> 	(dwarf2_lineno_debug_hooks): Likewise.
Seems reasonable once prereqs and when #9/9 is approved.  WIth the
removal of SDB trivial adjustment will be needed and is pre-approved.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 9/9] [IEPM] Introduce inline entry point markers
  2017-09-30  9:10               ` [PATCH 9/9] [IEPM] Introduce " Alexandre Oliva
@ 2017-10-31  6:22                 ` Jeff Law
  2017-11-01 18:36                   ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-10-31  6:22 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener; +Cc: GCC Patches

On 09/30/2017 03:08 AM, Alexandre Oliva wrote:
> Output DW_AT_entry_pc based on markers.
> 
> Introduce DW_AT_GNU_entry_view as a DWARF extension.
> 
> If views are enabled are we're not in strict compliance mode, output
> DW_AT_GNU_entry_view if it might be nonzero.
> 
> This patch depends on SFN and LVU patchsets, and on the IEPM patch that
> introduces the inline_entry debug hook.
> 
> for  include/ChangeLog
> 
> 	* dwarf2.def (DW_AT_GNU_entry_view): New.
> 
> for  gcc/ChangeLog
> 
> 	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
> 	markers.
> 	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
> 	(BLOCK_INLINE_ENTRY_LABEL): New.
> 	(dwarf2out_var_location): Disregard inline entry markers.
> 	(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.
> 	(block_within_block_p, dwarf2out_inline_entry): New.
> 	(dwarf2out_finish): Check that no entries remained in
> 	inline_entry_data_table.
> 	* final.c (reemit_insn_block_notes): Handle inline entry notes.
> 	(final_scan_insn, notice_source_line): Likewise.
> 	(rest_of_clean_state): Skip inline entry markers.
> 	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
> 	markers.
> 	* gimple.c (gimple_build_debug_inline_entry): New.
> 	* gimple.h (enum gimple_debug_subcode): Add
> 	GIMPLE_DEBUG_INLINE_ENTRY.
> 	(gimple_build_debug_inline_entry): Declare.
> 	(gimple_debug_inline_entry_p): New.
> 	(gimple_debug_nonbind_marker_p): Adjust.
> 	* insn-notes.def (INLINE_ENTRY): New.
> 	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
> 	inline entry marker notes.
> 	(print_insn): Likewise.
> 	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
> 	(INSN_DEBUG_MARKER_KIND): Likewise.
> 	* tree-inline.c	(expand_call_inline): Build and insert
> 	debug_inline_entry stmt.
> 	* 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.
> 	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
> 	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
> 	(gimple_build_debug_inline_entry): New.
> 	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
> 	Enable/disable inline entry points too.
> 	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
> 	(DEBUG_INSN): Describe inline entry markers.
> ---
> 
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index c854ffd..8ccdafd 100644
> --- a/gcc/cfgexpand.c
> +++ b/gcc/cfgexpand.c
> @@ -5691,6 +5691,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>  		goto delink_debug_stmt;
>  	      else if (gimple_debug_begin_stmt_p (stmt))
>  		val = gen_rtx_DEBUG_MARKER (VOIDmode);
> +	      else if (gimple_debug_inline_entry_p (stmt))
> +		{
> +		  tree block = gimple_block (stmt);
> +
> +		  if (block)
> +		    val = gen_rtx_DEBUG_MARKER (BLKmode);
> +		  else
> +		    goto delink_debug_stmt;
> +		}
>  	      else
>  		gcc_unreachable ();
So again, I haven't looked at prior patches.  It seems to me like we're
abusing the mode of the debug marker rtx here.  Is that really the best
way to do things?  Would it be better to have different RTXs for the
marker or real arguments?  Or what about keying on the existence of
INSN_LOCATION?!?  Something just feels a bit icky here.



> +/* 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.  */
So this seemed reasonable up to here.  Based on the name and function
comment, I'd think at this point you'd be able to return true.  We found
OUTER in BLOCK's supercontext chain.

But you've got another blob of code.  So it seems like you're check more
than what the name/function comment imply.

Otherwise this patch seems pretty reasonable.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-10-31  5:23                 ` Jeff Law
@ 2017-11-01 18:20                   ` Alexandre Oliva
  2017-11-02 13:00                     ` Richard Biener
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-01 18:20 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, GCC Patches

On Oct 31, 2017, Jeff Law <law@redhat.com> wrote:

> On 09/30/2017 03:08 AM, Alexandre Oliva wrote:
>> This API change will enable final_start_function() to "consume"
>> initial insns, and choose the first insn to be passed to final().
>> 
>> Many ports call final_start_function() and final() when creating
>> thunks and whatnot, so they needed adjusting.
> So I haven't really followed the discussion until now.  What's driving
> the need to have some insns "consumed" and have more control over what
> tthe first insn passed to final will be?

We want to build debug notes that bind arguments into the initial view
in a function.  That initial view (first .loc note) is emitted in
final_start_function.  So we don't want to process the initial debug
bind insns in final_start_function, and not process them again in final.

In response to richi's objections, I reverted the API exposed by final.c
so that we process the loc notes in final_start_function, and just skip
them in final, so that no changes are required to the various backends,
at a very slight performance penalty as the leading debug insns will be
looked at twice instead of just once, when final is so used by the
backends.

As for uses within final.c, those benefit from an API change internal to
that file, that allows the leading debug insns to be processed just
once.  Here are the relevant snippets from the updated patchset (yet to
be posted):


+/* We want to emit param bindings (before the first begin_stmt) in the
+   initial view, if we are emitting views.  To that end, we may
+   consume initial notes in the function, processing them in
+   final_start_function, before signaling the beginning of the
+   prologue, rather than in final.
+
+   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.  */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+  return !DECL_IGNORED_P (current_function_decl)
+    && debug_variable_location_views
+    && insn && GET_CODE (insn) == NOTE
+    && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
+}
+
 /* 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
@@ -1757,12 +1819,15 @@ 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)
 {
   block_depth = 0;
 
@@ -1780,8 +1845,21 @@ final_start_function (rtx_insn *first, FILE *file,
   if (flag_sanitize & SANITIZE_ADDRESS)
     asan_function_start ();
 
+  rtx_insn *first = *firstp;
+  if (in_initial_view_p (first))
+    {
+      do
+	{
+	  final_scan_insn (first, file, 0, 0, seen);
+	  first = NEXT_INSN (first);
+	}
+      while (in_initial_view_p (first));
+      *firstp = first;
+    }
+
   if (!DECL_IGNORED_P (current_function_decl))
@@ -1856,6 +1934,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 *first, FILE *file,
+		      int optimize_p ATTRIBUTE_UNUSED)
+{
+  int seen = 0;
+  final_start_function_1 (&first, file, &seen, optimize_p);
+  gcc_assert (seen == 0);
+}
+
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1987,11 +2076,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;
@@ -2074,6 +2164,23 @@ 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)
+{
+  /* Those that use the internal final_start_function_1/final_1 API
+     skip initial debug bind notes in final_start_function_1, and pass
+     the modified FIRST to final_1.  But those that use the public
+     final_start_function/final APIs, final_start_function can't move
+     FIRST because it's not passed by reference, so if they were
+     skipped there, skip them again here.  */
+  while (in_initial_view_p (first))
+    first = NEXT_INSN (first);
+
+  final_1 (first, file, 0, optimize_p);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)


@@ -4525,8 +4650,10 @@ rest_of_handle_final (void)
     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 ();

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 9/9] [IEPM] Introduce inline entry point markers
  2017-10-31  6:22                 ` Jeff Law
@ 2017-11-01 18:36                   ` Alexandre Oliva
  2017-11-09 16:30                     ` Jeff Law
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-01 18:36 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, GCC Patches

On Oct 31, 2017, Jeff Law <law@redhat.com> wrote:

>> @@ -5691,6 +5691,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>> goto delink_debug_stmt;
>> else if (gimple_debug_begin_stmt_p (stmt))
>> val = gen_rtx_DEBUG_MARKER (VOIDmode);
>> +	      else if (gimple_debug_inline_entry_p (stmt))
>> +		{
>> +		  tree block = gimple_block (stmt);
>> +
>> +		  if (block)
>> +		    val = gen_rtx_DEBUG_MARKER (BLKmode);
>> +		  else
>> +		    goto delink_debug_stmt;
>> +		}
>> else
>> gcc_unreachable ();
> So again, I haven't looked at prior patches.  It seems to me like we're
> abusing the mode of the debug marker rtx here.

It is still abuse if it's documented in INSN_DEBUG_MARKER_KIND and
rtl.texi?  :-)

We need some way to tell the (currently) two kinds of markers apart.  I
didn't want yet another rtl code that would have to be added to cases
all over; the distinction between markers matters at only very few
points in the compiler.  I considered adding an operand to the debug
marker, to reference a const_int that could tell them apart with room
for growth to other kinds of markers, or using any of the flag bits, but
the mode was the most visibly unused mandatory rtl field in debug
markers, so I went for it.

Changing that would make for a very localized patch, touching only this
creation point, the macro that tells the kinds apart, and the
documentation, so if you'd rather have something else, I'll be glad to
comply.



>> +/* 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.  */
> So this seemed reasonable up to here.  Based on the name and function
> comment, I'd think at this point you'd be able to return true.  We found
> OUTER in BLOCK's supercontext chain.

The part you quoted looks at only at child-to-parent links; the other
part looks at parent-to-children links, to make sure they match.  The
function is a consistency check, used only in a checking assert.  It's
intended to check both links, that the parent is reachable by the child,
and that the child is reachable by the parent.  At some point, I had
blocks that had been disconnected and discarded from the lexical block
tree, but that remained pointed-to by markers; they still pointed to
their parents, but their parents no longer pointed to them.

> But you've got another blob of code.  So it seems like you're check more
> than what the name/function comment imply.

I guess I should expand the comments ;-)

Will do...

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-10-24 18:11                 ` Jason Merrill
@ 2017-11-01 19:14                   ` Alexandre Oliva
  2017-11-01 19:49                     ` Jason Merrill
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-01 19:14 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, GCC Patches

Hi, Jason,

Apologies for the delay in responding; somehow I missed your reply when
it arrived (probably because I had a cold back then :-), and only saw it
today.

On Oct 24, 2017, Jason Merrill <jason@redhat.com> wrote:

> On Sat, Sep 30, 2017 at 5:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
>> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
>> index a89ee49..f9209ac 100644
>> --- a/gcc/cp/constexpr.c
>> +++ b/gcc/cp/constexpr.c
>> @@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
>> tree_stmt_iterator i;
>> for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>> {
>> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
>> +           /* ??? Can we retain this information somehow?  */

> There's no need; the result of this function isn't used for codegen
> any more, just checking.

> Why do you need a special case for this?  The existing code should
> have the same effect.

More than anything, it was to add the comment about retaining the begin
stmt markers.

Something in me wishes that, in spite of resolving the entire function
call to a constant expression, we could still express in debug info that
"we went through these statements", and maybe even single-step through
them towards the final result.

But if we all agree we don't want to do that, I'll be glad to drop the
???/FIXME markers to that effect.

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

> Likewise.

>> @@ -3783,6 +3791,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
>> for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>> {
>> tree stmt = tsi_stmt (i);
>> +      if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
>> +       continue;

> Maybe instead of handling this here, add it to the sequence of codes
> that are returned unchanged in cxx_eval_constant_expression, after
> PREDICT_EXPR?

That would likely work, but there's a slight risk of codegen changes
then, if a debug begin stmt happens to be present (for some reason I
can't imagine) after the statement expression whose result we're
supposed to use and return: we'd then overwrite the expression value we
should use with the debug begin stmt.  Defensively, it seemed best to
avoid that risk, even though in theory it shouldn't ever occur.

There's another case that's more material, that also involves a debug
begin stmt at the end of a statement list: that of an empty statement
list.  It's not expected that cxx_eval_statement_list returns a debug
begin stmt marker, but that's what it would do with the proposed change.
Then we'd have to handle that up the call chain.  Maybe it doesn't
matter, maybe it's no big deal, but by just skipping it there we can
just not worry about it elsewhere.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled
  2017-11-01 19:14                   ` Alexandre Oliva
@ 2017-11-01 19:49                     ` Jason Merrill
  0 siblings, 0 replies; 156+ messages in thread
From: Jason Merrill @ 2017-11-01 19:49 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Richard Biener, GCC Patches

On Wed, Nov 1, 2017 at 3:13 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> Hi, Jason,
>
> Apologies for the delay in responding; somehow I missed your reply when
> it arrived (probably because I had a cold back then :-), and only saw it
> today.
>
> On Oct 24, 2017, Jason Merrill <jason@redhat.com> wrote:
>
>> On Sat, Sep 30, 2017 at 5:08 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
>>> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
>>> index a89ee49..f9209ac 100644
>>> --- a/gcc/cp/constexpr.c
>>> +++ b/gcc/cp/constexpr.c
>>> @@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
>>> tree_stmt_iterator i;
>>> for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>>> {
>>> +         if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
>>> +           /* ??? Can we retain this information somehow?  */
>
>> There's no need; the result of this function isn't used for codegen
>> any more, just checking.
>
>> Why do you need a special case for this?  The existing code should
>> have the same effect.
>
> More than anything, it was to add the comment about retaining the begin
> stmt markers.
>
> Something in me wishes that, in spite of resolving the entire function
> call to a constant expression, we could still express in debug info that
> "we went through these statements", and maybe even single-step through
> them towards the final result.

Sure, but my point is that this function is not involved in evaluating
the call, so there would be no reason for a change here.  Most likely
you'd want something in cxx_eval_store_expression.

>>> @@ -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?  */
>
>> Likewise.

>>> @@ -3783,6 +3791,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
>>> for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
>>> {
>>> tree stmt = tsi_stmt (i);
>>> +      if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
>>> +       continue;
>
>> Maybe instead of handling this here, add it to the sequence of codes
>> that are returned unchanged in cxx_eval_constant_expression, after
>> PREDICT_EXPR?
>
> That would likely work, but there's a slight risk of codegen changes
> then, if a debug begin stmt happens to be present (for some reason I
> can't imagine) after the statement expression whose result we're
> supposed to use and return: we'd then overwrite the expression value we
> should use with the debug begin stmt.  Defensively, it seemed best to
> avoid that risk, even though in theory it shouldn't ever occur.

> There's another case that's more material, that also involves a debug
> begin stmt at the end of a statement list: that of an empty statement
> list.  It's not expected that cxx_eval_statement_list returns a debug
> begin stmt marker, but that's what it would do with the proposed change.
> Then we'd have to handle that up the call chain.  Maybe it doesn't
> matter, maybe it's no big deal, but by just skipping it there we can
> just not worry about it elsewhere.

I'm skeptical about adding defensive special cases everywhere to deal
with seemingly impossible situations.  If I'm not sure something's
actually impossible, I prefer to add an assert so things break more
loudly.

Jason

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns
  2017-11-01 18:20                   ` Alexandre Oliva
@ 2017-11-02 13:00                     ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2017-11-02 13:00 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, GCC Patches

On Wed, Nov 1, 2017 at 7:18 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Oct 31, 2017, Jeff Law <law@redhat.com> wrote:
>
>> On 09/30/2017 03:08 AM, Alexandre Oliva wrote:
>>> This API change will enable final_start_function() to "consume"
>>> initial insns, and choose the first insn to be passed to final().
>>>
>>> Many ports call final_start_function() and final() when creating
>>> thunks and whatnot, so they needed adjusting.
>> So I haven't really followed the discussion until now.  What's driving
>> the need to have some insns "consumed" and have more control over what
>> tthe first insn passed to final will be?
>
> We want to build debug notes that bind arguments into the initial view
> in a function.  That initial view (first .loc note) is emitted in
> final_start_function.  So we don't want to process the initial debug
> bind insns in final_start_function, and not process them again in final.
>
> In response to richi's objections, I reverted the API exposed by final.c
> so that we process the loc notes in final_start_function, and just skip
> them in final, so that no changes are required to the various backends,
> at a very slight performance penalty as the leading debug insns will be
> looked at twice instead of just once, when final is so used by the
> backends.

That works for me - we can still improve with some refactoring but didn't
introduce some ugliness in the way.

Richard.

> As for uses within final.c, those benefit from an API change internal to
> that file, that allows the leading debug insns to be processed just
> once.  Here are the relevant snippets from the updated patchset (yet to
> be posted):
>
>
> +/* We want to emit param bindings (before the first begin_stmt) in the
> +   initial view, if we are emitting views.  To that end, we may
> +   consume initial notes in the function, processing them in
> +   final_start_function, before signaling the beginning of the
> +   prologue, rather than in final.
> +
> +   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.  */
> +
> +static inline bool
> +in_initial_view_p (rtx_insn *insn)
> +{
> +  return !DECL_IGNORED_P (current_function_decl)
> +    && debug_variable_location_views
> +    && insn && GET_CODE (insn) == NOTE
> +    && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
> +}
> +
>  /* 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
> @@ -1757,12 +1819,15 @@ 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)
>  {
>    block_depth = 0;
>
> @@ -1780,8 +1845,21 @@ final_start_function (rtx_insn *first, FILE *file,
>    if (flag_sanitize & SANITIZE_ADDRESS)
>      asan_function_start ();
>
> +  rtx_insn *first = *firstp;
> +  if (in_initial_view_p (first))
> +    {
> +      do
> +       {
> +         final_scan_insn (first, file, 0, 0, seen);
> +         first = NEXT_INSN (first);
> +       }
> +      while (in_initial_view_p (first));
> +      *firstp = first;
> +    }
> +
>    if (!DECL_IGNORED_P (current_function_decl))
> @@ -1856,6 +1934,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 *first, FILE *file,
> +                     int optimize_p ATTRIBUTE_UNUSED)
> +{
> +  int seen = 0;
> +  final_start_function_1 (&first, file, &seen, optimize_p);
> +  gcc_assert (seen == 0);
> +}
> +
>  static void
>  profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
>  {
> @@ -1987,11 +2076,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;
> @@ -2074,6 +2164,23 @@ 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)
> +{
> +  /* Those that use the internal final_start_function_1/final_1 API
> +     skip initial debug bind notes in final_start_function_1, and pass
> +     the modified FIRST to final_1.  But those that use the public
> +     final_start_function/final APIs, final_start_function can't move
> +     FIRST because it's not passed by reference, so if they were
> +     skipped there, skip them again here.  */
> +  while (in_initial_view_p (first))
> +    first = NEXT_INSN (first);
> +
> +  final_1 (first, file, 0, optimize_p);
> +}
>
>  const char *
>  get_insn_template (int code, rtx insn)
>
>
> @@ -4525,8 +4650,10 @@ rest_of_handle_final (void)
>      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 ();
>
> --
> 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 9/9] [IEPM] Introduce inline entry point markers
  2017-11-01 18:36                   ` Alexandre Oliva
@ 2017-11-09 16:30                     ` Jeff Law
  2017-11-10  2:31                       ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-11-09 16:30 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Richard Biener, GCC Patches

On 11/01/2017 12:35 PM, Alexandre Oliva wrote:
> On Oct 31, 2017, Jeff Law <law@redhat.com> wrote:
> 
>>> @@ -5691,6 +5691,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>>> goto delink_debug_stmt;
>>> else if (gimple_debug_begin_stmt_p (stmt))
>>> val = gen_rtx_DEBUG_MARKER (VOIDmode);
>>> +	      else if (gimple_debug_inline_entry_p (stmt))
>>> +		{
>>> +		  tree block = gimple_block (stmt);
>>> +
>>> +		  if (block)
>>> +		    val = gen_rtx_DEBUG_MARKER (BLKmode);
>>> +		  else
>>> +		    goto delink_debug_stmt;
>>> +		}
>>> else
>>> gcc_unreachable ();
>> So again, I haven't looked at prior patches.  It seems to me like we're
>> abusing the mode of the debug marker rtx here.
> 
> It is still abuse if it's documented in INSN_DEBUG_MARKER_KIND and
> rtl.texi?  :-)
It's just documented abuse, but it's still abuse.  Though there's
certainly other cases where we've used modes to carry odd information
(reload was notorious for that, which I think we fixed a little while
back with some of David M's work).





> 
> We need some way to tell the (currently) two kinds of markers apart. 
I figured out that much.

> I
> didn't want yet another rtl code that would have to be added to cases
> all over; the distinction between markers matters at only very few
> points in the compiler.  
Is it fair to say one is just a variant of the other?


I considered adding an operand to the debug
> marker, to reference a const_int that could tell them apart with room
> for growth to other kinds of markers, or using any of the flag bits, but
> the mode was the most visibly unused mandatory rtl field in debug
> markers, so I went for it.
Is there a bit we could use in the rtx flags?  Yes, it's harder to prove
correct, but I would be a bit surprised if there wasn't a free one for
the debug rtxs.

>
> 
> Changing that would make for a very localized patch, touching only this
> creation point, the macro that tells the kinds apart, and the
> documentation, so if you'd rather have something else, I'll be glad to
> comply.
Alternately, let's at least abstract things via a macro or getter/setter
type function so that we can change the implementation in the future
without having to do searches on mode twiddling.


> 
> 
> 
>>> +/* 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.  */
>> So this seemed reasonable up to here.  Based on the name and function
>> comment, I'd think at this point you'd be able to return true.  We found
>> OUTER in BLOCK's supercontext chain.
> 
> The part you quoted looks at only at child-to-parent links; the other
> part looks at parent-to-children links, to make sure they match.  The
> function is a consistency check, used only in a checking assert.  It's
> intended to check both links, that the parent is reachable by the child,
> and that the child is reachable by the parent.  At some point, I had
> blocks that had been disconnected and discarded from the lexical block
> tree, but that remained pointed-to by markers; they still pointed to
> their parents, but their parents no longer pointed to them.
Ah, if it's just a consistency check then it makes perfect sense.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [PATCH 9/9] [IEPM] Introduce inline entry point markers
  2017-11-09 16:30                     ` Jeff Law
@ 2017-11-10  2:31                       ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:31 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, GCC Patches

On Nov  9, 2017, Jeff Law <law@redhat.com> wrote:

>> I didn't want yet another rtl code that would have to be added to
>> cases all over; the distinction between markers matters at only very
>> few points in the compiler.

> Is it fair to say one is just a variant of the other?

I don't see them that way, but the fact that there's a name that applies
to a whole class of potential debug markers, two of which are
implemented in this patchset, could imply they are.  They're variants of
debug markers, and as such optimization passes should generally leave
them alone.  They are all supposed to carry information about relevant
points in the source program throughout compilation, but they differ in
what the points are.

They currently don't carry any information besides their lexical block
and source location information, which makes a single RTL code enough,
but this could change: stmt markers could link back to a representation
of the source statement, if we had one; inline entry point markers could
link back to the original call that was inlined; end-of-prologue markers
might require other kinds of data I can't think of; return value
assignment points and actual return points also come to mind.  These are
the markers I've thought of so far; many of them are no more than ideas
yet to be implemented.

> Is there a bit we could use in the rtx flags?

As long as we have only two kinds of markers, yes.  Even more than that,
probably.

Now, I've just looked at the actual data, and my concern that having
separate RTL codes would require them to appear in tons of locations is
unfounded.  The only occurrence of DEBUG_MARKER, aside from that in
macros defined in rtl.h, is in extract_insn.c.

OTOH, having multiple RTL codes to check for in e.g. DEBUG_MARKER_INSN_P
(or DEBUG_BIND_INSN_P) could have a larger impact on the compiler
performance than I would like; these macros are used very often, and
currently they have to test three RTL codes: DEBUG_INSN, and then either
VAR_LOCATION or DEBUG_MARKER.  As long as one of the classes has only
one RTL code, we can test by negating the other (like
DEBUG_MARKER_INSN_P currently tests that the pattern is *not*
VAR_LOCATION), but if both classes were to have more than one RTL code,
the tests would become more expensive.  So I strive to reduce the number
of codes tested for in such pervasive tests, and, should that become
unavoidable, to keep them in sequence, so that the compiler can optimize
a sequence of tests to a range test, or maybe use distinct RTX_CLASSes
for them.

>> Changing that would make for a very localized patch, touching only this
>> creation point, the macro that tells the kinds apart, and the
>> documentation, so if you'd rather have something else, I'll be glad to
>> comply.
> Alternately, let's at least abstract things via a macro or getter/setter
> type function so that we can change the implementation in the future
> without having to do searches on mode twiddling.

Done in a patch I'm about to push to the branch.  (I was just about to
post the updated patchset when I got your email; now it will be a bit
later ;-)

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (3 preceding siblings ...)
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-11-10  2:36                 ` Alexandre Oliva
  2017-12-07 22:44                   ` Jeff Law
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
                                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

This patch adjusts numerous parts of the compiler that would
malfunction should they find debug markers at points where they may be
introduced.  The changes purport to allow the compiler to pass
bootstrap-debug-lean (-fcompare-debug in stage3) at various
optimization levels, as well as bootstrap-debug-lib (-fcompare-debug
for target libraries), even after the compiler is changed so that
debug markers are introduced in code streams at spots where earlier
debug stmts, insns and notes wouldn't normally appear.

This patch depends on an earlier SFN boilerplate patch, and on another
SFN patch that introduces new RTL insn-walking functions.

for  gcc/ChangeLog

	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
	* cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
	(rtl_tidy_fallthru_edge): Likewise.
	(rtl_verify_fallthru): Likewise.
	(rtl_verify_bb_layout): Likewise.
	(skip_insns_after_block): Likewise.
	(duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
	* dwarf2out.c: Include print-rtl.h.
	(dwarf2out_next_real_insn): New.
	(dwarf2out_var_location): Call it.  Disregard begin stmt markers.
	Dump debug binds in asm comments.
	* gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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 (gimple_seq_may_fallthru): Take last nondebug stmt.
	* gimple.h (gimple_seq_last_nondebug_stmt): New.
	* gimplify.c (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.
	* graphite-isl-ast-to-gimple.c (gsi_insert_earliest): Adjust.
	(graphite_copy_stmts_from_block): Skip nonbind markers.
	* haifa-sched.c (sched_extend_bb): Skip debug insns.
	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
	* jump.c (clean_barriers): Skip debug insns.
	* 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.
	* postreload.c (fixup_debug_insns): Skip nonbind debug insns.
	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
	* sese.c (sese_trivially_empty_bb_p): Call is_gimple_debug in
	test.
	* 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
	* var-tracking.c (get_first_insn): New.
	(vt_emit_notes): Call it.
	(vt_initialize): Walk any insns before the first BB.
	(delete_debug_insns): Likewise.
---
 gcc/cfgbuild.c                   |   1 +
 gcc/cfgcleanup.c                 |  12 +--
 gcc/cfgexpand.c                  |  24 +++++-
 gcc/cfgrtl.c                     |  18 +++--
 gcc/dwarf2out.c                  |  38 ++++++++-
 gcc/gimple-iterator.c            |  24 +++++-
 gcc/gimple-iterator.h            |  46 ++++++-----
 gcc/gimple-low.c                 |   2 +-
 gcc/gimple.h                     |  16 ++++
 gcc/gimplify.c                   |  23 +++---
 gcc/graphite-isl-ast-to-gimple.c |   7 +-
 gcc/haifa-sched.c                |   2 +-
 gcc/ipa-icf-gimple.c             |   4 +-
 gcc/jump.c                       |   2 +-
 gcc/omp-expand.c                 | 161 ++++++++++++++++++++-------------------
 gcc/omp-low.c                    |   2 +
 gcc/postreload.c                 |   2 +-
 gcc/regcprop.c                   |   2 +
 gcc/sese.c                       |   2 +-
 gcc/tree-cfg.c                   |  52 +++++++++++--
 gcc/tree-cfgcleanup.c            |  31 +++-----
 gcc/tree-pretty-print.c          |   5 +-
 gcc/tree-ssa-dce.c               |   6 +-
 gcc/tree-ssa-tail-merge.c        |   4 +-
 gcc/var-tracking.c               |  54 ++++++++++++-
 25 files changed, 366 insertions(+), 174 deletions(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 77a221de2119..8fa15fec45e4 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -475,6 +475,7 @@ find_bb_boundaries (basic_block bb)
 	  if (debug_insn && code != CODE_LABEL && code != BARRIER)
 	    prev = PREV_INSN (debug_insn);
 	  fallthru = split_block (bb, prev);
+
 	  if (flow_transfer_insn)
 	    {
 	      BB_END (bb) = flow_transfer_insn;
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 4734d3eae17e..754e52fe799a 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -3037,13 +3037,13 @@ delete_unreachable_blocks (void)
 
   find_unreachable_blocks ();
 
-  /* When we're in GIMPLE mode and there may be debug insns, we should
-     delete blocks in reverse dominator order, so as to get a chance
-     to substitute all released DEFs into debug stmts.  If we don't
-     have dominators information, walking blocks backward gets us a
-     better chance of retaining most debug information than
+  /* When we're in GIMPLE mode and there may be debug bind insns, we
+     should delete blocks in reverse dominator order, so as to get a
+     chance to substitute all released DEFs into debug bind stmts.  If
+     we don't have dominators information, walking blocks backward
+     gets us a better chance of retaining most debug information than
      otherwise.  */
-  if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE
+  if (MAY_HAVE_DEBUG_BIND_INSNS && current_ir_type () == IR_GIMPLE
       && dom_info_available_p (CDI_DOMINATORS))
     {
       for (b = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 22a9eb45b45e..6f64897d0688 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2327,6 +2327,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;
@@ -5456,7 +5459,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;
@@ -5497,18 +5500,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)
@@ -5523,6 +5534,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);
@@ -5530,7 +5542,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))
     {
@@ -5538,6 +5551,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
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index f788334ffb57..0968e68ba7ec 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
@@ -1746,7 +1746,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.
@@ -2901,7 +2901,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);
@@ -2923,7 +2923,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;
@@ -2950,6 +2950,7 @@ rtl_verify_bb_layout (void)
 	    {
 	    case BARRIER:
 	    case NOTE:
+	    case DEBUG_INSN:
 	      break;
 
 	    case CODE_LABEL:
@@ -2968,7 +2969,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))
@@ -3385,6 +3387,9 @@ skip_insns_after_block (basic_block bb)
 	  last_insn = insn;
 	  continue;
 
+	case DEBUG_INSN:
+	  continue;
+
 	case NOTE:
 	  switch (NOTE_KIND (insn))
 	    {
@@ -4137,7 +4142,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 (DEBUG_BIND_INSN_P (insn)
+	      && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
 	    break;
 	  /* FALLTHRU */
 	case INSN:
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index b8f4e4888f1b..4f808b95519c 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"
@@ -26189,6 +26190,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.  */
@@ -26237,7 +26254,7 @@ 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;
@@ -26267,11 +26284,12 @@ 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_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)
     {
@@ -26430,6 +26448,22 @@ create_label:
       newloc->label = last_postcall_label;
     }
 
+  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;
 }
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 3b74cc540f66..fb75f993e9a1 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -744,9 +744,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 +780,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 70f18beceffc..167edc18db5b 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 4ea6c3532f3f..22db61bbd48a 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -645,7 +645,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.h b/gcc/gimple.h
index f8b0a9dee4af..103d9555e465 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -4602,6 +4602,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
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index e9168785fc01..d252af04bcbf 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1857,7 +1857,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)
@@ -1870,27 +1870,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;
     }
@@ -1994,7 +1997,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);
     }
@@ -2031,7 +2034,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;
     }
@@ -2044,7 +2047,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)
@@ -2091,7 +2094,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))
@@ -2234,8 +2237,8 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
 		}
 	      else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
 		;
-	      else
-		/* Something other is not expected.  */
+	      else if (!is_gimple_debug (stmt))
+		/* Anything else is not expected.  */
 		break;
 	      gsi_next (&gsi2);
 	    }
diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
index 16570e168557..b0409930104b 100644
--- a/gcc/graphite-isl-ast-to-gimple.c
+++ b/gcc/graphite-isl-ast-to-gimple.c
@@ -1007,7 +1007,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;
@@ -1039,7 +1039,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);
 	}
@@ -1146,7 +1146,8 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_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))
 	    ;
 	  else
 	    gcc_unreachable ();
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index b7c0b3a6f4ff..cf44422d8219 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -8086,7 +8086,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/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index b40dd8653b4d..be8c70912698 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -640,8 +640,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/jump.c b/gcc/jump.c
index fc4b4345444a..e60a6c6f8e66 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/omp-expand.c b/gcc/omp-expand.c
index 07856424f65a..7d3cbbe6dc2e 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -695,7 +695,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;
@@ -748,7 +748,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;
@@ -874,7 +874,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;
@@ -951,15 +951,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);
@@ -1186,7 +1186,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);
@@ -1299,7 +1299,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));
@@ -1315,7 +1315,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);
@@ -1324,7 +1324,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)));
@@ -1787,7 +1787,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))
@@ -2592,7 +2592,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
@@ -2622,7 +2622,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));
@@ -2643,7 +2643,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));
@@ -3061,7 +3061,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);
@@ -3127,7 +3127,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)))
@@ -3347,7 +3347,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)
@@ -3479,7 +3479,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)),
@@ -3489,7 +3489,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);
@@ -3631,7 +3631,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);
@@ -3664,7 +3664,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));
@@ -3831,7 +3831,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)
@@ -4137,7 +4137,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);
@@ -4181,7 +4181,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));
@@ -4392,7 +4392,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.
@@ -4437,7 +4437,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,
@@ -4467,7 +4467,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.  */
@@ -4641,7 +4641,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.  */
@@ -4736,7 +4736,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);
 
@@ -4834,7 +4834,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.  */
@@ -4960,7 +4960,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)
@@ -5061,10 +5061,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 ();
@@ -5138,7 +5138,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)
@@ -5217,7 +5217,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);
@@ -5254,7 +5254,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 ();
@@ -5437,7 +5437,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);
 
@@ -5564,7 +5564,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);
@@ -5688,7 +5688,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);
 
@@ -5777,7 +5777,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));
 
@@ -6004,7 +6004,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)
@@ -6012,7 +6012,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)
 	      {
@@ -6037,7 +6037,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);
@@ -6061,7 +6061,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)
     {
@@ -6103,7 +6103,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);
@@ -6112,7 +6112,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);
 
@@ -6138,7 +6138,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);
@@ -6151,7 +6151,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)))
@@ -6179,12 +6179,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));
@@ -6207,7 +6207,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
@@ -6219,7 +6219,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;
@@ -6240,7 +6240,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);
@@ -6270,7 +6270,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);
 
@@ -6296,14 +6296,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);
@@ -6348,7 +6348,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))
@@ -6395,10 +6395,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));
@@ -6462,7 +6469,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.
@@ -6485,10 +6492,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);
 
@@ -6541,7 +6548,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
@@ -6621,7 +6628,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)
@@ -6724,7 +6731,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);
@@ -6735,7 +6742,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)),
@@ -7234,7 +7241,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));
@@ -7246,7 +7253,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);
@@ -7428,7 +7435,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));
 	}
@@ -7463,11 +7470,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);
     }
@@ -7611,7 +7618,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);
@@ -7692,17 +7699,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)
@@ -7846,11 +7853,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);
@@ -8034,7 +8041,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 33e633cd627b..528516b7d010 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -7033,6 +7033,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/postreload.c b/gcc/postreload.c
index 000ed341b034..8e4a81903f5e 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -836,7 +836,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to)
     {
       rtx t;
 
-      if (!DEBUG_INSN_P (insn))
+      if (!DEBUG_BIND_INSN_P (insn))
 	continue;
       
       t = INSN_VAR_LOCATION_LOC (insn);
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 15d8b140ce7f..33e6e62a4c26 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -428,6 +428,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) (...))
diff --git a/gcc/sese.c b/gcc/sese.c
index bbc72d4d7618..a69ea90622da 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -460,7 +460,7 @@ sese_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))
 	&& gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
       return false;
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 17fe2b3002fe..f5cfe098c77f 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);
 
@@ -1492,6 +1505,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));
 
@@ -1652,6 +1668,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));
 
@@ -1820,6 +1842,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;
@@ -2621,6 +2645,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.  */
@@ -5439,6 +5470,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);
@@ -5508,7 +5543,7 @@ gimple_verify_flow_info (void)
 	    }
 	}
 
-      gsi = gsi_last_bb (bb);
+      gsi = gsi_last_nondebug_bb (bb);
       if (gsi_end_p (gsi))
 	continue;
 
@@ -5763,8 +5798,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;
@@ -5775,6 +5812,7 @@ gimple_block_label (basic_block bb)
 	    gsi_move_before (&i, &s);
 	  return label;
 	}
+      first = false;
     }
 
   label = create_artificial_label (UNKNOWN_LOCATION);
@@ -5850,7 +5888,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 9b7f08c586c3..346ce92669c9 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -554,13 +554,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);
@@ -569,20 +569,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.  */
@@ -1288,7 +1274,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-pretty-print.c b/gcc/tree-pretty-print.c
index 61a28c6757fb..8c7b6d67b44c 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3387,7 +3387,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 4a5cd87e25e7..0e485a683afa 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -256,7 +256,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);
@@ -1442,8 +1443,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-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index 6db33c566c86..613b194e6122 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/var-tracking.c b/gcc/var-tracking.c
index 33bcca7d6f52..b324a2c97c28 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9479,6 +9479,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
@@ -9507,7 +9525,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_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
@@ -10103,11 +10122,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 (DEBUG_BIND_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);
@@ -10175,6 +10217,7 @@ vt_initialize (void)
 			    }
 			}
 		    }
+		  BLOCK_FOR_INSN (insn) = save_bb;
 		}
 	    }
 	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
@@ -10215,7 +10258,10 @@ 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))
 	  {
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers)
  2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
                                 ` (8 preceding siblings ...)
  2017-09-30  9:10               ` [PATCH 7/9] [LVU] Introduce location views Alexandre Oliva
@ 2017-11-10  2:36               ` Alexandre Oliva
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries Alexandre Oliva
                                   ` (9 more replies)
  9 siblings, 10 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (2 preceding siblings ...)
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
@ 2017-11-10  2:36                 ` Alexandre Oliva
  2017-12-07 22:27                   ` Jeff Law
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate " Alexandre Oliva
                                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

This patch introduces a number of new macros and functions that will
be used to distinguish between different kinds of debug stmts, insns
and notes, namely, preexisting debug bind ones and to-be-introduced
nonbind markers.

In a seemingly mechanical way, it adjusts several uses of the macros
and functions, so that they refer to narrower categories when
appropriate.

These changes, by themselves, should not have any visible effect in
the compiler behavior, since the upcoming debug markers are never
created with this patch alone.

for  gcc/ChangeLog

	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_BEGIN_STMT.
	(gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
	(MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
	(MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
	* insn-notes.def (BEGIN_STMT): New.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
	(MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
	(MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
	(NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
	(DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
	(INSN_DEBUG_MARKER_KIND): New.
	(GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT): New.
	(INSN_VAR_LOCATION): Check for VAR_LOCATION.
	(INSN_VAR_LOCATION_PTR): New.
	* cfgexpand.c (expand_debug_locations): Handle debug bind insns
	only.
	(expand_gimple_basic_block): Likewise.  Emit debug temps for TER
	deps only if debug bind insns are enabled.
	(pass_expand::execute): Avoid deep TER and expand
	debug locations for debug bind insns only.
	* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
	debug stmts special handling down to debug bind stmts.
	* combine.c (try_combine): Narrow debug insns special handling
	down to debug bind insns.
	* cse.c (delete_trivially_dead_insns): Handle debug bindings.
	Narrow debug insns preexisting special handling down to debug
	bind insns.
	* dce.c (rest_of_handle_ud_dce): Narrow debug insns special
	handling down to debug bind insns.
	* function.c (instantiate_virtual_regs): Skip debug markers,
	adjust handling of debug binds.
	* gimple-ssa-backprop.c (backprop::prepare_change): Try debug
	temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
	* haifa-sched.c (schedule_insn): Narrow special handling of debug
	insns to debug bind insns.
	* ipa-param-manipulation.c (ipa_modify_call_arguments): Narrow
	special handling of debug stmts to debug bind stmts.
	* ipa-split.c (split_function): Likewise.
	* ira.c (combine_and_move_insns): Adjust debug bind insns only.
	* loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
	debug insns.
	* reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
	* regrename.c (build_def_use): Likewise.
	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
	(pass_cprop_hardreg): Narrow special casing of debug insns to
	debug bind insns.
	* regstat.c (regstat_init_n_sets_and_refs): Likewise.
	* reload1.c (reload): Likewise.
	* sese.c (sese_insert_phis_for_liveouts): Narrow special
	casing of debug stmts to debug bind stmts.
	* shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
	* ssa-iterators.h (num_imm_uses): Likewise.
	* tree-cfg.c (gimple_merge_blocks): Narrow special casing of
	debug stmts to debug bind stmts.
	* tree-inline.c	(tree_function_versioning): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-loop-distribution.c (generate_loops_for_partition):
	Narrow special casing of debug stmts to debug bind stmts.
	* tree-sra.c (analyze_access_subtree): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
	stmts to debug bind stmts.
	* tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
	* tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Likewise.
	* tree-ssa.c (flush_pending_stmts): Narrow special casing of
	debug stmts to debug bind stmts.
	(gimple_replace_ssa_lhs): Likewise.
	(insert_debug_temp_for_var_def): Likewise.
	(insert_debug_temps_for_defs): Likewise.
	(reset_debug_uses): Likewise.
	* tree-ssanames.c (release_ssa_name_fn): Likewise.
	* tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
	(adjust_debug_stmts): Likewise.
	(adjust_phi_and_debug_stmts): Likewise.
	(vect_do_peeling): Likewise.
	* tree-vect-loop.c (vect_transform_loop): Likewise.
	* valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
	* var-tracking.c (adjust_mems): Narrow special casing of debug
	insns to debug bind insns.
	(dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
	(compute_bb_dataflow, vt_find_locations): Likewise.
	(vt_expand_loc, emit_notes_for_changes): Likewise.
	(vt_init_cfa_base): Likewise.
	(vt_emit_notes): Likewise.
	(vt_initialize): Likewise.
	(vt_finalize): Likewise.
---
 gcc/cfgexpand.c              |  8 +++----
 gcc/cgraph.c                 |  2 +-
 gcc/combine.c                | 12 +++++------
 gcc/cse.c                    | 17 ++++++++-------
 gcc/dce.c                    |  2 +-
 gcc/function.c               |  7 ++++---
 gcc/gimple-ssa-backprop.c    |  2 +-
 gcc/gimple.h                 | 31 ++++++++++++++++++++++-----
 gcc/haifa-sched.c            |  4 ++--
 gcc/insn-notes.def           |  3 +++
 gcc/ipa-param-manipulation.c |  2 +-
 gcc/ipa-split.c              | 11 +++++-----
 gcc/ira.c                    |  4 ++--
 gcc/loop-unroll.c            |  6 ++++--
 gcc/reg-stack.c              |  4 ++--
 gcc/regcprop.c               |  4 ++--
 gcc/regrename.c              |  2 +-
 gcc/regstat.c                |  2 +-
 gcc/reload1.c                |  4 ++--
 gcc/rtl.h                    | 47 +++++++++++++++++++++++++++++++++++++++--
 gcc/sese.c                   |  2 +-
 gcc/shrink-wrap.c            |  4 ++--
 gcc/ssa-iterators.h          |  2 +-
 gcc/tree-cfg.c               |  2 +-
 gcc/tree-inline.c            |  4 ++--
 gcc/tree-loop-distribution.c |  2 +-
 gcc/tree-sra.c               |  2 +-
 gcc/tree-ssa-dce.c           |  2 +-
 gcc/tree-ssa-loop-ivopts.c   |  2 +-
 gcc/tree-ssa-reassoc.c       |  2 +-
 gcc/tree-ssa-tail-merge.c    |  2 +-
 gcc/tree-ssa-threadedge.c    |  2 +-
 gcc/tree-ssa.c               | 10 ++++-----
 gcc/tree-ssanames.c          |  2 +-
 gcc/tree-vect-loop-manip.c   |  8 +++----
 gcc/tree-vect-loop.c         |  4 ++--
 gcc/tree.h                   |  8 ++++++-
 gcc/valtrack.c               |  2 +-
 gcc/var-tracking.c           | 50 +++++++++++++++++++++-----------------------
 39 files changed, 182 insertions(+), 104 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index ca5d8dbdfd68..22a9eb45b45e 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5309,7 +5309,7 @@ expand_debug_locations (void)
   flag_strict_aliasing = 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (DEBUG_INSN_P (insn))
+    if (DEBUG_BIND_INSN_P (insn))
       {
 	tree value = (tree)INSN_VAR_LOCATION_LOC (insn);
 	rtx val;
@@ -5562,7 +5562,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	   a_2 = ...
            #DEBUG ... => #D1
 	 */
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && SA.values
 	  && !is_gimple_debug (stmt))
 	{
@@ -6183,7 +6183,7 @@ pass_expand::execute (function *fun)
   timevar_pop (TV_OUT_OF_SSA);
   SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions);
 
-  if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter)
+  if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter)
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, cfun)
@@ -6374,7 +6374,7 @@ pass_expand::execute (function *fun)
 		  next_bb)
     bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     expand_debug_locations ();
 
   if (deep_ter_debug_map)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 7c3507c6ecee..536b80aac6d9 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1459,7 +1459,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
 	 stmts and associate D#X with parm in decl_debug_args_lookup
 	 vector to say for debug info that if parameter parm had been passed,
 	 it would have value parm_Y(D).  */
-      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  vec<tree, va_gc> **debug_args
 	    = decl_debug_args_lookup (e->callee->decl);
diff --git a/gcc/combine.c b/gcc/combine.c
index eab10c599a61..78b949323771 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3760,7 +3760,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 	  /* *SPLIT may be part of I2SRC, so make sure we have the
 	     original expression around for later debug processing.
 	     We should not need I2SRC any more in other cases.  */
-	  if (MAY_HAVE_DEBUG_INSNS)
+	  if (MAY_HAVE_DEBUG_BIND_INSNS)
 	    i2src = copy_rtx (i2src);
 	  else
 	    i2src = NULL;
@@ -4117,7 +4117,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       struct undo *undo;
 
@@ -4430,7 +4430,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
     if (newi2pat)
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2scratch)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	INSN_CODE (i2) = i2_code_number;
@@ -4438,7 +4438,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       }
     else
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2src)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2src)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	SET_INSN_DELETED (i2);
@@ -4448,7 +4448,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i1) = NULL;
 	REG_NOTES (i1) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
 			       this_basic_block);
 	SET_INSN_DELETED (i1);
@@ -4458,7 +4458,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i0) = NULL;
 	REG_NOTES (i0) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
 			       this_basic_block);
 	SET_INSN_DELETED (i0);
diff --git a/gcc/cse.c b/gcc/cse.c
index 65cc9ae110c1..e449223cbb25 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -7049,11 +7049,11 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       counts = XCNEWVEC (int, nreg * 3);
       for (insn = insns; insn; insn = NEXT_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_INSN_P (insn))
 	  count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
 			   NULL_RTX, 1);
 	else if (INSN_P (insn))
@@ -7111,12 +7111,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
       if (! live_insn && dbg_cnt (delete_trivial_dead))
 	{
 	  if (DEBUG_INSN_P (insn))
-	    count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-			     NULL_RTX, -1);
+	    {
+	      if (DEBUG_BIND_INSN_P (insn))
+		count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+				 NULL_RTX, -1);
+	    }
 	  else
 	    {
 	      rtx set;
-	      if (MAY_HAVE_DEBUG_INSNS
+	      if (MAY_HAVE_DEBUG_BIND_INSNS
 		  && (set = single_set (insn)) != NULL_RTX
 		  && is_dead_reg (SET_DEST (set), counts)
 		  /* Used at least once in some DEBUG_INSN.  */
@@ -7156,10 +7159,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_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/dce.c b/gcc/dce.c
index 7534d2abadf6..6fd9548015ce 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -777,7 +777,7 @@ rest_of_handle_ud_dce (void)
     }
   worklist.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     reset_unmarked_insns_debug_uses ();
 
   /* Before any insns are deleted, we must remove the chains since
diff --git a/gcc/function.c b/gcc/function.c
index fe3d9c1bbf3a..2f9f83117143 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
+	    || DEBUG_MARKER_INSN_P (insn))
 	  continue;
-	else if (DEBUG_INSN_P (insn))
-	  instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
+	else if (DEBUG_BIND_INSN_P (insn))
+	  instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
 	else
 	  instantiate_virtual_regs_in_insn (insn);
 
diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c
index 1daa0ceef0ac..8068c2ab1f71 100644
--- a/gcc/gimple-ssa-backprop.c
+++ b/gcc/gimple-ssa-backprop.c
@@ -729,7 +729,7 @@ strip_sign_op (tree rhs)
 void
 backprop::prepare_change (tree var)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     insert_debug_temp_for_var_def (NULL, var);
   reset_flow_sensitive_info (var);
 }
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 334def89398e..f8b0a9dee4af 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -199,13 +199,12 @@ 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
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -4759,6 +4758,28 @@ 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 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;
+
+  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/haifa-sched.c b/gcc/haifa-sched.c
index f5c06a95bb67..b7c0b3a6f4ff 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -4010,7 +4010,7 @@ schedule_insn (rtx_insn *insn)
   gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK));
 
   /* Reset debug insns invalidated by moving this insn.  */
-  if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn))
+  if (MAY_HAVE_DEBUG_BIND_INSNS && !DEBUG_INSN_P (insn))
     for (sd_it = sd_iterator_start (insn, SD_LIST_BACK);
 	 sd_iterator_cond (&sd_it, &dep);)
       {
@@ -4023,7 +4023,7 @@ schedule_insn (rtx_insn *insn)
 	    continue;
 	  }
 
-	gcc_assert (DEBUG_INSN_P (dbg));
+	gcc_assert (DEBUG_BIND_INSN_P (dbg));
 
 	if (sched_verbose >= 6)
 	  fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n",
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index f96ce18ecb6d..960487b31db1 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
 /* The values passed to callee.  */
 INSN_NOTE (CALL_ARG_LOCATION)
 
+/* The beginning of a statement.  */
+INSN_NOTE (BEGIN_STMT)
+
 /* 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-param-manipulation.c b/gcc/ipa-param-manipulation.c
index bedd201f6dd1..bcc736b99c0f 100644
--- a/gcc/ipa-param-manipulation.c
+++ b/gcc/ipa-param-manipulation.c
@@ -402,7 +402,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
 	    }
 	  vargs.quick_push (expr);
 	}
-      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
+      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  unsigned int ix;
 	  tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index 252ea053e2aa..ff09f237f054 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1473,7 +1473,7 @@ split_function (basic_block return_bb, struct split_point *split_point,
     {
       vec<tree, va_gc> **debug_args = NULL;
       unsigned i = 0, len = 0;
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  debug_args = decl_debug_args_lookup (node->decl);
 	  if (debug_args)
@@ -1486,11 +1486,12 @@ split_function (basic_block return_bb, struct split_point *split_point,
 	    tree ddecl;
 	    gimple *def_temp;
 
-	    /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
-	       otherwise if it didn't exist before, we'd end up with
-	       different SSA_NAME_VERSIONs between -g and -g0.  */
+	    /* This needs to be done even without
+	       MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist
+	       before, we'd end up with different SSA_NAME_VERSIONs
+	       between -g and -g0.  */
 	    arg = get_or_create_ssa_default_def (cfun, parm);
-	    if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL)
+	    if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL)
 	      continue;
 
 	    while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
diff --git a/gcc/ira.c b/gcc/ira.c
index 8c93d3df518e..888886ea1679 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3842,9 +3842,9 @@ combine_and_move_insns (void)
 	}
 
       /* Last pass - adjust debug insns referencing cleared regs.  */
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
-	  if (DEBUG_INSN_P (insn))
+	  if (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
 	      INSN_VAR_LOCATION_LOC (insn)
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 91bf5dddeeda..4710f8bb192d 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -2012,12 +2012,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)
+	      || (DEBUG_BIND_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)
+		 || (DEBUG_BIND_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/reg-stack.c b/gcc/reg-stack.c
index 83fc47626710..e17b60296d80 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -3039,7 +3039,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 (DEBUG_BIND_INSN_P (insn))
 	{
 	  if (starting_stack_p)
 	    debug_insns_with_starting_stack++;
@@ -3079,7 +3079,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 (!DEBUG_BIND_INSN_P (insn))
 	    continue;
 
 	  debug_insns_with_starting_stack--;
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index b80019b5be0d..15d8b140ce7f 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -752,7 +752,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 (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx loc = INSN_VAR_LOCATION_LOC (insn);
 	      if (!VAR_LOC_UNKNOWN_P (loc))
@@ -1296,7 +1296,7 @@ pass_cprop_hardreg::execute (function *fun)
       copyprop_hardreg_forward_1 (bb, all_vd + bb->index);
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       FOR_EACH_BB_FN (bb, fun)
 	if (bitmap_bit_p (visited, bb->index)
diff --git a/gcc/regrename.c b/gcc/regrename.c
index 7fbfa3162ca6..89380a877004 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 (DEBUG_BIND_INSN_P (insn)
 	       && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
 	{
 	  scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
diff --git a/gcc/regstat.c b/gcc/regstat.c
index 3fd26fd2fc68..fd3d3a8d98bd 100644
--- a/gcc/regstat.c
+++ b/gcc/regstat.c
@@ -54,7 +54,7 @@ regstat_init_n_sets_and_refs (void)
 
   regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     for (i = 0; i < max_regno; i++)
       {
 	int use_count;
diff --git a/gcc/reload1.c b/gcc/reload1.c
index e15bd8a2c1a9..322696a25f3e 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1112,7 +1112,7 @@ reload (rtx_insn *first, int global)
       /* We don't want complex addressing modes in debug insns
 	 if simpler ones will do, so delegitimize equivalences
 	 in debug insns.  */
-      if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0)
+      if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0)
 	{
 	  rtx reg = regno_reg_rtx[i];
 	  rtx equiv = 0;
@@ -1140,7 +1140,7 @@ reload (rtx_insn *first, int global)
 	      while (next && DF_REF_INSN (next) == insn)
 		next = DF_REF_NEXT_REG (next);
 
-	      if (DEBUG_INSN_P (insn))
+	      if (DEBUG_BIND_INSN_P (insn))
 		{
 		  if (!equiv)
 		    {
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 9cc982172f53..4de167d982cf 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -815,8 +815,13 @@ struct GTY(()) rtvec_def {
 /* Predicate yielding nonzero iff X is an insn that is not a debug insn.  */
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
+/* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+/* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_INSNS					\
+  (MAY_HAVE_DEBUG_MARKER_INSNS || MAY_HAVE_DEBUG_BIND_INSNS)
 
 /* Predicate yielding nonzero iff X is a real insn.  */
 #define INSN_P(X) \
@@ -1604,6 +1609,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)
 
@@ -1615,6 +1621,12 @@ 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))
+
 /* 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))
@@ -1634,8 +1646,39 @@ 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 DEBUG_BIND_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 DEBUG_MARKER_INSN_P(INSN)		\
+  (DEBUG_INSN_P (INSN)				\
+   && (GET_CODE (PATTERN (INSN))		\
+       != VAR_LOCATION))
+/* Evaluate to the marker kind.  */
+#define INSN_DEBUG_MARKER_KIND(INSN)		  \
+  (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
+   ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
+      ? NOTE_INSN_BEGIN_STMT			  \
+      : (enum insn_note)-1) 			  \
+   : (enum insn_note)-1)
+/* Create patterns for debug markers.  These and the above abstract
+   the representation, so that it's easier to get rid of the abuse of
+   the mode to hold the marker kind.  Other marker types are
+   envisioned, so a single bit flag won't do; maybe separate RTL codes
+   wouldn't be a problem.  */
+#define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \
+  gen_rtx_DEBUG_MARKER (VOIDmode)
+
 /* 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) \
diff --git a/gcc/sese.c b/gcc/sese.c
index 89cddf0ec974..bbc72d4d7618 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -205,7 +205,7 @@ void
 sese_insert_phis_for_liveouts (sese_info_p region, basic_block bb,
 			       edge false_e, edge true_e)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     sese_reset_debug_liveouts (region);
 
   unsigned i;
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index 0e4ff6cd46a0..472928f05f76 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -309,10 +309,10 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
      move it as far as we can.  */
   do
     {
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  FOR_BB_INSNS_REVERSE (bb, dinsn)
-	    if (DEBUG_INSN_P (dinsn))
+	    if (DEBUG_BIND_INSN_P (dinsn))
 	      {
 		df_ref use;
 		FOR_EACH_INSN_USE (use, dinsn)
diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h
index 740cbf13cb2b..201bf190cefa 100644
--- a/gcc/ssa-iterators.h
+++ b/gcc/ssa-iterators.h
@@ -453,7 +453,7 @@ num_imm_uses (const_tree var)
   const ssa_use_operand_t *ptr;
   unsigned int num = 0;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     {
       for (ptr = start->next; ptr != start; ptr = ptr->next)
 	if (USE_STMT (ptr))
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index def3f0b8d9bc..17fe2b3002fe 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -2051,7 +2051,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
 	      gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
 	    }
 	  /* Other user labels keep around in a form of a debug stmt.  */
-	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
+	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      gimple *dbg = gimple_build_debug_bind (label,
 						     integer_zero_node,
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index fc5d2c703abc..0d2a31763f1f 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5959,7 +5959,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 					    &vars);
 		if (init)
 		  init_stmts.safe_push (init);
-		if (MAY_HAVE_DEBUG_STMTS && args_to_skip)
+		if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip)
 		  {
 		    if (parm_num == -1)
 		      {
@@ -6106,7 +6106,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 	}
     }
 
-  if (debug_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+  if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree parm;
       vec<tree, va_gc> **debug_args = NULL;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 52db3c94bd95..1accc9f49446 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -826,7 +826,7 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
   /* Remove stmts not in the PARTITION bitmap.  */
   bbs = get_loop_body_in_dom_order (loop);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     for (i = 0; i < loop->num_nodes; i++)
       {
 	basic_block bb = bbs[i];
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index db490b20c3ed..7a1a93ab2387 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -2478,7 +2478,7 @@ analyze_access_subtree (struct access *root, struct access *parent,
 	  gcc_checking_assert (!root->grp_scalar_read
 			       && !root->grp_assignment_read);
 	  sth_created = true;
-	  if (MAY_HAVE_DEBUG_STMTS)
+	  if (MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      root->grp_to_be_debug_replaced = 1;
 	      root->replacement_decl = create_access_replacement (root);
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index a5f0edf7893b..4a5cd87e25e7 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1081,7 +1081,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
 
   /* If this is a store into a variable that is being optimized away,
      add a debug bind stmt if possible.  */
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && gimple_assign_single_p (stmt)
       && is_gimple_val (gimple_assign_rhs1 (stmt)))
     {
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index 65794b2b777e..350f94dfc33f 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -7154,7 +7154,7 @@ remove_unused_ivs (struct ivopts_data *data)
 
 	  tree def = info->iv->ssa_name;
 
-	  if (MAY_HAVE_DEBUG_STMTS && SSA_NAME_DEF_STMT (def))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def))
 	    {
 	      imm_use_iterator imm_iter;
 	      use_operand_p use_p;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 5e8cac69d5d5..45ca43ffac47 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -232,7 +232,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
-  if (!MAY_HAVE_DEBUG_STMTS || gimple_code (stmt) == GIMPLE_PHI)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI)
     return gsi_remove (gsi, true);
 
   gimple_stmt_iterator prev = *gsi;
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index 97e90233d580..6db33c566c86 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1800,7 +1800,7 @@ tail_merge_optimize (unsigned int todo)
 
   if (nr_bbs_removed_total > 0)
     {
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  calculate_dominance_info (CDI_DOMINATORS);
 	  update_debug_stmts ();
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 536c4717b725..70675e4a3fcd 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -692,7 +692,7 @@ simplify_control_stmt_condition_1 (edge e,
 void
 propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   if (!single_pred_p (dest))
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 8b6da9645ce0..151f544babad 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -220,7 +220,7 @@ flush_pending_stmts (edge e)
 void
 gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree lhs = gimple_get_lhs (stmt);
 
@@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 tree
 target_for_debug_bind (tree var)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return NULL_TREE;
 
   if (TREE_CODE (var) == SSA_NAME)
@@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
   int usecount = 0;
   tree value = NULL;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   /* If this name has already been registered for replacement, do nothing
@@ -495,7 +495,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
   ssa_op_iter op_iter;
   def_operand_p def_p;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   stmt = gsi_stmt (*gsi);
@@ -521,7 +521,7 @@ reset_debug_uses (gimple *stmt)
   imm_use_iterator imm_iter;
   gimple *use_stmt;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 6d344ad53096..d00d64852c2e 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -562,7 +562,7 @@ release_ssa_name_fn (struct function *fn, tree var)
       int saved_ssa_name_version = SSA_NAME_VERSION (var);
       use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
 
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	insert_debug_temp_for_var_def (NULL, var);
 
       if (flag_checking)
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index be34310fd03f..9ba4843be4a9 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -192,7 +192,7 @@ adjust_debug_stmts_now (adjust_info *ai)
 static void
 adjust_vec_debug_stmts (void)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   gcc_assert (adjust_vec.exists ());
@@ -214,7 +214,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb)
 {
   adjust_info ai;
 
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && TREE_CODE (from) == SSA_NAME
       && ! SSA_NAME_IS_DEFAULT_DEF (from)
       && ! virtual_operand_p (from))
@@ -242,7 +242,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def)
 
   SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     adjust_debug_stmts (orig_def, PHI_RESULT (update_phi),
 			gimple_bb (update_phi));
 }
@@ -1683,7 +1683,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
   create_lcssa_for_virtual_phi (loop);
   update_ssa (TODO_update_ssa_only_virtuals);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       gcc_assert (!adjust_vec.exists ());
       adjust_vec.create (32);
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index afb36eab1f7e..d66b0219d922 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -7380,7 +7380,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	  if (!stmt_info)
 	    continue;
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, phi);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
@@ -7443,7 +7443,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	      continue;
 	    }
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, stmt);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
diff --git a/gcc/tree.h b/gcc/tree.h
index 277aa919780e..efc7947f4ab7 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1105,8 +1105,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define VL_EXP_OPERAND_LENGTH(NODE) \
   ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
 
+/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+/* Nonzero if gimple_debug_bind_p() (and thus
+   gimple_debug_source_bind_p()) may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
 /* Nonzero if is_gimple_debug() may possibly hold.  */
-#define MAY_HAVE_DEBUG_STMTS    (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_STMTS					\
+  (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS)
 
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
diff --git a/gcc/valtrack.c b/gcc/valtrack.c
index 38af3f0ce51d..8d864c93e6a3 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 (DEBUG_BIND_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 16327bd43f33..33bcca7d6f52 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -1125,7 +1125,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
       if (tem == NULL_RTX)
 	tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
     finish_subreg:
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && GET_CODE (tem) == SUBREG
 	  && (GET_CODE (SUBREG_REG (tem)) == PLUS
 	      || GET_CODE (SUBREG_REG (tem)) == MINUS
@@ -1337,7 +1337,7 @@ dv_onepart_p (decl_or_value dv)
 {
   tree decl;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return NOT_ONEPART;
 
   if (dv_is_value_p (dv))
@@ -4861,7 +4861,7 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
   EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
     var_regno_delete (set, r);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       set->traversed_vars = set->vars;
       shared_hash_htab (set->vars)
@@ -5535,7 +5535,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
 		  variable names such as VALUEs (never happens) or
 		  DEBUG_EXPRs (only happens in the presence of debug
 		  insns).  */
-	       && (!MAY_HAVE_DEBUG_INSNS
+	       && (!MAY_HAVE_DEBUG_BIND_INSNS
 		   || !rtx_debug_expr_p (XEXP (loc, 0))))
 	return MO_USE;
       else
@@ -6700,7 +6700,7 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     local_get_addr_cache = new hash_map<rtx, rtx>;
 
   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
@@ -6982,7 +6982,7 @@ compute_bb_dataflow (basic_block bb)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       delete local_get_addr_cache;
       local_get_addr_cache = NULL;
@@ -7069,7 +7069,7 @@ vt_find_locations (void)
 	      else
 		oldinsz = oldoutsz = 0;
 
-	      if (MAY_HAVE_DEBUG_INSNS)
+	      if (MAY_HAVE_DEBUG_BIND_INSNS)
 		{
 		  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
 		  bool first = true, adjust = false;
@@ -7130,7 +7130,7 @@ vt_find_locations (void)
 
 	      if (htabmax && htabsz > htabmax)
 		{
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    inform (DECL_SOURCE_LOCATION (cfun->decl),
 			    "variable tracking size limit exceeded with "
 			    "-fvar-tracking-assignments, retrying without");
@@ -7190,7 +7190,7 @@ vt_find_locations (void)
 	}
     }
 
-  if (success && MAY_HAVE_DEBUG_INSNS)
+  if (success && MAY_HAVE_DEBUG_BIND_INSNS)
     FOR_EACH_BB_FN (bb, cfun)
       gcc_assert (VTI (bb)->flooded);
 
@@ -8579,7 +8579,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars)
   struct expand_loc_callback_data data;
   rtx result;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return loc;
 
   INIT_ELCD (data, vars);
@@ -9014,7 +9014,7 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
   if (!changed_variables->elements ())
     return;
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     process_changed_values (htab);
 
   data.insn = insn;
@@ -9498,10 +9498,8 @@ vt_emit_notes (void)
      delete_variable_part).  */
   emit_notes = true;
 
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
-    }
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
+    dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
 
   dataflow_set_init (&cur);
 
@@ -9511,13 +9509,13 @@ vt_emit_notes (void)
 	 subsequent basic blocks.  */
       emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
 
       /* Emit the notes for the changes in the basic block itself.  */
       emit_notes_in_bb (bb, &cur);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	delete local_get_addr_cache;
       local_get_addr_cache = NULL;
 
@@ -9533,7 +9531,7 @@ vt_emit_notes (void)
 
   dataflow_set_destroy (&cur);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     delete dropped_values;
   dropped_values = NULL;
 
@@ -9893,7 +9891,7 @@ vt_init_cfa_base (void)
       cfa_base_rtx = NULL_RTX;
       return;
     }
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return;
 
   /* Tell alias analysis that cfa_base_rtx should share
@@ -9935,7 +9933,7 @@ vt_initialize (void)
       VTI (bb)->permp = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
@@ -9948,7 +9946,7 @@ vt_initialize (void)
       global_get_addr_cache = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       rtx reg, expr;
       int ofst;
@@ -10078,7 +10076,7 @@ vt_initialize (void)
       HOST_WIDE_INT pre, post = 0;
       basic_block first_bb, last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_record_sets_hook = add_with_sets;
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10129,7 +10127,7 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
 			prepare_call_arguments (bb, insn);
@@ -10164,7 +10162,7 @@ vt_initialize (void)
 		      vt_init_cfa_base ();
 		      hard_frame_pointer_adjustment = fp_cfa_offset;
 		      /* Disassociate sp from fp now.  */
-		      if (MAY_HAVE_DEBUG_INSNS)
+		      if (MAY_HAVE_DEBUG_BIND_INSNS)
 			{
 			  cselib_val *v;
 			  cselib_invalidate_rtx (stack_pointer_rtx);
@@ -10184,7 +10182,7 @@ vt_initialize (void)
 
       bb = last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_preserve_only_values ();
 	  cselib_reset_table (cselib_get_next_uid ());
@@ -10283,7 +10281,7 @@ vt_finalize (void)
   location_chain_pool.release ();
   shared_hash_pool.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       if (global_get_addr_cache)
 	delete global_get_addr_cache;
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries Alexandre Oliva
@ 2017-11-10  2:36                 ` Alexandre Oliva
  2017-12-07 23:59                   ` Jeff Law
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
                                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

This patch completes the infrastructure for the introduction of
statement frontiers in C-family languages.

It brings in all the code remaining code needed to introduce and
transform begin stmt trees, gimple stmts, insns and notes, and
ultimately use them to generate the is_stmt column in DWARF2+ line
number tables/programs, however none of it is activated: the option
that would do so will be introduced in a subsequent patch.

This patch depends on an earlier patch with not-quite-boilerplate
changes towards SFN.

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 (check_constexpr_ctor_body_1): Skip begin stmt
	markers.
	(constexpr_fn_retval): Likewise.
	(potential_constant_expression_1): Likewise.
	(cxx_eval_statement_list): Check that a begin stmt marker is
	not used as the value of a statement list.
	(cxx_eval_constant_expression): Return begin stmt markers
	unchanged.
	* cp-array-notation.c (stmt_location): New.
	(cp_expand_cond_array_notations): Use it.
	* cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
	* parser.c (add_debug_begin_stmt): New.
	(cp_parser_statement): Call it.
	* pt.c (tsubst_copy): Handle begin stmt markers.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
	markers.  Integrate source bind into debug stmt expand loop.
	(pass_expand::execute): Check debug marker limit.  Avoid deep
	TER and expand debug locations for debug bind insns only.
	* cse.c (insn_live_p): Keep nonbind markers and debug bindings
	followed by them.
	* df-scan.c (df_insn_delete): Accept out-of-block debug insn.
	* final.c (reemit_insn_block_notes): Take current block from
	nonbind markers.  Declare note where it's first set.
	(final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
	begin stmt markers if enabled.
	(notice_source_line): Handle nonbind markers.  Fail if their
	location is unknown or that of builtins.
	(rest_of_handle_final): Convert begin stmt markers to notes if
	var-tracking didn't run.
	(rest_of_clean_state): Skip begin stmt markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
	markers.
	* function.c (allocate_struct_function): Set begin_stmt_markers.
	* function.h (struct function): Add debug_marker_count counter
	and debug_nonbind_markers flag.
	* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
	* gimple-low.c (lower_function_body): Adjust
	debug_nonbind_markers.
	(lower_stmt): Drop or skip gimple debug stmts.
	(lower_try_catch): Skip debug stmts.
	* gimple.c (gimple_build_debug_begin_stmt): New.
	(gimple_copy): Increment debug_marker_count if copying one.
	* gimple.h (gimple_build_debug_begin_stmt): Declare.
	* gimplify.c (rexpr_location): New.
	(rexpr_has_location): New.
	(warn_switch_unreachable_r): Handle gimple debug stmts.
	(shortcut_cond_r): Call expr_location.
	(find_goto): New.
	(find_goto_label): New.
	(shortcut_cond_expr): Call expr_has_location, expr_location, and
	find_goto_label.
	(gimplify_cond_expr): Call find_goto_label, expr_has_location, and
	expr_location.
	(gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
	* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
	(LANG_HOOKS_INITIALIZER): ... this.
	* langhooks.h (struct lang_hooks): Add emits_begin_stmt.
	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
	debug insns.
	(update_ebb_live_info): Skip debug insn markers.
	* lra.c (debug_insn_static_data): Rename to...
	(debug_bind_static_data): ... this.
	(debug_marker_static_data): New.
	(lra_set_insn_recog_data): Select one of the above depending
	on debug insn kind.
	(lra_update_isn_regno_info): Don't assume debug insns have
	freqs.
	(push_insns): Skip debug insns.
	* lto-streamer-in.c (input_function): Drop debug stmts
	depending on active options.  Adjust debug_nonbind_markers.
	* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	begin stmt marker notes.
	(print_insn): Likewise.
	* recog.c (extract_insn): Recognize rtl for debug markers.
	* rtl.def (DEBUG_MARKER): New.
	* tree-inline.c: Include params.h.
	(remap_gimple_stmt): Handle nonbind markers.
	(maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.
	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
	markers regardless of no side effects.
	(tsi_link_before): Don't update container's side effects when adding
	a begin stmt marker.
	(tsi_link_after): Likewise.
	(expr_first): Skip begin stmt markers.
	(expr_last): Likewise.
	* tree-pretty-print (dump_generic_node): Handle begin stmt markers.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Disregard nonbind markers.
	* tree.c (make_node_stat): Don't set side effects for begin stmt
	markers.
	(build1_stat): Likewise.
	* tree.def (DEBUG_BEGIN_STMT): New.
	* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
	* var-tracking.c (delete_debug_insns): Renamed to...
	(delete_vta_debug_insns): ... this.
	(reemit_marker_as_note): New.
	(vt_initialize): Reemit markers.
	(delete_vta_debug_insns): Likewise.
	(vt_debug_insns_local): Reemit or delete markers.
	(variable_tracking_main_1): Likewise.
	* doc/generic.texi (DEBUG_BEGIN_STMT): Document.
	* doc/gimple.texi (gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	(gimple_build_debug_bind): Adjust.
	(gimple_build_debug_begin_stmt): New.
	* doc/invoke.texi (max-debug-marker-count): New param.
	* doc/rtl.texi (debug_implicit_ptr, entry_value): New.
	(debug_parameter_ref, debug_marker): New.
	(NOTE_INSN_BEGIN_STMT): New.
	(DEBUG_INSN): Describe begin stmt markers.
---
 gcc/c-family/c-semantics.c |  21 ++++++
 gcc/c/c-objc-common.h      |   2 +
 gcc/c/c-parser.c           |  20 ++++++
 gcc/c/c-typeck.c           |   8 ++-
 gcc/cfgexpand.c            | 113 +++++++++++++++++---------------
 gcc/cp/constexpr.c         |  16 +++++
 gcc/cp/cp-array-notation.c |  37 +++++++++--
 gcc/cp/cp-objcp-common.h   |   2 +
 gcc/cp/parser.c            |  14 ++++
 gcc/cp/pt.c                |   6 ++
 gcc/cse.c                  |   7 ++
 gcc/df-scan.c              |   2 +-
 gcc/doc/generic.texi       |   5 ++
 gcc/doc/gimple.texi        |  24 ++++++-
 gcc/doc/invoke.texi        |   7 ++
 gcc/doc/rtl.texi           |  53 ++++++++++++---
 gcc/final.c                |  89 +++++++++++++++++++------
 gcc/function.c             |   6 ++
 gcc/function.h             |  10 +++
 gcc/gimple-iterator.c      |   4 ++
 gcc/gimple-low.c           |  29 +++++++++
 gcc/gimple-pretty-print.c  |   7 ++
 gcc/gimple.c               |  24 +++++++
 gcc/gimple.h               |   1 +
 gcc/gimplify.c             | 158 +++++++++++++++++++++++++++++++++++----------
 gcc/langhooks-def.h        |   2 +
 gcc/langhooks.h            |   3 +
 gcc/lra-constraints.c      |  10 ++-
 gcc/lra.c                  |  36 +++++++++--
 gcc/lto-streamer-in.c      |  12 +++-
 gcc/params.def             |   9 +++
 gcc/print-rtl.c            |  24 +++++++
 gcc/recog.c                |   1 +
 gcc/rtl.def                |   3 +
 gcc/tree-inline.c          |  31 ++++++++-
 gcc/tree-iterator.c        |  48 +++++++++++---
 gcc/tree-pretty-print.c    |   4 ++
 gcc/tree-ssa-threadedge.c  |  25 ++++---
 gcc/tree.c                 |   8 ++-
 gcc/tree.def               |   3 +
 gcc/tree.h                 |   2 +-
 gcc/var-tracking.c         |  70 +++++++++++++++++---
 42 files changed, 798 insertions(+), 158 deletions(-)

diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 3ceb714e4b16..cd872d8ac740 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 bee06e9a37ef..27ceabcdfb2f 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 7bca5f1a2a7c..9903c5a1506a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1659,6 +1659,19 @@ c_parser_external_declaration (c_parser *parser)
 static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
    6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
    is accepted; otherwise (old-style parameter declarations) only other
@@ -1759,6 +1772,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))
     {
@@ -5026,6 +5041,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;
     }
@@ -5480,6 +5496,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 4bdc48a9ea38..3f01b482bf20 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10761,6 +10761,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;
     }
@@ -10780,7 +10784,9 @@ c_finish_stmt_expr (location_t loc, tree body)
 
   /* In the case that the BIND_EXPR is not necessary, return the
      expression out from inside it.  */
-  if (last == BIND_EXPR_BODY (body)
+  if ((last == BIND_EXPR_BODY (body)
+       /* Skip nested debug stmts.  */
+       || last == expr_first (BIND_EXPR_BODY (body)))
       && BIND_EXPR_VARS (body) == NULL)
     {
       /* Even if this looks constant, do not allow it in a constant
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 6f64897d0688..3f17e90d50b3 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5659,39 +5659,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	  if (new_bb)
 	    return new_bb;
 	}
-      else if (gimple_debug_bind_p (stmt))
+      else if (is_gimple_debug (stmt))
 	{
 	  location_t sloc = curr_insn_location ();
 	  gimple_stmt_iterator nsi = gsi;
 
 	  for (;;)
 	    {
-	      tree var = gimple_debug_bind_get_var (stmt);
-	      tree value;
-	      rtx val;
+	      tree var;
+	      tree value = NULL_TREE;
+	      rtx val = NULL_RTX;
 	      machine_mode mode;
 
-	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
-		  && TREE_CODE (var) != LABEL_DECL
-		  && !target_for_debug_bind (var))
-		goto delink_debug_stmt;
+	      if (!gimple_debug_nonbind_marker_p (stmt))
+		{
+		  if (gimple_debug_bind_p (stmt))
+		    {
+		      var = gimple_debug_bind_get_var (stmt);
 
-	      if (gimple_debug_bind_has_value_p (stmt))
-		value = gimple_debug_bind_get_value (stmt);
-	      else
-		value = NULL_TREE;
+		      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+			  && TREE_CODE (var) != LABEL_DECL
+			  && !target_for_debug_bind (var))
+			goto delink_debug_stmt;
 
-	      last = get_last_insn ();
+		      if (DECL_P (var))
+			mode = DECL_MODE (var);
+		      else
+			mode = TYPE_MODE (TREE_TYPE (var));
 
-	      set_curr_insn_location (gimple_location (stmt));
+		      if (gimple_debug_bind_has_value_p (stmt))
+			value = gimple_debug_bind_get_value (stmt);
+
+		      val = gen_rtx_VAR_LOCATION
+			(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+		    }
+		  else if (gimple_debug_source_bind_p (stmt))
+		    {
+		      var = gimple_debug_source_bind_get_var (stmt);
+
+		      value = gimple_debug_source_bind_get_value (stmt);
+
+		      mode = DECL_MODE (var);
 
-	      if (DECL_P (var))
-		mode = DECL_MODE (var);
+		      val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+						  VAR_INIT_STATUS_UNINITIALIZED);
+		    }
+		  else
+		    gcc_unreachable ();
+		}
+	      /* If this function was first compiled with markers
+		 enabled, but they're now disable (e.g. LTO), drop
+		 them on the floor.  */
+	      else if (gimple_debug_nonbind_marker_p (stmt)
+		       && !MAY_HAVE_DEBUG_MARKER_INSNS)
+		goto delink_debug_stmt;
+	      else if (gimple_debug_begin_stmt_p (stmt))
+		val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT ();
 	      else
-		mode = TYPE_MODE (TREE_TYPE (var));
+		gcc_unreachable ();
 
-	      val = gen_rtx_VAR_LOCATION
-		(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+	      last = get_last_insn ();
+
+	      set_curr_insn_location (gimple_location (stmt));
 
 	      emit_debug_insn (val);
 
@@ -5699,9 +5728,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		{
 		  /* We can't dump the insn with a TREE where an RTX
 		     is expected.  */
-		  PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    {
+		      gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);
+		      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		    }
 		  maybe_dump_rtl_for_gimple_stmt (stmt, last);
-		  PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    PAT_VAR_LOCATION_LOC (val) = (rtx)value;
 		}
 
 	    delink_debug_stmt:
@@ -5717,42 +5751,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	      if (gsi_end_p (nsi))
 		break;
 	      stmt = gsi_stmt (nsi);
-	      if (!gimple_debug_bind_p (stmt))
+	      if (!is_gimple_debug (stmt))
 		break;
 	    }
 
 	  set_curr_insn_location (sloc);
 	}
-      else if (gimple_debug_source_bind_p (stmt))
-	{
-	  location_t sloc = curr_insn_location ();
-	  tree var = gimple_debug_source_bind_get_var (stmt);
-	  tree value = gimple_debug_source_bind_get_value (stmt);
-	  rtx val;
-	  machine_mode mode;
-
-	  last = get_last_insn ();
-
-	  set_curr_insn_location (gimple_location (stmt));
-
-	  mode = DECL_MODE (var);
-
-	  val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
-				      VAR_INIT_STATUS_UNINITIALIZED);
-
-	  emit_debug_insn (val);
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      /* We can't dump the insn with a TREE where an RTX
-		 is expected.  */
-	      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
-	      maybe_dump_rtl_for_gimple_stmt (stmt, last);
-	      PAT_VAR_LOCATION_LOC (val) = (rtx)value;
-	    }
-
-	  set_curr_insn_location (sloc);
-	}
       else
 	{
 	  gcall *call_stmt = dyn_cast <gcall *> (stmt);
@@ -6385,6 +6389,11 @@ pass_expand::execute (function *fun)
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
     e->flags &= ~EDGE_EXECUTABLE;
 
+  /* If the function has too many markers, drop them while expanding.  */
+  if (cfun->debug_marker_count
+      >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+    cfun->debug_nonbind_markers = false;
+
   lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
   FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
 		  next_bb)
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 670aae22dd66..b03337fe0e58 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -455,6 +455,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
 
     case USING_STMT:
     case STATIC_ASSERT:
+    case DEBUG_BEGIN_STMT:
       return true;
 
     default:
@@ -694,6 +695,7 @@ constexpr_fn_retval (tree body)
       return constexpr_fn_retval (BIND_EXPR_BODY (body));
 
     case USING_STMT:
+    case DEBUG_BEGIN_STMT:
       return NULL_TREE;
 
     case CALL_EXPR:
@@ -3818,6 +3820,14 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
       if (returns (jump_target) || breaks (jump_target))
 	break;
     }
+  /* Make sure we don't use the "result" of a debug-only marker.  That
+     would be wrong.  We should be using the result of the previous
+     statement, or NULL if there isn't one.  In practice, this should
+     never happen: the statement after the marker should override the
+     result of the marker, so its value shouldn't survive in R.  Now,
+     should that ever change, we'll need some fixing here to stop
+     markers from modifying the generated executable code.  */
+  gcc_checking_assert (!r || TREE_CODE (r) != DEBUG_BEGIN_STMT);
   return r;
 }
 
@@ -4043,6 +4053,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	}
       break;
 
+    case DEBUG_BEGIN_STMT:
+      /* ??? It might be nice to retain this information somehow, so
+	 as to be able to step into a constexpr function call.  */
+      /* Fall through.  */
+
     case FUNCTION_DECL:
     case TEMPLATE_DECL:
     case LABEL_DECL:
@@ -5146,6 +5161,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case CONTINUE_STMT:
     case REQUIRES_EXPR:
     case STATIC_ASSERT:
+    case DEBUG_BEGIN_STMT:
       return true;
 
     case PARM_DECL:
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index 31be7d685ba7..17f0b35cc56c 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 3e4cc9c5d4ce..c1c82b61d5eb 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -105,6 +105,8 @@ extern void cp_register_dumps (gcc::dump_manager *);
 #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
 #undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
 #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
 
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 77b96376e136..a792e78e3dcf 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10775,6 +10775,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 
 /* Statements [gram.stmt.stmt]  */
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a statement.
 
    statement:
@@ -10850,6 +10863,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 710333ddabac..ad335bc08632 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15284,6 +15284,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 e449223cbb25..c0db32b9f11d 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -6962,11 +6962,18 @@ insn_live_p (rtx_insn *insn, int *counts)
     {
       rtx_insn *next;
 
+      if (DEBUG_MARKER_INSN_P (insn))
+	return true;
+
       for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
 	if (NOTE_P (next))
 	  continue;
 	else if (!DEBUG_INSN_P (next))
 	  return true;
+	/* If we find an inspection point, such as a debug begin stmt,
+	   we want to keep the earlier debug insn.  */
+	else if (DEBUG_MARKER_INSN_P (next))
+	  return true;
 	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
 	  return false;
 
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 8ab3d716ea29..429dab8a99b4 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 a51cfd6e9557..a13bce94020a 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 fa98800a675b..492678705c6f 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -831,6 +831,16 @@ expression to a variable.
 Return true if g is any of the OpenMP codes.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
+a source statement.
+@end deftypefn
+
+@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
+without any variable binding.
+@end deftypefn
+
 @node Manipulating GIMPLE statements
 @section Manipulating GIMPLE statements
 @cindex Manipulating GIMPLE statements
@@ -1530,10 +1540,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
@@ -1604,6 +1615,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
 and @code{FALSE} if it unbinds the variable.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that the
+user statement at the given @code{location} and @code{block} starts at
+the point at which the statement is inserted.  The intent is that side
+effects (e.g. variable bindings) of all prior user statements are
+observable, and that none of the side effects of subsequent user
+statements are.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e897d93070ae..6ff7c34cdd6c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10529,6 +10529,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 21524f546964..898574a01ad0 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3436,6 +3436,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},
 that points back to it, within value expressions in
 @code{VAR_LOCATION} nodes.
 
+@findex debug_implicit_ptr
+@item (debug_implicit_ptr:@var{mode} @var{decl})
+Stands for the location of a @var{decl} that is no longer addressable.
+
+@findex entry_value
+@item (entry_value:@var{mode} @var{decl})
+Stands for the value a @var{decl} had at the entry point of the
+containing function.
+
+@findex debug_parameter_ref
+@item (debug_parameter_ref:@var{mode} @var{decl})
+Refers to a parameter that was completely optimized out.
+
+@findex debug_marker
+@item (debug_marker:@var{mode})
+Marks a program location.  With @code{VOIDmode}, it stands for the
+beginning of a statement, a recommended inspection point logically after
+all prior side effects, and before any subsequent side effects.
+
 @end table
 
 @node Insns
@@ -3712,6 +3731,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.
@@ -3729,15 +3754,25 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-Throughout optimization passes, binding information is kept in
-pseudo-instruction form, so that, unlike notes, it gets the same
-treatment and adjustments that regular instructions would.  It is the
-variable tracking pass that turns these pseudo-instructions into var
-location notes, analyzing control flow, value equivalences and changes
-to registers and memory referenced in value expressions, propagating
-the values of debug temporaries and determining expressions that can
-be used to compute the value of each user variable at as many points
-(ranges, actually) in the program as possible.
+@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
+with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
+just @code{DEBUG_MARKER}s, can be detected by testing
+@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
+@code{DEBUG_BIND_INSN_P}.
+
+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
+with respect to each other, particularly during scheduling.  Binding
+information is kept in pseudo-instruction form, so that, unlike notes,
+it gets the same treatment and adjustments that regular instructions
+would.  It is the variable tracking pass that turns these
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
+@code{NOTE_INSN_BEGIN_STMT} notes,
+analyzing control flow, value equivalences and changes to registers and
+memory referenced in value expressions, propagating the values of debug
+temporaries and determining expressions that can be used to compute the
+value of each user variable at as many points (ranges, actually) in the
+program as possible.
 
 Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
 @code{INSN_VAR_LOCATION} denotes a value at that specific point in the
diff --git a/gcc/final.c b/gcc/final.c
index 039c37a31352..b343063faa6d 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1646,7 +1646,6 @@ reemit_insn_block_notes (void)
 {
   tree cur_block = DECL_INITIAL (cfun->decl);
   rtx_insn *insn;
-  rtx_note *note;
 
   insn = get_insns ();
   for (; insn; insn = NEXT_INSN (insn))
@@ -1654,17 +1653,29 @@ reemit_insn_block_notes (void)
       tree this_block;
 
       /* Prevent lexical blocks from straddling section boundaries.  */
-      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
-        {
-          for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
-               s = BLOCK_SUPERCONTEXT (s))
-            {
-              rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
-              NOTE_BLOCK (note) = s;
-              note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
-              NOTE_BLOCK (note) = s;
-            }
-        }
+      if (NOTE_P (insn))
+	switch (NOTE_KIND (insn))
+	  {
+	  case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+	    {
+	      for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
+		   s = BLOCK_SUPERCONTEXT (s))
+		{
+		  rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+		  NOTE_BLOCK (note) = s;
+		  note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
+		  NOTE_BLOCK (note) = s;
+		}
+	    }
+	    break;
+
+	  case NOTE_INSN_BEGIN_STMT:
+	    this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
+	    goto set_cur_block_to_this_block;
+
+	  default:
+	    continue;
+	}
 
       if (!active_insn_p (insn))
         continue;
@@ -1685,6 +1696,7 @@ reemit_insn_block_notes (void)
 	    this_block = choose_inner_scope (this_block,
 					     insn_scope (body->insn (i)));
 	}
+    set_cur_block_to_this_block:
       if (! this_block)
 	{
 	  if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
@@ -1701,7 +1713,7 @@ reemit_insn_block_notes (void)
     }
 
   /* change_scope emits before the insn, not after.  */
-  note = emit_note (NOTE_INSN_DELETED);
+  rtx_note *note = emit_note (NOTE_INSN_DELETED);
   change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
   delete_insn (note);
 
@@ -2400,6 +2412,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    debug_hooks->var_location (insn);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+	  gcc_checking_assert (cfun->debug_nonbind_markers);
+	  if (!DECL_IGNORED_P (current_function_decl)
+	      && notice_source_line (insn, NULL))
+	    {
+	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
+					   last_filename, last_discriminator,
+					   true);
+	    }
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	  break;
@@ -2486,7 +2509,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	rtx body = PATTERN (insn);
 	int insn_code_number;
 	const char *templ;
-	bool is_stmt;
+	bool is_stmt, *is_stmt_p;
+
+	if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
+	  {
+	    is_stmt = false;
+	    is_stmt_p = NULL;
+	  }
+	else
+	  is_stmt_p = &is_stmt;
 
 	/* Reset this early so it is correct for ASM statements.  */
 	current_insn_predicate = NULL_RTX;
@@ -2589,7 +2620,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	/* Output this line note if it is the first or the last line
 	   note in a row.  */
 	if (!DECL_IGNORED_P (current_function_decl)
-	    && notice_source_line (insn, &is_stmt))
+	    && notice_source_line (insn, is_stmt_p))
 	  {
 	    if (flag_verbose_asm)
 	      asm_show_source (last_filename, last_linenum);
@@ -3082,7 +3113,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   const char *filename;
   int linenum, columnnum;
 
-  if (override_filename)
+  if (NOTE_MARKER_P (insn))
+    {
+      location_t loc = NOTE_MARKER_LOCATION (insn);
+      expanded_location xloc = expand_location (loc);
+      if (xloc.line == 0)
+	{
+	  gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
+			       || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
+	  return false;
+	}
+      filename = xloc.file;
+      linenum = xloc.line;
+      columnnum = xloc.column;
+      force_source_line = true;
+    }
+  else if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
@@ -3115,7 +3161,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;
@@ -3127,7 +3174,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;
     }
 
@@ -4472,6 +4520,10 @@ rest_of_handle_final (void)
 {
   const char *fnname = get_fnname_from_decl (current_function_decl);
 
+  /* Turn debug markers into notes.  */
+  if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)
+    variable_tracking_main ();
+
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
@@ -4659,6 +4711,7 @@ rest_of_clean_state (void)
       if (final_output
 	  && (!NOTE_P (insn) ||
 	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
 	       && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
diff --git a/gcc/function.c b/gcc/function.c
index 2f9f83117143..80f854b494e8 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4932,6 +4932,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
     }
+
+  /* Don't enable begin stmt markers if var-tracking at assignments is
+     disabled.  The markers make little sense without the variable
+     binding annotations among them.  */
+  cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
+    && MAY_HAVE_DEBUG_MARKER_STMTS;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 76434cd59a50..1186116fc0b5 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 fb75f993e9a1..2359760e9c24 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -573,6 +573,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
 
   if (remove_permanently)
     {
+      if (gimple_debug_nonbind_marker_p (stmt))
+	/* We don't need this to be exact, but try to keep it at least
+	   close.  */
+	cfun->debug_marker_count--;
       require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
       gimple_remove_stmt_histograms (cfun, stmt);
     }
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 22db61bbd48a..95f3f4561f9f 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -110,6 +110,17 @@ lower_function_body (void)
 
   i = gsi_last (lowered_body);
 
+  /* If we had begin stmt markers from e.g. PCH, but this compilation
+     doesn't want them, lower_stmt will have cleaned them up; we can
+     now clear the flag that indicates we had them.  */
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
+    {
+      /* This counter needs not be exact, but before lowering it will
+	 most certainly be.  */
+      gcc_assert (cfun->debug_marker_count == 0);
+      cfun->debug_nonbind_markers = false;
+    }
+
   /* If the function falls off the end, we need a null return statement.
      If we've already got one in the return_statements vector, we don't
      need to do anything special.  Otherwise build one by hand.  */
@@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (cfun->debug_nonbind_markers);
+      /* We can't possibly have debug bind stmts before lowering, we
+	 first emit them when entering SSA.  */
+      gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
+      /* Propagate fallthruness.  */
+      /* If the function (e.g. from PCH) had debug stmts, but they're
+	 disabled for this compilation, remove them.  */
+      if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+	gsi_remove (gsi, true);
+      else
+	gsi_next (gsi);
+      return;
+
     case GIMPLE_NOP:
     case GIMPLE_ASM:
     case GIMPLE_ASSIGN:
@@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
 	cannot_fallthru = false;
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
+      break;
+
     default:
       /* This case represents statements to be executed when an
 	 exception occurs.  Those statements are implicitly followed
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 55c623e37bb4..61b1f2c89cbb 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1363,6 +1363,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 			 gimple_debug_source_bind_get_value (gs));
       break;
 
+    case GIMPLE_DEBUG_BEGIN_STMT:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+      break;
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 37f2248f224d..66496d002a8d 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -852,6 +852,27 @@ gimple_build_debug_source_bind (tree var, tree value,
 }
 
 
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+   LOCATION.  */
+
+gdebug *
+gimple_build_debug_begin_stmt (tree block, location_t location
+				    MEM_STAT_DECL)
+{
+  gdebug *p
+    = as_a <gdebug *> (
+        gimple_build_with_ops_stat (GIMPLE_DEBUG,
+				    (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+				    PASS_MEM_STAT));
+
+  gimple_set_location (p, location);
+  gimple_set_block (p, block);
+  cfun->debug_marker_count++;
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1914,6 +1935,9 @@ gimple_copy (gimple *stmt)
       gimple_set_modified (copy, true);
     }
 
+  if (gimple_debug_nonbind_marker_p (stmt))
+    cfun->debug_marker_count++;
+
   return copy;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 103d9555e465..f44887ad7a9b 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1455,6 +1455,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
+gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
 gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
 gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
 gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index d252af04bcbf..78c7ba57ef8c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -984,6 +984,48 @@ unshare_expr_without_location (tree expr)
     walk_tree (&expr, prune_expr_location, NULL, NULL);
   return expr;
 }
+
+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
+   one, OR_ELSE otherwise.  The location of a STATEMENT_LISTs
+   comprising at least one DEBUG_BEGIN_STMT followed by exactly one
+   EXPR is the location of the EXPR.  */
+
+static location_t
+rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
+  if (!expr)
+    return or_else;
+
+  if (EXPR_HAS_LOCATION (expr))
+    return EXPR_LOCATION (expr);
+
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    return or_else;
+
+  tree_stmt_iterator i = tsi_start (expr);
+
+  bool found = false;
+  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+    {
+      found = true;
+      tsi_next (&i);
+    }
+
+  if (!found || !tsi_one_before_end_p (i))
+    return or_else;
+
+  return rexpr_location (tsi_stmt (i), or_else);
+}
+
+/* Return TRUE iff EXPR (maybe recursively) has a location; see
+   rexpr_location for the potential recursion.  */
+
+static inline bool
+rexpr_has_location (tree expr)
+{
+  return rexpr_location (expr) != UNKNOWN_LOCATION;
+}
+
 \f
 /* 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
@@ -1774,6 +1816,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))
 	{
@@ -3443,7 +3492,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the && on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3466,7 +3515,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the || on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3488,7 +3537,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
 
       /* Keep the original source location on the first 'if'.  Set the source
 	 location of the ? on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
 		     shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
 				      false_label_p, locus),
@@ -3512,6 +3561,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.  */
@@ -3542,8 +3630,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the && on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  then_ = shortcut_cond_expr (expr);
 	  then_se = then_ && TREE_SIDE_EFFECTS (then_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3564,8 +3652,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the || on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  else_ = shortcut_cond_expr (expr);
 	  else_se = else_ && TREE_SIDE_EFFECTS (else_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3592,20 +3680,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;
     }
@@ -3669,8 +3753,8 @@ shortcut_cond_expr (tree expr)
 	{
 	  tree last = expr_last (expr);
 	  t = build_and_jump (&end_label);
-	  if (EXPR_HAS_LOCATION (last))
-	    SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
+	  if (rexpr_has_location (last))
+	    SET_EXPR_LOCATION (t, rexpr_location (last));
 	  append_to_statement_list (t, &expr);
 	}
       if (emit_false)
@@ -3963,39 +4047,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   gimple_push_condition ();
 
   have_then_clause_p = have_else_clause_p = false;
-  if (TREE_OPERAND (expr, 1) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
-	  == current_function_decl)
+  label_true = find_goto_label (TREE_OPERAND (expr, 1));
+  if (label_true
+      && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
+	  || !rexpr_has_location (label_true)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_true)))
     {
-      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
       have_then_clause_p = true;
+      label_true = GOTO_DESTINATION (label_true);
     }
   else
     label_true = create_artificial_label (UNKNOWN_LOCATION);
-  if (TREE_OPERAND (expr, 2) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
-	  == current_function_decl)
+  label_false = find_goto_label (TREE_OPERAND (expr, 2));
+  if (label_false
+      && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
+	  || !rexpr_has_location (label_false)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_false)))
     {
-      label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
       have_else_clause_p = true;
+      label_false = GOTO_DESTINATION (label_false);
     }
   else
     label_false = create_artificial_label (UNKNOWN_LOCATION);
@@ -11792,6 +11872,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case DEBUG_EXPR_DECL:
+	  gcc_unreachable ();
+
+	case DEBUG_BEGIN_STMT:
+	  gimplify_seq_add_stmt (pre_p,
+				 gimple_build_debug_begin_stmt
+				 (TREE_BLOCK (*expr_p),
+				  EXPR_LOCATION (*expr_p)));
+	  ret = GS_ALL_DONE;
+	  *expr_p = NULL;
+	  break;
+
 	case SSA_NAME:
 	  /* Allow callbacks into the gimplifier during optimization.  */
 	  ret = GS_ALL_DONE;
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 61b081bd7ccc..a3f02b219df7 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int);
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP	false
 #define LANG_HOOKS_DEEP_UNSHARING	false
 #define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS	false
+#define LANG_HOOKS_EMITS_BEGIN_STMT	false
 #define LANG_HOOKS_RUN_LANG_SELFTESTS   lhd_do_nothing
 #define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
 
@@ -343,6 +344,7 @@ extern void lhd_end_section (void);
   LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
   LANG_HOOKS_DEEP_UNSHARING, \
   LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \
+  LANG_HOOKS_EMITS_BEGIN_STMT, \
   LANG_HOOKS_RUN_LANG_SELFTESTS, \
   LANG_HOOKS_GET_SUBSTRING_LOCATION \
 }
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index d1288f1965d1..40c5bade6167 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -528,6 +528,9 @@ struct lang_hooks
      instead of trampolines.  */
   bool custom_function_descriptors;
 
+  /* True if this language emits begin stmt notes.  */
+  bool emits_begin_stmt;
+
   /* Run all lang-specific selftests.  */
   void (*run_lang_selftests) (void);
 
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 3758409bb9c5..0f81ce6766a1 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -5264,10 +5264,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));
 	}
     }
@@ -5806,6 +5807,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
       if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
 	continue;
       curr_bb = BLOCK_FOR_INSN (curr_insn);
+      if (!curr_bb)
+	{
+	  gcc_assert (DEBUG_INSN_P (curr_insn));
+	  if (DEBUG_MARKER_INSN_P (curr_insn))
+	    continue;
+	  curr_bb = prev_bb;
+	}
       if (curr_bb != prev_bb)
 	{
 	  if (prev_bb != NULL)
diff --git a/gcc/lra.c b/gcc/lra.c
index 88d75c18e86c..d1de053abd65 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
@@ -947,12 +963,20 @@ lra_set_insn_recog_data (rtx_insn *insn)
   data->regs = NULL;
   if (DEBUG_INSN_P (insn))
     {
-      data->insn_static_data = &debug_insn_static_data;
       data->dup_loc = NULL;
       data->arg_hard_regs = NULL;
       data->preferred_alternatives = ALL_ALTERNATIVES;
-      data->operand_loc = XNEWVEC (rtx *, 1);
-      data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+      if (DEBUG_BIND_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_bind_static_data;
+	  data->operand_loc = XNEWVEC (rtx *, 1);
+	  data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+	}
+      else if (DEBUG_MARKER_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_marker_static_data;
+	  data->operand_loc = NULL;
+	}
       return data;
     }
   if (icode < 0)
@@ -1595,7 +1619,7 @@ lra_update_insn_regno_info (rtx_insn *insn)
     return;
   data = lra_get_insn_recog_data (insn);
   static_data = data->insn_static_data;
-  freq = get_insn_freq (insn);
+  freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
   invalidate_insn_data_regno_info (data, insn, freq);
   uid = INSN_UID (insn);
   for (i = static_data->n_operands - 1; i >= 0; i--)
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index acbbc9d68235..210a5eff210b 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1125,7 +1125,10 @@ input_function (tree fn_decl, struct data_in *data_in,
 	     Similarly remove all IFN_*SAN_* internal calls   */
 	  if (!flag_wpa)
 	    {
-	      if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+	      if (is_gimple_debug (stmt)
+		  && (gimple_debug_nonbind_marker_p (stmt)
+		      ? !MAY_HAVE_DEBUG_MARKER_STMTS
+		      : !MAY_HAVE_DEBUG_BIND_STMTS))
 		remove = true;
 	      if (is_gimple_call (stmt)
 		  && gimple_call_internal_p (stmt))
@@ -1179,6 +1182,13 @@ input_function (tree fn_decl, struct data_in *data_in,
 	    {
 	      gsi_next (&bsi);
 	      stmts[gimple_uid (stmt)] = stmt;
+
+	      /* Remember that the input function has begin stmt
+		 markers, so that we know to expect them when emitting
+		 debug info.  */
+	      if (!cfun->debug_nonbind_markers
+		  && gimple_debug_nonbind_marker_p (stmt))
+		cfun->debug_nonbind_markers = true;
 	    }
 	}
     }
diff --git a/gcc/params.def b/gcc/params.def
index 8881f4c403a0..c27eb6447a24 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -962,6 +962,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
 	  "Max. size of loc list for which reverse ops should be added.",
 	  50, 0, 0)
 
+/* Set a threshold to discard debug markers (e.g. debug begin stmt
+   markers) when expanding a function to RTL, or inlining it into
+   another function.  */
+
+DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
+	  "max-debug-marker-count",
+	  "Max. count of debug markers to expand or inline.",
+	  100000, 0, 0)
+
 /* Set minimum insn uid for non-debug insns.  */
 
 DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 28d99862cad2..acbe2f37748a 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  fputc ('\t', m_outfile);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+	  {
+	    expanded_location xloc
+	      = expand_location (NOTE_MARKER_LOCATION (in_rtx));
+	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+	  }
+#endif
+	  break;
+
 	default:
 	  break;
 	}
@@ -1791,6 +1801,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 
     case DEBUG_INSN:
       {
+	if (DEBUG_MARKER_INSN_P (x))
+	  {
+	    switch (INSN_DEBUG_MARKER_KIND (x))
+	      {
+	      case NOTE_INSN_BEGIN_STMT:
+		pp_string (pp, "debug begin stmt marker");
+		break;
+
+	      default:
+		gcc_unreachable ();
+	      }
+	    break;
+	  }
+
 	const char *name = "?";
 	char idbuf[32];
 
diff --git a/gcc/recog.c b/gcc/recog.c
index 4f11c579137c..3eb7fb8b14ab 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -2252,6 +2252,7 @@ extract_insn (rtx_insn *insn)
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
     case VAR_LOCATION:
+    case DEBUG_MARKER:
       return;
 
     case SET:
diff --git a/gcc/rtl.def b/gcc/rtl.def
index ee7b7e195243..0000808c9e99 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -766,6 +766,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
    been optimized away completely.  */
 DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
 
+/* Used in marker DEBUG_INSNs to avoid being recognized as an insn.  */
+DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_EXTRA)
+
 /* All expressions from this point forward appear only in machine
    descriptions.  */
 #ifdef GENERATOR_FILE
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 0d2a31763f1f..f858d426a500 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "except.h"
 #include "debug.h"
+#include "params.h"
 #include "value-prof.h"
 #include "cfgloop.h"
 #include "builtins.h"
@@ -1354,7 +1355,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
   gimple_seq stmts = NULL;
 
   if (is_gimple_debug (stmt)
-      && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
+      && (gimple_debug_nonbind_marker_p (stmt)
+	  ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers
+	  : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return stmts;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
@@ -1637,6 +1640,20 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
 	  gimple_seq_add_stmt (&stmts, copy);
 	  return stmts;
 	}
+      if (gimple_debug_nonbind_marker_p (stmt))
+	{
+	  /* If the inlined function has too many debug markers,
+	     don't copy them.  */
+	  if (id->src_cfun->debug_marker_count
+	      > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+	    return stmts;
+
+	  gdebug *copy = as_a <gdebug *> (gimple_copy (stmt));
+	  id->debug_stmts.safe_push (copy);
+	  gimple_seq_add_stmt (&stmts, copy);
+	  return stmts;
+	}
+      gcc_checking_assert (!is_gimple_debug (stmt));
 
       /* Create a new deep copy of the statement.  */
       copy = gimple_copy (stmt);
@@ -1732,7 +1749,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
       gimple_set_block (copy, *n);
     }
 
-  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
+  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)
+      || gimple_debug_nonbind_marker_p (copy))
     {
       gimple_seq_add_stmt (&stmts, copy);
       return stmts;
@@ -2585,6 +2603,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
 	      value = gimple_debug_source_bind_get_value (stmt);
 	      new_stmt = gimple_build_debug_source_bind (var, value, stmt);
 	    }
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    new_stmt = as_a <gdebug *> (gimple_copy (stmt));
 	  else
 	    gcc_unreachable ();
 	  gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2849,6 +2869,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;
@@ -2857,8 +2880,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
 
   if (gimple_debug_source_bind_p (stmt))
     t = gimple_debug_source_bind_get_var (stmt);
-  else
+  else if (gimple_debug_bind_p (stmt))
     t = gimple_debug_bind_get_var (stmt);
+  else
+    gcc_unreachable ();
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = id->debug_map->get (t)))
diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
index c485413b5e50..10e510db0921 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 8c7b6d67b44c..0ce96c5b88cb 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3292,6 +3292,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
       pp_string (pp, "_Cilk_sync");
       break;
 
+    case DEBUG_BEGIN_STMT:
+      pp_string (pp, "# DEBUG BEGIN STMT");
+      break;
+
     default:
       NIY;
     }
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 70675e4a3fcd..91793bfa59d3 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
       gimple *stmt = gsi_stmt (si);
       if (!is_gimple_debug (stmt))
 	break;
+      if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       i++;
     }
 
@@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	var = gimple_debug_bind_get_var (stmt);
       else if (gimple_debug_source_bind_p (stmt))
 	var = gimple_debug_source_bind_get_var (stmt);
+      else if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       else
 	gcc_unreachable ();
 
@@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	    var = gimple_debug_bind_get_var (stmt);
 	  else if (gimple_debug_source_bind_p (stmt))
 	    var = gimple_debug_source_bind_get_var (stmt);
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    continue;
 	  else
 	    gcc_unreachable ();
 
-	  /* Discard debug bind overlaps.  ??? Unlike stmts from src,
+	  /* Discard debug bind overlaps.  Unlike stmts from src,
 	     copied into a new block that will precede BB, debug bind
 	     stmts in bypassed BBs may actually be discarded if
-	     they're overwritten by subsequent debug bind stmts, which
-	     might be a problem once we introduce stmt frontier notes
-	     or somesuch.  Adding `&& bb == src' to the condition
-	     below will preserve all potentially relevant debug
-	     notes.  */
+	     they're overwritten by subsequent debug bind stmts.  We
+	     want to copy binds for all modified variables, so that we
+	     retain a bind to the shared def if there is one, or to a
+	     newly introduced PHI node if there is one.  Our bind will
+	     end up reset if the value is dead, but that implies the
+	     variable couldn't have survived, so it's fine.  We are
+	     not actually running the code that performed the binds at
+	     this point, we're just adding binds so that they survive
+	     the new confluence, so markers should not be copied.  */
 	  if (vars && vars->add (var))
 	    continue;
 	  else if (!vars)
@@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 		  break;
 	      if (i >= 0)
 		continue;
-
-	      if (fewvars.length () < (unsigned) alloc_count)
+	      else if (fewvars.length () < (unsigned) alloc_count)
 		fewvars.quick_push (var);
 	      else
 		{
diff --git a/gcc/tree.c b/gcc/tree.c
index 28e157f5fd28..e76ff12ec304 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1030,7 +1030,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:
@@ -4428,7 +4429,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 3d2bd95d6665..97c05275e90c 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 efc7947f4ab7..94375adcda84 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1204,7 +1204,7 @@ extern void protected_set_expr_location (tree, location_t);
 
 /* GOTO_EXPR accessor. This gives access to the label associated with
    a goto statement.  */
-#define GOTO_DESTINATION(NODE)  TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE)  TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
 
 /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
    instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index b324a2c97c28..8e500b144712 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9926,6 +9926,36 @@ vt_init_cfa_base (void)
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
 }
 
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
+{
+  gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
+
+  enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
+
+  switch (kind)
+    {
+    case NOTE_INSN_BEGIN_STMT:
+      {
+	rtx_insn *note = NULL;
+	if (cfun->debug_nonbind_markers)
+	  {
+	    note = emit_note_before (kind, insn);
+	    NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
+	    if (bb)
+	      BLOCK_FOR_INSN (note) = *bb;
+	  }
+	delete_insn (insn);
+	return note;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
@@ -10169,6 +10199,12 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
+		  if (DEBUG_MARKER_INSN_P (insn))
+		    {
+		      insn = reemit_marker_as_note (insn, &save_bb);
+		      continue;
+		    }
+
 		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
@@ -10245,10 +10281,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;
@@ -10264,6 +10301,12 @@ delete_debug_insns (void)
 	   insn = next)
 	if (DEBUG_INSN_P (insn))
 	  {
+	    if (DEBUG_MARKER_INSN_P (insn))
+	      {
+		insn = reemit_marker_as_note (insn, NULL);
+		continue;
+	      }
+
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
 	    if (TREE_CODE (decl) == LABEL_DECL
 		&& DECL_NAME (decl)
@@ -10289,10 +10332,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.  */
@@ -10357,15 +10403,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)
     {
@@ -10387,7 +10439,9 @@ variable_tracking_main_1 (void)
     {
       vt_finalize ();
 
-      delete_debug_insns ();
+      cfun->debug_nonbind_markers = 0;
+
+      delete_vta_debug_insns ();
 
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (4 preceding siblings ...)
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate " Alexandre Oliva
@ 2017-11-10  2:36                 ` Alexandre Oliva
  2017-12-07 22:49                   ` Jeff Law
  2017-12-27  8:00                   ` [nvptx, committed] Disable -gstatement-frontiers for nvptx Tom de Vries
  2017-11-10  2:37                 ` [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
                                   ` (3 subsequent siblings)
  9 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

Introduce a command line option to enable statement frontiers, enabled
by default in optimized builds with DWARF2+ debug information.

This patch depends on an earlier patch that completed the
infrastructure for debug markers, and on another patch that turns -g
into a negatable option prefix.

gcc/ChangeLog

	* common.opt (gstatement-frontiers): New, setting
	debug_nonbind_markers_p.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
	* toplev.c (process_options): Autodetect value for debug statement
	frontiers option.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
---
 gcc/common.opt      |  4 ++++
 gcc/doc/invoke.texi | 12 ++++++++++++
 gcc/rtl.h           |  2 +-
 gcc/toplev.c        |  4 ++++
 gcc/tree.h          |  2 +-
 5 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index f8f2ed3db8ae..421b4a2ce2a1 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2936,6 +2936,10 @@ gstabs+
 Common Driver JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format.
 
+gstatement-frontiers
+Common Driver Var(debug_nonbind_markers_p) Init(2)
+Emit progressive recommended breakpoint locations.
+
 gstrict-dwarf
 Common Driver Report Var(dwarf_strict) Init(0)
 Don't emit DWARF additions beyond selected version.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 6ff7c34cdd6c..9509c95acf14 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -346,6 +346,7 @@ 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
+-gstatement-frontiers  -gno-statement-frontiers @gol
 -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
 -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
 -fno-eliminate-unused-debug-types @gol
@@ -7081,6 +7082,17 @@ Emit location column information into DWARF debugging information, rather
 than just file and line.
 This option is enabled 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 -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 4de167d982cf..3ef687e5a371 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -816,7 +816,7 @@ struct GTY(()) rtvec_def {
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
 /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p
 /* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index eff169008d13..0b9f1f546279 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1537,6 +1537,10 @@ 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 (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/gcc/tree.h b/gcc/tree.h
index 94375adcda84..5dd653ea7f69 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1106,7 +1106,7 @@ 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 gimple_debug_nonbind_marker_p() may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p
 /* Nonzero if gimple_debug_bind_p() (and thus
    gimple_debug_source_bind_p()) may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
@ 2017-11-10  2:36                 ` Alexandre Oliva
  2017-12-07 22:46                   ` Jeff Law
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
                                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

If find_bb_boundaries is given a block with zero or one nondebug insn
beside debug insns, it shouldn't purge dead edges, because without
debug insns we wouldn't purge them at that point.  Doing so may change
the order in which edges are processed, and ultimately lead to
different transformations to the CFG and then to different
optimizations.

We shouldn't, however, retain debug insns after control flow insns, so
if we find debug insns after a single insn that happens to be a
control flow insn, do the debug insn cleanups, but still refrain from
purging dead edges at that point.


for  gcc/ChangeLog

	* cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
	without debug insns, we wouldn't, but clean up debug insns
	after a control flow insn nevertheless.
---
 gcc/cfgbuild.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 8fa15fec45e4..7b57589f1dfa 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -444,10 +444,43 @@ find_bb_boundaries (basic_block bb)
   rtx_insn *flow_transfer_insn = NULL;
   rtx_insn *debug_insn = NULL;
   edge fallthru = NULL;
+  bool skip_purge;
 
   if (insn == end)
     return;
 
+  if (DEBUG_INSN_P (insn) || DEBUG_INSN_P (end))
+    {
+      /* Check whether, without debug insns, the insn==end test above
+	 would have caused us to return immediately, and behave the
+	 same way even with debug insns.  If we don't do this, debug
+	 insns could cause us to purge dead edges at different times,
+	 which could in turn change the cfg and affect codegen
+	 decisions in subtle but undesirable ways.  */
+      while (insn != end && DEBUG_INSN_P (insn))
+	insn = NEXT_INSN (insn);
+      rtx_insn *e = end;
+      while (insn != e && DEBUG_INSN_P (e))
+	e = PREV_INSN (e);
+      if (insn == e)
+	{
+	  /* If there are debug insns after a single insn that is a
+	     control flow insn in the block, we'd have left right
+	     away, but we should clean up the debug insns after the
+	     control flow insn, because they can't remain in the same
+	     block.  So, do the debug insn cleaning up, but then bail
+	     out without purging dead edges as we would if the debug
+	     insns hadn't been there.  */
+	  if (e != end && !DEBUG_INSN_P (e) && control_flow_insn_p (e))
+	    {
+	      skip_purge = true;
+	      flow_transfer_insn = e;
+	      goto clean_up_debug_after_control_flow;
+	    }
+	  return;
+	}
+    }
+
   if (LABEL_P (insn))
     insn = NEXT_INSN (insn);
 
@@ -475,7 +508,6 @@ find_bb_boundaries (basic_block bb)
 	  if (debug_insn && code != CODE_LABEL && code != BARRIER)
 	    prev = PREV_INSN (debug_insn);
 	  fallthru = split_block (bb, prev);
-
 	  if (flow_transfer_insn)
 	    {
 	      BB_END (bb) = flow_transfer_insn;
@@ -527,6 +559,9 @@ find_bb_boundaries (basic_block bb)
      ordinary jump, we need to take care and move basic block boundary.  */
   if (flow_transfer_insn && flow_transfer_insn != end)
     {
+      skip_purge = false;
+
+    clean_up_debug_after_control_flow:
       BB_END (bb) = flow_transfer_insn;
 
       /* Clean up the bb field for the insns that do not belong to BB.  */
@@ -543,6 +578,9 @@ find_bb_boundaries (basic_block bb)
 	  if (x == end)
 	    break;
 	}
+
+      if (skip_purge)
+	return;
     }
 
   /* We've possibly replaced the conditional jump by conditional jump
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries Alexandre Oliva
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
@ 2017-11-10  2:36                 ` Alexandre Oliva
  2017-12-07 22:25                   ` Jeff Law
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
                                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:36 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

This patch removes unused RTL functions, introduces alternate ones for
use in a later SFN patch, and regroups other related functions so that
they appear in a more consistent order.

for  gcc/ChangeLog

	* 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.
	* rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
	(prev_nonnote_nondebug_insn_bb): Declare.
	(next_nonnote_nondebug_insn_bb): Declare.
	* cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
	* cfgrtl.c (get_last_bb_insn): Likewise.
	* lra.c (push_insns): Likewise.
---
 gcc/cfgbuild.c |  2 +-
 gcc/cfgrtl.c   |  4 ++--
 gcc/emit-rtl.c | 69 ++++++++++++++++++++++++++++++++--------------------------
 gcc/lra.c      |  2 +-
 gcc/rtl.h      |  4 ++--
 5 files changed, 44 insertions(+), 37 deletions(-)

diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index a0926752143d..77a221de2119 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -511,7 +511,7 @@ 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))
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index ae469088eecb..f788334ffb57 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -2281,11 +2281,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;
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index a07671164361..2823b2eb5bcd 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -3370,20 +3370,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;
@@ -3405,67 +3402,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;
     }
@@ -3473,17 +3473,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/lra.c b/gcc/lra.c
index 66fbfd5477b3..88d75c18e86c 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1805,7 +1805,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/rtl.h b/gcc/rtl.h
index 8de5a1cada5a..9cc982172f53 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3085,13 +3085,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 *);
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (5 preceding siblings ...)
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
@ 2017-11-10  2:37                 ` Alexandre Oliva
  2017-12-07 22:51                   ` Jeff Law
  2017-11-10  5:05                 ` [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views Alexandre Oliva
                                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  2:37 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

The inline_entry hook will be given a definition in a later patch.

for  gcc/ChangeLog

	* debug.h (gcc_debug_hooks): Add inline_entry.
	* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
	* debug.c (do_nothing_debug_hooks): Likewise.
	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
	(dwarf2_lineno_debug_hooks): Likewise.
---
 gcc/dbxout.c    | 2 ++
 gcc/debug.c     | 1 +
 gcc/debug.h     | 3 +++
 gcc/dwarf2out.c | 2 ++
 gcc/vmsdbgout.c | 1 +
 5 files changed, 9 insertions(+)

diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 49a858339f8c..bb0650ddcacf 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -379,6 +379,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 */
@@ -421,6 +422,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 4db94c3e675d..c0bc66764121 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -55,6 +55,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 19b27848ca8b..b521d7dbf856 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -176,6 +176,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/dwarf2out.c b/gcc/dwarf2out.c
index 1d92a6eed5dd..5fdac8269654 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2773,6 +2773,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
+  debug_nothing_tree,		/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -2813,6 +2814,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 */
diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
index 580dd2840162..83ba2aee7ad4 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -205,6 +205,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 */
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (6 preceding siblings ...)
  2017-11-10  2:37                 ` [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
@ 2017-11-10  5:05                 ` Alexandre Oliva
  2017-11-13 10:18                   ` Richard Biener
  2017-12-11 23:12                   ` Jeff Law
  2017-11-10  5:29                 ` [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
  2017-11-10 21:31                 ` SFN+LVU+IEPM v4 Alexandre Oliva
  9 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  5:05 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

This patch introduces an option to enable the generation of location
views along with location lists.  The exact format depends on the
DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
(DW_LLE_view_pair) entries in DWARF5+ loclists.

Line number tables are also affected.  If the assembler is found, at
compiler build time, to support .loc views, we use them and
assembler-computed view labels, otherwise we output compiler-generated
line number programs with conservatively-computed view labels.  In
either case, we output view information next to line number changes
when verbose assembly output is requested.

This patch requires an LVU patch that modifies the exported API of
final_scan_insn.  It also expects the entire SFN patchset to be
installed first, although SFN is not a requirement for LVU.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_locviews): New.
	* dwarf2.h (enum dwarf_location_list_entry_type): Add
	DW_LLE_GNU_view_pair.
	(DW_LLE_view_pair): Define.

for  gcc/ChangeLog

	* common.opt (gvariable-location-views): New.
	* config.in: Rebuilt.
	* configure: Rebuilt.
	* configure.ac: Test assembler for view support.
	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
	* dwarf2out.c (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.
	(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.
	(maybe_emit_file): Call output_asm_line_debug_info for test.
	(dwarf2out_var_location): Reset views as needed.  Precompute
	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
	attribute.  Set view.
	(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.
	Use output_dwarf_version.
	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
	(struct dw_val_node): Add val_view_list.
	* final.c: Include langhooks.h.
	(SEEN_NEXT_VIEW): New.
	(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.  Notify debug backend of section
	changes, and of location view changes.
	(rest_of_handle_final): Adjust.
	* opts.c (common_handle_option): Accept -gdwarf version 6.
	* toplev.c (process_options): Autodetect value for debug variable
	location views option.
	* doc/invoke.texi (gvariable-location-views): New.
	(gno-variable-location-views): New.
---
 gcc/common.opt      |   4 +
 gcc/config.in       |   6 +
 gcc/configure       |  46 ++++
 gcc/configure.ac    |  18 +-
 gcc/doc/invoke.texi |  19 ++
 gcc/dwarf2asm.c     |  25 ++
 gcc/dwarf2asm.h     |   4 +
 gcc/dwarf2out.c     | 646 ++++++++++++++++++++++++++++++++++++++++++++++------
 gcc/dwarf2out.h     |   4 +-
 gcc/final.c         | 149 +++++++++++-
 gcc/opts.c          |   2 +-
 gcc/toplev.c        |   8 +
 include/dwarf2.def  |   1 +
 include/dwarf2.h    |   8 +
 14 files changed, 858 insertions(+), 82 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 421b4a2ce2a1..f37bafce3f48 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2948,6 +2948,10 @@ gtoggle
 Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
+gvariable-location-views
+Common Driver Var(debug_variable_location_views) Init(2)
+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 5651bcba431c..e4154f666f96 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/configure b/gcc/configure
index fb40ead92046..5992d8b75ffe 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27777,6 +27777,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 0e5167695a23..c6761832071f 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4862,9 +4862,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/doc/invoke.texi b/gcc/doc/invoke.texi
index 9509c95acf14..2d574ad3d496 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -347,6 +347,7 @@ Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gcolumn-info  -gno-column-info @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
 -fno-eliminate-unused-debug-types @gol
@@ -7093,6 +7094,24 @@ 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.
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index 8e3e86f224c1..f19e6d65020e 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 7fc87a0b0c94..d8370df0ac71 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 4f808b95519c..1d92a6eed5dd 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1276,6 +1276,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.  */
@@ -1285,9 +1287,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.  */
@@ -1324,6 +1328,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.  */
@@ -1399,6 +1428,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:
@@ -2844,7 +2875,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 {
@@ -2866,6 +2905,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;
 };
 
@@ -3067,6 +3125,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
@@ -3176,6 +3269,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.  */
@@ -3384,6 +3478,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);
@@ -3420,7 +3516,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 void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -3620,8 +3716,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);
@@ -4617,11 +4713,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>
@@ -5891,7 +6031,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;
@@ -5982,7 +6122,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.  */
@@ -5998,7 +6138,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
 	    {
@@ -6133,6 +6273,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;
@@ -8993,6 +9139,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);
@@ -9364,6 +9511,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)
@@ -9638,7 +9786,8 @@ output_abbrev_section (void)
    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> ();
@@ -9648,10 +9797,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.  */
 
@@ -9660,6 +9827,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.  */
@@ -9667,34 +9927,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,
@@ -9712,6 +10023,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
@@ -9762,6 +10074,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);
@@ -9776,6 +10089,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);
@@ -9791,6 +10105,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);
@@ -9869,6 +10184,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
@@ -9933,6 +10251,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
@@ -10158,6 +10492,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))
 	    {
@@ -10342,6 +10680,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.  */
 
@@ -10358,7 +10718,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;
@@ -10570,7 +10930,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");
@@ -10869,7 +11229,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,
@@ -10951,7 +11311,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,
@@ -11212,7 +11572,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
@@ -11846,8 +12206,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)
     {
@@ -11862,14 +12225,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)
 	    {
@@ -11977,7 +12362,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");
@@ -16343,6 +16728,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;
@@ -16398,24 +16784,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)
@@ -16438,12 +16827,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;
 	      }
 	  }
@@ -16455,8 +16844,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;
 }
@@ -17276,7 +17664,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;
     }
@@ -18089,7 +18477,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;
 }
@@ -18413,12 +18801,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.  */
@@ -19600,7 +20001,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;
     }
@@ -19616,7 +20017,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;
@@ -19638,14 +20039,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;
 	}
@@ -19654,19 +20055,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;
 }
@@ -26029,7 +26429,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,
@@ -26223,11 +26623,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++;
@@ -26261,6 +26663,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
 		}
 	    }
 	}
+      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;
     }
 
@@ -26324,10 +26738,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;
     }
@@ -26368,8 +26783,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
@@ -26437,7 +26852,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)
@@ -26446,6 +26864,7 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      newloc->view = view;
     }
 
   if (var_loc_p && flag_debug_asm)
@@ -26512,6 +26931,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;
 }
@@ -26560,7 +26980,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);
@@ -26741,7 +27161,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",
@@ -26764,6 +27184,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
@@ -26772,7 +27219,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)
@@ -27447,9 +27906,10 @@ init_sections_and_labels (bool early_lto_debug)
 					    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);
+
       debug_ranges_section = get_section (dwarf_version >= 5
 					  ? DEBUG_RNGLISTS_SECTION
 					  : DEBUG_RANGES_SECTION,
@@ -27828,6 +28288,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.
@@ -28927,6 +29392,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)
@@ -28971,7 +29438,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)
@@ -29041,6 +29508,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);
@@ -29066,6 +29534,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);
@@ -29462,6 +29945,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);
@@ -29683,6 +30168,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;
@@ -29701,6 +30187,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)
@@ -29711,11 +30199,33 @@ 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));
 }
 
@@ -29740,7 +30250,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
@@ -30164,7 +30674,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,
@@ -30223,7 +30733,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 940247316d39..a7653ceb6182 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/final.c b/gcc/final.c
index b343063faa6d..c6a1d5b7e05a 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.  */
@@ -110,6 +111,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;
@@ -1752,6 +1754,66 @@ 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);
+    }
+}
+
+/* We want to emit param bindings (before the first begin_stmt) in the
+   initial view, if we are emitting views.  To that end, we may
+   consume initial notes in the function, processing them in
+   final_start_function, before signaling the beginning of the
+   prologue, rather than in final.
+
+   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.  */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+  return !DECL_IGNORED_P (current_function_decl)
+    && debug_variable_location_views
+    && insn && GET_CODE (insn) == NOTE
+    && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
+}
+
 /* 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
@@ -1759,12 +1821,15 @@ 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)
 {
   block_depth = 0;
 
@@ -1782,8 +1847,21 @@ final_start_function (rtx_insn *first, FILE *file,
   if (flag_sanitize & SANITIZE_ADDRESS)
     asan_function_start ();
 
+  rtx_insn *first = *firstp;
+  if (in_initial_view_p (first))
+    {
+      do
+	{
+	  final_scan_insn (first, file, 0, 0, seen);
+	  first = NEXT_INSN (first);
+	}
+      while (in_initial_view_p (first));
+      *firstp = first;
+    }
+
   if (!DECL_IGNORED_P (current_function_decl))
-    debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+    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);
@@ -1858,6 +1936,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 *first, FILE *file,
+		      int optimize_p ATTRIBUTE_UNUSED)
+{
+  int seen = 0;
+  final_start_function_1 (&first, file, &seen, optimize_p);
+  gcc_assert (seen == 0);
+}
+
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1987,11 +2076,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;
@@ -2058,6 +2146,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);
@@ -2074,6 +2164,23 @@ 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)
+{
+  /* Those that use the internal final_start_function_1/final_1 API
+     skip initial debug bind notes in final_start_function_1, and pass
+     the modified FIRST to final_1.  But those that use the public
+     final_start_function/final APIs, final_start_function can't move
+     FIRST because it's not passed by reference, so if they were
+     skipped there, skip them again here.  */
+  while (in_initial_view_p (first))
+    first = NEXT_INSN (first);
+
+  final_1 (first, file, 0, optimize_p);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2214,6 +2321,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 ())
@@ -2353,6 +2462,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
@@ -2409,7 +2520,10 @@ 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:
@@ -2420,6 +2534,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
 					   last_filename, last_discriminator,
 					   true);
+	      clear_next_view_needed (seen);
 	    }
 	  break;
 
@@ -2615,6 +2730,10 @@ 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
@@ -2627,7 +2746,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    (*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)
@@ -3094,7 +3218,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;
@@ -4525,8 +4650,10 @@ rest_of_handle_final (void)
     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 ();
diff --git a/gcc/opts.c b/gcc/opts.c
index ac383d48ec18..2abae2da47e5 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2364,7 +2364,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/toplev.c b/gcc/toplev.c
index 0b9f1f546279..55d6f21aaeb7 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1541,6 +1541,14 @@ process_options (void)
     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/include/dwarf2.def b/include/dwarf2.def
index 2a3b23fef873..f3fa4009207b 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* VMS extensions.  */
 DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
 /* GNAT extensions.  */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index a2e022dbdb35..fd76d82e6eb7 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -298,6 +298,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,
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (7 preceding siblings ...)
  2017-11-10  5:05                 ` [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views Alexandre Oliva
@ 2017-11-10  5:29                 ` Alexandre Oliva
  2017-12-12  2:54                   ` Alexandre Oliva
  2017-11-10 21:31                 ` SFN+LVU+IEPM v4 Alexandre Oliva
  9 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10  5:29 UTC (permalink / raw)
  To: Richard Biener, Jeff Law, Jason Merrill; +Cc: GCC Patches, Alexandre Oliva

Output DW_AT_entry_pc based on markers.

Introduce DW_AT_GNU_entry_view as a DWARF extension.

If views are enabled are we're not in strict compliance mode, output
DW_AT_GNU_entry_view if it might be nonzero.

This patch depends on SFN and LVU patchsets, and on the IEPM patch that
introduces the inline_entry debug hook.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_entry_view): New.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
	markers.
	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
	(BLOCK_INLINE_ENTRY_LABEL): New.
	(dwarf2out_var_location): Disregard inline entry markers.
	(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.
	(block_within_block_p, dwarf2out_inline_entry): New.
	(dwarf2out_finish): Check that no entries remained in
	inline_entry_data_table.
	* final.c (reemit_insn_block_notes): Handle inline entry notes.
	(final_scan_insn, notice_source_line): Likewise.
	(rest_of_clean_state): Skip inline entry markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
	markers.
	* gimple.c (gimple_build_debug_inline_entry): New.
	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_INLINE_ENTRY.
	(gimple_build_debug_inline_entry): Declare.
	(gimple_debug_inline_entry_p): New.
	(gimple_debug_nonbind_marker_p): Adjust.
	* insn-notes.def (INLINE_ENTRY): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	inline entry marker notes.
	(print_insn): Likewise.
	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
	(INSN_DEBUG_MARKER_KIND): Likewise.
	(GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT): New.
	* tree-inline.c	(expand_call_inline): Build and insert
	debug_inline_entry stmt.
	* 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.
	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
	(gimple_build_debug_inline_entry): New.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
	Enable/disable inline entry points too.
	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
	(DEBUG_INSN): Describe inline entry markers.
---
 gcc/cfgexpand.c           |   9 +++
 gcc/doc/gimple.texi       |  18 +++++
 gcc/doc/rtl.texi          |  24 ++++--
 gcc/dwarf2out.c           | 199 +++++++++++++++++++++++++++++++++++++++++++++-
 gcc/final.c               |  26 ++++++
 gcc/gimple-pretty-print.c |  13 +++
 gcc/gimple.c              |  21 +++++
 gcc/gimple.h              |  18 ++++-
 gcc/insn-notes.def        |   4 +
 gcc/print-rtl.c           |   5 ++
 gcc/rtl.h                 |   7 +-
 gcc/tree-inline.c         |   7 ++
 gcc/tree-ssa-live.c       |  27 +++++--
 gcc/var-tracking.c        |   1 +
 include/dwarf2.def        |   1 +
 15 files changed, 364 insertions(+), 16 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 3f17e90d50b3..a9531e86a662 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5715,6 +5715,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		goto delink_debug_stmt;
 	      else if (gimple_debug_begin_stmt_p (stmt))
 		val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT ();
+	      else if (gimple_debug_inline_entry_p (stmt))
+		{
+		  tree block = gimple_block (stmt);
+
+		  if (block)
+		    val = GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT ();
+		  else
+		    goto delink_debug_stmt;
+		}
 	      else
 		gcc_unreachable ();
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 492678705c6f..3825378080fa 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -836,6 +836,11 @@ Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
 a source statement.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_inline_entry_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the entry
+point of an inlined function.
+@end deftypefn
+
 @deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
 Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
 without any variable binding.
@@ -1541,6 +1546,7 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
 @cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
+@cindex @code{GIMPLE_DEBUG_INLINE_ENTRY}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
@@ -1626,6 +1632,18 @@ observable, and that none of the side effects of subsequent user
 statements are.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_inline_entry (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_INLINE_ENTRY} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that a
+function call at @code{location} underwent inline substitution, that
+@code{block} is the enclosing lexical block created for the
+substitution, and that at the point of the program in which the stmt is
+inserted, all parameters for the inlined function are bound to the
+respective arguments, and none of the side effects of its stmts are
+observable.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 898574a01ad0..8d7d32177c16 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3453,7 +3453,10 @@ Refers to a parameter that was completely optimized out.
 @item (debug_marker:@var{mode})
 Marks a program location.  With @code{VOIDmode}, it stands for the
 beginning of a statement, a recommended inspection point logically after
-all prior side effects, and before any subsequent side effects.
+all prior side effects, and before any subsequent side effects.  With
+@code{BLKmode}, it indicates an inline entry point: the lexical block
+encoded in the @code{INSN_LOCATION} is the enclosing block that encloses
+the inlined function.
 
 @end table
 
@@ -3737,6 +3740,13 @@ This note is used to generate @code{is_stmt} markers in line number
 debuggign information.  It indicates the beginning of a user
 statement.
 
+@findex NOTE_INSN_INLINE_ENTRY
+@item NOTE_INSN_INLINE_ENTRY
+This note is used to generate @code{entry_pc} for inlined subroutines in
+debugging information.  It indicates an inspection point at which all
+arguments for the inlined function have been bound, and before its first
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3754,8 +3764,12 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
-with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{GIMPLE_DEBUG_BEGIN_STMT} and @code{GIMPLE_DEBUG_INLINE_ENTRY} are
+expanded to RTL as a @code{DEBUG_INSN} with a @code{DEBUG_MARKER}
+@code{PATTERN}; the difference is the RTL mode: the former's
+@code{DEBUG_MARKER} is @code{VOIDmode}, whereas the latter is
+@code{BLKmode}; information about the inlined function can be taken from
+the lexical block encoded in the @code{INSN_LOCATION}.  These
 @code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
 just @code{DEBUG_MARKER}s, can be detected by testing
 @code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
@@ -3766,8 +3780,8 @@ 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,
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION},
+@code{NOTE_INSN_BEGIN_STMT} and @code{NOTE_INSN_INLINE_ENTRY} 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
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5fdac8269654..9e2f73525b6a 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2720,6 +2720,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);
@@ -2773,7 +2774,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
-  debug_nothing_tree,		/* inline_entry */
+  dwarf2out_inline_entry,	/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -4011,6 +4012,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
@@ -23046,6 +23050,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
@@ -23500,6 +23546,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 (MAY_HAVE_DEBUG_MARKER_INSNS);
+      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))
     {
@@ -23507,7 +23589,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 (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23672,7 +23754,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26701,6 +26783,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
       || ! 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;
 
@@ -26889,6 +26972,113 @@ create_label:
   last_in_cold_section_p = in_cold_section_p;
 }
 
+/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
+   OUTER itself.  If BOTHWAYS, check not only that BLOCK can reach
+   OUTER through BLOCK_SUPERCONTEXT links, but also that there is a
+   path from OUTER to BLOCK through BLOCK_SUBBLOCKs and
+   BLOCK_FRAGMENT_ORIGIN links.  */
+static bool
+block_within_block_p (tree block, tree outer, bool bothways)
+{
+  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;
+
+  if (!bothways)
+    return true;
+
+  /* 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)));
+
+  /* Sanity check the block tree.  This would catch a case in which
+     BLOCK got removed from the tree reachable from the outermost
+     lexical block, but got retained in markers.  It would still link
+     back to its parents, but some ancestor would be missing a link
+     down the path to the sub BLOCK.  If the block got removed, its
+     BLOCK_NUMBER will not be a usable value.  */
+  gcc_checking_assert (block_within_block_p (block,
+					     DECL_INITIAL
+					     (current_function_decl),
+					     true));
+
+  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.  */
@@ -30360,6 +30550,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 ());
diff --git a/gcc/final.c b/gcc/final.c
index c6a1d5b7e05a..afb2988f8207 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1672,6 +1672,7 @@ reemit_insn_block_notes (void)
 	    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;
 
@@ -2531,6 +2532,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  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);
@@ -2538,6 +2540,18 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    }
 	  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:
 	  gcc_unreachable ();
 	  break;
@@ -3241,6 +3255,17 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   if (NOTE_MARKER_P (insn))
     {
       location_t loc = NOTE_MARKER_LOCATION (insn);
+      /* The inline entry markers (gimple, insn, note) carry the
+	 location of the call, because that's what we want to carry
+	 during compilation, but the location we want to output in
+	 debug information for the inline entry point is the location
+	 of the function itself.  */
+      if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY)
+	{
+	  tree block = LOCATION_BLOCK (loc);
+	  tree fn = block_ultimate_origin (block);
+	  loc = DECL_SOURCE_LOCATION (fn);
+	}
       expanded_location xloc = expand_location (loc);
       if (xloc.line == 0)
 	{
@@ -4839,6 +4864,7 @@ rest_of_clean_state (void)
 	  && (!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/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 61b1f2c89cbb..5e832a78475d 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1370,6 +1370,19 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 	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 66496d002a8d..da6df9898512 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -873,6 +873,27 @@ gimple_build_debug_begin_stmt (tree block, location_t location
 }
 
 
+/* 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.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index f44887ad7a9b..e925c329a347 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -204,7 +204,8 @@ enum gf_mask {
 enum gimple_debug_subcode {
   GIMPLE_DEBUG_BIND = 0,
   GIMPLE_DEBUG_SOURCE_BIND = 1,
-  GIMPLE_DEBUG_BEGIN_STMT = 2
+  GIMPLE_DEBUG_BEGIN_STMT = 2,
+  GIMPLE_DEBUG_INLINE_ENTRY = 3
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -1456,6 +1457,7 @@ 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);
@@ -4786,13 +4788,25 @@ gimple_debug_begin_stmt_p (const gimple *s)
   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;
+    return s->subcode == GIMPLE_DEBUG_BEGIN_STMT
+      || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
 
   return false;
 }
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index 960487b31db1..252e95722447 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -71,6 +71,10 @@ 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/print-rtl.c b/gcc/print-rtl.c
index acbe2f37748a..277ef16c8499 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -259,6 +259,7 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_BEGIN_STMT:
+	case NOTE_INSN_INLINE_ENTRY:
 #ifndef GENERATOR_FILE
 	  {
 	    expanded_location xloc
@@ -1809,6 +1810,10 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 		pp_string (pp, "debug begin stmt marker");
 		break;
 
+	      case NOTE_INSN_INLINE_ENTRY:
+		pp_string (pp, "debug inline entry marker");
+		break;
+
 	      default:
 		gcc_unreachable ();
 	      }
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3ef687e5a371..63df02e0376a 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1625,7 +1625,8 @@ extern const char * const reg_note_name[];
    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_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))
@@ -1663,6 +1664,8 @@ extern const char * const reg_note_name[];
   (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
    ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
       ? NOTE_INSN_BEGIN_STMT			  \
+      : GET_MODE (PATTERN (INSN)) == BLKmode	  \
+      ? NOTE_INSN_INLINE_ENTRY			  \
       : (enum insn_note)-1) 			  \
    : (enum insn_note)-1)
 /* Create patterns for debug markers.  These and the above abstract
@@ -1672,6 +1675,8 @@ extern const char * const reg_note_name[];
    wouldn't be a problem.  */
 #define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \
   gen_rtx_DEBUG_MARKER (VOIDmode)
+#define GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT() \
+  gen_rtx_DEBUG_MARKER (BLKmode)
 
 /* The VAR_LOCATION rtx in a DEBUG_INSN.  */
 #define INSN_VAR_LOCATION(INSN) \
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index f858d426a500..8fd757fd40e6 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4631,6 +4631,13 @@ 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, input_location), GSI_NEW_STMT);
+    }
 
   if (DECL_INITIAL (fn))
     {
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 8738fe21a6e1..734d15df2c51 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/var-tracking.c b/gcc/var-tracking.c
index 8e500b144712..4f8f9f182203 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9938,6 +9938,7 @@ reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
   switch (kind)
     {
     case NOTE_INSN_BEGIN_STMT:
+    case NOTE_INSN_INLINE_ENTRY:
       {
 	rtx_insn *note = NULL;
 	if (cfun->debug_nonbind_markers)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index f3fa4009207b..8e731a3b87a6 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -444,6 +444,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
    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.  */
-- 
2.13.6

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: SFN+LVU+IEPM v4
  2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
                                   ` (8 preceding siblings ...)
  2017-11-10  5:29                 ` [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
@ 2017-11-10 21:31                 ` Alexandre Oliva
  9 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-10 21:31 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jeff Law, Jason Merrill, GCC Patches

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

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-11-10  5:05                 ` [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views Alexandre Oliva
@ 2017-11-13 10:18                   ` Richard Biener
  2017-11-15  3:59                     ` Alexandre Oliva
  2017-12-11 23:12                   ` Jeff Law
  1 sibling, 1 reply; 156+ messages in thread
From: Richard Biener @ 2017-11-13 10:18 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Jason Merrill, GCC Patches

On Fri, Nov 10, 2017 at 3:34 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> This patch introduces an option to enable the generation of location
> views along with location lists.  The exact format depends on the
> DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
> (DW_LLE_view_pair) entries in DWARF5+ loclists.
>
> Line number tables are also affected.  If the assembler is found, at
> compiler build time, to support .loc views, we use them and
> assembler-computed view labels, otherwise we output compiler-generated
> line number programs with conservatively-computed view labels.  In
> either case, we output view information next to line number changes
> when verbose assembly output is requested.
>
> This patch requires an LVU patch that modifies the exported API of
> final_scan_insn.  It also expects the entire SFN patchset to be
> installed first, although SFN is not a requirement for LVU.

What does final.c need langhooks for?  Asking because needing langhooks
at that point in time is bad (LTO, etc.).  I'd appreciate a DWARF
person reviewing
the dwarf bits, some new static fns seem to lack their toplevel comment.

The middle-end pieces are ok.

Thanks,
Richard.

> for  include/ChangeLog
>
>         * dwarf2.def (DW_AT_GNU_locviews): New.
>         * dwarf2.h (enum dwarf_location_list_entry_type): Add
>         DW_LLE_GNU_view_pair.
>         (DW_LLE_view_pair): Define.
>
> for  gcc/ChangeLog
>
>         * common.opt (gvariable-location-views): New.
>         * config.in: Rebuilt.
>         * configure: Rebuilt.
>         * configure.ac: Test assembler for view support.
>         * dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
>         * dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
>         * dwarf2out.c (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.
>         (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.
>         (maybe_emit_file): Call output_asm_line_debug_info for test.
>         (dwarf2out_var_location): Reset views as needed.  Precompute
>         add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
>         attribute.  Set view.
>         (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.
>         Use output_dwarf_version.
>         * dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
>         (struct dw_val_node): Add val_view_list.
>         * final.c: Include langhooks.h.
>         (SEEN_NEXT_VIEW): New.
>         (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.  Notify debug backend of section
>         changes, and of location view changes.
>         (rest_of_handle_final): Adjust.
>         * opts.c (common_handle_option): Accept -gdwarf version 6.
>         * toplev.c (process_options): Autodetect value for debug variable
>         location views option.
>         * doc/invoke.texi (gvariable-location-views): New.
>         (gno-variable-location-views): New.
> ---
>  gcc/common.opt      |   4 +
>  gcc/config.in       |   6 +
>  gcc/configure       |  46 ++++
>  gcc/configure.ac    |  18 +-
>  gcc/doc/invoke.texi |  19 ++
>  gcc/dwarf2asm.c     |  25 ++
>  gcc/dwarf2asm.h     |   4 +
>  gcc/dwarf2out.c     | 646 ++++++++++++++++++++++++++++++++++++++++++++++------
>  gcc/dwarf2out.h     |   4 +-
>  gcc/final.c         | 149 +++++++++++-
>  gcc/opts.c          |   2 +-
>  gcc/toplev.c        |   8 +
>  include/dwarf2.def  |   1 +
>  include/dwarf2.h    |   8 +
>  14 files changed, 858 insertions(+), 82 deletions(-)
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 421b4a2ce2a1..f37bafce3f48 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2948,6 +2948,10 @@ gtoggle
>  Common Driver Report Var(flag_gtoggle)
>  Toggle debug information generation.
>
> +gvariable-location-views
> +Common Driver Var(debug_variable_location_views) Init(2)
> +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 5651bcba431c..e4154f666f96 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/configure b/gcc/configure
> index fb40ead92046..5992d8b75ffe 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -27777,6 +27777,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 0e5167695a23..c6761832071f 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -4862,9 +4862,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/doc/invoke.texi b/gcc/doc/invoke.texi
> index 9509c95acf14..2d574ad3d496 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -347,6 +347,7 @@ Objective-C and Objective-C++ Dialects}.
>  -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
>  -gcolumn-info  -gno-column-info @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
>  -fno-eliminate-unused-debug-types @gol
> @@ -7093,6 +7094,24 @@ 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.
> diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
> index 8e3e86f224c1..f19e6d65020e 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 7fc87a0b0c94..d8370df0ac71 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 4f808b95519c..1d92a6eed5dd 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -1276,6 +1276,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.  */
> @@ -1285,9 +1287,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.  */
> @@ -1324,6 +1328,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.  */
> @@ -1399,6 +1428,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:
> @@ -2844,7 +2875,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 {
> @@ -2866,6 +2905,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;
>  };
>
> @@ -3067,6 +3125,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
> @@ -3176,6 +3269,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.  */
> @@ -3384,6 +3478,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);
> @@ -3420,7 +3516,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 void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
> @@ -3620,8 +3716,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);
> @@ -4617,11 +4713,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>
> @@ -5891,7 +6031,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;
> @@ -5982,7 +6122,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.  */
> @@ -5998,7 +6138,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
>             {
> @@ -6133,6 +6273,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;
> @@ -8993,6 +9139,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);
> @@ -9364,6 +9511,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)
> @@ -9638,7 +9786,8 @@ output_abbrev_section (void)
>     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> ();
> @@ -9648,10 +9797,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.  */
>
> @@ -9660,6 +9827,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.  */
> @@ -9667,34 +9927,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,
> @@ -9712,6 +10023,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
> @@ -9762,6 +10074,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);
> @@ -9776,6 +10089,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);
> @@ -9791,6 +10105,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);
> @@ -9869,6 +10184,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
> @@ -9933,6 +10251,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
> @@ -10158,6 +10492,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))
>             {
> @@ -10342,6 +10680,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.  */
>
> @@ -10358,7 +10718,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;
> @@ -10570,7 +10930,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");
> @@ -10869,7 +11229,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,
> @@ -10951,7 +11311,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,
> @@ -11212,7 +11572,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
> @@ -11846,8 +12206,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)
>      {
> @@ -11862,14 +12225,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)
>             {
> @@ -11977,7 +12362,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");
> @@ -16343,6 +16728,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;
> @@ -16398,24 +16784,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)
> @@ -16438,12 +16827,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;
>               }
>           }
> @@ -16455,8 +16844,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;
>  }
> @@ -17276,7 +17664,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;
>      }
> @@ -18089,7 +18477,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;
>  }
> @@ -18413,12 +18801,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.  */
> @@ -19600,7 +20001,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;
>      }
> @@ -19616,7 +20017,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;
> @@ -19638,14 +20039,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;
>         }
> @@ -19654,19 +20055,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;
>  }
> @@ -26029,7 +26429,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,
> @@ -26223,11 +26623,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++;
> @@ -26261,6 +26663,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
>                 }
>             }
>         }
> +      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;
>      }
>
> @@ -26324,10 +26738,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;
>      }
> @@ -26368,8 +26783,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
> @@ -26437,7 +26852,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)
> @@ -26446,6 +26864,7 @@ create_label:
>           last_postcall_label = ggc_strdup (loclabel);
>         }
>        newloc->label = last_postcall_label;
> +      newloc->view = view;
>      }
>
>    if (var_loc_p && flag_debug_asm)
> @@ -26512,6 +26931,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;
>  }
> @@ -26560,7 +26980,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);
> @@ -26741,7 +27161,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",
> @@ -26764,6 +27184,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
> @@ -26772,7 +27219,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)
> @@ -27447,9 +27906,10 @@ init_sections_and_labels (bool early_lto_debug)
>                                             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);
> +
>        debug_ranges_section = get_section (dwarf_version >= 5
>                                           ? DEBUG_RNGLISTS_SECTION
>                                           : DEBUG_RANGES_SECTION,
> @@ -27828,6 +28288,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.
> @@ -28927,6 +29392,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)
> @@ -28971,7 +29438,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)
> @@ -29041,6 +29508,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);
> @@ -29066,6 +29534,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);
> @@ -29462,6 +29945,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);
> @@ -29683,6 +30168,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;
> @@ -29701,6 +30187,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)
> @@ -29711,11 +30199,33 @@ 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));
>  }
>
> @@ -29740,7 +30250,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
> @@ -30164,7 +30674,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,
> @@ -30223,7 +30733,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 940247316d39..a7653ceb6182 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/final.c b/gcc/final.c
> index b343063faa6d..c6a1d5b7e05a 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.  */
> @@ -110,6 +111,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;
> @@ -1752,6 +1754,66 @@ 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);
> +    }
> +}
> +
> +/* We want to emit param bindings (before the first begin_stmt) in the
> +   initial view, if we are emitting views.  To that end, we may
> +   consume initial notes in the function, processing them in
> +   final_start_function, before signaling the beginning of the
> +   prologue, rather than in final.
> +
> +   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.  */
> +
> +static inline bool
> +in_initial_view_p (rtx_insn *insn)
> +{
> +  return !DECL_IGNORED_P (current_function_decl)
> +    && debug_variable_location_views
> +    && insn && GET_CODE (insn) == NOTE
> +    && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
> +}
> +
>  /* 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
> @@ -1759,12 +1821,15 @@ 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)
>  {
>    block_depth = 0;
>
> @@ -1782,8 +1847,21 @@ final_start_function (rtx_insn *first, FILE *file,
>    if (flag_sanitize & SANITIZE_ADDRESS)
>      asan_function_start ();
>
> +  rtx_insn *first = *firstp;
> +  if (in_initial_view_p (first))
> +    {
> +      do
> +       {
> +         final_scan_insn (first, file, 0, 0, seen);
> +         first = NEXT_INSN (first);
> +       }
> +      while (in_initial_view_p (first));
> +      *firstp = first;
> +    }
> +
>    if (!DECL_IGNORED_P (current_function_decl))
> -    debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
> +    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);
> @@ -1858,6 +1936,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 *first, FILE *file,
> +                     int optimize_p ATTRIBUTE_UNUSED)
> +{
> +  int seen = 0;
> +  final_start_function_1 (&first, file, &seen, optimize_p);
> +  gcc_assert (seen == 0);
> +}
> +
>  static void
>  profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
>  {
> @@ -1987,11 +2076,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;
> @@ -2058,6 +2146,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);
> @@ -2074,6 +2164,23 @@ 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)
> +{
> +  /* Those that use the internal final_start_function_1/final_1 API
> +     skip initial debug bind notes in final_start_function_1, and pass
> +     the modified FIRST to final_1.  But those that use the public
> +     final_start_function/final APIs, final_start_function can't move
> +     FIRST because it's not passed by reference, so if they were
> +     skipped there, skip them again here.  */
> +  while (in_initial_view_p (first))
> +    first = NEXT_INSN (first);
> +
> +  final_1 (first, file, 0, optimize_p);
> +}
>
>  const char *
>  get_insn_template (int code, rtx insn)
> @@ -2214,6 +2321,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 ())
> @@ -2353,6 +2462,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
> @@ -2409,7 +2520,10 @@ 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:
> @@ -2420,6 +2534,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>               (*debug_hooks->source_line) (last_linenum, last_columnnum,
>                                            last_filename, last_discriminator,
>                                            true);
> +             clear_next_view_needed (seen);
>             }
>           break;
>
> @@ -2615,6 +2730,10 @@ 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
> @@ -2627,7 +2746,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
>             (*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)
> @@ -3094,7 +3218,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;
> @@ -4525,8 +4650,10 @@ rest_of_handle_final (void)
>      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 ();
> diff --git a/gcc/opts.c b/gcc/opts.c
> index ac383d48ec18..2abae2da47e5 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2364,7 +2364,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/toplev.c b/gcc/toplev.c
> index 0b9f1f546279..55d6f21aaeb7 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -1541,6 +1541,14 @@ process_options (void)
>      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/include/dwarf2.def b/include/dwarf2.def
> index 2a3b23fef873..f3fa4009207b 100644
> --- a/include/dwarf2.def
> +++ b/include/dwarf2.def
> @@ -443,6 +443,7 @@ 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)
>  /* VMS extensions.  */
>  DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
>  /* GNAT extensions.  */
> diff --git a/include/dwarf2.h b/include/dwarf2.h
> index a2e022dbdb35..fd76d82e6eb7 100644
> --- a/include/dwarf2.h
> +++ b/include/dwarf2.h
> @@ -298,6 +298,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,
> --
> 2.13.6
>

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-11-13 10:18                   ` Richard Biener
@ 2017-11-15  3:59                     ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-11-15  3:59 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jeff Law, Jason Merrill, GCC Patches

On Nov 13, 2017, Richard Biener <richard.guenther@gmail.com> wrote:

> What does final.c need langhooks for?

Thanks for catching this.

At some point I had a check on whether there could be being stmt markers
emitted by the language, but that's long gone, in part because of LTO;
that's now computed dynamically, on a per-function basis, so the check
was modified to match, but the include added back then lingered.
Consider it gone (I'm dropping it in the SFN and SLI branches, so it
won't be in the next version of the patchset)

> I'd appreciate a DWARF person reviewing the dwarf bits, some new
> static fns seem to lack their toplevel comment.

Thanks for pointing this out.  I've added the following comments:


/* Return true iff we're to emit .loc directives for the assembler to
   generate line number sections.  */

>> +output_asm_line_debug_info (void)


/* Add a view list attribute to DIE.  It must have a DW_AT_location
   attribute, because the view list complements the location list.  */

>> +add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind)


/* Return a pointer to the location list referenced by the attribute.
   If the named attribute is a view list, look up the corresponding
   DW_AT_location attribute and return its location list.  */

>> AT_loc_list_ptr (dw_attr_node *a)


/* Return the location attribute value associated with a view list
   attribute value.  */

>> +view_list_to_loc_list_val_node (dw_val_node *val)


> The middle-end pieces are ok.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
@ 2017-12-07 22:25                   ` Jeff Law
  2017-12-12  3:10                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 22:25 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> This patch removes unused RTL functions, introduces alternate ones for
> use in a later SFN patch, and regroups other related functions so that
> they appear in a more consistent order.
> 
> for  gcc/ChangeLog
> 
> 	* 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.
> 	* rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
> 	(prev_nonnote_nondebug_insn_bb): Declare.
> 	(next_nonnote_nondebug_insn_bb): Declare.
> 	* cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
> 	* cfgrtl.c (get_last_bb_insn): Likewise.
> 	* lra.c (push_insns): Likewise.
OK.  Seems like this ought to go in immediately rather than waiting on
the full kit to be ack'd.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
@ 2017-12-07 22:27                   ` Jeff Law
  2017-12-12  2:55                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 22:27 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> This patch introduces a number of new macros and functions that will
> be used to distinguish between different kinds of debug stmts, insns
> and notes, namely, preexisting debug bind ones and to-be-introduced
> nonbind markers.
> 
> In a seemingly mechanical way, it adjusts several uses of the macros
> and functions, so that they refer to narrower categories when
> appropriate.
> 
> These changes, by themselves, should not have any visible effect in
> the compiler behavior, since the upcoming debug markers are never
> created with this patch alone.
> 
> for  gcc/ChangeLog
> 
> 	* gimple.h (enum gimple_debug_subcode): Add
> 	GIMPLE_DEBUG_BEGIN_STMT.
> 	(gimple_debug_begin_stmt_p): New.
> 	(gimple_debug_nonbind_marker_p): New.
> 	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
> 	(MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
> 	(MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
> 	* insn-notes.def (BEGIN_STMT): New.
> 	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
> 	(MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
> 	(MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
> 	(NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
> 	(DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
> 	(INSN_DEBUG_MARKER_KIND): New.
> 	(GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT): New.
> 	(INSN_VAR_LOCATION): Check for VAR_LOCATION.
> 	(INSN_VAR_LOCATION_PTR): New.
> 	* cfgexpand.c (expand_debug_locations): Handle debug bind insns
> 	only.
> 	(expand_gimple_basic_block): Likewise.  Emit debug temps for TER
> 	deps only if debug bind insns are enabled.
> 	(pass_expand::execute): Avoid deep TER and expand
> 	debug locations for debug bind insns only.
> 	* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
> 	debug stmts special handling down to debug bind stmts.
> 	* combine.c (try_combine): Narrow debug insns special handling
> 	down to debug bind insns.
> 	* cse.c (delete_trivially_dead_insns): Handle debug bindings.
> 	Narrow debug insns preexisting special handling down to debug
> 	bind insns.
> 	* dce.c (rest_of_handle_ud_dce): Narrow debug insns special
> 	handling down to debug bind insns.
> 	* function.c (instantiate_virtual_regs): Skip debug markers,
> 	adjust handling of debug binds.
> 	* gimple-ssa-backprop.c (backprop::prepare_change): Try debug
> 	temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
> 	* haifa-sched.c (schedule_insn): Narrow special handling of debug
> 	insns to debug bind insns.
> 	* ipa-param-manipulation.c (ipa_modify_call_arguments): Narrow
> 	special handling of debug stmts to debug bind stmts.
> 	* ipa-split.c (split_function): Likewise.
> 	* ira.c (combine_and_move_insns): Adjust debug bind insns only.
> 	* loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
> 	debug insns.
> 	* reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
> 	* regrename.c (build_def_use): Likewise.
> 	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
> 	(pass_cprop_hardreg): Narrow special casing of debug insns to
> 	debug bind insns.
> 	* regstat.c (regstat_init_n_sets_and_refs): Likewise.
> 	* reload1.c (reload): Likewise.
> 	* sese.c (sese_insert_phis_for_liveouts): Narrow special
> 	casing of debug stmts to debug bind stmts.
> 	* shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
> 	* ssa-iterators.h (num_imm_uses): Likewise.
> 	* tree-cfg.c (gimple_merge_blocks): Narrow special casing of
> 	debug stmts to debug bind stmts.
> 	* tree-inline.c	(tree_function_versioning): Narrow special casing
> 	of debug stmts to debug bind stmts.
> 	* tree-loop-distribution.c (generate_loops_for_partition):
> 	Narrow special casing of debug stmts to debug bind stmts.
> 	* tree-sra.c (analyze_access_subtree): Narrow special casing
> 	of debug stmts to debug bind stmts.
> 	* tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
> 	stmts to debug bind stmts.
> 	* tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
> 	casing of debug stmts to debug bind stmts.
> 	* tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
> 	* tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
> 	casing of debug stmts to debug bind stmts.
> 	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
> 	Likewise.
> 	* tree-ssa.c (flush_pending_stmts): Narrow special casing of
> 	debug stmts to debug bind stmts.
> 	(gimple_replace_ssa_lhs): Likewise.
> 	(insert_debug_temp_for_var_def): Likewise.
> 	(insert_debug_temps_for_defs): Likewise.
> 	(reset_debug_uses): Likewise.
> 	* tree-ssanames.c (release_ssa_name_fn): Likewise.
> 	* tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
> 	(adjust_debug_stmts): Likewise.
> 	(adjust_phi_and_debug_stmts): Likewise.
> 	(vect_do_peeling): Likewise.
> 	* tree-vect-loop.c (vect_transform_loop): Likewise.
> 	* valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
> 	* var-tracking.c (adjust_mems): Narrow special casing of debug
> 	insns to debug bind insns.
> 	(dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
> 	(compute_bb_dataflow, vt_find_locations): Likewise.
> 	(vt_expand_loc, emit_notes_for_changes): Likewise.
> 	(vt_init_cfa_base): Likewise.
> 	(vt_emit_notes): Likewise.
> 	(vt_initialize): Likewise.
> 	(vt_finalize): Likewise.

OK.  Again, I think this can probably go in as-is.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate " Alexandre Oliva
@ 2017-12-07 22:44                   ` Jeff Law
  2017-12-12  2:31                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 22:44 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> This patch adjusts numerous parts of the compiler that would
> malfunction should they find debug markers at points where they may be
> introduced.  The changes purport to allow the compiler to pass
> bootstrap-debug-lean (-fcompare-debug in stage3) at various
> optimization levels, as well as bootstrap-debug-lib (-fcompare-debug
> for target libraries), even after the compiler is changed so that
> debug markers are introduced in code streams at spots where earlier
> debug stmts, insns and notes wouldn't normally appear.
> 
> This patch depends on an earlier SFN boilerplate patch, and on another
> SFN patch that introduces new RTL insn-walking functions.
> 
> for  gcc/ChangeLog
> 
> 	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
> 	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
> 	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
> 	* cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
> 	(rtl_tidy_fallthru_edge): Likewise.
> 	(rtl_verify_fallthru): Likewise.
> 	(rtl_verify_bb_layout): Likewise.
> 	(skip_insns_after_block): Likewise.
> 	(duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
> 	* dwarf2out.c: Include print-rtl.h.
> 	(dwarf2out_next_real_insn): New.
> 	(dwarf2out_var_location): Call it.  Disregard begin stmt markers.
> 	Dump debug binds in asm comments.
> 	* gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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 (gimple_seq_may_fallthru): Take last nondebug stmt.
> 	* gimple.h (gimple_seq_last_nondebug_stmt): New.
> 	* gimplify.c (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.
> 	* graphite-isl-ast-to-gimple.c (gsi_insert_earliest): Adjust.
> 	(graphite_copy_stmts_from_block): Skip nonbind markers.
> 	* haifa-sched.c (sched_extend_bb): Skip debug insns.
> 	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
> 	* jump.c (clean_barriers): Skip debug insns.
> 	* 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.
> 	* postreload.c (fixup_debug_insns): Skip nonbind debug insns.
> 	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
> 	* sese.c (sese_trivially_empty_bb_p): Call is_gimple_debug in
> 	test.
> 	* 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
> 	* var-tracking.c (get_first_insn): New.
> 	(vt_emit_notes): Call it.
> 	(vt_initialize): Walk any insns before the first BB.
> 	(delete_debug_insns): Likewise.
OK.

As I read through this my first thought is that we're way too lose with
how we find the first/last statement by not taking into account
debugging info.  And the more debugging markers we add, the more likely
it is that we'll expose goofs in this area.  Thank goodness we've got a
stronger bootstrap check for subtle codgen differences when debuginfo is
included.

In general, I assumed that anytime you changed from something like
gsi_last to gsi_last_nondebug or gsi_prev to gsi_prev_nondebug that it
was the right thing to do :-)


I'll note you may need minor tweaks due to the Cilk+ removal.  THose
changes are pre-approved.

Commit when prereqs are ack'd.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries Alexandre Oliva
@ 2017-12-07 22:46                   ` Jeff Law
  2017-12-12  2:38                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 22:46 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> If find_bb_boundaries is given a block with zero or one nondebug insn
> beside debug insns, it shouldn't purge dead edges, because without
> debug insns we wouldn't purge them at that point.  Doing so may change
> the order in which edges are processed, and ultimately lead to
> different transformations to the CFG and then to different
> optimizations.
> 
> We shouldn't, however, retain debug insns after control flow insns, so
> if we find debug insns after a single insn that happens to be a
> control flow insn, do the debug insn cleanups, but still refrain from
> purging dead edges at that point.
> 
> 
> for  gcc/ChangeLog
> 
> 	* cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
> 	without debug insns, we wouldn't, but clean up debug insns
> 	after a control flow insn nevertheless.
OK.  Seems to me like it's independent of the rest of the work and
should go in immediately.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
@ 2017-12-07 22:49                   ` Jeff Law
  2017-12-12  2:42                     ` Alexandre Oliva
  2017-12-27  8:00                   ` [nvptx, committed] Disable -gstatement-frontiers for nvptx Tom de Vries
  1 sibling, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 22:49 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> Introduce a command line option to enable statement frontiers, enabled
> by default in optimized builds with DWARF2+ debug information.
> 
> This patch depends on an earlier patch that completed the
> infrastructure for debug markers, and on another patch that turns -g
> into a negatable option prefix.
> 
> gcc/ChangeLog
> 
> 	* common.opt (gstatement-frontiers): New, setting
> 	debug_nonbind_markers_p.
> 	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
> 	* toplev.c (process_options): Autodetect value for debug statement
> 	frontiers option.
> 	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
> 	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
OK once all prereqs are ack'd.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers
  2017-11-10  2:37                 ` [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
@ 2017-12-07 22:51                   ` Jeff Law
  2017-12-12  2:44                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 22:51 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> The inline_entry hook will be given a definition in a later patch.
> 
> for  gcc/ChangeLog
> 
> 	* debug.h (gcc_debug_hooks): Add inline_entry.
> 	* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
> 	* debug.c (do_nothing_debug_hooks): Likewise.
> 	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
> 	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
> 	(dwarf2_lineno_debug_hooks): Likewise.
OK.
jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
@ 2017-12-07 23:59                   ` Jeff Law
  2017-12-12  2:41                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-07 23:59 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: GCC Patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> This patch completes the infrastructure for the introduction of
> statement frontiers in C-family languages.
> 
> It brings in all the code remaining code needed to introduce and
> transform begin stmt trees, gimple stmts, insns and notes, and
> ultimately use them to generate the is_stmt column in DWARF2+ line
> number tables/programs, however none of it is activated: the option
> that would do so will be introduced in a subsequent patch.
> 
> This patch depends on an earlier patch with not-quite-boilerplate
> changes towards SFN.
> 
> 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 (check_constexpr_ctor_body_1): Skip begin stmt
> 	markers.
> 	(constexpr_fn_retval): Likewise.
> 	(potential_constant_expression_1): Likewise.
> 	(cxx_eval_statement_list): Check that a begin stmt marker is
> 	not used as the value of a statement list.
> 	(cxx_eval_constant_expression): Return begin stmt markers
> 	unchanged.
> 	* cp-array-notation.c (stmt_location): New.
> 	(cp_expand_cond_array_notations): Use it.
> 	* cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
> 	* parser.c (add_debug_begin_stmt): New.
> 	(cp_parser_statement): Call it.
> 	* pt.c (tsubst_copy): Handle begin stmt markers.
> 
> for  gcc/ChangeLog
> 
> 	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
> 	markers.  Integrate source bind into debug stmt expand loop.
> 	(pass_expand::execute): Check debug marker limit.  Avoid deep
> 	TER and expand debug locations for debug bind insns only.
> 	* cse.c (insn_live_p): Keep nonbind markers and debug bindings
> 	followed by them.
> 	* df-scan.c (df_insn_delete): Accept out-of-block debug insn.
> 	* final.c (reemit_insn_block_notes): Take current block from
> 	nonbind markers.  Declare note where it's first set.
> 	(final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
> 	begin stmt markers if enabled.
> 	(notice_source_line): Handle nonbind markers.  Fail if their
> 	location is unknown or that of builtins.
> 	(rest_of_handle_final): Convert begin stmt markers to notes if
> 	var-tracking didn't run.
> 	(rest_of_clean_state): Skip begin stmt markers.
> 	* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
> 	markers.
> 	* function.c (allocate_struct_function): Set begin_stmt_markers.
> 	* function.h (struct function): Add debug_marker_count counter
> 	and debug_nonbind_markers flag.
> 	* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
> 	* gimple-low.c (lower_function_body): Adjust
> 	debug_nonbind_markers.
> 	(lower_stmt): Drop or skip gimple debug stmts.
> 	(lower_try_catch): Skip debug stmts.
> 	* gimple.c (gimple_build_debug_begin_stmt): New.
> 	(gimple_copy): Increment debug_marker_count if copying one.
> 	* gimple.h (gimple_build_debug_begin_stmt): Declare.
> 	* gimplify.c (rexpr_location): New.
> 	(rexpr_has_location): New.
> 	(warn_switch_unreachable_r): Handle gimple debug stmts.
> 	(shortcut_cond_r): Call expr_location.
> 	(find_goto): New.
> 	(find_goto_label): New.
> 	(shortcut_cond_expr): Call expr_has_location, expr_location, and
> 	find_goto_label.
> 	(gimplify_cond_expr): Call find_goto_label, expr_has_location, and
> 	expr_location.
> 	(gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
> 	* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
> 	(LANG_HOOKS_INITIALIZER): ... this.
> 	* langhooks.h (struct lang_hooks): Add emits_begin_stmt.
> 	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
> 	debug insns.
> 	(update_ebb_live_info): Skip debug insn markers.
> 	* lra.c (debug_insn_static_data): Rename to...
> 	(debug_bind_static_data): ... this.
> 	(debug_marker_static_data): New.
> 	(lra_set_insn_recog_data): Select one of the above depending
> 	on debug insn kind.
> 	(lra_update_isn_regno_info): Don't assume debug insns have
> 	freqs.
> 	(push_insns): Skip debug insns.
> 	* lto-streamer-in.c (input_function): Drop debug stmts
> 	depending on active options.  Adjust debug_nonbind_markers.
> 	* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
> 	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
> 	begin stmt marker notes.
> 	(print_insn): Likewise.
> 	* recog.c (extract_insn): Recognize rtl for debug markers.
> 	* rtl.def (DEBUG_MARKER): New.
> 	* tree-inline.c: Include params.h.
> 	(remap_gimple_stmt): Handle nonbind markers.
> 	(maybe_move_debug_stmts_to_successors): Likewise.
> 	(copy_debug_stmt): Likewise.
> 	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
> 	markers regardless of no side effects.
> 	(tsi_link_before): Don't update container's side effects when adding
> 	a begin stmt marker.
> 	(tsi_link_after): Likewise.
> 	(expr_first): Skip begin stmt markers.
> 	(expr_last): Likewise.
> 	* tree-pretty-print (dump_generic_node): Handle begin stmt markers.
> 	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
> 	Disregard nonbind markers.
> 	* tree.c (make_node_stat): Don't set side effects for begin stmt
> 	markers.
> 	(build1_stat): Likewise.
> 	* tree.def (DEBUG_BEGIN_STMT): New.
> 	* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
> 	* var-tracking.c (delete_debug_insns): Renamed to...
> 	(delete_vta_debug_insns): ... this.
> 	(reemit_marker_as_note): New.
> 	(vt_initialize): Reemit markers.
> 	(delete_vta_debug_insns): Likewise.
> 	(vt_debug_insns_local): Reemit or delete markers.
> 	(variable_tracking_main_1): Likewise.
> 	* doc/generic.texi (DEBUG_BEGIN_STMT): Document.
> 	* doc/gimple.texi (gimple_debug_begin_stmt_p): New.
> 	(gimple_debug_nonbind_marker_p): New.
> 	(gimple_build_debug_bind): Adjust.
> 	(gimple_build_debug_begin_stmt): New.
> 	* doc/invoke.texi (max-debug-marker-count): New param.
> 	* doc/rtl.texi (debug_implicit_ptr, entry_value): New.
> 	(debug_parameter_ref, debug_marker): New.
> 	(NOTE_INSN_BEGIN_STMT): New.
> 	(DEBUG_INSN): Describe begin stmt markers.
Note I expect minor updates will be necessary due to the Cilk+ removal.
Such changes are pre-approved.

ok

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-11-10  5:05                 ` [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views Alexandre Oliva
  2017-11-13 10:18                   ` Richard Biener
@ 2017-12-11 23:12                   ` Jeff Law
  2017-12-12  2:52                     ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-11 23:12 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jason Merrill; +Cc: Jakub Jelinek, gcc-patches

On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
> This patch introduces an option to enable the generation of location
> views along with location lists.  The exact format depends on the
> DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
> (DW_LLE_view_pair) entries in DWARF5+ loclists.
> 
> Line number tables are also affected.  If the assembler is found, at
> compiler build time, to support .loc views, we use them and
> assembler-computed view labels, otherwise we output compiler-generated
> line number programs with conservatively-computed view labels.  In
> either case, we output view information next to line number changes
> when verbose assembly output is requested.
> 
> This patch requires an LVU patch that modifies the exported API of
> final_scan_insn.  It also expects the entire SFN patchset to be
> installed first, although SFN is not a requirement for LVU.
> 
> for  include/ChangeLog
> 
> 	* dwarf2.def (DW_AT_GNU_locviews): New.
> 	* dwarf2.h (enum dwarf_location_list_entry_type): Add
> 	DW_LLE_GNU_view_pair.
> 	(DW_LLE_view_pair): Define.
> 
> for  gcc/ChangeLog
> 
> 	* common.opt (gvariable-location-views): New.
> 	* config.in: Rebuilt.
> 	* configure: Rebuilt.
> 	* configure.ac: Test assembler for view support.
> 	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
> 	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
> 	* dwarf2out.c (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.
> 	(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.
> 	(maybe_emit_file): Call output_asm_line_debug_info for test.
> 	(dwarf2out_var_location): Reset views as needed.  Precompute
> 	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
> 	attribute.  Set view.
> 	(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.
> 	Use output_dwarf_version.
> 	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
> 	(struct dw_val_node): Add val_view_list.
> 	* final.c: Include langhooks.h.
> 	(SEEN_NEXT_VIEW): New.
> 	(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.  Notify debug backend of section
> 	changes, and of location view changes.
> 	(rest_of_handle_final): Adjust.
> 	* opts.c (common_handle_option): Accept -gdwarf version 6.
> 	* toplev.c (process_options): Autodetect value for debug variable
> 	location views option.
> 	* doc/invoke.texi (gvariable-location-views): New.
> 	(gno-variable-location-views): New.
> ---
> diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
> index 8e3e86f224c1..f19e6d65020e 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, ...)
Needs a function comment.  Yes I realize others are missing in that
file.  But I think it's best to avoid making the problem worse.

The stuff outside dwarf2*.c is OK.  We really need Jason or Jakub to
comment on the meat of the dwarf2 bits.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers
  2017-12-07 22:44                   ` Jeff Law
@ 2017-12-12  2:31                     ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:31 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> This patch adjusts numerous parts of the compiler that would
> OK.


> I'll note you may need minor tweaks due to the Cilk+ removal.  THose
> changes are pre-approved.

Thanks, here's what I've just installed:

From bce107d7e689174f402f931b34071ab12b0262cb Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:15:30 +0000
Subject: [PATCH 3/7] [SFN] not-quite-boilerplate changes in preparation to
 introduce nonbind markers

This patch adjusts numerous parts of the compiler that would
malfunction should they find debug markers at points where they may be
introduced.  The changes purport to allow the compiler to pass
bootstrap-debug-lean (-fcompare-debug in stage3) at various
optimization levels, as well as bootstrap-debug-lib (-fcompare-debug
for target libraries), even after the compiler is changed so that
debug markers are introduced in code streams at spots where earlier
debug stmts, insns and notes wouldn't normally appear.

This patch depends on an earlier SFN boilerplate patch, and on another
SFN patch that introduces new RTL insn-walking functions.

for  gcc/ChangeLog

	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
	* cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
	(rtl_tidy_fallthru_edge): Likewise.
	(rtl_verify_fallthru): Likewise.
	(rtl_verify_bb_layout): Likewise.
	(skip_insns_after_block): Likewise.
	(duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
	* dwarf2out.c: Include print-rtl.h.
	(dwarf2out_next_real_insn): New.
	(dwarf2out_var_location): Call it.  Disregard begin stmt markers.
	Dump debug binds in asm comments.
	* gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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-loop-interchange.c (find_deps_in_bb_for_stmt): Adjust.
	(proper_loop_form_for_interchange): Adjust.
	* gimple-low.c (gimple_seq_may_fallthru): Take last nondebug stmt.
	* gimple.h (gimple_seq_last_nondebug_stmt): New.
	* gimplify.c (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.
	* graphite-isl-ast-to-gimple.c (gsi_insert_earliest): Adjust.
	(graphite_copy_stmts_from_block): Skip nonbind markers.
	* haifa-sched.c (sched_extend_bb): Skip debug insns.
	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
	* jump.c (clean_barriers): Skip debug insns.
	* omp-expand.c (expand_parallel_call): Skip debug insns.
	(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_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.
	* postreload.c (fixup_debug_insns): Skip nonbind debug insns.
	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
	* sese.c (sese_trivially_empty_bb_p): Call is_gimple_debug in
	test.
	* 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
	* var-tracking.c (get_first_insn): New.
	(vt_emit_notes): Call it.
	(vt_initialize): Walk any insns before the first BB.
	(delete_debug_insns): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255566 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                    |  83 +++++++++++++++++++++
 gcc/cfgbuild.c                   |   1 +
 gcc/cfgcleanup.c                 |  12 +--
 gcc/cfgexpand.c                  |  24 +++++-
 gcc/cfgrtl.c                     |  18 +++--
 gcc/dwarf2out.c                  |  38 +++++++++-
 gcc/gimple-iterator.c            |  24 +++++-
 gcc/gimple-iterator.h            |  46 +++++++-----
 gcc/gimple-loop-interchange.cc   |   4 +-
 gcc/gimple-low.c                 |   2 +-
 gcc/gimple.h                     |  16 ++++
 gcc/gimplify.c                   |  23 +++---
 gcc/graphite-isl-ast-to-gimple.c |   7 +-
 gcc/haifa-sched.c                |   2 +-
 gcc/ipa-icf-gimple.c             |   4 +-
 gcc/jump.c                       |   2 +-
 gcc/omp-expand.c                 | 153 ++++++++++++++++++++-------------------
 gcc/omp-low.c                    |   2 +
 gcc/postreload.c                 |   2 +-
 gcc/regcprop.c                   |   2 +
 gcc/sese.c                       |   2 +-
 gcc/tree-cfg.c                   |  52 +++++++++++--
 gcc/tree-cfgcleanup.c            |  31 +++-----
 gcc/tree-pretty-print.c          |   5 +-
 gcc/tree-ssa-dce.c               |   6 +-
 gcc/tree-ssa-tail-merge.c        |   4 +-
 gcc/var-tracking.c               |  54 +++++++++++++-
 27 files changed, 447 insertions(+), 172 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 286a0fbac94c..03ad41c3e27a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,88 @@
 2017-12-12  Alexandre Oliva <aoliva@redhat.com>
 
+	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
+	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
+	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
+	* cfgrtl.c (try_redirect_by_replacing_jump): Skip debug insns.
+	(rtl_tidy_fallthru_edge): Likewise.
+	(rtl_verify_fallthru): Likewise.
+	(rtl_verify_bb_layout): Likewise.
+	(skip_insns_after_block): Likewise.
+	(duplicate_insn_chain): Use DEBUG_BIND_INSN_P.
+	* dwarf2out.c: Include print-rtl.h.
+	(dwarf2out_next_real_insn): New.
+	(dwarf2out_var_location): Call it.  Disregard begin stmt markers.
+	Dump debug binds in asm comments.
+	* gimple-iterator.c (gimple_find_edge_insert_loc): Skip 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-loop-interchange.c (find_deps_in_bb_for_stmt): Adjust.
+	(proper_loop_form_for_interchange): Adjust.
+	* gimple-low.c (gimple_seq_may_fallthru): Take last nondebug stmt.
+	* gimple.h (gimple_seq_last_nondebug_stmt): New.
+	* gimplify.c (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.
+	* graphite-isl-ast-to-gimple.c (gsi_insert_earliest): Adjust.
+	(graphite_copy_stmts_from_block): Skip nonbind markers.
+	* haifa-sched.c (sched_extend_bb): Skip debug insns.
+	* ipa-icf-gimple.c (func_checker::compare_bb): Adjust.
+	* jump.c (clean_barriers): Skip debug insns.
+	* omp-expand.c (expand_parallel_call): Skip debug insns.
+	(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_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.
+	* postreload.c (fixup_debug_insns): Skip nonbind debug insns.
+	* regcprop.c (find_oldest_value_reg): Ensure REGNO is not a pseudo.
+	* sese.c (sese_trivially_empty_bb_p): Call is_gimple_debug in
+	test.
+	* 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-pretty-print (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-tail-merge.c (find_duplicate): Skip debug stmts.
+	* var-tracking.c (get_first_insn): New.
+	(vt_emit_notes): Call it.
+	(vt_initialize): Walk any insns before the first BB.
+	(delete_debug_insns): Likewise.
+
 	* gimple.h (enum gimple_debug_subcode): Add
 	GIMPLE_DEBUG_BEGIN_STMT.
 	(gimple_debug_begin_stmt_p): New.
diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 77a221de2119..8fa15fec45e4 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -475,6 +475,7 @@ find_bb_boundaries (basic_block bb)
 	  if (debug_insn && code != CODE_LABEL && code != BARRIER)
 	    prev = PREV_INSN (debug_insn);
 	  fallthru = split_block (bb, prev);
+
 	  if (flow_transfer_insn)
 	    {
 	      BB_END (bb) = flow_transfer_insn;
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 4734d3eae17e..754e52fe799a 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -3037,13 +3037,13 @@ delete_unreachable_blocks (void)
 
   find_unreachable_blocks ();
 
-  /* When we're in GIMPLE mode and there may be debug insns, we should
-     delete blocks in reverse dominator order, so as to get a chance
-     to substitute all released DEFs into debug stmts.  If we don't
-     have dominators information, walking blocks backward gets us a
-     better chance of retaining most debug information than
+  /* When we're in GIMPLE mode and there may be debug bind insns, we
+     should delete blocks in reverse dominator order, so as to get a
+     chance to substitute all released DEFs into debug bind stmts.  If
+     we don't have dominators information, walking blocks backward
+     gets us a better chance of retaining most debug information than
      otherwise.  */
-  if (MAY_HAVE_DEBUG_INSNS && current_ir_type () == IR_GIMPLE
+  if (MAY_HAVE_DEBUG_BIND_INSNS && current_ir_type () == IR_GIMPLE
       && dom_info_available_p (CDI_DOMINATORS))
     {
       for (b = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index b1646a5ec507..3ee242df6b98 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2327,6 +2327,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;
@@ -5454,7 +5457,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;
@@ -5495,18 +5498,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)
@@ -5521,6 +5532,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);
@@ -5528,7 +5540,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))
     {
@@ -5536,6 +5549,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
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index eb673a1e0799..b127ea1a0b38 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
@@ -1750,7 +1750,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.
@@ -2905,7 +2905,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);
@@ -2927,7 +2927,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;
@@ -2954,6 +2954,7 @@ rtl_verify_bb_layout (void)
 	    {
 	    case BARRIER:
 	    case NOTE:
+	    case DEBUG_INSN:
 	      break;
 
 	    case CODE_LABEL:
@@ -2972,7 +2973,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))
@@ -3389,6 +3391,9 @@ skip_insns_after_block (basic_block bb)
 	  last_insn = insn;
 	  continue;
 
+	case DEBUG_INSN:
+	  continue;
+
 	case NOTE:
 	  switch (NOTE_KIND (insn))
 	    {
@@ -4141,7 +4146,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 (DEBUG_BIND_INSN_P (insn)
+	      && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
 	    break;
 	  /* FALLTHRU */
 	case INSN:
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 876e53f234fa..82c9ccfa7c25 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"
@@ -26210,6 +26211,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.  */
@@ -26258,7 +26275,7 @@ 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;
@@ -26288,11 +26305,12 @@ 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_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)
     {
@@ -26451,6 +26469,22 @@ create_label:
       newloc->label = last_postcall_label;
     }
 
+  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;
 }
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 9841eb14784a..1e87825a20f8 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -739,9 +739,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 +780,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 70f18beceffc..167edc18db5b 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-loop-interchange.cc b/gcc/gimple-loop-interchange.cc
index e80e65c69da0..1d1cf96c8123 100644
--- a/gcc/gimple-loop-interchange.cc
+++ b/gcc/gimple-loop-interchange.cc
@@ -827,7 +827,7 @@ find_deps_in_bb_for_stmt (gimple_seq *stmts, basic_block bb, gimple *consumer)
 	}
       gimple_set_plf (stmt, GF_PLF_1, true);
     }
-  for (gsi = gsi_start_bb_nondebug (bb);
+  for (gsi = gsi_start_nondebug_bb (bb);
        !gsi_end_p (gsi) && (stmt = gsi_stmt (gsi)) != consumer;)
     {
       /* Move dep stmts to sequence STMTS.  */
@@ -1749,7 +1749,7 @@ proper_loop_form_for_interchange (struct loop *loop, struct loop **min_outer)
 	  || dominated_by_p (CDI_DOMINATORS, exit->src, bb))
 	continue;
 
-      for (gimple_stmt_iterator gsi = gsi_start_bb_nondebug (bb);
+      for (gimple_stmt_iterator gsi = gsi_start_nondebug_bb (bb);
 	   !gsi_end_p (gsi); gsi_next_nondebug (&gsi))
 	if (gimple_vuse (gsi_stmt (gsi)))
 	  {
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 4ea6c3532f3f..22db61bbd48a 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -645,7 +645,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.h b/gcc/gimple.h
index d34aa142849c..26fed1d4ecb6 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -4600,6 +4600,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
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 16a86ce70f04..6a15daf45b58 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1847,7 +1847,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)
@@ -1860,27 +1860,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;
     }
@@ -2005,7 +2008,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);
     }
@@ -2042,7 +2045,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;
     }
@@ -2055,7 +2058,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)
@@ -2102,7 +2105,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))
@@ -2245,8 +2248,8 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
 		}
 	      else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
 		;
-	      else
-		/* Something other is not expected.  */
+	      else if (!is_gimple_debug (stmt))
+		/* Anything else is not expected.  */
 		break;
 	      gsi_next (&gsi2);
 	    }
diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
index ab7f0e786ba2..848bfe9dfc29 100644
--- a/gcc/graphite-isl-ast-to-gimple.c
+++ b/gcc/graphite-isl-ast-to-gimple.c
@@ -1033,7 +1033,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;
@@ -1065,7 +1065,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);
 	}
@@ -1174,7 +1174,8 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_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))
 	    ;
 	  else
 	    gcc_unreachable ();
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index b7c0b3a6f4ff..cf44422d8219 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -8086,7 +8086,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/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index b40dd8653b4d..be8c70912698 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -640,8 +640,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/jump.c b/gcc/jump.c
index fc4b4345444a..e60a6c6f8e66 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/omp-expand.c b/gcc/omp-expand.c
index 4aadc6f4170b..02488339b401 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -694,7 +694,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;
@@ -834,7 +834,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;
@@ -911,15 +911,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);
@@ -1135,7 +1135,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);
@@ -1248,7 +1248,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));
@@ -1264,7 +1264,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);
@@ -1273,7 +1273,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)));
@@ -1732,7 +1732,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))
@@ -2537,7 +2537,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
@@ -2567,7 +2567,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));
@@ -2588,7 +2588,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));
@@ -3006,7 +3006,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);
@@ -3072,7 +3072,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)))
@@ -3292,7 +3292,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)
@@ -3424,7 +3424,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)),
@@ -3434,7 +3434,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);
@@ -3576,7 +3576,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);
@@ -3609,7 +3609,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));
@@ -3776,7 +3776,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)
@@ -4082,7 +4082,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);
@@ -4126,7 +4126,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));
@@ -4399,7 +4399,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.  */
@@ -4494,7 +4494,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);
 
@@ -4592,7 +4592,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.  */
@@ -4718,7 +4718,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)
@@ -4819,10 +4819,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 ();
@@ -4896,7 +4896,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)
@@ -4975,7 +4975,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);
@@ -5012,7 +5012,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 ();
@@ -5195,7 +5195,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);
 
@@ -5322,7 +5322,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);
@@ -5446,7 +5446,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);
 
@@ -5535,7 +5535,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));
 
@@ -5760,7 +5760,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)
@@ -5768,7 +5768,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)
 	      {
@@ -5793,7 +5793,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);
@@ -5817,7 +5817,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)
     {
@@ -5859,7 +5859,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);
@@ -5868,7 +5868,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);
 
@@ -5894,7 +5894,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);
@@ -5907,7 +5907,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)))
@@ -5935,12 +5935,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));
@@ -5963,7 +5963,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
@@ -5975,7 +5975,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;
@@ -5996,7 +5996,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);
@@ -6026,7 +6026,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);
 
@@ -6052,14 +6052,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);
@@ -6104,7 +6104,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))
@@ -6151,10 +6151,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));
@@ -6218,7 +6225,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.
@@ -6241,10 +6248,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);
 
@@ -6297,7 +6304,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
@@ -6377,7 +6384,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)
@@ -6480,7 +6487,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);
@@ -6491,7 +6498,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)),
@@ -6990,7 +6997,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));
@@ -7002,7 +7009,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);
@@ -7184,7 +7191,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));
 	}
@@ -7219,11 +7226,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);
     }
@@ -7367,7 +7374,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);
@@ -7448,17 +7455,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)
@@ -7602,11 +7609,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);
@@ -7790,7 +7797,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 5076c63fd734..3d566aaef12b 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -6963,6 +6963,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/postreload.c b/gcc/postreload.c
index 000ed341b034..8e4a81903f5e 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -836,7 +836,7 @@ fixup_debug_insns (rtx reg, rtx replacement, rtx_insn *from, rtx_insn *to)
     {
       rtx t;
 
-      if (!DEBUG_INSN_P (insn))
+      if (!DEBUG_BIND_INSN_P (insn))
 	continue;
       
       t = INSN_VAR_LOCATION_LOC (insn);
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 15d8b140ce7f..33e6e62a4c26 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -428,6 +428,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) (...))
diff --git a/gcc/sese.c b/gcc/sese.c
index bbc72d4d7618..a69ea90622da 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -460,7 +460,7 @@ sese_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))
 	&& gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
       return false;
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 00f86613137a..b00a29132936 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -561,14 +561,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))
@@ -583,6 +591,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
@@ -996,7 +1005,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);
 
@@ -1506,6 +1519,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));
 
@@ -1666,6 +1682,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));
 
@@ -1841,6 +1863,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;
@@ -2642,6 +2666,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.  */
@@ -5488,6 +5519,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);
@@ -5557,7 +5592,7 @@ gimple_verify_flow_info (void)
 	    }
 	}
 
-      gsi = gsi_last_bb (bb);
+      gsi = gsi_last_nondebug_bb (bb);
       if (gsi_end_p (gsi))
 	continue;
 
@@ -5812,8 +5847,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;
@@ -5824,6 +5861,7 @@ gimple_block_label (basic_block bb)
 	    gsi_move_before (&i, &s);
 	  return label;
 	}
+      first = false;
     }
 
   label = create_artificial_label (UNKNOWN_LOCATION);
@@ -5899,7 +5937,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 526793723dce..0bee21756f2b 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -542,13 +542,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);
@@ -557,20 +557,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.  */
@@ -1309,7 +1295,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-pretty-print.c b/gcc/tree-pretty-print.c
index ab4b2f705c80..bf872b8d35e9 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3325,7 +3325,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 1e1307b2ff72..3b9e1076506a 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -256,7 +256,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);
@@ -1442,8 +1443,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-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index fc94f5d83d2c..743ee4e1cf99 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/var-tracking.c b/gcc/var-tracking.c
index 33bcca7d6f52..b324a2c97c28 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9479,6 +9479,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
@@ -9507,7 +9525,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_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
@@ -10103,11 +10122,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 (DEBUG_BIND_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);
@@ -10175,6 +10217,7 @@ vt_initialize (void)
 			    }
 			}
 		    }
+		  BLOCK_FOR_INSN (insn) = save_bb;
 		}
 	    }
 	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
@@ -10215,7 +10258,10 @@ 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))
 	  {
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries
  2017-12-07 22:46                   ` Jeff Law
@ 2017-12-12  2:38                     ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:38 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> * cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
>> without debug insns, we wouldn't, but clean up debug insns
>> after a control flow insn nevertheless.
> OK.  Seems to me like it's independent of the rest of the work and
> should go in immediately.

Yeah, I wasn't even sure whether to submit it as part of the SFN
patchset.  IIRC it was a build regression of the patchset, that only
came up after I'd first posted it, and I could only trigger it with the
patchset, IIRC because it involved debug insns at places where only
these patches would insert them.  So I kept it in the set, but as a
separate patch.

Anyway, thanks, here it is as installed, FTR:

From 116cfb8c5abdcd64333be8fa105a4af2dfd13823 Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:15:44 +0000
Subject: [PATCH 4/7] [SFN] stabilize find_bb_boundaries

If find_bb_boundaries is given a block with zero or one nondebug insn
beside debug insns, it shouldn't purge dead edges, because without
debug insns we wouldn't purge them at that point.  Doing so may change
the order in which edges are processed, and ultimately lead to
different transformations to the CFG and then to different
optimizations.

We shouldn't, however, retain debug insns after control flow insns, so
if we find debug insns after a single insn that happens to be a
control flow insn, do the debug insn cleanups, but still refrain from
purging dead edges at that point.


for  gcc/ChangeLog

	* cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
	without debug insns, we wouldn't, but clean up debug insns
	after a control flow insn nevertheless.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255567 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog  |  4 ++++
 gcc/cfgbuild.c | 40 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 03ad41c3e27a..3c1add62c944 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,9 @@
 2017-12-12  Alexandre Oliva <aoliva@redhat.com>
 
+	* cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
+	without debug insns, we wouldn't, but clean up debug insns
+	after a control flow insn nevertheless.
+
 	* cfgcleanup.c (delete_unreachable_blocks): Use alternate
 	block removal order if MAY_HAVE_DEBUG_BIND_INSNS.
 	* cfgexpand.c (label_rtx_for_bb): Skip debug insns.
diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 8fa15fec45e4..7b57589f1dfa 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -444,10 +444,43 @@ find_bb_boundaries (basic_block bb)
   rtx_insn *flow_transfer_insn = NULL;
   rtx_insn *debug_insn = NULL;
   edge fallthru = NULL;
+  bool skip_purge;
 
   if (insn == end)
     return;
 
+  if (DEBUG_INSN_P (insn) || DEBUG_INSN_P (end))
+    {
+      /* Check whether, without debug insns, the insn==end test above
+	 would have caused us to return immediately, and behave the
+	 same way even with debug insns.  If we don't do this, debug
+	 insns could cause us to purge dead edges at different times,
+	 which could in turn change the cfg and affect codegen
+	 decisions in subtle but undesirable ways.  */
+      while (insn != end && DEBUG_INSN_P (insn))
+	insn = NEXT_INSN (insn);
+      rtx_insn *e = end;
+      while (insn != e && DEBUG_INSN_P (e))
+	e = PREV_INSN (e);
+      if (insn == e)
+	{
+	  /* If there are debug insns after a single insn that is a
+	     control flow insn in the block, we'd have left right
+	     away, but we should clean up the debug insns after the
+	     control flow insn, because they can't remain in the same
+	     block.  So, do the debug insn cleaning up, but then bail
+	     out without purging dead edges as we would if the debug
+	     insns hadn't been there.  */
+	  if (e != end && !DEBUG_INSN_P (e) && control_flow_insn_p (e))
+	    {
+	      skip_purge = true;
+	      flow_transfer_insn = e;
+	      goto clean_up_debug_after_control_flow;
+	    }
+	  return;
+	}
+    }
+
   if (LABEL_P (insn))
     insn = NEXT_INSN (insn);
 
@@ -475,7 +508,6 @@ find_bb_boundaries (basic_block bb)
 	  if (debug_insn && code != CODE_LABEL && code != BARRIER)
 	    prev = PREV_INSN (debug_insn);
 	  fallthru = split_block (bb, prev);
-
 	  if (flow_transfer_insn)
 	    {
 	      BB_END (bb) = flow_transfer_insn;
@@ -527,6 +559,9 @@ find_bb_boundaries (basic_block bb)
      ordinary jump, we need to take care and move basic block boundary.  */
   if (flow_transfer_insn && flow_transfer_insn != end)
     {
+      skip_purge = false;
+
+    clean_up_debug_after_control_flow:
       BB_END (bb) = flow_transfer_insn;
 
       /* Clean up the bb field for the insns that do not belong to BB.  */
@@ -543,6 +578,9 @@ find_bb_boundaries (basic_block bb)
 	  if (x == end)
 	    break;
 	}
+
+      if (skip_purge)
+	return;
     }
 
   /* We've possibly replaced the conditional jump by conditional jump
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled
  2017-12-07 23:59                   ` Jeff Law
@ 2017-12-12  2:41                     ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:41 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> This patch completes the infrastructure for the introduction of
>> statement frontiers in C-family languages.
> Note I expect minor updates will be necessary due to the Cilk+ removal.
> Such changes are pre-approved.

> ok

Thanks, here's what got installed, FTR:

From 90567983c3c093c60bd99a28266285553e615d43 Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:16:07 +0000
Subject: [PATCH 5/7] [SFN] introduce statement frontier notes, still disabled

This patch completes the infrastructure for the introduction of
statement frontiers in C-family languages.

It brings in all the code remaining code needed to introduce and
transform begin stmt trees, gimple stmts, insns and notes, and
ultimately use them to generate the is_stmt column in DWARF2+ line
number tables/programs, however none of it is activated: the option
that would do so will be introduced in a subsequent patch.

This patch depends on an earlier patch with not-quite-boilerplate
changes towards SFN.

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 (check_constexpr_ctor_body_1): Skip begin stmt
	markers.
	(constexpr_fn_retval): Likewise.
	(potential_constant_expression_1): Likewise.
	(cxx_eval_statement_list): Check that a begin stmt marker is
	not used as the value of a statement list.
	(cxx_eval_constant_expression): Return begin stmt markers
	unchanged.
	* cp-array-notation.c (stmt_location): New.
	(cp_expand_cond_array_notations): Use it.
	* cp-objcp-common.h (LANG_HOOKS_EMITS_BEGIN_STMT): Redefine as true.
	* parser.c (add_debug_begin_stmt): New.
	(cp_parser_statement): Call it.
	* pt.c (tsubst_copy): Handle begin stmt markers.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
	markers.  Integrate source bind into debug stmt expand loop.
	(pass_expand::execute): Check debug marker limit.  Avoid deep
	TER and expand debug locations for debug bind insns only.
	* cse.c (insn_live_p): Keep nonbind markers and debug bindings
	followed by them.
	* df-scan.c (df_insn_delete): Accept out-of-block debug insn.
	* final.c (reemit_insn_block_notes): Take current block from
	nonbind markers.  Declare note where it's first set.
	(final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
	begin stmt markers if enabled.
	(notice_source_line): Handle nonbind markers.  Fail if their
	location is unknown or that of builtins.
	(rest_of_handle_final): Convert begin stmt markers to notes if
	var-tracking didn't run.
	(rest_of_clean_state): Skip begin stmt markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
	markers.
	* function.c (allocate_struct_function): Set begin_stmt_markers.
	* function.h (struct function): Add debug_marker_count counter
	and debug_nonbind_markers flag.
	* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
	* gimple-low.c (lower_function_body): Adjust
	debug_nonbind_markers.
	(lower_stmt): Drop or skip gimple debug stmts.
	(lower_try_catch): Skip debug stmts.
	* gimple.c (gimple_build_debug_begin_stmt): New.
	(gimple_copy): Increment debug_marker_count if copying one.
	* gimple.h (gimple_build_debug_begin_stmt): Declare.
	* gimplify.c (rexpr_location): New.
	(rexpr_has_location): New.
	(warn_switch_unreachable_r): Handle gimple debug stmts.
	(shortcut_cond_r): Call expr_location.
	(find_goto): New.
	(find_goto_label): New.
	(shortcut_cond_expr): Call expr_has_location, expr_location, and
	find_goto_label.
	(gimplify_cond_expr): Call find_goto_label, expr_has_location, and
	expr_location.
	(gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
	* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
	(LANG_HOOKS_INITIALIZER): ... this.
	* langhooks.h (struct lang_hooks): Add emits_begin_stmt.
	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
	debug insns.
	(update_ebb_live_info): Skip debug insn markers.
	* lra.c (debug_insn_static_data): Rename to...
	(debug_bind_static_data): ... this.
	(debug_marker_static_data): New.
	(lra_set_insn_recog_data): Select one of the above depending
	on debug insn kind.
	(lra_update_isn_regno_info): Don't assume debug insns have
	freqs.
	(push_insns): Skip debug insns.
	* lto-streamer-in.c (input_function): Drop debug stmts
	depending on active options.  Adjust debug_nonbind_markers.
	* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	begin stmt marker notes.
	(print_insn): Likewise.
	* recog.c (extract_insn): Recognize rtl for debug markers.
	* rtl.def (DEBUG_MARKER): New.
	* tree-inline.c: Include params.h.
	(remap_gimple_stmt): Handle nonbind markers.
	(maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.
	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
	markers regardless of no side effects.
	(tsi_link_before): Don't update container's side effects when adding
	a begin stmt marker.
	(tsi_link_after): Likewise.
	(expr_first): Skip begin stmt markers.
	(expr_last): Likewise.
	* tree-pretty-print (dump_generic_node): Handle begin stmt markers.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Disregard nonbind markers.
	* tree.c (make_node_stat): Don't set side effects for begin stmt
	markers.
	(build1_stat): Likewise.
	* tree.def (DEBUG_BEGIN_STMT): New.
	* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
	* var-tracking.c (delete_debug_insns): Renamed to...
	(delete_vta_debug_insns): ... this.
	(reemit_marker_as_note): New.
	(vt_initialize): Reemit markers.
	(delete_vta_debug_insns): Likewise.
	(vt_debug_insns_local): Reemit or delete markers.
	(variable_tracking_main_1): Likewise.
	* doc/generic.texi (DEBUG_BEGIN_STMT): Document.
	* doc/gimple.texi (gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	(gimple_build_debug_bind): Adjust.
	(gimple_build_debug_begin_stmt): New.
	* doc/invoke.texi (max-debug-marker-count): New param.
	* doc/rtl.texi (debug_implicit_ptr, entry_value): New.
	(debug_parameter_ref, debug_marker): New.
	(NOTE_INSN_BEGIN_STMT): New.
	(DEBUG_INSN): Describe begin stmt markers.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255568 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog              |  99 ++++++++++++++++++++++++++++
 gcc/c-family/ChangeLog     |   5 ++
 gcc/c-family/c-semantics.c |  21 ++++++
 gcc/c/ChangeLog            |   9 +++
 gcc/c/c-objc-common.h      |   2 +
 gcc/c/c-parser.c           |  20 ++++++
 gcc/c/c-typeck.c           |   8 ++-
 gcc/cfgexpand.c            | 113 +++++++++++++++++---------------
 gcc/cp/ChangeLog           |  17 +++++
 gcc/cp/constexpr.c         |  16 +++++
 gcc/cp/cp-objcp-common.h   |   2 +
 gcc/cp/parser.c            |  14 ++++
 gcc/cp/pt.c                |   6 ++
 gcc/cse.c                  |   7 ++
 gcc/df-scan.c              |   2 +-
 gcc/doc/generic.texi       |   5 ++
 gcc/doc/gimple.texi        |  24 ++++++-
 gcc/doc/invoke.texi        |   7 ++
 gcc/doc/rtl.texi           |  53 ++++++++++++---
 gcc/final.c                |  89 +++++++++++++++++++------
 gcc/function.c             |   6 ++
 gcc/function.h             |  10 +++
 gcc/gimple-iterator.c      |   4 ++
 gcc/gimple-low.c           |  29 +++++++++
 gcc/gimple-pretty-print.c  |   7 ++
 gcc/gimple.c               |  24 +++++++
 gcc/gimple.h               |   1 +
 gcc/gimplify.c             | 158 +++++++++++++++++++++++++++++++++++----------
 gcc/langhooks-def.h        |   2 +
 gcc/langhooks.h            |   3 +
 gcc/lra-constraints.c      |  10 ++-
 gcc/lra.c                  |  36 +++++++++--
 gcc/lto-streamer-in.c      |  12 +++-
 gcc/params.def             |   9 +++
 gcc/print-rtl.c            |  24 +++++++
 gcc/recog.c                |   1 +
 gcc/rtl.def                |   3 +
 gcc/tree-inline.c          |  31 ++++++++-
 gcc/tree-iterator.c        |  48 +++++++++++---
 gcc/tree-pretty-print.c    |   4 ++
 gcc/tree-ssa-threadedge.c  |  25 ++++---
 gcc/tree.c                 |   8 ++-
 gcc/tree.def               |   3 +
 gcc/tree.h                 |   2 +-
 gcc/var-tracking.c         |  70 +++++++++++++++++---
 45 files changed, 895 insertions(+), 154 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3c1add62c944..01bd2b9f49ad 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,104 @@
 2017-12-12  Alexandre Oliva <aoliva@redhat.com>
 
+	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
+	markers.  Integrate source bind into debug stmt expand loop.
+	(pass_expand::execute): Check debug marker limit.  Avoid deep
+	TER and expand debug locations for debug bind insns only.
+	* cse.c (insn_live_p): Keep nonbind markers and debug bindings
+	followed by them.
+	* df-scan.c (df_insn_delete): Accept out-of-block debug insn.
+	* final.c (reemit_insn_block_notes): Take current block from
+	nonbind markers.  Declare note where it's first set.
+	(final_scan_insn): Handle begin stmt notes.  Emit is_stmt according to
+	begin stmt markers if enabled.
+	(notice_source_line): Handle nonbind markers.  Fail if their
+	location is unknown or that of builtins.
+	(rest_of_handle_final): Convert begin stmt markers to notes if
+	var-tracking didn't run.
+	(rest_of_clean_state): Skip begin stmt markers.
+	* gimple-pretty-print.c (dump_gimple_debug): Handle begin stmt
+	markers.
+	* function.c (allocate_struct_function): Set begin_stmt_markers.
+	* function.h (struct function): Add debug_marker_count counter
+	and debug_nonbind_markers flag.
+	* gimple-iterator.c (gsi_remove): Adjust debug_marker_count.
+	* gimple-low.c (lower_function_body): Adjust
+	debug_nonbind_markers.
+	(lower_stmt): Drop or skip gimple debug stmts.
+	(lower_try_catch): Skip debug stmts.
+	* gimple.c (gimple_build_debug_begin_stmt): New.
+	(gimple_copy): Increment debug_marker_count if copying one.
+	* gimple.h (gimple_build_debug_begin_stmt): Declare.
+	* gimplify.c (rexpr_location): New.
+	(rexpr_has_location): New.
+	(warn_switch_unreachable_r): Handle gimple debug stmts.
+	(shortcut_cond_r): Call expr_location.
+	(find_goto): New.
+	(find_goto_label): New.
+	(shortcut_cond_expr): Call expr_has_location, expr_location, and
+	find_goto_label.
+	(gimplify_cond_expr): Call find_goto_label, expr_has_location, and
+	expr_location.
+	(gimplify_expr): Handle begin stmt markers.  Reject debug expr decls.
+	* langhooks-def.h (LANG_HOOKS_EMITS_BEGIN_STMT): New.  Add to...
+	(LANG_HOOKS_INITIALIZER): ... this.
+	* langhooks.h (struct lang_hooks): Add emits_begin_stmt.
+	* lra-contraints.c (inherit_reload_reg): Tolerate between-blocks
+	debug insns.
+	(update_ebb_live_info): Skip debug insn markers.
+	* lra.c (debug_insn_static_data): Rename to...
+	(debug_bind_static_data): ... this.
+	(debug_marker_static_data): New.
+	(lra_set_insn_recog_data): Select one of the above depending
+	on debug insn kind.
+	(lra_update_isn_regno_info): Don't assume debug insns have
+	freqs.
+	(push_insns): Skip debug insns.
+	* lto-streamer-in.c (input_function): Drop debug stmts
+	depending on active options.  Adjust debug_nonbind_markers.
+	* params.def (PARAM_MAX_DEBUG_MARKER_COUNT): New.
+	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
+	begin stmt marker notes.
+	(print_insn): Likewise.
+	* recog.c (extract_insn): Recognize rtl for debug markers.
+	* rtl.def (DEBUG_MARKER): New.
+	* tree-inline.c: Include params.h.
+	(remap_gimple_stmt): Handle nonbind markers.
+	(maybe_move_debug_stmts_to_successors): Likewise.
+	(copy_debug_stmt): Likewise.
+	* tree-iterator.c (append_to_statement_list_1): Append begin stmt
+	markers regardless of no side effects.
+	(tsi_link_before): Don't update container's side effects when adding
+	a begin stmt marker.
+	(tsi_link_after): Likewise.
+	(expr_first): Skip begin stmt markers.
+	(expr_last): Likewise.
+	* tree-pretty-print (dump_generic_node): Handle begin stmt markers.
+	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
+	Disregard nonbind markers.
+	* tree.c (make_node_stat): Don't set side effects for begin stmt
+	markers.
+	(build1_stat): Likewise.
+	* tree.def (DEBUG_BEGIN_STMT): New.
+	* tree.h (GOTO_DESTINATION): Require a GOTO_EXPR.
+	* var-tracking.c (delete_debug_insns): Renamed to...
+	(delete_vta_debug_insns): ... this.
+	(reemit_marker_as_note): New.
+	(vt_initialize): Reemit markers.
+	(delete_vta_debug_insns): Likewise.
+	(vt_debug_insns_local): Reemit or delete markers.
+	(variable_tracking_main_1): Likewise.
+	* doc/generic.texi (DEBUG_BEGIN_STMT): Document.
+	* doc/gimple.texi (gimple_debug_begin_stmt_p): New.
+	(gimple_debug_nonbind_marker_p): New.
+	(gimple_build_debug_bind): Adjust.
+	(gimple_build_debug_begin_stmt): New.
+	* doc/invoke.texi (max-debug-marker-count): New param.
+	* doc/rtl.texi (debug_implicit_ptr, entry_value): New.
+	(debug_parameter_ref, debug_marker): New.
+	(NOTE_INSN_BEGIN_STMT): New.
+	(DEBUG_INSN): Describe begin stmt markers.
+
 	* cfgbuild.c (find_bb_boundaries): Don't purge dead edges if,
 	without debug insns, we wouldn't, but clean up debug insns
 	after a control flow insn nevertheless.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 4ad83f362873..6c31dbef45e0 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,8 @@
+2017-12-12  Alexandre Oliva <aoliva@redhat.com>
+
+	* c-semantics.c (pop_stmt_list): Move begin stmt marker into
+	subsequent statement list.
+
 2017-12-07  Martin Sebor  <msebor@redhat.com>
 
 	PR c/81544
diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index 3ceb714e4b16..cd872d8ac740 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/ChangeLog b/gcc/c/ChangeLog
index 14d7f63bf4e3..f98126650697 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,12 @@
+2017-12-12  Alexandre Oliva <aoliva@redhat.com>
+
+	* 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.
+
 2017-12-07  Joseph Myers  <joseph@codesourcery.com>
 
 	* c-decl.c (build_compound_literal): Add parameter alignas_align
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index bee06e9a37ef..27ceabcdfb2f 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 d39854805048..f1bae8abdf38 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1649,6 +1649,19 @@ c_parser_external_declaration (c_parser *parser)
 static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
    6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
    is accepted; otherwise (old-style parameter declarations) only other
@@ -1749,6 +1762,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))
     {
@@ -4911,6 +4926,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;
     }
@@ -5365,6 +5381,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 676dbbd2e2ff..13b26845d97a 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -10710,6 +10710,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;
     }
@@ -10729,7 +10733,9 @@ c_finish_stmt_expr (location_t loc, tree body)
 
   /* In the case that the BIND_EXPR is not necessary, return the
      expression out from inside it.  */
-  if (last == BIND_EXPR_BODY (body)
+  if ((last == BIND_EXPR_BODY (body)
+       /* Skip nested debug stmts.  */
+       || last == expr_first (BIND_EXPR_BODY (body)))
       && BIND_EXPR_VARS (body) == NULL)
     {
       /* Even if this looks constant, do not allow it in a constant
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 3ee242df6b98..ce98264214ae 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5657,39 +5657,68 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	  if (new_bb)
 	    return new_bb;
 	}
-      else if (gimple_debug_bind_p (stmt))
+      else if (is_gimple_debug (stmt))
 	{
 	  location_t sloc = curr_insn_location ();
 	  gimple_stmt_iterator nsi = gsi;
 
 	  for (;;)
 	    {
-	      tree var = gimple_debug_bind_get_var (stmt);
-	      tree value;
-	      rtx val;
+	      tree var;
+	      tree value = NULL_TREE;
+	      rtx val = NULL_RTX;
 	      machine_mode mode;
 
-	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
-		  && TREE_CODE (var) != LABEL_DECL
-		  && !target_for_debug_bind (var))
-		goto delink_debug_stmt;
+	      if (!gimple_debug_nonbind_marker_p (stmt))
+		{
+		  if (gimple_debug_bind_p (stmt))
+		    {
+		      var = gimple_debug_bind_get_var (stmt);
 
-	      if (gimple_debug_bind_has_value_p (stmt))
-		value = gimple_debug_bind_get_value (stmt);
-	      else
-		value = NULL_TREE;
+		      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+			  && TREE_CODE (var) != LABEL_DECL
+			  && !target_for_debug_bind (var))
+			goto delink_debug_stmt;
 
-	      last = get_last_insn ();
+		      if (DECL_P (var))
+			mode = DECL_MODE (var);
+		      else
+			mode = TYPE_MODE (TREE_TYPE (var));
 
-	      set_curr_insn_location (gimple_location (stmt));
+		      if (gimple_debug_bind_has_value_p (stmt))
+			value = gimple_debug_bind_get_value (stmt);
+
+		      val = gen_rtx_VAR_LOCATION
+			(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+		    }
+		  else if (gimple_debug_source_bind_p (stmt))
+		    {
+		      var = gimple_debug_source_bind_get_var (stmt);
+
+		      value = gimple_debug_source_bind_get_value (stmt);
+
+		      mode = DECL_MODE (var);
 
-	      if (DECL_P (var))
-		mode = DECL_MODE (var);
+		      val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+						  VAR_INIT_STATUS_UNINITIALIZED);
+		    }
+		  else
+		    gcc_unreachable ();
+		}
+	      /* If this function was first compiled with markers
+		 enabled, but they're now disable (e.g. LTO), drop
+		 them on the floor.  */
+	      else if (gimple_debug_nonbind_marker_p (stmt)
+		       && !MAY_HAVE_DEBUG_MARKER_INSNS)
+		goto delink_debug_stmt;
+	      else if (gimple_debug_begin_stmt_p (stmt))
+		val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT ();
 	      else
-		mode = TYPE_MODE (TREE_TYPE (var));
+		gcc_unreachable ();
 
-	      val = gen_rtx_VAR_LOCATION
-		(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+	      last = get_last_insn ();
+
+	      set_curr_insn_location (gimple_location (stmt));
 
 	      emit_debug_insn (val);
 
@@ -5697,9 +5726,14 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		{
 		  /* We can't dump the insn with a TREE where an RTX
 		     is expected.  */
-		  PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    {
+		      gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value);
+		      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+		    }
 		  maybe_dump_rtl_for_gimple_stmt (stmt, last);
-		  PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+		  if (GET_CODE (val) == VAR_LOCATION)
+		    PAT_VAR_LOCATION_LOC (val) = (rtx)value;
 		}
 
 	    delink_debug_stmt:
@@ -5715,42 +5749,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	      if (gsi_end_p (nsi))
 		break;
 	      stmt = gsi_stmt (nsi);
-	      if (!gimple_debug_bind_p (stmt))
+	      if (!is_gimple_debug (stmt))
 		break;
 	    }
 
 	  set_curr_insn_location (sloc);
 	}
-      else if (gimple_debug_source_bind_p (stmt))
-	{
-	  location_t sloc = curr_insn_location ();
-	  tree var = gimple_debug_source_bind_get_var (stmt);
-	  tree value = gimple_debug_source_bind_get_value (stmt);
-	  rtx val;
-	  machine_mode mode;
-
-	  last = get_last_insn ();
-
-	  set_curr_insn_location (gimple_location (stmt));
-
-	  mode = DECL_MODE (var);
-
-	  val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
-				      VAR_INIT_STATUS_UNINITIALIZED);
-
-	  emit_debug_insn (val);
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      /* We can't dump the insn with a TREE where an RTX
-		 is expected.  */
-	      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
-	      maybe_dump_rtl_for_gimple_stmt (stmt, last);
-	      PAT_VAR_LOCATION_LOC (val) = (rtx)value;
-	    }
-
-	  set_curr_insn_location (sloc);
-	}
       else
 	{
 	  gcall *call_stmt = dyn_cast <gcall *> (stmt);
@@ -6383,6 +6387,11 @@ pass_expand::execute (function *fun)
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
     e->flags &= ~EDGE_EXECUTABLE;
 
+  /* If the function has too many markers, drop them while expanding.  */
+  if (cfun->debug_marker_count
+      >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+    cfun->debug_nonbind_markers = false;
+
   lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
   FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
 		  next_bb)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e492f0a98675..4f1be5bd8ac1 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,20 @@
+2017-12-12  Alexandre Oliva <aoliva@redhat.com>
+
+	* constexpr.c (check_constexpr_ctor_body_1): Skip begin stmt
+	markers.
+	(constexpr_fn_retval): Likewise.
+	(potential_constant_expression_1): Likewise.
+	(cxx_eval_statement_list): Check that a begin stmt marker is
+	not used as the value of a statement list.
+	(cxx_eval_constant_expression): Return begin stmt markers
+	unchanged.
+	* 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.
+
 2017-12-07  Martin Sebor  <msebor@redhat.com>
 
 	PR c/81544
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 6dfecfc1b144..0455be1d6dae 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -455,6 +455,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
 
     case USING_STMT:
     case STATIC_ASSERT:
+    case DEBUG_BEGIN_STMT:
       return true;
 
     default:
@@ -694,6 +695,7 @@ constexpr_fn_retval (tree body)
       return constexpr_fn_retval (BIND_EXPR_BODY (body));
 
     case USING_STMT:
+    case DEBUG_BEGIN_STMT:
       return NULL_TREE;
 
     case CALL_EXPR:
@@ -3856,6 +3858,14 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
       if (returns (jump_target) || breaks (jump_target))
 	break;
     }
+  /* Make sure we don't use the "result" of a debug-only marker.  That
+     would be wrong.  We should be using the result of the previous
+     statement, or NULL if there isn't one.  In practice, this should
+     never happen: the statement after the marker should override the
+     result of the marker, so its value shouldn't survive in R.  Now,
+     should that ever change, we'll need some fixing here to stop
+     markers from modifying the generated executable code.  */
+  gcc_checking_assert (!r || TREE_CODE (r) != DEBUG_BEGIN_STMT);
   return r;
 }
 
@@ -4081,6 +4091,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	}
       break;
 
+    case DEBUG_BEGIN_STMT:
+      /* ??? It might be nice to retain this information somehow, so
+	 as to be able to step into a constexpr function call.  */
+      /* Fall through.  */
+
     case FUNCTION_DECL:
     case TEMPLATE_DECL:
     case LABEL_DECL:
@@ -5187,6 +5202,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case CONTINUE_STMT:
     case REQUIRES_EXPR:
     case STATIC_ASSERT:
+    case DEBUG_BEGIN_STMT:
       return true;
 
     case PARM_DECL:
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index a1b1fcdea63e..8d3bc8767589 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -107,6 +107,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 891f742eb215..94e87c235f1b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10684,6 +10684,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 
 /* Statements [gram.stmt.stmt]  */
 
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+    return;
+
+  tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+}
+
 /* Parse a statement.
 
    statement:
@@ -10759,6 +10772,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 252712e80f24..0cf6509c247b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15305,6 +15305,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 e449223cbb25..c0db32b9f11d 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -6962,11 +6962,18 @@ insn_live_p (rtx_insn *insn, int *counts)
     {
       rtx_insn *next;
 
+      if (DEBUG_MARKER_INSN_P (insn))
+	return true;
+
       for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
 	if (NOTE_P (next))
 	  continue;
 	else if (!DEBUG_INSN_P (next))
 	  return true;
+	/* If we find an inspection point, such as a debug begin stmt,
+	   we want to keep the earlier debug insn.  */
+	else if (DEBUG_MARKER_INSN_P (next))
+	  return true;
 	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
 	  return false;
 
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 8ab3d716ea29..429dab8a99b4 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 75c448e7330f..b01cdaa4d889 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -2006,6 +2006,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 fa98800a675b..492678705c6f 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -831,6 +831,16 @@ expression to a variable.
 Return true if g is any of the OpenMP codes.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
+a source statement.
+@end deftypefn
+
+@deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
+without any variable binding.
+@end deftypefn
+
 @node Manipulating GIMPLE statements
 @section Manipulating GIMPLE statements
 @cindex Manipulating GIMPLE statements
@@ -1530,10 +1540,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
@@ -1604,6 +1615,17 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
 and @code{FALSE} if it unbinds the variable.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that the
+user statement at the given @code{location} and @code{block} starts at
+the point at which the statement is inserted.  The intent is that side
+effects (e.g. variable bindings) of all prior user statements are
+observable, and that none of the side effects of subsequent user
+statements are.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1413095dd6c3..189b3e438fff 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10609,6 +10609,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 a58eedc4aa16..dd3c0d3cfc1e 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3448,6 +3448,25 @@ Stands for the value bound to the @code{DEBUG_EXPR_DECL} @var{decl},
 that points back to it, within value expressions in
 @code{VAR_LOCATION} nodes.
 
+@findex debug_implicit_ptr
+@item (debug_implicit_ptr:@var{mode} @var{decl})
+Stands for the location of a @var{decl} that is no longer addressable.
+
+@findex entry_value
+@item (entry_value:@var{mode} @var{decl})
+Stands for the value a @var{decl} had at the entry point of the
+containing function.
+
+@findex debug_parameter_ref
+@item (debug_parameter_ref:@var{mode} @var{decl})
+Refers to a parameter that was completely optimized out.
+
+@findex debug_marker
+@item (debug_marker:@var{mode})
+Marks a program location.  With @code{VOIDmode}, it stands for the
+beginning of a statement, a recommended inspection point logically after
+all prior side effects, and before any subsequent side effects.
+
 @end table
 
 @node Insns
@@ -3724,6 +3743,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.
@@ -3741,15 +3766,25 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-Throughout optimization passes, binding information is kept in
-pseudo-instruction form, so that, unlike notes, it gets the same
-treatment and adjustments that regular instructions would.  It is the
-variable tracking pass that turns these pseudo-instructions into var
-location notes, analyzing control flow, value equivalences and changes
-to registers and memory referenced in value expressions, propagating
-the values of debug temporaries and determining expressions that can
-be used to compute the value of each user variable at as many points
-(ranges, actually) in the program as possible.
+@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
+with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
+just @code{DEBUG_MARKER}s, can be detected by testing
+@code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
+@code{DEBUG_BIND_INSN_P}.
+
+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
+with respect to each other, particularly during scheduling.  Binding
+information is kept in pseudo-instruction form, so that, unlike notes,
+it gets the same treatment and adjustments that regular instructions
+would.  It is the variable tracking pass that turns these
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
+@code{NOTE_INSN_BEGIN_STMT} notes,
+analyzing control flow, value equivalences and changes to registers and
+memory referenced in value expressions, propagating the values of debug
+temporaries and determining expressions that can be used to compute the
+value of each user variable at as many points (ranges, actually) in the
+program as possible.
 
 Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
 @code{INSN_VAR_LOCATION} denotes a value at that specific point in the
diff --git a/gcc/final.c b/gcc/final.c
index afb6906997da..3bcb9c5a2dd6 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1652,7 +1652,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))
@@ -1660,17 +1659,29 @@ reemit_insn_block_notes (void)
       tree this_block;
 
       /* Prevent lexical blocks from straddling section boundaries.  */
-      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
-        {
-          for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
-               s = BLOCK_SUPERCONTEXT (s))
-            {
-              rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
-              NOTE_BLOCK (note) = s;
-              note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
-              NOTE_BLOCK (note) = s;
-            }
-        }
+      if (NOTE_P (insn))
+	switch (NOTE_KIND (insn))
+	  {
+	  case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+	    {
+	      for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
+		   s = BLOCK_SUPERCONTEXT (s))
+		{
+		  rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+		  NOTE_BLOCK (note) = s;
+		  note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
+		  NOTE_BLOCK (note) = s;
+		}
+	    }
+	    break;
+
+	  case NOTE_INSN_BEGIN_STMT:
+	    this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
+	    goto set_cur_block_to_this_block;
+
+	  default:
+	    continue;
+	}
 
       if (!active_insn_p (insn))
         continue;
@@ -1691,6 +1702,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)
@@ -1707,7 +1719,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);
 
@@ -2413,6 +2425,17 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    debug_hooks->var_location (insn);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+	  gcc_checking_assert (cfun->debug_nonbind_markers);
+	  if (!DECL_IGNORED_P (current_function_decl)
+	      && notice_source_line (insn, NULL))
+	    {
+	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
+					   last_filename, last_discriminator,
+					   true);
+	    }
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	  break;
@@ -2499,7 +2522,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	rtx body = PATTERN (insn);
 	int insn_code_number;
 	const char *templ;
-	bool is_stmt;
+	bool is_stmt, *is_stmt_p;
+
+	if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
+	  {
+	    is_stmt = false;
+	    is_stmt_p = NULL;
+	  }
+	else
+	  is_stmt_p = &is_stmt;
 
 	/* Reset this early so it is correct for ASM statements.  */
 	current_insn_predicate = NULL_RTX;
@@ -2602,7 +2633,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	/* Output this line note if it is the first or the last line
 	   note in a row.  */
 	if (!DECL_IGNORED_P (current_function_decl)
-	    && notice_source_line (insn, &is_stmt))
+	    && notice_source_line (insn, is_stmt_p))
 	  {
 	    if (flag_verbose_asm)
 	      asm_show_source (last_filename, last_linenum);
@@ -3095,7 +3126,22 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   const char *filename;
   int linenum, columnnum;
 
-  if (override_filename)
+  if (NOTE_MARKER_P (insn))
+    {
+      location_t loc = NOTE_MARKER_LOCATION (insn);
+      expanded_location xloc = expand_location (loc);
+      if (xloc.line == 0)
+	{
+	  gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
+			       || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
+	  return false;
+	}
+      filename = xloc.file;
+      linenum = xloc.line;
+      columnnum = xloc.column;
+      force_source_line = true;
+    }
+  else if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
@@ -3128,7 +3174,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;
@@ -3140,7 +3187,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;
     }
 
@@ -4493,6 +4541,10 @@ rest_of_handle_final (void)
 {
   const char *fnname = get_fnname_from_decl (current_function_decl);
 
+  /* Turn debug markers into notes.  */
+  if (!MAY_HAVE_DEBUG_BIND_INSNS && MAY_HAVE_DEBUG_MARKER_INSNS)
+    variable_tracking_main ();
+
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
@@ -4680,6 +4732,7 @@ rest_of_clean_state (void)
       if (final_output
 	  && (!NOTE_P (insn) ||
 	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
 	       && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
diff --git a/gcc/function.c b/gcc/function.c
index 88f93db6cf0f..cdb2fc8a557b 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4939,6 +4939,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
       if (!profile_flag && !flag_instrument_function_entry_exit)
 	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
     }
+
+  /* Don't enable begin stmt markers if var-tracking at assignments is
+     disabled.  The markers make little sense without the variable
+     binding annotations among them.  */
+  cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
+    && MAY_HAVE_DEBUG_MARKER_STMTS;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 971ab667e1a4..b94abb65b7f9 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -281,6 +281,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;
 
@@ -381,6 +387,10 @@ struct GTY(()) function {
 
   /* Nonzero if the current function contains a #pragma GCC unroll.  */
   unsigned int has_unroll : 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 1e87825a20f8..46d3c6ab6928 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -568,6 +568,10 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
 
   if (remove_permanently)
     {
+      if (gimple_debug_nonbind_marker_p (stmt))
+	/* We don't need this to be exact, but try to keep it at least
+	   close.  */
+	cfun->debug_marker_count--;
       require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
       gimple_remove_stmt_histograms (cfun, stmt);
     }
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 22db61bbd48a..95f3f4561f9f 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -110,6 +110,17 @@ lower_function_body (void)
 
   i = gsi_last (lowered_body);
 
+  /* If we had begin stmt markers from e.g. PCH, but this compilation
+     doesn't want them, lower_stmt will have cleaned them up; we can
+     now clear the flag that indicates we had them.  */
+  if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers)
+    {
+      /* This counter needs not be exact, but before lowering it will
+	 most certainly be.  */
+      gcc_assert (cfun->debug_marker_count == 0);
+      cfun->debug_nonbind_markers = false;
+    }
+
   /* If the function falls off the end, we need a null return statement.
      If we've already got one in the return_statements vector, we don't
      need to do anything special.  Otherwise build one by hand.  */
@@ -296,6 +307,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       }
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (cfun->debug_nonbind_markers);
+      /* We can't possibly have debug bind stmts before lowering, we
+	 first emit them when entering SSA.  */
+      gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
+      /* Propagate fallthruness.  */
+      /* If the function (e.g. from PCH) had debug stmts, but they're
+	 disabled for this compilation, remove them.  */
+      if (!MAY_HAVE_DEBUG_MARKER_STMTS)
+	gsi_remove (gsi, true);
+      else
+	gsi_next (gsi);
+      return;
+
     case GIMPLE_NOP:
     case GIMPLE_ASM:
     case GIMPLE_ASSIGN:
@@ -503,6 +528,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
 	cannot_fallthru = false;
       break;
 
+    case GIMPLE_DEBUG:
+      gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
+      break;
+
     default:
       /* This case represents statements to be executed when an
 	 exception occurs.  Those statements are implicitly followed
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index e952f3378121..aee2ad8f1ea1 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1363,6 +1363,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 			 gimple_debug_source_bind_get_value (gs));
       break;
 
+    case GIMPLE_DEBUG_BEGIN_STMT:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+      break;
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c986a7320046..5a118e9095ca 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -853,6 +853,27 @@ gimple_build_debug_source_bind (tree var, tree value,
 }
 
 
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+   LOCATION.  */
+
+gdebug *
+gimple_build_debug_begin_stmt (tree block, location_t location
+				    MEM_STAT_DECL)
+{
+  gdebug *p
+    = as_a <gdebug *> (
+        gimple_build_with_ops_stat (GIMPLE_DEBUG,
+				    (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+				    PASS_MEM_STAT));
+
+  gimple_set_location (p, location);
+  gimple_set_block (p, block);
+  cfun->debug_marker_count++;
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1915,6 +1936,9 @@ gimple_copy (gimple *stmt)
       gimple_set_modified (copy, true);
     }
 
+  if (gimple_debug_nonbind_marker_p (stmt))
+    cfun->debug_marker_count++;
+
   return copy;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 26fed1d4ecb6..7c36679d092f 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1453,6 +1453,7 @@ gswitch *gimple_build_switch (tree, tree, vec<tree> );
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
+gdebug *gimple_build_debug_begin_stmt (tree, location_t CXX_MEM_STAT_INFO);
 gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
 gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
 gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 6a15daf45b58..8e1d400f303e 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -983,6 +983,48 @@ unshare_expr_without_location (tree expr)
     walk_tree (&expr, prune_expr_location, NULL, NULL);
   return expr;
 }
+
+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
+   one, OR_ELSE otherwise.  The location of a STATEMENT_LISTs
+   comprising at least one DEBUG_BEGIN_STMT followed by exactly one
+   EXPR is the location of the EXPR.  */
+
+static location_t
+rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
+  if (!expr)
+    return or_else;
+
+  if (EXPR_HAS_LOCATION (expr))
+    return EXPR_LOCATION (expr);
+
+  if (TREE_CODE (expr) != STATEMENT_LIST)
+    return or_else;
+
+  tree_stmt_iterator i = tsi_start (expr);
+
+  bool found = false;
+  while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+    {
+      found = true;
+      tsi_next (&i);
+    }
+
+  if (!found || !tsi_one_before_end_p (i))
+    return or_else;
+
+  return rexpr_location (tsi_stmt (i), or_else);
+}
+
+/* Return TRUE iff EXPR (maybe recursively) has a location; see
+   rexpr_location for the potential recursion.  */
+
+static inline bool
+rexpr_has_location (tree expr)
+{
+  return rexpr_location (expr) != UNKNOWN_LOCATION;
+}
+
 \f
 /* 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
@@ -1764,6 +1806,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))
 	{
@@ -3466,7 +3515,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the && on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3489,7 +3538,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
       append_to_statement_list (t, &expr);
 
       /* Set the source location of the || on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
 			   new_locus);
       append_to_statement_list (t, &expr);
@@ -3511,7 +3560,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
 
       /* Keep the original source location on the first 'if'.  Set the source
 	 location of the ? on the second 'if'.  */
-      new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+      new_locus = rexpr_location (pred, locus);
       expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
 		     shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
 				      false_label_p, locus),
@@ -3535,6 +3584,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.  */
@@ -3565,8 +3653,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the && on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  then_ = shortcut_cond_expr (expr);
 	  then_se = then_ && TREE_SIDE_EFFECTS (then_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3587,8 +3675,8 @@ shortcut_cond_expr (tree expr)
 	  location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
 	  /* Set the source location of the || on the second 'if'.  */
-	  if (EXPR_HAS_LOCATION (pred))
-	    SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+	  if (rexpr_has_location (pred))
+	    SET_EXPR_LOCATION (expr, rexpr_location (pred));
 	  else_ = shortcut_cond_expr (expr);
 	  else_se = else_ && TREE_SIDE_EFFECTS (else_);
 	  pred = TREE_OPERAND (pred, 0);
@@ -3615,20 +3703,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;
     }
@@ -3692,8 +3776,8 @@ shortcut_cond_expr (tree expr)
 	{
 	  tree last = expr_last (expr);
 	  t = build_and_jump (&end_label);
-	  if (EXPR_HAS_LOCATION (last))
-	    SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
+	  if (rexpr_has_location (last))
+	    SET_EXPR_LOCATION (t, rexpr_location (last));
 	  append_to_statement_list (t, &expr);
 	}
       if (emit_false)
@@ -3988,39 +4072,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   gimple_push_condition ();
 
   have_then_clause_p = have_else_clause_p = false;
-  if (TREE_OPERAND (expr, 1) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
-	  == current_function_decl)
+  label_true = find_goto_label (TREE_OPERAND (expr, 1));
+  if (label_true
+      && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
+	  || !rexpr_has_location (label_true)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_true)))
     {
-      label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
       have_then_clause_p = true;
+      label_true = GOTO_DESTINATION (label_true);
     }
   else
     label_true = create_artificial_label (UNKNOWN_LOCATION);
-  if (TREE_OPERAND (expr, 2) != NULL
-      && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
-      && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
-      && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
-	  == current_function_decl)
+  label_false = find_goto_label (TREE_OPERAND (expr, 2));
+  if (label_false
+      && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
       /* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
 	 have different locations, otherwise we end up with incorrect
 	 location information on the branches.  */
       && (optimize
 	  || !EXPR_HAS_LOCATION (expr)
-	  || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
-	  || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
+	  || !rexpr_has_location (label_false)
+	  || EXPR_LOCATION (expr) == rexpr_location (label_false)))
     {
-      label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
       have_else_clause_p = true;
+      label_false = GOTO_DESTINATION (label_false);
     }
   else
     label_false = create_artificial_label (UNKNOWN_LOCATION);
@@ -11809,6 +11889,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  ret = GS_ALL_DONE;
 	  break;
 
+	case DEBUG_EXPR_DECL:
+	  gcc_unreachable ();
+
+	case DEBUG_BEGIN_STMT:
+	  gimplify_seq_add_stmt (pre_p,
+				 gimple_build_debug_begin_stmt
+				 (TREE_BLOCK (*expr_p),
+				  EXPR_LOCATION (*expr_p)));
+	  ret = GS_ALL_DONE;
+	  *expr_p = NULL;
+	  break;
+
 	case SSA_NAME:
 	  /* Allow callbacks into the gimplifier during optimization.  */
 	  ret = GS_ALL_DONE;
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 44e7edf04ba5..9362d9674ede 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -132,6 +132,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
 
@@ -346,6 +347,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 afc879ff9c2f..dddb0270d498 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -532,6 +532,9 @@ struct lang_hooks
      instead of trampolines.  */
   bool custom_function_descriptors;
 
+  /* True if this language emits begin stmt notes.  */
+  bool emits_begin_stmt;
+
   /* Run all lang-specific selftests.  */
   void (*run_lang_selftests) (void);
 
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index a6600ef992c8..4adf4bfea8b0 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -5265,10 +5265,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));
 	}
     }
@@ -5807,6 +5808,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
       if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
 	continue;
       curr_bb = BLOCK_FOR_INSN (curr_insn);
+      if (!curr_bb)
+	{
+	  gcc_assert (DEBUG_INSN_P (curr_insn));
+	  if (DEBUG_MARKER_INSN_P (curr_insn))
+	    continue;
+	  curr_bb = prev_bb;
+	}
       if (curr_bb != prev_bb)
 	{
 	  if (prev_bb != NULL)
diff --git a/gcc/lra.c b/gcc/lra.c
index f790904ec57f..943d1ca65d97 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
@@ -947,12 +963,20 @@ lra_set_insn_recog_data (rtx_insn *insn)
   data->regs = NULL;
   if (DEBUG_INSN_P (insn))
     {
-      data->insn_static_data = &debug_insn_static_data;
       data->dup_loc = NULL;
       data->arg_hard_regs = NULL;
       data->preferred_alternatives = ALL_ALTERNATIVES;
-      data->operand_loc = XNEWVEC (rtx *, 1);
-      data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+      if (DEBUG_BIND_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_bind_static_data;
+	  data->operand_loc = XNEWVEC (rtx *, 1);
+	  data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+	}
+      else if (DEBUG_MARKER_INSN_P (insn))
+	{
+	  data->insn_static_data = &debug_marker_static_data;
+	  data->operand_loc = NULL;
+	}
       return data;
     }
   if (icode < 0)
@@ -1597,7 +1621,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);
   for (i = static_data->n_operands - 1; i >= 0; i--)
     add_regs_to_insn_regno_info (data, *data->operand_loc[i], insn,
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 3db1d38d535d..9b785ff365d7 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1128,7 +1128,10 @@ input_function (tree fn_decl, struct data_in *data_in,
 	     Similarly remove all IFN_*SAN_* internal calls   */
 	  if (!flag_wpa)
 	    {
-	      if (!MAY_HAVE_DEBUG_STMTS && is_gimple_debug (stmt))
+	      if (is_gimple_debug (stmt)
+		  && (gimple_debug_nonbind_marker_p (stmt)
+		      ? !MAY_HAVE_DEBUG_MARKER_STMTS
+		      : !MAY_HAVE_DEBUG_BIND_STMTS))
 		remove = true;
 	      if (is_gimple_call (stmt)
 		  && gimple_call_internal_p (stmt))
@@ -1182,6 +1185,13 @@ input_function (tree fn_decl, struct data_in *data_in,
 	    {
 	      gsi_next (&bsi);
 	      stmts[gimple_uid (stmt)] = stmt;
+
+	      /* Remember that the input function has begin stmt
+		 markers, so that we know to expect them when emitting
+		 debug info.  */
+	      if (!cfun->debug_nonbind_markers
+		  && gimple_debug_nonbind_marker_p (stmt))
+		cfun->debug_nonbind_markers = true;
 	    }
 	}
     }
diff --git a/gcc/params.def b/gcc/params.def
index 923ebc8e66c0..9d7f34fb003a 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -976,6 +976,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
 	  "Max. size of loc list for which reverse ops should be added.",
 	  50, 0, 0)
 
+/* Set a threshold to discard debug markers (e.g. debug begin stmt
+   markers) when expanding a function to RTL, or inlining it into
+   another function.  */
+
+DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
+	  "max-debug-marker-count",
+	  "Max. count of debug markers to expand or inline.",
+	  100000, 0, 0)
+
 /* Set minimum insn uid for non-debug insns.  */
 
 DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 5fe23801ab2d..0af739da0be6 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  fputc ('\t', m_outfile);
 	  break;
 
+	case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+	  {
+	    expanded_location xloc
+	      = expand_location (NOTE_MARKER_LOCATION (in_rtx));
+	    fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+	  }
+#endif
+	  break;
+
 	default:
 	  break;
 	}
@@ -1808,6 +1818,20 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 
     case DEBUG_INSN:
       {
+	if (DEBUG_MARKER_INSN_P (x))
+	  {
+	    switch (INSN_DEBUG_MARKER_KIND (x))
+	      {
+	      case NOTE_INSN_BEGIN_STMT:
+		pp_string (pp, "debug begin stmt marker");
+		break;
+
+	      default:
+		gcc_unreachable ();
+	      }
+	    break;
+	  }
+
 	const char *name = "?";
 	char idbuf[32];
 
diff --git a/gcc/recog.c b/gcc/recog.c
index cdcff8f2e720..3da6e5b827c8 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -2252,6 +2252,7 @@ extract_insn (rtx_insn *insn)
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
     case VAR_LOCATION:
+    case DEBUG_MARKER:
       return;
 
     case SET:
diff --git a/gcc/rtl.def b/gcc/rtl.def
index ee7b7e195243..0000808c9e99 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -766,6 +766,9 @@ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
    been optimized away completely.  */
 DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
 
+/* Used in marker DEBUG_INSNs to avoid being recognized as an insn.  */
+DEF_RTL_EXPR(DEBUG_MARKER, "debug_marker", "", RTX_EXTRA)
+
 /* All expressions from this point forward appear only in machine
    descriptions.  */
 #ifdef GENERATOR_FILE
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index e6e3f129d427..8604ba14a00a 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"
@@ -1355,7 +1356,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
   gimple_seq stmts = NULL;
 
   if (is_gimple_debug (stmt)
-      && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
+      && (gimple_debug_nonbind_marker_p (stmt)
+	  ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers
+	  : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return stmts;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
@@ -1638,6 +1641,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);
@@ -1733,7 +1750,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;
@@ -2555,6 +2573,8 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
 	      value = gimple_debug_source_bind_get_value (stmt);
 	      new_stmt = gimple_build_debug_source_bind (var, value, stmt);
 	    }
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    new_stmt = as_a <gdebug *> (gimple_copy (stmt));
 	  else
 	    gcc_unreachable ();
 	  gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2825,6 +2845,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;
@@ -2833,8 +2856,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
 
   if (gimple_debug_source_bind_p (stmt))
     t = gimple_debug_source_bind_get_var (stmt);
-  else
+  else if (gimple_debug_bind_p (stmt))
     t = gimple_debug_bind_get_var (stmt);
+  else
+    gcc_unreachable ();
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = id->debug_map->get (t)))
diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c
index c485413b5e50..10e510db0921 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 bf872b8d35e9..6519f3e35481 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -3230,6 +3230,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
       dump_block_node (pp, node, spc, flags);
       break;
 
+    case DEBUG_BEGIN_STMT:
+      pp_string (pp, "# DEBUG BEGIN STMT");
+      break;
+
     default:
       NIY;
     }
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 70675e4a3fcd..91793bfa59d3 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -712,6 +712,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
       gimple *stmt = gsi_stmt (si);
       if (!is_gimple_debug (stmt))
 	break;
+      if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       i++;
     }
 
@@ -739,6 +741,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	var = gimple_debug_bind_get_var (stmt);
       else if (gimple_debug_source_bind_p (stmt))
 	var = gimple_debug_source_bind_get_var (stmt);
+      else if (gimple_debug_nonbind_marker_p (stmt))
+	continue;
       else
 	gcc_unreachable ();
 
@@ -766,17 +770,23 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 	    var = gimple_debug_bind_get_var (stmt);
 	  else if (gimple_debug_source_bind_p (stmt))
 	    var = gimple_debug_source_bind_get_var (stmt);
+	  else if (gimple_debug_nonbind_marker_p (stmt))
+	    continue;
 	  else
 	    gcc_unreachable ();
 
-	  /* Discard debug bind overlaps.  ??? Unlike stmts from src,
+	  /* Discard debug bind overlaps.  Unlike stmts from src,
 	     copied into a new block that will precede BB, debug bind
 	     stmts in bypassed BBs may actually be discarded if
-	     they're overwritten by subsequent debug bind stmts, which
-	     might be a problem once we introduce stmt frontier notes
-	     or somesuch.  Adding `&& bb == src' to the condition
-	     below will preserve all potentially relevant debug
-	     notes.  */
+	     they're overwritten by subsequent debug bind stmts.  We
+	     want to copy binds for all modified variables, so that we
+	     retain a bind to the shared def if there is one, or to a
+	     newly introduced PHI node if there is one.  Our bind will
+	     end up reset if the value is dead, but that implies the
+	     variable couldn't have survived, so it's fine.  We are
+	     not actually running the code that performed the binds at
+	     this point, we're just adding binds so that they survive
+	     the new confluence, so markers should not be copied.  */
 	  if (vars && vars->add (var))
 	    continue;
 	  else if (!vars)
@@ -787,8 +797,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 		  break;
 	      if (i >= 0)
 		continue;
-
-	      if (fewvars.length () < (unsigned) alloc_count)
+	      else if (fewvars.length () < (unsigned) alloc_count)
 		fewvars.quick_push (var);
 	      else
 		{
diff --git a/gcc/tree.c b/gcc/tree.c
index 053670cb6b97..ed1852b3e66b 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1040,7 +1040,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:
@@ -4397,7 +4398,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 edcb7effd50e..137e63f255f9 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 49cbb99d2db2..892a8ba7f707 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1223,7 +1223,7 @@ extern void protected_set_expr_location (tree, location_t);
 
 /* GOTO_EXPR accessor. This gives access to the label associated with
    a goto statement.  */
-#define GOTO_DESTINATION(NODE)  TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE)  TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
 
 /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
    instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index b324a2c97c28..8e500b144712 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9926,6 +9926,36 @@ vt_init_cfa_base (void)
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
 }
 
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
+{
+  gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
+
+  enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
+
+  switch (kind)
+    {
+    case NOTE_INSN_BEGIN_STMT:
+      {
+	rtx_insn *note = NULL;
+	if (cfun->debug_nonbind_markers)
+	  {
+	    note = emit_note_before (kind, insn);
+	    NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
+	    if (bb)
+	      BLOCK_FOR_INSN (note) = *bb;
+	  }
+	delete_insn (insn);
+	return note;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
@@ -10169,6 +10199,12 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
+		  if (DEBUG_MARKER_INSN_P (insn))
+		    {
+		      insn = reemit_marker_as_note (insn, &save_bb);
+		      continue;
+		    }
+
 		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
@@ -10245,10 +10281,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;
@@ -10264,6 +10301,12 @@ delete_debug_insns (void)
 	   insn = next)
 	if (DEBUG_INSN_P (insn))
 	  {
+	    if (DEBUG_MARKER_INSN_P (insn))
+	      {
+		insn = reemit_marker_as_note (insn, NULL);
+		continue;
+	      }
+
 	    tree decl = INSN_VAR_LOCATION_DECL (insn);
 	    if (TREE_CODE (decl) == LABEL_DECL
 		&& DECL_NAME (decl)
@@ -10289,10 +10332,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.  */
@@ -10357,15 +10403,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)
     {
@@ -10387,7 +10439,9 @@ variable_tracking_main_1 (void)
     {
       vt_finalize ();
 
-      delete_debug_insns ();
+      cfun->debug_nonbind_markers = 0;
+
+      delete_vta_debug_insns ();
 
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-12-07 22:49                   ` Jeff Law
@ 2017-12-12  2:42                     ` Alexandre Oliva
  2017-12-12  9:16                       ` Christophe Lyon
  2018-01-07 17:48                       ` H.J. Lu
  0 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:42 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> Introduce a command line option to enable statement frontiers, enabled
>> by default in optimized builds with DWARF2+ debug information.
> OK once all prereqs are ack'd.

Thanks, here's what's installed, FTR:

From aa2fd8850c18861c8e3811b9174b0b1667111783 Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:16:31 +0000
Subject: [PATCH 6/7] [SFN] Introduce -gstatement-frontiers option, enable
 debug markers

Introduce a command line option to enable statement frontiers, enabled
by default in optimized builds with DWARF2+ debug information.

This patch depends on an earlier patch that completed the
infrastructure for debug markers, and on another patch that turns -g
into a negatable option prefix.

for  gcc/ChangeLog

	* common.opt (gstatement-frontiers): New, setting
	debug_nonbind_markers_p.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
	* toplev.c (process_options): Autodetect value for debug statement
	frontiers option.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255569 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog       |  8 ++++++++
 gcc/common.opt      |  4 ++++
 gcc/doc/invoke.texi | 12 ++++++++++++
 gcc/rtl.h           |  2 +-
 gcc/toplev.c        |  4 ++++
 gcc/tree.h          |  2 +-
 6 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 01bd2b9f49ad..a53e7b8173f5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,13 @@
 2017-12-12  Alexandre Oliva <aoliva@redhat.com>
 
+	* common.opt (gstatement-frontiers): New, setting
+	debug_nonbind_markers_p.
+	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
+	* toplev.c (process_options): Autodetect value for debug statement
+	frontiers option.
+	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
+	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
+
 	* cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
 	markers.  Integrate source bind into debug stmt expand loop.
 	(pass_expand::execute): Check debug marker limit.  Avoid deep
diff --git a/gcc/common.opt b/gcc/common.opt
index 57b3cd7304ab..d80ae5b7f39b 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2936,6 +2936,10 @@ gstabs+
 Common Driver JoinedOrMissing Negative(gvms)
 Generate debug information in extended STABS format.
 
+gstatement-frontiers
+Common Driver Var(debug_nonbind_markers_p) Init(2)
+Emit progressive recommended breakpoint locations.
+
 gstrict-dwarf
 Common Driver Report Var(dwarf_strict) Init(0)
 Don't emit DWARF additions beyond selected version.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 189b3e438fff..6402a5ae1734 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -346,6 +346,7 @@ 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
+-gstatement-frontiers  -gno-statement-frontiers @gol
 -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
 -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
 -fno-eliminate-unused-debug-types @gol
@@ -7146,6 +7147,17 @@ Emit location column information into DWARF debugging information, rather
 than just file and line.
 This option is enabled 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 -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 4de167d982cf..3ef687e5a371 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -816,7 +816,7 @@ struct GTY(()) rtvec_def {
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
 /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p
 /* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 2f154960a170..b6e038d2f89d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1536,6 +1536,10 @@ 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 (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/gcc/tree.h b/gcc/tree.h
index 892a8ba7f707..83af3bcaf55f 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1124,7 +1124,7 @@ 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 gimple_debug_nonbind_marker_p() may possibly hold.  */
-#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p
 /* Nonzero if gimple_debug_bind_p() (and thus
    gimple_debug_source_bind_p()) may possibly hold.  */
 #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers
  2017-12-07 22:51                   ` Jeff Law
@ 2017-12-12  2:44                     ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:44 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> The inline_entry hook will be given a definition in a later patch.
>> 
>> for  gcc/ChangeLog
>> 
>> * debug.h (gcc_debug_hooks): Add inline_entry.
>> * dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
>> * debug.c (do_nothing_debug_hooks): Likewise.
>> * vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
>> * dwarf2out.c (dwarf2_debug_hooks): Likewise.
>> (dwarf2_lineno_debug_hooks): Likewise.
> OK.

Thanks, I went ahead and installed this, as follows:

From 793569eb27eb1fdb494bd1229f181ba231bff16b Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:16:47 +0000
Subject: [PATCH 7/7] [IEPM] Introduce debug hook for inline entry point
 markers

The inline_entry hook will be given a definition in a later patch.

for  gcc/ChangeLog

	* debug.h (gcc_debug_hooks): Add inline_entry.
	* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
	* debug.c (do_nothing_debug_hooks): Likewise.
	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
	(dwarf2_lineno_debug_hooks): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255570 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog   | 7 +++++++
 gcc/dbxout.c    | 2 ++
 gcc/debug.c     | 1 +
 gcc/debug.h     | 3 +++
 gcc/dwarf2out.c | 2 ++
 gcc/vmsdbgout.c | 1 +
 6 files changed, 16 insertions(+)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a53e7b8173f5..4ad2df180147 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
 2017-12-12  Alexandre Oliva <aoliva@redhat.com>
 
+	* debug.h (gcc_debug_hooks): Add inline_entry.
+	* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
+	* debug.c (do_nothing_debug_hooks): Likewise.
+	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
+	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
+	(dwarf2_lineno_debug_hooks): Likewise.
+
 	* common.opt (gstatement-frontiers): New, setting
 	debug_nonbind_markers_p.
 	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 290f11b3c467..38cc63af9259 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -384,6 +384,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 */
   dbxout_switch_text_section,            /* switch_text_section */
   debug_nothing_tree_tree,		 /* set_name */
@@ -426,6 +427,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 4db94c3e675d..c0bc66764121 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -55,6 +55,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 277d990c20f0..bed3f176efbf 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -176,6 +176,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/dwarf2out.c b/gcc/dwarf2out.c
index 82c9ccfa7c25..70409410fde7 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2753,6 +2753,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
+  debug_nothing_tree,		/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -2793,6 +2794,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 */
diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
index 91dcd2e39109..03b7205a16b4 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -206,6 +206,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 */
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-12-11 23:12                   ` Jeff Law
@ 2017-12-12  2:52                     ` Alexandre Oliva
  2018-01-24 17:36                       ` Jakub Jelinek
  2018-02-06 21:13                       ` Jason Merrill
  0 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:52 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, Jakub Jelinek, gcc-patches

On Dec 11, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> This patch introduces an option to enable the generation of location
>> views along with location lists.  The exact format depends on the
>> void
>> +dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
>> +				const char *comment, ...)
> Needs a function comment.  Yes I realize others are missing in that
> file.  But I think it's best to avoid making the problem worse.

'k, added.

> The stuff outside dwarf2*.c is OK.  We really need Jason or Jakub to
> comment on the meat of the dwarf2 bits.

Here's an updated version of the patch, also including the comments and
other changes (*) that richi had requested.

(*) the earlier version of the patch added an #include that was had
already been rendered unnecessary; it is no longer added by this version.


[LVU] Introduce location views

This patch introduces an option to enable the generation of location
views along with location lists.  The exact format depends on the
DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
(DW_LLE_view_pair) entries in DWARF5+ loclists.

Line number tables are also affected.  If the assembler is found, at
compiler build time, to support .loc views, we use them and
assembler-computed view labels, otherwise we output compiler-generated
line number programs with conservatively-computed view labels.  In
either case, we output view information next to line number changes
when verbose assembly output is requested.

This patch requires an LVU patch that modifies the exported API of
final_scan_insn.  It also expects the entire SFN patchset to be
installed first, although SFN is not a requirement for LVU.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_locviews): New.
	* dwarf2.h (enum dwarf_location_list_entry_type): Add
	DW_LLE_GNU_view_pair.
	(DW_LLE_view_pair): Define.

for  gcc/ChangeLog

	* common.opt (gvariable-location-views): New.
	* config.in: Rebuilt.
	* configure: Rebuilt.
	* configure.ac: Test assembler for view support.
	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
	* dwarf2out.c (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.
	(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.
	(maybe_emit_file): Call output_asm_line_debug_info for test.
	(dwarf2out_var_location): Reset views as needed.  Precompute
	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
	attribute.  Set view.
	(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.
	Use output_dwarf_version.
	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
	(struct dw_val_node): Add val_view_list.
	* final.c (SEEN_NEXT_VIEW): New.
	(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.  Notify debug backend of section
	changes, and of location view changes.
	(rest_of_handle_final): Adjust.
	* opts.c (common_handle_option): Accept -gdwarf version 6.
	* toplev.c (process_options): Autodetect value for debug variable
	location views option.
	* doc/invoke.texi (gvariable-location-views): New.
	(gno-variable-location-views): New.
---
 gcc/common.opt      |    4 
 gcc/config.in       |    6 
 gcc/configure       |   46 ++++
 gcc/configure.ac    |   18 +
 gcc/doc/invoke.texi |   19 +
 gcc/dwarf2asm.c     |   27 ++
 gcc/dwarf2asm.h     |    4 
 gcc/dwarf2out.c     |  659 ++++++++++++++++++++++++++++++++++++++++++++++-----
 gcc/dwarf2out.h     |    4 
 gcc/final.c         |  148 +++++++++++
 gcc/opts.c          |    2 
 gcc/toplev.c        |    8 +
 include/dwarf2.def  |    1 
 include/dwarf2.h    |    8 +
 14 files changed, 872 insertions(+), 82 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index d80ae5b7f39b..a7609029af35 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2948,6 +2948,10 @@ gtoggle
 Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
+gvariable-location-views
+Common Driver Var(debug_variable_location_views) Init(2)
+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 5651bcba431c..e4154f666f96 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/configure b/gcc/configure
index 39eb3c829307..a0dbf9dfb84a 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27777,6 +27777,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 aec8df928bf0..6e50b5c8a889 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4862,9 +4862,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/doc/invoke.texi b/gcc/doc/invoke.texi
index 6402a5ae1734..71072052b928 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -347,6 +347,7 @@ Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gcolumn-info  -gno-column-info @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
 -fno-eliminate-unused-debug-types @gol
@@ -7158,6 +7159,24 @@ 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.
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index 8e3e86f224c1..51903274f232 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -767,6 +767,33 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
   va_end (ap);
 }
 
+/* output symbol LAB1 as an unsigned LEB128 quantity.  */
+
+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,
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index 7fc87a0b0c94..d8370df0ac71 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 70409410fde7..a88b4cdf6e25 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1287,6 +1287,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.  */
@@ -1296,9 +1298,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.  */
@@ -1335,6 +1339,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.  */
@@ -1410,6 +1439,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:
@@ -2857,7 +2888,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 {
@@ -2879,6 +2918,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;
 };
 
@@ -3080,6 +3138,44 @@ 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)
+
+/* Return true iff we're to emit .loc directives for the assembler to
+   generate line number sections.  */
+
+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
@@ -3189,6 +3285,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.  */
@@ -3397,6 +3494,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);
@@ -3433,7 +3532,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 void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -3633,8 +3732,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);
@@ -4630,11 +4729,65 @@ AT_loc_list (dw_attr_node *a)
   return a->dw_attr_val.v.val_loc_list;
 }
 
+/* Add a view list attribute to DIE.  It must have a DW_AT_location
+   attribute, because the view list complements the location 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);
+}
+
+/* Return a pointer to the location list referenced by the attribute.
+   If the named attribute is a view list, look up the corresponding
+   DW_AT_location attribute and return its location list.  */
+
 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 ();
+    }
+}
+
+/* Return the location attribute value associated with a view list
+   attribute value.  */
+
+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>
@@ -5889,7 +6042,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;
@@ -5980,7 +6133,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.  */
@@ -5996,7 +6149,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
 	    {
@@ -6131,6 +6284,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;
@@ -8991,6 +9150,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);
@@ -9362,6 +9522,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)
@@ -9636,7 +9797,8 @@ output_abbrev_section (void)
    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> ();
@@ -9646,10 +9808,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.  */
 
@@ -9658,6 +9838,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.  */
@@ -9665,34 +9938,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,
@@ -9710,6 +10034,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
@@ -9760,6 +10085,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);
@@ -9774,6 +10100,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);
@@ -9789,6 +10116,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);
@@ -9867,6 +10195,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
@@ -9931,6 +10262,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
@@ -10156,6 +10503,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))
 	    {
@@ -10340,6 +10691,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.  */
 
@@ -10356,7 +10729,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;
@@ -10568,7 +10941,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");
@@ -10867,7 +11240,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,
@@ -10949,7 +11322,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,
@@ -11214,7 +11587,7 @@ output_rnglists (unsigned generation)
   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
@@ -11848,8 +12221,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)
     {
@@ -11864,14 +12240,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)
 	    {
@@ -11979,7 +12377,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");
@@ -16346,6 +16744,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;
@@ -16410,24 +16809,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)
@@ -16462,11 +16864,11 @@ 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;
-	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin,
-				 endname, secname);
+	    endname = cfun->fde->dw_fde_second_end, endview = 0;
+	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, 0,
+				 endname, endview, secname);
 	  listp = &(*listp)->dw_loc_next;
 	}
     }
@@ -16477,8 +16879,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;
 }
@@ -17298,7 +17699,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;
     }
@@ -18111,7 +18512,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;
 }
@@ -18435,12 +18836,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.  */
@@ -19622,7 +20036,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;
     }
@@ -19638,7 +20052,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;
@@ -19660,14 +20074,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;
 	}
@@ -19676,19 +20090,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;
 }
@@ -26052,7 +26465,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,
@@ -26246,11 +26659,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++;
@@ -26284,6 +26699,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
 		}
 	    }
 	}
+      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;
     }
 
@@ -26347,10 +26774,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;
     }
@@ -26391,8 +26819,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
@@ -26460,7 +26888,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)
@@ -26469,6 +26900,7 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      newloc->view = view;
     }
 
   if (var_loc_p && flag_debug_asm)
@@ -26535,6 +26967,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;
 }
@@ -26583,7 +27016,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);
@@ -26764,7 +27197,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",
@@ -26787,6 +27220,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
@@ -26795,7 +27255,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)
@@ -27471,9 +27943,10 @@ init_sections_and_labels (bool early_lto_debug)
 					    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);
+
       debug_ranges_section = get_section (dwarf_version >= 5
 					  ? DEBUG_RNGLISTS_SECTION
 					  : DEBUG_RANGES_SECTION,
@@ -27858,6 +28331,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.
@@ -28957,6 +29435,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)
@@ -29001,7 +29481,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)
@@ -29071,6 +29551,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);
@@ -29096,6 +29577,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);
@@ -29492,6 +29988,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);
@@ -29713,6 +30211,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;
@@ -29731,6 +30230,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)
@@ -29741,11 +30242,33 @@ 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));
 }
 
@@ -29770,7 +30293,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
@@ -30194,7 +30717,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,
@@ -30253,7 +30776,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 940247316d39..a7653ceb6182 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/final.c b/gcc/final.c
index 3bcb9c5a2dd6..72719c218e0c 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -110,6 +110,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;
@@ -1758,6 +1759,66 @@ 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);
+    }
+}
+
+/* We want to emit param bindings (before the first begin_stmt) in the
+   initial view, if we are emitting views.  To that end, we may
+   consume initial notes in the function, processing them in
+   final_start_function, before signaling the beginning of the
+   prologue, rather than in final.
+
+   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.  */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+  return !DECL_IGNORED_P (current_function_decl)
+    && debug_variable_location_views
+    && insn && GET_CODE (insn) == NOTE
+    && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
+}
+
 /* 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
@@ -1765,12 +1826,15 @@ 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)
 {
   block_depth = 0;
 
@@ -1788,8 +1852,21 @@ final_start_function (rtx_insn *first, FILE *file,
   if (flag_sanitize & SANITIZE_ADDRESS)
     asan_function_start ();
 
+  rtx_insn *first = *firstp;
+  if (in_initial_view_p (first))
+    {
+      do
+	{
+	  final_scan_insn (first, file, 0, 0, seen);
+	  first = NEXT_INSN (first);
+	}
+      while (in_initial_view_p (first));
+      *firstp = first;
+    }
+
   if (!DECL_IGNORED_P (current_function_decl))
-    debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+    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);
@@ -1864,6 +1941,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 *first, FILE *file,
+		      int optimize_p ATTRIBUTE_UNUSED)
+{
+  int seen = 0;
+  final_start_function_1 (&first, file, &seen, optimize_p);
+  gcc_assert (seen == 0);
+}
+
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1993,11 +2081,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;
@@ -2064,6 +2151,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);
@@ -2080,6 +2169,23 @@ 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)
+{
+  /* Those that use the internal final_start_function_1/final_1 API
+     skip initial debug bind notes in final_start_function_1, and pass
+     the modified FIRST to final_1.  But those that use the public
+     final_start_function/final APIs, final_start_function can't move
+     FIRST because it's not passed by reference, so if they were
+     skipped there, skip them again here.  */
+  while (in_initial_view_p (first))
+    first = NEXT_INSN (first);
+
+  final_1 (first, file, 0, optimize_p);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2220,6 +2326,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 (in_cold_section_p)
@@ -2366,6 +2474,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
@@ -2422,7 +2532,10 @@ 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:
@@ -2433,6 +2546,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
 					   last_filename, last_discriminator,
 					   true);
+	      clear_next_view_needed (seen);
 	    }
 	  break;
 
@@ -2628,6 +2742,10 @@ 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
@@ -2640,7 +2758,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    (*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)
@@ -3107,7 +3230,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;
@@ -4546,8 +4670,10 @@ rest_of_handle_final (void)
     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 ();
diff --git a/gcc/opts.c b/gcc/opts.c
index a157b5f8816e..9a893fdb43e8 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2382,7 +2382,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/toplev.c b/gcc/toplev.c
index b6e038d2f89d..5f16c5b3f140 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1540,6 +1540,14 @@ process_options (void)
     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/include/dwarf2.def b/include/dwarf2.def
index 2a3b23fef873..f3fa4009207b 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* VMS extensions.  */
 DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
 /* GNAT extensions.  */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index a2e022dbdb35..fd76d82e6eb7 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -298,6 +298,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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2017-11-10  5:29                 ` [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
@ 2017-12-12  2:54                   ` Alexandre Oliva
  2017-12-21  5:18                     ` Jeff Law
  2018-01-24 17:40                     ` Jakub Jelinek
  0 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:54 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jeff Law, Jason Merrill, Jakub Jelinek, GCC Patches

On Nov 10, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> Output DW_AT_entry_pc based on markers.

Here's an updated version of the patch.

[IEPM] Introduce inline entry point markers

Output DW_AT_entry_pc based on markers.

Introduce DW_AT_GNU_entry_view as a DWARF extension.

If views are enabled are we're not in strict compliance mode, output
DW_AT_GNU_entry_view if it might be nonzero.

This patch depends on SFN and LVU patchsets, and on the IEPM patch that
introduces the inline_entry debug hook.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_entry_view): New.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
	markers.
	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
	(BLOCK_INLINE_ENTRY_LABEL): New.
	(dwarf2out_var_location): Disregard inline entry markers.
	(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.
	(block_within_block_p, dwarf2out_inline_entry): New.
	(dwarf2out_finish): Check that no entries remained in
	inline_entry_data_table.
	* final.c (reemit_insn_block_notes): Handle inline entry notes.
	(final_scan_insn, notice_source_line): Likewise.
	(rest_of_clean_state): Skip inline entry markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
	markers.
	* gimple.c (gimple_build_debug_inline_entry): New.
	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_INLINE_ENTRY.
	(gimple_build_debug_inline_entry): Declare.
	(gimple_debug_inline_entry_p): New.
	(gimple_debug_nonbind_marker_p): Adjust.
	* insn-notes.def (INLINE_ENTRY): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	inline entry marker notes.
	(print_insn): Likewise.
	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
	(INSN_DEBUG_MARKER_KIND): Likewise.
	(GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT): New.
	* tree-inline.c	(expand_call_inline): Build and insert
	debug_inline_entry stmt.
	* 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.
	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
	(gimple_build_debug_inline_entry): New.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
	Enable/disable inline entry points too.
	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
	(DEBUG_INSN): Describe inline entry markers.
---
 gcc/cfgexpand.c           |    9 ++
 gcc/doc/gimple.texi       |   18 ++++
 gcc/doc/rtl.texi          |   24 ++++-
 gcc/dwarf2out.c           |  199 ++++++++++++++++++++++++++++++++++++++++++++-
 gcc/final.c               |   26 ++++++
 gcc/gimple-pretty-print.c |   13 +++
 gcc/gimple.c              |   21 +++++
 gcc/gimple.h              |   18 ++++
 gcc/insn-notes.def        |    4 +
 gcc/print-rtl.c           |    5 +
 gcc/rtl.h                 |    7 +-
 gcc/tree-inline.c         |    7 ++
 gcc/tree-ssa-live.c       |   27 +++++-
 gcc/var-tracking.c        |    1 
 include/dwarf2.def        |    1 
 15 files changed, 364 insertions(+), 16 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index ce98264214ae..23a061fe1c40 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5713,6 +5713,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		goto delink_debug_stmt;
 	      else if (gimple_debug_begin_stmt_p (stmt))
 		val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT ();
+	      else if (gimple_debug_inline_entry_p (stmt))
+		{
+		  tree block = gimple_block (stmt);
+
+		  if (block)
+		    val = GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT ();
+		  else
+		    goto delink_debug_stmt;
+		}
 	      else
 		gcc_unreachable ();
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 492678705c6f..3825378080fa 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -836,6 +836,11 @@ Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
 a source statement.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_inline_entry_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the entry
+point of an inlined function.
+@end deftypefn
+
 @deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
 Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
 without any variable binding.
@@ -1541,6 +1546,7 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
 @cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
+@cindex @code{GIMPLE_DEBUG_INLINE_ENTRY}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
@@ -1626,6 +1632,18 @@ observable, and that none of the side effects of subsequent user
 statements are.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_inline_entry (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_INLINE_ENTRY} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that a
+function call at @code{location} underwent inline substitution, that
+@code{block} is the enclosing lexical block created for the
+substitution, and that at the point of the program in which the stmt is
+inserted, all parameters for the inlined function are bound to the
+respective arguments, and none of the side effects of its stmts are
+observable.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index dd3c0d3cfc1e..e219d4bdeacd 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3465,7 +3465,10 @@ Refers to a parameter that was completely optimized out.
 @item (debug_marker:@var{mode})
 Marks a program location.  With @code{VOIDmode}, it stands for the
 beginning of a statement, a recommended inspection point logically after
-all prior side effects, and before any subsequent side effects.
+all prior side effects, and before any subsequent side effects.  With
+@code{BLKmode}, it indicates an inline entry point: the lexical block
+encoded in the @code{INSN_LOCATION} is the enclosing block that encloses
+the inlined function.
 
 @end table
 
@@ -3749,6 +3752,13 @@ This note is used to generate @code{is_stmt} markers in line number
 debuggign information.  It indicates the beginning of a user
 statement.
 
+@findex NOTE_INSN_INLINE_ENTRY
+@item NOTE_INSN_INLINE_ENTRY
+This note is used to generate @code{entry_pc} for inlined subroutines in
+debugging information.  It indicates an inspection point at which all
+arguments for the inlined function have been bound, and before its first
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3766,8 +3776,12 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
-with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{GIMPLE_DEBUG_BEGIN_STMT} and @code{GIMPLE_DEBUG_INLINE_ENTRY} are
+expanded to RTL as a @code{DEBUG_INSN} with a @code{DEBUG_MARKER}
+@code{PATTERN}; the difference is the RTL mode: the former's
+@code{DEBUG_MARKER} is @code{VOIDmode}, whereas the latter is
+@code{BLKmode}; information about the inlined function can be taken from
+the lexical block encoded in the @code{INSN_LOCATION}.  These
 @code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
 just @code{DEBUG_MARKER}s, can be detected by testing
 @code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
@@ -3778,8 +3792,8 @@ 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,
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION},
+@code{NOTE_INSN_BEGIN_STMT} and @code{NOTE_INSN_INLINE_ENTRY} 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
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index a88b4cdf6e25..df2f6d92c6fc 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2731,6 +2731,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);
@@ -2784,7 +2785,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
-  debug_nothing_tree,		/* inline_entry */
+  dwarf2out_inline_entry,	/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -4025,6 +4026,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
@@ -23079,6 +23083,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
@@ -23533,6 +23579,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 (MAY_HAVE_DEBUG_MARKER_INSNS);
+      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))
     {
@@ -23540,7 +23622,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 (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23705,7 +23787,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26735,6 +26817,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
       || ! 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;
 
@@ -26923,6 +27006,113 @@ create_label:
   last_in_cold_section_p = in_cold_section_p;
 }
 
+/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
+   OUTER itself.  If BOTHWAYS, check not only that BLOCK can reach
+   OUTER through BLOCK_SUPERCONTEXT links, but also that there is a
+   path from OUTER to BLOCK through BLOCK_SUBBLOCKs and
+   BLOCK_FRAGMENT_ORIGIN links.  */
+static bool
+block_within_block_p (tree block, tree outer, bool bothways)
+{
+  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;
+
+  if (!bothways)
+    return true;
+
+  /* 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)));
+
+  /* Sanity check the block tree.  This would catch a case in which
+     BLOCK got removed from the tree reachable from the outermost
+     lexical block, but got retained in markers.  It would still link
+     back to its parents, but some ancestor would be missing a link
+     down the path to the sub BLOCK.  If the block got removed, its
+     BLOCK_NUMBER will not be a usable value.  */
+  gcc_checking_assert (block_within_block_p (block,
+					     DECL_INITIAL
+					     (current_function_decl),
+					     true));
+
+  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.  */
@@ -30401,6 +30591,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 ());
diff --git a/gcc/final.c b/gcc/final.c
index 72719c218e0c..6a8693d6b1f9 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1677,6 +1677,7 @@ reemit_insn_block_notes (void)
 	    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;
 
@@ -2543,6 +2544,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  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);
@@ -2550,6 +2552,18 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    }
 	  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:
 	  gcc_unreachable ();
 	  break;
@@ -3253,6 +3267,17 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   if (NOTE_MARKER_P (insn))
     {
       location_t loc = NOTE_MARKER_LOCATION (insn);
+      /* The inline entry markers (gimple, insn, note) carry the
+	 location of the call, because that's what we want to carry
+	 during compilation, but the location we want to output in
+	 debug information for the inline entry point is the location
+	 of the function itself.  */
+      if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY)
+	{
+	  tree block = LOCATION_BLOCK (loc);
+	  tree fn = block_ultimate_origin (block);
+	  loc = DECL_SOURCE_LOCATION (fn);
+	}
       expanded_location xloc = expand_location (loc);
       if (xloc.line == 0)
 	{
@@ -4859,6 +4884,7 @@ rest_of_clean_state (void)
 	  && (!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/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index aee2ad8f1ea1..1a0551033c99 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1370,6 +1370,19 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 	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 5a118e9095ca..be422467b11e 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -874,6 +874,27 @@ gimple_build_debug_begin_stmt (tree block, location_t location
 }
 
 
+/* 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.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 7c36679d092f..0406aedcf0e4 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -202,7 +202,8 @@ enum gf_mask {
 enum gimple_debug_subcode {
   GIMPLE_DEBUG_BIND = 0,
   GIMPLE_DEBUG_SOURCE_BIND = 1,
-  GIMPLE_DEBUG_BEGIN_STMT = 2
+  GIMPLE_DEBUG_BEGIN_STMT = 2,
+  GIMPLE_DEBUG_INLINE_ENTRY = 3
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -1454,6 +1455,7 @@ 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);
@@ -4784,13 +4786,25 @@ gimple_debug_begin_stmt_p (const gimple *s)
   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;
+    return s->subcode == GIMPLE_DEBUG_BEGIN_STMT
+      || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
 
   return false;
 }
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index 960487b31db1..252e95722447 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -71,6 +71,10 @@ 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/print-rtl.c b/gcc/print-rtl.c
index 0af739da0be6..af9448de6e43 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -259,6 +259,7 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_BEGIN_STMT:
+	case NOTE_INSN_INLINE_ENTRY:
 #ifndef GENERATOR_FILE
 	  {
 	    expanded_location xloc
@@ -1826,6 +1827,10 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 		pp_string (pp, "debug begin stmt marker");
 		break;
 
+	      case NOTE_INSN_INLINE_ENTRY:
+		pp_string (pp, "debug inline entry marker");
+		break;
+
 	      default:
 		gcc_unreachable ();
 	      }
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3ef687e5a371..63df02e0376a 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1625,7 +1625,8 @@ extern const char * const reg_note_name[];
    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_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))
@@ -1663,6 +1664,8 @@ extern const char * const reg_note_name[];
   (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
    ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
       ? NOTE_INSN_BEGIN_STMT			  \
+      : GET_MODE (PATTERN (INSN)) == BLKmode	  \
+      ? NOTE_INSN_INLINE_ENTRY			  \
       : (enum insn_note)-1) 			  \
    : (enum insn_note)-1)
 /* Create patterns for debug markers.  These and the above abstract
@@ -1672,6 +1675,8 @@ extern const char * const reg_note_name[];
    wouldn't be a problem.  */
 #define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \
   gen_rtx_DEBUG_MARKER (VOIDmode)
+#define GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT() \
+  gen_rtx_DEBUG_MARKER (BLKmode)
 
 /* The VAR_LOCATION rtx in a DEBUG_INSN.  */
 #define INSN_VAR_LOCATION(INSN) \
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 8604ba14a00a..f312b50ce57c 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4602,6 +4602,13 @@ 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, input_location), GSI_NEW_STMT);
+    }
 
   if (DECL_INITIAL (fn))
     {
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 8738fe21a6e1..734d15df2c51 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/var-tracking.c b/gcc/var-tracking.c
index 8e500b144712..4f8f9f182203 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9938,6 +9938,7 @@ reemit_marker_as_note (rtx_insn *insn, basic_block *bb)
   switch (kind)
     {
     case NOTE_INSN_BEGIN_STMT:
+    case NOTE_INSN_INLINE_ENTRY:
       {
 	rtx_insn *note = NULL;
 	if (cfun->debug_nonbind_markers)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index f3fa4009207b..8e731a3b87a6 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -444,6 +444,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
    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.  */

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers
  2017-12-07 22:27                   ` Jeff Law
@ 2017-12-12  2:55                     ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  2:55 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> This patch introduces a number of new macros and functions that will
> OK.  Again, I think this can probably go in as-is.

Thanks, FTR here's the installed patch:

From c64f38bf4d2f6c50fdc5122d129d2ad34088d19c Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:15:00 +0000
Subject: [PATCH 2/7] [SFN] boilerplate changes in preparation to introduce
 nonbind markers

This patch introduces a number of new macros and functions that will
be used to distinguish between different kinds of debug stmts, insns
and notes, namely, preexisting debug bind ones and to-be-introduced
nonbind markers.

In a seemingly mechanical way, it adjusts several uses of the macros
and functions, so that they refer to narrower categories when
appropriate.

These changes, by themselves, should not have any visible effect in
the compiler behavior, since the upcoming debug markers are never
created with this patch alone.

for  gcc/ChangeLog

	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_BEGIN_STMT.
	(gimple_debug_begin_stmt_p): New.
	(gimple_debug_nonbind_marker_p): New.
	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
	(MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
	(MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
	* insn-notes.def (BEGIN_STMT): New.
	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
	(MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
	(MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
	(NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
	(DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
	(INSN_DEBUG_MARKER_KIND): New.
	(GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT): New.
	(INSN_VAR_LOCATION): Check for VAR_LOCATION.
	(INSN_VAR_LOCATION_PTR): New.
	* cfgexpand.c (expand_debug_locations): Handle debug bind insns
	only.
	(expand_gimple_basic_block): Likewise.  Emit debug temps for TER
	deps only if debug bind insns are enabled.
	(pass_expand::execute): Avoid deep TER and expand
	debug locations for debug bind insns only.
	* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
	debug stmts special handling down to debug bind stmts.
	* combine.c (try_combine): Narrow debug insns special handling
	down to debug bind insns.
	* cse.c (delete_trivially_dead_insns): Handle debug bindings.
	Narrow debug insns preexisting special handling down to debug
	bind insns.
	* dce.c (rest_of_handle_ud_dce): Narrow debug insns special
	handling down to debug bind insns.
	* function.c (instantiate_virtual_regs): Skip debug markers,
	adjust handling of debug binds.
	* gimple-ssa-backprop.c (backprop::prepare_change): Try debug
	temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
	* haifa-sched.c (schedule_insn): Narrow special handling of debug
	insns to debug bind insns.
	* ipa-param-manipulation.c (ipa_modify_call_arguments): Narrow
	special handling of debug stmts to debug bind stmts.
	* ipa-split.c (split_function): Likewise.
	* ira.c (combine_and_move_insns): Adjust debug bind insns only.
	* loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
	debug insns.
	* reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
	* regrename.c (build_def_use): Likewise.
	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
	(pass_cprop_hardreg): Narrow special casing of debug insns to
	debug bind insns.
	* regstat.c (regstat_init_n_sets_and_refs): Likewise.
	* reload1.c (reload): Likewise.
	* sese.c (sese_insert_phis_for_liveouts): Narrow special
	casing of debug stmts to debug bind stmts.
	* shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
	* ssa-iterators.h (num_imm_uses): Likewise.
	* tree-cfg.c (gimple_merge_blocks): Narrow special casing of
	debug stmts to debug bind stmts.
	* tree-inline.c	(tree_function_versioning): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-loop-distribution.c (generate_loops_for_partition):
	Narrow special casing of debug stmts to debug bind stmts.
	* tree-sra.c (analyze_access_subtree): Narrow special casing
	of debug stmts to debug bind stmts.
	* tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
	stmts to debug bind stmts.
	* tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
	* tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
	casing of debug stmts to debug bind stmts.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
	Likewise.
	* tree-ssa.c (flush_pending_stmts): Narrow special casing of
	debug stmts to debug bind stmts.
	(gimple_replace_ssa_lhs): Likewise.
	(insert_debug_temp_for_var_def): Likewise.
	(insert_debug_temps_for_defs): Likewise.
	(reset_debug_uses): Likewise.
	* tree-ssanames.c (release_ssa_name_fn): Likewise.
	* tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
	(adjust_debug_stmts): Likewise.
	(adjust_phi_and_debug_stmts): Likewise.
	(vect_do_peeling): Likewise.
	* tree-vect-loop.c (vect_transform_loop): Likewise.
	* valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
	* var-tracking.c (adjust_mems): Narrow special casing of debug
	insns to debug bind insns.
	(dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
	(compute_bb_dataflow, vt_find_locations): Likewise.
	(vt_expand_loc, emit_notes_for_changes): Likewise.
	(vt_init_cfa_base): Likewise.
	(vt_emit_notes): Likewise.
	(vt_initialize): Likewise.
	(vt_finalize): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255565 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                | 95 ++++++++++++++++++++++++++++++++++++++++++++
 gcc/cfgexpand.c              |  8 ++--
 gcc/cgraph.c                 |  2 +-
 gcc/combine.c                | 12 +++---
 gcc/cse.c                    | 17 ++++----
 gcc/dce.c                    |  2 +-
 gcc/function.c               |  7 ++--
 gcc/gimple-ssa-backprop.c    |  2 +-
 gcc/gimple.h                 | 31 ++++++++++++---
 gcc/haifa-sched.c            |  4 +-
 gcc/insn-notes.def           |  3 ++
 gcc/ipa-param-manipulation.c |  2 +-
 gcc/ipa-split.c              | 11 ++---
 gcc/ira.c                    |  4 +-
 gcc/loop-unroll.c            |  6 ++-
 gcc/reg-stack.c              |  4 +-
 gcc/regcprop.c               |  4 +-
 gcc/regrename.c              |  2 +-
 gcc/regstat.c                |  2 +-
 gcc/reload1.c                |  4 +-
 gcc/rtl.h                    | 47 +++++++++++++++++++++-
 gcc/sese.c                   |  2 +-
 gcc/shrink-wrap.c            |  4 +-
 gcc/ssa-iterators.h          |  2 +-
 gcc/tree-cfg.c               |  2 +-
 gcc/tree-inline.c            |  4 +-
 gcc/tree-loop-distribution.c |  2 +-
 gcc/tree-sra.c               |  2 +-
 gcc/tree-ssa-dce.c           |  2 +-
 gcc/tree-ssa-loop-ivopts.c   |  2 +-
 gcc/tree-ssa-reassoc.c       |  2 +-
 gcc/tree-ssa-tail-merge.c    |  2 +-
 gcc/tree-ssa-threadedge.c    |  2 +-
 gcc/tree-ssa.c               | 10 ++---
 gcc/tree-ssanames.c          |  2 +-
 gcc/tree-vect-loop-manip.c   |  8 ++--
 gcc/tree-vect-loop.c         |  4 +-
 gcc/tree.h                   |  8 +++-
 gcc/valtrack.c               |  2 +-
 gcc/var-tracking.c           | 50 +++++++++++------------
 40 files changed, 277 insertions(+), 104 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6d0a64e6adcc..286a0fbac94c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,100 @@
 2017-12-12  Alexandre Oliva <aoliva@redhat.com>
 
+	* gimple.h (enum gimple_debug_subcode): Add
+	GIMPLE_DEBUG_BEGIN_STMT.
+	(gimple_debug_begin_stmt_p): New.
+	(gimple_debug_nonbind_marker_p): New.
+	* tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): New.
+	(MAY_HAVE_DEBUG_BIND_STMTS): Renamed from....
+	(MAY_HAVE_DEBUG_STMTS): ... this.  Check both.
+	* insn-notes.def (BEGIN_STMT): New.
+	* rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): New.
+	(MAY_HAVE_DEBUG_BIND_INSNS): Renamed from....
+	(MAY_HAVE_DEBUG_INSNS): ... this.  Check both.
+	(NOTE_MARKER_LOCATION, NOTE_MARKER_P): New.
+	(DEBUG_BIND_INSN_P, DEBUG_MARKER_INSN_P): New.
+	(INSN_DEBUG_MARKER_KIND): New.
+	(GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT): New.
+	(INSN_VAR_LOCATION): Check for VAR_LOCATION.
+	(INSN_VAR_LOCATION_PTR): New.
+	* cfgexpand.c (expand_debug_locations): Handle debug bind insns
+	only.
+	(expand_gimple_basic_block): Likewise.  Emit debug temps for TER
+	deps only if debug bind insns are enabled.
+	(pass_expand::execute): Avoid deep TER and expand
+	debug locations for debug bind insns only.
+	* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Narrow
+	debug stmts special handling down to debug bind stmts.
+	* combine.c (try_combine): Narrow debug insns special handling
+	down to debug bind insns.
+	* cse.c (delete_trivially_dead_insns): Handle debug bindings.
+	Narrow debug insns preexisting special handling down to debug
+	bind insns.
+	* dce.c (rest_of_handle_ud_dce): Narrow debug insns special
+	handling down to debug bind insns.
+	* function.c (instantiate_virtual_regs): Skip debug markers,
+	adjust handling of debug binds.
+	* gimple-ssa-backprop.c (backprop::prepare_change): Try debug
+	temp insertion iff MAY_HAVE_DEBUG_BIND_STMTS.
+	* haifa-sched.c (schedule_insn): Narrow special handling of debug
+	insns to debug bind insns.
+	* ipa-param-manipulation.c (ipa_modify_call_arguments): Narrow
+	special handling of debug stmts to debug bind stmts.
+	* ipa-split.c (split_function): Likewise.
+	* ira.c (combine_and_move_insns): Adjust debug bind insns only.
+	* loop-unroll.c (apply_opt_in_copies): Adjust tests on bind
+	debug insns.
+	* reg-stack.c (convert_regs_1): Use DEBUG_BIND_INSN_P.
+	* regrename.c (build_def_use): Likewise.
+	* regcprop.c (copyprop_hardreg_forward_1): Likewise.
+	(pass_cprop_hardreg): Narrow special casing of debug insns to
+	debug bind insns.
+	* regstat.c (regstat_init_n_sets_and_refs): Likewise.
+	* reload1.c (reload): Likewise.
+	* sese.c (sese_insert_phis_for_liveouts): Narrow special
+	casing of debug stmts to debug bind stmts.
+	* shrink-wrap.c (move_insn_for_shrink_wrap): Likewise.
+	* ssa-iterators.h (num_imm_uses): Likewise.
+	* tree-cfg.c (gimple_merge_blocks): Narrow special casing of
+	debug stmts to debug bind stmts.
+	* tree-inline.c	(tree_function_versioning): Narrow special casing
+	of debug stmts to debug bind stmts.
+	* tree-loop-distribution.c (generate_loops_for_partition):
+	Narrow special casing of debug stmts to debug bind stmts.
+	* tree-sra.c (analyze_access_subtree): Narrow special casing
+	of debug stmts to debug bind stmts.
+	* tree-ssa-dce.c (remove_dead_stmt): Narrow special casing of debug
+	stmts to debug bind stmts.
+	* tree-ssa-loop-ivopt.c (remove_unused_ivs): Narrow special
+	casing of debug stmts to debug bind stmts.
+	* tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise.
+	* tree-ssa-tail-merge.c (tail_merge_optimize): Narrow special
+	casing of debug stmts to debug bind stmts.
+	* tree-ssa-threadedge.c (propagate_threaded_block_debug_info):
+	Likewise.
+	* tree-ssa.c (flush_pending_stmts): Narrow special casing of
+	debug stmts to debug bind stmts.
+	(gimple_replace_ssa_lhs): Likewise.
+	(insert_debug_temp_for_var_def): Likewise.
+	(insert_debug_temps_for_defs): Likewise.
+	(reset_debug_uses): Likewise.
+	* tree-ssanames.c (release_ssa_name_fn): Likewise.
+	* tree-vect-loop-manip.c (adjust_debug_stmts_now): Likewise.
+	(adjust_debug_stmts): Likewise.
+	(adjust_phi_and_debug_stmts): Likewise.
+	(vect_do_peeling): Likewise.
+	* tree-vect-loop.c (vect_transform_loop): Likewise.
+	* valtrack.c (propagate_for_debug): Use BIND_DEBUG_INSN_P.
+	* var-tracking.c (adjust_mems): Narrow special casing of debug
+	insns to debug bind insns.
+	(dv_onepart_p, dataflow_set_clar_at_call, use_type): Likewise.
+	(compute_bb_dataflow, vt_find_locations): Likewise.
+	(vt_expand_loc, emit_notes_for_changes): Likewise.
+	(vt_init_cfa_base): Likewise.
+	(vt_emit_notes): Likewise.
+	(vt_initialize): Likewise.
+	(vt_finalize): Likewise.
+
 	* 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.
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index d1140602da4b..b1646a5ec507 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5307,7 +5307,7 @@ expand_debug_locations (void)
   flag_strict_aliasing = 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (DEBUG_INSN_P (insn))
+    if (DEBUG_BIND_INSN_P (insn))
       {
 	tree value = (tree)INSN_VAR_LOCATION_LOC (insn);
 	rtx val;
@@ -5560,7 +5560,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 	   a_2 = ...
            #DEBUG ... => #D1
 	 */
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && SA.values
 	  && !is_gimple_debug (stmt))
 	{
@@ -6181,7 +6181,7 @@ pass_expand::execute (function *fun)
   timevar_pop (TV_OUT_OF_SSA);
   SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions);
 
-  if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter)
+  if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter)
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, cfun)
@@ -6372,7 +6372,7 @@ pass_expand::execute (function *fun)
 		  next_bb)
     bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     expand_debug_locations ();
 
   if (deep_ter_debug_map)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 7ac58ce91c1a..17a0d32ce5ea 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1431,7 +1431,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
 	 stmts and associate D#X with parm in decl_debug_args_lookup
 	 vector to say for debug info that if parameter parm had been passed,
 	 it would have value parm_Y(D).  */
-      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  vec<tree, va_gc> **debug_args
 	    = decl_debug_args_lookup (e->callee->decl);
diff --git a/gcc/combine.c b/gcc/combine.c
index 7f10c67bf0f6..f4e94450c094 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3778,7 +3778,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 	  /* *SPLIT may be part of I2SRC, so make sure we have the
 	     original expression around for later debug processing.
 	     We should not need I2SRC any more in other cases.  */
-	  if (MAY_HAVE_DEBUG_INSNS)
+	  if (MAY_HAVE_DEBUG_BIND_INSNS)
 	    i2src = copy_rtx (i2src);
 	  else
 	    i2src = NULL;
@@ -4134,7 +4134,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       struct undo *undo;
 
@@ -4447,7 +4447,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
 
     if (newi2pat)
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2scratch)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2scratch)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	INSN_CODE (i2) = i2_code_number;
@@ -4455,7 +4455,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       }
     else
       {
-	if (MAY_HAVE_DEBUG_INSNS && i2src)
+	if (MAY_HAVE_DEBUG_BIND_INSNS && i2src)
 	  propagate_for_debug (i2, last_combined_insn, i2dest, i2src,
 			       this_basic_block);
 	SET_INSN_DELETED (i2);
@@ -4465,7 +4465,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i1) = NULL;
 	REG_NOTES (i1) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i1, last_combined_insn, i1dest, i1src,
 			       this_basic_block);
 	SET_INSN_DELETED (i1);
@@ -4475,7 +4475,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       {
 	LOG_LINKS (i0) = NULL;
 	REG_NOTES (i0) = 0;
-	if (MAY_HAVE_DEBUG_INSNS)
+	if (MAY_HAVE_DEBUG_BIND_INSNS)
 	  propagate_for_debug (i0, last_combined_insn, i0dest, i0src,
 			       this_basic_block);
 	SET_INSN_DELETED (i0);
diff --git a/gcc/cse.c b/gcc/cse.c
index 65cc9ae110c1..e449223cbb25 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -7049,11 +7049,11 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       counts = XCNEWVEC (int, nreg * 3);
       for (insn = insns; insn; insn = NEXT_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_INSN_P (insn))
 	  count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
 			   NULL_RTX, 1);
 	else if (INSN_P (insn))
@@ -7111,12 +7111,15 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
       if (! live_insn && dbg_cnt (delete_trivial_dead))
 	{
 	  if (DEBUG_INSN_P (insn))
-	    count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-			     NULL_RTX, -1);
+	    {
+	      if (DEBUG_BIND_INSN_P (insn))
+		count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+				 NULL_RTX, -1);
+	    }
 	  else
 	    {
 	      rtx set;
-	      if (MAY_HAVE_DEBUG_INSNS
+	      if (MAY_HAVE_DEBUG_BIND_INSNS
 		  && (set = single_set (insn)) != NULL_RTX
 		  && is_dead_reg (SET_DEST (set), counts)
 		  /* Used at least once in some DEBUG_INSN.  */
@@ -7156,10 +7159,10 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-	if (DEBUG_INSN_P (insn))
+	if (DEBUG_BIND_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/dce.c b/gcc/dce.c
index 7534d2abadf6..6fd9548015ce 100644
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -777,7 +777,7 @@ rest_of_handle_ud_dce (void)
     }
   worklist.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     reset_unmarked_insns_debug_uses ();
 
   /* Before any insns are deleted, we must remove the chains since
diff --git a/gcc/function.c b/gcc/function.c
index 1fa538b4b7fd..88f93db6cf0f 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
+	    || DEBUG_MARKER_INSN_P (insn))
 	  continue;
-	else if (DEBUG_INSN_P (insn))
-	  instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
+	else if (DEBUG_BIND_INSN_P (insn))
+	  instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
 	else
 	  instantiate_virtual_regs_in_insn (insn);
 
diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c
index 1daa0ceef0ac..8068c2ab1f71 100644
--- a/gcc/gimple-ssa-backprop.c
+++ b/gcc/gimple-ssa-backprop.c
@@ -729,7 +729,7 @@ strip_sign_op (tree rhs)
 void
 backprop::prepare_change (tree var)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     insert_debug_temp_for_var_def (NULL, var);
   reset_flow_sensitive_info (var);
 }
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 0fcdd05aaba6..d34aa142849c 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -197,13 +197,12 @@ 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
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -4757,6 +4756,28 @@ 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 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;
+
+  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/haifa-sched.c b/gcc/haifa-sched.c
index f5c06a95bb67..b7c0b3a6f4ff 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -4010,7 +4010,7 @@ schedule_insn (rtx_insn *insn)
   gcc_assert (sd_lists_empty_p (insn, SD_LIST_HARD_BACK));
 
   /* Reset debug insns invalidated by moving this insn.  */
-  if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn))
+  if (MAY_HAVE_DEBUG_BIND_INSNS && !DEBUG_INSN_P (insn))
     for (sd_it = sd_iterator_start (insn, SD_LIST_BACK);
 	 sd_iterator_cond (&sd_it, &dep);)
       {
@@ -4023,7 +4023,7 @@ schedule_insn (rtx_insn *insn)
 	    continue;
 	  }
 
-	gcc_assert (DEBUG_INSN_P (dbg));
+	gcc_assert (DEBUG_BIND_INSN_P (dbg));
 
 	if (sched_verbose >= 6)
 	  fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n",
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index f96ce18ecb6d..960487b31db1 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
 /* The values passed to callee.  */
 INSN_NOTE (CALL_ARG_LOCATION)
 
+/* The beginning of a statement.  */
+INSN_NOTE (BEGIN_STMT)
+
 /* 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-param-manipulation.c b/gcc/ipa-param-manipulation.c
index bedd201f6dd1..bcc736b99c0f 100644
--- a/gcc/ipa-param-manipulation.c
+++ b/gcc/ipa-param-manipulation.c
@@ -402,7 +402,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
 	    }
 	  vargs.quick_push (expr);
 	}
-      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
+      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  unsigned int ix;
 	  tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index 7ebd51554e56..48857c2aab37 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1485,7 +1485,7 @@ split_function (basic_block return_bb, struct split_point *split_point,
     {
       vec<tree, va_gc> **debug_args = NULL;
       unsigned i = 0, len = 0;
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  debug_args = decl_debug_args_lookup (node->decl);
 	  if (debug_args)
@@ -1498,11 +1498,12 @@ split_function (basic_block return_bb, struct split_point *split_point,
 	    tree ddecl;
 	    gimple *def_temp;
 
-	    /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
-	       otherwise if it didn't exist before, we'd end up with
-	       different SSA_NAME_VERSIONs between -g and -g0.  */
+	    /* This needs to be done even without
+	       MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist
+	       before, we'd end up with different SSA_NAME_VERSIONs
+	       between -g and -g0.  */
 	    arg = get_or_create_ssa_default_def (cfun, parm);
-	    if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL)
+	    if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL)
 	      continue;
 
 	    while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
diff --git a/gcc/ira.c b/gcc/ira.c
index a9ed17ea308b..79837da1db51 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3839,9 +3839,9 @@ combine_and_move_insns (void)
 	}
 
       /* Last pass - adjust debug insns referencing cleared regs.  */
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
-	  if (DEBUG_INSN_P (insn))
+	  if (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
 	      INSN_VAR_LOCATION_LOC (insn)
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 0fdecd7fde2d..cc154da9686a 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -2037,12 +2037,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)
+	      || (DEBUG_BIND_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)
+		 || (DEBUG_BIND_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/reg-stack.c b/gcc/reg-stack.c
index 4f67a7bfa507..fe754b242d58 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -3034,7 +3034,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 (DEBUG_BIND_INSN_P (insn))
 	{
 	  if (starting_stack_p)
 	    debug_insns_with_starting_stack++;
@@ -3074,7 +3074,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 (!DEBUG_BIND_INSN_P (insn))
 	    continue;
 
 	  debug_insns_with_starting_stack--;
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index b80019b5be0d..15d8b140ce7f 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -752,7 +752,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 (DEBUG_BIND_INSN_P (insn))
 	    {
 	      rtx loc = INSN_VAR_LOCATION_LOC (insn);
 	      if (!VAR_LOC_UNKNOWN_P (loc))
@@ -1296,7 +1296,7 @@ pass_cprop_hardreg::execute (function *fun)
       copyprop_hardreg_forward_1 (bb, all_vd + bb->index);
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       FOR_EACH_BB_FN (bb, fun)
 	if (bitmap_bit_p (visited, bb->index)
diff --git a/gcc/regrename.c b/gcc/regrename.c
index 7fbfa3162ca6..89380a877004 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 (DEBUG_BIND_INSN_P (insn)
 	       && !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
 	{
 	  scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
diff --git a/gcc/regstat.c b/gcc/regstat.c
index 3fd26fd2fc68..fd3d3a8d98bd 100644
--- a/gcc/regstat.c
+++ b/gcc/regstat.c
@@ -54,7 +54,7 @@ regstat_init_n_sets_and_refs (void)
 
   regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     for (i = 0; i < max_regno; i++)
       {
 	int use_count;
diff --git a/gcc/reload1.c b/gcc/reload1.c
index e15bd8a2c1a9..322696a25f3e 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1112,7 +1112,7 @@ reload (rtx_insn *first, int global)
       /* We don't want complex addressing modes in debug insns
 	 if simpler ones will do, so delegitimize equivalences
 	 in debug insns.  */
-      if (MAY_HAVE_DEBUG_INSNS && reg_renumber[i] < 0)
+      if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0)
 	{
 	  rtx reg = regno_reg_rtx[i];
 	  rtx equiv = 0;
@@ -1140,7 +1140,7 @@ reload (rtx_insn *first, int global)
 	      while (next && DF_REF_INSN (next) == insn)
 		next = DF_REF_NEXT_REG (next);
 
-	      if (DEBUG_INSN_P (insn))
+	      if (DEBUG_BIND_INSN_P (insn))
 		{
 		  if (!equiv)
 		    {
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 9cc982172f53..4de167d982cf 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -815,8 +815,13 @@ struct GTY(()) rtvec_def {
 /* Predicate yielding nonzero iff X is an insn that is not a debug insn.  */
 #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
 
+/* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
+/* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
 /* Nonzero if DEBUG_INSN_P may possibly hold.  */
-#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_INSNS					\
+  (MAY_HAVE_DEBUG_MARKER_INSNS || MAY_HAVE_DEBUG_BIND_INSNS)
 
 /* Predicate yielding nonzero iff X is a real insn.  */
 #define INSN_P(X) \
@@ -1604,6 +1609,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)
 
@@ -1615,6 +1621,12 @@ 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))
+
 /* 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))
@@ -1634,8 +1646,39 @@ 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 DEBUG_BIND_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 DEBUG_MARKER_INSN_P(INSN)		\
+  (DEBUG_INSN_P (INSN)				\
+   && (GET_CODE (PATTERN (INSN))		\
+       != VAR_LOCATION))
+/* Evaluate to the marker kind.  */
+#define INSN_DEBUG_MARKER_KIND(INSN)		  \
+  (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
+   ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
+      ? NOTE_INSN_BEGIN_STMT			  \
+      : (enum insn_note)-1) 			  \
+   : (enum insn_note)-1)
+/* Create patterns for debug markers.  These and the above abstract
+   the representation, so that it's easier to get rid of the abuse of
+   the mode to hold the marker kind.  Other marker types are
+   envisioned, so a single bit flag won't do; maybe separate RTL codes
+   wouldn't be a problem.  */
+#define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \
+  gen_rtx_DEBUG_MARKER (VOIDmode)
+
 /* 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) \
diff --git a/gcc/sese.c b/gcc/sese.c
index 89cddf0ec974..bbc72d4d7618 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -205,7 +205,7 @@ void
 sese_insert_phis_for_liveouts (sese_info_p region, basic_block bb,
 			       edge false_e, edge true_e)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     sese_reset_debug_liveouts (region);
 
   unsigned i;
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index ce2ddfc09f78..91745936e95a 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -309,10 +309,10 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
      move it as far as we can.  */
   do
     {
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  FOR_BB_INSNS_REVERSE (bb, dinsn)
-	    if (DEBUG_INSN_P (dinsn))
+	    if (DEBUG_BIND_INSN_P (dinsn))
 	      {
 		df_ref use;
 		FOR_EACH_INSN_USE (use, dinsn)
diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h
index 740cbf13cb2b..201bf190cefa 100644
--- a/gcc/ssa-iterators.h
+++ b/gcc/ssa-iterators.h
@@ -453,7 +453,7 @@ num_imm_uses (const_tree var)
   const ssa_use_operand_t *ptr;
   unsigned int num = 0;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     {
       for (ptr = start->next; ptr != start; ptr = ptr->next)
 	if (USE_STMT (ptr))
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 4d09b2cc99d7..00f86613137a 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -2072,7 +2072,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
 	      gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
 	    }
 	  /* Other user labels keep around in a form of a debug stmt.  */
-	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
+	  else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      gimple *dbg = gimple_build_debug_bind (label,
 						     integer_zero_node,
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index ca98e43327ec..e6e3f129d427 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -5930,7 +5930,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 					    &vars);
 		if (init)
 		  init_stmts.safe_push (init);
-		if (MAY_HAVE_DEBUG_STMTS && args_to_skip)
+		if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip)
 		  {
 		    if (parm_num == -1)
 		      {
@@ -6072,7 +6072,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
 	}
     }
 
-  if (debug_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+  if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree parm;
       vec<tree, va_gc> **debug_args = NULL;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 29825cc3f530..7439a1f370e8 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -826,7 +826,7 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
   /* Remove stmts not in the PARTITION bitmap.  */
   bbs = get_loop_body_in_dom_order (loop);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     for (i = 0; i < loop->num_nodes; i++)
       {
 	basic_block bb = bbs[i];
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 54f1c8d54d5b..daef8d72cd0e 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -2512,7 +2512,7 @@ analyze_access_subtree (struct access *root, struct access *parent,
 	  gcc_checking_assert (!root->grp_scalar_read
 			       && !root->grp_assignment_read);
 	  sth_created = true;
-	  if (MAY_HAVE_DEBUG_STMTS)
+	  if (MAY_HAVE_DEBUG_BIND_STMTS)
 	    {
 	      root->grp_to_be_debug_replaced = 1;
 	      root->replacement_decl = create_access_replacement (root);
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 8595decc7023..1e1307b2ff72 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1081,7 +1081,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
 
   /* If this is a store into a variable that is being optimized away,
      add a debug bind stmt if possible.  */
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && gimple_assign_single_p (stmt)
       && is_gimple_val (gimple_assign_rhs1 (stmt)))
     {
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index 65794b2b777e..350f94dfc33f 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -7154,7 +7154,7 @@ remove_unused_ivs (struct ivopts_data *data)
 
 	  tree def = info->iv->ssa_name;
 
-	  if (MAY_HAVE_DEBUG_STMTS && SSA_NAME_DEF_STMT (def))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def))
 	    {
 	      imm_use_iterator imm_iter;
 	      use_operand_p use_p;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 485d0a692ce8..b037dfbff8fb 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -232,7 +232,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
-  if (!MAY_HAVE_DEBUG_STMTS || gimple_code (stmt) == GIMPLE_PHI)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI)
     return gsi_remove (gsi, true);
 
   gimple_stmt_iterator prev = *gsi;
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index e90283b9cc8b..fc94f5d83d2c 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1781,7 +1781,7 @@ tail_merge_optimize (unsigned int todo)
 
   if (nr_bbs_removed_total > 0)
     {
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	{
 	  calculate_dominance_info (CDI_DOMINATORS);
 	  update_debug_stmts ();
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 536c4717b725..70675e4a3fcd 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -692,7 +692,7 @@ simplify_control_stmt_condition_1 (edge e,
 void
 propagate_threaded_block_debug_into (basic_block dest, basic_block src)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   if (!single_pred_p (dest))
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 8b6da9645ce0..151f544babad 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -220,7 +220,7 @@ flush_pending_stmts (edge e)
 void
 gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 {
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       tree lhs = gimple_get_lhs (stmt);
 
@@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs)
 tree
 target_for_debug_bind (tree var)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return NULL_TREE;
 
   if (TREE_CODE (var) == SSA_NAME)
@@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
   int usecount = 0;
   tree value = NULL;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   /* If this name has already been registered for replacement, do nothing
@@ -495,7 +495,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
   ssa_op_iter op_iter;
   def_operand_p def_p;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   stmt = gsi_stmt (*gsi);
@@ -521,7 +521,7 @@ reset_debug_uses (gimple *stmt)
   imm_use_iterator imm_iter;
   gimple *use_stmt;
 
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 6d344ad53096..d00d64852c2e 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -562,7 +562,7 @@ release_ssa_name_fn (struct function *fn, tree var)
       int saved_ssa_name_version = SSA_NAME_VERSION (var);
       use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
 
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
 	insert_debug_temp_for_var_def (NULL, var);
 
       if (flag_checking)
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index a0d9baf0ee52..d56fbfcbde5a 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -192,7 +192,7 @@ adjust_debug_stmts_now (adjust_info *ai)
 static void
 adjust_vec_debug_stmts (void)
 {
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_BIND_STMTS)
     return;
 
   gcc_assert (adjust_vec.exists ());
@@ -214,7 +214,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb)
 {
   adjust_info ai;
 
-  if (MAY_HAVE_DEBUG_STMTS
+  if (MAY_HAVE_DEBUG_BIND_STMTS
       && TREE_CODE (from) == SSA_NAME
       && ! SSA_NAME_IS_DEFAULT_DEF (from)
       && ! virtual_operand_p (from))
@@ -242,7 +242,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def)
 
   SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     adjust_debug_stmts (orig_def, PHI_RESULT (update_phi),
 			gimple_bb (update_phi));
 }
@@ -1685,7 +1685,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
   create_lcssa_for_virtual_phi (loop);
   update_ssa (TODO_update_ssa_only_virtuals);
 
-  if (MAY_HAVE_DEBUG_STMTS)
+  if (MAY_HAVE_DEBUG_BIND_STMTS)
     {
       gcc_assert (!adjust_vec.exists ());
       adjust_vec.create (32);
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index 1759655fd072..3e4703a36004 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -7381,7 +7381,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	  if (!stmt_info)
 	    continue;
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, phi);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
@@ -7444,7 +7444,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
 	      continue;
 	    }
 
-	  if (MAY_HAVE_DEBUG_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
+	  if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info))
 	    vect_loop_kill_debug_uses (loop, stmt);
 
 	  if (!STMT_VINFO_RELEVANT_P (stmt_info)
diff --git a/gcc/tree.h b/gcc/tree.h
index 306ff0904081..49cbb99d2db2 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1123,8 +1123,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define VL_EXP_OPERAND_LENGTH(NODE) \
   ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
 
+/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold.  */
+#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
+/* Nonzero if gimple_debug_bind_p() (and thus
+   gimple_debug_source_bind_p()) may possibly hold.  */
+#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
 /* Nonzero if is_gimple_debug() may possibly hold.  */
-#define MAY_HAVE_DEBUG_STMTS    (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_STMTS					\
+  (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS)
 
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
diff --git a/gcc/valtrack.c b/gcc/valtrack.c
index d4bab00c9534..610c2f6d6c43 100644
--- a/gcc/valtrack.c
+++ b/gcc/valtrack.c
@@ -214,7 +214,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 (DEBUG_BIND_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 16327bd43f33..33bcca7d6f52 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -1125,7 +1125,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
       if (tem == NULL_RTX)
 	tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
     finish_subreg:
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
 	  && GET_CODE (tem) == SUBREG
 	  && (GET_CODE (SUBREG_REG (tem)) == PLUS
 	      || GET_CODE (SUBREG_REG (tem)) == MINUS
@@ -1337,7 +1337,7 @@ dv_onepart_p (decl_or_value dv)
 {
   tree decl;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return NOT_ONEPART;
 
   if (dv_is_value_p (dv))
@@ -4861,7 +4861,7 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
   EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
     var_regno_delete (set, r);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       set->traversed_vars = set->vars;
       shared_hash_htab (set->vars)
@@ -5535,7 +5535,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
 		  variable names such as VALUEs (never happens) or
 		  DEBUG_EXPRs (only happens in the presence of debug
 		  insns).  */
-	       && (!MAY_HAVE_DEBUG_INSNS
+	       && (!MAY_HAVE_DEBUG_BIND_INSNS
 		   || !rtx_debug_expr_p (XEXP (loc, 0))))
 	return MO_USE;
       else
@@ -6700,7 +6700,7 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     local_get_addr_cache = new hash_map<rtx, rtx>;
 
   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
@@ -6982,7 +6982,7 @@ compute_bb_dataflow (basic_block bb)
 	}
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       delete local_get_addr_cache;
       local_get_addr_cache = NULL;
@@ -7069,7 +7069,7 @@ vt_find_locations (void)
 	      else
 		oldinsz = oldoutsz = 0;
 
-	      if (MAY_HAVE_DEBUG_INSNS)
+	      if (MAY_HAVE_DEBUG_BIND_INSNS)
 		{
 		  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
 		  bool first = true, adjust = false;
@@ -7130,7 +7130,7 @@ vt_find_locations (void)
 
 	      if (htabmax && htabsz > htabmax)
 		{
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    inform (DECL_SOURCE_LOCATION (cfun->decl),
 			    "variable tracking size limit exceeded with "
 			    "-fvar-tracking-assignments, retrying without");
@@ -7190,7 +7190,7 @@ vt_find_locations (void)
 	}
     }
 
-  if (success && MAY_HAVE_DEBUG_INSNS)
+  if (success && MAY_HAVE_DEBUG_BIND_INSNS)
     FOR_EACH_BB_FN (bb, cfun)
       gcc_assert (VTI (bb)->flooded);
 
@@ -8579,7 +8579,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars)
   struct expand_loc_callback_data data;
   rtx result;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return loc;
 
   INIT_ELCD (data, vars);
@@ -9014,7 +9014,7 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
   if (!changed_variables->elements ())
     return;
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     process_changed_values (htab);
 
   data.insn = insn;
@@ -9498,10 +9498,8 @@ vt_emit_notes (void)
      delete_variable_part).  */
   emit_notes = true;
 
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
-    }
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
+    dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
 
   dataflow_set_init (&cur);
 
@@ -9511,13 +9509,13 @@ vt_emit_notes (void)
 	 subsequent basic blocks.  */
       emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	local_get_addr_cache = new hash_map<rtx, rtx>;
 
       /* Emit the notes for the changes in the basic block itself.  */
       emit_notes_in_bb (bb, &cur);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	delete local_get_addr_cache;
       local_get_addr_cache = NULL;
 
@@ -9533,7 +9531,7 @@ vt_emit_notes (void)
 
   dataflow_set_destroy (&cur);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     delete dropped_values;
   dropped_values = NULL;
 
@@ -9893,7 +9891,7 @@ vt_init_cfa_base (void)
       cfa_base_rtx = NULL_RTX;
       return;
     }
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return;
 
   /* Tell alias analysis that cfa_base_rtx should share
@@ -9935,7 +9933,7 @@ vt_initialize (void)
       VTI (bb)->permp = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
@@ -9948,7 +9946,7 @@ vt_initialize (void)
       global_get_addr_cache = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       rtx reg, expr;
       int ofst;
@@ -10078,7 +10076,7 @@ vt_initialize (void)
       HOST_WIDE_INT pre, post = 0;
       basic_block first_bb, last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_record_sets_hook = add_with_sets;
 	  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10129,7 +10127,7 @@ vt_initialize (void)
 
 		  cselib_hook_called = false;
 		  adjust_insn (bb, insn);
-		  if (MAY_HAVE_DEBUG_INSNS)
+		  if (MAY_HAVE_DEBUG_BIND_INSNS)
 		    {
 		      if (CALL_P (insn))
 			prepare_call_arguments (bb, insn);
@@ -10164,7 +10162,7 @@ vt_initialize (void)
 		      vt_init_cfa_base ();
 		      hard_frame_pointer_adjustment = fp_cfa_offset;
 		      /* Disassociate sp from fp now.  */
-		      if (MAY_HAVE_DEBUG_INSNS)
+		      if (MAY_HAVE_DEBUG_BIND_INSNS)
 			{
 			  cselib_val *v;
 			  cselib_invalidate_rtx (stack_pointer_rtx);
@@ -10184,7 +10182,7 @@ vt_initialize (void)
 
       bb = last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
 	{
 	  cselib_preserve_only_values ();
 	  cselib_reset_table (cselib_get_next_uid ());
@@ -10283,7 +10281,7 @@ vt_finalize (void)
   location_chain_pool.release ();
   shared_hash_pool.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       if (global_get_addr_cache)
 	delete global_get_addr_cache;
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API
  2017-12-07 22:25                   ` Jeff Law
@ 2017-12-12  3:10                     ` Alexandre Oliva
  2017-12-14 11:55                       ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-12  3:10 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:

> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>> This patch removes unused RTL functions, introduces alternate ones for
>> use in a later SFN patch, and regroups other related functions so that
>> they appear in a more consistent order.
>> 
>> for  gcc/ChangeLog
>> 
>> * 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.
>> * rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
>> (prev_nonnote_nondebug_insn_bb): Declare.
>> (next_nonnote_nondebug_insn_bb): Declare.
>> * cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
>> * cfgrtl.c (get_last_bb_insn): Likewise.
>> * lra.c (push_insns): Likewise.
> OK.  Seems like this ought to go in immediately rather than waiting on
> the full kit to be ack'd.

Thanks, FTR, here it is, as installed:

From 18fc635703209d1a4ab2d9544c0f7b946e3c4c04 Mon Sep 17 00:00:00 2001
From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 12 Dec 2017 02:14:39 +0000
Subject: [PATCH 1/7] [SFN] adjust RTL insn-walking API

This patch removes unused RTL functions, introduces alternate ones for
use in a later SFN patch, and regroups other related functions so that
they appear in a more consistent order.

for  gcc/ChangeLog

	* 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.
	* rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
	(prev_nonnote_nondebug_insn_bb): Declare.
	(next_nonnote_nondebug_insn_bb): Declare.
	* cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
	* cfgrtl.c (get_last_bb_insn): Likewise.
	* lra.c (push_insns): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255564 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog  | 14 ++++++++++++
 gcc/cfgbuild.c |  2 +-
 gcc/cfgrtl.c   |  4 ++--
 gcc/emit-rtl.c | 69 ++++++++++++++++++++++++++++++++--------------------------
 gcc/lra.c      |  2 +-
 gcc/rtl.h      |  4 ++--
 6 files changed, 58 insertions(+), 37 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 54df8c0ee727..6d0a64e6adcc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2017-12-12  Alexandre Oliva <aoliva@redhat.com>
+
+	* 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.
+	* rtl.h	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove decls.
+	(prev_nonnote_nondebug_insn_bb): Declare.
+	(next_nonnote_nondebug_insn_bb): Declare.
+	* cfgbuild.c (find_bb_boundaries): Adjust to skip debug insns.
+	* cfgrtl.c (get_last_bb_insn): Likewise.
+	* lra.c (push_insns): Likewise.
+
 2017-12-11  David Malcolm  <dmalcolm@redhat.com>
 
 	PR c/82050
diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index a0926752143d..77a221de2119 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -511,7 +511,7 @@ 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))
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index a2ad075db85f..eb673a1e0799 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -2285,11 +2285,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;
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 428e4743454f..42de598067f4 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -3370,20 +3370,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;
@@ -3405,67 +3402,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;
     }
@@ -3473,17 +3473,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/lra.c b/gcc/lra.c
index 3fd15ee57943..f790904ec57f 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1806,7 +1806,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/rtl.h b/gcc/rtl.h
index 8de5a1cada5a..9cc982172f53 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3085,13 +3085,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 *);
-- 
2.13.6



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-12-12  2:42                     ` Alexandre Oliva
@ 2017-12-12  9:16                       ` Christophe Lyon
  2017-12-13  4:22                         ` Alexandre Oliva
  2018-01-07 17:48                       ` H.J. Lu
  1 sibling, 1 reply; 156+ messages in thread
From: Christophe Lyon @ 2017-12-12  9:16 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Richard Biener, Jason Merrill, GCC Patches

Hi,


On 12 December 2017 at 03:42, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:
>
>> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>>> Introduce a command line option to enable statement frontiers, enabled
>>> by default in optimized builds with DWARF2+ debug information.
>> OK once all prereqs are ack'd.
>
> Thanks, here's what's installed, FTR:
>
> From aa2fd8850c18861c8e3811b9174b0b1667111783 Mon Sep 17 00:00:00 2001
> From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
> Date: Tue, 12 Dec 2017 02:16:31 +0000
> Subject: [PATCH 6/7] [SFN] Introduce -gstatement-frontiers option, enable
>  debug markers
>
> Introduce a command line option to enable statement frontiers, enabled
> by default in optimized builds with DWARF2+ debug information.
>
> This patch depends on an earlier patch that completed the
> infrastructure for debug markers, and on another patch that turns -g
> into a negatable option prefix.
>
> for  gcc/ChangeLog
>
>         * common.opt (gstatement-frontiers): New, setting
>         debug_nonbind_markers_p.
>         * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
>         * toplev.c (process_options): Autodetect value for debug statement
>         frontiers option.
>         * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
>         * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
>
> git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255569 138bc75d-0d04-0410-961f-82ee72b054a4


Since this was checked in, I've noticed GCC/libatomic build failures
on ARM targets when configuring
--with-mode thumb (--with-mode arm is OK).

I'm seeing this:
/tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/obj-arm-none-linux-gnueabi/gcc3/./gcc/xgcc
-B/tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/obj-arm-none-
linux-gnueabi/gcc3/./gcc/
-B/tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/tools/arm-none-linux-gnueabi/bin/
-B/tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/tools/arm-non
e-linux-gnueabi/lib/ -isystem
/tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/tools/arm-none-linux-gnueabi/include
-isystem /tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/t
ools/arm-none-linux-gnueabi/sys-include -DHAVE_CONFIG_H
-I/tmp/923972_2.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libatomic/config/arm
-I/tmp/923972_2.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libato
mic/config/linux/arm
-I/tmp/923972_2.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libatomic/config/posix
-I/tmp/923972_2.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libatomic
-I. -Wall -Werror -pthread -g
 -O2 -MT gload.lo -MD -MP -MF .deps/gload.Tpo -c
/tmp/923972_2.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libatomic/gload.c
 -fPIC -DPIC -o .libs/gload.o
/tmp/923972_2.tmpdir/ccxBYdCX.s: Assembler messages:
/tmp/923972_2.tmpdir/ccxBYdCX.s: Error: unaligned opcodes detected in
executable segment
make[4]: *** [gload.lo] Error 1
make[4]: Leaving directory
`/tmp/923972_2.tmpdir/aci-gcc-fsf/builds/gcc-fsf-gccsrc-thumb/obj-arm-none-linux-gnueabi/gcc3/arm-none-linux-gnueabi/libatomic'

Christophe

> ---
>  gcc/ChangeLog       |  8 ++++++++
>  gcc/common.opt      |  4 ++++
>  gcc/doc/invoke.texi | 12 ++++++++++++
>  gcc/rtl.h           |  2 +-
>  gcc/toplev.c        |  4 ++++
>  gcc/tree.h          |  2 +-
>  6 files changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 01bd2b9f49ad..a53e7b8173f5 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,5 +1,13 @@
>  2017-12-12  Alexandre Oliva <aoliva@redhat.com>
>
> +       * common.opt (gstatement-frontiers): New, setting
> +       debug_nonbind_markers_p.
> +       * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
> +       * toplev.c (process_options): Autodetect value for debug statement
> +       frontiers option.
> +       * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
> +       * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
> +
>         * cfgexpand.c (expand_gimple_basic_block): Handle begin stmt
>         markers.  Integrate source bind into debug stmt expand loop.
>         (pass_expand::execute): Check debug marker limit.  Avoid deep
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 57b3cd7304ab..d80ae5b7f39b 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2936,6 +2936,10 @@ gstabs+
>  Common Driver JoinedOrMissing Negative(gvms)
>  Generate debug information in extended STABS format.
>
> +gstatement-frontiers
> +Common Driver Var(debug_nonbind_markers_p) Init(2)
> +Emit progressive recommended breakpoint locations.
> +
>  gstrict-dwarf
>  Common Driver Report Var(dwarf_strict) Init(0)
>  Don't emit DWARF additions beyond selected version.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 189b3e438fff..6402a5ae1734 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -346,6 +346,7 @@ 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
> +-gstatement-frontiers  -gno-statement-frontiers @gol
>  -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
>  -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
>  -fno-eliminate-unused-debug-types @gol
> @@ -7146,6 +7147,17 @@ Emit location column information into DWARF debugging information, rather
>  than just file and line.
>  This option is enabled 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 -gz@r{[}=@var{type}@r{]}
>  @opindex gz
>  Produce compressed debug sections in DWARF format, if that is supported.
> diff --git a/gcc/rtl.h b/gcc/rtl.h
> index 4de167d982cf..3ef687e5a371 100644
> --- a/gcc/rtl.h
> +++ b/gcc/rtl.h
> @@ -816,7 +816,7 @@ struct GTY(()) rtvec_def {
>  #define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
>
>  /* Nonzero if DEBUG_MARKER_INSN_P may possibly hold.  */
> -#define MAY_HAVE_DEBUG_MARKER_INSNS 0 /* debug_nonbind_markers_p */
> +#define MAY_HAVE_DEBUG_MARKER_INSNS debug_nonbind_markers_p
>  /* Nonzero if DEBUG_BIND_INSN_P may possibly hold.  */
>  #define MAY_HAVE_DEBUG_BIND_INSNS flag_var_tracking_assignments
>  /* Nonzero if DEBUG_INSN_P may possibly hold.  */
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index 2f154960a170..b6e038d2f89d 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -1536,6 +1536,10 @@ 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 (flag_tree_cselim == AUTODETECT_VALUE)
>      {
>        if (HAVE_conditional_move)
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 892a8ba7f707..83af3bcaf55f 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -1124,7 +1124,7 @@ 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 gimple_debug_nonbind_marker_p() may possibly hold.  */
> -#define MAY_HAVE_DEBUG_MARKER_STMTS 0 /* debug_nonbind_markers_p */
> +#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p
>  /* Nonzero if gimple_debug_bind_p() (and thus
>     gimple_debug_source_bind_p()) may possibly hold.  */
>  #define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments
> --
> 2.13.6
>
>
>
> --
> 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-12-12  9:16                       ` Christophe Lyon
@ 2017-12-13  4:22                         ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-13  4:22 UTC (permalink / raw)
  To: Christophe Lyon; +Cc: Jeff Law, Richard Biener, Jason Merrill, GCC Patches

On Dec 12, 2017, Christophe Lyon <christophe.lyon@linaro.org> wrote:

> Since this was checked in, I've noticed GCC/libatomic build failures
> on ARM targets when configuring
> --with-mode thumb (--with-mode arm is OK).

Could you possibly provide me with preprocessed source that exercises
the error, so that I could duplicate and debug it with a cross
compiler+assembler, without libc?  Thanks in advance,

(just in case, you might want to keep an eye on the patches in pr83396;
 patches there might already take care of this issue)

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API
  2017-12-12  3:10                     ` Alexandre Oliva
@ 2017-12-14 11:55                       ` Alexandre Oliva
  2017-12-14 12:07                         ` Jakub Jelinek
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-14 11:55 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, GCC Patches

On Dec 12, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:
>> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>>> (prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove.
> Thanks, FTR, here it is, as installed:

On Aug 31, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> 	(prev_nonnote_insn_bb, next_nonnote_insn_bb): Remove.

[SFN] next/prev_nonnote_insn_bb are no more, even for ports

The patch that added _nondebug to next_ and prev_nonnote_insn_bb
failed to find and adjust uses within config.  Fixed.

Sanity-checked by cross-building both *-elf targets (with binutils and
newlib) on x86_64-linux-gnu.  I'm going ahead and checking it in
shortly.

for  gcc/ChangeLog

	PR bootstrap/83396
	* config/arc/arc.c (hwloop_optimize): Skip debug insns.
	* config/sh/sh-protos.h (sh_find_set_of_reg): Adjust.
	* config/sh/sh.c: Skip debug insns besides notes.
	* config/sh/sh.md: Likewise.
	* config/sh/sh_treg_combine.cc: Likewise.
	* config/sh/sync.md: Likewise.
---
 gcc/config/arc/arc.c             |    2 +-
 gcc/config/sh/sh-protos.h        |    2 +-
 gcc/config/sh/sh.c               |   10 +++++-----
 gcc/config/sh/sh.md              |   18 +++++++++---------
 gcc/config/sh/sh_treg_combine.cc |    8 ++++----
 gcc/config/sh/sync.md            |    2 +-
 6 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index b8eec10086dd..9974a1f999b5 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -7499,7 +7499,7 @@ hwloop_optimize (hwloop_info loop)
                  && NOTE_KIND (entry_after) != NOTE_INSN_CALL_ARG_LOCATION))
         entry_after = NEXT_INSN (entry_after);
 #endif
-      entry_after = next_nonnote_insn_bb (entry_after);
+      entry_after = next_nonnote_nondebug_insn_bb (entry_after);
 
       gcc_assert (entry_after);
       emit_insn_before (seq, entry_after);
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index e98030d31bd7..0a83fbe17011 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -122,7 +122,7 @@ struct set_of_reg
 
 /* Given a reg rtx and a start insn, try to find the insn that sets the
    specified reg by using the specified insn stepping function, such as 
-   'prev_nonnote_insn_bb'.  When the insn is found, try to extract the rtx
+   'prev_nonnote_nondebug_insn_bb'.  When the insn is found, try to extract the rtx
    of the reg set.  */
 template <typename F> inline set_of_reg
 sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc,
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 0d7d7bc53ca2..3776415f1589 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -11897,7 +11897,7 @@ sh_is_logical_t_store_expr (rtx op, rtx_insn* insn)
       else
 	{
 	  set_of_reg op_set = sh_find_set_of_reg (ops[i], insn,
-						  prev_nonnote_insn_bb);
+						  prev_nonnote_nondebug_insn_bb);
 	  if (op_set.set_src == NULL_RTX)
 	    continue;
 
@@ -11929,7 +11929,7 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn)
   if (GET_MODE (extended_op) != SImode)
     return NULL_RTX;
 
-  set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_insn_bb);
+  set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_nondebug_insn_bb);
   if (s.set_src == NULL_RTX)
     return NULL_RTX;
 
@@ -11966,9 +11966,9 @@ sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[])
     return false;
 
   set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
-						 prev_nonnote_insn_bb);
+						 prev_nonnote_nondebug_insn_bb);
   set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
-						next_nonnote_insn_bb);
+						next_nonnote_nondebug_insn_bb);
 
   if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX
       && rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx)
@@ -12010,7 +12010,7 @@ sh_find_extending_set_of_reg (rtx reg, rtx_insn* curr_insn)
      cases, where a zero_extend is followed an (implicit) sign_extend, and it
      fails to see the sign_extend.  */
   sh_extending_set_of_reg result =
-	sh_find_set_of_reg (reg, curr_insn, prev_nonnote_insn_bb, true);
+	sh_find_set_of_reg (reg, curr_insn, prev_nonnote_nondebug_insn_bb, true);
 
   if (result.set_src != NULL)
     {
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 840fd922d41e..587af3b25581 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -848,7 +848,7 @@
   /* FIXME: Maybe also search the predecessor basic blocks to catch
      more cases.  */
   set_of_reg op = sh_find_set_of_reg (operands[0], curr_insn,
-				      prev_nonnote_insn_bb);
+				      prev_nonnote_nondebug_insn_bb);
 
   if (op.set_src != NULL && GET_CODE (op.set_src) == AND
       && !sh_insn_operands_modified_between_p (op.insn, op.insn, curr_insn))
@@ -939,7 +939,7 @@
   if (dump_file)
     fprintf (dump_file, "cmpgesi_t: trying to optimize for const_int 0\n");
 
-  rtx_insn* i = next_nonnote_insn_bb (curr_insn);
+  rtx_insn* i = next_nonnote_nondebug_insn_bb (curr_insn);
 
   if (dump_file)
     {
@@ -3094,7 +3094,7 @@
 	  && ! sh_dynamicalize_shift_p (shift_count))
 	{
 	  if (prev_set_t_insn == NULL)
-	    prev_set_t_insn = prev_nonnote_insn_bb (curr_insn);
+	    prev_set_t_insn = prev_nonnote_nondebug_insn_bb (curr_insn);
 
 	  /* Skip the nott insn, which was probably inserted by the splitter
 	     of *rotcr_neg_t.  Don't use one of the recog functions
@@ -3106,7 +3106,7 @@
 	      if (GET_CODE (pat) == SET
 		  && t_reg_operand (XEXP (pat, 0), SImode)
 		  && negt_reg_operand (XEXP (pat, 1), SImode))
-	      prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
+	      prev_set_t_insn = prev_nonnote_nondebug_insn_bb (prev_set_t_insn);
 	    }
 
 	  if (! (prev_set_t_insn != NULL_RTX
@@ -3194,7 +3194,7 @@
       if (sh_ashlsi_clobbers_t_reg_p (shift_count)
 	  && ! sh_dynamicalize_shift_p (shift_count))
 	{
-	  prev_set_t_insn = prev_nonnote_insn_bb (curr_insn);
+	  prev_set_t_insn = prev_nonnote_nondebug_insn_bb (curr_insn);
 
 	  /* Skip the nott insn, which was probably inserted by the splitter
 	     of *rotcl_neg_t.  Don't use one of the recog functions
@@ -3206,7 +3206,7 @@
 	      if (GET_CODE (pat) == SET
 		  && t_reg_operand (XEXP (pat, 0), SImode)
 		  && negt_reg_operand (XEXP (pat, 1), SImode))
-	      prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
+	      prev_set_t_insn = prev_nonnote_nondebug_insn_bb (prev_set_t_insn);
 	    }
 
 	  if (! (prev_set_t_insn != NULL_RTX
@@ -4423,7 +4423,7 @@
    When we're here, the not:SI pattern obviously has been matched already
    and we only have to see whether the following insn is the left shift.  */
 
-  rtx_insn *i = next_nonnote_insn_bb (curr_insn);
+  rtx_insn *i = next_nonnote_nondebug_insn_bb (curr_insn);
   if (i == NULL_RTX || !NONJUMP_INSN_P (i))
     FAIL;
 
@@ -10751,8 +10751,8 @@
 {
   rtx t_reg = get_t_reg_rtx ();
 
-  for (rtx_insn* i = prev_nonnote_insn_bb (curr_insn); i != NULL;
-       i = prev_nonnote_insn_bb (i))
+  for (rtx_insn* i = prev_nonnote_nondebug_insn_bb (curr_insn); i != NULL;
+       i = prev_nonnote_nondebug_insn_bb (i))
     {
       if (!INSN_P (i) || DEBUG_INSN_P (i))
 	continue;
diff --git a/gcc/config/sh/sh_treg_combine.cc b/gcc/config/sh/sh_treg_combine.cc
index cb3a7a85d173..0bbaf415db8f 100644
--- a/gcc/config/sh/sh_treg_combine.cc
+++ b/gcc/config/sh/sh_treg_combine.cc
@@ -291,7 +291,7 @@ find_set_of_reg_bb (rtx reg, rtx_insn *insn)
     return result;
 
   for (result.insn = insn; result.insn != NULL;
-       result.insn = prev_nonnote_insn_bb (result.insn))
+       result.insn = prev_nonnote_nondebug_insn_bb (result.insn))
     {
       if (BARRIER_P (result.insn))
 	return result;
@@ -750,7 +750,7 @@ sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn,
       log_msg ("tracing ccreg\n");
       new_entry.setcc =
 	  find_set_of_reg_bb (m_ccreg,
-			      prev_nonnote_insn_bb (new_entry.cstore.insn));
+			      prev_nonnote_nondebug_insn_bb (new_entry.cstore.insn));
 
       // If cstore was found but setcc was not found continue anyway, as
       // for some of the optimization types the setcc is irrelevant.
@@ -1353,7 +1353,7 @@ sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
   //   (set (reg ccreg) (eq (reg) (const_int 0)))
   // The testing insn could also be outside of the current basic block, but
   // for now we limit the search to the current basic block.
-  trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_insn_bb (insn));
+  trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_nondebug_insn_bb (insn));
 
   if (trace.setcc.set_src () == NULL_RTX)
     log_return_void ("could not find set of ccreg in current BB\n");
@@ -1413,7 +1413,7 @@ sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
   trace.bb_entries.push_front (bb_entry (trace.bb ()));
 
   record_return_t res =
-      record_set_of_reg (trace_reg, prev_nonnote_insn_bb (trace.setcc.insn),
+      record_set_of_reg (trace_reg, prev_nonnote_nondebug_insn_bb (trace.setcc.insn),
 			 trace.bb_entries.front ());
 
   if (res == other_set_found)
diff --git a/gcc/config/sh/sync.md b/gcc/config/sh/sync.md
index b46ac3131a8a..9f158bd93533 100644
--- a/gcc/config/sh/sync.md
+++ b/gcc/config/sh/sync.md
@@ -294,7 +294,7 @@
   /* FIXME: Sometimes the 'expected value' operand is not propagated as
      immediate value.  See PR 64974.  */
   set_of_reg op2 = sh_find_set_of_reg (operands[2], curr_insn,
-				       prev_nonnote_insn_bb);
+				       prev_nonnote_nondebug_insn_bb);
   if (op2.set_src != NULL && satisfies_constraint_I08 (op2.set_src))
     {
       rtx* r = &XVECEXP (XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1), 0, 1);

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API
  2017-12-14 11:55                       ` Alexandre Oliva
@ 2017-12-14 12:07                         ` Jakub Jelinek
  2017-12-14 18:25                           ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jakub Jelinek @ 2017-12-14 12:07 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Richard Biener, Jason Merrill, GCC Patches

On Thu, Dec 14, 2017 at 09:55:30AM -0200, Alexandre Oliva wrote:
> for  gcc/ChangeLog
> 
> 	PR bootstrap/83396
> 	* config/arc/arc.c (hwloop_optimize): Skip debug insns.
> 	* config/sh/sh-protos.h (sh_find_set_of_reg): Adjust.
> 	* config/sh/sh.c: Skip debug insns besides notes.
> 	* config/sh/sh.md: Likewise.
> 	* config/sh/sh_treg_combine.cc: Likewise.
> 	* config/sh/sync.md: Likewise.

Please fix up formatting.  Otherwise LGTM.

> --- a/gcc/config/sh/sh-protos.h
> +++ b/gcc/config/sh/sh-protos.h
> @@ -122,7 +122,7 @@ struct set_of_reg
>  
>  /* Given a reg rtx and a start insn, try to find the insn that sets the
>     specified reg by using the specified insn stepping function, such as 
> -   'prev_nonnote_insn_bb'.  When the insn is found, try to extract the rtx
> +   'prev_nonnote_nondebug_insn_bb'.  When the insn is found, try to extract the rtx

Too long line.

>     of the reg set.  */
>  template <typename F> inline set_of_reg
>  sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc,
> diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
> index 0d7d7bc53ca2..3776415f1589 100644
> --- a/gcc/config/sh/sh.c
> +++ b/gcc/config/sh/sh.c
> @@ -11897,7 +11897,7 @@ sh_is_logical_t_store_expr (rtx op, rtx_insn* insn)
>        else
>  	{
>  	  set_of_reg op_set = sh_find_set_of_reg (ops[i], insn,
> -						  prev_nonnote_insn_bb);
> +						  prev_nonnote_nondebug_insn_bb);

Likewise.  Just do:
-	  set_of_reg op_set = sh_find_set_of_reg (ops[i], insn,
-						  prev_nonnote_insn_bb);
+	  set_of_reg op_set
+	    = sh_find_set_of_reg (ops[i], insn, prev_nonnote_nondebug_insn_bb);

> @@ -11929,7 +11929,7 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn)
>    if (GET_MODE (extended_op) != SImode)
>      return NULL_RTX;
>  
> -  set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_insn_bb);
> +  set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_nondebug_insn_bb);

Likewise.

>    if (s.set_src == NULL_RTX)
>      return NULL_RTX;
>  
> @@ -11966,9 +11966,9 @@ sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[])
>      return false;
>  
>    set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
> -						 prev_nonnote_insn_bb);
> +						 prev_nonnote_nondebug_insn_bb);
>    set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
> -						next_nonnote_insn_bb);
> +						next_nonnote_nondebug_insn_bb);

2x further.
>  
>    if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX
>        && rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx)
> @@ -12010,7 +12010,7 @@ sh_find_extending_set_of_reg (rtx reg, rtx_insn* curr_insn)
>       cases, where a zero_extend is followed an (implicit) sign_extend, and it
>       fails to see the sign_extend.  */
>    sh_extending_set_of_reg result =
> -	sh_find_set_of_reg (reg, curr_insn, prev_nonnote_insn_bb, true);
> +	sh_find_set_of_reg (reg, curr_insn, prev_nonnote_nondebug_insn_bb, true);

Likewise.

> @@ -3106,7 +3106,7 @@
>  	      if (GET_CODE (pat) == SET
>  		  && t_reg_operand (XEXP (pat, 0), SImode)
>  		  && negt_reg_operand (XEXP (pat, 1), SImode))
> -	      prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
> +	      prev_set_t_insn = prev_nonnote_nondebug_insn_bb (prev_set_t_insn);

Likewise.

> @@ -3206,7 +3206,7 @@
>  	      if (GET_CODE (pat) == SET
>  		  && t_reg_operand (XEXP (pat, 0), SImode)
>  		  && negt_reg_operand (XEXP (pat, 1), SImode))
> -	      prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
> +	      prev_set_t_insn = prev_nonnote_nondebug_insn_bb (prev_set_t_insn);

Likewise.

> @@ -750,7 +750,7 @@ sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn,
>        log_msg ("tracing ccreg\n");
>        new_entry.setcc =
>  	  find_set_of_reg_bb (m_ccreg,
> -			      prev_nonnote_insn_bb (new_entry.cstore.insn));
> +			      prev_nonnote_nondebug_insn_bb (new_entry.cstore.insn));

Likewise.  + = shouldn't be at the end of line.  I'm afraid best will be to
use a temporary here.
>  
>        // If cstore was found but setcc was not found continue anyway, as
>        // for some of the optimization types the setcc is irrelevant.
> @@ -1353,7 +1353,7 @@ sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
>    //   (set (reg ccreg) (eq (reg) (const_int 0)))
>    // The testing insn could also be outside of the current basic block, but
>    // for now we limit the search to the current basic block.
> -  trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_insn_bb (insn));
> +  trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_nondebug_insn_bb (insn));

Likewise.
>  
>    if (trace.setcc.set_src () == NULL_RTX)
>      log_return_void ("could not find set of ccreg in current BB\n");
> @@ -1413,7 +1413,7 @@ sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
>    trace.bb_entries.push_front (bb_entry (trace.bb ()));
>  
>    record_return_t res =
> -      record_set_of_reg (trace_reg, prev_nonnote_insn_bb (trace.setcc.insn),
> +      record_set_of_reg (trace_reg, prev_nonnote_nondebug_insn_bb (trace.setcc.insn),

Likewise.  The indentation and = is wrong.


	Jakub

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API
  2017-12-14 12:07                         ` Jakub Jelinek
@ 2017-12-14 18:25                           ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-14 18:25 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jeff Law, Richard Biener, Jason Merrill, GCC Patches

On Dec 14, 2017, Jakub Jelinek <jakub@redhat.com> wrote:

> On Thu, Dec 14, 2017 at 09:55:30AM -0200, Alexandre Oliva wrote:
>> for  gcc/ChangeLog

> Please fix up formatting.  Otherwise LGTM.

Thanks, here's what I ended up installing (formatting fixes were
slightly different from what you suggested, but to the same effect)

[SFN] next/prev_nonnote_insn_bb are no more, even for ports

The patch that added _nondebug to next_ and prev_nonnote_insn_bb
failed to find and adjust uses within config.  Fixed.

for  gcc/ChangeLog

	PR bootstrap/83396
	* config/arc/arc.c (hwloop_optimize): Skip debug insns.
	* config/sh/sh-protos.h (sh_find_set_of_reg): Adjust.
	* config/sh/sh.c: Skip debug insns besides notes.
	* config/sh/sh.md: Likewise.
	* config/sh/sh_treg_combine.cc: Likewise.
	* config/sh/sync.md: Likewise.
---
 gcc/config/arc/arc.c             |    2 +-
 gcc/config/sh/sh-protos.h        |    8 ++++----
 gcc/config/sh/sh.c               |   19 ++++++++++---------
 gcc/config/sh/sh.md              |   20 +++++++++++---------
 gcc/config/sh/sh_treg_combine.cc |   16 ++++++++--------
 gcc/config/sh/sync.md            |    2 +-
 6 files changed, 35 insertions(+), 32 deletions(-)

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index b8eec10086dd..9974a1f999b5 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -7499,7 +7499,7 @@ hwloop_optimize (hwloop_info loop)
                  && NOTE_KIND (entry_after) != NOTE_INSN_CALL_ARG_LOCATION))
         entry_after = NEXT_INSN (entry_after);
 #endif
-      entry_after = next_nonnote_insn_bb (entry_after);
+      entry_after = next_nonnote_nondebug_insn_bb (entry_after);
 
       gcc_assert (entry_after);
       emit_insn_before (seq, entry_after);
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index e98030d31bd7..938487501f30 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -120,10 +120,10 @@ struct set_of_reg
   rtx set_src;
 };
 
-/* Given a reg rtx and a start insn, try to find the insn that sets the
-   specified reg by using the specified insn stepping function, such as 
-   'prev_nonnote_insn_bb'.  When the insn is found, try to extract the rtx
-   of the reg set.  */
+/* Given a reg rtx and a start insn, try to find the insn that sets
+   the specified reg by using the specified insn stepping function,
+   such as 'prev_nonnote_nondebug_insn_bb'.  When the insn is found,
+   try to extract the rtx of the reg set.  */
 template <typename F> inline set_of_reg
 sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc,
 		    bool ignore_reg_reg_copies = false)
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 0d7d7bc53ca2..85cc77b873a5 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -11896,8 +11896,8 @@ sh_is_logical_t_store_expr (rtx op, rtx_insn* insn)
 
       else
 	{
-	  set_of_reg op_set = sh_find_set_of_reg (ops[i], insn,
-						  prev_nonnote_insn_bb);
+	  set_of_reg op_set = sh_find_set_of_reg
+	    (ops[i], insn, prev_nonnote_nondebug_insn_bb);
 	  if (op_set.set_src == NULL_RTX)
 	    continue;
 
@@ -11929,7 +11929,8 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn)
   if (GET_MODE (extended_op) != SImode)
     return NULL_RTX;
 
-  set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_insn_bb);
+  set_of_reg s = sh_find_set_of_reg (extended_op, insn,
+				     prev_nonnote_nondebug_insn_bb);
   if (s.set_src == NULL_RTX)
     return NULL_RTX;
 
@@ -11965,10 +11966,10 @@ sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[])
   if (!can_create_pseudo_p ())
     return false;
 
-  set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
-						 prev_nonnote_insn_bb);
-  set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
-						next_nonnote_insn_bb);
+  set_of_reg t_before_negc = sh_find_set_of_reg
+    (get_t_reg_rtx (), curr_insn, prev_nonnote_nondebug_insn_bb);
+  set_of_reg t_after_negc = sh_find_set_of_reg
+    (get_t_reg_rtx (), curr_insn, next_nonnote_nondebug_insn_bb);
 
   if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX
       && rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx)
@@ -12009,8 +12010,8 @@ sh_find_extending_set_of_reg (rtx reg, rtx_insn* curr_insn)
      Also try to look through the first extension that we hit.  There are some
      cases, where a zero_extend is followed an (implicit) sign_extend, and it
      fails to see the sign_extend.  */
-  sh_extending_set_of_reg result =
-	sh_find_set_of_reg (reg, curr_insn, prev_nonnote_insn_bb, true);
+  sh_extending_set_of_reg result = sh_find_set_of_reg
+    (reg, curr_insn, prev_nonnote_nondebug_insn_bb, true);
 
   if (result.set_src != NULL)
     {
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 840fd922d41e..eb39b24e06da 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -848,7 +848,7 @@
   /* FIXME: Maybe also search the predecessor basic blocks to catch
      more cases.  */
   set_of_reg op = sh_find_set_of_reg (operands[0], curr_insn,
-				      prev_nonnote_insn_bb);
+				      prev_nonnote_nondebug_insn_bb);
 
   if (op.set_src != NULL && GET_CODE (op.set_src) == AND
       && !sh_insn_operands_modified_between_p (op.insn, op.insn, curr_insn))
@@ -939,7 +939,7 @@
   if (dump_file)
     fprintf (dump_file, "cmpgesi_t: trying to optimize for const_int 0\n");
 
-  rtx_insn* i = next_nonnote_insn_bb (curr_insn);
+  rtx_insn* i = next_nonnote_nondebug_insn_bb (curr_insn);
 
   if (dump_file)
     {
@@ -3094,7 +3094,7 @@
 	  && ! sh_dynamicalize_shift_p (shift_count))
 	{
 	  if (prev_set_t_insn == NULL)
-	    prev_set_t_insn = prev_nonnote_insn_bb (curr_insn);
+	    prev_set_t_insn = prev_nonnote_nondebug_insn_bb (curr_insn);
 
 	  /* Skip the nott insn, which was probably inserted by the splitter
 	     of *rotcr_neg_t.  Don't use one of the recog functions
@@ -3106,7 +3106,8 @@
 	      if (GET_CODE (pat) == SET
 		  && t_reg_operand (XEXP (pat, 0), SImode)
 		  && negt_reg_operand (XEXP (pat, 1), SImode))
-	      prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
+		prev_set_t_insn = prev_nonnote_nondebug_insn_bb
+		  (prev_set_t_insn);
 	    }
 
 	  if (! (prev_set_t_insn != NULL_RTX
@@ -3194,7 +3195,7 @@
       if (sh_ashlsi_clobbers_t_reg_p (shift_count)
 	  && ! sh_dynamicalize_shift_p (shift_count))
 	{
-	  prev_set_t_insn = prev_nonnote_insn_bb (curr_insn);
+	  prev_set_t_insn = prev_nonnote_nondebug_insn_bb (curr_insn);
 
 	  /* Skip the nott insn, which was probably inserted by the splitter
 	     of *rotcl_neg_t.  Don't use one of the recog functions
@@ -3206,7 +3207,8 @@
 	      if (GET_CODE (pat) == SET
 		  && t_reg_operand (XEXP (pat, 0), SImode)
 		  && negt_reg_operand (XEXP (pat, 1), SImode))
-	      prev_set_t_insn = prev_nonnote_insn_bb (prev_set_t_insn);
+		prev_set_t_insn = prev_nonnote_nondebug_insn_bb
+		  (prev_set_t_insn);
 	    }
 
 	  if (! (prev_set_t_insn != NULL_RTX
@@ -4423,7 +4425,7 @@
    When we're here, the not:SI pattern obviously has been matched already
    and we only have to see whether the following insn is the left shift.  */
 
-  rtx_insn *i = next_nonnote_insn_bb (curr_insn);
+  rtx_insn *i = next_nonnote_nondebug_insn_bb (curr_insn);
   if (i == NULL_RTX || !NONJUMP_INSN_P (i))
     FAIL;
 
@@ -10751,8 +10753,8 @@
 {
   rtx t_reg = get_t_reg_rtx ();
 
-  for (rtx_insn* i = prev_nonnote_insn_bb (curr_insn); i != NULL;
-       i = prev_nonnote_insn_bb (i))
+  for (rtx_insn* i = prev_nonnote_nondebug_insn_bb (curr_insn); i != NULL;
+       i = prev_nonnote_nondebug_insn_bb (i))
     {
       if (!INSN_P (i) || DEBUG_INSN_P (i))
 	continue;
diff --git a/gcc/config/sh/sh_treg_combine.cc b/gcc/config/sh/sh_treg_combine.cc
index cb3a7a85d173..bae81af3126e 100644
--- a/gcc/config/sh/sh_treg_combine.cc
+++ b/gcc/config/sh/sh_treg_combine.cc
@@ -291,7 +291,7 @@ find_set_of_reg_bb (rtx reg, rtx_insn *insn)
     return result;
 
   for (result.insn = insn; result.insn != NULL;
-       result.insn = prev_nonnote_insn_bb (result.insn))
+       result.insn = prev_nonnote_nondebug_insn_bb (result.insn))
     {
       if (BARRIER_P (result.insn))
 	return result;
@@ -748,9 +748,8 @@ sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn,
       // Now see how the ccreg was set.
       // For now it must be in the same BB.
       log_msg ("tracing ccreg\n");
-      new_entry.setcc =
-	  find_set_of_reg_bb (m_ccreg,
-			      prev_nonnote_insn_bb (new_entry.cstore.insn));
+      new_entry.setcc = find_set_of_reg_bb
+	(m_ccreg, prev_nonnote_nondebug_insn_bb (new_entry.cstore.insn));
 
       // If cstore was found but setcc was not found continue anyway, as
       // for some of the optimization types the setcc is irrelevant.
@@ -1353,7 +1352,8 @@ sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
   //   (set (reg ccreg) (eq (reg) (const_int 0)))
   // The testing insn could also be outside of the current basic block, but
   // for now we limit the search to the current basic block.
-  trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_insn_bb (insn));
+  trace.setcc = find_set_of_reg_bb
+    (m_ccreg, prev_nonnote_nondebug_insn_bb (insn));
 
   if (trace.setcc.set_src () == NULL_RTX)
     log_return_void ("could not find set of ccreg in current BB\n");
@@ -1412,9 +1412,9 @@ sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
   // If we find it here there's no point in checking other BBs.
   trace.bb_entries.push_front (bb_entry (trace.bb ()));
 
-  record_return_t res =
-      record_set_of_reg (trace_reg, prev_nonnote_insn_bb (trace.setcc.insn),
-			 trace.bb_entries.front ());
+  record_return_t res = record_set_of_reg
+    (trace_reg, prev_nonnote_nondebug_insn_bb (trace.setcc.insn),
+     trace.bb_entries.front ());
 
   if (res == other_set_found)
     log_return_void ("other set found - aborting trace\n");
diff --git a/gcc/config/sh/sync.md b/gcc/config/sh/sync.md
index b46ac3131a8a..9f158bd93533 100644
--- a/gcc/config/sh/sync.md
+++ b/gcc/config/sh/sync.md
@@ -294,7 +294,7 @@
   /* FIXME: Sometimes the 'expected value' operand is not propagated as
      immediate value.  See PR 64974.  */
   set_of_reg op2 = sh_find_set_of_reg (operands[2], curr_insn,
-				       prev_nonnote_insn_bb);
+				       prev_nonnote_nondebug_insn_bb);
   if (op2.set_src != NULL && satisfies_constraint_I08 (op2.set_src))
     {
       rtx* r = &XVECEXP (XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1), 0, 1);


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2017-12-12  2:54                   ` Alexandre Oliva
@ 2017-12-21  5:18                     ` Jeff Law
  2018-01-24  7:11                       ` Alexandre Oliva
  2018-01-24 17:40                     ` Jakub Jelinek
  1 sibling, 1 reply; 156+ messages in thread
From: Jeff Law @ 2017-12-21  5:18 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener; +Cc: Jason Merrill, Jakub Jelinek, GCC Patches

On 12/11/2017 07:54 PM, Alexandre Oliva wrote:
> On Nov 10, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:
> 
>> Output DW_AT_entry_pc based on markers.
> 
> Here's an updated version of the patch.
> 
> [IEPM] Introduce inline entry point markers
> 
> Output DW_AT_entry_pc based on markers.
> 
> Introduce DW_AT_GNU_entry_view as a DWARF extension.
> 
> If views are enabled are we're not in strict compliance mode, output
> DW_AT_GNU_entry_view if it might be nonzero.
> 
> This patch depends on SFN and LVU patchsets, and on the IEPM patch that
> introduces the inline_entry debug hook.
> 
> for  include/ChangeLog
> 
> 	* dwarf2.def (DW_AT_GNU_entry_view): New.
> 
> for  gcc/ChangeLog
> 
> 	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
> 	markers.
> 	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
> 	(BLOCK_INLINE_ENTRY_LABEL): New.
> 	(dwarf2out_var_location): Disregard inline entry markers.
> 	(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.
> 	(block_within_block_p, dwarf2out_inline_entry): New.
> 	(dwarf2out_finish): Check that no entries remained in
> 	inline_entry_data_table.
> 	* final.c (reemit_insn_block_notes): Handle inline entry notes.
> 	(final_scan_insn, notice_source_line): Likewise.
> 	(rest_of_clean_state): Skip inline entry markers.
> 	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
> 	markers.
> 	* gimple.c (gimple_build_debug_inline_entry): New.
> 	* gimple.h (enum gimple_debug_subcode): Add
> 	GIMPLE_DEBUG_INLINE_ENTRY.
> 	(gimple_build_debug_inline_entry): Declare.
> 	(gimple_debug_inline_entry_p): New.
> 	(gimple_debug_nonbind_marker_p): Adjust.
> 	* insn-notes.def (INLINE_ENTRY): New.
> 	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
> 	inline entry marker notes.
> 	(print_insn): Likewise.
> 	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
> 	(INSN_DEBUG_MARKER_KIND): Likewise.
> 	(GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT): New.
> 	* tree-inline.c	(expand_call_inline): Build and insert
> 	debug_inline_entry stmt.
> 	* 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.
> 	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
> 	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
> 	(gimple_build_debug_inline_entry): New.
> 	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
> 	Enable/disable inline entry points too.
> 	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
> 	(DEBUG_INSN): Describe inline entry markers.



> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index a88b4cdf6e25..df2f6d92c6fc 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -23533,6 +23579,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 (MAY_HAVE_DEBUG_MARKER_INSNS);
> +      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);
Do you have a sense of whether or not this really matters in practice?
how much bigger do we get due when we enable LVU?

In general I'm more concerned with getting the data we need into the
dwarf2 records than I am with optimizing its size.  I'm not saying we
should ignore the size, but



> +
> +/* 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)));
> +
> +  /* Sanity check the block tree.  This would catch a case in which
> +     BLOCK got removed from the tree reachable from the outermost
> +     lexical block, but got retained in markers.  It would still link
> +     back to its parents, but some ancestor would be missing a link
> +     down the path to the sub BLOCK.  If the block got removed, its
> +     BLOCK_NUMBER will not be a usable value.  */
> +  gcc_checking_assert (block_within_block_p (block,
> +					     DECL_INITIAL
> +					     (current_function_decl),
> +					     true));
> +
> +  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;
Consider moving this check earlier.  I don't think it's a hard
requirement, so if you put it after the asserts for a reason, then leave
it has is.


Generally I think this is fine (it's much simpler than the dwarf2 bits
of the LVU patch.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* [nvptx, committed] Disable -gstatement-frontiers for nvptx
  2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
  2017-12-07 22:49                   ` Jeff Law
@ 2017-12-27  8:00                   ` Tom de Vries
  2017-12-29  4:12                     ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Tom de Vries @ 2017-12-27  8:00 UTC (permalink / raw)
  To: Alexandre Oliva, Richard Biener, Jeff Law, Jason Merrill
  Cc: GCC Patches, Thomas Schwinge

[-- Attachment #1: Type: text/plain, Size: 905 bytes --]

[ was: Re: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers 
option, enable debug markers ]

On 11/10/2017 03:34 AM, Alexandre Oliva wrote:
> Introduce a command line option to enable statement frontiers, enabled
> by default in optimized builds with DWARF2+ debug information.
> 
> This patch depends on an earlier patch that completed the
> infrastructure for debug markers, and on another patch that turns -g
> into a negatable option prefix.
> 
> gcc/ChangeLog
> 
> 	* common.opt (gstatement-frontiers): New, setting
> 	debug_nonbind_markers_p.

Hi,

the ptx syntax for the .loc directive is limited to:
...
.loc file_index line_number column_position
...
so this causes ptxas errors when compiling something for nvptx with -g, 
which breaks the nvptx build.

This patch disables gstatement-frontiers for nvptx.

Tested libgomp for x86_64 with nvptx accelerator.

Committed.

Thanks,
- Tom

[-- Attachment #2: 0001-Disable-gstatement-frontiers-for-nvptx.patch --]
[-- Type: text/x-patch, Size: 730 bytes --]

Disable -gstatement-frontiers for nvptx

2017-12-27  Tom de Vries  <tom@codesourcery.com>

	* config/nvptx/nvptx.c (nvptx_option_override): Disable
	-gstatement-frontiers.

---
 gcc/config/nvptx/nvptx.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c
index cce0a55..e024570 100644
--- a/gcc/config/nvptx/nvptx.c
+++ b/gcc/config/nvptx/nvptx.c
@@ -177,6 +177,8 @@ nvptx_option_override (void)
   if (!global_options_set.x_flag_toplevel_reorder)
     flag_toplevel_reorder = 1;
 
+  debug_nonbind_markers_p = 0;
+
   /* Set flag_no_common, unless explicitly disabled.  We fake common
      using .weak, and that's not entirely accurate, so avoid it
      unless forced.  */

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [nvptx, committed] Disable -gstatement-frontiers for nvptx
  2017-12-27  8:00                   ` [nvptx, committed] Disable -gstatement-frontiers for nvptx Tom de Vries
@ 2017-12-29  4:12                     ` Alexandre Oliva
  2017-12-29 11:42                       ` Tom de Vries
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-29  4:12 UTC (permalink / raw)
  To: Tom de Vries
  Cc: Richard Biener, Jeff Law, Jason Merrill, GCC Patches, Thomas Schwinge

On Dec 27, 2017, Tom de Vries <Tom_deVries@mentor.com> wrote:

> .loc file_index line_number column_position

> so this causes ptxas errors when compiling something for nvptx with
> -g, which breaks the nvptx build.

What do the errors look like?

I ask because the patches that actually change the generated debug info,
adding view to .loc lines when the assembler supports them, are yet to
be installed, in the patches that introduces LVUs.  No significant
changes have been made to dwarf2out in the SFN patchset so far.

Furthermore, even with the LVU patch, .loc directives with view numbers
would only be used if the assembler is detected as supporting them at
compiler build time.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [nvptx, committed] Disable -gstatement-frontiers for nvptx
  2017-12-29  4:12                     ` Alexandre Oliva
@ 2017-12-29 11:42                       ` Tom de Vries
  2017-12-31 20:05                         ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Tom de Vries @ 2017-12-29 11:42 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Richard Biener, Jeff Law, Jason Merrill, GCC Patches, Thomas Schwinge

On 12/29/2017 05:12 AM, Alexandre Oliva wrote:
> On Dec 27, 2017, Tom de Vries <Tom_deVries@mentor.com> wrote:
> 
>> .loc file_index line_number column_position
> 
>> so this causes ptxas errors when compiling something for nvptx with
>> -g, which breaks the nvptx build.
> 
> What do the errors look like?
> 

The nvptx-none build breaks in libgcc:
...
configure:3706: error: in 
`/home/vries/nvptx/mainkernel-2/build-gcc/nvptx-none/libgcc':
configure:3709: error: cannot compute suffix of object files: cannot compile
...

For this conftest.c:
...
#define PACKAGE_NAME "GNU C Runtime Library"
#define PACKAGE_TARNAME "libgcc"
#define PACKAGE_VERSION "1.0"
#define PACKAGE_STRING "GNU C Runtime Library 1.0"
#define PACKAGE_BUGREPORT ""
#define PACKAGE_URL "http://www.gnu.org/software/libgcc/"
/* end confdefs.h.  */

int
main ()
{

   ;
   return 0;
}
...

We get this error:
...
$ build-gcc/gcc/xgcc -Bbuild-gcc/gcc -c -g -O2 conftest.c
ptxas conftest.o, line 17; fatal   : Parsing error near 'st': syntax error
ptxas fatal   : Ptx assembly aborted due to errors
nvptx-as: ptxas returned 255 exit status
...

By using -Wa,--no-verify, we can see the ptxas input:
...
$ cat -n conftest.o
     ...
     15  mov.u32 %value,0;
     16  .loc 1 15 1 is_stmt 0
     17  st.param.u32 [%value_out],%value;
     18  ret;
     19  }
...

With -gno-statement-frontiers, we have this instead:
...
     ...
     13  mov.u32 %value,0;
     14  .loc 1 15 1
     15  st.param.u32 [%value_out],%value;
     16  ret;
     17  }
...
and ptxas is able to parse the input.

> I ask because the patches that actually change the generated debug info,
> adding view to .loc lines when the assembler supports them, are yet to
> be installed, in the patches that introduces LVUs.  No significant
> changes have been made to dwarf2out in the SFN patchset so far.
>
> Furthermore, even with the LVU patch, .loc directives with view numbers
> would only be used if the assembler is detected as supporting them at
> compiler build time.
> 

If you point me to the location of a configure test that is supposed to 
file, I can try to find out why it passes.

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [nvptx, committed] Disable -gstatement-frontiers for nvptx
  2017-12-29 11:42                       ` Tom de Vries
@ 2017-12-31 20:05                         ` Alexandre Oliva
  2018-01-11 10:12                           ` Tom de Vries
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2017-12-31 20:05 UTC (permalink / raw)
  To: Tom de Vries
  Cc: Richard Biener, Jeff Law, Jason Merrill, GCC Patches, Thomas Schwinge

On Dec 29, 2017, Tom de Vries <Tom_deVries@mentor.com> wrote:

> On 12/29/2017 05:12 AM, Alexandre Oliva wrote:
>> On Dec 27, 2017, Tom de Vries <Tom_deVries@mentor.com> wrote:
>> 
>>> .loc file_index line_number column_position
>> 
>>> so this causes ptxas errors when compiling something for nvptx with
>>> -g, which breaks the nvptx build.
>> 
>> What do the errors look like?

>     16  .loc 1 15 1 is_stmt 0

Oh, is_stmt is not a new assembler feature, nor is it one that's
introduced by SFN, but SFN does indeed get GCC to exercise it in cases
it didn't before, and that completely escaped me when I was surprised by
your previous email.  Thanks for the data, it clears it all up for me.

> If you point me to the location of a configure test that is supposed
> to file, I can try to find out why it passes.

Thanks, even the configure test for '.loc ... view' support is in the
LVU patch yet to be reviewed and installed.

Now, perhaps it would be wise to introduce a test for is_stmt support in
.loc directives, now that we know there are assemblers that don't
support it.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers
  2017-12-12  2:42                     ` Alexandre Oliva
  2017-12-12  9:16                       ` Christophe Lyon
@ 2018-01-07 17:48                       ` H.J. Lu
  1 sibling, 0 replies; 156+ messages in thread
From: H.J. Lu @ 2018-01-07 17:48 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Richard Biener, Jason Merrill, GCC Patches

On Mon, Dec 11, 2017 at 6:42 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Dec  7, 2017, Jeff Law <law@redhat.com> wrote:
>
>> On 11/09/2017 07:34 PM, Alexandre Oliva wrote:
>>> Introduce a command line option to enable statement frontiers, enabled
>>> by default in optimized builds with DWARF2+ debug information.
>> OK once all prereqs are ack'd.
>
> Thanks, here's what's installed, FTR:
>
> From aa2fd8850c18861c8e3811b9174b0b1667111783 Mon Sep 17 00:00:00 2001
> From: aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
> Date: Tue, 12 Dec 2017 02:16:31 +0000
> Subject: [PATCH 6/7] [SFN] Introduce -gstatement-frontiers option, enable
>  debug markers
>
> Introduce a command line option to enable statement frontiers, enabled
> by default in optimized builds with DWARF2+ debug information.
>
> This patch depends on an earlier patch that completed the
> infrastructure for debug markers, and on another patch that turns -g
> into a negatable option prefix.
>
> for  gcc/ChangeLog
>
>         * common.opt (gstatement-frontiers): New, setting
>         debug_nonbind_markers_p.
>         * rtl.h (MAY_HAVE_DEBUG_MARKER_INSNS): Activate.
>         * toplev.c (process_options): Autodetect value for debug statement
>         frontiers option.
>         * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Activate.
>         * doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers): New.
>

This caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83728


H.J.

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [nvptx, committed] Disable -gstatement-frontiers for nvptx
  2017-12-31 20:05                         ` Alexandre Oliva
@ 2018-01-11 10:12                           ` Tom de Vries
  0 siblings, 0 replies; 156+ messages in thread
From: Tom de Vries @ 2018-01-11 10:12 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Richard Biener, Jeff Law, Jason Merrill, GCC Patches, Thomas Schwinge

On 12/31/2017 09:04 PM, Alexandre Oliva wrote:
> On Dec 29, 2017, Tom de Vries <Tom_deVries@mentor.com> wrote:
> 
>> On 12/29/2017 05:12 AM, Alexandre Oliva wrote:
>>> On Dec 27, 2017, Tom de Vries <Tom_deVries@mentor.com> wrote:
>>>
>>>> .loc file_index line_number column_position
>>>
>>>> so this causes ptxas errors when compiling something for nvptx with
>>>> -g, which breaks the nvptx build.
>>>
>>> What do the errors look like?
> 
>>      16  .loc 1 15 1 is_stmt 0
> 
> Oh, is_stmt is not a new assembler feature, nor is it one that's
> introduced by SFN, but SFN does indeed get GCC to exercise it in cases
> it didn't before, and that completely escaped me when I was surprised by
> your previous email.  Thanks for the data, it clears it all up for me.
> 
>> If you point me to the location of a configure test that is supposed
>> to file, I can try to find out why it passes.
> 
> Thanks, even the configure test for '.loc ... view' support is in the
> LVU patch yet to be reviewed and installed.
> 
> Now, perhaps it would be wise to introduce a test for is_stmt support in
> .loc directives, now that we know there are assemblers that don't
> support it.
> 

Filed: PR83788 - Add .loc is_stmt support test ( 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83788 ).

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2017-12-21  5:18                     ` Jeff Law
@ 2018-01-24  7:11                       ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-01-24  7:11 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Biener, Jason Merrill, Jakub Jelinek, GCC Patches

On Dec 21, 2017, Jeff Law <law@redhat.com> wrote:

> On 12/11/2017 07:54 PM, Alexandre Oliva wrote:
>> +	      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);

> Do you have a sense of whether or not this really matters in practice?
> how much bigger do we get due when we enable LVU?

It's more of a matter of general design principle.  DWARF strives to be
compact, and outputting a very-likely small constant with most bits
known to be zero is kind of against the rules.

LVU proper doesn't run into this because the location view numbers are
emitted as uleb128 constants in location list sections, never in the
main debug section.  How much it really grows depends on the
representation: DWARF>5 loclists only get additional entries when at
least one view number in a range pair is nonzero, and I have a sense
that most view numbers in loclists are zero; for DWARF[2,5], we emit
list of pairs corresponding to the ranges in each entry in the actual
loclist, so we spend at least two bytes for both views, plus the pointer
to the locviewlist in an additional attribute.  Considering each range
amounts to a pair of pointers plus at least two bytes for the location
expression, and that each range gets a corresponding pair of views, and
assuming all views will fit in a single uleb128 byte (128+ views at the
same PC are very unlikely), the loclist section would grow by at most
20% with 32-bit pointers, and about half that much with 64-bit pointers.
In reality, it ought to be a lot less than that, since location
expressions's taking up a single byte (plus another byte representing
the size) are common but hardly a majority of the cases.

>> +  /* Sanity check the block tree.  This would catch a case in which
>> +     BLOCK got removed from the tree reachable from the outermost
>> +     lexical block, but got retained in markers.  It would still link
>> +     back to its parents, but some ancestor would be missing a link
>> +     down the path to the sub BLOCK.  If the block got removed, its
>> +     BLOCK_NUMBER will not be a usable value.  */
>> +  gcc_checking_assert (block_within_block_p (block,
>> +					     DECL_INITIAL
>> +					     (current_function_decl),
>> +					     true));
>> +
>> +  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;
> Consider moving this check earlier.  I don't think it's a hard
> requirement, so if you put it after the asserts for a reason, then leave
> it has is.

The reason I put the check after the asserts was that I wanted to catch
messed up block trees even if we wouldn't emit the entry point after
all.  Now, considering the block tree messing up was figured out, I
guess moving the test earlier and saving the cycles if we're not
emitting the annotation makes sense.  Will do.

> Generally I think this is fine (it's much simpler than the dwarf2 bits
> of the LVU patch.

Yeah.  I wonder if there's anything I can do, now that I'm back from
vacations, to help get the LVU patch reviewed.  I suppose it might still
be eligible for GCC 8, considering it was posted even before stage3, let
alone stage4, and considering it only deals with debug info (mainly
location lists), but then...  unlike the SFN stuff, the additional
information it outputs will only make a difference once debug info
consumers learn to use it.  So maybe we could afford to leave it out, or
to bring it in but disabled.

Thoughts?  Does it make sense at this point for me to pester ^W entice
some review to have a look at it?

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-12-12  2:52                     ` Alexandre Oliva
@ 2018-01-24 17:36                       ` Jakub Jelinek
  2018-01-25 20:19                         ` Alexandre Oliva
  2018-02-06 21:13                       ` Jason Merrill
  1 sibling, 1 reply; 156+ messages in thread
From: Jakub Jelinek @ 2018-01-24 17:36 UTC (permalink / raw)
  To: Alexandre Oliva, Jason Merrill
  Cc: Jeff Law, Richard Biener, Jason Merrill, gcc-patches

On Tue, Dec 12, 2017 at 12:52:18AM -0200, Alexandre Oliva wrote:
> --- a/include/dwarf2.h
> +++ b/include/dwarf2.h
> @@ -298,6 +298,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
> +

This looks wrong.  The proposal has not been accepted yet, so you
really can't know if DW_LLE_view_pair will be like that or whether it
will have value of 9.  Unfortunately, the DWARF standard doesn't specify a
vendor range for DW_LLE_* values.  I'd use 0xf0 or so, and don't pretend
there is DW_LLE_view_pair at all, just use DW_LLE_GNU_view_pair everywhere.
Jason, what do you think?

> --- a/gcc/dwarf2asm.c
> +++ b/gcc/dwarf2asm.c
> @@ -767,6 +767,33 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
>    va_end (ap);
>  }
>  
> +/* output symbol LAB1 as an unsigned LEB128 quantity.  */

Capital O in Output please.

> +static inline bool
> +dwarf2out_locviews_in_attribute ()
> +{
> +  return debug_variable_location_views
> +    && dwarf_version <= 5;

Formatting, should be
  return debug_variable_location_views && dwarf_version <= 5;
or
  return (debug_variable_location_views
	  && dwarf_version <= 5);
if it wouldn't fit (but it does).

> +static inline bool
> +dwarf2out_locviews_in_loclist ()
> +{
> +#ifndef DW_LLE_view_pair
> +  return false;
> +#else
> +  return debug_variable_location_views
> +    && dwarf_version >= 6;

Likewise.

> +
> +static bool
> +output_asm_line_debug_info (void)
> +{
> +  return DWARF2_ASM_VIEW_DEBUG_INFO
> +    || (DWARF2_ASM_LINE_DEBUG_INFO && !debug_variable_location_views);

Likewise.

> +  dw2_asm_output_data (1, DW_LLE_view_pair,
> +		       "DW_LLE_view_pair");

This also fits on a single line.

> +/* 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");
> +    }

Do we really need to introduce -gdwarf-6 at this point?
-gdwarf-5 -gvariable-location-views should be sufficient, isn't it?
We don't know at all what will it look like in 3 or how many years.
My preference would be to keep all those dwarf_version == 6 related changes
out, including this output_dwarf_version function etc.

> +      const char *label = NOTE_DURING_CALL_P (loc_note)
> +	? last_postcall_label : last_label;

Again wrong formatting,
      const char *label
	= NOTE_DURING_CALL_P (loc_note) ? last_postcall_label : last_label;
is better.

> +  return !DECL_IGNORED_P (current_function_decl)
> +    && debug_variable_location_views
> +    && insn && GET_CODE (insn) == NOTE
> +    && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;

Formatting.

	Jakub

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2017-12-12  2:54                   ` Alexandre Oliva
  2017-12-21  5:18                     ` Jeff Law
@ 2018-01-24 17:40                     ` Jakub Jelinek
  2018-01-25 20:14                       ` Alexandre Oliva
  2018-02-21 10:33                       ` Alexandre Oliva
  1 sibling, 2 replies; 156+ messages in thread
From: Jakub Jelinek @ 2018-01-24 17:40 UTC (permalink / raw)
  To: Alexandre Oliva, Jason Merrill; +Cc: Richard Biener, Jeff Law, GCC Patches

On Tue, Dec 12, 2017 at 12:54:13AM -0200, Alexandre Oliva wrote:
> +/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
> +   OUTER itself.  If BOTHWAYS, check not only that BLOCK can reach
> +   OUTER through BLOCK_SUPERCONTEXT links, but also that there is a
> +   path from OUTER to BLOCK through BLOCK_SUBBLOCKs and
> +   BLOCK_FRAGMENT_ORIGIN links.  */
> +static bool
> +block_within_block_p (tree block, tree outer, bool bothways)
> +{
> +  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;
> +
> +  if (!bothways)
> +    return true;
> +
> +  /* 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)));
> +
> +  /* Sanity check the block tree.  This would catch a case in which
> +     BLOCK got removed from the tree reachable from the outermost
> +     lexical block, but got retained in markers.  It would still link
> +     back to its parents, but some ancestor would be missing a link
> +     down the path to the sub BLOCK.  If the block got removed, its
> +     BLOCK_NUMBER will not be a usable value.  */
> +  gcc_checking_assert (block_within_block_p (block,
> +					     DECL_INITIAL
> +					     (current_function_decl),
> +					     true));

I think this asks for
  if (flag_checking)
    gcc_assert (block_within_block_p (block,
				      DECL_INITIAL (current_function_decl),
				      true));

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

Wonder what the above hunks will do for LTO memory consumption.  We'll see.

Otherwise the patch looks reasonable to me, but I think it depends on the
7/9.

	Jakub

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-01-24 17:40                     ` Jakub Jelinek
@ 2018-01-25 20:14                       ` Alexandre Oliva
  2018-02-09  3:21                         ` Alexandre Oliva
  2018-02-21 10:33                       ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-01-25 20:14 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Richard Biener, Jeff Law, GCC Patches

On Jan 24, 2018, Jakub Jelinek <jakub@redhat.com> wrote:

> I think this asks for
>   if (flag_checking)
>     gcc_assert (block_within_block_p (block,
> 				      DECL_INITIAL (current_function_decl),
> 				      true));

'k, changed.

> Otherwise the patch looks reasonable to me, but I think it depends on the
> 7/9.

Thanks, yeah, it very much does.  It *might* be possible to split out
the dependency, but...  it would just take most of the LVU patch with it
;-)

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-01-24 17:36                       ` Jakub Jelinek
@ 2018-01-25 20:19                         ` Alexandre Oliva
  2018-01-26 14:58                           ` Jakub Jelinek
  2018-02-07  7:43                           ` Alexandre Oliva
  0 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-01-25 20:19 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jeff Law, Richard Biener, gcc-patches

On Jan 24, 2018, Jakub Jelinek <jakub@redhat.com> wrote:

> On Tue, Dec 12, 2017 at 12:52:18AM -0200, Alexandre Oliva wrote:
>> --- a/include/dwarf2.h
>> +++ b/include/dwarf2.h
>> @@ -298,6 +298,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
>> +

> This looks wrong.  The proposal has not been accepted yet, so you
> really can't know if DW_LLE_view_pair will be like that or whether it
> will have value of 9.  Unfortunately, the DWARF standard doesn't specify a
> vendor range for DW_LLE_* values.  I'd use 0xf0 or so, and don't pretend
> there is DW_LLE_view_pair at all, just use DW_LLE_GNU_view_pair everywhere.
> Jason, what do you think?

My reasoning was that, since we'd only emit this as an
explicitly-requested backward-incompatible extension to DWARF-5 (by
specifying -gdwarf-6 in this patch, but the option spelling could be
changed), any LLE number whatsoever would do.  The point of the #define
was to write the code in GCC so that, once DW_LLE_view_pair was
standardized (if it ever was), we'd just set up an enum for it and we'd
be done, but that would only happen at DWARF6+ anyway, so we'd be able
to tell, since we'd then have actual DWARF6, rather than DWARF5 with an
incompatible extensions (which is what we emit with the current
-gdwarf-6 option; see below).


>> --- a/gcc/dwarf2asm.c
>> +++ b/gcc/dwarf2asm.c
>> @@ -767,6 +767,33 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
>> va_end (ap);
>> }
>> 
>> +/* output symbol LAB1 as an unsigned LEB128 quantity.  */

> Capital O in Output please.

Thanks, fixed.

>> +static inline bool
>> +dwarf2out_locviews_in_attribute ()
>> +{
>> +  return debug_variable_location_views
>> +    && dwarf_version <= 5;

> Formatting, should be
>   return debug_variable_location_views && dwarf_version <= 5;
> or
>   return (debug_variable_location_views
> 	  && dwarf_version <= 5);
> if it wouldn't fit (but it does).

Hmm...  Where does that mandate come from?, if you don't mind my asking.
I have just revised both GNU Coding Standards, and GCC-specific
conventions, to make sure I hadn't missed a change or some long-ago
established convention, and I couldn't find anything that supports that
"should".

I don't mind adjusting code to match your preferences (if that's what it
is), especially in modules you maintain, but I'd like to make sure I
haven't missed some requirement in the coding standards.  Or maybe, if
it's more than a personal preference and rather a group preference, we
should add that at least to the GCC coding conventions, if most of us
agree with it.

Personally, I don't see that line breaks before operators are only
permitted when the operand that follows wouldn't fit; the standards are
more permissive than that.  And I don't see that the parentheses are
mandatory either; GNU recommends them so that one doesn't have to indent
the subsequent lines by hand (or risk automatically reintendation to
undo that manual work), but it doesn't seem to mandate the indentation
or the paretheses, and the indentation one gets in their absence is IIUC
permitted and occasionally even desirable.  Am I missing something?

Anyway, consider the requested changes done.

> Do we really need to introduce -gdwarf-6 at this point?
> -gdwarf-5 -gvariable-location-views should be sufficient, isn't it?

No, that means something else, namely emit location view lists in a
separate attribute, matching corresponding ranges.

Maybe we shouldn't even have an option to emit that at this point, or
make it a very different spelling.  But I'd argue there's no point in
discarding the code that implements the format that was proposed for
standardization; at the very least it serves as a reference.  That's
also an argument for retaining the ability to emit it somehow, even if
with an option that we document as to-be-dropped if/when there's a
standard representation.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-01-25 20:19                         ` Alexandre Oliva
@ 2018-01-26 14:58                           ` Jakub Jelinek
  2018-01-30 18:40                             ` Alexandre Oliva
  2018-02-07  7:43                           ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Jakub Jelinek @ 2018-01-26 14:58 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jason Merrill, Jeff Law, Richard Biener, gcc-patches

On Thu, Jan 25, 2018 at 05:58:37PM -0200, Alexandre Oliva wrote:
> > This looks wrong.  The proposal has not been accepted yet, so you
> > really can't know if DW_LLE_view_pair will be like that or whether it
> > will have value of 9.  Unfortunately, the DWARF standard doesn't specify a
> > vendor range for DW_LLE_* values.  I'd use 0xf0 or so, and don't pretend
> > there is DW_LLE_view_pair at all, just use DW_LLE_GNU_view_pair everywhere.
> > Jason, what do you think?
> 
> My reasoning was that, since we'd only emit this as an
> explicitly-requested backward-incompatible extension to DWARF-5 (by
> specifying -gdwarf-6 in this patch, but the option spelling could be
> changed), any LLE number whatsoever would do.  The point of the #define
> was to write the code in GCC so that, once DW_LLE_view_pair was
> standardized (if it ever was), we'd just set up an enum for it and we'd
> be done, but that would only happen at DWARF6+ anyway, so we'd be able
> to tell, since we'd then have actual DWARF6, rather than DWARF5 with an
> incompatible extensions (which is what we emit with the current
> -gdwarf-6 option; see below).

Having to tweak debug info consumers so that they treat DW_LLE_* of 9
one way for .debug_loclist of version 5 and another way for .debug_loclist
of version 6 isn't a good idea.
Why don't you emit the DW_LLE_GNU_view_pair stuff in .debug_loclists
already with -gdwarf-5, if needed paired without some TU attribute that says
that views are emitted?

> >> +static inline bool
> >> +dwarf2out_locviews_in_attribute ()
> >> +{
> >> +  return debug_variable_location_views
> >> +    && dwarf_version <= 5;
> 
> > Formatting, should be
> >   return debug_variable_location_views && dwarf_version <= 5;
> > or
> >   return (debug_variable_location_views
> > 	  && dwarf_version <= 5);
> > if it wouldn't fit (but it does).
> 
> Hmm...  Where does that mandate come from?, if you don't mind my asking.
> I have just revised both GNU Coding Standards, and GCC-specific
> conventions, to make sure I hadn't missed a change or some long-ago
> established convention, and I couldn't find anything that supports that
> "should".

Haven't looked for it it in the coding standards, but it is something
I've been asked to do in my code by various reviewers over the years and
what I've been asking others in my patch reviews from others too.

I'm personally not using emacs and so the extra ()s isn't something I'd
want myself, it is just something others asked for multiple times.
I feel strongly about indenting stuff right, which if it wouldn't fit would
be
  return verylongcondition____________________________________
	 && otherlongcondition__________________________________;
rather than
  return verylongcondition____________________________________
      && otherlongcondition__________________________________;
or similar, it would surprise me if it is not in the coding standard.

> Personally, I don't see that line breaks before operators are only
> permitted when the operand that follows wouldn't fit; the standards are

Yes, you can break it, but why, it doesn't make the code more readable,
but less in this case.

> No, that means something else, namely emit location view lists in a
> separate attribute, matching corresponding ranges.
> 
> Maybe we shouldn't even have an option to emit that at this point, or
> make it a very different spelling.  But I'd argue there's no point in
> discarding the code that implements the format that was proposed for
> standardization; at the very least it serves as a reference.  That's
> also an argument for retaining the ability to emit it somehow, even if
> with an option that we document as to-be-dropped if/when there's a
> standard representation.

So, what is the reason not to emit the format you are proposing already with
-gdwarf-5, perhaps with some extra attribute on the TU (of course not when
-gstrict-dwarf)?
Debuggers are still barely catching up with DWARF5, so even if they would be
upset by the DW_LLE_GNU_view_pair stuff, they can be still tweaked to ignore
those (skip over them) if they don't want to deal with the views.

	Jakub

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-01-26 14:58                           ` Jakub Jelinek
@ 2018-01-30 18:40                             ` Alexandre Oliva
  2018-01-30 22:11                               ` Richard Sandiford
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-01-30 18:40 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jeff Law, Richard Biener, gcc-patches

On Jan 26, 2018, Jakub Jelinek <jakub@redhat.com> wrote:

> Having to tweak debug info consumers so that they treat DW_LLE_* of 9
> one way for .debug_loclist of version 5 and another way for .debug_loclist
> of version 6 isn't a good idea.

Maybe we don't have to do that.  The reason I implemented the proposed
format was to have a reference implementation, but since it's an
extension to a non-extensible part of DWARF5, it's hard to justify
consumer implementations for that.

> Why don't you emit the DW_LLE_GNU_view_pair stuff in .debug_loclists
> already with -gdwarf-5, if needed paired without some TU attribute that says
> that views are emitted?

Because that would make the loclists unreadable for any DWARF5-compliant
consumer.


> Haven't looked for it it in the coding standards, but it is something
> I've been asked to do in my code by various reviewers over the years and
> what I've been asking others in my patch reviews from others too.

Thanks.  It was the first (well, second; you'd requested similar changes
another time before) I heard of that.  I'm still unconvinced the way I
used is not compliant, but I'll keep that in mind.  Hopefully I won't
run into someone who insists the other one (the one you reject) is the
only correct one ;-)

> I feel strongly about indenting stuff right,

I'm with you on that, we just have different ideas about what "right"
stands for ;-)

> which if it wouldn't fit would be
>   return verylongcondition____________________________________
> 	   && otherlongcondition__________________________________;
> rather than
>   return verylongcondition____________________________________
>       && otherlongcondition__________________________________;
> or similar, it would surprise me if it is not in the coding standard.

I agree neither of these two forms is correct.

But it is my understanding that both of the following are correct:

  return (verylongcondition____________________________________
          && otherlongcondition__________________________________);

  return verylongcondition____________________________________
    && otherlongcondition__________________________________;

The first, because the parenthesized expression is continued with
indentation to match the parenthesis, the second because the return
statement is continued with the correct indentation for the continuation
of a statement.

>> Personally, I don't see that line breaks before operators are only
>> permitted when the operand that follows wouldn't fit; the standards are

> Yes, you can break it, but why, it doesn't make the code more readable,
> but less in this case.

I thought it made it more readable, especially in the context of the
patch.  I guess this means we'll have to agree to disagree.

> So, what is the reason not to emit the format you are proposing already with
> -gdwarf-5, perhaps with some extra attribute on the TU (of course not when
> -gstrict-dwarf)?

See above.  We don't want to create unreadable loclists for
standard-compliant consumers, do we?

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-01-30 18:40                             ` Alexandre Oliva
@ 2018-01-30 22:11                               ` Richard Sandiford
  2018-02-07  4:14                                 ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Richard Sandiford @ 2018-01-30 22:11 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jakub Jelinek, Jason Merrill, Jeff Law, Richard Biener, gcc-patches

Alexandre Oliva <aoliva@redhat.com> writes:
> On Jan 26, 2018, Jakub Jelinek <jakub@redhat.com> wrote:
>
>> Having to tweak debug info consumers so that they treat DW_LLE_* of 9
>> one way for .debug_loclist of version 5 and another way for .debug_loclist
>> of version 6 isn't a good idea.
>
> Maybe we don't have to do that.  The reason I implemented the proposed
> format was to have a reference implementation, but since it's an
> extension to a non-extensible part of DWARF5, it's hard to justify
> consumer implementations for that.
>
>> Why don't you emit the DW_LLE_GNU_view_pair stuff in .debug_loclists
>> already with -gdwarf-5, if needed paired without some TU attribute that says
>> that views are emitted?
>
> Because that would make the loclists unreadable for any DWARF5-compliant
> consumer.
>
>
>> Haven't looked for it it in the coding standards, but it is something
>> I've been asked to do in my code by various reviewers over the years and
>> what I've been asking others in my patch reviews from others too.
>
> Thanks.  It was the first (well, second; you'd requested similar changes
> another time before) I heard of that.  I'm still unconvinced the way I
> used is not compliant, but I'll keep that in mind.  Hopefully I won't
> run into someone who insists the other one (the one you reject) is the
> only correct one ;-)
>
>> I feel strongly about indenting stuff right,
>
> I'm with you on that, we just have different ideas about what "right"
> stands for ;-)
>
>> which if it wouldn't fit would be
>>   return verylongcondition____________________________________
>> 	   && otherlongcondition__________________________________;
>> rather than
>>   return verylongcondition____________________________________
>>       && otherlongcondition__________________________________;
>> or similar, it would surprise me if it is not in the coding standard.
>
> I agree neither of these two forms is correct.
>
> But it is my understanding that both of the following are correct:
>
>   return (verylongcondition____________________________________
>           && otherlongcondition__________________________________);
>
>   return verylongcondition____________________________________
>     && otherlongcondition__________________________________;
>
> The first, because the parenthesized expression is continued with
> indentation to match the parenthesis, the second because the return
> statement is continued with the correct indentation for the continuation
> of a statement.

Thought it had to be the first.  When they talk about indenting leading
operators, the conventions say:

  Insert extra parentheses so that Emacs will indent the code properly.

which at least implies that not inserting parantheses and indenting by
two spaces isn't "properly".

And I think most GCC code does stick to that (i.e. use the bracketed form).

Thanks,
Richard

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2017-12-12  2:52                     ` Alexandre Oliva
  2018-01-24 17:36                       ` Jakub Jelinek
@ 2018-02-06 21:13                       ` Jason Merrill
  2018-02-07  4:02                         ` Alexandre Oliva
                                           ` (2 more replies)
  1 sibling, 3 replies; 156+ messages in thread
From: Jason Merrill @ 2018-02-06 21:13 UTC (permalink / raw)
  To: Alexandre Oliva, Jeff Law; +Cc: Richard Biener, Jakub Jelinek, gcc-patches

On 12/11/2017 09:52 PM, Alexandre Oliva wrote:
> +/* output symbol LAB1 as an unsigned LEB128 quantity.  */
> +
> +void
> +dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
> +				const char *comment, ...)

I'm having trouble understanding the use of symbols for views.  The 
configure test for gas support doesn't obviously define a symbol 
anywhere; is it implicitly defined by its use in the location directive? 
  This could use more documentation in dwarf2out.

> +   view computation, and it is refers to a view identifier for which

"it refers"

Why do we need to use a non-zero view identifier for a zero view?  Why 
can't we always use 0 instead of the bitmap?

>   Rationale: location lists can refer to address and view, not
>   op_index, so views are reset at address changes, not at op_index
>   changes.  Opcodes that advance op_index only will only reset the
>   view when they happen to advance the address, e.g. by exceeding
>   maximum_operations_per_instruction in op_index.
> 
>   DW_LNS_fixed_advance_pc is the only opcode that may change the
>   address without resetting the view.  It is available for compilers
>   to use when an address change is uncertain, e.g., when advancing
>   past opcodes that may expand to an empty sequence,
>   e.g. possibly-empty alignment sequences, optional no-operation
>   opcodes or the like.

> +      if (debug_variable_location_views && table->view)
> +	push_dw_line_info_entry (table, LI_adv_address, label_num);

It looks like you'll always use DW_LNS_fixed_advance_pc when we don't 
have .loc support.  Does that mean that the view never gets reset?

I'm uncomfortable with the special handling of this opcode; it isn't 
special in DWARF5 except as a fallback if more compact encodings aren't 
usable.  Currently GCC is even more conservative than this, and always 
use a relocation (DW_LNS_set_address); if we can use D_L_f_a_p instead, 
I would expect that to help with link times.  It seems wrong to use it 
only in the context of view support.

Would it make sense to say for *all* opcodes that the view is reset if 
and only if the address actually changes?

How are we coordinating the line number table and location list versions 
of the view counter?

Jason

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-06 21:13                       ` Jason Merrill
@ 2018-02-07  4:02                         ` Alexandre Oliva
  2018-02-07 19:23                           ` Jason Merrill
  2018-02-07  7:35                         ` Alexandre Oliva
  2018-02-07  7:36                         ` Alexandre Oliva
  2 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-07  4:02 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb  6, 2018, Jason Merrill <jason@redhat.com> wrote:

> On 12/11/2017 09:52 PM, Alexandre Oliva wrote:
>> +/* output symbol LAB1 as an unsigned LEB128 quantity.  */
>> +
>> +void
>> +dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
>> +				const char *comment, ...)

> I'm having trouble understanding the use of symbols for views.  The
> configure test for gas support doesn't obviously define a symbol
> anywhere; is it implicitly defined by its use in the location
> directive? This could use more documentation in dwarf2out.

Yeah.  It's the .loc statement that assigns a view number to the view
number symbol.  That's documented in the gas manual, but I guess it
won't hurt to add something to dwarf2out too.  Will do.

>> +   view computation, and it is refers to a view identifier for which

> "it refers"

Thanks

> Why do we need to use a non-zero view identifier for a zero view?  Why
> can't we always use 0 instead of the bitmap?

We assign view ids before we can determine whether the assigned view id
will be a zero view.  That's because we scan insns forward, and debug
binds take effect at the next .loc directive, which might be hundreds of
insns after the first reference (lots of intervening debug binds before
the insn that will take the next view), and insns that would cause the
.loc directive to be at a different address from that of the previous
.loc might be anywhere between those two loc-generating insns, before or
after the bind.  So, by the time we have to assign an id to the view, we
don't know whether we'll find an insn that sets RESETTING_VIEW_P before
we reach the loc-emitting insn that will take that view id.

It made more sense to me to assign the ids uniformly, and then mark
those that we find to be zero when we reach them, than to scan forward
(potentially O(n^2)) to tell in advance.  This also reduces differences
in view id tracking between gcc-internal and asm view assignment.


>> DW_LNS_fixed_advance_pc is the only opcode that may change the
>> address without resetting the view.  It is available for compilers
>> to use when an address change is uncertain, e.g., when advancing
>> past opcodes that may expand to an empty sequence,
>> e.g. possibly-empty alignment sequences, optional no-operation
>> opcodes or the like.

>> +      if (debug_variable_location_views && table->view)
>> +	push_dw_line_info_entry (table, LI_adv_address, label_num);

> It looks like you'll always use DW_LNS_fixed_advance_pc when we don't
> have .loc support.  Does that mean that the view never gets reset?

No, table->view will be zero if we have crossed an insn that
RESET_NEXT_VIEW, and then we'll use a LI_set_address.

> I'm uncomfortable with the special handling of this opcode; it isn't
> special in DWARF5 except as a fallback if more compact encodings
> aren't usable.  Currently GCC is even more conservative than this, and
> always use a relocation (DW_LNS_set_address); if we can use D_L_f_a_p
> instead, I would expect that to help with link times.  It seems wrong
> to use it only in the context of view support.

We didn't use it before, but if we use, that's ok.  We don't *have* to
reset the view number to zero at a PC change.  It would be all right to
never reset it, as long as the compiler and the debug info consumer
agrees about it.  Since in some cases the compiler has to assign views
itself (when the assembler doesn't support views), but it can't tell
whether there will be a PC change (e.g. at an align), we need some
mechanism that predictably refrains from resetting the view number,
otherwise the compiler might pick a view number based on a possibly
incorrect assumption about whether the align changes PC or not, and then
it might not match what the consumer, that knows whether the PC
advanced, would compute.  To make it concrete:

# ...
.L352:
# .loc 1 533 view 3 (internal compiler tracking, no assembler support)
mov r12 <- whatever
# DEBUG x => r12
.balign 32
.L353:
# .loc 1 480 view <?>

Consider you're the compiler and you're generating a view-augmented
loclist for variable x.  You have to indicate the view number at .L353
for the range that starts there, and possibly for the range that ends
there.

But is the view number 4 or 0?  Namely, does .balign advance PC or not?
The compiler can't possibly know.  So if it guesses .balign does advance
PC and assign a view number zero at .L353, but it guesses wrong, that
will be indistinguishable from view number zero at say .L350, because
the PC is the same.  The debug info consumer will see no PC change and
assign view number 4 to the line number table entry correspoding to the
.loc directive with view <?>, but it won't find any loclist referencing
that view number.  Conversely, if the compiler guessed .balign did not
advance PC, it would assign view number 4 to .L353, but then, with your
suggestion, the debug info consumer would instead assign it view number
zero, and we'd be out of sync.

That's why we need an opcode that enables the compiler and the debug
info consumer to remain in sync, disregarding a potential PC change that
would cause a view reset, because the compiler can't predict whether or
not there will be an actual PC change.

> Would it make sense to say for *all* opcodes that the view is reset if
> and only if the address actually changes?

I don't see how to keep compiler and consumer in sync with this
arrangement.  That's why I introduced the one exceptional opcode.

> How are we coordinating the line number table and location list
> versions of the view counter?

When the compiler is emitting the line number programs and computing
view numbers itself, it resets view numbers at known PC changes and
counts from that, and then it emits view numbers as literal constants in
locviewlists.

When the compiler defers view computation to the assembler, it emits
symbolic view numbers in locviewlists, with the exception of views known
to be zero (forced resets, or reset after compiler-visible PC changes):
instead of emitting symbols for these, we emit literal zero and assert
the assembler agrees with the compiler's assessment.  We could use
symbolic views everywhere, instead of special-casing zero views, but
then we'd be unable to optimize out locviewlists that contain only
zeros.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-01-30 22:11                               ` Richard Sandiford
@ 2018-02-07  4:14                                 ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-07  4:14 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jason Merrill, Jeff Law, Richard Biener, gcc-patches, richard.sandiford

On Jan 30, 2018, Richard Sandiford <richard.sandiford@linaro.org> wrote:

>> But it is my understanding that both of the following are correct:
>> 
>> return (verylongcondition____________________________________
>>         && otherlongcondition__________________________________);
>> 
>> return verylongcondition____________________________________
>>   && otherlongcondition__________________________________;
>> 
>> The first, because the parenthesized expression is continued with
>> indentation to match the parenthesis, the second because the return
>> statement is continued with the correct indentation for the continuation
>> of a statement.

> Thought it had to be the first.  When they talk about indenting leading
> operators, the conventions say:

>   Insert extra parentheses so that Emacs will indent the code properly.

> which at least implies that not inserting parantheses and indenting by
> two spaces isn't "properly".

Hmm, in my reading, the "properly" there was to contrast with the IMHO
improper, excessive manual indentation in the example that follows it:

  v = rup->ru_utime.tv_sec*1000 + rup->ru_utime.tv_usec/1000
      + rup->ru_stime.tv_sec*1000 + rup->ru_stime.tv_usec/1000;

but I think it's just as legitimate to instead understand that the above
indentation is proper, and that the only problem with it is that
mechanical reindent would turn it into

  v = rup->ru_utime.tv_sec*1000 + rup->ru_utime.tv_usec/1000
    + rup->ru_stime.tv_sec*1000 + rup->ru_stime.tv_usec/1000;

which, in *this* case, would be wrong, because you'd have '=' and '+'
operators, of different precedence, at the same level of indentation.

But in the case of return, there's no such issue with operator
precedence.

I'll raise this issue at bug-standards@gnu.org and request
clarification.

> And I think most GCC code does stick to that (i.e. use the bracketed form).

Let's see what GNU decides, then we can decide whether to add a
GCC-specific constraint, if GNU doesn't impose it already.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-06 21:13                       ` Jason Merrill
  2018-02-07  4:02                         ` Alexandre Oliva
@ 2018-02-07  7:35                         ` Alexandre Oliva
  2018-02-07  7:36                         ` Alexandre Oliva
  2 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-07  7:35 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

Here's an incremental patch with the changes I made in response to your
requests.  I'll post the complete updated patch momentarily.

diff --git a/gcc/common.opt b/gcc/common.opt
index 55d9cdd714ff..7e024fdab124 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2957,9 +2957,12 @@ Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
 gvariable-location-views
-Common Driver Var(debug_variable_location_views) Init(2)
+Common Driver Var(debug_variable_location_views, 1) Init(2)
 Augment variable location lists with progressive views.
 
+gvariable-location-views=incompat5
+Common Driver RejectNegative Var(debug_variable_location_views, -1) Init(2)
+
 gvms
 Common Driver JoinedOrMissing Negative(gxcoff)
 Generate debug information in VMS format.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7f09fcb64968..045aab78ce51 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7220,8 +7220,10 @@ 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 -gvariable-location-views=incompat5
 @item -gno-variable-location-views
 @opindex gvariable-location-views
+@opindex gvariable-location-views=incompat5
 @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
@@ -7234,8 +7236,16 @@ 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.
+the normal level, as long as @option{-fvar-tracking-assignments} is
+enabled and @option{-gstrict-dwarf} is not.
+
+There is a proposed representation for view numbers that is not backward
+compatible with the location list format introduced in DWARF 5, that can
+be enabled with @option{-gvariable-location-views=incompat5}.  This
+option may be removed in the future, is only provided as a reference
+implementation of the proposed representation.  Debug information
+consumers are not expected to support this extended format, and they
+would be rendered unable to decode location lists using it.
 
 @item -gz@r{[}=@var{type}@r{]}
 @opindex gz
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 9ef7fa3516d4..3cf79270b72c 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1350,7 +1350,7 @@ dwarf_stack_op_name (unsigned int op)
 static inline bool
 dwarf2out_locviews_in_attribute ()
 {
-  return debug_variable_location_views && dwarf_version <= 5;
+  return debug_variable_location_views == 1;
 }
 
 /* Return TRUE iff we're to output location view lists as part of the
@@ -1362,7 +1362,7 @@ dwarf2out_locviews_in_loclist ()
 #ifndef DW_LLE_view_pair
   return false;
 #else
-  return debug_variable_location_views && dwarf_version >= 6;
+  return debug_variable_location_views == -1;
 #endif
 }
 
@@ -3164,7 +3164,7 @@ skeleton_chain_node;
 #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
+   view computation, and it refers to a view identifier for which we
    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
@@ -27344,23 +27344,40 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
 	      zero_view_p = BITMAP_GGC_ALLOC ();
 	      bitmap_set_bit (zero_view_p, 0);
 	    }
-	  if (RESETTING_VIEW_P (table->view))
+	  if (!RESETTING_VIEW_P (table->view))
+	    {
+	      /* When we're using the assembler to compute view
+		 numbers, we output symbolic labels after "view" in
+		 .loc directives, and the assembler will set them for
+		 us, so that we can refer to the view numbers in
+		 location lists.  The only exceptions are when we know
+		 a view will be zero: "-0" is a forced reset, used
+		 e.g. in the beginning of functions, whereas "0" tells
+		 the assembler to check that there was a PC change
+		 since the previous view, in a way that implicitly
+		 resets the next view.  */
+	      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;
+	    }
+	  else
 	    {
 	      if (!table->in_use)
 		fputs (" view -0", asm_out_file);
 	      else
 		fputs (" view 0", asm_out_file);
+	      /* Mark the present view as a zero view.  Earlier debug
+		 binds may have already added its id to loclists to be
+		 emitted later, so we can't reuse the id for something
+		 else.  However, it's good to know whether a view is
+		 known to be zero, because then we may be able to
+		 optimize out locviews that are all zeros, so take
+		 note of it in zero_view_p.  */
 	      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);
     }
diff --git a/gcc/final.c b/gcc/final.c
index 642b757a9a97..68397b3ded36 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1750,7 +1750,8 @@ in_initial_view_p (rtx_insn *insn)
   return (!DECL_IGNORED_P (current_function_decl)
 	  && debug_variable_location_views
 	  && insn && GET_CODE (insn) == NOTE
-	  && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION);
+	  && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+	      || NOTE_KIND (insn) == NOTE_INSN_DELETED));
 }
 
 /* Output assembler code for the start of a function,
diff --git a/gcc/opts.c b/gcc/opts.c
index 50a240afbff4..f2795f98bf44 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2393,7 +2393,7 @@ common_handle_option (struct gcc_options *opts,
       
       /* FALLTHRU */
     case OPT_gdwarf_:
-      if (value < 2 || value > 6)
+      if (value < 2 || value > 5)
 	error_at (loc, "dwarf version %d is not supported", value);
       else
 	opts->x_dwarf_version = value;
diff --git a/gcc/toplev.c b/gcc/toplev.c
index bdb7509c9e69..23db0636fc79 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1562,9 +1562,17 @@ process_options (void)
     {
       debug_variable_location_views = flag_var_tracking
 	&& debug_info_level >= DINFO_LEVEL_NORMAL
-	&& (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+	&& (write_symbols == DWARF2_DEBUG
+	    || write_symbols == VMS_AND_DWARF2_DEBUG)
 	&& !dwarf_strict;
     }
+  else if (debug_variable_location_views == -1 && dwarf_version != 5)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "without -gdwarf-5, -gvariable-location-views=incompat5 "
+		  "is equivalent to -gvariable-location-views");
+      debug_variable_location_views = 1;
+    }
 
   if (flag_tree_cselim == AUTODETECT_VALUE)
     {


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-06 21:13                       ` Jason Merrill
  2018-02-07  4:02                         ` Alexandre Oliva
  2018-02-07  7:35                         ` Alexandre Oliva
@ 2018-02-07  7:36                         ` Alexandre Oliva
  2018-02-08 19:58                           ` Jason Merrill
  2 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-07  7:36 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

Here's the updated version of the LVU patch, integrating changes
requested or proposed by yourself and by Jakub.


for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_locviews): New.
	* dwarf2.h (enum dwarf_location_list_entry_type): Add
	DW_LLE_GNU_view_pair.
	(DW_LLE_view_pair): Define.

for  gcc/ChangeLog

	* common.opt (gvariable-location-views): New.
	(gvariable-location-views=incompat5): New.
	* config.in: Rebuilt.
	* configure: Rebuilt.
	* configure.ac: Test assembler for view support.
	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
	* dwarf2out.c (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.
	(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.
	(maybe_emit_file): Call output_asm_line_debug_info for test.
	(dwarf2out_var_location): Reset views as needed.  Precompute
	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
	attribute.  Set view.
	(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.
	Use output_dwarf_version.
	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
	(struct dw_val_node): Add val_view_list.
	* final.c (SEEN_NEXT_VIEW): New.
	(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.  Notify debug backend of section
	changes, and of location view changes.
	(rest_of_handle_final): Adjust.
	* toplev.c (process_options): Autodetect value for debug variable
	location views option.  Warn on incompat5 without -gdwarf-5.
	* doc/invoke.texi (gvariable-location-views): New.
	(gvariable-location-views=incompat5): New.
	(gno-variable-location-views): New.
---
 gcc/common.opt      |    7 +
 gcc/config.in       |    6 
 gcc/configure       |   46 +++
 gcc/configure.ac    |   18 +
 gcc/doc/invoke.texi |   29 ++
 gcc/dwarf2asm.c     |   27 ++
 gcc/dwarf2asm.h     |    4 
 gcc/dwarf2out.c     |  674 ++++++++++++++++++++++++++++++++++++++++++++++-----
 gcc/dwarf2out.h     |    4 
 gcc/final.c         |  149 ++++++++++-
 gcc/toplev.c        |   16 +
 include/dwarf2.def  |    1 
 include/dwarf2.h    |    8 +
 13 files changed, 908 insertions(+), 81 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 874d0c2e72b5..7e024fdab124 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2956,6 +2956,13 @@ gtoggle
 Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
+gvariable-location-views
+Common Driver Var(debug_variable_location_views, 1) Init(2)
+Augment variable location lists with progressive views.
+
+gvariable-location-views=incompat5
+Common Driver RejectNegative Var(debug_variable_location_views, -1) Init(2)
+
 gvms
 Common Driver JoinedOrMissing Negative(gxcoff)
 Generate debug information in VMS format.
diff --git a/gcc/config.in b/gcc/config.in
index 8dc453104c13..5bccb408016b 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/configure b/gcc/configure
index 6db8c805f81e..0f6384141eda 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27818,6 +27818,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 f8b0e5a66066..0e683b823d53 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4895,9 +4895,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/doc/invoke.texi b/gcc/doc/invoke.texi
index dbc5c47b0313..045aab78ce51 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -348,6 +348,7 @@ Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gcolumn-info  -gno-column-info @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
 -fno-eliminate-unused-debug-types @gol
@@ -7218,6 +7219,34 @@ 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 -gvariable-location-views=incompat5
+@item -gno-variable-location-views
+@opindex gvariable-location-views
+@opindex gvariable-location-views=incompat5
+@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 @option{-fvar-tracking-assignments} is
+enabled and @option{-gstrict-dwarf} is not.
+
+There is a proposed representation for view numbers that is not backward
+compatible with the location list format introduced in DWARF 5, that can
+be enabled with @option{-gvariable-location-views=incompat5}.  This
+option may be removed in the future, is only provided as a reference
+implementation of the proposed representation.  Debug information
+consumers are not expected to support this extended format, and they
+would be rendered unable to decode location lists using it.
+
 @item -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index 9952e0a98506..06ce8a814393 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -767,6 +767,33 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
   va_end (ap);
 }
 
+/* Output symbol LAB1 as an unsigned LEB128 quantity.  */
+
+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,
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index b5ed449205ef..1b76909a1c91 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 948b3cbe5918..3cf79270b72c 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1291,6 +1291,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.  */
@@ -1300,9 +1302,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.  */
@@ -1339,6 +1343,29 @@ 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 == 1;
+}
+
+/* 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 == -1;
+#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.  */
@@ -1401,6 +1428,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:
@@ -2875,7 +2904,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 {
@@ -2897,6 +2934,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;
 };
 
@@ -3098,6 +3154,45 @@ 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 refers to a view identifier for which we
+   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)
+
+/* Return true iff we're to emit .loc directives for the assembler to
+   generate line number sections.  */
+
+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
@@ -3207,6 +3302,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.  */
@@ -3415,6 +3511,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);
@@ -3451,7 +3549,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 void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -3651,8 +3749,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);
@@ -4648,11 +4746,65 @@ AT_loc_list (dw_attr_node *a)
   return a->dw_attr_val.v.val_loc_list;
 }
 
+/* Add a view list attribute to DIE.  It must have a DW_AT_location
+   attribute, because the view list complements the location 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);
+}
+
+/* Return a pointer to the location list referenced by the attribute.
+   If the named attribute is a view list, look up the corresponding
+   DW_AT_location attribute and return its location list.  */
+
 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 ();
+    }
+}
+
+/* Return the location attribute value associated with a view list
+   attribute value.  */
+
+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>
@@ -5907,7 +6059,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;
@@ -5996,7 +6148,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.  */
@@ -6012,7 +6164,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
 	    {
@@ -6147,6 +6299,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;
@@ -9007,6 +9165,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);
@@ -9378,6 +9537,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)
@@ -9652,7 +9812,8 @@ output_abbrev_section (void)
    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> ();
@@ -9662,10 +9823,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.  */
 
@@ -9674,6 +9853,98 @@ 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.  */
@@ -9681,34 +9952,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,
@@ -9726,6 +10048,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
@@ -9776,6 +10099,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);
@@ -9790,6 +10114,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);
@@ -9805,6 +10130,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);
@@ -9883,6 +10209,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
@@ -9947,6 +10276,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
@@ -10172,6 +10517,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))
 	    {
@@ -10356,6 +10705,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.  */
 
@@ -10372,7 +10743,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;
@@ -10584,7 +10955,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");
@@ -10883,7 +11254,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,
@@ -10965,7 +11336,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,
@@ -11230,7 +11601,7 @@ output_rnglists (unsigned generation)
   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
@@ -11864,8 +12235,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)
     {
@@ -11880,14 +12254,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)
 	    {
@@ -11995,7 +12391,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");
@@ -16453,6 +16849,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;
@@ -16517,24 +16914,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)
@@ -16569,11 +16969,11 @@ 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;
-	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin,
-				 endname, secname);
+	    endname = cfun->fde->dw_fde_second_end, endview = 0;
+	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, 0,
+				 endname, endview, secname);
 	  listp = &(*listp)->dw_loc_next;
 	}
     }
@@ -16584,8 +16984,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;
 }
@@ -17404,7 +17803,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;
     }
@@ -18220,7 +18619,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;
 }
@@ -18544,12 +18943,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.  */
@@ -19738,7 +20150,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;
     }
@@ -19754,7 +20166,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;
@@ -19776,14 +20188,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;
 	}
@@ -19792,19 +20204,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;
 }
@@ -26164,7 +26575,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,
@@ -26358,11 +26769,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++;
@@ -26396,6 +26809,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
 		}
 	    }
 	}
+      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;
     }
 
@@ -26459,10 +26884,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;
     }
@@ -26503,8 +26929,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
@@ -26572,7 +26998,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)
@@ -26581,6 +27010,7 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      newloc->view = view;
     }
 
   if (var_loc_p && flag_debug_asm)
@@ -26652,6 +27082,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;
 }
@@ -26700,7 +27131,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);
@@ -26881,7 +27312,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",
@@ -26904,6 +27335,50 @@ 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))
+	    {
+	      /* When we're using the assembler to compute view
+		 numbers, we output symbolic labels after "view" in
+		 .loc directives, and the assembler will set them for
+		 us, so that we can refer to the view numbers in
+		 location lists.  The only exceptions are when we know
+		 a view will be zero: "-0" is a forced reset, used
+		 e.g. in the beginning of functions, whereas "0" tells
+		 the assembler to check that there was a PC change
+		 since the previous view, in a way that implicitly
+		 resets the next view.  */
+	      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;
+	    }
+	  else
+	    {
+	      if (!table->in_use)
+		fputs (" view -0", asm_out_file);
+	      else
+		fputs (" view 0", asm_out_file);
+	      /* Mark the present view as a zero view.  Earlier debug
+		 binds may have already added its id to loclists to be
+		 emitted later, so we can't reuse the id for something
+		 else.  However, it's good to know whether a view is
+		 known to be zero, because then we may be able to
+		 optimize out locviews that are all zeros, so take
+		 note of it in zero_view_p.  */
+	      bitmap_set_bit (zero_view_p, lvugid);
+	      table->view = ++lvugid;
+	    }
+	}
       putc ('\n', asm_out_file);
     }
   else
@@ -26912,7 +27387,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)
@@ -27588,9 +28075,10 @@ init_sections_and_labels (bool early_lto_debug)
 					    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);
+
       debug_ranges_section = get_section (dwarf_version >= 5
 					  ? DEBUG_RNGLISTS_SECTION
 					  : DEBUG_RANGES_SECTION,
@@ -27976,6 +28464,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.
@@ -29075,6 +29568,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)
@@ -29119,7 +29614,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)
@@ -29189,6 +29684,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);
@@ -29214,6 +29710,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);
@@ -29610,6 +30121,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);
@@ -29831,6 +30344,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;
@@ -29849,6 +30363,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)
@@ -29859,11 +30375,33 @@ 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));
 }
 
@@ -29888,7 +30426,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
@@ -30312,7 +30850,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,
@@ -30371,7 +30909,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 bc2ae4de1d3d..a1856a5185e2 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -160,7 +160,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.  */
@@ -203,6 +204,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/final.c b/gcc/final.c
index 578e5d6af4c7..68397b3ded36 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -110,6 +110,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;
@@ -1692,6 +1693,67 @@ 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);
+    }
+}
+
+/* We want to emit param bindings (before the first begin_stmt) in the
+   initial view, if we are emitting views.  To that end, we may
+   consume initial notes in the function, processing them in
+   final_start_function, before signaling the beginning of the
+   prologue, rather than in final.
+
+   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.  */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+  return (!DECL_IGNORED_P (current_function_decl)
+	  && debug_variable_location_views
+	  && insn && GET_CODE (insn) == NOTE
+	  && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+	      || NOTE_KIND (insn) == NOTE_INSN_DELETED));
+}
+
 /* 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
@@ -1699,12 +1761,15 @@ 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)
 {
   block_depth = 0;
 
@@ -1722,8 +1787,21 @@ final_start_function (rtx_insn *first, FILE *file,
   if (flag_sanitize & SANITIZE_ADDRESS)
     asan_function_start ();
 
+  rtx_insn *first = *firstp;
+  if (in_initial_view_p (first))
+    {
+      do
+	{
+	  final_scan_insn (first, file, 0, 0, seen);
+	  first = NEXT_INSN (first);
+	}
+      while (in_initial_view_p (first));
+      *firstp = first;
+    }
+
   if (!DECL_IGNORED_P (current_function_decl))
-    debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+    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);
@@ -1799,6 +1877,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 *first, FILE *file,
+		      int optimize_p ATTRIBUTE_UNUSED)
+{
+  int seen = 0;
+  final_start_function_1 (&first, file, &seen, optimize_p);
+  gcc_assert (seen == 0);
+}
+
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1928,11 +2017,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;
@@ -1999,6 +2087,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);
@@ -2015,6 +2105,23 @@ 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)
+{
+  /* Those that use the internal final_start_function_1/final_1 API
+     skip initial debug bind notes in final_start_function_1, and pass
+     the modified FIRST to final_1.  But those that use the public
+     final_start_function/final APIs, final_start_function can't move
+     FIRST because it's not passed by reference, so if they were
+     skipped there, skip them again here.  */
+  while (in_initial_view_p (first))
+    first = NEXT_INSN (first);
+
+  final_1 (first, file, 0, optimize_p);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2155,6 +2262,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 (in_cold_section_p)
@@ -2301,6 +2410,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
@@ -2357,7 +2468,10 @@ 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:
@@ -2368,6 +2482,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
 					   last_filename, last_discriminator,
 					   true);
+	      clear_next_view_needed (seen);
 	    }
 	  break;
 
@@ -2563,6 +2678,10 @@ 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
@@ -2575,7 +2694,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    (*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)
@@ -3042,7 +3166,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;
@@ -4481,8 +4606,10 @@ rest_of_handle_final (void)
     delete_vta_debug_insns (false);
 
   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 ();
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 35d79680ab03..23db0636fc79 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1558,6 +1558,22 @@ process_options (void)
 	     || write_symbols == VMS_AND_DWARF2_DEBUG)
 	 && !(flag_selective_scheduling || flag_selective_scheduling2));
 
+  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;
+    }
+  else if (debug_variable_location_views == -1 && dwarf_version != 5)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "without -gdwarf-5, -gvariable-location-views=incompat5 "
+		  "is equivalent to -gvariable-location-views");
+      debug_variable_location_views = 1;
+    }
+
   if (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index f0ad0ca16b23..c454506d1eda 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* VMS extensions.  */
 DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
 /* GNAT extensions.  */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index 882e286872e8..cf0039a92ab4 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -298,6 +298,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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-01-25 20:19                         ` Alexandre Oliva
  2018-01-26 14:58                           ` Jakub Jelinek
@ 2018-02-07  7:43                           ` Alexandre Oliva
  1 sibling, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-07  7:43 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jeff Law, Richard Biener, gcc-patches

On Jan 25, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Jan 24, 2018, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Tue, Dec 12, 2017 at 12:52:18AM -0200, Alexandre Oliva wrote:
>>> +    DW_LLE_GNU_view_pair = 0x09,
>>> +#define DW_LLE_view_pair DW_LLE_GNU_view_pair

>> This looks wrong.  The proposal has not been accepted yet, so you
>> really can't know if DW_LLE_view_pair will be like that or whether it
>> will have value of 9.  Unfortunately, the DWARF standard doesn't specify a
>> vendor range for DW_LLE_* values.  I'd use 0xf0 or so, and don't pretend
>> there is DW_LLE_view_pair at all, just use DW_LLE_GNU_view_pair everywhere.
>> Jason, what do you think?

> My reasoning was that, since we'd only emit this as an
> explicitly-requested backward-incompatible extension to DWARF-5 (by
> specifying -gdwarf-6 in this patch, but the option spelling could be
> changed), any LLE number whatsoever would do.  The point of the #define
> was to write the code in GCC so that, once DW_LLE_view_pair was
> standardized (if it ever was), we'd just set up an enum for it and we'd
> be done, but that would only happen at DWARF6+ anyway, so we'd be able
> to tell, since we'd then have actual DWARF6, rather than DWARF5 with an
> incompatible extensions (which is what we emit with the current
> -gdwarf-6 option; see below).

Also...  I have implemented DW_LLE_view_pair support in binutils's debug
info dumping code, based on the proposed extension, and that has already
been released, so changing the number in GCC would make it incompatible
with the already-released binutils.

You may notice I've renamed the GCC option to emit this extension in the
latest version of the patch.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-07  4:02                         ` Alexandre Oliva
@ 2018-02-07 19:23                           ` Jason Merrill
  2018-02-08 12:56                             ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jason Merrill @ 2018-02-07 19:23 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On 02/06/2018 11:02 PM, Alexandre Oliva wrote:
> On Feb  6, 2018, Jason Merrill <jason@redhat.com> wrote:
>> On 12/11/2017 09:52 PM, Alexandre Oliva wrote:

>> Why do we need to use a non-zero view identifier for a zero view?  Why
>> can't we always use 0 instead of the bitmap?
> 
> We assign view ids before we can determine whether the assigned view id
> will be a zero view.  That's because we scan insns forward, and debug
> binds take effect at the next .loc directive, which might be hundreds of
> insns after the first reference (lots of intervening debug binds before
> the insn that will take the next view), and insns that would cause the > .loc directive to be at a different address from that of the previous
> .loc might be anywhere between those two loc-generating insns, before or
> after the bind.  So, by the time we have to assign an id to the view, we
> don't know whether we'll find an insn that sets RESETTING_VIEW_P before
> we reach the loc-emitting insn that will take that view id.
> 
> It made more sense to me to assign the ids uniformly, and then mark
> those that we find to be zero when we reach them, than to scan forward
> (potentially O(n^2)) to tell in advance.  This also reduces differences
> in view id tracking between gcc-internal and asm view assignment.

Makes sense, thanks.

>>> DW_LNS_fixed_advance_pc is the only opcode that may change the
>>> address without resetting the view.  It is available for compilers
>>> to use when an address change is uncertain, e.g., when advancing
>>> past opcodes that may expand to an empty sequence,
>>> e.g. possibly-empty alignment sequences, optional no-operation
>>> opcodes or the like.
> 
>>> +      if (debug_variable_location_views && table->view)
>>> +	push_dw_line_info_entry (table, LI_adv_address, label_num);
> 
>> It looks like you'll always use DW_LNS_fixed_advance_pc when we don't
>> have .loc support.  Does that mean that the view never gets reset?
> 
> No, table->view will be zero if we have crossed an insn that
> RESET_NEXT_VIEW, and then we'll use a LI_set_address.
> 
>> I'm uncomfortable with the special handling of this opcode; it isn't
>> special in DWARF5 except as a fallback if more compact encodings
>> aren't usable.  Currently GCC is even more conservative than this, and
>> always use a relocation (DW_LNS_set_address); if we can use D_L_f_a_p
>> instead, I would expect that to help with link times.  It seems wrong
>> to use it only in the context of view support.
> 
> We didn't use it before, but if we use, that's ok.  We don't *have* to
> reset the view number to zero at a PC change.  It would be all right to
> never reset it, as long as the compiler and the debug info consumer
> agrees about it.  Since in some cases the compiler has to assign views
> itself (when the assembler doesn't support views), but it can't tell
> whether there will be a PC change (e.g. at an align), we need some
> mechanism that predictably refrains from resetting the view number,
> otherwise the compiler might pick a view number based on a possibly
> incorrect assumption about whether the align changes PC or not, and then
> it might not match what the consumer, that knows whether the PC
> advanced, would compute.  To make it concrete:
> 
> # ...
> .L352:
> # .loc 1 533 view 3 (internal compiler tracking, no assembler support)
> mov r12 <- whatever
> # DEBUG x => r12
> .balign 32
> .L353:
> # .loc 1 480 view <?>
> 
> Consider you're the compiler and you're generating a view-augmented
> loclist for variable x.  You have to indicate the view number at .L353
> for the range that starts there, and possibly for the range that ends
> there.
> 
> But is the view number 4 or 0?  Namely, does .balign advance PC or not?
> The compiler can't possibly know.  So if it guesses .balign does advance
> PC and assign a view number zero at .L353, but it guesses wrong, that
> will be indistinguishable from view number zero at say .L350, because
> the PC is the same.  The debug info consumer will see no PC change and
> assign view number 4 to the line number table entry correspoding to the
> .loc directive with view <?>, but it won't find any loclist referencing
> that view number.  Conversely, if the compiler guessed .balign did not
> advance PC, it would assign view number 4 to .L353, but then, with your
> suggestion, the debug info consumer would instead assign it view number
> zero, and we'd be out of sync.
> 
> That's why we need an opcode that enables the compiler and the debug
> info consumer to remain in sync, disregarding a potential PC change that
> would cause a view reset, because the compiler can't predict whether or
> not there will be an actual PC change.
> 
>> Would it make sense to say for *all* opcodes that the view is reset if
>> and only if the address actually changes?
> 
> I don't see how to keep compiler and consumer in sync with this
> arrangement.  That's why I introduced the one exceptional opcode.

OK, that makes sense.  But I'm still uncomfortable with choosing an 
existing opcode for that purpose, which previously would have been 
chosen just for reasons of encoding complexity and size.

>> How are we coordinating the line number table and location list
>> versions of the view counter?
> 
> When the compiler is emitting the line number programs and computing
> view numbers itself, it resets view numbers at known PC changes and
> counts from that, and then it emits view numbers as literal constants in
> locviewlists.
> 
> When the compiler defers view computation to the assembler, it emits
> symbolic view numbers in locviewlists, with the exception of views known
> to be zero (forced resets, or reset after compiler-visible PC changes):
> instead of emitting symbols for these, we emit literal zero and assert
> the assembler agrees with the compiler's assessment.  We could use
> symbolic views everywhere, instead of special-casing zero views, but
> then we'd be unable to optimize out locviewlists that contain only
> zeros.

Thanks, it would be good to have this overview in a comment somewhere.

Jason

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-07 19:23                           ` Jason Merrill
@ 2018-02-08 12:56                             ` Alexandre Oliva
  2018-02-08 16:05                               ` Jason Merrill
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-08 12:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb  7, 2018, Jason Merrill <jason@redhat.com> wrote:

> OK, that makes sense.  But I'm still uncomfortable with choosing an
> existing opcode for that purpose, which previously would have been
> chosen just for reasons of encoding complexity and size.

Well, there's a good reason we didn't used to output this opcode: it's
nearly always the case that you're better off using a special opcode or
DW_LNS_advance_pc, that encodes the offset as uleb128 instead of a fixed
size.  The only exceptions I can think of are offsets that have the most
significant bits set in the representable range for
DW_LNS_fixed_advance_pc (the uleb128 representation for
DW_LNS_advance_pc would end up taking an extra byte if insns don't get
more than byte alignment), and VLIW machines, in which the
DW_LNS_advance_pc operand needs to be multiplied by the ops-per-insns
(but also divided by the min-insn-length).  So, unless you're creating a
gap of 16KiB to 64KiB in the middle of a function on an ISA such as
x86*, that has insns as small as 1 byte, you'll only use
DW_LNS_fixed_advance_pc when the assembler can't encode uleb128 offsets,
as stated in the DWARF specs.  Well, now there's one more case for using
it, and it's a rare one as well.  I didn't think it made sense to add
yet another opcode with a fixed-size operand for that.

But then again, even it was an opcode used more often, it wouldn't be a
significant problem to assign it the special behavior of not resetting
the view counter.  Views don't have to be reset for the whole thing to
work, we just need some means for the compiler (who doesn't know all
offsets) and debug info consumers (who do) to keep view numbers in sync.
A single opcode for the compiler to signal to the consumer that it
wasn't sure a smallish offset would be nonzero is enough, and
DW_LNS_fixed_advance_pc provides us with just what we need, without any
complications of having to compute a special opcode, or compute a
compiler-unknown offset times min-insn-length and have that encoded in
uleb128.


> Thanks, it would be good to have this overview in a comment somewhere.

You meant just these two paragraphs (like below), or the whole thing?


diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 3cf79270b72c..56d3e14b81bf 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3183,7 +3183,33 @@ static GTY(()) bitmap zero_view_p;
 			: (N) == 0)
 
 /* Return true iff we're to emit .loc directives for the assembler to
-   generate line number sections.  */
+   generate line number sections.
+
+   When we're not emitting views, all we need from the assembler is
+   support for .loc directives.
+
+   If we are emitting views, we can only use the assembler's .loc
+   support if it also supports views.
+
+   When the compiler is emitting the line number programs and
+   computing view numbers itself, it resets view numbers at known PC
+   changes and counts from that, and then it emits view numbers as
+   literal constants in locviewlists.  There are cases in which the
+   compiler is not sure about PC changes, e.g. when extra alignment is
+   requested for a label.  In these cases, the compiler may not reset
+   the view counter, and the potential PC advance in the line number
+   program will use an opcode that does not reset the view counter
+   even if the PC actually changes, so that compiler and debug info
+   consumer can keep view numbers in sync.
+
+   When the compiler defers view computation to the assembler, it
+   emits symbolic view numbers in locviewlists, with the exception of
+   views known to be zero (forced resets, or reset after
+   compiler-visible PC changes): instead of emitting symbols for
+   these, we emit literal zero and assert the assembler agrees with
+   the compiler's assessment.  We could use symbolic views everywhere,
+   instead of special-casing zero views, but then we'd be unable to
+   optimize out locviewlists that contain only zeros.  */
 
 static bool
 output_asm_line_debug_info (void)


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-08 12:56                             ` Alexandre Oliva
@ 2018-02-08 16:05                               ` Jason Merrill
  2018-02-09  3:49                                 ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jason Merrill @ 2018-02-08 16:05 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Thu, Feb 8, 2018 at 7:56 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Feb  7, 2018, Jason Merrill <jason@redhat.com> wrote:
>
>> OK, that makes sense.  But I'm still uncomfortable with choosing an
>> existing opcode for that purpose, which previously would have been
>> chosen just for reasons of encoding complexity and size.
>
> Well, there's a good reason we didn't used to output this opcode: it's
> nearly always the case that you're better off using a special opcode or
> DW_LNS_advance_pc, that encodes the offset as uleb128 instead of a fixed
> size.  The only exceptions I can think of are offsets that have the most
> significant bits set in the representable range for
> DW_LNS_fixed_advance_pc (the uleb128 representation for
> DW_LNS_advance_pc would end up taking an extra byte if insns don't get
> more than byte alignment), and VLIW machines, in which the
> DW_LNS_advance_pc operand needs to be multiplied by the ops-per-insns
> (but also divided by the min-insn-length).  So, unless you're creating a
> gap of 16KiB to 64KiB in the middle of a function on an ISA such as
> x86*, that has insns as small as 1 byte, you'll only use
> DW_LNS_fixed_advance_pc when the assembler can't encode uleb128 offsets,
> as stated in the DWARF specs.

Which is often true of non-gas assemblers, isn't it?

> Well, now there's one more case for using
> it, and it's a rare one as well.  I didn't think it made sense to add
> yet another opcode with a fixed-size operand for that.

So, if I've got this right: The most conservative approach to updating
the address is DW_LNE_set_address, but we definitely want that to
reset the view because it's used for e.g. starting a new function.
And if it resets the view, we need to be careful not to use it more
than once for the same address.  Special opcodes are only generated by
the assembler from .loc directives, so we use symbolic views and let
the assembler decide whether or not they reset the view.  If we don't
have that assembler support, and don't want to use DW_LNE_set_address,
that leaves DW_LNS_advance_pc and DW_LNS_fixed_advance_pc.  The former
could be used by the assembler in cases when special opcodes can't
express the necessary change compactly, whereas the latter won't be,
so it's a better choice for this situation.  And since we don't know
whether the increment will be zero, we don't want it to reset the
view.

OK, that makes sense.  Though I expect this will come up again when
the DWARF committee looks at the proposal.

> But then again, even it was an opcode used more often, it wouldn't be a
> significant problem to assign it the special behavior of not resetting
> the view counter.  Views don't have to be reset for the whole thing to
> work, we just need some means for the compiler (who doesn't know all
> offsets) and debug info consumers (who do) to keep view numbers in sync.
> A single opcode for the compiler to signal to the consumer that it
> wasn't sure a smallish offset would be nonzero is enough, and
> DW_LNS_fixed_advance_pc provides us with just what we need, without any
> complications of having to compute a special opcode, or compute a
> compiler-unknown offset times min-insn-length and have that encoded in
> uleb128.
>
>> Thanks, it would be good to have this overview in a comment somewhere.
>
> You meant just these two paragraphs (like below), or the whole thing?

I meant just the two paragraphs, thanks.

Jason

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-07  7:36                         ` Alexandre Oliva
@ 2018-02-08 19:58                           ` Jason Merrill
  2018-02-09  3:20                             ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jason Merrill @ 2018-02-08 19:58 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On 02/07/2018 02:36 AM, Alexandre Oliva wrote:
> +/* Output symbol LAB1 as an unsigned LEB128 quantity.  */

Let's mention here that the value of LAB1 must be an assemble-time 
constant (such as a view counter), since we can't have LEB128 relocations.

With that, the patch looks OK.

Jason

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-08 19:58                           ` Jason Merrill
@ 2018-02-09  3:20                             ` Alexandre Oliva
  2018-02-11 19:04                               ` Andreas Schwab
  2018-02-11 20:47                               ` Andreas Schwab
  0 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-09  3:20 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb  8, 2018, Jason Merrill <jason@redhat.com> wrote:

> On 02/07/2018 02:36 AM, Alexandre Oliva wrote:
>> +/* Output symbol LAB1 as an unsigned LEB128 quantity.  */

> Let's mention here that the value of LAB1 must be an assemble-time
> constant (such as a view counter), since we can't have LEB128
> relocations.

/* Output symbol LAB1 as an unsigned LEB128 quantity.  LAB1 should be
   an assembler-computed constant, e.g. a view number, because we
   can't have relocations in LEB128 quantities.  */

> With that, the patch looks OK.

Thanks, here's what I checked in.


[LVU] Introduce location views

This patch introduces an option to enable the generation of location
views along with location lists.  The exact format depends on the
DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
(DW_LLE_view_pair) entries in DWARF5+ loclists.

Line number tables are also affected.  If the assembler is found, at
compiler build time, to support .loc views, we use them and
assembler-computed view labels, otherwise we output compiler-generated
line number programs with conservatively-computed view labels.  In
either case, we output view information next to line number changes
when verbose assembly output is requested.

This patch requires an LVU patch that modifies the exported API of
final_scan_insn.  It also expects the entire SFN patchset to be
installed first, although SFN is not a requirement for LVU.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_locviews): New.
	* dwarf2.h (enum dwarf_location_list_entry_type): Add
	DW_LLE_GNU_view_pair.
	(DW_LLE_view_pair): Define.

for  gcc/ChangeLog

	* common.opt (gvariable-location-views): New.
	(gvariable-location-views=incompat5): New.
	* config.in: Rebuilt.
	* configure: Rebuilt.
	* configure.ac: Test assembler for view support.
	* dwarf2asm.c (dw2_asm_output_symname_uleb128): New.
	* dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare.
	* dwarf2out.c (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.
	(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.
	(maybe_emit_file): Call output_asm_line_debug_info for test.
	(dwarf2out_var_location): Reset views as needed.  Precompute
	add_var_loc_to_decl args.  Call get_attr_min_length only if we have the
	attribute.  Set view.
	(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.
	Use output_dwarf_version.
	* dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list.
	(struct dw_val_node): Add val_view_list.
	* final.c (SEEN_NEXT_VIEW): New.
	(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.  Notify debug backend of section
	changes, and of location view changes.
	(rest_of_handle_final): Adjust.
	* toplev.c (process_options): Autodetect value for debug variable
	location views option.  Warn on incompat5 without -gdwarf-5.
	* doc/invoke.texi (gvariable-location-views): New.
	(gvariable-location-views=incompat5): New.
	(gno-variable-location-views): New.
---
 gcc/common.opt      |    7 +
 gcc/config.in       |    6 
 gcc/configure       |   46 +++
 gcc/configure.ac    |   18 +
 gcc/doc/invoke.texi |   29 ++
 gcc/dwarf2asm.c     |   29 ++
 gcc/dwarf2asm.h     |    4 
 gcc/dwarf2out.c     |  700 ++++++++++++++++++++++++++++++++++++++++++++++-----
 gcc/dwarf2out.h     |    4 
 gcc/final.c         |  149 ++++++++++-
 gcc/toplev.c        |   16 +
 include/dwarf2.def  |    1 
 include/dwarf2.h    |    8 +
 13 files changed, 936 insertions(+), 81 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 3e9e3101c8f2..40ec0088c57e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2956,6 +2956,13 @@ gtoggle
 Common Driver Report Var(flag_gtoggle)
 Toggle debug information generation.
 
+gvariable-location-views
+Common Driver Var(debug_variable_location_views, 1) Init(2)
+Augment variable location lists with progressive views.
+
+gvariable-location-views=incompat5
+Common Driver RejectNegative Var(debug_variable_location_views, -1) Init(2)
+
 gvms
 Common Driver JoinedOrMissing Negative(gxcoff)
 Generate debug information in VMS format.
diff --git a/gcc/config.in b/gcc/config.in
index 8dc453104c13..5bccb408016b 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/configure b/gcc/configure
index 3360209559b2..b12628725b67 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27825,6 +27825,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 1019b3152621..140c804412a7 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4902,9 +4902,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/doc/invoke.texi b/gcc/doc/invoke.texi
index 367b99bc95cb..df357bea7dc2 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -348,6 +348,7 @@ Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gcolumn-info  -gno-column-info @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
 -fno-eliminate-unused-debug-types @gol
@@ -7255,6 +7256,34 @@ 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 -gvariable-location-views=incompat5
+@item -gno-variable-location-views
+@opindex gvariable-location-views
+@opindex gvariable-location-views=incompat5
+@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 @option{-fvar-tracking-assignments} is
+enabled and @option{-gstrict-dwarf} is not.
+
+There is a proposed representation for view numbers that is not backward
+compatible with the location list format introduced in DWARF 5, that can
+be enabled with @option{-gvariable-location-views=incompat5}.  This
+option may be removed in the future, is only provided as a reference
+implementation of the proposed representation.  Debug information
+consumers are not expected to support this extended format, and they
+would be rendered unable to decode location lists using it.
+
 @item -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index 9952e0a98506..e9b18b8b7852 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -767,6 +767,35 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
   va_end (ap);
 }
 
+/* Output symbol LAB1 as an unsigned LEB128 quantity.  LAB1 should be
+   an assembler-computed constant, e.g. a view number, because we
+   can't have relocations in LEB128 quantities.  */
+
+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,
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index b5ed449205ef..1b76909a1c91 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 948b3cbe5918..56d3e14b81bf 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1291,6 +1291,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.  */
@@ -1300,9 +1302,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.  */
@@ -1339,6 +1343,29 @@ 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 == 1;
+}
+
+/* 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 == -1;
+#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.  */
@@ -1401,6 +1428,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:
@@ -2875,7 +2904,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 {
@@ -2897,6 +2934,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;
 };
 
@@ -3098,6 +3154,71 @@ 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 refers to a view identifier for which we
+   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)
+
+/* Return true iff we're to emit .loc directives for the assembler to
+   generate line number sections.
+
+   When we're not emitting views, all we need from the assembler is
+   support for .loc directives.
+
+   If we are emitting views, we can only use the assembler's .loc
+   support if it also supports views.
+
+   When the compiler is emitting the line number programs and
+   computing view numbers itself, it resets view numbers at known PC
+   changes and counts from that, and then it emits view numbers as
+   literal constants in locviewlists.  There are cases in which the
+   compiler is not sure about PC changes, e.g. when extra alignment is
+   requested for a label.  In these cases, the compiler may not reset
+   the view counter, and the potential PC advance in the line number
+   program will use an opcode that does not reset the view counter
+   even if the PC actually changes, so that compiler and debug info
+   consumer can keep view numbers in sync.
+
+   When the compiler defers view computation to the assembler, it
+   emits symbolic view numbers in locviewlists, with the exception of
+   views known to be zero (forced resets, or reset after
+   compiler-visible PC changes): instead of emitting symbols for
+   these, we emit literal zero and assert the assembler agrees with
+   the compiler's assessment.  We could use symbolic views everywhere,
+   instead of special-casing zero views, but then we'd be unable to
+   optimize out locviewlists that contain only zeros.  */
+
+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
@@ -3207,6 +3328,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.  */
@@ -3415,6 +3537,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);
@@ -3451,7 +3575,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 void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -3651,8 +3775,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);
@@ -4648,11 +4772,65 @@ AT_loc_list (dw_attr_node *a)
   return a->dw_attr_val.v.val_loc_list;
 }
 
+/* Add a view list attribute to DIE.  It must have a DW_AT_location
+   attribute, because the view list complements the location 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);
+}
+
+/* Return a pointer to the location list referenced by the attribute.
+   If the named attribute is a view list, look up the corresponding
+   DW_AT_location attribute and return its location list.  */
+
 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 ();
+    }
+}
+
+/* Return the location attribute value associated with a view list
+   attribute value.  */
+
+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>
@@ -5907,7 +6085,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;
@@ -5996,7 +6174,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.  */
@@ -6012,7 +6190,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
 	    {
@@ -6147,6 +6325,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;
@@ -9007,6 +9191,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);
@@ -9378,6 +9563,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)
@@ -9652,7 +9838,8 @@ output_abbrev_section (void)
    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> ();
@@ -9662,10 +9849,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.  */
 
@@ -9674,6 +9879,98 @@ 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.  */
@@ -9681,34 +9978,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,
@@ -9726,6 +10074,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
@@ -9776,6 +10125,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);
@@ -9790,6 +10140,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);
@@ -9805,6 +10156,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);
@@ -9883,6 +10235,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
@@ -9947,6 +10302,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
@@ -10172,6 +10543,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))
 	    {
@@ -10356,6 +10731,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.  */
 
@@ -10372,7 +10769,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;
@@ -10584,7 +10981,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");
@@ -10883,7 +11280,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,
@@ -10965,7 +11362,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,
@@ -11230,7 +11627,7 @@ output_rnglists (unsigned generation)
   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
@@ -11864,8 +12261,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)
     {
@@ -11880,14 +12280,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)
 	    {
@@ -11995,7 +12417,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");
@@ -16453,6 +16875,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;
@@ -16517,24 +16940,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)
@@ -16569,11 +16995,11 @@ 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;
-	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin,
-				 endname, secname);
+	    endname = cfun->fde->dw_fde_second_end, endview = 0;
+	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, 0,
+				 endname, endview, secname);
 	  listp = &(*listp)->dw_loc_next;
 	}
     }
@@ -16584,8 +17010,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;
 }
@@ -17404,7 +17829,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;
     }
@@ -18220,7 +18645,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;
 }
@@ -18544,12 +18969,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.  */
@@ -19738,7 +20176,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;
     }
@@ -19754,7 +20192,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;
@@ -19776,14 +20214,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;
 	}
@@ -19792,19 +20230,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;
 }
@@ -26164,7 +26601,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,
@@ -26358,11 +26795,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++;
@@ -26396,6 +26835,18 @@ dwarf2out_var_location (rtx_insn *loc_note)
 		}
 	    }
 	}
+      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;
     }
 
@@ -26459,10 +26910,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;
     }
@@ -26503,8 +26955,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
@@ -26572,7 +27024,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)
@@ -26581,6 +27036,7 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      newloc->view = view;
     }
 
   if (var_loc_p && flag_debug_asm)
@@ -26652,6 +27108,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;
 }
@@ -26700,7 +27157,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);
@@ -26881,7 +27338,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",
@@ -26904,6 +27361,50 @@ 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))
+	    {
+	      /* When we're using the assembler to compute view
+		 numbers, we output symbolic labels after "view" in
+		 .loc directives, and the assembler will set them for
+		 us, so that we can refer to the view numbers in
+		 location lists.  The only exceptions are when we know
+		 a view will be zero: "-0" is a forced reset, used
+		 e.g. in the beginning of functions, whereas "0" tells
+		 the assembler to check that there was a PC change
+		 since the previous view, in a way that implicitly
+		 resets the next view.  */
+	      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;
+	    }
+	  else
+	    {
+	      if (!table->in_use)
+		fputs (" view -0", asm_out_file);
+	      else
+		fputs (" view 0", asm_out_file);
+	      /* Mark the present view as a zero view.  Earlier debug
+		 binds may have already added its id to loclists to be
+		 emitted later, so we can't reuse the id for something
+		 else.  However, it's good to know whether a view is
+		 known to be zero, because then we may be able to
+		 optimize out locviews that are all zeros, so take
+		 note of it in zero_view_p.  */
+	      bitmap_set_bit (zero_view_p, lvugid);
+	      table->view = ++lvugid;
+	    }
+	}
       putc ('\n', asm_out_file);
     }
   else
@@ -26912,7 +27413,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)
@@ -27588,9 +28101,10 @@ init_sections_and_labels (bool early_lto_debug)
 					    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);
+
       debug_ranges_section = get_section (dwarf_version >= 5
 					  ? DEBUG_RNGLISTS_SECTION
 					  : DEBUG_RANGES_SECTION,
@@ -27976,6 +28490,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.
@@ -29075,6 +29594,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)
@@ -29119,7 +29640,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)
@@ -29189,6 +29710,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);
@@ -29214,6 +29736,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);
@@ -29610,6 +30147,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);
@@ -29831,6 +30370,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;
@@ -29849,6 +30389,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)
@@ -29859,11 +30401,33 @@ 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));
 }
 
@@ -29888,7 +30452,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
@@ -30312,7 +30876,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,
@@ -30371,7 +30935,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 bc2ae4de1d3d..a1856a5185e2 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -160,7 +160,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.  */
@@ -203,6 +204,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/final.c b/gcc/final.c
index 578e5d6af4c7..68397b3ded36 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -110,6 +110,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;
@@ -1692,6 +1693,67 @@ 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);
+    }
+}
+
+/* We want to emit param bindings (before the first begin_stmt) in the
+   initial view, if we are emitting views.  To that end, we may
+   consume initial notes in the function, processing them in
+   final_start_function, before signaling the beginning of the
+   prologue, rather than in final.
+
+   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.  */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+  return (!DECL_IGNORED_P (current_function_decl)
+	  && debug_variable_location_views
+	  && insn && GET_CODE (insn) == NOTE
+	  && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+	      || NOTE_KIND (insn) == NOTE_INSN_DELETED));
+}
+
 /* 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
@@ -1699,12 +1761,15 @@ 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)
 {
   block_depth = 0;
 
@@ -1722,8 +1787,21 @@ final_start_function (rtx_insn *first, FILE *file,
   if (flag_sanitize & SANITIZE_ADDRESS)
     asan_function_start ();
 
+  rtx_insn *first = *firstp;
+  if (in_initial_view_p (first))
+    {
+      do
+	{
+	  final_scan_insn (first, file, 0, 0, seen);
+	  first = NEXT_INSN (first);
+	}
+      while (in_initial_view_p (first));
+      *firstp = first;
+    }
+
   if (!DECL_IGNORED_P (current_function_decl))
-    debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+    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);
@@ -1799,6 +1877,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 *first, FILE *file,
+		      int optimize_p ATTRIBUTE_UNUSED)
+{
+  int seen = 0;
+  final_start_function_1 (&first, file, &seen, optimize_p);
+  gcc_assert (seen == 0);
+}
+
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1928,11 +2017,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;
@@ -1999,6 +2087,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);
@@ -2015,6 +2105,23 @@ 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)
+{
+  /* Those that use the internal final_start_function_1/final_1 API
+     skip initial debug bind notes in final_start_function_1, and pass
+     the modified FIRST to final_1.  But those that use the public
+     final_start_function/final APIs, final_start_function can't move
+     FIRST because it's not passed by reference, so if they were
+     skipped there, skip them again here.  */
+  while (in_initial_view_p (first))
+    first = NEXT_INSN (first);
+
+  final_1 (first, file, 0, optimize_p);
+}
 \f
 const char *
 get_insn_template (int code, rtx insn)
@@ -2155,6 +2262,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 (in_cold_section_p)
@@ -2301,6 +2410,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
@@ -2357,7 +2468,10 @@ 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:
@@ -2368,6 +2482,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	      (*debug_hooks->source_line) (last_linenum, last_columnnum,
 					   last_filename, last_discriminator,
 					   true);
+	      clear_next_view_needed (seen);
 	    }
 	  break;
 
@@ -2563,6 +2678,10 @@ 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
@@ -2575,7 +2694,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    (*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)
@@ -3042,7 +3166,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;
@@ -4481,8 +4606,10 @@ rest_of_handle_final (void)
     delete_vta_debug_insns (false);
 
   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 ();
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 35d79680ab03..23db0636fc79 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1558,6 +1558,22 @@ process_options (void)
 	     || write_symbols == VMS_AND_DWARF2_DEBUG)
 	 && !(flag_selective_scheduling || flag_selective_scheduling2));
 
+  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;
+    }
+  else if (debug_variable_location_views == -1 && dwarf_version != 5)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "without -gdwarf-5, -gvariable-location-views=incompat5 "
+		  "is equivalent to -gvariable-location-views");
+      debug_variable_location_views = 1;
+    }
+
   if (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index f0ad0ca16b23..c454506d1eda 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -443,6 +443,7 @@ 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)
 /* VMS extensions.  */
 DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
 /* GNAT extensions.  */
diff --git a/include/dwarf2.h b/include/dwarf2.h
index 882e286872e8..cf0039a92ab4 100644
--- a/include/dwarf2.h
+++ b/include/dwarf2.h
@@ -298,6 +298,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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-01-25 20:14                       ` Alexandre Oliva
@ 2018-02-09  3:21                         ` Alexandre Oliva
  2018-02-09  3:53                           ` Alan Modra
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-09  3:21 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Richard Biener, Jeff Law, GCC Patches

On Jan 25, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Jan 24, 2018, Jakub Jelinek <jakub@redhat.com> wrote:
>> I think this asks for
>> if (flag_checking)
>> gcc_assert (block_within_block_p (block,
>> DECL_INITIAL (current_function_decl),
>> true));

> 'k, changed.

>> Otherwise the patch looks reasonable to me, but I think it depends on the
>> 7/9.

> Thanks, yeah, it very much does.  It *might* be possible to split out
> the dependency, but...  it would just take most of the LVU patch with it
> ;-)

Here's what I checked in, right after the LVU patch.

[IEPM] Introduce inline entry point markers

Output DW_AT_entry_pc based on markers.

Introduce DW_AT_GNU_entry_view as a DWARF extension.

If views are enabled are we're not in strict compliance mode, output
DW_AT_GNU_entry_view if it might be nonzero.

This patch depends on SFN and LVU patchsets, and on the IEPM patch that
introduces the inline_entry debug hook.

for  include/ChangeLog

	* dwarf2.def (DW_AT_GNU_entry_view): New.

for  gcc/ChangeLog

	* cfgexpand.c (expand_gimple_basic_block): Handle inline entry
	markers.
	* dwarf2out.c (dwarf2_debug_hooks): Enable inline_entry hook.
	(BLOCK_INLINE_ENTRY_LABEL): New.
	(dwarf2out_var_location): Disregard inline entry markers.
	(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.
	(block_within_block_p, dwarf2out_inline_entry): New.
	(dwarf2out_finish): Check that no entries remained in
	inline_entry_data_table.
	* final.c (reemit_insn_block_notes): Handle inline entry notes.
	(final_scan_insn, notice_source_line): Likewise.
	(rest_of_clean_state): Skip inline entry markers.
	* gimple-pretty-print.c (dump_gimple_debug): Handle inline entry
	markers.
	* gimple.c (gimple_build_debug_inline_entry): New.
	* gimple.h (enum gimple_debug_subcode): Add
	GIMPLE_DEBUG_INLINE_ENTRY.
	(gimple_build_debug_inline_entry): Declare.
	(gimple_debug_inline_entry_p): New.
	(gimple_debug_nonbind_marker_p): Adjust.
	* insn-notes.def (INLINE_ENTRY): New.
	* print-rtl.c (rtx_writer::print_rtx_operand_code_0): Handle
	inline entry marker notes.
	(print_insn): Likewise.
	* rtl.h	(NOTE_MARKER_P): Add INLINE_ENTRY support.
	(INSN_DEBUG_MARKER_KIND): Likewise.
	(GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT): New.
	* tree-inline.c	(expand_call_inline): Build and insert
	debug_inline_entry stmt.
	* 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.
	* var-tracking.c (reemit_marker_as_note): Handle inline entry note.
	* doc/gimple.texi (gimple_debug_inline_entry_p): New.
	(gimple_build_debug_inline_entry): New.
	* doc/invoke.texi (gstatement-frontiers, gno-statement-frontiers):
	Enable/disable inline entry points too.
	* doc/rtl.texi (NOTE_INSN_INLINE_ENTRY): New.
	(DEBUG_INSN): Describe inline entry markers.
---
 gcc/cfgexpand.c           |    9 ++
 gcc/doc/gimple.texi       |   18 ++++
 gcc/doc/rtl.texi          |   24 ++++-
 gcc/dwarf2out.c           |  199 ++++++++++++++++++++++++++++++++++++++++++++-
 gcc/final.c               |   26 ++++++
 gcc/gimple-pretty-print.c |   13 +++
 gcc/gimple.c              |   21 +++++
 gcc/gimple.h              |   18 ++++
 gcc/insn-notes.def        |    4 +
 gcc/print-rtl.c           |    5 +
 gcc/rtl.h                 |    7 +-
 gcc/tree-inline.c         |    7 ++
 gcc/tree-ssa-live.c       |   27 +++++-
 gcc/var-tracking.c        |    1 
 include/dwarf2.def        |    1 
 15 files changed, 364 insertions(+), 16 deletions(-)

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 2ee6fbac2e30..deab9296001a 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5731,6 +5731,15 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
 		goto delink_debug_stmt;
 	      else if (gimple_debug_begin_stmt_p (stmt))
 		val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT ();
+	      else if (gimple_debug_inline_entry_p (stmt))
+		{
+		  tree block = gimple_block (stmt);
+
+		  if (block)
+		    val = GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT ();
+		  else
+		    goto delink_debug_stmt;
+		}
 	      else
 		gcc_unreachable ();
 
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 6d920aeb9675..1f9449f133bd 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -836,6 +836,11 @@ Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
 a source statement.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple_debug_inline_entry_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the entry
+point of an inlined function.
+@end deftypefn
+
 @deftypefn {GIMPLE function} gimple_debug_nonbind_marker_p (gimple g)
 Return true if g is a @code{GIMPLE_DEBUG} that marks a program location,
 without any variable binding.
@@ -1541,6 +1546,7 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
 @cindex @code{GIMPLE_DEBUG}
 @cindex @code{GIMPLE_DEBUG_BIND}
 @cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
+@cindex @code{GIMPLE_DEBUG_INLINE_ENTRY}
 
 @deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
 tree value, gimple stmt)
@@ -1626,6 +1632,18 @@ observable, and that none of the side effects of subsequent user
 statements are.
 @end deftypefn
 
+@deftypefn {GIMPLE function} gimple gimple_build_debug_inline_entry (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_INLINE_ENTRY} @code{subcode}.  The effect of this
+statement is to tell debug information generation machinery that a
+function call at @code{location} underwent inline substitution, that
+@code{block} is the enclosing lexical block created for the
+substitution, and that at the point of the program in which the stmt is
+inserted, all parameters for the inlined function are bound to the
+respective arguments, and none of the side effects of its stmts are
+observable.
+@end deftypefn
+
 @node @code{GIMPLE_EH_FILTER}
 @subsection @code{GIMPLE_EH_FILTER}
 @cindex @code{GIMPLE_EH_FILTER}
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 2523f63c6738..43d5405ddb47 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3670,7 +3670,10 @@ Refers to a parameter that was completely optimized out.
 @item (debug_marker:@var{mode})
 Marks a program location.  With @code{VOIDmode}, it stands for the
 beginning of a statement, a recommended inspection point logically after
-all prior side effects, and before any subsequent side effects.
+all prior side effects, and before any subsequent side effects.  With
+@code{BLKmode}, it indicates an inline entry point: the lexical block
+encoded in the @code{INSN_LOCATION} is the enclosing block that encloses
+the inlined function.
 
 @end table
 
@@ -3954,6 +3957,13 @@ This note is used to generate @code{is_stmt} markers in line number
 debuggign information.  It indicates the beginning of a user
 statement.
 
+@findex NOTE_INSN_INLINE_ENTRY
+@item NOTE_INSN_INLINE_ENTRY
+This note is used to generate @code{entry_pc} for inlined subroutines in
+debugging information.  It indicates an inspection point at which all
+arguments for the inlined function have been bound, and before its first
+statement.
+
 @end table
 
 These codes are printed symbolically when they appear in debugging dumps.
@@ -3971,8 +3981,12 @@ binds a user variable tree to an RTL representation of the
 it stands for the value bound to the corresponding
 @code{DEBUG_EXPR_DECL}.
 
-@code{GIMPLE_DEBUG_BEGIN_STMT} is expanded to RTL as a @code{DEBUG_INSN}
-with a @code{VOIDmode} @code{DEBUG_MARKER} @code{PATTERN}.  These
+@code{GIMPLE_DEBUG_BEGIN_STMT} and @code{GIMPLE_DEBUG_INLINE_ENTRY} are
+expanded to RTL as a @code{DEBUG_INSN} with a @code{DEBUG_MARKER}
+@code{PATTERN}; the difference is the RTL mode: the former's
+@code{DEBUG_MARKER} is @code{VOIDmode}, whereas the latter is
+@code{BLKmode}; information about the inlined function can be taken from
+the lexical block encoded in the @code{INSN_LOCATION}.  These
 @code{DEBUG_INSN}s, that do not carry @code{VAR_LOCATION} information,
 just @code{DEBUG_MARKER}s, can be detected by testing
 @code{DEBUG_MARKER_INSN_P}, whereas those that do can be recognized as
@@ -3983,8 +3997,8 @@ 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,
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION},
+@code{NOTE_INSN_BEGIN_STMT} and @code{NOTE_INSN_INLINE_ENTRY} 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
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 56d3e14b81bf..749c7e3b9bbc 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2747,6 +2747,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);
@@ -2800,7 +2801,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   debug_nothing_rtx_code_label,	/* label */
   debug_nothing_int,		/* handle_pch */
   dwarf2out_var_location,
-  debug_nothing_tree,		/* inline_entry */
+  dwarf2out_inline_entry,	/* inline_entry */
   dwarf2out_size_function,	/* size_function */
   dwarf2out_switch_text_section,
   dwarf2out_set_name,
@@ -4068,6 +4069,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
@@ -23215,6 +23219,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
@@ -23667,6 +23713,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 (MAY_HAVE_DEBUG_MARKER_INSNS);
+      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))
     {
@@ -23674,7 +23756,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 (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23839,7 +23921,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26871,6 +26953,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
       || ! 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;
 
@@ -27064,6 +27147,113 @@ create_label:
   last_in_cold_section_p = in_cold_section_p;
 }
 
+/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
+   OUTER itself.  If BOTHWAYS, check not only that BLOCK can reach
+   OUTER through BLOCK_SUPERCONTEXT links, but also that there is a
+   path from OUTER to BLOCK through BLOCK_SUBBLOCKs and
+   BLOCK_FRAGMENT_ORIGIN links.  */
+static bool
+block_within_block_p (tree block, tree outer, bool bothways)
+{
+  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;
+
+  if (!bothways)
+    return true;
+
+  /* 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)
+{
+  /* If we can't represent it, don't bother.  */
+  if (!(dwarf_version >= 3 || !dwarf_strict))
+    return;
+
+  gcc_assert (DECL_P (block_ultimate_origin (block)));
+
+  /* Sanity check the block tree.  This would catch a case in which
+     BLOCK got removed from the tree reachable from the outermost
+     lexical block, but got retained in markers.  It would still link
+     back to its parents, but some ancestor would be missing a link
+     down the path to the sub BLOCK.  If the block got removed, its
+     BLOCK_NUMBER will not be a usable value.  */
+  if (flag_checking)
+    gcc_assert (block_within_block_p (block,
+				      DECL_INITIAL (current_function_decl),
+				      true));
+
+  gcc_assert (inlined_function_outer_scope_p (block));
+  gcc_assert (!BLOCK_DIE (block));
+
+  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.  */
@@ -30560,6 +30750,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 ());
diff --git a/gcc/final.c b/gcc/final.c
index 68397b3ded36..99a7cadd7c9f 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1611,6 +1611,7 @@ reemit_insn_block_notes (void)
 	    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;
 
@@ -2479,6 +2480,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	  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);
@@ -2486,6 +2488,18 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    }
 	  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:
 	  gcc_unreachable ();
 	  break;
@@ -3189,6 +3203,17 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
   if (NOTE_MARKER_P (insn))
     {
       location_t loc = NOTE_MARKER_LOCATION (insn);
+      /* The inline entry markers (gimple, insn, note) carry the
+	 location of the call, because that's what we want to carry
+	 during compilation, but the location we want to output in
+	 debug information for the inline entry point is the location
+	 of the function itself.  */
+      if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY)
+	{
+	  tree block = LOCATION_BLOCK (loc);
+	  tree fn = block_ultimate_origin (block);
+	  loc = DECL_SOURCE_LOCATION (fn);
+	}
       expanded_location xloc = expand_location (loc);
       if (xloc.line == 0)
 	{
@@ -4795,6 +4820,7 @@ rest_of_clean_state (void)
 	  && (!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/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 374bd45b09b9..6695526f3702 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1371,6 +1371,19 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
 	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 c1b7229a6b79..9dc4911a36e0 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -874,6 +874,27 @@ gimple_build_debug_begin_stmt (tree block, location_t location
 }
 
 
+/* 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.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 74605864a71a..265e3e24398c 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -202,7 +202,8 @@ enum gf_mask {
 enum gimple_debug_subcode {
   GIMPLE_DEBUG_BIND = 0,
   GIMPLE_DEBUG_SOURCE_BIND = 1,
-  GIMPLE_DEBUG_BEGIN_STMT = 2
+  GIMPLE_DEBUG_BEGIN_STMT = 2,
+  GIMPLE_DEBUG_INLINE_ENTRY = 3
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -1454,6 +1455,7 @@ 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);
@@ -4784,13 +4786,25 @@ gimple_debug_begin_stmt_p (const gimple *s)
   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;
+    return s->subcode == GIMPLE_DEBUG_BEGIN_STMT
+      || s->subcode == GIMPLE_DEBUG_INLINE_ENTRY;
 
   return false;
 }
diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def
index 5186d5812b30..9cac5f1549a7 100644
--- a/gcc/insn-notes.def
+++ b/gcc/insn-notes.def
@@ -71,6 +71,10 @@ 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/print-rtl.c b/gcc/print-rtl.c
index c26e46c0b767..3ad11dc4cf9b 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -276,6 +276,7 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_BEGIN_STMT:
+	case NOTE_INSN_INLINE_ENTRY:
 #ifndef GENERATOR_FILE
 	  {
 	    expanded_location xloc
@@ -1879,6 +1880,10 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
 		pp_string (pp, "debug begin stmt marker");
 		break;
 
+	      case NOTE_INSN_INLINE_ENTRY:
+		pp_string (pp, "debug inline entry marker");
+		break;
+
 	      default:
 		gcc_unreachable ();
 	      }
diff --git a/gcc/rtl.h b/gcc/rtl.h
index fcad6a7e3f89..c9dd7dd959fc 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1654,7 +1654,8 @@ extern const char * const reg_note_name[];
    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_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))
@@ -1692,6 +1693,8 @@ extern const char * const reg_note_name[];
   (GET_CODE (PATTERN (INSN)) == DEBUG_MARKER	  \
    ? (GET_MODE (PATTERN (INSN)) == VOIDmode	  \
       ? NOTE_INSN_BEGIN_STMT			  \
+      : GET_MODE (PATTERN (INSN)) == BLKmode	  \
+      ? NOTE_INSN_INLINE_ENTRY			  \
       : (enum insn_note)-1) 			  \
    : (enum insn_note)-1)
 /* Create patterns for debug markers.  These and the above abstract
@@ -1701,6 +1704,8 @@ extern const char * const reg_note_name[];
    wouldn't be a problem.  */
 #define GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT() \
   gen_rtx_DEBUG_MARKER (VOIDmode)
+#define GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT() \
+  gen_rtx_DEBUG_MARKER (BLKmode)
 
 /* The VAR_LOCATION rtx in a DEBUG_INSN.  */
 #define INSN_VAR_LOCATION(INSN) \
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index b0d9beb530a0..7f9ec770e197 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4605,6 +4605,13 @@ 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, input_location), GSI_NEW_STMT);
+    }
 
   if (DECL_INITIAL (fn))
     {
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 08ac678e74c1..26da31f74cb2 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/var-tracking.c b/gcc/var-tracking.c
index fbb63dbc305f..c3d4dac59ef2 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9959,6 +9959,7 @@ reemit_marker_as_note (rtx_insn *insn)
   switch (kind)
     {
     case NOTE_INSN_BEGIN_STMT:
+    case NOTE_INSN_INLINE_ENTRY:
       {
 	rtx_insn *note = NULL;
 	if (cfun->debug_nonbind_markers)
diff --git a/include/dwarf2.def b/include/dwarf2.def
index c454506d1eda..3becd7f8219c 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -444,6 +444,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
    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.  */


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-08 16:05                               ` Jason Merrill
@ 2018-02-09  3:49                                 ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-09  3:49 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb  8, 2018, Jason Merrill <jason@redhat.com> wrote:

> On Thu, Feb 8, 2018 at 7:56 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
>> On Feb  7, 2018, Jason Merrill <jason@redhat.com> wrote:
>> 
>>> OK, that makes sense.  But I'm still uncomfortable with choosing an
>>> existing opcode for that purpose, which previously would have been
>>> chosen just for reasons of encoding complexity and size.
>> 
>> Well, there's a good reason we didn't used to output this opcode: it's
>> nearly always the case that you're better off using a special opcode or
>> DW_LNS_advance_pc, that encodes the offset as uleb128 instead of a fixed
>> size.  The only exceptions I can think of are offsets that have the most
>> significant bits set in the representable range for
>> DW_LNS_fixed_advance_pc (the uleb128 representation for
>> DW_LNS_advance_pc would end up taking an extra byte if insns don't get
>> more than byte alignment), and VLIW machines, in which the
>> DW_LNS_advance_pc operand needs to be multiplied by the ops-per-insns
>> (but also divided by the min-insn-length).  So, unless you're creating a
>> gap of 16KiB to 64KiB in the middle of a function on an ISA such as
>> x86*, that has insns as small as 1 byte, you'll only use
>> DW_LNS_fixed_advance_pc when the assembler can't encode uleb128 offsets,
>> as stated in the DWARF specs.

> Which is often true of non-gas assemblers, isn't it?

Uhh...  I don't know.  Anyway, without gas, we probably won't have view
supports in .loc directives either, and then we'll have to emit the line
number program ourselves, in which case we could (if we have accurate
insn lengths) compute offsets and output special opcodes or
byte-expanded uleb128 literals, even if the assembler doesn't support
leb128.  Sure enough, if we don't have accurate insn lengths, we'll have
to resort to something else; for small increments without assembler
support for uleb128, DW_LNS_fixed_advance_pc would probably be a more
compact option than DW_LNS_set_address, if we're sure the increment is
small enough.

Even then, if we were to do something along these lines, when we know
the offset is nonzero (i.e., we want to reset the view), we could output
DW_LNS_fixed_advance_pc with the desired offset minus 1, followed by a
special opcode that advances PC (resetting the view count) and emitting
the line table entry, rather than using DW_LNS_fixed_advance_pc with the
offset, followed by DW_LNS_copy to output the line number table without
resetting the view.  Same size, with the choice of resetting or not the
view counter.  As for when we don't know whether the offset could be
zero, we have only one choice: not resetting the view counter.

> So, if I've got this right: The most conservative approach to updating
> the address is DW_LNE_set_address, but we definitely want that to
> reset the view because it's used for e.g. starting a new function.

Yup.

> And if it resets the view, we need to be careful not to use it more
> than once for the same address.

I guess it's ok if we do that e.g. once as the one-past-the-end of a
function, and then again as the entry of another function, but other
than that, yeah, it shouldn't happen.

  [...] 
> And since we don't know whether the increment will be zero, we
> don't want it to reset the view.

Yup

> OK, that makes sense.  Though I expect this will come up again when
> the DWARF committee looks at the proposal.

Most likely.  The reasoning that led me down this path was quite
intricate indeed.

Please let it be known that I'd be glad to join the committee's
conversation when they're to discuss this proposal, if that would be of
any help.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09  3:21                         ` Alexandre Oliva
@ 2018-02-09  3:53                           ` Alan Modra
  2018-02-09  4:13                             ` Jeff Law
  0 siblings, 1 reply; 156+ messages in thread
From: Alan Modra @ 2018-02-09  3:53 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jakub Jelinek, Jason Merrill, Richard Biener, Jeff Law, GCC Patches

On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
> Here's what I checked in, right after the LVU patch.
> 
> [IEPM] Introduce inline entry point markers

One of these two patches breaks ppc64le bootstrap with the assembler
complaining "Error: view number mismatch" when compiling
libdecnumber.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09  3:53                           ` Alan Modra
@ 2018-02-09  4:13                             ` Jeff Law
  2018-02-09 10:35                               ` Alexandre Oliva
  2018-02-09 21:01                               ` Alexandre Oliva
  0 siblings, 2 replies; 156+ messages in thread
From: Jeff Law @ 2018-02-09  4:13 UTC (permalink / raw)
  To: Alan Modra, Alexandre Oliva
  Cc: Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On 02/08/2018 08:53 PM, Alan Modra wrote:
> On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
>> Here's what I checked in, right after the LVU patch.
>>
>> [IEPM] Introduce inline entry point markers
> 
> One of these two patches breaks ppc64le bootstrap with the assembler
> complaining "Error: view number mismatch" when compiling
> libdecnumber.
> 
I've just passed along a similar failure (.i, .s and command line
options) to Alex for ppc64 (be) building glibc.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09  4:13                             ` Jeff Law
@ 2018-02-09 10:35                               ` Alexandre Oliva
  2018-02-09 12:10                                 ` Alan Modra
  2018-02-09 15:09                                 ` Jeff Law
  2018-02-09 21:01                               ` Alexandre Oliva
  1 sibling, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-09 10:35 UTC (permalink / raw)
  To: Jeff Law
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On Feb  9, 2018, Jeff Law <law@redhat.com> wrote:

> On 02/08/2018 08:53 PM, Alan Modra wrote:
>> On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
>>> Here's what I checked in, right after the LVU patch.
>>> 
>>> [IEPM] Introduce inline entry point markers
>> 
>> One of these two patches breaks ppc64le bootstrap with the assembler
>> complaining "Error: view number mismatch" when compiling
>> libdecnumber.
>> 
> I've just passed along a similar failure (.i, .s and command line
> options) to Alex for ppc64 (be) building glibc.

This fixes at least the testcase Jeff provided me with.  I'm going ahead
and checking it in as obvious.  I suppose we might need more of these,
on this and other ports, if they have been sloppy about zero-length
pseudo insns :-(

Would you guys please let me know whether you still see a problem, if
you get a chance to respin?  I was just about to crash in bed when I saw
your email.

When I get back up, I'll build the latest binutils release on ppc64,
ppc64el and aarch64, and then bootstrap gcc with it.  I should have done
that when I broadened my testing of the SFN+LVU+IEPM patchset to those 
platforms, but I didn't realize I was failing to test them with an
assembler with view support, doh!  Sorry about that.


for  gcc/ChangeLog

	* config/rs6000/rs6000.md (blockage): Set length to zero.

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 33f0d959f5d0..8aa4e0e7c71e 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -11063,7 +11063,8 @@
 (define_insn "blockage"
   [(unspec_volatile [(const_int 0)] UNSPECV_BLOCK)]
   ""
-  "")
+  ""
+  [(set_attr "length" "0")])
 
 (define_expand "probe_stack_address"
   [(use (match_operand 0 "address_operand"))]


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 10:35                               ` Alexandre Oliva
@ 2018-02-09 12:10                                 ` Alan Modra
  2018-02-09 15:09                                 ` Jeff Law
  1 sibling, 0 replies; 156+ messages in thread
From: Alan Modra @ 2018-02-09 12:10 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jeff Law, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On Fri, Feb 09, 2018 at 08:34:08AM -0200, Alexandre Oliva wrote:
> 	* config/rs6000/rs6000.md (blockage): Set length to zero.

Thanks!  This fixed the ppc64le libdecnumber error for me.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 10:35                               ` Alexandre Oliva
  2018-02-09 12:10                                 ` Alan Modra
@ 2018-02-09 15:09                                 ` Jeff Law
  2018-02-09 22:52                                   ` Joseph Myers
  1 sibling, 1 reply; 156+ messages in thread
From: Jeff Law @ 2018-02-09 15:09 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On 02/09/2018 03:34 AM, Alexandre Oliva wrote:
> On Feb  9, 2018, Jeff Law <law@redhat.com> wrote:
> 
>> On 02/08/2018 08:53 PM, Alan Modra wrote:
>>> On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
>>>> Here's what I checked in, right after the LVU patch.
>>>>
>>>> [IEPM] Introduce inline entry point markers
>>>
>>> One of these two patches breaks ppc64le bootstrap with the assembler
>>> complaining "Error: view number mismatch" when compiling
>>> libdecnumber.
>>>
>> I've just passed along a similar failure (.i, .s and command line
>> options) to Alex for ppc64 (be) building glibc.
> 
> This fixes at least the testcase Jeff provided me with.  I'm going ahead
> and checking it in as obvious.  I suppose we might need more of these,
> on this and other ports, if they have been sloppy about zero-length
> pseudo insns :-(
> 
> Would you guys please let me know whether you still see a problem, if
> you get a chance to respin?  I was just about to crash in bed when I saw
> your email.
> 
> When I get back up, I'll build the latest binutils release on ppc64,
> ppc64el and aarch64, and then bootstrap gcc with it.  I should have done
> that when I broadened my testing of the SFN+LVU+IEPM patchset to those 
> platforms, but I didn't realize I was failing to test them with an
> assembler with view support, doh!  Sorry about that.
No need for the binutils+gcc bootstrapping test when you get up.  Mine's
already run.  ppc, ppc64, ppc64le, aarch64 all covered.

My tester does have half-dozen or so other failures overnight, but I
haven't looked at them yet.  If any look similar I'll first check if
we're dealing with a zero length pseudo insn (I wouldn't be surprised if
blockage insns are consistently wrong on that).


jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09  4:13                             ` Jeff Law
  2018-02-09 10:35                               ` Alexandre Oliva
@ 2018-02-09 21:01                               ` Alexandre Oliva
  2018-02-09 23:49                                 ` Jakub Jelinek
  2018-02-10  4:39                                 ` Alexandre Oliva
  1 sibling, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-09 21:01 UTC (permalink / raw)
  To: Jeff Law
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On Feb  9, 2018, Jeff Law <law@redhat.com> wrote:

> On 02/08/2018 08:53 PM, Alan Modra wrote:
>> On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
>>> Here's what I checked in, right after the LVU patch.
>>> 
>>> [IEPM] Introduce inline entry point markers
>> 
>> One of these two patches breaks ppc64le bootstrap with the assembler
>> complaining "Error: view number mismatch" when compiling
>> libdecnumber.
>> 
> I've just passed along a similar failure (.i, .s and command line
> options) to Alex for ppc64 (be) building glibc.

Thanks.  So, I'm told there are more such issues, that non-asm insn
length attrs can't be relied on at this time to be nonzero only when the
actual length is not zero.  When we fail that and regard a zero-length
insn as nonzero and that's all we have between two subsequent views, the
assembler (GNU as 2.30) will catch and report the error.  With other
assemblers, the incorrect view reset will go unnoticed and result in
incorrect debug info.

So, as discussed on IRC, I'm trying to use a target hook to allow
targets to indicate that their length attrs have been assessed for this
purpose, and a param to make that overridable, but I'm having trouble
initializing the param from the target hook.  How does one do that?

Meanwhile, here's the (WIP) patch that introduces the param defaulting
to no locview optimizations (which can only be performed at points in
which the compiler knows there are PC changes); I'd like it to default
to targetm.attr_length_reliable_for_view_count, but I couldn't figure
out how to do so.  Help?


By disabling it altogether, we won't get the assembler checks or
incorrect view numbers in debug info, but we will get plenty of all-zero
locview lists.  Oh well...  I guess at this point that's better than
wrong debug info or assembler failures.




disable locview optimizations for now

---
 gcc/doc/tm.texi    |   13 +++++++++++++
 gcc/doc/tm.texi.in |    2 ++
 gcc/dwarf2out.c    |    4 +++-
 gcc/opts.c         |    6 ++++++
 gcc/params.def     |    5 +++++
 gcc/target.def     |   13 +++++++++++++
 6 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ddf48cb4b4d2..50fa0d387f32 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9986,6 +9986,19 @@ following it should not be run.  Usually true only for virtual assembler
 targets.
 @end deftypevr
 
+@deftypevr {Target Hook} bool TARGET_ATTR_LENGTH_RELIABLE_FOR_VIEW_COUNT
+TRUE if get_min_attr_length returns
+zero for any non-asm insn that might have length zero, during final.
+It's ok if it's conservative and always returns zero.
+If, in addition to the essential property, when an insn is known to have
+nonzero length, get_min_attr_length returns a positive number, that will
+enable loclist optimizations.  There is little point in making this TRUE
+otherwise.  Enabling this when the essential property is not met while
+using GNU as 2.30 or newer may cause the assembler to detect the errors
+and fail to assemble; other assemblers will silently let the errors
+through, with incorrect view numbers in debug information.
+@end deftypevr
+
 @defmac ASM_OUTPUT_DWARF_DELTA (@var{stream}, @var{size}, @var{label1}, @var{label2})
 A C statement to issue assembly directives that create a difference
 @var{lab1} minus @var{lab2}, using an integer of the given @var{size}.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 0aab45f4992c..26b32db77f74 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -6929,6 +6929,8 @@ tables, and hence is desirable if it works.
 
 @hook TARGET_NO_REGISTER_ALLOCATION
 
+@hook TARGET_ATTR_LENGTH_RELIABLE_FOR_VIEW_COUNT
+
 @defmac ASM_OUTPUT_DWARF_DELTA (@var{stream}, @var{size}, @var{label1}, @var{label2})
 A C statement to issue assembly directives that create a difference
 @var{lab1} minus @var{lab2}, using an integer of the given @var{size}.
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 749c7e3b9bbc..6a6520a05e8b 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -96,6 +96,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "file-prefix-map.h" /* remap_debug_filename()  */
+#include "params.h"
 
 static void dwarf2out_source_line (unsigned int, unsigned int, const char *,
 				   int, bool);
@@ -26926,7 +26927,8 @@ dwarf2out_var_location (rtx_insn *loc_note)
 	       || GET_CODE (loc_note) == ASM_INPUT
 	       || asm_noperands (loc_note) >= 0)
 	;
-      else if (get_attr_min_length (loc_note) > 0)
+      else if (PARAM_VALUE (PARAM_USE_ATTR_LENGTH_IN_VIEW_COUNTING)
+	       && get_attr_min_length (loc_note) > 0)
 	RESET_NEXT_VIEW (cur_line_info_table->view);
 
       return;
diff --git a/gcc/opts.c b/gcc/opts.c
index f2795f98bf44..d4b3065caad6 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1039,6 +1039,12 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if ((opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS) && opts->x_flag_tm)
     sorry ("transactional memory is not supported with "
 	   "%<-fsanitize=kernel-address%>");
+
+#if 0
+  maybe_set_param_value (PARAM_USE_ATTR_LENGTH_IN_VIEW_COUNTING,
+			 targetm.attr_length_reliable_for_view_count,
+			 opts->x_param_values, opts_set->x_param_values);
+#endif
 }
 
 #define LEFT_COLUMN	27
diff --git a/gcc/params.def b/gcc/params.def
index 930b31820be9..184e435c786a 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1331,6 +1331,11 @@ DEFPARAM(PARAM_AVOID_FMA_MAX_BITS,
 	 "Maximum number of bits for which we avoid creating FMAs.",
 	 0, 0, 512)
 
+DEFPARAM(PARAM_USE_ATTR_LENGTH_IN_VIEW_COUNTING,
+	 "use-attr-length-in-view-counting",
+	 "Optimize locview lists based on length attributes.",
+	 0 /* targetm.attr_length_reliable_for_view_count */, 0, 1)
+
 /*
 
 Local variables:
diff --git a/gcc/target.def b/gcc/target.def
index aeb41df19454..6966053157a3 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6631,6 +6631,19 @@ following it should not be run.  Usually true only for virtual assembler\n\
 targets.",
 bool, false)
 
+DEFHOOKPOD
+(attr_length_reliable_for_view_count, "TRUE if get_min_attr_length returns\n\
+zero for any non-asm insn that might have length zero, during final.\n\
+It's ok if it's conservative and always returns zero.\n\
+If, in addition to the essential property, when an insn is known to have\n\
+nonzero length, get_min_attr_length returns a positive number, that will\n\
+enable loclist optimizations.  There is little point in making this TRUE\n\
+otherwise.  Enabling this when the essential property is not met while\n\
+using GNU as 2.30 or newer may cause the assembler to detect the errors\n\
+and fail to assemble; other assemblers will silently let the errors\n\
+through, with incorrect view numbers in debug information.",
+bool, false)
+
 /* Leave the boolean fields at the end.  */
 
 /* Functions related to mode switching.  */


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 15:09                                 ` Jeff Law
@ 2018-02-09 22:52                                   ` Joseph Myers
  2018-02-10  1:36                                     ` Joseph Myers
  0 siblings, 1 reply; 156+ messages in thread
From: Joseph Myers @ 2018-02-09 22:52 UTC (permalink / raw)
  To: Jeff Law
  Cc: Alexandre Oliva, Alan Modra, Jakub Jelinek, Jason Merrill,
	Richard Biener, GCC Patches

I'm seeing regressions from my glibc bot for all of arm, mips, s390 and 
sh.

https://sourceware.org/ml/libc-testresults/2018-q1/msg00283.html

arm and mips are "view number mismatch" building glibc and s390 is the 
same error but building libgcc, so presumably those are the present issue.  
sh is GCC segfaults building glibc, so it's less clearly associated with 
this patch (but GCC mainline r257539 is bad and r257480 is good, in any 
case).

(It's possible more failures might appear on other architectures once the 
bot builds the glibc testsuite, that's just failures from building GCC and 
glibc.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 21:01                               ` Alexandre Oliva
@ 2018-02-09 23:49                                 ` Jakub Jelinek
  2018-02-10  0:56                                   ` Alexandre Oliva
  2018-02-10  4:39                                 ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Jakub Jelinek @ 2018-02-09 23:49 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jeff Law, Alan Modra, Jason Merrill, Richard Biener, GCC Patches

On Fri, Feb 09, 2018 at 07:01:25PM -0200, Alexandre Oliva wrote:
> So, as discussed on IRC, I'm trying to use a target hook to allow
> targets to indicate that their length attrs have been assessed for this
> purpose, and a param to make that overridable, but I'm having trouble
> initializing the param from the target hook.  How does one do that?

Better in the default version of the target hook check the param
whether it should return true or false, and for analyzed targets
just use an always true (or false, depending on what the hook is)
as the hook.

> By disabling it altogether, we won't get the assembler checks or
> incorrect view numbers in debug info, but we will get plenty of all-zero
> locview lists.  Oh well...  I guess at this point that's better than
> wrong debug info or assembler failures.

For the debugging of the target issues, you can also use a hack:
in final.c for instructions that have minimum length longer than zero
emit a label right before emitting the insn and after it:
.Lhacke1:
	.if (.Lhacke1 - .Lhackb1) == 0
	.error "zero length"
	.endif
(or perhaps just:
	.if (. - .Lhack1) == 0
	.error "zero length"
	.endif
), then make check various targets with that.

	Jakub

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 23:49                                 ` Jakub Jelinek
@ 2018-02-10  0:56                                   ` Alexandre Oliva
  2018-02-12  8:08                                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-10  0:56 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jeff Law, Alan Modra, Jason Merrill, Richard Biener, GCC Patches

On Feb  9, 2018, Jakub Jelinek <jakub@redhat.com> wrote:

> On Fri, Feb 09, 2018 at 07:01:25PM -0200, Alexandre Oliva wrote:
>> So, as discussed on IRC, I'm trying to use a target hook to allow
>> targets to indicate that their length attrs have been assessed for this
>> purpose, and a param to make that overridable, but I'm having trouble
>> initializing the param from the target hook.  How does one do that?

> Better in the default version of the target hook check the param
> whether it should return true or false, and for analyzed targets
> just use an always true (or false, depending on what the hook is)
> as the hook.

I want it to be overridable, so here's what I ended up with.
Testing underway; ok to install if it succeeds?


We need accurate length information to be able to optimize away
locviews that would contain only zero-numbered views, and even to
output correct view numbers.  E.g., if we assume an insn has length
nonzero, i.e., that it will advance PC, we conclude the view number
after it is zero.  If the assumption turns out to be false, the
assembler view zero assert will catch the mistake, but only if we're
using a view-capable assembler.  Otherwise, view numbers will silently
go out of sync between the compiler and the assembler, and thus the
debug info consumer.

Unfortunately, a number of targets seem to fail the essential property
for this to work, namely, that get_min_attr_length() be zero for every
insn that might have length zero.

We thus introduce a target hook that indicates whether we can rely on
the length attribute for this purpose, and a param that can be used to
override it, for testing purposes or to work around errors.

for  gcc/ChangeLog

	* params.def (PARAM_USE_ATTR_LENGTH_IN_VIEW_COUNTING): New.
	* target.def (attr_length_reliable_for_view_count): New.
	* dwarf2out.c: Include params.h.
	(unreliable_attr_length_p): New.
	(dwarf2out_var_location): Use it.
	* doc/tm.texi.in (TARGET_ATTR_LENGTH_RELIABLE_FOR_VIEW_COUNT):
	New.
	* doc/tm.texi: Rebuilt.
---
 gcc/doc/tm.texi    |   13 +++++++++++++
 gcc/doc/tm.texi.in |    2 ++
 gcc/dwarf2out.c    |   28 +++++++++++++++++++++++++++-
 gcc/params.def     |    5 +++++
 gcc/target.def     |   14 ++++++++++++++
 5 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ddf48cb4b4d2..50fa0d387f32 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9986,6 +9986,19 @@ following it should not be run.  Usually true only for virtual assembler
 targets.
 @end deftypevr
 
+@deftypevr {Target Hook} bool TARGET_ATTR_LENGTH_RELIABLE_FOR_VIEW_COUNT
+TRUE if get_min_attr_length returns
+zero for any non-asm insn that might have length zero, during final.
+It's ok if it's conservative and always returns zero.
+If, in addition to the essential property, when an insn is known to have
+nonzero length, get_min_attr_length returns a positive number, that will
+enable loclist optimizations.  There is little point in making this TRUE
+otherwise.  Enabling this when the essential property is not met while
+using GNU as 2.30 or newer may cause the assembler to detect the errors
+and fail to assemble; other assemblers will silently let the errors
+through, with incorrect view numbers in debug information.
+@end deftypevr
+
 @defmac ASM_OUTPUT_DWARF_DELTA (@var{stream}, @var{size}, @var{label1}, @var{label2})
 A C statement to issue assembly directives that create a difference
 @var{lab1} minus @var{lab2}, using an integer of the given @var{size}.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 0aab45f4992c..26b32db77f74 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -6929,6 +6929,8 @@ tables, and hence is desirable if it works.
 
 @hook TARGET_NO_REGISTER_ALLOCATION
 
+@hook TARGET_ATTR_LENGTH_RELIABLE_FOR_VIEW_COUNT
+
 @defmac ASM_OUTPUT_DWARF_DELTA (@var{stream}, @var{size}, @var{label1}, @var{label2})
 A C statement to issue assembly directives that create a difference
 @var{lab1} minus @var{lab2}, using an integer of the given @var{size}.
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 749c7e3b9bbc..c48c117c8a16 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -96,6 +96,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "file-prefix-map.h" /* remap_debug_filename()  */
+#include "params.h"
 
 static void dwarf2out_source_line (unsigned int, unsigned int, const char *,
 				   int, bool);
@@ -26860,6 +26861,30 @@ dwarf2out_next_real_insn (rtx_insn *loc_note)
   return next_real;
 }
 
+/* Return TRUE if we should NOT use ATTR_length to optimize locview
+   lists, and FALSE otherwise.
+
+   If ATTR_length is always zero for insns that could have length
+   zero, we can use it, then we'll know when we're guaranteed to have
+   a PC change that implies a view reset.  locview lists whose views
+   are all zero can be optimized out completely.
+
+   However, if we enable these optimizations based on unreliable data,
+   we might get errors from the assembler (binutils 2.30+) when it
+   notices we have incorrectly assumed a view would be zero, or
+   silently get incorrect locview lists otherwise.  */
+
+static bool
+unreliable_attr_length_p (void)
+{
+  int parm = PARAM_VALUE (PARAM_USE_ATTR_LENGTH_IN_VIEW_COUNTING);
+
+  if (parm != -1)
+    return !parm;
+  else
+    return !targetm.attr_length_reliable_for_view_count;
+}
+
 /* 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.  */
@@ -26921,7 +26946,8 @@ dwarf2out_var_location (rtx_insn *loc_note)
 	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
+      else if (unreliable_attr_length_p ()
+	       || GET_CODE (loc_note) == USE
 	       || GET_CODE (loc_note) == CLOBBER
 	       || GET_CODE (loc_note) == ASM_INPUT
 	       || asm_noperands (loc_note) >= 0)
diff --git a/gcc/params.def b/gcc/params.def
index 930b31820be9..12e217ed9da4 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1331,6 +1331,11 @@ DEFPARAM(PARAM_AVOID_FMA_MAX_BITS,
 	 "Maximum number of bits for which we avoid creating FMAs.",
 	 0, 0, 512)
 
+DEFPARAM(PARAM_USE_ATTR_LENGTH_IN_VIEW_COUNTING,
+	 "use-attr-length-in-view-counting",
+	 "Optimize locview lists based on length attributes.",
+	 -1 /* targetm.attr_length_reliable_for_view_count */, 0, 1)
+
 /*
 
 Local variables:
diff --git a/gcc/target.def b/gcc/target.def
index aeb41df19454..a7fedb72fef2 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6631,6 +6631,20 @@ following it should not be run.  Usually true only for virtual assembler\n\
 targets.",
 bool, false)
 
+DEFHOOKPOD
+(attr_length_reliable_for_view_count,
+"True if, during final, get_min_attr_length returns zero\n\
+for all non-asm insns that might have length zero.\n\
+It's ok if it's conservative and always returns zero.\n\
+If, in addition to the essential property, when an insn is known to have\n\
+nonzero length, get_min_attr_length returns a positive number, that will\n\
+enable loclist optimizations.  There is little point in making this true\n\
+otherwise.  Enabling this when the essential property is not met while\n\
+using GNU as 2.30 or newer may cause the assembler to detect the errors\n\
+and fail to assemble; other assemblers will silently let the errors\n\
+through, with incorrect view numbers in debug information.",
+bool, false)
+
 /* Leave the boolean fields at the end.  */
 
 /* Functions related to mode switching.  */


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 22:52                                   ` Joseph Myers
@ 2018-02-10  1:36                                     ` Joseph Myers
  2018-02-10 12:35                                       ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Joseph Myers @ 2018-02-10  1:36 UTC (permalink / raw)
  To: Jeff Law
  Cc: Alexandre Oliva, Alan Modra, Jakub Jelinek, Jason Merrill,
	Richard Biener, GCC Patches

On Fri, 9 Feb 2018, Joseph Myers wrote:

> I'm seeing regressions from my glibc bot for all of arm, mips, s390 and 
> sh.
> 
> https://sourceware.org/ml/libc-testresults/2018-q1/msg00283.html
> 
> arm and mips are "view number mismatch" building glibc and s390 is the 
> same error but building libgcc, so presumably those are the present issue.  
> sh is GCC segfaults building glibc, so it's less clearly associated with 
> this patch (but GCC mainline r257539 is bad and r257480 is good, in any 
> case).

sh4 is:

during RTL pass: final
In file included from strtof_l.c:45:
strtod_l.c: In function '____strtof_l_internal':
strtod_l.c:1769:1: internal compiler error: Segmentation fault
 }
 ^
0xb98e3f crash_signal
        /scratch/jmyers/glibc-bot/src/gcc/gcc/toplev.c:325
0x856b18 maybe_output_next_view
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:1726
0x856b18 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2714
0xef36bc print_slot
        /scratch/jmyers/glibc-bot/src/gcc/gcc/config/sh/sh.c:2557
0xef6520 output_far_jump(rtx_insn*, rtx_def*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/config/sh/sh.c:2617
0x857098 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:3101
0x856c26 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2806
0x858469 final_1
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2088
0x8591d8 rest_of_handle_final
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4637
0x8591d8 execute
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4711

Since it's in maybe_output_next_view, I think it probably comes from these 
patches.

> (It's possible more failures might appear on other architectures once the 
> bot builds the glibc testsuite, that's just failures from building GCC and 
> glibc.)

hppa has a similar ICE building glibc tests, also in 
maybe_output_next_view, so probably also from these patches:

during RTL pass: final
test-tgmath2.c: In function 'test_fma_3':
test-tgmath2.c:421:1: internal compiler error: Segmentation fault
 }
 ^
0xb7525f crash_signal
        /scratch/jmyers/glibc-bot/src/gcc/gcc/toplev.c:325
0x835f14 maybe_output_next_view
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:1726
0x835f14 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2714
0xed7761 pa_output_call(rtx_insn*, rtx_def*, int)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/config/pa/pa.c:8019
0x83642b final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:3101
0x836026 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2806
0x837629 final_1
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2088
0x8389d6 rest_of_handle_final
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4637
0x8389d6 execute
        /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4711

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-09 21:01                               ` Alexandre Oliva
  2018-02-09 23:49                                 ` Jakub Jelinek
@ 2018-02-10  4:39                                 ` Alexandre Oliva
  2018-02-10  6:35                                   ` Jeff Law
  1 sibling, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-10  4:39 UTC (permalink / raw)
  To: Jeff Law
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On Feb  9, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Feb  9, 2018, Jeff Law <law@redhat.com> wrote:
>> On 02/08/2018 08:53 PM, Alan Modra wrote:
>>> On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
>>>> Here's what I checked in, right after the LVU patch.
>>>> 
>>>> [IEPM] Introduce inline entry point markers
>>> 
>>> One of these two patches breaks ppc64le bootstrap with the assembler
>>> complaining "Error: view number mismatch" when compiling
>>> libdecnumber.
>>> 
>> I've just passed along a similar failure (.i, .s and command line
>> options) to Alex for ppc64 (be) building glibc.

> Thanks.  So, I'm told there are more such issues, that non-asm insn
> length attrs can't be relied on at this time to be nonzero only when the
> actual length is not zero.

I wonder...  In the previously-posted patch, we still regard call insns
are advancing PC.  I think that's a safe assumption, but...  are there
any other kinds of patterns we could recognize that would certainly
generate an actual PC-changing insn?  How about jump insns?  How about
insns that are SETs, or PARALLELs containing at least one SET?  Does
anyone see any risk in recognizing those when the length attr is,
conservatively or not, deemed unreliable?  Any other paterns we could
recognize to that end?

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10  4:39                                 ` Alexandre Oliva
@ 2018-02-10  6:35                                   ` Jeff Law
  2018-02-10 13:05                                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2018-02-10  6:35 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On 02/09/2018 09:39 PM, Alexandre Oliva wrote:
> On Feb  9, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
> 
>> On Feb  9, 2018, Jeff Law <law@redhat.com> wrote:
>>> On 02/08/2018 08:53 PM, Alan Modra wrote:
>>>> On Fri, Feb 09, 2018 at 01:21:27AM -0200, Alexandre Oliva wrote:
>>>>> Here's what I checked in, right after the LVU patch.
>>>>>
>>>>> [IEPM] Introduce inline entry point markers
>>>>
>>>> One of these two patches breaks ppc64le bootstrap with the assembler
>>>> complaining "Error: view number mismatch" when compiling
>>>> libdecnumber.
>>>>
>>> I've just passed along a similar failure (.i, .s and command line
>>> options) to Alex for ppc64 (be) building glibc.
> 
>> Thanks.  So, I'm told there are more such issues, that non-asm insn
>> length attrs can't be relied on at this time to be nonzero only when the
>> actual length is not zero.
> 
> I wonder...  In the previously-posted patch, we still regard call insns
> are advancing PC.  I think that's a safe assumption, but...  are there
> any other kinds of patterns we could recognize that would certainly
> generate an actual PC-changing insn?  How about jump insns?  How about
> insns that are SETs, or PARALLELs containing at least one SET?  Does
> anyone see any risk in recognizing those when the length attr is,
> conservatively or not, deemed unreliable?  Any other paterns we could
> recognize to that end?
So given what I've seen in the ARM port, I don't think we can generally
assume any insn advances the PC.

Here's why.

On the ARM there's a little state machine that's used to implement
conditional execution.   When we're in certain states the backend will
generate no code for certain JUMP_INSNs and change the state.

That's fine and dandy.  THe problem is we can't actually tell outside
the ARM backend when that's happened!

You might think we could embed tests of the FSM within the length
computation.  But the state of the FSM is only valid during assembly
output (e.g. final).  But insn lengths are set up during branch
shortening and if you query the length attribute you get value computed
by branch shortening.

The only way around this would be to do what I would consider some
interface abuse and query insn_min_length (not to be confused with
get_attr_min_length).  Then we wouldn't get the cached version and we
could do queries of the state machine on the fly in
dwarf2out_var_location.  But it seems rather icky and I haven't even
been able to convince myself it's really safe.

And while this is specific to the ARM and JUMP_INSNs, I can easily
envision scenarios where other ports could use the same kind of little
state machine for standard INSNs (PA to generate add,tr) or even
CALL_INSNs (target dependent optimization of tail calls).

You also have to worry about ports that try to optimize away nop-insns
that snuck through the optimizers.   I once worked on a port that
couldn't encode a register self copy.  So when one snuck through the
optimizers, we had to deal with it in the output code and I know I've
seen other instances where ports tried to compensate for nop-insns that
snuck through.

So in the end I don't think you can assume that any given insn advances
the PC.  The closest we have is the length attribute, but it has always
supposed to have been conservatively correct for the purposes of branch
shortening.  ie, it can never return a length less than the actual
length, but it is allowed to return a length longer than the actual length.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10  1:36                                     ` Joseph Myers
@ 2018-02-10 12:35                                       ` Alexandre Oliva
  2018-02-10 18:19                                         ` Jeff Law
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-10 12:35 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Jeff Law, Alan Modra, Jakub Jelinek, Jason Merrill,
	Richard Biener, GCC Patches

Hi, Joseph,

On Feb  9, 2018, Joseph Myers <joseph@codesourcery.com> wrote:

> sh4 is:

> during RTL pass: final
> In file included from strtof_l.c:45:
> strtod_l.c: In function '____strtof_l_internal':
> strtod_l.c:1769:1: internal compiler error: Segmentation fault
>  }
>  ^
> 0xb98e3f crash_signal
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/toplev.c:325
> 0x856b18 maybe_output_next_view
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:1726
> 0x856b18 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2714
> 0xef36bc print_slot
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/config/sh/sh.c:2557
> 0xef6520 output_far_jump(rtx_insn*, rtx_def*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/config/sh/sh.c:2617
> 0x857098 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:3101
> 0x856c26 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2806
> 0x858469 final_1
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2088
> 0x8591d8 rest_of_handle_final
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4637
> 0x8591d8 execute
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4711


> Since it's in maybe_output_next_view, I think it probably comes from these 
> patches.

Thanks for the backtraces.  The problem is that ports call
final_scan_insn recursively passing NULL for seen, but now there is code
that actually cares about carrying information around in it.  I decided
against silencing the errors by testing seen for non-NULL before
dereferencing it, and instead arranging for the outermost pointer to be
recovered in recursive calls.  I hope this is enough to cover all the
cases of final_scan_insn being called from ports.  Could you possibly
give it a spin, pretty please with sugar on top? ;-)  Thanks a ton,

(I'll provide a ChangeLog for formal review and hopefully approval once
it has gone through more than my initial smoke testing on x86_64, but my
own testing will take some time, and I wanted to give you something that
at least stood a chance of fixing the problem before crashing in bed :-)


[LVU] deal with md final_scan_insn

From: Alexandre Oliva <aoliva@redhat.com>

Ports call final_scan_insn with seen == NULL, and then
maybe_output_next_view crashes because it assumes it's
non-NULL.  Oops.  Fixed.
---
 gcc/final.c |   34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/gcc/final.c b/gcc/final.c
index c311c198da67..a60be5ddc31c 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -2236,9 +2236,9 @@ asm_show_source (const char *filename, int linenum)
    debug information.  We force the emission of a line note after
    both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG.  */
 
-rtx_insn *
-final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
-		 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
+static rtx_insn *
+final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
+		   int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #if HAVE_cc0
   rtx set;
@@ -3204,6 +3204,34 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
     }
   return NEXT_INSN (insn);
 }
+
+/* This is a wrapper around final_scan_insn_1 that allows ports to
+   call it recursively without a known value for SEEN.  The value is
+   saved at the outermost call, and recovered for recursive calls.  */
+
+rtx_insn *
+final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
+		 int nopeepholes, int *seen)
+{
+  static int *enclosing_seen;
+  static int recursion_counter;
+
+  gcc_assert (seen || recursion_counter);
+  gcc_assert (!recursion_counter || !seen || seen == enclosing_seen);
+
+  if (!recursion_counter++)
+    enclosing_seen = seen;
+  else if (!seen)
+    seen = enclosing_seen;
+
+  rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen);
+  
+  if (!--recursion_counter)
+    enclosing_seen = NULL;
+
+  return ret;
+}
+
 \f
 /* Return whether a source line note needs to be emitted before INSN.
    Sets IS_STMT to TRUE if the line should be marked as a possible




>> (It's possible more failures might appear on other architectures once the 
>> bot builds the glibc testsuite, that's just failures from building GCC and 
>> glibc.)

> hppa has a similar ICE building glibc tests, also in 
> maybe_output_next_view, so probably also from these patches:

> during RTL pass: final
> test-tgmath2.c: In function 'test_fma_3':
> test-tgmath2.c:421:1: internal compiler error: Segmentation fault
>  }
>  ^
> 0xb7525f crash_signal
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/toplev.c:325
> 0x835f14 maybe_output_next_view
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:1726
> 0x835f14 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2714
> 0xed7761 pa_output_call(rtx_insn*, rtx_def*, int)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/config/pa/pa.c:8019
> 0x83642b final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:3101
> 0x836026 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2806
> 0x837629 final_1
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2088
> 0x8389d6 rest_of_handle_final
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4637
> 0x8389d6 execute
>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4711

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10  6:35                                   ` Jeff Law
@ 2018-02-10 13:05                                     ` Alexandre Oliva
  2018-02-10 16:36                                       ` Jeff Law
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-10 13:05 UTC (permalink / raw)
  To: Jeff Law
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On Feb 10, 2018, Jeff Law <law@redhat.com> wrote:

> So given what I've seen in the ARM port, I don't think we can generally
> assume any insn advances the PC.

Ugh.  Thanks, I'll adjust the patch to not count call insns, I guess.

Maybe what we should have is some target hook that, instead of vowing
for ATTR_length (or not), tells us whether an insn might not advance the
PC, with a default that assumes "reasonable" behavior and some more
conservative alternatives for targets that do messy stuff.  I'll give
that some more thought.

> So in the end I don't think you can assume that any given insn advances
> the PC.  The closest we have is the length attribute, but it has always
> supposed to have been conservatively correct for the purposes of branch
> shortening.  ie, it can never return a length less than the actual
> length, but it is allowed to return a length longer than the actual length.

Interesting.  I recall some cases back in my SH days in which I needed
it to be quite precise; I guess this distorted my general expectation.
Oh well...  Back to the drawing board WRT the locview table
optimizations.  Maybe we'll find out my concern about them was
unjustified, and the space they take up is tolerable.  Or maybe we can
find some way to get the most out of them without actually breaking
anything.  We'll see...

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10 13:05                                     ` Alexandre Oliva
@ 2018-02-10 16:36                                       ` Jeff Law
  0 siblings, 0 replies; 156+ messages in thread
From: Jeff Law @ 2018-02-10 16:36 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On 02/10/2018 06:04 AM, Alexandre Oliva wrote:
> On Feb 10, 2018, Jeff Law <law@redhat.com> wrote:
> 
>> So given what I've seen in the ARM port, I don't think we can generally
>> assume any insn advances the PC.
> 
> Ugh.  Thanks, I'll adjust the patch to not count call insns, I guess.
> 
> Maybe what we should have is some target hook that, instead of vowing
> for ATTR_length (or not), tells us whether an insn might not advance the
> PC, with a default that assumes "reasonable" behavior and some more
> conservative alternatives for targets that do messy stuff.  I'll give
> that some more thought.
> 
>> So in the end I don't think you can assume that any given insn advances
>> the PC.  The closest we have is the length attribute, but it has always
>> supposed to have been conservatively correct for the purposes of branch
>> shortening.  ie, it can never return a length less than the actual
>> length, but it is allowed to return a length longer than the actual length.
> 
> Interesting.  I recall some cases back in my SH days in which I needed
> it to be quite precise; I guess this distorted my general expectation.
> Oh well...  Back to the drawing board WRT the locview table
> optimizations.  Maybe we'll find out my concern about them was
> unjustified, and the space they take up is tolerable.  Or maybe we can
> find some way to get the most out of them without actually breaking
> anything.  We'll see...
We have had ports at times try to be very accurate.  You mention the sh,
I also tried for high accuracy on the PA at one time.  I think it was to
support jumps in call delay slots where you have to compute the
difference of two labels.  I eventually gave up and fixed gas :-)  But
the process was still helpful in improving delay slot filling and
instruction scheduling.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10 12:35                                       ` Alexandre Oliva
@ 2018-02-10 18:19                                         ` Jeff Law
  2018-02-11 15:29                                           ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Jeff Law @ 2018-02-10 18:19 UTC (permalink / raw)
  To: Alexandre Oliva, Joseph Myers
  Cc: Alan Modra, Jakub Jelinek, Jason Merrill, Richard Biener, GCC Patches

On 02/10/2018 05:34 AM, Alexandre Oliva wrote:
> Hi, Joseph,
> 
> On Feb  9, 2018, Joseph Myers <joseph@codesourcery.com> wrote:
> 
>> sh4 is:
>> during RTL pass: final
>> In file included from strtof_l.c:45:
>> strtod_l.c: In function '____strtof_l_internal':
>> strtod_l.c:1769:1: internal compiler error: Segmentation fault
>>  }
>>  ^
>> 0xb98e3f crash_signal
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/toplev.c:325
>> 0x856b18 maybe_output_next_view
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:1726
>> 0x856b18 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2714
>> 0xef36bc print_slot
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/config/sh/sh.c:2557
>> 0xef6520 output_far_jump(rtx_insn*, rtx_def*)
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/config/sh/sh.c:2617
>> 0x857098 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:3101
>> 0x856c26 final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*)
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2806
>> 0x858469 final_1
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:2088
>> 0x8591d8 rest_of_handle_final
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4637
>> 0x8591d8 execute
>>         /scratch/jmyers/glibc-bot/src/gcc/gcc/final.c:4711
> 
>> Since it's in maybe_output_next_view, I think it probably comes from these 
>> patches.
> Thanks for the backtraces.  The problem is that ports call
> final_scan_insn recursively passing NULL for seen, but now there is code
> that actually cares about carrying information around in it.  I decided
> against silencing the errors by testing seen for non-NULL before
> dereferencing it, and instead arranging for the outermost pointer to be
> recovered in recursive calls.  I hope this is enough to cover all the
> cases of final_scan_insn being called from ports.  Could you possibly
> give it a spin, pretty please with sugar on top? ;-)  Thanks a ton,
> 
> (I'll provide a ChangeLog for formal review and hopefully approval once
> it has gone through more than my initial smoke testing on x86_64, but my
> own testing will take some time, and I wanted to give you something that
> at least stood a chance of fixing the problem before crashing in bed :-)
> 
> 
> [LVU] deal with md final_scan_insn
> 
> From: Alexandre Oliva <aoliva@redhat.com>
> 
> Ports call final_scan_insn with seen == NULL, and then
> maybe_output_next_view crashes because it assumes it's
> non-NULL.  Oops.  Fixed.
A bit icky.  But OK.

Jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10 18:19                                         ` Jeff Law
@ 2018-02-11 15:29                                           ` Alexandre Oliva
  0 siblings, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-11 15:29 UTC (permalink / raw)
  To: Jeff Law
  Cc: Joseph Myers, Alan Modra, Jakub Jelinek, Jason Merrill,
	Richard Biener, GCC Patches

On Feb 10, 2018, Jeff Law <law@redhat.com> wrote:

>> Ports call final_scan_insn with seen == NULL, and then
>> maybe_output_next_view crashes because it assumes it's
>> non-NULL.  Oops.  Fixed.
> A bit icky.  But OK.

Thanks.  Testing revealed some ports had already introduced their own
'seen' variables passed to final_scan_insn recursive calls, so I
adjusted them, and the comments to the wrapper to indicate ports should
not do that.  Here's what I checked in.


[LVU] deal with md final_scan_insn

Ports call final_scan_insn with seen == NULL, and then
maybe_output_next_view crashes because it assumes it's
non-NULL.  Oops.  Fixed.

for  gcc/ChangeLog

	* final.c (final_scan_insn_1): Renamed from...
	(final_scan_insn): ... this.  New wrapper, to recover
	seen from the outermost call in recursive ones.
	* config/sparc/sparc.c (output_return): Drop seen from call.
	(output_sibcall): Likewise.
	* config/visium/visium.c (output_branch): Likewise.
---
 gcc/config/sparc/sparc.c   |    6 ++----
 gcc/config/visium/visium.c |    3 +--
 gcc/final.c                |   36 +++++++++++++++++++++++++++++++++---
 3 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 48669f177652..7126b57ba011 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -6422,7 +6422,6 @@ output_return (rtx_insn *insn)
 	{
 	  rtx_insn *delay;
 	  rtx pat;
-	  int seen;
 
 	  delay = NEXT_INSN (insn);
 	  gcc_assert (delay);
@@ -6442,7 +6441,7 @@ output_return (rtx_insn *insn)
 		 Make sure to output its source location first.  */
 	      PATTERN (delay) = gen_blockage ();
 	      INSN_CODE (delay) = -1;
-	      final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
+	      final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
 	      INSN_LOCATION (delay) = UNKNOWN_LOCATION;
 
 	      output_restore (pat);
@@ -6503,7 +6502,6 @@ output_sibcall (rtx_insn *insn, rtx call_operand)
 	{
 	  rtx_insn *delay;
 	  rtx pat;
-	  int seen;
 
 	  delay = NEXT_INSN (insn);
 	  gcc_assert (delay);
@@ -6514,7 +6512,7 @@ output_sibcall (rtx_insn *insn, rtx call_operand)
 	     Make sure to output its source location first.  */
 	  PATTERN (delay) = gen_blockage ();
 	  INSN_CODE (delay) = -1;
-	  final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
+	  final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
 	  INSN_LOCATION (delay) = UNKNOWN_LOCATION;
 
 	  output_restore (pat);
diff --git a/gcc/config/visium/visium.c b/gcc/config/visium/visium.c
index 8751156c4065..106cdaf9e3f9 100644
--- a/gcc/config/visium/visium.c
+++ b/gcc/config/visium/visium.c
@@ -3094,10 +3094,9 @@ output_branch (rtx label, const char *cond, rtx_insn *insn)
 	  if (final_sequence)
 	    {
 	      rtx_insn *delay = NEXT_INSN (insn);
-	      int seen;
 	      gcc_assert (delay);
 
-	      final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
+	      final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
 	      PATTERN (delay) = gen_blockage ();
 	      INSN_CODE (delay) = -1;
 	    }
diff --git a/gcc/final.c b/gcc/final.c
index 99a7cadd7c9f..cbebbfdf5b07 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -2236,9 +2236,9 @@ asm_show_source (const char *filename, int linenum)
    debug information.  We force the emission of a line note after
    both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG.  */
 
-rtx_insn *
-final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
-		 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
+static rtx_insn *
+final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
+		   int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #if HAVE_cc0
   rtx set;
@@ -3189,6 +3189,36 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
     }
   return NEXT_INSN (insn);
 }
+
+/* This is a wrapper around final_scan_insn_1 that allows ports to
+   call it recursively without a known value for SEEN.  The value is
+   saved at the outermost call, and recovered for recursive calls.
+   Recursive calls MUST pass NULL, or the same pointer if they can
+   otherwise get to it.  */
+
+rtx_insn *
+final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
+		 int nopeepholes, int *seen)
+{
+  static int *enclosing_seen;
+  static int recursion_counter;
+
+  gcc_assert (seen || recursion_counter);
+  gcc_assert (!recursion_counter || !seen || seen == enclosing_seen);
+
+  if (!recursion_counter++)
+    enclosing_seen = seen;
+  else if (!seen)
+    seen = enclosing_seen;
+
+  rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen);
+
+  if (!--recursion_counter)
+    enclosing_seen = NULL;
+
+  return ret;
+}
+
 \f
 /* Return whether a source line note needs to be emitted before INSN.
    Sets IS_STMT to TRUE if the line should be marked as a possible


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-09  3:20                             ` Alexandre Oliva
@ 2018-02-11 19:04                               ` Andreas Schwab
  2018-02-11 20:47                               ` Andreas Schwab
  1 sibling, 0 replies; 156+ messages in thread
From: Andreas Schwab @ 2018-02-11 19:04 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 09 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> [LVU] Introduce location views
>
> This patch introduces an option to enable the generation of location
> views along with location lists.  The exact format depends on the
> DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or
> (DW_LLE_view_pair) entries in DWARF5+ loclists.

This breaks ia64 bootstrap.  While building the stage3 compiler I get
this error:

/usr/local/gcc/gcc-20180211/Build/./prev-gcc/xg++ -B/usr/local/gcc/gcc-20180211/Build/./prev-gcc/ -B/usr/ia64-suse-linux/bin/ -nostdinc++ -B/usr/local/gcc/gcc-20180211/Build/prev-ia64-suse-linux/libstdc++-v3/src/.libs -B/usr/local/gcc/gcc-20180211/Build/prev-ia64-suse-linux/libstdc++-v3/libsupc++/.libs  -I/usr/local/gcc/gcc-20180211/Build/prev-ia64-suse-linux/libstdc++-v3/include/ia64-suse-linux  -I/usr/local/gcc/gcc-20180211/Build/prev-ia64-suse-linux/libstdc++-v3/include  -I/usr/local/gcc/gcc-20180211/libstdc++-v3/libsupc++ -L/usr/local/gcc/gcc-20180211/Build/prev-ia64-suse-linux/libstdc++-v3/src/.libs -L/usr/local/gcc/gcc-20180211/Build/prev-ia64-suse-linux/libstdc++-v3/libsupc++/.libs -fno-PIE -c  -DUSE_LIBUNWIND_EXCEPTIONS -DIN_GCC_FRONTEND -g -O2 -DIN_GCC     -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -Werror -fno-common  -DHAVE_CONFIG_H -I. -Ilto -I../../gcc -I../../gcc/lto -I../../gcc/../include -I../../gcc/../libcpp/include  -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/dpd -I../libdecnumber -I../../gcc/../libbacktrace   -o lto/lto-lang.o -MT lto/lto-lang.o -MMD -MP -MF lto/.deps/lto-lang.TPo ../../gcc/lto/lto-lang.c
/tmp/cccLpNWi.s: Assembler messages:
/tmp/cccLpNWi.s:1058101: Error: value of 89616 too large for field of 2 bytes at 502338
make[3]: *** [lto/lto-lang.o] Error 1
make[3]: Leaving directory `/usr/local/gcc/gcc-20180211/Build/gcc'
make[2]: *** [all-stage3-gcc] Error 2
make[2]: Leaving directory `/usr/local/gcc/gcc-20180211/Build'
make[1]: *** [stage3-bubble] Error 2
make[1]: Leaving directory `/usr/local/gcc/gcc-20180211/Build'
make: *** [all] Error 2

The erroneous line has "data2.ua .LM78805-.LM78804", where .LM78805
points to the start of a function, and .LM78804 is the last of a long
list of labels (with consecutive numbers) all pointing to the same
address in the middle of an unrelated function.  Also, most of the .LM
labels point to insns in the middle of a bundle without using the
bracket notation.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-09  3:20                             ` Alexandre Oliva
  2018-02-11 19:04                               ` Andreas Schwab
@ 2018-02-11 20:47                               ` Andreas Schwab
  2018-02-12  7:46                                 ` Alexandre Oliva
  2018-02-12  7:49                                 ` Alexandre Oliva
  1 sibling, 2 replies; 156+ messages in thread
From: Andreas Schwab @ 2018-02-11 20:47 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 09 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> @@ -9681,34 +9978,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);

That needs to use ASM_OUTPUT_DEBUG_LABEL.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-11 20:47                               ` Andreas Schwab
@ 2018-02-12  7:46                                 ` Alexandre Oliva
  2018-02-12  7:49                                 ` Alexandre Oliva
  1 sibling, 0 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-12  7:46 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 11, 2018, Andreas Schwab <schwab@linux-m68k.org> wrote:

>> +  if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
>> +    {
>> +      ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);

> That needs to use ASM_OUTPUT_DEBUG_LABEL.

There's another use of the same macro that was already there, right
before the locview block output:

  ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);

Shouldn't it be ASM_OUTPUT_DEBUG_LABEL too?


is fixing these enough to address the problem you reported?

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-11 20:47                               ` Andreas Schwab
  2018-02-12  7:46                                 ` Alexandre Oliva
@ 2018-02-12  7:49                                 ` Alexandre Oliva
  2018-02-12 10:11                                   ` Andreas Schwab
  1 sibling, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-12  7:49 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 11, 2018, Andreas Schwab <schwab@linux-m68k.org> wrote:

> On Feb 09 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

>> +  if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
>> +    {
>> +      ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);

> That needs to use ASM_OUTPUT_DEBUG_LABEL.

Note this is always output in the .debug_loclist section, not in code
sections, so I don't get why it should matter.  Care to clarify, please?

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-10  0:56                                   ` Alexandre Oliva
@ 2018-02-12  8:08                                     ` Alexandre Oliva
  2018-02-13 13:52                                       ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-12  8:08 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jeff Law, Alan Modra, Jason Merrill, Richard Biener, GCC Patches

On Feb  9, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Feb  9, 2018, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Fri, Feb 09, 2018 at 07:01:25PM -0200, Alexandre Oliva wrote:
>>> So, as discussed on IRC, I'm trying to use a target hook to allow
>>> targets to indicate that their length attrs have been assessed for this
>>> purpose, and a param to make that overridable, but I'm having trouble
>>> initializing the param from the target hook.  How does one do that?

>> Better in the default version of the target hook check the param
>> whether it should return true or false, and for analyzed targets
>> just use an always true (or false, depending on what the hook is)
>> as the hook.

> I want it to be overridable, so here's what I ended up with.
> Testing underway; ok to install if it succeeds?

This patch supersedes the previous one.  Testing underway...  Ok if it
succeeds?

Sorry for combining so many not-entirely-related issues in a single
patch, but there would be lots of overlaps and conflicts otherwise, and
in the end they're all about allowing finer-tuning of markers and views,
so I hope tha's ok.  Well, not all: there are formatting fixes to docs
that are totally unrelated, but still overlapping.  Anyway...


[LVU, IEPM] several new controlling options

Given that the minimum insn length is not generally reliable to tell
whether an insn actually advances PC, this patch disables the locview
list optimizations that can only be done when can tell it.

The preexisting logic is retained, however, and can be enabled with
the newly-introduced -ginternal-reset-location-view.  This is now
enabled by default only if the target defines a hook that may override
or defer to the preexisting logic.  The negated command line option
can then be used should errors still be encountered.


We also introduce options to control whether to assume .loc and view
support in the assembler, and to control whether to output inline
entry points (and views) from markers.


This patch also fixes a number of documentation formatting errors,
namely using @item rather than @itemx for all but the first of several
options before a description.

for  gcc/ChangeLog

	* common.opt (gas-loc-support, gas-locview-support): New.
	(ginline-points, ginternal-reset-location-views): New.
	* doc/invoke.texi: Document them.  Use @itemx where intended.
	(gvariable-location-views): Adjust.
	* target.def (reset_location_view): New.
	* doc/tm.texi.in (DWARF2_ASM_VIEW_DEBUG_INFO): New.
	(TARGET_RESET_LOCATION_VIEW): New.
	* doc/tm.texi: Rebuilt.
	* dwarf2out.c (dwarf2out_default_as_loc_support): New.
	(dwarf2out_default_as_locview_support): New.
	(output_asm_line_debug_info): Use option variables.
	(dwarf2out_maybe_output_loclist_view_pair): Likewise.
	(output_loc_list): Likewise.
	(add_high_low_attributes): Check option variables.
	Don't output entry view attribute in strict mode.
	(gen_inlined_subroutine_die): Check option variables.
	(dwarf2out_inline_entry): Likewise.
	(init_sections_and_labels): Likewise.
	(dwarf2out_early_finish): Likewise.
	(maybe_reset_location_view): New, from...
	(dwarf2out_var_location): ... here.  Call it.
	* debug.h (dwarf2out_default_as_loc_support): Declare.
	(dwarf2out_default_as_locview_support): Declare.
	* hooks.c (hook_int_rtx_insn_0): New.
	* hooks.h (hook_int_rtx_insn_0): Declare.
	* toplev.c (process_options): Take -gas-loc-support and
	-gas-locview-support from dwarf2out.  Enable
	-gvariable-location-views by default only with locview
	assembler support.  Enable -ginternal-reset-location-views by
	default only if the target defines the corresponding hook.
	Enable -ginline-points by default if location views are
	enabled; force it disabled if statement frontiers are
	disabled.
	* tree-inline.c (expand_call_inline): Check option variables.
	* tree-ssa-live.c (remove_unused_scope_block_p): Likewise.
---
 gcc/common.opt      |   16 ++++
 gcc/debug.h         |    2 +
 gcc/doc/invoke.texi |  106 +++++++++++++++++++++++------
 gcc/doc/tm.texi     |   23 ++++++
 gcc/doc/tm.texi.in  |    9 ++
 gcc/dwarf2out.c     |  186 +++++++++++++++++++++++++++++++++------------------
 gcc/hooks.c         |    6 ++
 gcc/hooks.h         |    1 
 gcc/target.def      |   17 +++++
 gcc/toplev.c        |   45 +++++++++++-
 gcc/tree-inline.c   |    2 -
 gcc/tree-ssa-live.c |    4 +
 12 files changed, 324 insertions(+), 93 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 40ec0088c57e..e0bc4d1bb18d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2880,6 +2880,14 @@ g
 Common Driver RejectNegative JoinedOrMissing
 Generate debug information in default format.
 
+gas-loc-support
+Common Driver Var(dwarf2out_as_loc_support) Init(2)
+Assume assembler support for (DWARF2+) .loc directives
+
+gas-locview-support
+Common Driver Var(dwarf2out_as_locview_support) Init(2)
+Assume assembler support for view in (DWARF2+) .loc directives
+
 gcoff
 Common Driver Ignore Warn(switch %qs no longer supported)
 Does nothing.  Preserved for backward compatibility.
@@ -2912,6 +2920,14 @@ ggdb
 Common Driver JoinedOrMissing
 Generate debug information in default extended format.
 
+ginline-points
+Common Driver Var(debug_inline_points) Init(2)
+Generate extended entry point information for inlined functions
+
+ginternal-reset-location-views
+Common Driver Var(debug_internal_reset_location_views) Init(2)
+Compute locview reset points based on insn length estimates
+
 gno-
 RejectNegative Joined Undocumented
 ; Catch the gno- prefix, so it doesn't backtrack to g<level>.
diff --git a/gcc/debug.h b/gcc/debug.h
index e1dfe4befaa1..126e56e8c8d7 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -248,6 +248,8 @@ extern bool dwarf2out_do_eh_frame (void);
 extern bool dwarf2out_do_frame (void);
 extern bool dwarf2out_do_cfi_asm (void);
 extern void dwarf2out_switch_text_section (void);
+extern bool dwarf2out_default_as_loc_support (void);
+extern bool dwarf2out_default_as_locview_support (void);
 
 /* For -fdump-go-spec.  */
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index df357bea7dc2..f45577e77b4e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -346,9 +346,13 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-g  -g@var{level}  -gdwarf  -gdwarf-@var{version} @gol
 -ggdb  -grecord-gcc-switches  -gno-record-gcc-switches @gol
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
+-gas-loc-support  -gno-as-loc-support @gol
+-gas-locview-support  -gno-as-locview-support @gol
 -gcolumn-info  -gno-column-info @gol
 -gstatement-frontiers  -gno-statement-frontiers @gol
 -gvariable-location-views  -gno-variable-location-views @gol
+-ginternal-reset-location-views  -gno-internal-reset-location-views @gol
+-ginline-points  -gno-inline-points @gol
 -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
 -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
 -fno-eliminate-unused-debug-types @gol
@@ -4159,7 +4163,7 @@ result in false positives.
 
 @table @gcctabopt
 @item -Wformat-overflow
-@item -Wformat-overflow=1
+@itemx -Wformat-overflow=1
 @opindex Wformat-overflow
 @opindex Wno-format-overflow
 Level @var{1} of @option{-Wformat-overflow} enabled by @option{-Wformat}
@@ -4278,7 +4282,7 @@ logic @option{-Wformat-overflow}.
 
 @table @gcctabopt
 @item -Wformat-truncation
-@item -Wformat-truncation=1
+@itemx -Wformat-truncation=1
 @opindex Wformat-truncation
 @opindex Wno-format-overflow
 Level @var{1} of @option{-Wformat-truncation} enabled by @option{-Wformat}
@@ -5239,7 +5243,7 @@ Option @option{-Wstringop-overflow=2} is enabled by default.
 
 @table @gcctabopt
 @item -Wstringop-overflow
-@item -Wstringop-overflow=1
+@itemx -Wstringop-overflow=1
 @opindex Wstringop-overflow
 @opindex Wno-stringop-overflow
 The @option{-Wstringop-overflow=1} option uses type-zero Object Size Checking
@@ -7214,7 +7218,7 @@ and on some objects @code{.debug_types} produces larger instead of smaller
 debugging information.
 
 @item -grecord-gcc-switches
-@item -gno-record-gcc-switches
+@itemx -gno-record-gcc-switches
 @opindex grecord-gcc-switches
 @opindex gno-record-gcc-switches
 This switch causes the command-line options used to invoke the
@@ -7237,8 +7241,38 @@ DWARF extensions from later standard versions is allowed.
 Allow using extensions of later DWARF standard version than selected with
 @option{-gdwarf-@var{version}}.
 
+@item -gas-loc-support
+@opindex gas-loc-support
+Inform the compiler that the assembler supports @code{.loc} directives.
+It may then use them for the assembler to generate DWARF2+ line number
+tables.
+
+This is generally desirable, because assembler-generated line-number
+tables are a lot more compact than those the compiler can generate
+itself.
+
+This option will be enabled by default if, at GCC configure time, the
+assembler was found to support such directives.
+
+@item -gno-as-loc-support
+@opindex gno-as-loc-support
+Force GCC to generate DWARF2+ line number tables internally, if DWARF2+
+line number tables are to be generated.
+
+@item gas-locview-support
+@opindex gas-locview-support
+Inform the compiler that the assembler supports @code{view} assignment
+and reset assertion checking in @code{.loc} directives.
+
+This option will be enabled by default if, at GCC configure time, the
+assembler was found to support them.
+
+@item gno-as-locview-support
+Force GCC to assign view numbers internally, if
+@option{-gvariable-location-views} are explicitly requested.
+
 @item -gcolumn-info
-@item -gno-column-info
+@itemx -gno-column-info
 @opindex gcolumn-info
 @opindex gno-column-info
 Emit location column information into DWARF debugging information, rather
@@ -7246,7 +7280,7 @@ than just file and line.
 This option is enabled by default.
 
 @item -gstatement-frontiers
-@item -gno-statement-frontiers
+@itemx -gno-statement-frontiers
 @opindex gstatement-frontiers
 @opindex gno-statement-frontiers
 This option causes GCC to create markers in the internal representation
@@ -7257,8 +7291,8 @@ 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 -gvariable-location-views=incompat5
-@item -gno-variable-location-views
+@itemx -gvariable-location-views=incompat5
+@itemx -gno-variable-location-views
 @opindex gvariable-location-views
 @opindex gvariable-location-views=incompat5
 @opindex gno-variable-location-views
@@ -7272,9 +7306,15 @@ 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 @option{-fvar-tracking-assignments} is
-enabled and @option{-gstrict-dwarf} is not.
+the normal level, as long as there is assembler support,
+@option{-fvar-tracking-assignments} is enabled and
+@option{-gstrict-dwarf} is not.  When assembler support is not
+available, this may still be enabled, but it will force GCC to output
+internal line number tables, and if
+@option{-ginternal-reset-location-views} is not enabled, that will most
+certainly lead to silently mismatching location views.
 
 There is a proposed representation for view numbers that is not backward
 compatible with the location list format introduced in DWARF 5, that can
@@ -7284,6 +7324,30 @@ implementation of the proposed representation.  Debug information
 consumers are not expected to support this extended format, and they
 would be rendered unable to decode location lists using it.
 
+@item -ginternal-reset-location-views
+@itemx -gnointernal-reset-location-views
+@opindex ginternal-reset-location-views
+@opindex gno-internal-reset-location-views
+Attempt to determine location views that can be omitted from location
+view lists.  This requires the compiler to have very accurate insn
+length estimates, which isn't always the case, and it may cause
+incorrect view lists to be generated silently when using an assembler
+that does not support location view lists.  The GNU assembler will flag
+any such error as a @code{view number mismatch}.  This is only enabled
+on ports that define a reliable estimation function.
+
+@item -ginline-points
+@itemx -gno-inline-points
+@opindex ginline-points
+@opindex gno-inline-points
+Generate extended debug information for inlined functions.  Location
+view tracking markers are inserted at inlined entry points, so that
+address and view numbers can be computed and output in debug
+information.  This can be enabled independently of location views, in
+which case the view numbers won't be output, but it can only be enabled
+along with statement frontiers, and it is only enabled by default if
+location views are enabled.
+
 @item -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
@@ -10043,7 +10107,7 @@ also use other heuristics to decide whether if-conversion is likely to be
 profitable.
 
 @item max-rtl-if-conversion-predictable-cost
-@item max-rtl-if-conversion-unpredictable-cost
+@itemx max-rtl-if-conversion-unpredictable-cost
 RTL if-conversion will try to remove conditional branches around a block
 and replace them with conditionally executed instructions.  These parameters
 give the maximum permissible cost for the sequence that would be generated
@@ -10767,7 +10831,7 @@ parameters only when their cumulative size is less or equal to
 pointer parameter.
 
 @item sra-max-scalarization-size-Ospeed
-@item sra-max-scalarization-size-Osize
+@itemx sra-max-scalarization-size-Osize
 The two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to
 replace scalar parts of aggregates with uses of independent scalar
 variables.  These parameters control the maximum size, in storage units,
@@ -14544,7 +14608,7 @@ This erratum workaround is made at link time and this will only pass the
 corresponding flag to the linker.
 
 @item -mlow-precision-recip-sqrt
-@item -mno-low-precision-recip-sqrt
+@itemx -mno-low-precision-recip-sqrt
 @opindex mlow-precision-recip-sqrt
 @opindex mno-low-precision-recip-sqrt
 Enable or disable the reciprocal square root approximation.
@@ -14554,7 +14618,7 @@ precision of reciprocal square root results to about 16 bits for
 single precision and to 32 bits for double precision.
 
 @item -mlow-precision-sqrt
-@item -mno-low-precision-sqrt
+@itemx -mno-low-precision-sqrt
 @opindex -mlow-precision-sqrt
 @opindex -mno-low-precision-sqrt
 Enable or disable the square root approximation.
@@ -14565,7 +14629,7 @@ single precision and to 32 bits for double precision.
 If enabled, it implies @option{-mlow-precision-recip-sqrt}.
 
 @item -mlow-precision-div
-@item -mno-low-precision-div
+@itemx -mno-low-precision-div
 @opindex -mlow-precision-div
 @opindex -mno-low-precision-div
 Enable or disable the division approximation.
@@ -20193,7 +20257,7 @@ for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
 @item -minterlink-compressed
-@item -mno-interlink-compressed
+@itemx -mno-interlink-compressed
 @opindex minterlink-compressed
 @opindex mno-interlink-compressed
 Require (do not require) that code using the standard (uncompressed) MIPS ISA
@@ -20774,7 +20838,7 @@ Tell the MIPS assembler to not run its preprocessor over user
 assembler files (with a @samp{.s} suffix) when assembling them.
 
 @item -mfix-24k
-@item -mno-fix-24k
+@itemx -mno-fix-24k
 @opindex mfix-24k
 @opindex mno-fix-24k
 Work around the 24K E48 (lost data on stores during refill) errata.
@@ -21534,7 +21598,7 @@ into the small data or BSS sections instead of the normal data or BSS
 sections.  The default value of @var{num} is 8.
 
 @item -mgpopt=@var{option}
-@item -mgpopt
+@itemx -mgpopt
 @itemx -mno-gpopt
 @opindex mgpopt
 @opindex mno-gpopt
@@ -23093,7 +23157,7 @@ or 32 bits (@option{-m32bit-doubles}) in size.  The default is
 @option{-m32bit-doubles}.
 
 @item -msave-mduc-in-interrupts
-@item -mno-save-mduc-in-interrupts
+@itemx -mno-save-mduc-in-interrupts
 @opindex msave-mduc-in-interrupts
 @opindex mno-save-mduc-in-interrupts
 Specifies that interrupt handler functions should preserve the
@@ -26726,13 +26790,13 @@ comparisons.  These correctly handle the case where the result of a
 comparison is unordered.
 
 @item -m80387
-@item -mhard-float
+@itemx -mhard-float
 @opindex 80387
 @opindex mhard-float
 Generate output containing 80387 instructions for floating point.
 
 @item -mno-80387
-@item -msoft-float
+@itemx -msoft-float
 @opindex no-80387
 @opindex msoft-float
 Generate output containing library calls for floating point.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ddf48cb4b4d2..bd8b917ba829 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9966,6 +9966,29 @@ line debug info sections.  This will result in much more compact line number
 tables, and hence is desirable if it works.
 @end defmac
 
+@defmac DWARF2_ASM_VIEW_DEBUG_INFO
+Define this macro to be a nonzero value if the assembler supports view
+assignment and verification in @code{.loc}.  If it does not, but the
+user enables location views, the compiler may have to fallback to
+internal line number tables.
+@end defmac
+
+@deftypefn {Target Hook} int TARGET_RESET_LOCATION_VIEW (rtx_insn *@var{})
+This hook, if defined, enables -ginternal-reset-location-views, and
+uses its result to override cases in which the estimated min insn
+length might be nonzero even when a PC advance (i.e., a view reset)
+cannot be taken for granted.
+
+If the hook is defined, it must return a positive value to indicate
+the insn definitely advances the PC, and so the view number can be
+safely assumed to be reset; a negative value to mean the insn
+definitely does not advance the PC, and os the view number must not
+be reset; or zero to decide based on the estimated insn length.
+
+If insn length is to be regarded as reliable, set the hook to
+@code{hook_int_rtx_insn_0}.
+@end deftypefn
+
 @deftypevr {Target Hook} bool TARGET_WANT_DEBUG_PUB_SECTIONS
 True if the @code{.debug_pubtypes} and @code{.debug_pubnames} sections should be emitted.  These sections are not used on most platforms, and in particular GDB does not use them.
 @end deftypevr
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 0aab45f4992c..b0207146e8c2 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -6921,6 +6921,15 @@ line debug info sections.  This will result in much more compact line number
 tables, and hence is desirable if it works.
 @end defmac
 
+@defmac DWARF2_ASM_VIEW_DEBUG_INFO
+Define this macro to be a nonzero value if the assembler supports view
+assignment and verification in @code{.loc}.  If it does not, but the
+user enables location views, the compiler may have to fallback to
+internal line number tables.
+@end defmac
+
+@hook TARGET_RESET_LOCATION_VIEW
+
 @hook TARGET_WANT_DEBUG_PUB_SECTIONS
 
 @hook TARGET_DELAY_SCHED2
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 984df9fe4e9a..4e8d40bc91f2 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2957,6 +2957,37 @@ struct GTY(()) dw_line_info_table {
   vec<dw_line_info_entry, va_gc> *entries;
 };
 
+/* If we're keep track of location views and their reset points, and
+   INSN is a reset point (i.e., it necessarily advances the PC), mark
+   the next view in TABLE as reset.  */
+
+static void
+maybe_reset_location_view (rtx_insn *insn, dw_line_info_table *table)
+{
+  if (!debug_internal_reset_location_views)
+    return;
+
+  /* Maybe turn (part of?) this test into a default target hook.  */
+  int reset = 0;
+
+  if (targetm.reset_location_view)
+    reset = targetm.reset_location_view (insn);
+
+  if (reset)
+    ;
+  else if (JUMP_TABLE_DATA_P (insn))
+    reset = 1;
+  else if (GET_CODE (insn) == USE
+	   || GET_CODE (insn) == CLOBBER
+	   || GET_CODE (insn) == ASM_INPUT
+	   || asm_noperands (insn) >= 0)
+    ;
+  else if (get_attr_min_length (insn) > 0)
+    reset = 1;
+
+  if (reset > 0)
+    RESET_NEXT_VIEW (table->view);
+}
 
 /* Each DIE attribute has a field specifying the attribute kind,
    a link to the next attribute in the chain, and an attribute value.
@@ -3164,6 +3195,29 @@ skeleton_chain_node;
 #endif
 #endif
 
+/* Return true if GCC configure detected assembler support for .loc.  */
+
+bool
+dwarf2out_default_as_loc_support (void)
+{
+  return DWARF2_ASM_LINE_DEBUG_INFO;
+#if (GCC_VERSION >= 3000)
+ #pragma GCC poison DWARF2_ASM_LINE_DEBUG_INFO
+#endif
+}
+
+/* Return true if GCC configure detected assembler support for views
+   in .loc directives.  */
+
+bool
+dwarf2out_default_as_locview_support (void)
+{
+  return DWARF2_ASM_VIEW_DEBUG_INFO;
+#if (GCC_VERSION >= 3000)
+ #pragma GCC poison DWARF2_ASM_VIEW_DEBUG_INFO
+#endif
+}
+
 /* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
    view computation, and it refers to a view identifier for which we
    will not emit a label because it is known to map to a view number
@@ -3215,9 +3269,9 @@ static GTY(()) bitmap zero_view_p;
 static bool
 output_asm_line_debug_info (void)
 {
-  return (DWARF2_ASM_VIEW_DEBUG_INFO
-	  || (DWARF2_ASM_LINE_DEBUG_INFO
-	      && !debug_variable_location_views));
+  return (dwarf2out_as_loc_support
+	  && (dwarf2out_as_locview_support
+	      || !debug_variable_location_views));
 }
 
 /* Minimum line offset in a special line info. opcode.
@@ -9950,28 +10004,31 @@ dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr)
 #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
+  if (dwarf2out_as_locview_support)
     {
-      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->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");
+      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
     {
-      char label[MAX_ARTIFICIAL_LABEL_BYTES];
-      ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
-      dw2_asm_output_symname_uleb128 (label, "Location view end");
+      dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
+      dw2_asm_output_data_uleb128 (curr->vend, "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;
@@ -10001,40 +10058,43 @@ output_loc_list (dw_loc_list_ref list_head)
 	  vcount++;
 
 	  /* ?? dwarf_split_debug_info?  */
-#if DWARF2_ASM_VIEW_DEBUG_INFO
-	  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
-	  if (!ZERO_VIEW_P (curr->vbegin))
+	  if (dwarf2out_as_locview_support)
 	    {
-	      ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
-	      dw2_asm_output_symname_uleb128 (label,
-					      "View list begin (%s)",
-					      list_head->vl_symbol);
+	      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
-	    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);
+	      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);
 	    }
-	  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
 	}
     }
 
@@ -23721,11 +23781,14 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
     {
       inline_entry_data *ied = *iedp;
       gcc_assert (MAY_HAVE_DEBUG_MARKER_INSNS);
+      gcc_assert (debug_inline_points);
       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 (debug_variable_location_views && !ZERO_VIEW_P (ied->view)
+	  && !dwarf_strict)
 	{
 	  if (!output_asm_line_debug_info ())
 	    add_AT_unsigned (die, DW_AT_GNU_entry_view, ied->view);
@@ -23756,7 +23819,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
       dw_die_ref pdie;
       dw_attr_node *attr = NULL;
 
-      if (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
+      if (!debug_inline_points && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23921,7 +23984,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
+      if (call_arg_locations || debug_inline_points)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26906,7 +26969,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
     {
       if (CALL_P (loc_note))
 	{
-	  RESET_NEXT_VIEW (cur_line_info_table->view);
+	  maybe_reset_location_view (loc_note, cur_line_info_table);
 	  call_site_count++;
 	  if (SIBLING_CALL_P (loc_note))
 	    tail_call_site_count++;
@@ -26942,15 +27005,8 @@ dwarf2out_var_location (rtx_insn *loc_note)
 	}
       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);
+      else
+	maybe_reset_location_view (loc_note, cur_line_info_table);
 
       return;
     }
@@ -27219,6 +27275,8 @@ block_within_block_p (tree block, tree outer, bool bothways)
 static void
 dwarf2out_inline_entry (tree block)
 {
+  gcc_assert (debug_inline_points);
+
   /* If we can't represent it, don't bother.  */
   if (!(dwarf_version >= 3 || !dwarf_strict))
     return;
@@ -28233,7 +28291,7 @@ init_sections_and_labels (bool early_lto_debug)
       debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
 				       DEBUG_STR_SECTION_FLAGS
 				       | SECTION_EXCLUDE, NULL);
-      if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+      if (!dwarf_split_debug_info && !dwarf2out_as_loc_support)
 	debug_line_str_section
 	  = get_section (DEBUG_LTO_LINE_STR_SECTION,
 			 DEBUG_STR_SECTION_FLAGS | SECTION_EXCLUDE, NULL);
@@ -31468,7 +31526,7 @@ dwarf2out_early_finish (const char *filename)
 
   /* When emitting DWARF5 .debug_line_str, move DW_AT_name and
      DW_AT_comp_dir into .debug_line_str section.  */
-  if (!DWARF2_ASM_LINE_DEBUG_INFO
+  if (!dwarf2out_as_loc_support
       && dwarf_version >= 5
       && DWARF5_USE_DEBUG_LINE_STR)
     {
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 61719606a36d..780cc1e08631 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -235,6 +235,12 @@ hook_int_rtx_1 (rtx)
   return 1;
 }
 
+int
+hook_int_rtx_insn_0 (rtx_insn *)
+{
+  return 0;
+}
+
 int
 hook_int_rtx_insn_unreachable (rtx_insn *)
 {
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 8caedd429a69..0ed5b952b48e 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -93,6 +93,7 @@ extern int hook_int_const_tree_0 (const_tree);
 extern int hook_int_const_tree_const_tree_1 (const_tree, const_tree);
 extern int hook_int_rtx_0 (rtx);
 extern int hook_int_rtx_1 (rtx);
+extern int hook_int_rtx_insn_0 (rtx_insn *);
 extern int hook_int_rtx_insn_unreachable (rtx_insn *);
 extern int hook_int_rtx_bool_0 (rtx, bool);
 extern int hook_int_rtx_mode_as_bool_0 (rtx, machine_mode, addr_space_t,
diff --git a/gcc/target.def b/gcc/target.def
index aeb41df19454..c5b2a1e7e71f 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6447,6 +6447,23 @@ This will suppress generation of the normal debug frame unwind information.",
  enum unwind_info_type, (void),
  default_debug_unwind_info)
 
+DEFHOOK
+(reset_location_view, "\
+This hook, if defined, enables -ginternal-reset-location-views, and\n\
+uses its result to override cases in which the estimated min insn\n\
+length might be nonzero even when a PC advance (i.e., a view reset)\n\
+cannot be taken for granted.\n\
+\n\
+If the hook is defined, it must return a positive value to indicate\n\
+the insn definitely advances the PC, and so the view number can be\n\
+safely assumed to be reset; a negative value to mean the insn\n\
+definitely does not advance the PC, and os the view number must not\n\
+be reset; or zero to decide based on the estimated insn length.\n\
+\n\
+If insn length is to be regarded as reliable, set the hook to\n\
+@code{hook_int_rtx_insn_0}.",
+ int, (rtx_insn *), NULL)
+
 /* The code parameter should be of type enum rtx_code but this is not
    defined at this time.  */
 DEFHOOK
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 23db0636fc79..b066bcc72297 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1558,13 +1558,23 @@ process_options (void)
 	     || write_symbols == VMS_AND_DWARF2_DEBUG)
 	 && !(flag_selective_scheduling || flag_selective_scheduling2));
 
+  if (dwarf2out_as_loc_support == AUTODETECT_VALUE)
+    dwarf2out_as_loc_support
+      = dwarf2out_default_as_loc_support ();
+  if (dwarf2out_as_locview_support == AUTODETECT_VALUE)
+    dwarf2out_as_locview_support
+      = dwarf2out_default_as_locview_support ();
+
   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;
+      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
+	   && dwarf2out_as_loc_support
+	   && dwarf2out_as_locview_support);
     }
   else if (debug_variable_location_views == -1 && dwarf_version != 5)
     {
@@ -1574,6 +1584,31 @@ process_options (void)
       debug_variable_location_views = 1;
     }
 
+  if (debug_internal_reset_location_views == 2)
+    {
+      debug_internal_reset_location_views
+	= (debug_variable_location_views
+	   && targetm.reset_location_view);
+    }
+  else if (debug_internal_reset_location_views
+	   && !debug_variable_location_views)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "-ginternal-reset-location-views is forced disabled "
+		  "without -gvariable-location-views");
+      debug_internal_reset_location_views = 0;
+    }
+
+  if (debug_inline_points == AUTODETECT_VALUE)
+    debug_inline_points = debug_variable_location_views;
+  else if (debug_inline_points && !debug_nonbind_markers_p)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "-ginline-points is forced disabled without "
+		  "-gstatement-frontiers");
+      debug_inline_points = 0;
+    }
+
   if (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 7f9ec770e197..811829e85299 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4605,7 +4605,7 @@ 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
+  if (debug_nonbind_markers_p && debug_inline_points && id->block
       && inlined_function_outer_scope_p (id->block))
     {
       gimple_stmt_iterator si = gsi_last_bb (bb);
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 26da31f74cb2..62bb3c5de659 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -522,7 +522,7 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
      unused = false;
    /* Preserve the block, it is referenced by at least the inline
       entry point marker.  */
-   else if (debug_nonbind_markers_p
+   else if (debug_inline_points
 	    && inlined_function_outer_scope_p (scope))
      unused = false;
    /* Innermost blocks with no live variables nor statements can be always
@@ -558,7 +558,7 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_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
+   else if (!debug_inline_points
 	    && inlined_function_outer_scope_p (scope))
      unused = false;
    else


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-12  7:49                                 ` Alexandre Oliva
@ 2018-02-12 10:11                                   ` Andreas Schwab
  2018-02-13  5:47                                     ` Alexandre Oliva
  0 siblings, 1 reply; 156+ messages in thread
From: Andreas Schwab @ 2018-02-12 10:11 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 12 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Feb 11, 2018, Andreas Schwab <schwab@linux-m68k.org> wrote:
>
>> On Feb 09 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
>
>>> +  if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
>>> +    {
>>> +      ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);
>
>> That needs to use ASM_OUTPUT_DEBUG_LABEL.
>
> Note this is always output in the .debug_loclist section, not in code
> sections, so I don't get why it should matter.  Care to clarify, please?

Perhaps I'm misunderstanding it, but I see .LM labels emitted in the
middle of code bundles, which breaks them apart.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-12 10:11                                   ` Andreas Schwab
@ 2018-02-13  5:47                                     ` Alexandre Oliva
  2018-02-14  9:23                                       ` Andreas Schwab
  0 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-13  5:47 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 12, 2018, Andreas Schwab <schwab@linux-m68k.org> wrote:

> On Feb 12 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
>> On Feb 11, 2018, Andreas Schwab <schwab@linux-m68k.org> wrote:
>> 
>>> On Feb 09 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
>> 
>>>> +  if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
>>>> +    {
>>>> +      ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);
>> 
>>> That needs to use ASM_OUTPUT_DEBUG_LABEL.
>> 
>> Note this is always output in the .debug_loclist section, not in code
>> sections, so I don't get why it should matter.  Care to clarify, please?

> Perhaps I'm misunderstanding it, but I see .LM labels emitted in the
> middle of code bundles, which breaks them apart.

That line would only output .LVUS symbols.

The only line that outputs LM symbols is 

      targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);

It's not ASM_OUTPUT_DEBUG_LABEL, but it was there before.

What may have changed is that, using an assembler without .loc view
support, GCC would switch to internal line number tables, which requires
it to emit LM labels at points in which it would otherwise have output
.loc directives.

The patch I posted last night should work around this problem, in that
it will disable LVU by default if the assembler doesn't support .loc
views, and then you won't get this error any more, unless you explicitly
ask for location views.  If you can give it a try on ia64-linux-gnu,
that would be appreciated.  You might also want to give it a spin with
GNU as 2.30: the assembler view mismatch errors you'd get before that
patch should now be gone too, because we no longer trust min insn
lengths to compute view reset points internally.

If you force that on, with -ginternal-reset-location-views, you'll get
errors in at meast some of the cases in which the assembler finds the
GCC-computed insn length mismatches the assembler's, and then you can
fix the lengths in GCC, so that eventually we can mark this port as one
whose lengths can be used to this end.  See also the reset_location_view
target hook introduced in the same patch.

https://gcc.gnu.org/ml/gcc-patches/2018-02/msg00624.html

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-12  8:08                                     ` Alexandre Oliva
@ 2018-02-13 13:52                                       ` Alexandre Oliva
  2018-02-13 16:15                                         ` Jeff Law
  2018-02-15 15:23                                         ` Szabolcs Nagy
  0 siblings, 2 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-13 13:52 UTC (permalink / raw)
  To: Rainer Orth
  Cc: Jakub Jelinek, Jeff Law, Alan Modra, Jason Merrill,
	Richard Biener, GCC Patches

On Feb 12, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> This patch supersedes the previous one.  Testing underway...  Ok if it
> succeeds?

I failed to update the patch I posted after making a correct to symbol
poisoning, that had caused builds to fail right away, sorry.  Thanks,
Rainer, for catching the error.

Here's the patch that actually passed regstrap on native i686 and
x86_64-linux-gnu, and fixed numerous regressions on cross builds.
Ok to install?


[LVU, IEPM] several new controlling options

Given that the minimum insn length is not generally reliable to tell
whether an insn actually advances PC, this patch disables the locview
list optimizations that can only be done when can tell it.

The preexisting logic is retained, however, and can be enabled with
the newly-introduced -ginternal-reset-location-view.  This is now
enabled by default only if the target defines a hook that may override
or defer to the preexisting logic.  The negated command line option
can then be used should errors still be encountered.


We also introduce options to control whether to assume .loc and view
support in the assembler, and to control whether to output inline
entry points (and views) from markers.


This patch also fixes a number of documentation formatting errors,
namely using @item rather than @itemx for all but the first of several
options before a description.

for  gcc/ChangeLog

	* common.opt (gas-loc-support, gas-locview-support): New.
	(ginline-points, ginternal-reset-location-views): New.
	* doc/invoke.texi: Document them.  Use @itemx where intended.
	(gvariable-location-views): Adjust.
	* target.def (reset_location_view): New.
	* doc/tm.texi.in (DWARF2_ASM_VIEW_DEBUG_INFO): New.
	(TARGET_RESET_LOCATION_VIEW): New.
	* doc/tm.texi: Rebuilt.
	* dwarf2out.c (dwarf2out_default_as_loc_support): New.
	(dwarf2out_default_as_locview_support): New.
	(output_asm_line_debug_info): Use option variables.
	(dwarf2out_maybe_output_loclist_view_pair): Likewise.
	(output_loc_list): Likewise.
	(add_high_low_attributes): Check option variables.
	Don't output entry view attribute in strict mode.
	(gen_inlined_subroutine_die): Check option variables.
	(dwarf2out_inline_entry): Likewise.
	(init_sections_and_labels): Likewise.
	(dwarf2out_early_finish): Likewise.
	(maybe_reset_location_view): New, from...
	(dwarf2out_var_location): ... here.  Call it.
	* debug.h (dwarf2out_default_as_loc_support): Declare.
	(dwarf2out_default_as_locview_support): Declare.
	* hooks.c (hook_int_rtx_insn_0): New.
	* hooks.h (hook_int_rtx_insn_0): Declare.
	* toplev.c (process_options): Take -gas-loc-support and
	-gas-locview-support from dwarf2out.  Enable
	-gvariable-location-views by default only with locview
	assembler support.  Enable -ginternal-reset-location-views by
	default only if the target defines the corresponding hook.
	Enable -ginline-points by default if location views are
	enabled; force it disabled if statement frontiers are
	disabled.
	* tree-inline.c (expand_call_inline): Check option variables.
	* tree-ssa-live.c (remove_unused_scope_block_p): Likewise.
---
 gcc/common.opt      |   16 ++++
 gcc/debug.h         |    2 +
 gcc/doc/invoke.texi |  106 +++++++++++++++++++++++------
 gcc/doc/tm.texi     |   23 ++++++
 gcc/doc/tm.texi.in  |    9 ++
 gcc/dwarf2out.c     |  188 ++++++++++++++++++++++++++++++++++-----------------
 gcc/hooks.c         |    6 ++
 gcc/hooks.h         |    1 
 gcc/target.def      |   17 +++++
 gcc/toplev.c        |   45 +++++++++++-
 gcc/tree-inline.c   |    2 -
 gcc/tree-ssa-live.c |    4 +
 12 files changed, 326 insertions(+), 93 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 40ec0088c57e..e0bc4d1bb18d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2880,6 +2880,14 @@ g
 Common Driver RejectNegative JoinedOrMissing
 Generate debug information in default format.
 
+gas-loc-support
+Common Driver Var(dwarf2out_as_loc_support) Init(2)
+Assume assembler support for (DWARF2+) .loc directives
+
+gas-locview-support
+Common Driver Var(dwarf2out_as_locview_support) Init(2)
+Assume assembler support for view in (DWARF2+) .loc directives
+
 gcoff
 Common Driver Ignore Warn(switch %qs no longer supported)
 Does nothing.  Preserved for backward compatibility.
@@ -2912,6 +2920,14 @@ ggdb
 Common Driver JoinedOrMissing
 Generate debug information in default extended format.
 
+ginline-points
+Common Driver Var(debug_inline_points) Init(2)
+Generate extended entry point information for inlined functions
+
+ginternal-reset-location-views
+Common Driver Var(debug_internal_reset_location_views) Init(2)
+Compute locview reset points based on insn length estimates
+
 gno-
 RejectNegative Joined Undocumented
 ; Catch the gno- prefix, so it doesn't backtrack to g<level>.
diff --git a/gcc/debug.h b/gcc/debug.h
index e1dfe4befaa1..126e56e8c8d7 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -248,6 +248,8 @@ extern bool dwarf2out_do_eh_frame (void);
 extern bool dwarf2out_do_frame (void);
 extern bool dwarf2out_do_cfi_asm (void);
 extern void dwarf2out_switch_text_section (void);
+extern bool dwarf2out_default_as_loc_support (void);
+extern bool dwarf2out_default_as_locview_support (void);
 
 /* For -fdump-go-spec.  */
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9db9d083a475..48194c825f33 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -346,9 +346,13 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-g  -g@var{level}  -gdwarf  -gdwarf-@var{version} @gol
 -ggdb  -grecord-gcc-switches  -gno-record-gcc-switches @gol
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
+-gas-loc-support  -gno-as-loc-support @gol
+-gas-locview-support  -gno-as-locview-support @gol
 -gcolumn-info  -gno-column-info @gol
 -gstatement-frontiers  -gno-statement-frontiers @gol
 -gvariable-location-views  -gno-variable-location-views @gol
+-ginternal-reset-location-views  -gno-internal-reset-location-views @gol
+-ginline-points  -gno-inline-points @gol
 -gvms  -gxcoff  -gxcoff+  -gz@r{[}=@var{type}@r{]} @gol
 -fdebug-prefix-map=@var{old}=@var{new}  -fdebug-types-section @gol
 -fno-eliminate-unused-debug-types @gol
@@ -4159,7 +4163,7 @@ result in false positives.
 
 @table @gcctabopt
 @item -Wformat-overflow
-@item -Wformat-overflow=1
+@itemx -Wformat-overflow=1
 @opindex Wformat-overflow
 @opindex Wno-format-overflow
 Level @var{1} of @option{-Wformat-overflow} enabled by @option{-Wformat}
@@ -4278,7 +4282,7 @@ logic @option{-Wformat-overflow}.
 
 @table @gcctabopt
 @item -Wformat-truncation
-@item -Wformat-truncation=1
+@itemx -Wformat-truncation=1
 @opindex Wformat-truncation
 @opindex Wno-format-overflow
 Level @var{1} of @option{-Wformat-truncation} enabled by @option{-Wformat}
@@ -5239,7 +5243,7 @@ Option @option{-Wstringop-overflow=2} is enabled by default.
 
 @table @gcctabopt
 @item -Wstringop-overflow
-@item -Wstringop-overflow=1
+@itemx -Wstringop-overflow=1
 @opindex Wstringop-overflow
 @opindex Wno-stringop-overflow
 The @option{-Wstringop-overflow=1} option uses type-zero Object Size Checking
@@ -7214,7 +7218,7 @@ and on some objects @code{.debug_types} produces larger instead of smaller
 debugging information.
 
 @item -grecord-gcc-switches
-@item -gno-record-gcc-switches
+@itemx -gno-record-gcc-switches
 @opindex grecord-gcc-switches
 @opindex gno-record-gcc-switches
 This switch causes the command-line options used to invoke the
@@ -7237,8 +7241,38 @@ DWARF extensions from later standard versions is allowed.
 Allow using extensions of later DWARF standard version than selected with
 @option{-gdwarf-@var{version}}.
 
+@item -gas-loc-support
+@opindex gas-loc-support
+Inform the compiler that the assembler supports @code{.loc} directives.
+It may then use them for the assembler to generate DWARF2+ line number
+tables.
+
+This is generally desirable, because assembler-generated line-number
+tables are a lot more compact than those the compiler can generate
+itself.
+
+This option will be enabled by default if, at GCC configure time, the
+assembler was found to support such directives.
+
+@item -gno-as-loc-support
+@opindex gno-as-loc-support
+Force GCC to generate DWARF2+ line number tables internally, if DWARF2+
+line number tables are to be generated.
+
+@item gas-locview-support
+@opindex gas-locview-support
+Inform the compiler that the assembler supports @code{view} assignment
+and reset assertion checking in @code{.loc} directives.
+
+This option will be enabled by default if, at GCC configure time, the
+assembler was found to support them.
+
+@item gno-as-locview-support
+Force GCC to assign view numbers internally, if
+@option{-gvariable-location-views} are explicitly requested.
+
 @item -gcolumn-info
-@item -gno-column-info
+@itemx -gno-column-info
 @opindex gcolumn-info
 @opindex gno-column-info
 Emit location column information into DWARF debugging information, rather
@@ -7246,7 +7280,7 @@ than just file and line.
 This option is enabled by default.
 
 @item -gstatement-frontiers
-@item -gno-statement-frontiers
+@itemx -gno-statement-frontiers
 @opindex gstatement-frontiers
 @opindex gno-statement-frontiers
 This option causes GCC to create markers in the internal representation
@@ -7257,8 +7291,8 @@ 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 -gvariable-location-views=incompat5
-@item -gno-variable-location-views
+@itemx -gvariable-location-views=incompat5
+@itemx -gno-variable-location-views
 @opindex gvariable-location-views
 @opindex gvariable-location-views=incompat5
 @opindex gno-variable-location-views
@@ -7272,9 +7306,15 @@ 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 @option{-fvar-tracking-assignments} is
-enabled and @option{-gstrict-dwarf} is not.
+the normal level, as long as there is assembler support,
+@option{-fvar-tracking-assignments} is enabled and
+@option{-gstrict-dwarf} is not.  When assembler support is not
+available, this may still be enabled, but it will force GCC to output
+internal line number tables, and if
+@option{-ginternal-reset-location-views} is not enabled, that will most
+certainly lead to silently mismatching location views.
 
 There is a proposed representation for view numbers that is not backward
 compatible with the location list format introduced in DWARF 5, that can
@@ -7284,6 +7324,30 @@ implementation of the proposed representation.  Debug information
 consumers are not expected to support this extended format, and they
 would be rendered unable to decode location lists using it.
 
+@item -ginternal-reset-location-views
+@itemx -gnointernal-reset-location-views
+@opindex ginternal-reset-location-views
+@opindex gno-internal-reset-location-views
+Attempt to determine location views that can be omitted from location
+view lists.  This requires the compiler to have very accurate insn
+length estimates, which isn't always the case, and it may cause
+incorrect view lists to be generated silently when using an assembler
+that does not support location view lists.  The GNU assembler will flag
+any such error as a @code{view number mismatch}.  This is only enabled
+on ports that define a reliable estimation function.
+
+@item -ginline-points
+@itemx -gno-inline-points
+@opindex ginline-points
+@opindex gno-inline-points
+Generate extended debug information for inlined functions.  Location
+view tracking markers are inserted at inlined entry points, so that
+address and view numbers can be computed and output in debug
+information.  This can be enabled independently of location views, in
+which case the view numbers won't be output, but it can only be enabled
+along with statement frontiers, and it is only enabled by default if
+location views are enabled.
+
 @item -gz@r{[}=@var{type}@r{]}
 @opindex gz
 Produce compressed debug sections in DWARF format, if that is supported.
@@ -10043,7 +10107,7 @@ also use other heuristics to decide whether if-conversion is likely to be
 profitable.
 
 @item max-rtl-if-conversion-predictable-cost
-@item max-rtl-if-conversion-unpredictable-cost
+@itemx max-rtl-if-conversion-unpredictable-cost
 RTL if-conversion will try to remove conditional branches around a block
 and replace them with conditionally executed instructions.  These parameters
 give the maximum permissible cost for the sequence that would be generated
@@ -10768,7 +10832,7 @@ parameters only when their cumulative size is less or equal to
 pointer parameter.
 
 @item sra-max-scalarization-size-Ospeed
-@item sra-max-scalarization-size-Osize
+@itemx sra-max-scalarization-size-Osize
 The two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to
 replace scalar parts of aggregates with uses of independent scalar
 variables.  These parameters control the maximum size, in storage units,
@@ -14545,7 +14609,7 @@ This erratum workaround is made at link time and this will only pass the
 corresponding flag to the linker.
 
 @item -mlow-precision-recip-sqrt
-@item -mno-low-precision-recip-sqrt
+@itemx -mno-low-precision-recip-sqrt
 @opindex mlow-precision-recip-sqrt
 @opindex mno-low-precision-recip-sqrt
 Enable or disable the reciprocal square root approximation.
@@ -14555,7 +14619,7 @@ precision of reciprocal square root results to about 16 bits for
 single precision and to 32 bits for double precision.
 
 @item -mlow-precision-sqrt
-@item -mno-low-precision-sqrt
+@itemx -mno-low-precision-sqrt
 @opindex -mlow-precision-sqrt
 @opindex -mno-low-precision-sqrt
 Enable or disable the square root approximation.
@@ -14566,7 +14630,7 @@ single precision and to 32 bits for double precision.
 If enabled, it implies @option{-mlow-precision-recip-sqrt}.
 
 @item -mlow-precision-div
-@item -mno-low-precision-div
+@itemx -mno-low-precision-div
 @opindex -mlow-precision-div
 @opindex -mno-low-precision-div
 Enable or disable the division approximation.
@@ -20194,7 +20258,7 @@ for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
 @item -minterlink-compressed
-@item -mno-interlink-compressed
+@itemx -mno-interlink-compressed
 @opindex minterlink-compressed
 @opindex mno-interlink-compressed
 Require (do not require) that code using the standard (uncompressed) MIPS ISA
@@ -20775,7 +20839,7 @@ Tell the MIPS assembler to not run its preprocessor over user
 assembler files (with a @samp{.s} suffix) when assembling them.
 
 @item -mfix-24k
-@item -mno-fix-24k
+@itemx -mno-fix-24k
 @opindex mfix-24k
 @opindex mno-fix-24k
 Work around the 24K E48 (lost data on stores during refill) errata.
@@ -21535,7 +21599,7 @@ into the small data or BSS sections instead of the normal data or BSS
 sections.  The default value of @var{num} is 8.
 
 @item -mgpopt=@var{option}
-@item -mgpopt
+@itemx -mgpopt
 @itemx -mno-gpopt
 @opindex mgpopt
 @opindex mno-gpopt
@@ -23094,7 +23158,7 @@ or 32 bits (@option{-m32bit-doubles}) in size.  The default is
 @option{-m32bit-doubles}.
 
 @item -msave-mduc-in-interrupts
-@item -mno-save-mduc-in-interrupts
+@itemx -mno-save-mduc-in-interrupts
 @opindex msave-mduc-in-interrupts
 @opindex mno-save-mduc-in-interrupts
 Specifies that interrupt handler functions should preserve the
@@ -26727,13 +26791,13 @@ comparisons.  These correctly handle the case where the result of a
 comparison is unordered.
 
 @item -m80387
-@item -mhard-float
+@itemx -mhard-float
 @opindex 80387
 @opindex mhard-float
 Generate output containing 80387 instructions for floating point.
 
 @item -mno-80387
-@item -msoft-float
+@itemx -msoft-float
 @opindex no-80387
 @opindex msoft-float
 Generate output containing library calls for floating point.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ddf48cb4b4d2..bd8b917ba829 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9966,6 +9966,29 @@ line debug info sections.  This will result in much more compact line number
 tables, and hence is desirable if it works.
 @end defmac
 
+@defmac DWARF2_ASM_VIEW_DEBUG_INFO
+Define this macro to be a nonzero value if the assembler supports view
+assignment and verification in @code{.loc}.  If it does not, but the
+user enables location views, the compiler may have to fallback to
+internal line number tables.
+@end defmac
+
+@deftypefn {Target Hook} int TARGET_RESET_LOCATION_VIEW (rtx_insn *@var{})
+This hook, if defined, enables -ginternal-reset-location-views, and
+uses its result to override cases in which the estimated min insn
+length might be nonzero even when a PC advance (i.e., a view reset)
+cannot be taken for granted.
+
+If the hook is defined, it must return a positive value to indicate
+the insn definitely advances the PC, and so the view number can be
+safely assumed to be reset; a negative value to mean the insn
+definitely does not advance the PC, and os the view number must not
+be reset; or zero to decide based on the estimated insn length.
+
+If insn length is to be regarded as reliable, set the hook to
+@code{hook_int_rtx_insn_0}.
+@end deftypefn
+
 @deftypevr {Target Hook} bool TARGET_WANT_DEBUG_PUB_SECTIONS
 True if the @code{.debug_pubtypes} and @code{.debug_pubnames} sections should be emitted.  These sections are not used on most platforms, and in particular GDB does not use them.
 @end deftypevr
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 0aab45f4992c..b0207146e8c2 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -6921,6 +6921,15 @@ line debug info sections.  This will result in much more compact line number
 tables, and hence is desirable if it works.
 @end defmac
 
+@defmac DWARF2_ASM_VIEW_DEBUG_INFO
+Define this macro to be a nonzero value if the assembler supports view
+assignment and verification in @code{.loc}.  If it does not, but the
+user enables location views, the compiler may have to fallback to
+internal line number tables.
+@end defmac
+
+@hook TARGET_RESET_LOCATION_VIEW
+
 @hook TARGET_WANT_DEBUG_PUB_SECTIONS
 
 @hook TARGET_DELAY_SCHED2
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 984df9fe4e9a..4e2bf3b4c88b 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2957,6 +2957,37 @@ struct GTY(()) dw_line_info_table {
   vec<dw_line_info_entry, va_gc> *entries;
 };
 
+/* If we're keep track of location views and their reset points, and
+   INSN is a reset point (i.e., it necessarily advances the PC), mark
+   the next view in TABLE as reset.  */
+
+static void
+maybe_reset_location_view (rtx_insn *insn, dw_line_info_table *table)
+{
+  if (!debug_internal_reset_location_views)
+    return;
+
+  /* Maybe turn (part of?) this test into a default target hook.  */
+  int reset = 0;
+
+  if (targetm.reset_location_view)
+    reset = targetm.reset_location_view (insn);
+
+  if (reset)
+    ;
+  else if (JUMP_TABLE_DATA_P (insn))
+    reset = 1;
+  else if (GET_CODE (insn) == USE
+	   || GET_CODE (insn) == CLOBBER
+	   || GET_CODE (insn) == ASM_INPUT
+	   || asm_noperands (insn) >= 0)
+    ;
+  else if (get_attr_min_length (insn) > 0)
+    reset = 1;
+
+  if (reset > 0)
+    RESET_NEXT_VIEW (table->view);
+}
 
 /* Each DIE attribute has a field specifying the attribute kind,
    a link to the next attribute in the chain, and an attribute value.
@@ -3164,6 +3195,31 @@ skeleton_chain_node;
 #endif
 #endif
 
+/* Return true if GCC configure detected assembler support for .loc.  */
+
+bool
+dwarf2out_default_as_loc_support (void)
+{
+  return DWARF2_ASM_LINE_DEBUG_INFO;
+#if (GCC_VERSION >= 3000)
+# undef DWARF2_ASM_LINE_DEBUG_INFO
+# pragma GCC poison DWARF2_ASM_LINE_DEBUG_INFO
+#endif
+}
+
+/* Return true if GCC configure detected assembler support for views
+   in .loc directives.  */
+
+bool
+dwarf2out_default_as_locview_support (void)
+{
+  return DWARF2_ASM_VIEW_DEBUG_INFO;
+#if (GCC_VERSION >= 3000)
+# undef DWARF2_ASM_VIEW_DEBUG_INFO
+# pragma GCC poison DWARF2_ASM_VIEW_DEBUG_INFO
+#endif
+}
+
 /* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
    view computation, and it refers to a view identifier for which we
    will not emit a label because it is known to map to a view number
@@ -3215,9 +3271,9 @@ static GTY(()) bitmap zero_view_p;
 static bool
 output_asm_line_debug_info (void)
 {
-  return (DWARF2_ASM_VIEW_DEBUG_INFO
-	  || (DWARF2_ASM_LINE_DEBUG_INFO
-	      && !debug_variable_location_views));
+  return (dwarf2out_as_loc_support
+	  && (dwarf2out_as_locview_support
+	      || !debug_variable_location_views));
 }
 
 /* Minimum line offset in a special line info. opcode.
@@ -9950,28 +10006,31 @@ dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr)
 #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
+  if (dwarf2out_as_locview_support)
     {
-      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->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");
+      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
     {
-      char label[MAX_ARTIFICIAL_LABEL_BYTES];
-      ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
-      dw2_asm_output_symname_uleb128 (label, "Location view end");
+      dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
+      dw2_asm_output_data_uleb128 (curr->vend, "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;
@@ -10001,40 +10060,43 @@ output_loc_list (dw_loc_list_ref list_head)
 	  vcount++;
 
 	  /* ?? dwarf_split_debug_info?  */
-#if DWARF2_ASM_VIEW_DEBUG_INFO
-	  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
-	  if (!ZERO_VIEW_P (curr->vbegin))
+	  if (dwarf2out_as_locview_support)
 	    {
-	      ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
-	      dw2_asm_output_symname_uleb128 (label,
-					      "View list begin (%s)",
-					      list_head->vl_symbol);
+	      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
-	    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);
+	      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);
 	    }
-	  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
 	}
     }
 
@@ -23721,11 +23783,14 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
     {
       inline_entry_data *ied = *iedp;
       gcc_assert (MAY_HAVE_DEBUG_MARKER_INSNS);
+      gcc_assert (debug_inline_points);
       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 (debug_variable_location_views && !ZERO_VIEW_P (ied->view)
+	  && !dwarf_strict)
 	{
 	  if (!output_asm_line_debug_info ())
 	    add_AT_unsigned (die, DW_AT_GNU_entry_view, ied->view);
@@ -23756,7 +23821,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
       dw_die_ref pdie;
       dw_attr_node *attr = NULL;
 
-      if (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
+      if (!debug_inline_points && inlined_function_outer_scope_p (stmt))
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
@@ -23921,7 +23986,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 || MAY_HAVE_DEBUG_MARKER_INSNS)
+      if (call_arg_locations || debug_inline_points)
 	BLOCK_DIE (stmt) = subr_die;
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
@@ -26906,7 +26971,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
     {
       if (CALL_P (loc_note))
 	{
-	  RESET_NEXT_VIEW (cur_line_info_table->view);
+	  maybe_reset_location_view (loc_note, cur_line_info_table);
 	  call_site_count++;
 	  if (SIBLING_CALL_P (loc_note))
 	    tail_call_site_count++;
@@ -26942,15 +27007,8 @@ dwarf2out_var_location (rtx_insn *loc_note)
 	}
       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);
+      else
+	maybe_reset_location_view (loc_note, cur_line_info_table);
 
       return;
     }
@@ -27219,6 +27277,8 @@ block_within_block_p (tree block, tree outer, bool bothways)
 static void
 dwarf2out_inline_entry (tree block)
 {
+  gcc_assert (debug_inline_points);
+
   /* If we can't represent it, don't bother.  */
   if (!(dwarf_version >= 3 || !dwarf_strict))
     return;
@@ -28233,7 +28293,7 @@ init_sections_and_labels (bool early_lto_debug)
       debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
 				       DEBUG_STR_SECTION_FLAGS
 				       | SECTION_EXCLUDE, NULL);
-      if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+      if (!dwarf_split_debug_info && !dwarf2out_as_loc_support)
 	debug_line_str_section
 	  = get_section (DEBUG_LTO_LINE_STR_SECTION,
 			 DEBUG_STR_SECTION_FLAGS | SECTION_EXCLUDE, NULL);
@@ -31468,7 +31528,7 @@ dwarf2out_early_finish (const char *filename)
 
   /* When emitting DWARF5 .debug_line_str, move DW_AT_name and
      DW_AT_comp_dir into .debug_line_str section.  */
-  if (!DWARF2_ASM_LINE_DEBUG_INFO
+  if (!dwarf2out_as_loc_support
       && dwarf_version >= 5
       && DWARF5_USE_DEBUG_LINE_STR)
     {
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 61719606a36d..780cc1e08631 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -235,6 +235,12 @@ hook_int_rtx_1 (rtx)
   return 1;
 }
 
+int
+hook_int_rtx_insn_0 (rtx_insn *)
+{
+  return 0;
+}
+
 int
 hook_int_rtx_insn_unreachable (rtx_insn *)
 {
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 8caedd429a69..0ed5b952b48e 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -93,6 +93,7 @@ extern int hook_int_const_tree_0 (const_tree);
 extern int hook_int_const_tree_const_tree_1 (const_tree, const_tree);
 extern int hook_int_rtx_0 (rtx);
 extern int hook_int_rtx_1 (rtx);
+extern int hook_int_rtx_insn_0 (rtx_insn *);
 extern int hook_int_rtx_insn_unreachable (rtx_insn *);
 extern int hook_int_rtx_bool_0 (rtx, bool);
 extern int hook_int_rtx_mode_as_bool_0 (rtx, machine_mode, addr_space_t,
diff --git a/gcc/target.def b/gcc/target.def
index aeb41df19454..c5b2a1e7e71f 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6447,6 +6447,23 @@ This will suppress generation of the normal debug frame unwind information.",
  enum unwind_info_type, (void),
  default_debug_unwind_info)
 
+DEFHOOK
+(reset_location_view, "\
+This hook, if defined, enables -ginternal-reset-location-views, and\n\
+uses its result to override cases in which the estimated min insn\n\
+length might be nonzero even when a PC advance (i.e., a view reset)\n\
+cannot be taken for granted.\n\
+\n\
+If the hook is defined, it must return a positive value to indicate\n\
+the insn definitely advances the PC, and so the view number can be\n\
+safely assumed to be reset; a negative value to mean the insn\n\
+definitely does not advance the PC, and os the view number must not\n\
+be reset; or zero to decide based on the estimated insn length.\n\
+\n\
+If insn length is to be regarded as reliable, set the hook to\n\
+@code{hook_int_rtx_insn_0}.",
+ int, (rtx_insn *), NULL)
+
 /* The code parameter should be of type enum rtx_code but this is not
    defined at this time.  */
 DEFHOOK
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 23db0636fc79..b066bcc72297 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1558,13 +1558,23 @@ process_options (void)
 	     || write_symbols == VMS_AND_DWARF2_DEBUG)
 	 && !(flag_selective_scheduling || flag_selective_scheduling2));
 
+  if (dwarf2out_as_loc_support == AUTODETECT_VALUE)
+    dwarf2out_as_loc_support
+      = dwarf2out_default_as_loc_support ();
+  if (dwarf2out_as_locview_support == AUTODETECT_VALUE)
+    dwarf2out_as_locview_support
+      = dwarf2out_default_as_locview_support ();
+
   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;
+      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
+	   && dwarf2out_as_loc_support
+	   && dwarf2out_as_locview_support);
     }
   else if (debug_variable_location_views == -1 && dwarf_version != 5)
     {
@@ -1574,6 +1584,31 @@ process_options (void)
       debug_variable_location_views = 1;
     }
 
+  if (debug_internal_reset_location_views == 2)
+    {
+      debug_internal_reset_location_views
+	= (debug_variable_location_views
+	   && targetm.reset_location_view);
+    }
+  else if (debug_internal_reset_location_views
+	   && !debug_variable_location_views)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "-ginternal-reset-location-views is forced disabled "
+		  "without -gvariable-location-views");
+      debug_internal_reset_location_views = 0;
+    }
+
+  if (debug_inline_points == AUTODETECT_VALUE)
+    debug_inline_points = debug_variable_location_views;
+  else if (debug_inline_points && !debug_nonbind_markers_p)
+    {
+      warning_at (UNKNOWN_LOCATION, 0,
+		  "-ginline-points is forced disabled without "
+		  "-gstatement-frontiers");
+      debug_inline_points = 0;
+    }
+
   if (flag_tree_cselim == AUTODETECT_VALUE)
     {
       if (HAVE_conditional_move)
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 7f9ec770e197..811829e85299 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4605,7 +4605,7 @@ 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
+  if (debug_nonbind_markers_p && debug_inline_points && id->block
       && inlined_function_outer_scope_p (id->block))
     {
       gimple_stmt_iterator si = gsi_last_bb (bb);
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 26da31f74cb2..62bb3c5de659 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -522,7 +522,7 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
      unused = false;
    /* Preserve the block, it is referenced by at least the inline
       entry point marker.  */
-   else if (debug_nonbind_markers_p
+   else if (debug_inline_points
 	    && inlined_function_outer_scope_p (scope))
      unused = false;
    /* Innermost blocks with no live variables nor statements can be always
@@ -558,7 +558,7 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_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
+   else if (!debug_inline_points
 	    && inlined_function_outer_scope_p (scope))
      unused = false;
    else

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-13 13:52                                       ` Alexandre Oliva
@ 2018-02-13 16:15                                         ` Jeff Law
  2018-02-15 15:23                                         ` Szabolcs Nagy
  1 sibling, 0 replies; 156+ messages in thread
From: Jeff Law @ 2018-02-13 16:15 UTC (permalink / raw)
  To: Alexandre Oliva, Rainer Orth
  Cc: Jakub Jelinek, Alan Modra, Jason Merrill, Richard Biener, GCC Patches

On 02/13/2018 06:43 AM, Alexandre Oliva wrote:
> On Feb 12, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
> 
>> This patch supersedes the previous one.  Testing underway...  Ok if it
>> succeeds?
> 
> I failed to update the patch I posted after making a correct to symbol
> poisoning, that had caused builds to fail right away, sorry.  Thanks,
> Rainer, for catching the error.
> 
> Here's the patch that actually passed regstrap on native i686 and
> x86_64-linux-gnu, and fixed numerous regressions on cross builds.
> Ok to install?
> 
> 
> [LVU, IEPM] several new controlling options
> 
> Given that the minimum insn length is not generally reliable to tell
> whether an insn actually advances PC, this patch disables the locview
> list optimizations that can only be done when can tell it.
> 
> The preexisting logic is retained, however, and can be enabled with
> the newly-introduced -ginternal-reset-location-view.  This is now
> enabled by default only if the target defines a hook that may override
> or defer to the preexisting logic.  The negated command line option
> can then be used should errors still be encountered.
> 
> 
> We also introduce options to control whether to assume .loc and view
> support in the assembler, and to control whether to output inline
> entry points (and views) from markers.
> 
> 
> This patch also fixes a number of documentation formatting errors,
> namely using @item rather than @itemx for all but the first of several
> options before a description.
> 
> for  gcc/ChangeLog
> 
> 	* common.opt (gas-loc-support, gas-locview-support): New.
> 	(ginline-points, ginternal-reset-location-views): New.
> 	* doc/invoke.texi: Document them.  Use @itemx where intended.
> 	(gvariable-location-views): Adjust.
> 	* target.def (reset_location_view): New.
> 	* doc/tm.texi.in (DWARF2_ASM_VIEW_DEBUG_INFO): New.
> 	(TARGET_RESET_LOCATION_VIEW): New.
> 	* doc/tm.texi: Rebuilt.
> 	* dwarf2out.c (dwarf2out_default_as_loc_support): New.
> 	(dwarf2out_default_as_locview_support): New.
> 	(output_asm_line_debug_info): Use option variables.
> 	(dwarf2out_maybe_output_loclist_view_pair): Likewise.
> 	(output_loc_list): Likewise.
> 	(add_high_low_attributes): Check option variables.
> 	Don't output entry view attribute in strict mode.
> 	(gen_inlined_subroutine_die): Check option variables.
> 	(dwarf2out_inline_entry): Likewise.
> 	(init_sections_and_labels): Likewise.
> 	(dwarf2out_early_finish): Likewise.
> 	(maybe_reset_location_view): New, from...
> 	(dwarf2out_var_location): ... here.  Call it.
> 	* debug.h (dwarf2out_default_as_loc_support): Declare.
> 	(dwarf2out_default_as_locview_support): Declare.
> 	* hooks.c (hook_int_rtx_insn_0): New.
> 	* hooks.h (hook_int_rtx_insn_0): Declare.
> 	* toplev.c (process_options): Take -gas-loc-support and
> 	-gas-locview-support from dwarf2out.  Enable
> 	-gvariable-location-views by default only with locview
> 	assembler support.  Enable -ginternal-reset-location-views by
> 	default only if the target defines the corresponding hook.
> 	Enable -ginline-points by default if location views are
> 	enabled; force it disabled if statement frontiers are
> 	disabled.
> 	* tree-inline.c (expand_call_inline): Check option variables.
> 	* tree-ssa-live.c (remove_unused_scope_block_p): Likewise.
OK.  I probably would have gone with the initial version or something
closer to that -- this seems to have expanded in scope a bit.  But it's
not enough to object to since the scope creep is really just giving
options to turn on/off the various bits for testing purposes.

I plan to commit it momentarily given the number of targets that are
failing in my tester due to this issue.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views
  2018-02-13  5:47                                     ` Alexandre Oliva
@ 2018-02-14  9:23                                       ` Andreas Schwab
  0 siblings, 0 replies; 156+ messages in thread
From: Andreas Schwab @ 2018-02-14  9:23 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Jason Merrill, Jeff Law, Richard Biener, Jakub Jelinek, gcc-patches

On Feb 13 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> The patch I posted last night should work around this problem, in that
> it will disable LVU by default if the assembler doesn't support .loc
> views, and then you won't get this error any more, unless you explicitly
> ask for location views.  If you can give it a try on ia64-linux-gnu,
> that would be appreciated.

That fixes the build failure on ia64.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-13 13:52                                       ` Alexandre Oliva
  2018-02-13 16:15                                         ` Jeff Law
@ 2018-02-15 15:23                                         ` Szabolcs Nagy
  2018-02-21 10:12                                           ` Alexandre Oliva
  1 sibling, 1 reply; 156+ messages in thread
From: Szabolcs Nagy @ 2018-02-15 15:23 UTC (permalink / raw)
  To: Alexandre Oliva, Rainer Orth
  Cc: nd, Jakub Jelinek, Jeff Law, Alan Modra, Jason Merrill,
	Richard Biener, GCC Patches

On 13/02/18 13:43, Alexandre Oliva wrote:
> On Feb 12, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
> 
>> This patch supersedes the previous one.  Testing underway...  Ok if it
>> succeeds?
> 
> I failed to update the patch I posted after making a correct to symbol
> poisoning, that had caused builds to fail right away, sorry.  Thanks,
> Rainer, for catching the error.
> 
> Here's the patch that actually passed regstrap on native i686 and
> x86_64-linux-gnu, and fixed numerous regressions on cross builds.
> Ok to install?
> 
> 
> [LVU, IEPM] several new controlling options
> 
> Given that the minimum insn length is not generally reliable to tell
> whether an insn actually advances PC, this patch disables the locview
> list optimizations that can only be done when can tell it.
> 
> The preexisting logic is retained, however, and can be enabled with
> the newly-introduced -ginternal-reset-location-view.  This is now
> enabled by default only if the target defines a hook that may override
> or defer to the preexisting logic.  The negated command line option
> can then be used should errors still be encountered.
> 
> 
> We also introduce options to control whether to assume .loc and view
> support in the assembler, and to control whether to output inline
> entry points (and views) from markers.
> 

i see assembler slow downs with these location view patches
i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-15 15:23                                         ` Szabolcs Nagy
@ 2018-02-21 10:12                                           ` Alexandre Oliva
  2018-02-21 12:08                                             ` Uros Bizjak
                                                               ` (3 more replies)
  0 siblings, 4 replies; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-21 10:12 UTC (permalink / raw)
  To: Szabolcs Nagy, Uros Bizjak
  Cc: Rainer Orth, nd, Jakub Jelinek, Jeff Law, Alan Modra,
	Jason Merrill, Richard Biener, GCC Patches

On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

> i see assembler slow downs with these location view patches
> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408


[LVU] reset view at function entry, omit views at line zero

Location views might be associated with locations that lack line
number information (line number zero), but since we omit .loc
directives that would have been issued with line number zero, we also
omit the symbolic view numbers that would have been issued at such
points.

Resetting views at function entry points address some of these issues,
and alleviate the huge chains of symbolic views that have burdened
assemblers since we disabled -ginternal-reset-location-views by
default, but other problems of undefined views remain when it's not
the whole function that lacks line number info, just parts of it.

So, when we encounter a request to output a view that may have been
referenced, but we decide to omit the .loc because the line is zero,
we will now omit the view as well, i.e., we will internally regard
that view as zero-numbered.

Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?

Uros, could you please confirm whether this fixes the 84404 go problem
you reported on alpha?  I'm guessing it's the same issue.  TIA,

for  gcc/ChangeLog

	PR debug/84404
	PR debug/84408
	* dwarf2out.c (struct dw_line_info_table): Update comments for
	view == -1.
	(FORCE_RESET_NEXT_VIEW): New.
	(FORCE_RESETTING_VIEW_P): New.
	(RESETTING_VIEW_P): Check for -1 too.
	(ZERO_VIEW_P): Likewise.
	(new_line_info_table): Force-reset next view.
	(dwarf2out_begin_function): Likewise.
	(dwarf2out_source_line): Simplify zero_view_p initialization.
	Test FORCE_RESETTING_VIEW_P and RESETTING_VIEW_P instead of
	view directly.  Omit view when omitting .loc at line 0.

for  gcc/testsuite/ChangeLog

	PR debug/84404
	PR debug/84408
	* gcc.dg/graphite/pr84404.c: New.
---
 gcc/dwarf2out.c                         |   89 ++++++++++++++++++++++++-------
 gcc/testsuite/gcc.dg/graphite/pr84404.c |   18 ++++++
 2 files changed, 87 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/graphite/pr84404.c

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5e88c7bacf06..7bbe20e495ac 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2940,8 +2940,8 @@ struct GTY(()) dw_line_info_table {
      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.
+     If it is -1, we're forcing the view number to be reset, e.g. at a
+     function entry.
 
      The meaning of other nonzero values depends on whether we're
      computing views internally or leaving it for the assembler to do
@@ -2951,8 +2951,10 @@ struct GTY(()) dw_line_info_table {
      going to ask the assembler to assign.  */
   var_loc_view view;
 
+#define FORCE_RESET_NEXT_VIEW(x) ((x) = (var_loc_view)-1)
 #define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
-#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
+#define FORCE_RESETTING_VIEW_P(x) ((x) == (var_loc_view)-1)
+#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0 || FORCE_RESETTING_VIEW_P (x))
 
   vec<dw_line_info_entry, va_gc> *entries;
 };
@@ -2985,7 +2987,7 @@ maybe_reset_location_view (rtx_insn *insn, dw_line_info_table *table)
   else if (get_attr_min_length (insn) > 0)
     reset = 1;
 
-  if (reset > 0)
+  if (reset > 0 && !RESETTING_VIEW_P (table->view))
     RESET_NEXT_VIEW (table->view);
 }
 
@@ -3235,9 +3237,10 @@ static GTY(()) bitmap zero_view_p;
    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)
+#define ZERO_VIEW_P(N) ((N) == (var_loc_view)0				\
+			|| (N) == (var_loc_view)-1			\
+			|| (zero_view_p					\
+			    && bitmap_bit_p (zero_view_p, (N))))
 
 /* Return true iff we're to emit .loc directives for the assembler to
    generate line number sections.
@@ -27210,6 +27213,18 @@ create_label:
 	  last_postcall_label = ggc_strdup (loclabel);
 	}
       newloc->label = last_postcall_label;
+      /* ??? This view is at last_label, not last_label-1, but we
+	 could only assume view at last_label-1 is zero if we could
+	 assume calls always have length greater than one.  This is
+	 probably true in general, though there might be a rare
+	 exception to this rule, e.g. if a call insn is optimized out
+	 by target magic.  Then, even the -1 in the label will be
+	 wrong, which might invalidate the range.  Anyway, using view,
+	 though technically possibly incorrect, will work as far as
+	 ranges go: since L-1 is in the middle of the call insn,
+	 (L-1).0 and (L-1).V shouldn't make any difference, and having
+	 the loclist entry refer to the .loc entry might be useful, so
+	 leave it like this.  */
       newloc->view = view;
     }
 
@@ -27391,7 +27406,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);
+  FORCE_RESET_NEXT_VIEW (table->view);
 
   return table;
 }
@@ -27475,6 +27490,7 @@ dwarf2out_begin_function (tree fun)
   tail_call_site_count = 0;
 
   set_cur_line_info_table (sec);
+  FORCE_RESET_NEXT_VIEW (cur_line_info_table->view);
 }
 
 /* Helper function of dwarf2out_end_function, called only after emitting
@@ -27572,10 +27588,44 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
 {
   unsigned int file_num;
   dw_line_info_table *table;
+  static var_loc_view lvugid;
 
-  if (debug_info_level < DINFO_LEVEL_TERSE || line == 0)
+  if (debug_info_level < DINFO_LEVEL_TERSE)
     return;
 
+  table = cur_line_info_table;
+
+  if (line == 0)
+    {
+      if (debug_variable_location_views
+	  && output_asm_line_debug_info ()
+	  && table && !RESETTING_VIEW_P (table->view))
+	{
+	  /* If we're using the assembler to compute view numbers, we
+	     can't issue a .loc directive for line zero, so we can't
+	     get a view number at this point.  We might attempt to
+	     compute it from the previous view, but since we're
+	     omitting the line number entry, we might as well omit the
+	     view number as well.  That means pretending it's a view
+	     number zero, which might very well turn out to be
+	     correct.  */
+	  if (!zero_view_p)
+	    zero_view_p = BITMAP_GGC_ALLOC ();
+	  bitmap_set_bit (zero_view_p, table->view);
+	  if (flag_debug_asm)
+	    {
+	      char label[MAX_ARTIFICIAL_LABEL_BYTES];
+	      ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
+	      fprintf (asm_out_file, "\t%s line 0, omitted view ",
+		       ASM_COMMENT_START);
+	      assemble_name (asm_out_file, label);
+	      putc ('\n', asm_out_file);
+	    }
+	  table->view = ++lvugid;
+	}
+      return;
+    }
+
   /* The discriminator column was added in dwarf4.  Simplify the below
      by simply removing it if we're not supposed to output it.  */
   if (dwarf_version < 4 && dwarf_strict)
@@ -27584,7 +27634,6 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
   if (!debug_column_info)
     column = 0;
 
-  table = cur_line_info_table;
   file_num = maybe_emit_file (lookup_filename (filename));
 
   /* ??? TODO: Elide duplicate line number entries.  Traditionally,
@@ -27646,13 +27695,6 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
 	}
       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))
 	    {
 	      /* When we're using the assembler to compute view
@@ -27673,7 +27715,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
 	    }
 	  else
 	    {
-	      if (!table->in_use)
+	      if (FORCE_RESETTING_VIEW_P (table->view))
 		fputs (" view -0", asm_out_file);
 	      else
 		fputs (" view 0", asm_out_file);
@@ -27684,6 +27726,8 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
 		 known to be zero, because then we may be able to
 		 optimize out locviews that are all zeros, so take
 		 note of it in zero_view_p.  */
+	      if (!zero_view_p)
+		zero_view_p = BITMAP_GGC_ALLOC ();
 	      bitmap_set_bit (zero_view_p, lvugid);
 	      table->view = ++lvugid;
 	    }
@@ -27696,17 +27740,22 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
 
       targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
 
-      if (debug_variable_location_views && table->view)
+      if (debug_variable_location_views && !RESETTING_VIEW_P (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)
 	{
+	  bool resetting = FORCE_RESETTING_VIEW_P (table->view);
+	  if (resetting)
+	    table->view = 0;
+
 	  if (flag_debug_asm)
 	    fprintf (asm_out_file, "\t%s view %s%d\n",
 		     ASM_COMMENT_START,
-		     table->in_use ? "" : "-",
+		     resetting ? "-" : "",
 		     table->view);
+
 	  table->view++;
 	}
       if (file_num != table->file_num)
diff --git a/gcc/testsuite/gcc.dg/graphite/pr84404.c b/gcc/testsuite/gcc.dg/graphite/pr84404.c
new file mode 100644
index 000000000000..858e651cfab7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr84404.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-parallelize-loops=2 -floop-nest-optimize -g" } */
+
+int te[9];
+
+void
+dt (int cz)
+{
+  while (cz < 1)
+    {
+      int xy;
+
+      for (xy = 0; xy < 9; ++xy)
+        te[xy] = 0;
+
+      ++cz;
+    }
+}


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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-01-24 17:40                     ` Jakub Jelinek
  2018-01-25 20:14                       ` Alexandre Oliva
@ 2018-02-21 10:33                       ` Alexandre Oliva
  2018-02-26 12:47                         ` Richard Biener
  1 sibling, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-21 10:33 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Richard Biener, Jeff Law, GCC Patches

On Jan 24, 2018, Jakub Jelinek <jakub@redhat.com> wrote:

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

> Wonder what the above hunks will do for LTO memory consumption.  We'll see.


[IEPM] don't preserve lexical blocks just for debug inline markers

This patch stops preserving scope blocks just because they are inlined
function scopes, when cleaning up unused scope blocks.  This change
was introduced along with IEPM, but it preserved lots of blocks, and
output debug information for them, although no code from the inlined
function remained after optimization.

The additional preserved blocks took up compile-time memory, and
significant disk space and link time, in some cases more than 25%.
This is deemed excessive, compared with the reasonably small benefit
of allowing one to single-step into an inlined function using a
view-capable debugger.

There was another way of marking inlined function scopes as unused,
based on the markers referencing them during stmt scanning, but that
still preserved too much.

So, this patch restores the pre-IEPM logic of preservation of scopes.
Should a scope block referenced by an inline entry marker be found to
be unused in remove_unused_scope_block_p, the marker will be cleaned
up right after that, in clear_unused_block_pointer, so we won't keep
a dangling reference to a dropped block.

Regstrapped on x86_64- and i686-linux-gnu.  Ok to install?

for  gcc/ChangeLog

	* tree-ssa-live.c (remove_unused_scope_block_p): Do not
	preserve inline entry blocks for the sake of debug inline
	entry point markers alone.
	(remove_unused_locals): Suggest in comments a better place to
	force the preservation of inline entry blocks that are
	otherwise unused, but do not preserve them.
---
 gcc/tree-ssa-live.c |   15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 62bb3c5de659..62316bac7929 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -520,11 +520,6 @@ 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_inline_points
-	    && inlined_function_outer_scope_p (scope))
-     unused = false;
    /* Innermost blocks with no live variables nor statements can be always
       eliminated.  */
    else if (!nsubblocks)
@@ -556,10 +551,8 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
    /* 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_inline_points
-	    && inlined_function_outer_scope_p (scope))
+      DECL_SOURCE_LOCATION set, unless they expand to nothing...  */
+   else if (inlined_function_outer_scope_p (scope))
      unused = false;
    else
    /* Verfify that only blocks with source location set
@@ -741,6 +734,10 @@ remove_unused_locals (void)
 	  gimple *stmt = gsi_stmt (gsi);
 	  tree b = gimple_block (stmt);
 
+	  /* If we wanted to mark the block referenced by the inline
+	     entry point marker as used, this would be a good spot to
+	     do it.  If the block is not otherwise used, the stmt will
+	     be cleaned up in clean_unused_block_pointer.  */
 	  if (is_gimple_debug (stmt))
 	    continue;
 


Here's a patch I'm sharing just FTR, that introduces (on top of the
above) options to select other approaches to preserve scopes related
with inlined functions.  It's not meant for inclusion; the options'
spelling are such that the three possible approaches, as well as
-gno-inline-points, can be tested so as to compare file sizes to measure
debug info size changes, without noise out of different length of the
command-line options.

The differences in libgcc are tiny, but those in cc1 and cc1plus are
quite significant:

               no         df         mr         al
cc1            260726424  280455288  312591944  312600224
cc1plus        289090200  309719888  347144256  347152840
libgcc_s.so       864016     867840     868128     868128
libstdc++.so    12846528   14758400   17619736   17619480


---
 gcc/common.opt      |   12 ++++++++++++
 gcc/tree-ssa-live.c |    5 ++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index e0bc4d1bb18d..594ea0213cba 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2924,6 +2924,18 @@ ginline-points
 Common Driver Var(debug_inline_points) Init(2)
 Generate extended entry point information for inlined functions
 
+ginline-points=df
+Common Driver Var(debug_inline_points, 1) Init(2)
+Don't preserve blocks just for inlined functions
+
+ginline-points=al
+Common Driver Var(debug_inline_points, 3) Init(2)
+Preserve all blocks regarded as inlined function scopes
+
+ginline-points=mr
+Common Driver Var(debug_inline_points, 4) Init(2)
+Preserve blocks referenced by inline entry point markers only
+
 ginternal-reset-location-views
 Common Driver Var(debug_internal_reset_location_views) Init(2)
 Compute locview reset points based on insn length estimates
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 62316bac7929..f75a6ea2126a 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -520,6 +520,8 @@ 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;
+   else if (debug_inline_points == 3 && inlined_function_outer_scope_p (scope))
+     unused = false;
    /* Innermost blocks with no live variables nor statements can be always
       eliminated.  */
    else if (!nsubblocks)
@@ -738,7 +740,8 @@ remove_unused_locals (void)
 	     entry point marker as used, this would be a good spot to
 	     do it.  If the block is not otherwise used, the stmt will
 	     be cleaned up in clean_unused_block_pointer.  */
-	  if (is_gimple_debug (stmt))
+	  if (is_gimple_debug (stmt)
+	      && (debug_inline_points != 4 || !gimple_debug_inline_entry_p (stmt)))
 	    continue;
 
 	  if (gimple_clobber_p (stmt))



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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-21 10:12                                           ` Alexandre Oliva
@ 2018-02-21 12:08                                             ` Uros Bizjak
  2018-02-22 15:22                                             ` Szabolcs Nagy
                                                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 156+ messages in thread
From: Uros Bizjak @ 2018-02-21 12:08 UTC (permalink / raw)
  To: Alexandre Oliva
  Cc: Szabolcs Nagy, Rainer Orth, nd, Jakub Jelinek, Jeff Law,
	Alan Modra, Jason Merrill, Richard Biener, GCC Patches

On Wed, Feb 21, 2018 at 11:11 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>
>> i see assembler slow downs with these location view patches
>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408
>
>
> [LVU] reset view at function entry, omit views at line zero
>
> Location views might be associated with locations that lack line
> number information (line number zero), but since we omit .loc
> directives that would have been issued with line number zero, we also
> omit the symbolic view numbers that would have been issued at such
> points.
>
> Resetting views at function entry points address some of these issues,
> and alleviate the huge chains of symbolic views that have burdened
> assemblers since we disabled -ginternal-reset-location-views by
> default, but other problems of undefined views remain when it's not
> the whole function that lacks line number info, just parts of it.
>
> So, when we encounter a request to output a view that may have been
> referenced, but we decide to omit the .loc because the line is zero,
> we will now omit the view as well, i.e., we will internally regard
> that view as zero-numbered.
>
> Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?
>
> Uros, could you please confirm whether this fixes the 84404 go problem
> you reported on alpha?  I'm guessing it's the same issue.  TIA,

I can confirm, that all "leb128 operand is an undefined symbol" errors
are gone. I'm running full alpha native bootstrap & regression test,
but I don't expect any surprises here.

Thanks,
Uros.

> for  gcc/ChangeLog
>
>         PR debug/84404
>         PR debug/84408
>         * dwarf2out.c (struct dw_line_info_table): Update comments for
>         view == -1.
>         (FORCE_RESET_NEXT_VIEW): New.
>         (FORCE_RESETTING_VIEW_P): New.
>         (RESETTING_VIEW_P): Check for -1 too.
>         (ZERO_VIEW_P): Likewise.
>         (new_line_info_table): Force-reset next view.
>         (dwarf2out_begin_function): Likewise.
>         (dwarf2out_source_line): Simplify zero_view_p initialization.
>         Test FORCE_RESETTING_VIEW_P and RESETTING_VIEW_P instead of
>         view directly.  Omit view when omitting .loc at line 0.
>
> for  gcc/testsuite/ChangeLog
>
>         PR debug/84404
>         PR debug/84408
>         * gcc.dg/graphite/pr84404.c: New.
> ---
>  gcc/dwarf2out.c                         |   89 ++++++++++++++++++++++++-------
>  gcc/testsuite/gcc.dg/graphite/pr84404.c |   18 ++++++
>  2 files changed, 87 insertions(+), 20 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/graphite/pr84404.c
>
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 5e88c7bacf06..7bbe20e495ac 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -2940,8 +2940,8 @@ struct GTY(()) dw_line_info_table {
>       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.
> +     If it is -1, we're forcing the view number to be reset, e.g. at a
> +     function entry.
>
>       The meaning of other nonzero values depends on whether we're
>       computing views internally or leaving it for the assembler to do
> @@ -2951,8 +2951,10 @@ struct GTY(()) dw_line_info_table {
>       going to ask the assembler to assign.  */
>    var_loc_view view;
>
> +#define FORCE_RESET_NEXT_VIEW(x) ((x) = (var_loc_view)-1)
>  #define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
> -#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
> +#define FORCE_RESETTING_VIEW_P(x) ((x) == (var_loc_view)-1)
> +#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0 || FORCE_RESETTING_VIEW_P (x))
>
>    vec<dw_line_info_entry, va_gc> *entries;
>  };
> @@ -2985,7 +2987,7 @@ maybe_reset_location_view (rtx_insn *insn, dw_line_info_table *table)
>    else if (get_attr_min_length (insn) > 0)
>      reset = 1;
>
> -  if (reset > 0)
> +  if (reset > 0 && !RESETTING_VIEW_P (table->view))
>      RESET_NEXT_VIEW (table->view);
>  }
>
> @@ -3235,9 +3237,10 @@ static GTY(()) bitmap zero_view_p;
>     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)
> +#define ZERO_VIEW_P(N) ((N) == (var_loc_view)0                         \
> +                       || (N) == (var_loc_view)-1                      \
> +                       || (zero_view_p                                 \
> +                           && bitmap_bit_p (zero_view_p, (N))))
>
>  /* Return true iff we're to emit .loc directives for the assembler to
>     generate line number sections.
> @@ -27210,6 +27213,18 @@ create_label:
>           last_postcall_label = ggc_strdup (loclabel);
>         }
>        newloc->label = last_postcall_label;
> +      /* ??? This view is at last_label, not last_label-1, but we
> +        could only assume view at last_label-1 is zero if we could
> +        assume calls always have length greater than one.  This is
> +        probably true in general, though there might be a rare
> +        exception to this rule, e.g. if a call insn is optimized out
> +        by target magic.  Then, even the -1 in the label will be
> +        wrong, which might invalidate the range.  Anyway, using view,
> +        though technically possibly incorrect, will work as far as
> +        ranges go: since L-1 is in the middle of the call insn,
> +        (L-1).0 and (L-1).V shouldn't make any difference, and having
> +        the loclist entry refer to the .loc entry might be useful, so
> +        leave it like this.  */
>        newloc->view = view;
>      }
>
> @@ -27391,7 +27406,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);
> +  FORCE_RESET_NEXT_VIEW (table->view);
>
>    return table;
>  }
> @@ -27475,6 +27490,7 @@ dwarf2out_begin_function (tree fun)
>    tail_call_site_count = 0;
>
>    set_cur_line_info_table (sec);
> +  FORCE_RESET_NEXT_VIEW (cur_line_info_table->view);
>  }
>
>  /* Helper function of dwarf2out_end_function, called only after emitting
> @@ -27572,10 +27588,44 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>  {
>    unsigned int file_num;
>    dw_line_info_table *table;
> +  static var_loc_view lvugid;
>
> -  if (debug_info_level < DINFO_LEVEL_TERSE || line == 0)
> +  if (debug_info_level < DINFO_LEVEL_TERSE)
>      return;
>
> +  table = cur_line_info_table;
> +
> +  if (line == 0)
> +    {
> +      if (debug_variable_location_views
> +         && output_asm_line_debug_info ()
> +         && table && !RESETTING_VIEW_P (table->view))
> +       {
> +         /* If we're using the assembler to compute view numbers, we
> +            can't issue a .loc directive for line zero, so we can't
> +            get a view number at this point.  We might attempt to
> +            compute it from the previous view, but since we're
> +            omitting the line number entry, we might as well omit the
> +            view number as well.  That means pretending it's a view
> +            number zero, which might very well turn out to be
> +            correct.  */
> +         if (!zero_view_p)
> +           zero_view_p = BITMAP_GGC_ALLOC ();
> +         bitmap_set_bit (zero_view_p, table->view);
> +         if (flag_debug_asm)
> +           {
> +             char label[MAX_ARTIFICIAL_LABEL_BYTES];
> +             ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
> +             fprintf (asm_out_file, "\t%s line 0, omitted view ",
> +                      ASM_COMMENT_START);
> +             assemble_name (asm_out_file, label);
> +             putc ('\n', asm_out_file);
> +           }
> +         table->view = ++lvugid;
> +       }
> +      return;
> +    }
> +
>    /* The discriminator column was added in dwarf4.  Simplify the below
>       by simply removing it if we're not supposed to output it.  */
>    if (dwarf_version < 4 && dwarf_strict)
> @@ -27584,7 +27634,6 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>    if (!debug_column_info)
>      column = 0;
>
> -  table = cur_line_info_table;
>    file_num = maybe_emit_file (lookup_filename (filename));
>
>    /* ??? TODO: Elide duplicate line number entries.  Traditionally,
> @@ -27646,13 +27695,6 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>         }
>        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))
>             {
>               /* When we're using the assembler to compute view
> @@ -27673,7 +27715,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>             }
>           else
>             {
> -             if (!table->in_use)
> +             if (FORCE_RESETTING_VIEW_P (table->view))
>                 fputs (" view -0", asm_out_file);
>               else
>                 fputs (" view 0", asm_out_file);
> @@ -27684,6 +27726,8 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>                  known to be zero, because then we may be able to
>                  optimize out locviews that are all zeros, so take
>                  note of it in zero_view_p.  */
> +             if (!zero_view_p)
> +               zero_view_p = BITMAP_GGC_ALLOC ();
>               bitmap_set_bit (zero_view_p, lvugid);
>               table->view = ++lvugid;
>             }
> @@ -27696,17 +27740,22 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
>
>        targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
>
> -      if (debug_variable_location_views && table->view)
> +      if (debug_variable_location_views && !RESETTING_VIEW_P (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)
>         {
> +         bool resetting = FORCE_RESETTING_VIEW_P (table->view);
> +         if (resetting)
> +           table->view = 0;
> +
>           if (flag_debug_asm)
>             fprintf (asm_out_file, "\t%s view %s%d\n",
>                      ASM_COMMENT_START,
> -                    table->in_use ? "" : "-",
> +                    resetting ? "-" : "",
>                      table->view);
> +
>           table->view++;
>         }
>        if (file_num != table->file_num)
> diff --git a/gcc/testsuite/gcc.dg/graphite/pr84404.c b/gcc/testsuite/gcc.dg/graphite/pr84404.c
> new file mode 100644
> index 000000000000..858e651cfab7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/graphite/pr84404.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -ftree-parallelize-loops=2 -floop-nest-optimize -g" } */
> +
> +int te[9];
> +
> +void
> +dt (int cz)
> +{
> +  while (cz < 1)
> +    {
> +      int xy;
> +
> +      for (xy = 0; xy < 9; ++xy)
> +        te[xy] = 0;
> +
> +      ++cz;
> +    }
> +}
>
>
> --
> 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-21 10:12                                           ` Alexandre Oliva
  2018-02-21 12:08                                             ` Uros Bizjak
@ 2018-02-22 15:22                                             ` Szabolcs Nagy
  2018-02-28  6:17                                             ` Alexandre Oliva
  2018-03-07 19:43                                             ` Jeff Law
  3 siblings, 0 replies; 156+ messages in thread
From: Szabolcs Nagy @ 2018-02-22 15:22 UTC (permalink / raw)
  To: Alexandre Oliva, Uros Bizjak
  Cc: nd, Rainer Orth, Jakub Jelinek, Jeff Law, Alan Modra,
	Jason Merrill, Richard Biener, GCC Patches

On 21/02/18 10:11, Alexandre Oliva wrote:
> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
> 
>> i see assembler slow downs with these location view patches
>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408
> 
> 
> [LVU] reset view at function entry, omit views at line zero
> 
> Location views might be associated with locations that lack line
> number information (line number zero), but since we omit .loc
> directives that would have been issued with line number zero, we also
> omit the symbolic view numbers that would have been issued at such
> points.
> 
> Resetting views at function entry points address some of these issues,
> and alleviate the huge chains of symbolic views that have burdened
> assemblers since we disabled -ginternal-reset-location-views by
> default, but other problems of undefined views remain when it's not
> the whole function that lacks line number info, just parts of it.
> 
> So, when we encounter a request to output a view that may have been
> referenced, but we decide to omit the .loc because the line is zero,
> we will now omit the view as well, i.e., we will internally regard
> that view as zero-numbered.
> 
> Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?
> 

fixes 84408 for me, now i get

$ ./xg++ -B. -g -O -fPIC -shared -fno-rtti -time poly-int-07_plugin.ii
# cc1plus 47.39 0.60
# as 6.78 0.25
# collect2 0.27 0.04

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-21 10:33                       ` Alexandre Oliva
@ 2018-02-26 12:47                         ` Richard Biener
  0 siblings, 0 replies; 156+ messages in thread
From: Richard Biener @ 2018-02-26 12:47 UTC (permalink / raw)
  To: Alexandre Oliva; +Cc: Jakub Jelinek, Jason Merrill, Jeff Law, GCC Patches

On Wed, Feb 21, 2018 at 11:32 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Jan 24, 2018, Jakub Jelinek <jakub@redhat.com> wrote:
>
>>> --- 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;
>
>> Wonder what the above hunks will do for LTO memory consumption.  We'll see.
>
>
> [IEPM] don't preserve lexical blocks just for debug inline markers
>
> This patch stops preserving scope blocks just because they are inlined
> function scopes, when cleaning up unused scope blocks.  This change
> was introduced along with IEPM, but it preserved lots of blocks, and
> output debug information for them, although no code from the inlined
> function remained after optimization.
>
> The additional preserved blocks took up compile-time memory, and
> significant disk space and link time, in some cases more than 25%.
> This is deemed excessive, compared with the reasonably small benefit
> of allowing one to single-step into an inlined function using a
> view-capable debugger.
>
> There was another way of marking inlined function scopes as unused,
> based on the markers referencing them during stmt scanning, but that
> still preserved too much.
>
> So, this patch restores the pre-IEPM logic of preservation of scopes.
> Should a scope block referenced by an inline entry marker be found to
> be unused in remove_unused_scope_block_p, the marker will be cleaned
> up right after that, in clear_unused_block_pointer, so we won't keep
> a dangling reference to a dropped block.
>
> Regstrapped on x86_64- and i686-linux-gnu.  Ok to install?

Ok.

Thanks,
Richard.

> for  gcc/ChangeLog
>
>         * tree-ssa-live.c (remove_unused_scope_block_p): Do not
>         preserve inline entry blocks for the sake of debug inline
>         entry point markers alone.
>         (remove_unused_locals): Suggest in comments a better place to
>         force the preservation of inline entry blocks that are
>         otherwise unused, but do not preserve them.
> ---
>  gcc/tree-ssa-live.c |   15 ++++++---------
>  1 file changed, 6 insertions(+), 9 deletions(-)
>
> diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
> index 62bb3c5de659..62316bac7929 100644
> --- a/gcc/tree-ssa-live.c
> +++ b/gcc/tree-ssa-live.c
> @@ -520,11 +520,6 @@ 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_inline_points
> -           && inlined_function_outer_scope_p (scope))
> -     unused = false;
>     /* Innermost blocks with no live variables nor statements can be always
>        eliminated.  */
>     else if (!nsubblocks)
> @@ -556,10 +551,8 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
>     /* 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_inline_points
> -           && inlined_function_outer_scope_p (scope))
> +      DECL_SOURCE_LOCATION set, unless they expand to nothing...  */
> +   else if (inlined_function_outer_scope_p (scope))
>       unused = false;
>     else
>     /* Verfify that only blocks with source location set
> @@ -741,6 +734,10 @@ remove_unused_locals (void)
>           gimple *stmt = gsi_stmt (gsi);
>           tree b = gimple_block (stmt);
>
> +         /* If we wanted to mark the block referenced by the inline
> +            entry point marker as used, this would be a good spot to
> +            do it.  If the block is not otherwise used, the stmt will
> +            be cleaned up in clean_unused_block_pointer.  */
>           if (is_gimple_debug (stmt))
>             continue;
>
>
>
> Here's a patch I'm sharing just FTR, that introduces (on top of the
> above) options to select other approaches to preserve scopes related
> with inlined functions.  It's not meant for inclusion; the options'
> spelling are such that the three possible approaches, as well as
> -gno-inline-points, can be tested so as to compare file sizes to measure
> debug info size changes, without noise out of different length of the
> command-line options.
>
> The differences in libgcc are tiny, but those in cc1 and cc1plus are
> quite significant:
>
>                no         df         mr         al
> cc1            260726424  280455288  312591944  312600224
> cc1plus        289090200  309719888  347144256  347152840
> libgcc_s.so       864016     867840     868128     868128
> libstdc++.so    12846528   14758400   17619736   17619480
>
>
> ---
>  gcc/common.opt      |   12 ++++++++++++
>  gcc/tree-ssa-live.c |    5 ++++-
>  2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index e0bc4d1bb18d..594ea0213cba 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -2924,6 +2924,18 @@ ginline-points
>  Common Driver Var(debug_inline_points) Init(2)
>  Generate extended entry point information for inlined functions
>
> +ginline-points=df
> +Common Driver Var(debug_inline_points, 1) Init(2)
> +Don't preserve blocks just for inlined functions
> +
> +ginline-points=al
> +Common Driver Var(debug_inline_points, 3) Init(2)
> +Preserve all blocks regarded as inlined function scopes
> +
> +ginline-points=mr
> +Common Driver Var(debug_inline_points, 4) Init(2)
> +Preserve blocks referenced by inline entry point markers only
> +
>  ginternal-reset-location-views
>  Common Driver Var(debug_internal_reset_location_views) Init(2)
>  Compute locview reset points based on insn length estimates
> diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
> index 62316bac7929..f75a6ea2126a 100644
> --- a/gcc/tree-ssa-live.c
> +++ b/gcc/tree-ssa-live.c
> @@ -520,6 +520,8 @@ 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;
> +   else if (debug_inline_points == 3 && inlined_function_outer_scope_p (scope))
> +     unused = false;
>     /* Innermost blocks with no live variables nor statements can be always
>        eliminated.  */
>     else if (!nsubblocks)
> @@ -738,7 +740,8 @@ remove_unused_locals (void)
>              entry point marker as used, this would be a good spot to
>              do it.  If the block is not otherwise used, the stmt will
>              be cleaned up in clean_unused_block_pointer.  */
> -         if (is_gimple_debug (stmt))
> +         if (is_gimple_debug (stmt)
> +             && (debug_inline_points != 4 || !gimple_debug_inline_entry_p (stmt)))
>             continue;
>
>           if (gimple_clobber_p (stmt))
>
>
>
> --
> 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-21 10:12                                           ` Alexandre Oliva
  2018-02-21 12:08                                             ` Uros Bizjak
  2018-02-22 15:22                                             ` Szabolcs Nagy
@ 2018-02-28  6:17                                             ` Alexandre Oliva
  2018-03-09  9:49                                               ` Bin.Cheng
  2018-03-07 19:43                                             ` Jeff Law
  3 siblings, 1 reply; 156+ messages in thread
From: Alexandre Oliva @ 2018-02-28  6:17 UTC (permalink / raw)
  To: Szabolcs Nagy, Uros Bizjak, Rainer Orth, nd, Jakub Jelinek,
	Jeff Law, Alan Modra, Jason Merrill, Richard Biener, GCC Patches

On Feb 21, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:

> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>> i see assembler slow downs with these location view patches
>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408


> [LVU] reset view at function entry, omit views at line zero

Ping?  https://gcc.gnu.org/ml/gcc-patches/2018-02/msg01224.html

> for  gcc/ChangeLog

> 	PR debug/84404
> 	PR debug/84408
> 	* dwarf2out.c (struct dw_line_info_table): Update comments for
> 	view == -1.
> 	(FORCE_RESET_NEXT_VIEW): New.
> 	(FORCE_RESETTING_VIEW_P): New.
> 	(RESETTING_VIEW_P): Check for -1 too.
> 	(ZERO_VIEW_P): Likewise.
> 	(new_line_info_table): Force-reset next view.
> 	(dwarf2out_begin_function): Likewise.
> 	(dwarf2out_source_line): Simplify zero_view_p initialization.
> 	Test FORCE_RESETTING_VIEW_P and RESETTING_VIEW_P instead of
> 	view directly.  Omit view when omitting .loc at line 0.

> for  gcc/testsuite/ChangeLog

> 	PR debug/84404
> 	PR debug/84408
> 	* gcc.dg/graphite/pr84404.c: New.

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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-21 10:12                                           ` Alexandre Oliva
                                                               ` (2 preceding siblings ...)
  2018-02-28  6:17                                             ` Alexandre Oliva
@ 2018-03-07 19:43                                             ` Jeff Law
  3 siblings, 0 replies; 156+ messages in thread
From: Jeff Law @ 2018-03-07 19:43 UTC (permalink / raw)
  To: Alexandre Oliva, Szabolcs Nagy, Uros Bizjak
  Cc: Rainer Orth, nd, Jakub Jelinek, Alan Modra, Jason Merrill,
	Richard Biener, GCC Patches

On 02/21/2018 03:11 AM, Alexandre Oliva wrote:
> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
> 
>> i see assembler slow downs with these location view patches
>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408
> 
> 
> [LVU] reset view at function entry, omit views at line zero
> 
> Location views might be associated with locations that lack line
> number information (line number zero), but since we omit .loc
> directives that would have been issued with line number zero, we also
> omit the symbolic view numbers that would have been issued at such
> points.
> 
> Resetting views at function entry points address some of these issues,
> and alleviate the huge chains of symbolic views that have burdened
> assemblers since we disabled -ginternal-reset-location-views by
> default, but other problems of undefined views remain when it's not
> the whole function that lacks line number info, just parts of it.
> 
> So, when we encounter a request to output a view that may have been
> referenced, but we decide to omit the .loc because the line is zero,
> we will now omit the view as well, i.e., we will internally regard
> that view as zero-numbered.
> 
> Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?
> 
> Uros, could you please confirm whether this fixes the 84404 go problem
> you reported on alpha?  I'm guessing it's the same issue.  TIA,
> 
> for  gcc/ChangeLog
> 
> 	PR debug/84404
> 	PR debug/84408
> 	* dwarf2out.c (struct dw_line_info_table): Update comments for
> 	view == -1.
> 	(FORCE_RESET_NEXT_VIEW): New.
> 	(FORCE_RESETTING_VIEW_P): New.
> 	(RESETTING_VIEW_P): Check for -1 too.
> 	(ZERO_VIEW_P): Likewise.
> 	(new_line_info_table): Force-reset next view.
> 	(dwarf2out_begin_function): Likewise.
> 	(dwarf2out_source_line): Simplify zero_view_p initialization.
> 	Test FORCE_RESETTING_VIEW_P and RESETTING_VIEW_P instead of
> 	view directly.  Omit view when omitting .loc at line 0.
> 
> for  gcc/testsuite/ChangeLog
> 
> 	PR debug/84404
> 	PR debug/84408
> 	* gcc.dg/graphite/pr84404.c: New.
OK.

jeff

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-02-28  6:17                                             ` Alexandre Oliva
@ 2018-03-09  9:49                                               ` Bin.Cheng
  2018-03-09  9:55                                                 ` Ramana Radhakrishnan
  2018-03-09 11:35                                                 ` Jakub Jelinek
  0 siblings, 2 replies; 156+ messages in thread
From: Bin.Cheng @ 2018-03-09  9:49 UTC (permalink / raw)
  To: Alexandre Oliva, gcc-patches List, Jeff Law

On Wed, Feb 28, 2018 at 6:17 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Feb 21, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
>
>> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>>> i see assembler slow downs with these location view patches
>>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408
>
>
>> [LVU] reset view at function entry, omit views at line zero
>
> Ping?  https://gcc.gnu.org/ml/gcc-patches/2018-02/msg01224.html

Hi,
The new test case failed on aarch64-none-elf, aarch64_be-none-elf and
arm-none-eabi ,
which are all bare-metal toolchains with below message:

xgcc: error: unrecognized command line option '-pthread'

I assume pthread is unavailable on such targets if it's required.

Thanks,
bin
>
>> for  gcc/ChangeLog
>
>>       PR debug/84404
>>       PR debug/84408
>>       * dwarf2out.c (struct dw_line_info_table): Update comments for
>>       view == -1.
>>       (FORCE_RESET_NEXT_VIEW): New.
>>       (FORCE_RESETTING_VIEW_P): New.
>>       (RESETTING_VIEW_P): Check for -1 too.
>>       (ZERO_VIEW_P): Likewise.
>>       (new_line_info_table): Force-reset next view.
>>       (dwarf2out_begin_function): Likewise.
>>       (dwarf2out_source_line): Simplify zero_view_p initialization.
>>       Test FORCE_RESETTING_VIEW_P and RESETTING_VIEW_P instead of
>>       view directly.  Omit view when omitting .loc at line 0.
>
>> for  gcc/testsuite/ChangeLog
>
>>       PR debug/84404
>>       PR debug/84408
>>       * gcc.dg/graphite/pr84404.c: New.
>
> --
> 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-03-09  9:49                                               ` Bin.Cheng
@ 2018-03-09  9:55                                                 ` Ramana Radhakrishnan
  2018-03-09 11:35                                                 ` Jakub Jelinek
  1 sibling, 0 replies; 156+ messages in thread
From: Ramana Radhakrishnan @ 2018-03-09  9:55 UTC (permalink / raw)
  To: Bin.Cheng; +Cc: Alexandre Oliva, gcc-patches List, Jeff Law

On Fri, Mar 9, 2018 at 9:48 AM, Bin.Cheng <amker.cheng@gmail.com> wrote:
> On Wed, Feb 28, 2018 at 6:17 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
>> On Feb 21, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
>>
>>> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>>>> i see assembler slow downs with these location view patches
>>>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408
>>
>>
>>> [LVU] reset view at function entry, omit views at line zero
>>
>> Ping?  https://gcc.gnu.org/ml/gcc-patches/2018-02/msg01224.html
>
> Hi,
> The new test case failed on aarch64-none-elf, aarch64_be-none-elf and
> arm-none-eabi ,
> which are all bare-metal toolchains with below message:
>
> xgcc: error: unrecognized command line option '-pthread'
>
> I assume pthread is unavailable on such targets if it's required.

I think there's a dg-effective-target for pthread.

Ramana

>
> Thanks,
> bin
>>
>>> for  gcc/ChangeLog
>>
>>>       PR debug/84404
>>>       PR debug/84408
>>>       * dwarf2out.c (struct dw_line_info_table): Update comments for
>>>       view == -1.
>>>       (FORCE_RESET_NEXT_VIEW): New.
>>>       (FORCE_RESETTING_VIEW_P): New.
>>>       (RESETTING_VIEW_P): Check for -1 too.
>>>       (ZERO_VIEW_P): Likewise.
>>>       (new_line_info_table): Force-reset next view.
>>>       (dwarf2out_begin_function): Likewise.
>>>       (dwarf2out_source_line): Simplify zero_view_p initialization.
>>>       Test FORCE_RESETTING_VIEW_P and RESETTING_VIEW_P instead of
>>>       view directly.  Omit view when omitting .loc at line 0.
>>
>>> for  gcc/testsuite/ChangeLog
>>
>>>       PR debug/84404
>>>       PR debug/84408
>>>       * gcc.dg/graphite/pr84404.c: New.
>>
>> --
>> 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

^ permalink raw reply	[flat|nested] 156+ messages in thread

* Re: [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers
  2018-03-09  9:49                                               ` Bin.Cheng
  2018-03-09  9:55                                                 ` Ramana Radhakrishnan
@ 2018-03-09 11:35                                                 ` Jakub Jelinek
  1 sibling, 0 replies; 156+ messages in thread
From: Jakub Jelinek @ 2018-03-09 11:35 UTC (permalink / raw)
  To: Bin.Cheng; +Cc: Alexandre Oliva, gcc-patches List, Jeff Law

On Fri, Mar 09, 2018 at 09:48:45AM +0000, Bin.Cheng wrote:
> On Wed, Feb 28, 2018 at 6:17 AM, Alexandre Oliva <aoliva@redhat.com> wrote:
> > On Feb 21, 2018, Alexandre Oliva <aoliva@redhat.com> wrote:
> >
> >> On Feb 15, 2018, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
> >>> i see assembler slow downs with these location view patches
> >>> i opened https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84408
> >
> >
> >> [LVU] reset view at function entry, omit views at line zero
> >
> > Ping?  https://gcc.gnu.org/ml/gcc-patches/2018-02/msg01224.html
> 
> Hi,
> The new test case failed on aarch64-none-elf, aarch64_be-none-elf and
> arm-none-eabi ,
> which are all bare-metal toolchains with below message:
> 
> xgcc: error: unrecognized command line option '-pthread'
> 
> I assume pthread is unavailable on such targets if it's required.

I think this ought to fix it, committed as obvious:

2018-03-09  Jakub Jelinek  <jakub@redhat.com>

	PR debug/84404
	* gcc.dg/graphite/pr84404.c: Only compile on pthread effective
	targets.

--- gcc/testsuite/gcc.dg/graphite/pr84404.c.jj	2018-03-08 21:53:46.096560261 +0100
+++ gcc/testsuite/gcc.dg/graphite/pr84404.c	2018-03-09 10:54:49.605773196 +0100
@@ -1,4 +1,5 @@
-/* { dg-do compile } */
+/* PR debug/84404 */
+/* { dg-do compile { target pthread } } */
 /* { dg-options "-O2 -ftree-parallelize-loops=2 -floop-nest-optimize -g" } */
 
 int te[9];


	Jakub

^ permalink raw reply	[flat|nested] 156+ messages in thread

end of thread, other threads:[~2018-03-09 11:35 UTC | newest]

Thread overview: 156+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-05 23:21 Introduce Statement Frontier Notes and Location Views Alexandre Oliva
2017-07-13 13:17 ` Alexandre Oliva
2017-08-18 22:49   ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers (was: Re: Introduce Statement Frontier Notes and Location Views) Alexandre Oliva
2017-08-21 12:35     ` Richard Biener
2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
2017-08-23 12:12         ` Richard Biener
2017-08-25 15:26           ` Alexandre Oliva
2017-08-28 12:41             ` Richard Biener
2017-08-25 19:22           ` Alexandre Oliva
2017-09-01  1:07           ` Alexandre Oliva
2017-09-01  1:15             ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
2017-09-01  1:15             ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
2017-09-01  1:15             ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
2017-09-01  1:16             ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
2017-09-01  1:16             ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
2017-09-01  1:16             ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
2017-09-01  1:16             ` [PATCH 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
2017-09-01  1:16             ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
2017-09-01  1:16             ` [PATCH 7/9] [LVU] Introduce location views Alexandre Oliva
2017-09-30  9:04             ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
2017-09-30  9:09               ` [PATCH 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
2017-10-09 13:24                 ` Richard Biener
2017-09-30  9:09               ` [PATCH 5/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
2017-10-09 13:12                 ` Richard Biener
2017-09-30  9:09               ` [PATCH 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
2017-10-09 13:02                 ` Richard Biener
2017-09-30  9:09               ` [PATCH 4/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
2017-10-09 13:11                 ` Richard Biener
2017-10-13  7:25                   ` Alexandre Oliva
2017-10-13  9:41                     ` Richard Biener
2017-10-17 22:06                       ` Alexandre Oliva
2017-10-24 18:11                 ` Jason Merrill
2017-11-01 19:14                   ` Alexandre Oliva
2017-11-01 19:49                     ` Jason Merrill
2017-09-30  9:09               ` [PATCH 6/9] [LVU] Allow final_start_function to skip initial insns Alexandre Oliva
2017-10-19 11:07                 ` Richard Biener
2017-10-31  5:10                   ` Jeff Law
2017-10-31  5:23                 ` Jeff Law
2017-11-01 18:20                   ` Alexandre Oliva
2017-11-02 13:00                     ` Richard Biener
2017-09-30  9:10               ` [PATCH 3/9] [SFN] not-quite-boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
2017-10-09 13:07                 ` Richard Biener
2017-09-30  9:10               ` [PATCH 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
2017-10-31  5:58                 ` Jeff Law
2017-09-30  9:10               ` [PATCH 9/9] [IEPM] Introduce " Alexandre Oliva
2017-10-31  6:22                 ` Jeff Law
2017-11-01 18:36                   ` Alexandre Oliva
2017-11-09 16:30                     ` Jeff Law
2017-11-10  2:31                       ` Alexandre Oliva
2017-09-30  9:10               ` [PATCH 7/9] [LVU] Introduce location views Alexandre Oliva
2017-11-10  2:36               ` SFN+LVU+IEPM v4 (was: Re: Statement Frontier Notes, Location Views, and Inlined Entry Point Markers) Alexandre Oliva
2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 4/9] [SFN] stabilize find_bb_boundaries Alexandre Oliva
2017-12-07 22:46                   ` Jeff Law
2017-12-12  2:38                     ` Alexandre Oliva
2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 5/9] [SFN] introduce statement frontier notes, still disabled Alexandre Oliva
2017-12-07 23:59                   ` Jeff Law
2017-12-12  2:41                     ` Alexandre Oliva
2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 1/9] [SFN] adjust RTL insn-walking API Alexandre Oliva
2017-12-07 22:25                   ` Jeff Law
2017-12-12  3:10                     ` Alexandre Oliva
2017-12-14 11:55                       ` Alexandre Oliva
2017-12-14 12:07                         ` Jakub Jelinek
2017-12-14 18:25                           ` Alexandre Oliva
2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 2/9] [SFN] boilerplate changes in preparation to introduce nonbind markers Alexandre Oliva
2017-12-07 22:27                   ` Jeff Law
2017-12-12  2:55                     ` Alexandre Oliva
2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 3/9] [SFN] not-quite-boilerplate " Alexandre Oliva
2017-12-07 22:44                   ` Jeff Law
2017-12-12  2:31                     ` Alexandre Oliva
2017-11-10  2:36                 ` [SFN+LVU+IEPM v4 6/9] [SFN] Introduce -gstatement-frontiers option, enable debug markers Alexandre Oliva
2017-12-07 22:49                   ` Jeff Law
2017-12-12  2:42                     ` Alexandre Oliva
2017-12-12  9:16                       ` Christophe Lyon
2017-12-13  4:22                         ` Alexandre Oliva
2018-01-07 17:48                       ` H.J. Lu
2017-12-27  8:00                   ` [nvptx, committed] Disable -gstatement-frontiers for nvptx Tom de Vries
2017-12-29  4:12                     ` Alexandre Oliva
2017-12-29 11:42                       ` Tom de Vries
2017-12-31 20:05                         ` Alexandre Oliva
2018-01-11 10:12                           ` Tom de Vries
2017-11-10  2:37                 ` [SFN+LVU+IEPM v4 8/9] [IEPM] Introduce debug hook for inline entry point markers Alexandre Oliva
2017-12-07 22:51                   ` Jeff Law
2017-12-12  2:44                     ` Alexandre Oliva
2017-11-10  5:05                 ` [SFN+LVU+IEPM v4 7/9] [LVU] Introduce location views Alexandre Oliva
2017-11-13 10:18                   ` Richard Biener
2017-11-15  3:59                     ` Alexandre Oliva
2017-12-11 23:12                   ` Jeff Law
2017-12-12  2:52                     ` Alexandre Oliva
2018-01-24 17:36                       ` Jakub Jelinek
2018-01-25 20:19                         ` Alexandre Oliva
2018-01-26 14:58                           ` Jakub Jelinek
2018-01-30 18:40                             ` Alexandre Oliva
2018-01-30 22:11                               ` Richard Sandiford
2018-02-07  4:14                                 ` Alexandre Oliva
2018-02-07  7:43                           ` Alexandre Oliva
2018-02-06 21:13                       ` Jason Merrill
2018-02-07  4:02                         ` Alexandre Oliva
2018-02-07 19:23                           ` Jason Merrill
2018-02-08 12:56                             ` Alexandre Oliva
2018-02-08 16:05                               ` Jason Merrill
2018-02-09  3:49                                 ` Alexandre Oliva
2018-02-07  7:35                         ` Alexandre Oliva
2018-02-07  7:36                         ` Alexandre Oliva
2018-02-08 19:58                           ` Jason Merrill
2018-02-09  3:20                             ` Alexandre Oliva
2018-02-11 19:04                               ` Andreas Schwab
2018-02-11 20:47                               ` Andreas Schwab
2018-02-12  7:46                                 ` Alexandre Oliva
2018-02-12  7:49                                 ` Alexandre Oliva
2018-02-12 10:11                                   ` Andreas Schwab
2018-02-13  5:47                                     ` Alexandre Oliva
2018-02-14  9:23                                       ` Andreas Schwab
2017-11-10  5:29                 ` [SFN+LVU+IEPM v4 9/9] [IEPM] Introduce inline entry point markers Alexandre Oliva
2017-12-12  2:54                   ` Alexandre Oliva
2017-12-21  5:18                     ` Jeff Law
2018-01-24  7:11                       ` Alexandre Oliva
2018-01-24 17:40                     ` Jakub Jelinek
2018-01-25 20:14                       ` Alexandre Oliva
2018-02-09  3:21                         ` Alexandre Oliva
2018-02-09  3:53                           ` Alan Modra
2018-02-09  4:13                             ` Jeff Law
2018-02-09 10:35                               ` Alexandre Oliva
2018-02-09 12:10                                 ` Alan Modra
2018-02-09 15:09                                 ` Jeff Law
2018-02-09 22:52                                   ` Joseph Myers
2018-02-10  1:36                                     ` Joseph Myers
2018-02-10 12:35                                       ` Alexandre Oliva
2018-02-10 18:19                                         ` Jeff Law
2018-02-11 15:29                                           ` Alexandre Oliva
2018-02-09 21:01                               ` Alexandre Oliva
2018-02-09 23:49                                 ` Jakub Jelinek
2018-02-10  0:56                                   ` Alexandre Oliva
2018-02-12  8:08                                     ` Alexandre Oliva
2018-02-13 13:52                                       ` Alexandre Oliva
2018-02-13 16:15                                         ` Jeff Law
2018-02-15 15:23                                         ` Szabolcs Nagy
2018-02-21 10:12                                           ` Alexandre Oliva
2018-02-21 12:08                                             ` Uros Bizjak
2018-02-22 15:22                                             ` Szabolcs Nagy
2018-02-28  6:17                                             ` Alexandre Oliva
2018-03-09  9:49                                               ` Bin.Cheng
2018-03-09  9:55                                                 ` Ramana Radhakrishnan
2018-03-09 11:35                                                 ` Jakub Jelinek
2018-03-07 19:43                                             ` Jeff Law
2018-02-10  4:39                                 ` Alexandre Oliva
2018-02-10  6:35                                   ` Jeff Law
2018-02-10 13:05                                     ` Alexandre Oliva
2018-02-10 16:36                                       ` Jeff Law
2018-02-21 10:33                       ` Alexandre Oliva
2018-02-26 12:47                         ` Richard Biener
2017-11-10 21:31                 ` SFN+LVU+IEPM v4 Alexandre Oliva
2017-08-22 22:44       ` Statement Frontier Notes, Location Views, and Inlined Entry Point Markers Alexandre Oliva
2017-08-23 12:33         ` Richard Biener
2017-08-25 16:41           ` Alexandre Oliva
2017-09-07 21:44             ` Joseph Myers
2017-09-21  2:24               ` Alexandre Oliva

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).