On Fri, Nov 10, 2017 at 3:34 AM, Alexandre Oliva <[email protected]> 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
>