On Fri, Nov 10, 2017 at 3:34 AM, Alexandre Oliva <aol...@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
>

Reply via email to