[PATCH 7/9] [LVU] Introduce location views

Alexandre Oliva aoliva@redhat.com
Fri Sep 1 01:16:00 GMT 2017


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



More information about the Gcc-patches mailing list