From: Alexandre Oliva Date: Fri, 9 Feb 2018 02:21:57 +0000 (+0000) Subject: [LVU] Introduce location views X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bd2b9f1e2d67ec8e88c977154ecfee34fa2bebe3;p=gcc.git [LVU] Introduce location views This patch introduces an option to enable the generation of location views along with location lists. The exact format depends on the DWARF version: it can be a separate attribute (DW_AT_GNU_locviews) or (DW_LLE_view_pair) entries in DWARF5+ loclists. Line number tables are also affected. If the assembler is found, at compiler build time, to support .loc views, we use them and assembler-computed view labels, otherwise we output compiler-generated line number programs with conservatively-computed view labels. In either case, we output view information next to line number changes when verbose assembly output is requested. This patch requires an LVU patch that modifies the exported API of final_scan_insn. It also expects the entire SFN patchset to be installed first, although SFN is not a requirement for LVU. for include/ChangeLog * dwarf2.def (DW_AT_GNU_locviews): New. * dwarf2.h (enum dwarf_location_list_entry_type): Add DW_LLE_GNU_view_pair. (DW_LLE_view_pair): Define. for gcc/ChangeLog * common.opt (gvariable-location-views): New. (gvariable-location-views=incompat5): New. * config.in: Rebuilt. * configure: Rebuilt. * configure.ac: Test assembler for view support. * dwarf2asm.c (dw2_asm_output_symname_uleb128): New. * dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare. * dwarf2out.c (var_loc_view): New typedef. (struct dw_loc_list_struct): Add vl_symbol, vbegin, vend. (dwarf2out_locviews_in_attribute): New. (dwarf2out_locviews_in_loclist): New. (dw_val_equal_p): Compare val_view_list of dw_val_class_view_lists. (enum dw_line_info_opcode): Add LI_adv_address. (struct dw_line_info_table): Add view. (RESET_NEXT_VIEW, RESETTING_VIEW_P): New macros. (DWARF2_ASM_VIEW_DEBUG_INFO): Define default. (zero_view_p): New variable. (ZERO_VIEW_P): New macro. (output_asm_line_debug_info): New. (struct var_loc_node): Add view. (add_AT_view_list, AT_loc_list): New. (add_var_loc_to_decl): Add view param. Test it against last. (new_loc_list): Add view params. Record them. (AT_loc_list_ptr): Handle loc and view lists. (view_list_to_loc_list_val_node): New. (print_dw_val): Handle dw_val_class_view_list. (size_of_die): Likewise. (value_format): Likewise. (loc_list_has_views): New. (gen_llsym): Set vl_symbol too. (maybe_gen_llsym, skip_loc_list_entry): New. (dwarf2out_maybe_output_loclist_view_pair): New. (output_loc_list): Output view list or entries too. (output_view_list_offset): New. (output_die): Handle dw_val_class_view_list. (output_dwarf_version): New. (output_compilation_unit_header): Use it. (output_skeleton_debug_sections): Likewise. (output_rnglists, output_line_info): Likewise. (output_pubnames, output_aranges): Update version comments. (output_one_line_info_table): Output view numbers in asm comments. (dw_loc_list): Determine current endview, pass it to new_loc_list. Call maybe_gen_llsym. (loc_list_from_tree_1): Adjust. (add_AT_location_description): Create view list attribute if needed, check it's absent otherwise. (convert_cfa_to_fb_loc_list): Adjust. (maybe_emit_file): Call output_asm_line_debug_info for test. (dwarf2out_var_location): Reset views as needed. Precompute add_var_loc_to_decl args. Call get_attr_min_length only if we have the attribute. Set view. (new_line_info_table): Reset next view. (set_cur_line_info_table): Call output_asm_line_debug_info for test. (dwarf2out_source_line): Likewise. Output view resets and labels to the assembler, or select appropriate line info opcodes. (prune_unused_types_walk_attribs): Handle dw_val_class_view_list. (optimize_string_length): Catch it. Adjust. (resolve_addr): Copy vl_symbol along with ll_symbol. Handle dw_val_class_view_list, and remove it if no longer needed. (hash_loc_list): Hash view numbers. (loc_list_hasher::equal): Compare them. (optimize_location_lists): Check whether a view list symbol is needed, and whether the locview attribute is present, and whether they match. Remove the locview attribute if no longer needed. (index_location_lists): Call skip_loc_list_entry for test. (dwarf2out_finish): Call output_asm_line_debug_info for test. Use output_dwarf_version. * dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list. (struct dw_val_node): Add val_view_list. * final.c (SEEN_NEXT_VIEW): New. (set_next_view_needed): New. (clear_next_view_needed): New. (maybe_output_next_view): New. (final_start_function): Rename to... (final_start_function_1): ... this. Take pointer to FIRST, add SEEN parameter. Emit param bindings in the initial view. (final_start_function): Reintroduce SEEN-less interface. (final): Rename to... (final_1): ... this. Take SEEN parameter. Output final pending next view at the end. (final): Reintroduce seen-less interface. (final_scan_insn): Output pending next view before switching sections or ending a block. Mark the next view as needed when outputting variable locations. Notify debug backend of section changes, and of location view changes. (rest_of_handle_final): Adjust. * toplev.c (process_options): Autodetect value for debug variable location views option. Warn on incompat5 without -gdwarf-5. * doc/invoke.texi (gvariable-location-views): New. (gvariable-location-views=incompat5): New. (gno-variable-location-views): New. From-SVN: r257510 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8212952e8d8..1d9c97298e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,98 @@ +2018-02-09 Alexandre Oliva + + * common.opt (gvariable-location-views): New. + (gvariable-location-views=incompat5): New. + * config.in: Rebuilt. + * configure: Rebuilt. + * configure.ac: Test assembler for view support. + * dwarf2asm.c (dw2_asm_output_symname_uleb128): New. + * dwarf2asm.h (dw2_asm_output_symname_uleb128): Declare. + * dwarf2out.c (var_loc_view): New typedef. + (struct dw_loc_list_struct): Add vl_symbol, vbegin, vend. + (dwarf2out_locviews_in_attribute): New. + (dwarf2out_locviews_in_loclist): New. + (dw_val_equal_p): Compare val_view_list of dw_val_class_view_lists. + (enum dw_line_info_opcode): Add LI_adv_address. + (struct dw_line_info_table): Add view. + (RESET_NEXT_VIEW, RESETTING_VIEW_P): New macros. + (DWARF2_ASM_VIEW_DEBUG_INFO): Define default. + (zero_view_p): New variable. + (ZERO_VIEW_P): New macro. + (output_asm_line_debug_info): New. + (struct var_loc_node): Add view. + (add_AT_view_list, AT_loc_list): New. + (add_var_loc_to_decl): Add view param. Test it against last. + (new_loc_list): Add view params. Record them. + (AT_loc_list_ptr): Handle loc and view lists. + (view_list_to_loc_list_val_node): New. + (print_dw_val): Handle dw_val_class_view_list. + (size_of_die): Likewise. + (value_format): Likewise. + (loc_list_has_views): New. + (gen_llsym): Set vl_symbol too. + (maybe_gen_llsym, skip_loc_list_entry): New. + (dwarf2out_maybe_output_loclist_view_pair): New. + (output_loc_list): Output view list or entries too. + (output_view_list_offset): New. + (output_die): Handle dw_val_class_view_list. + (output_dwarf_version): New. + (output_compilation_unit_header): Use it. + (output_skeleton_debug_sections): Likewise. + (output_rnglists, output_line_info): Likewise. + (output_pubnames, output_aranges): Update version comments. + (output_one_line_info_table): Output view numbers in asm comments. + (dw_loc_list): Determine current endview, pass it to new_loc_list. + Call maybe_gen_llsym. + (loc_list_from_tree_1): Adjust. + (add_AT_location_description): Create view list attribute if + needed, check it's absent otherwise. + (convert_cfa_to_fb_loc_list): Adjust. + (maybe_emit_file): Call output_asm_line_debug_info for test. + (dwarf2out_var_location): Reset views as needed. Precompute + add_var_loc_to_decl args. Call get_attr_min_length only if we have the + attribute. Set view. + (new_line_info_table): Reset next view. + (set_cur_line_info_table): Call output_asm_line_debug_info for test. + (dwarf2out_source_line): Likewise. Output view resets and labels to + the assembler, or select appropriate line info opcodes. + (prune_unused_types_walk_attribs): Handle dw_val_class_view_list. + (optimize_string_length): Catch it. Adjust. + (resolve_addr): Copy vl_symbol along with ll_symbol. Handle + dw_val_class_view_list, and remove it if no longer needed. + (hash_loc_list): Hash view numbers. + (loc_list_hasher::equal): Compare them. + (optimize_location_lists): Check whether a view list symbol is + needed, and whether the locview attribute is present, and + whether they match. Remove the locview attribute if no longer + needed. + (index_location_lists): Call skip_loc_list_entry for test. + (dwarf2out_finish): Call output_asm_line_debug_info for test. + Use output_dwarf_version. + * dwarf2out.h (enum dw_val_class): Add dw_val_class_view_list. + (struct dw_val_node): Add val_view_list. + * final.c (SEEN_NEXT_VIEW): New. + (set_next_view_needed): New. + (clear_next_view_needed): New. + (maybe_output_next_view): New. + (final_start_function): Rename to... + (final_start_function_1): ... this. Take pointer to FIRST, + add SEEN parameter. Emit param bindings in the initial view. + (final_start_function): Reintroduce SEEN-less interface. + (final): Rename to... + (final_1): ... this. Take SEEN parameter. Output final pending + next view at the end. + (final): Reintroduce seen-less interface. + (final_scan_insn): Output pending next view before switching + sections or ending a block. Mark the next view as needed when + outputting variable locations. Notify debug backend of section + changes, and of location view changes. + (rest_of_handle_final): Adjust. + * toplev.c (process_options): Autodetect value for debug variable + location views option. Warn on incompat5 without -gdwarf-5. + * doc/invoke.texi (gvariable-location-views): New. + (gvariable-location-views=incompat5): New. + (gno-variable-location-views): New. + 2018-02-08 David Malcolm PR tree-optimization/84136 diff --git a/gcc/common.opt b/gcc/common.opt index 3e9e3101c8f..40ec0088c57 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2956,6 +2956,13 @@ gtoggle Common Driver Report Var(flag_gtoggle) Toggle debug information generation. +gvariable-location-views +Common Driver Var(debug_variable_location_views, 1) Init(2) +Augment variable location lists with progressive views. + +gvariable-location-views=incompat5 +Common Driver RejectNegative Var(debug_variable_location_views, -1) Init(2) + gvms Common Driver JoinedOrMissing Negative(gxcoff) Generate debug information in VMS format. diff --git a/gcc/config.in b/gcc/config.in index 8dc453104c1..5bccb408016 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 3360209559b..b12628725b6 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27825,6 +27825,52 @@ $as_echo "$gcc_cv_as_dwarf2_file_buggy" >&6; } $as_echo "#define HAVE_AS_DWARF2_DEBUG_LINE 1" >>confdefs.h + + if test $gcc_cv_as_leb128 = yes; then + conftest_s="\ + .file 1 \"conftest.s\" + .loc 1 3 0 view .LVU1 + $insn + .data + .uleb128 .LVU1 + .uleb128 .LVU1 +" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for dwarf2 debug_view support" >&5 +$as_echo_n "checking assembler for dwarf2 debug_view support... " >&6; } +if test "${gcc_cv_as_dwarf2_debug_view+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_dwarf2_debug_view=no + if test $in_tree_gas = yes; then + if test $in_tree_gas_is_elf = yes \ + && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 27 \) \* 1000 + 0` + then gcc_cv_as_dwarf2_debug_view=yes +fi + elif test x$gcc_cv_as != x; then + $as_echo "$conftest_s" > conftest.s + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_dwarf2_debug_view=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_dwarf2_debug_view" >&5 +$as_echo "$gcc_cv_as_dwarf2_debug_view" >&6; } +if test $gcc_cv_as_dwarf2_debug_view = yes; then + +$as_echo "#define HAVE_AS_DWARF2_DEBUG_VIEW 1" >>confdefs.h + +fi + fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for --gdwarf2 option" >&5 diff --git a/gcc/configure.ac b/gcc/configure.ac index 1019b315262..140c804412a 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4902,9 +4902,25 @@ if test x"$insn" != x; then if test $gcc_cv_as_dwarf2_debug_line = yes \ && test $gcc_cv_as_dwarf2_file_buggy = no; then - AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1, + AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1, [Define if your assembler supports dwarf2 .file/.loc directives, and preserves file table indices exactly as given.]) + + if test $gcc_cv_as_leb128 = yes; then + conftest_s="\ + .file 1 \"conftest.s\" + .loc 1 3 0 view .LVU1 + $insn + .data + .uleb128 .LVU1 + .uleb128 .LVU1 +" + gcc_GAS_CHECK_FEATURE([dwarf2 debug_view support], + gcc_cv_as_dwarf2_debug_view, + [elf,2,27,0],,[$conftest_s],, + [AC_DEFINE(HAVE_AS_DWARF2_DEBUG_VIEW, 1, + [Define if your assembler supports views in dwarf2 .loc directives.])]) + fi fi gcc_GAS_CHECK_FEATURE([--gdwarf2 option], diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 367b99bc95c..df357bea7dc 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -348,6 +348,7 @@ Objective-C and Objective-C++ Dialects}. -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol -gcolumn-info -gno-column-info @gol -gstatement-frontiers -gno-statement-frontiers @gol +-gvariable-location-views -gno-variable-location-views @gol -gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol -fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol -fno-eliminate-unused-debug-types @gol @@ -7255,6 +7256,34 @@ markers in the line number table. This is enabled by default when compiling with optimization (@option{-Os}, @option{-O}, @option{-O2}, @dots{}), and outputting DWARF 2 debug information at the normal level. +@item -gvariable-location-views +@item -gvariable-location-views=incompat5 +@item -gno-variable-location-views +@opindex gvariable-location-views +@opindex gvariable-location-views=incompat5 +@opindex gno-variable-location-views +Augment variable location lists with progressive view numbers implied +from the line number table. This enables debug information consumers to +inspect state at certain points of the program, even if no instructions +associated with the corresponding source locations are present at that +point. If the assembler lacks support for view numbers in line number +tables, this will cause the compiler to emit the line number table, +which generally makes them somewhat less compact. The augmented line +number tables and location lists are fully backward-compatible, so they +can be consumed by debug information consumers that are not aware of +these augmentations, but they won't derive any benefit from them either. +This is enabled by default when outputting DWARF 2 debug information at +the normal level, as long as @option{-fvar-tracking-assignments} is +enabled and @option{-gstrict-dwarf} is not. + +There is a proposed representation for view numbers that is not backward +compatible with the location list format introduced in DWARF 5, that can +be enabled with @option{-gvariable-location-views=incompat5}. This +option may be removed in the future, is only provided as a reference +implementation of the proposed representation. Debug information +consumers are not expected to support this extended format, and they +would be rendered unable to decode location lists using it. + @item -gz@r{[}=@var{type}@r{]} @opindex gz Produce compressed debug sections in DWARF format, if that is supported. diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c index 9952e0a9850..e9b18b8b785 100644 --- a/gcc/dwarf2asm.c +++ b/gcc/dwarf2asm.c @@ -767,6 +767,35 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value, va_end (ap); } +/* Output symbol LAB1 as an unsigned LEB128 quantity. LAB1 should be + an assembler-computed constant, e.g. a view number, because we + can't have relocations in LEB128 quantities. */ + +void +dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED, + const char *comment, ...) +{ + va_list ap; + + va_start (ap, comment); + +#ifdef HAVE_AS_LEB128 + fputs ("\t.uleb128 ", asm_out_file); + assemble_name (asm_out_file, lab1); +#else + gcc_unreachable (); +#endif + + if (flag_debug_asm && comment) + { + fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START); + vfprintf (asm_out_file, comment, ap); + } + fputc ('\n', asm_out_file); + + va_end (ap); +} + void dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED, const char *lab2 ATTRIBUTE_UNUSED, diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h index b5ed449205e..1b76909a1c9 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 948b3cbe591..56d3e14b81b 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1291,6 +1291,8 @@ struct GTY((for_user)) addr_table_entry { GTY ((desc ("%1.kind"))) addr; }; +typedef unsigned int var_loc_view; + /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over their entire life. */ @@ -1300,9 +1302,11 @@ typedef struct GTY(()) dw_loc_list_struct { addr_table_entry *begin_entry; const char *end; /* Label for end of range */ char *ll_symbol; /* Label for beginning of location list. - Only on head of list */ + Only on head of list. */ + char *vl_symbol; /* Label for beginning of view list. Ditto. */ const char *section; /* Section this loclist is relative to */ dw_loc_descr_ref expr; + var_loc_view vbegin, vend; hashval_t hash; /* True if all addresses in this and subsequent lists are known to be resolved. */ @@ -1339,6 +1343,29 @@ dwarf_stack_op_name (unsigned int op) return "OP_"; } +/* Return TRUE iff we're to output location view lists as a separate + attribute next to the location lists, as an extension compatible + with DWARF 2 and above. */ + +static inline bool +dwarf2out_locviews_in_attribute () +{ + return debug_variable_location_views == 1; +} + +/* Return TRUE iff we're to output location view lists as part of the + location lists, as proposed for standardization after DWARF 5. */ + +static inline bool +dwarf2out_locviews_in_loclist () +{ +#ifndef DW_LLE_view_pair + return false; +#else + return debug_variable_location_views == -1; +#endif +} + /* Return a pointer to a newly allocated location description. Location descriptions are simple expression terms that can be strung together to form more complicated location (address) descriptions. */ @@ -1401,6 +1428,8 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b) return a->v.val_loc == b->v.val_loc; case dw_val_class_loc_list: return a->v.val_loc_list == b->v.val_loc_list; + case dw_val_class_view_list: + return a->v.val_view_list == b->v.val_view_list; case dw_val_class_die_ref: return a->v.val_die_ref.die == b->v.val_die_ref.die; case dw_val_class_fde_ref: @@ -2875,7 +2904,15 @@ enum dw_line_info_opcode { LI_set_epilogue_begin, /* Emit a DW_LNE_set_discriminator. */ - LI_set_discriminator + LI_set_discriminator, + + /* Output a Fixed Advance PC; the target PC is the label index; the + base PC is the previous LI_adv_address or LI_set_address entry. + We only use this when emitting debug views without assembler + support, at explicit user request. Ideally, we should only use + it when the offset might be zero but we can't tell: it's the only + way to maybe change the PC without resetting the view number. */ + LI_adv_address }; typedef struct GTY(()) dw_line_info_struct { @@ -2897,6 +2934,25 @@ struct GTY(()) dw_line_info_table { bool is_stmt; bool in_use; + /* This denotes the NEXT view number. + + If it is 0, it is known that the NEXT view will be the first view + at the given PC. + + If it is -1, we've advanced PC but we haven't emitted a line location yet, + so we shouldn't use this view number. + + The meaning of other nonzero values depends on whether we're + computing views internally or leaving it for the assembler to do + so. If we're emitting them internally, view denotes the view + number since the last known advance of PC. If we're leaving it + for the assembler, it denotes the LVU label number that we're + going to ask the assembler to assign. */ + var_loc_view view; + +#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0) +#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0) + vec *entries; }; @@ -3098,6 +3154,71 @@ skeleton_chain_node; #endif #endif +/* Use assembler views in line directives if available. */ +#ifndef DWARF2_ASM_VIEW_DEBUG_INFO +#ifdef HAVE_AS_DWARF2_DEBUG_VIEW +#define DWARF2_ASM_VIEW_DEBUG_INFO 1 +#else +#define DWARF2_ASM_VIEW_DEBUG_INFO 0 +#endif +#endif + +/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported + view computation, and it refers to a view identifier for which we + will not emit a label because it is known to map to a view number + zero. We won't allocate the bitmap if we're not using assembler + support for location views, but we have to make the variable + visible for GGC and for code that will be optimized out for lack of + support but that's still parsed and compiled. We could abstract it + out with macros, but it's not worth it. */ +static GTY(()) bitmap zero_view_p; + +/* Evaluate to TRUE iff N is known to identify the first location view + at its PC. When not using assembler location view computation, + that must be view number zero. Otherwise, ZERO_VIEW_P is allocated + and views label numbers recorded in it are the ones known to be + zero. */ +#define ZERO_VIEW_P(N) (zero_view_p \ + ? bitmap_bit_p (zero_view_p, (N)) \ + : (N) == 0) + +/* Return true iff we're to emit .loc directives for the assembler to + generate line number sections. + + When we're not emitting views, all we need from the assembler is + support for .loc directives. + + If we are emitting views, we can only use the assembler's .loc + support if it also supports views. + + When the compiler is emitting the line number programs and + computing view numbers itself, it resets view numbers at known PC + changes and counts from that, and then it emits view numbers as + literal constants in locviewlists. There are cases in which the + compiler is not sure about PC changes, e.g. when extra alignment is + requested for a label. In these cases, the compiler may not reset + the view counter, and the potential PC advance in the line number + program will use an opcode that does not reset the view counter + even if the PC actually changes, so that compiler and debug info + consumer can keep view numbers in sync. + + When the compiler defers view computation to the assembler, it + emits symbolic view numbers in locviewlists, with the exception of + views known to be zero (forced resets, or reset after + compiler-visible PC changes): instead of emitting symbols for + these, we emit literal zero and assert the assembler agrees with + the compiler's assessment. We could use symbolic views everywhere, + instead of special-casing zero views, but then we'd be unable to + optimize out locviewlists that contain only zeros. */ + +static bool +output_asm_line_debug_info (void) +{ + return (DWARF2_ASM_VIEW_DEBUG_INFO + || (DWARF2_ASM_LINE_DEBUG_INFO + && !debug_variable_location_views)); +} + /* Minimum line offset in a special line info. opcode. This value was chosen to give a reasonable range of values. */ #define DWARF_LINE_BASE -10 @@ -3207,6 +3328,7 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node { rtx GTY (()) loc; const char * GTY (()) label; struct var_loc_node * GTY (()) next; + var_loc_view view; }; /* Variable location list. */ @@ -3415,6 +3537,8 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_node *); static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute, dw_loc_list_ref); static inline dw_loc_list_ref AT_loc_list (dw_attr_node *); +static void add_AT_view_list (dw_die_ref, enum dwarf_attribute); +static inline dw_loc_list_ref AT_loc_list (dw_attr_node *); static addr_table_entry *add_addr_table_entry (void *, enum ate_kind); static void remove_addr_table_entry (addr_table_entry *); static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool); @@ -3451,7 +3575,7 @@ static void equate_type_number_to_die (tree, dw_die_ref); static dw_die_ref lookup_decl_die (tree); static var_loc_list *lookup_decl_loc (const_tree); static void equate_decl_number_to_die (tree, dw_die_ref); -static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *); +static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *, var_loc_view); static void print_spaces (FILE *); static void print_die (dw_die_ref, FILE *); static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *); @@ -3651,8 +3775,8 @@ static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage); static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage); static void splice_child_die (dw_die_ref, dw_die_ref); static int file_info_cmp (const void *, const void *); -static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, - const char *, const char *); +static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, var_loc_view, + const char *, var_loc_view, const char *); static void output_loc_list (dw_loc_list_ref); static char *gen_internal_sym (const char *); static bool want_pubnames (void); @@ -4648,11 +4772,65 @@ AT_loc_list (dw_attr_node *a) return a->dw_attr_val.v.val_loc_list; } +/* Add a view list attribute to DIE. It must have a DW_AT_location + attribute, because the view list complements the location list. */ + +static inline void +add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind) +{ + dw_attr_node attr; + + if (XCOFF_DEBUGGING_INFO && !HAVE_XCOFF_DWARF_EXTRAS) + return; + + attr.dw_attr = attr_kind; + attr.dw_attr_val.val_class = dw_val_class_view_list; + attr.dw_attr_val.val_entry = NULL; + attr.dw_attr_val.v.val_view_list = die; + add_dwarf_attr (die, &attr); + gcc_checking_assert (get_AT (die, DW_AT_location)); + gcc_assert (have_location_lists); +} + +/* Return a pointer to the location list referenced by the attribute. + If the named attribute is a view list, look up the corresponding + DW_AT_location attribute and return its location list. */ + static inline dw_loc_list_ref * AT_loc_list_ptr (dw_attr_node *a) { - gcc_assert (a && AT_class (a) == dw_val_class_loc_list); - return &a->dw_attr_val.v.val_loc_list; + gcc_assert (a); + switch (AT_class (a)) + { + case dw_val_class_loc_list: + return &a->dw_attr_val.v.val_loc_list; + case dw_val_class_view_list: + { + dw_attr_node *l; + l = get_AT (a->dw_attr_val.v.val_view_list, DW_AT_location); + if (!l) + return NULL; + gcc_checking_assert (l + 1 == a); + return AT_loc_list_ptr (l); + } + default: + gcc_unreachable (); + } +} + +/* Return the location attribute value associated with a view list + attribute value. */ + +static inline dw_val_node * +view_list_to_loc_list_val_node (dw_val_node *val) +{ + gcc_assert (val->val_class == dw_val_class_view_list); + dw_attr_node *loc = get_AT (val->v.val_view_list, DW_AT_location); + if (!loc) + return NULL; + gcc_checking_assert (&(loc + 1)->dw_attr_val == val); + gcc_assert (AT_class (loc) == dw_val_class_loc_list); + return &loc->dw_attr_val; } struct addr_hasher : ggc_ptr_hash @@ -5907,7 +6085,7 @@ adjust_piece_list (rtx *dest, rtx *src, rtx *inner, /* Add a variable location node to the linked list for DECL. */ static struct var_loc_node * -add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) +add_var_loc_to_decl (tree decl, rtx loc_note, const char *label, var_loc_view view) { unsigned int decl_id; var_loc_list *temp; @@ -5996,7 +6174,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) /* TEMP->LAST here is either pointer to the last but one or last element in the chained list, LAST is pointer to the last element. */ - if (label && strcmp (last->label, label) == 0) + if (label && strcmp (last->label, label) == 0 && last->view == view) { /* For SRA optimized variables if there weren't any real insns since last note, just modify the last node. */ @@ -6012,7 +6190,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) temp->last->next = NULL; unused = last; last = temp->last; - gcc_assert (strcmp (last->label, label) != 0); + gcc_assert (strcmp (last->label, label) != 0 || last->view != view); } else { @@ -6147,6 +6325,12 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile) fprintf (outfile, "location list -> label:%s", val->v.val_loc_list->ll_symbol); break; + case dw_val_class_view_list: + val = view_list_to_loc_list_val_node (val); + fprintf (outfile, "location list with views -> labels:%s and %s", + val->v.val_loc_list->ll_symbol, + val->v.val_loc_list->vl_symbol); + break; case dw_val_class_range_list: fprintf (outfile, "range list"); break; @@ -9007,6 +9191,7 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: + case dw_val_class_view_list: if (dwarf_split_debug_info && dwarf_version >= 5) { gcc_assert (AT_loc_list (a)->num_assigned); @@ -9378,6 +9563,7 @@ value_format (dw_attr_node *a) gcc_unreachable (); } case dw_val_class_loc_list: + case dw_val_class_view_list: if (dwarf_split_debug_info && dwarf_version >= 5 && AT_loc_list (a)->num_assigned) @@ -9652,7 +9838,8 @@ output_abbrev_section (void) expression. */ static inline dw_loc_list_ref -new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, +new_loc_list (dw_loc_descr_ref expr, const char *begin, var_loc_view vbegin, + const char *end, var_loc_view vend, const char *section) { dw_loc_list_ref retlist = ggc_cleared_alloc (); @@ -9662,10 +9849,28 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, retlist->end = end; retlist->expr = expr; retlist->section = section; + retlist->vbegin = vbegin; + retlist->vend = vend; return retlist; } +/* Return true iff there's any nonzero view number in the loc list. */ + +static bool +loc_list_has_views (dw_loc_list_ref list) +{ + if (!debug_variable_location_views) + return false; + + for (dw_loc_list_ref loc = list; + loc != NULL; loc = loc->dw_loc_next) + if (!ZERO_VIEW_P (loc->vbegin) || !ZERO_VIEW_P (loc->vend)) + return true; + + return false; +} + /* Generate a new internal symbol for this location list node, if it hasn't got one yet. */ @@ -9674,6 +9879,98 @@ gen_llsym (dw_loc_list_ref list) { gcc_assert (!list->ll_symbol); list->ll_symbol = gen_internal_sym ("LLST"); + + if (!loc_list_has_views (list)) + return; + + if (dwarf2out_locviews_in_attribute ()) + { + /* Use the same label_num for the view list. */ + label_num--; + list->vl_symbol = gen_internal_sym ("LVUS"); + } + else + list->vl_symbol = list->ll_symbol; +} + +/* Generate a symbol for the list, but only if we really want to emit + it as a list. */ + +static inline void +maybe_gen_llsym (dw_loc_list_ref list) +{ + if (!list || (!list->dw_loc_next && !loc_list_has_views (list))) + return; + + gen_llsym (list); +} + +/* Determine whether or not to skip loc_list entry CURR. If we're not + to skip it, and SIZEP is non-null, store the size of CURR->expr's + representation in *SIZEP. */ + +static bool +skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0) +{ + /* Don't output an entry that starts and ends at the same address. */ + if (strcmp (curr->begin, curr->end) == 0 + && curr->vbegin == curr->vend && !curr->force) + return true; + + unsigned long size = size_of_locs (curr->expr); + + /* If the expression is too large, drop it on the floor. We could + perhaps put it into DW_TAG_dwarf_procedure and refer to that + in the expression, but >= 64KB expressions for a single value + in a single range are unlikely very useful. */ + if (dwarf_version < 5 && size > 0xffff) + return true; + + if (sizep) + *sizep = size; + + return false; +} + +/* Output a view pair loclist entry for CURR, if it requires one. */ + +static void +dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr) +{ + if (!dwarf2out_locviews_in_loclist ()) + return; + + if (ZERO_VIEW_P (curr->vbegin) && ZERO_VIEW_P (curr->vend)) + return; + +#ifdef DW_LLE_view_pair + dw2_asm_output_data (1, DW_LLE_view_pair, "DW_LLE_view_pair"); + +# if DWARF2_ASM_VIEW_DEBUG_INFO + if (ZERO_VIEW_P (curr->vbegin)) + dw2_asm_output_data_uleb128 (0, "Location view begin"); + else + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin); + dw2_asm_output_symname_uleb128 (label, "Location view begin"); + } + + if (ZERO_VIEW_P (curr->vend)) + dw2_asm_output_data_uleb128 (0, "Location view end"); + else + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend); + dw2_asm_output_symname_uleb128 (label, "Location view end"); + } +# else /* !DWARF2_ASM_VIEW_DEBUG_INFO */ + dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin"); + dw2_asm_output_data_uleb128 (curr->vend, "Location view end"); +# endif /* DWARF2_ASM_VIEW_DEBUG_INFO */ +#endif /* DW_LLE_view_pair */ + + return; } /* Output the location list given to us. */ @@ -9681,34 +9978,85 @@ gen_llsym (dw_loc_list_ref list) static void output_loc_list (dw_loc_list_ref list_head) { + int vcount = 0, lcount = 0; + if (list_head->emitted) return; list_head->emitted = true; + if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ()) + { + ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol); + + for (dw_loc_list_ref curr = list_head; curr != NULL; + curr = curr->dw_loc_next) + { + if (skip_loc_list_entry (curr)) + continue; + + vcount++; + + /* ?? dwarf_split_debug_info? */ +#if DWARF2_ASM_VIEW_DEBUG_INFO + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (!ZERO_VIEW_P (curr->vbegin)) + { + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin); + dw2_asm_output_symname_uleb128 (label, + "View list begin (%s)", + list_head->vl_symbol); + } + else + dw2_asm_output_data_uleb128 (0, + "View list begin (%s)", + list_head->vl_symbol); + + if (!ZERO_VIEW_P (curr->vend)) + { + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend); + dw2_asm_output_symname_uleb128 (label, + "View list end (%s)", + list_head->vl_symbol); + } + else + dw2_asm_output_data_uleb128 (0, + "View list end (%s)", + list_head->vl_symbol); +#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */ + dw2_asm_output_data_uleb128 (curr->vbegin, + "View list begin (%s)", + list_head->vl_symbol); + dw2_asm_output_data_uleb128 (curr->vend, + "View list end (%s)", + list_head->vl_symbol); +#endif + } + } + ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol); - dw_loc_list_ref curr = list_head; const char *last_section = NULL; const char *base_label = NULL; /* Walk the location list, and output each range + expression. */ - for (curr = list_head; curr != NULL; curr = curr->dw_loc_next) + for (dw_loc_list_ref curr = list_head; curr != NULL; + curr = curr->dw_loc_next) { unsigned long size; - /* Don't output an entry that starts and ends at the same address. */ - if (strcmp (curr->begin, curr->end) == 0 && !curr->force) - continue; - size = size_of_locs (curr->expr); - /* If the expression is too large, drop it on the floor. We could - perhaps put it into DW_TAG_dwarf_procedure and refer to that - in the expression, but >= 64KB expressions for a single value - in a single range are unlikely very useful. */ - if (dwarf_version < 5 && size > 0xffff) + + /* Skip this entry? If we skip it here, we must skip it in the + view list above as well. */ + if (skip_loc_list_entry (curr, &size)) continue; + + lcount++; + if (dwarf_version >= 5) { if (dwarf_split_debug_info) { + dwarf2out_maybe_output_loclist_view_pair (curr); /* For -gsplit-dwarf, emit DW_LLE_starx_length, which has uleb128 index into .debug_addr and uleb128 length. */ dw2_asm_output_data (1, DW_LLE_startx_length, @@ -9726,6 +10074,7 @@ output_loc_list (dw_loc_list_ref list_head) } else if (!have_multiple_function_sections && HAVE_AS_LEB128) { + dwarf2out_maybe_output_loclist_view_pair (curr); /* If all code is in .text section, the base address is already provided by the CU attributes. Use DW_LLE_offset_pair where both addresses are uleb128 encoded @@ -9776,6 +10125,7 @@ output_loc_list (dw_loc_list_ref list_head) length. */ if (last_section == NULL) { + dwarf2out_maybe_output_loclist_view_pair (curr); dw2_asm_output_data (1, DW_LLE_start_length, "DW_LLE_start_length (%s)", list_head->ll_symbol); @@ -9790,6 +10140,7 @@ output_loc_list (dw_loc_list_ref list_head) DW_LLE_base_address. */ else { + dwarf2out_maybe_output_loclist_view_pair (curr); dw2_asm_output_data (1, DW_LLE_offset_pair, "DW_LLE_offset_pair (%s)", list_head->ll_symbol); @@ -9805,6 +10156,7 @@ output_loc_list (dw_loc_list_ref list_head) DW_LLE_start_end with a pair of absolute addresses. */ else { + dwarf2out_maybe_output_loclist_view_pair (curr); dw2_asm_output_data (1, DW_LLE_start_end, "DW_LLE_start_end (%s)", list_head->ll_symbol); @@ -9883,6 +10235,9 @@ output_loc_list (dw_loc_list_ref list_head) "Location list terminator end (%s)", list_head->ll_symbol); } + + gcc_assert (!list_head->vl_symbol + || vcount == lcount * (dwarf2out_locviews_in_attribute () ? 1 : 0)); } /* Output a range_list offset into the .debug_ranges or .debug_rnglists @@ -9947,6 +10302,22 @@ output_loc_list_offset (dw_attr_node *a) "%s", dwarf_attr_name (a->dw_attr)); } +/* Output the offset into the debug_loc section. */ + +static void +output_view_list_offset (dw_attr_node *a) +{ + char *sym = (*AT_loc_list_ptr (a))->vl_symbol; + + gcc_assert (sym); + if (dwarf_split_debug_info) + dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, + "%s", dwarf_attr_name (a->dw_attr)); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section, + "%s", dwarf_attr_name (a->dw_attr)); +} + /* Output an attribute's index or value appropriately. */ static void @@ -10172,6 +10543,10 @@ output_die (dw_die_ref die) output_loc_list_offset (a); break; + case dw_val_class_view_list: + output_view_list_offset (a); + break; + case dw_val_class_die_ref: if (AT_ref_external (a)) { @@ -10356,6 +10731,28 @@ output_die (dw_die_ref die) (unsigned long) die->die_offset); } +/* Output the dwarf version number. */ + +static void +output_dwarf_version () +{ + /* ??? For now, if -gdwarf-6 is specified, we output version 5 with + views in loclist. That will change eventually. */ + if (dwarf_version == 6) + { + static bool once; + if (!once) + { + warning (0, + "-gdwarf-6 is output as version 5 with incompatibilities"); + once = true; + } + dw2_asm_output_data (2, 5, "DWARF version number"); + } + else + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); +} + /* Output the compilation unit that appears at the beginning of the .debug_info section, and precedes the DIE descriptions. */ @@ -10372,7 +10769,7 @@ output_compilation_unit_header (enum dwarf_unit_type ut) "Length of Compilation Unit Info"); } - dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + output_dwarf_version (); if (dwarf_version >= 5) { const char *name; @@ -10584,7 +10981,7 @@ output_skeleton_debug_sections (dw_die_ref comp_unit, - DWARF_INITIAL_LENGTH_SIZE + size_of_die (comp_unit), "Length of Compilation Unit Info"); - dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + output_dwarf_version (); if (dwarf_version >= 5) { dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton"); @@ -10883,7 +11280,7 @@ output_pubnames (vec *names) } /* Version number for pubnames/pubtypes is independent of dwarf version. */ - dw2_asm_output_data (2, 2, "DWARF Version"); + dw2_asm_output_data (2, 2, "DWARF pubnames/pubtypes version"); if (dwarf_split_debug_info) dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, @@ -10965,7 +11362,7 @@ output_aranges (void) } /* Version number for aranges is still 2, even up to DWARF5. */ - dw2_asm_output_data (2, 2, "DWARF Version"); + dw2_asm_output_data (2, 2, "DWARF aranges version"); if (dwarf_split_debug_info) dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, debug_skeleton_info_section, @@ -11230,7 +11627,7 @@ output_rnglists (unsigned generation) dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, "Length of Range Lists"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + output_dwarf_version (); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); dw2_asm_output_data (1, 0, "Segment Size"); /* Emit the offset table only for -gsplit-dwarf. If we don't care @@ -11864,8 +12261,11 @@ output_one_line_info_table (dw_line_info_table *table) char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; unsigned int current_line = 1; bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START; - dw_line_info_entry *ent; + dw_line_info_entry *ent, *prev_addr; size_t i; + unsigned int view; + + view = 0; FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent) { @@ -11880,14 +12280,36 @@ output_one_line_info_table (dw_line_info_table *table) to determine when it is safe to use DW_LNS_fixed_advance_pc. */ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val); + view = 0; + /* This can handle any delta. This takes 4+DWARF2_ADDR_SIZE bytes. */ - dw2_asm_output_data (1, 0, "set address %s", line_label); + dw2_asm_output_data (1, 0, "set address %s%s", line_label, + debug_variable_location_views + ? ", reset view to 0" : ""); dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); dw2_asm_output_data (1, DW_LNE_set_address, NULL); dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); + + prev_addr = ent; break; + case LI_adv_address: + { + ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val); + char prev_label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (prev_label, LINE_CODE_LABEL, prev_addr->val); + + view++; + + dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, "fixed advance PC, increment view to %i", view); + dw2_asm_output_delta (2, line_label, prev_label, + "from %s to %s", prev_label, line_label); + + prev_addr = ent; + break; + } + case LI_set_line: if (ent->val == current_line) { @@ -11995,7 +12417,7 @@ output_line_info (bool prologue_only) ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + output_dwarf_version (); if (dwarf_version >= 5) { dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); @@ -16453,6 +16875,7 @@ static dw_loc_list_ref dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) { const char *endname, *secname; + var_loc_view endview; rtx varloc; enum var_init_status initialized; struct var_loc_node *node; @@ -16517,24 +16940,27 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) && current_function_decl) { endname = cfun->fde->dw_fde_end; + endview = 0; range_across_switch = true; } /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ else if (node->next) - endname = node->next->label; + endname = node->next->label, endview = node->next->view; /* If the variable has a location at the last label it keeps its location until the end of function. */ else if (!current_function_decl) - endname = text_end_label; + endname = text_end_label, endview = 0; else { ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, current_function_funcdef_no); endname = ggc_strdup (label_id); + endview = 0; } - *listp = new_loc_list (descr, node->label, endname, secname); + *listp = new_loc_list (descr, node->label, node->view, + endname, endview, secname); if (TREE_CODE (decl) == PARM_DECL && node == loc_list->first && NOTE_P (node->loc) @@ -16569,11 +16995,11 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ if (node->next) - endname = node->next->label; + endname = node->next->label, endview = node->next->view; else - endname = cfun->fde->dw_fde_second_end; - *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, - endname, secname); + endname = cfun->fde->dw_fde_second_end, endview = 0; + *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, 0, + endname, endview, secname); listp = &(*listp)->dw_loc_next; } } @@ -16584,8 +17010,7 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) representable, we don't want to pretend a single entry that was applies to the entire scope in which the variable is available. */ - if (list && loc_list->first->next) - gen_llsym (list); + maybe_gen_llsym (list); return list; } @@ -17404,7 +17829,7 @@ loc_list_from_tree_1 (tree loc, int want_address, { if (dwarf_version >= 3 || !dwarf_strict) return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0), - NULL, NULL, NULL); + NULL, 0, NULL, 0, NULL); else return NULL; } @@ -18220,7 +18645,7 @@ loc_list_from_tree_1 (tree loc, int want_address, add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0)); } if (ret) - list_ret = new_loc_list (ret, NULL, NULL, NULL); + list_ret = new_loc_list (ret, NULL, 0, NULL, 0, NULL); return list_ret; } @@ -18544,12 +18969,25 @@ static inline void add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref descr) { + bool check_no_locviews = true; if (descr == 0) return; if (single_element_loc_list_p (descr)) add_AT_loc (die, attr_kind, descr->expr); else - add_AT_loc_list (die, attr_kind, descr); + { + add_AT_loc_list (die, attr_kind, descr); + gcc_assert (descr->ll_symbol); + if (attr_kind == DW_AT_location && descr->vl_symbol + && dwarf2out_locviews_in_attribute ()) + { + add_AT_view_list (die, DW_AT_GNU_locviews); + check_no_locviews = false; + } + } + + if (check_no_locviews) + gcc_assert (!get_AT (die, DW_AT_GNU_locviews)); } /* Add DW_AT_accessibility attribute to DIE if needed. */ @@ -19738,7 +20176,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) /* If the first partition contained no CFI adjustments, the CIE opcodes apply to the whole first partition. */ *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - fde->dw_fde_begin, fde->dw_fde_end, section); + fde->dw_fde_begin, 0, fde->dw_fde_end, 0, section); list_tail =&(*list_tail)->dw_loc_next; start_label = last_label = fde->dw_fde_second_begin; } @@ -19754,7 +20192,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); + start_label, 0, last_label, 0, section); list_tail = &(*list_tail)->dw_loc_next; last_cfa = next_cfa; @@ -19776,14 +20214,14 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); + start_label, 0, last_label, 0, section); list_tail = &(*list_tail)->dw_loc_next; last_cfa = next_cfa; start_label = last_label; } *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, fde->dw_fde_end, section); + start_label, 0, fde->dw_fde_end, 0, section); list_tail = &(*list_tail)->dw_loc_next; start_label = last_label = fde->dw_fde_second_begin; } @@ -19792,19 +20230,18 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) if (!cfa_equal_p (&last_cfa, &next_cfa)) { *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); + start_label, 0, last_label, 0, section); list_tail = &(*list_tail)->dw_loc_next; start_label = last_label; } *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset), - start_label, + start_label, 0, fde->dw_fde_second_begin - ? fde->dw_fde_second_end : fde->dw_fde_end, + ? fde->dw_fde_second_end : fde->dw_fde_end, 0, section); - if (list && list->dw_loc_next) - gen_llsym (list); + maybe_gen_llsym (list); return list; } @@ -26164,7 +26601,7 @@ maybe_emit_file (struct dwarf_file_data * fd) fd->emitted_number = 1; last_emitted_file = fd; - if (DWARF2_ASM_LINE_DEBUG_INFO) + if (output_asm_line_debug_info ()) { fprintf (asm_out_file, "\t.file %u ", fd->emitted_number); output_quoted_string (asm_out_file, @@ -26358,11 +26795,13 @@ dwarf2out_var_location (rtx_insn *loc_note) static rtx_insn *expected_next_loc_note; tree decl; bool var_loc_p; + var_loc_view view = 0; if (!NOTE_P (loc_note)) { if (CALL_P (loc_note)) { + RESET_NEXT_VIEW (cur_line_info_table->view); call_site_count++; if (SIBLING_CALL_P (loc_note)) tail_call_site_count++; @@ -26396,6 +26835,18 @@ dwarf2out_var_location (rtx_insn *loc_note) } } } + else if (!debug_variable_location_views) + gcc_unreachable (); + else if (JUMP_TABLE_DATA_P (loc_note)) + RESET_NEXT_VIEW (cur_line_info_table->view); + else if (GET_CODE (loc_note) == USE + || GET_CODE (loc_note) == CLOBBER + || GET_CODE (loc_note) == ASM_INPUT + || asm_noperands (loc_note) >= 0) + ; + else if (get_attr_min_length (loc_note) > 0) + RESET_NEXT_VIEW (cur_line_info_table->view); + return; } @@ -26459,10 +26910,11 @@ create_label: if (var_loc_p) { + const char *label + = NOTE_DURING_CALL_P (loc_note) ? last_postcall_label : last_label; + view = cur_line_info_table->view; decl = NOTE_VAR_LOCATION_DECL (loc_note); - newloc = add_var_loc_to_decl (decl, loc_note, - NOTE_DURING_CALL_P (loc_note) - ? last_postcall_label : last_label); + newloc = add_var_loc_to_decl (decl, loc_note, label, view); if (newloc == NULL) return; } @@ -26503,8 +26955,8 @@ create_label: else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) continue; -#ifdef HAVE_attr_length - else if (get_attr_min_length (insn) == 0) +#ifdef HAVE_ATTR_length /* ??? We don't include insn-attr.h. */ + else if (HAVE_ATTR_length && get_attr_min_length (insn) == 0) continue; #endif else @@ -26572,7 +27024,10 @@ create_label: call_arg_loc_last = ca_loc; } else if (loc_note != NULL_RTX && !NOTE_DURING_CALL_P (loc_note)) - newloc->label = last_label; + { + newloc->label = last_label; + newloc->view = view; + } else { if (!last_postcall_label) @@ -26581,6 +27036,7 @@ create_label: last_postcall_label = ggc_strdup (loclabel); } newloc->label = last_postcall_label; + newloc->view = view; } if (var_loc_p && flag_debug_asm) @@ -26652,6 +27108,7 @@ new_line_info_table (void) table->file_num = 1; table->line_num = 1; table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START; + RESET_NEXT_VIEW (table->view); return table; } @@ -26700,7 +27157,7 @@ set_cur_line_info_table (section *sec) vec_safe_push (separate_line_info, table); } - if (DWARF2_ASM_LINE_DEBUG_INFO) + if (output_asm_line_debug_info ()) table->is_stmt = (cur_line_info_table ? cur_line_info_table->is_stmt : DWARF_LINE_DEFAULT_IS_STMT_START); @@ -26881,7 +27338,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column, filename, line); } - if (DWARF2_ASM_LINE_DEBUG_INFO) + if (output_asm_line_debug_info ()) { /* Emit the .loc directive understood by GNU as. */ /* "\t.loc %u %u 0 is_stmt %u discriminator %u", @@ -26904,6 +27361,50 @@ dwarf2out_source_line (unsigned int line, unsigned int column, fputs (" discriminator ", asm_out_file); fprint_ul (asm_out_file, (unsigned long) discriminator); } + if (debug_variable_location_views) + { + static var_loc_view lvugid; + if (!lvugid) + { + gcc_assert (!zero_view_p); + zero_view_p = BITMAP_GGC_ALLOC (); + bitmap_set_bit (zero_view_p, 0); + } + if (!RESETTING_VIEW_P (table->view)) + { + /* When we're using the assembler to compute view + numbers, we output symbolic labels after "view" in + .loc directives, and the assembler will set them for + us, so that we can refer to the view numbers in + location lists. The only exceptions are when we know + a view will be zero: "-0" is a forced reset, used + e.g. in the beginning of functions, whereas "0" tells + the assembler to check that there was a PC change + since the previous view, in a way that implicitly + resets the next view. */ + fputs (" view ", asm_out_file); + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view); + assemble_name (asm_out_file, label); + table->view = ++lvugid; + } + else + { + if (!table->in_use) + fputs (" view -0", asm_out_file); + else + fputs (" view 0", asm_out_file); + /* Mark the present view as a zero view. Earlier debug + binds may have already added its id to loclists to be + emitted later, so we can't reuse the id for something + else. However, it's good to know whether a view is + known to be zero, because then we may be able to + optimize out locviews that are all zeros, so take + note of it in zero_view_p. */ + bitmap_set_bit (zero_view_p, lvugid); + table->view = ++lvugid; + } + } putc ('\n', asm_out_file); } else @@ -26912,7 +27413,19 @@ dwarf2out_source_line (unsigned int line, unsigned int column, targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num); - push_dw_line_info_entry (table, LI_set_address, label_num); + if (debug_variable_location_views && table->view) + push_dw_line_info_entry (table, LI_adv_address, label_num); + else + push_dw_line_info_entry (table, LI_set_address, label_num); + if (debug_variable_location_views) + { + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s view %s%d\n", + ASM_COMMENT_START, + table->in_use ? "" : "-", + table->view); + table->view++; + } if (file_num != table->file_num) push_dw_line_info_entry (table, LI_set_file, file_num); if (discriminator != table->discrim_num) @@ -27588,9 +28101,10 @@ init_sections_and_labels (bool early_lto_debug) SECTION_DEBUG, NULL); debug_str_section = get_section (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); - if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO) + if (!dwarf_split_debug_info && !output_asm_line_debug_info ()) debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); + debug_ranges_section = get_section (dwarf_version >= 5 ? DEBUG_RNGLISTS_SECTION : DEBUG_RANGES_SECTION, @@ -27976,6 +28490,11 @@ prune_unused_types_walk_attribs (dw_die_ref die) prune_unused_types_walk_loc_descr (list->expr); break; + case dw_val_class_view_list: + /* This points to a loc_list in another attribute, so it's + already covered. */ + break; + case dw_val_class_die_ref: /* A reference to another DIE. Make sure that it will get emitted. @@ -29075,6 +29594,8 @@ optimize_string_length (dw_attr_node *a) if (d->expr && non_dwarf_expression (d->expr)) non_dwarf_expr = true; break; + case dw_val_class_view_list: + gcc_unreachable (); case dw_val_class_loc: lv = AT_loc (av); if (lv == NULL) @@ -29119,7 +29640,7 @@ optimize_string_length (dw_attr_node *a) lv = copy_deref_exprloc (d->expr); if (lv) { - *p = new_loc_list (lv, d->begin, d->end, d->section); + *p = new_loc_list (lv, d->begin, d->vbegin, d->end, d->vend, d->section); p = &(*p)->dw_loc_next; } else if (!dwarf_strict && d->expr) @@ -29189,6 +29710,7 @@ resolve_addr (dw_die_ref die) { gcc_assert (!next->ll_symbol); next->ll_symbol = (*curr)->ll_symbol; + next->vl_symbol = (*curr)->vl_symbol; } if (dwarf_split_debug_info) remove_loc_list_addr_table_entries (l); @@ -29214,6 +29736,21 @@ resolve_addr (dw_die_ref die) ix--; } break; + case dw_val_class_view_list: + { + gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews); + gcc_checking_assert (dwarf2out_locviews_in_attribute ()); + dw_val_node *llnode + = view_list_to_loc_list_val_node (&a->dw_attr_val); + /* If we no longer have a loclist, or it no longer needs + views, drop this attribute. */ + if (!llnode || !llnode->v.val_loc_list->vl_symbol) + { + remove_AT (die, a->dw_attr); + ix--; + } + break; + } case dw_val_class_loc: { dw_loc_descr_ref l = AT_loc (a); @@ -29610,6 +30147,8 @@ hash_loc_list (dw_loc_list_ref list_head) { hstate.add (curr->begin, strlen (curr->begin) + 1); hstate.add (curr->end, strlen (curr->end) + 1); + hstate.add_object (curr->vbegin); + hstate.add_object (curr->vend); if (curr->section) hstate.add (curr->section, strlen (curr->section) + 1); hash_locs (curr->expr, hstate); @@ -29831,6 +30370,7 @@ loc_list_hasher::equal (const dw_loc_list_struct *a, || strcmp (a->end, b->end) != 0 || (a->section == NULL) != (b->section == NULL) || (a->section && strcmp (a->section, b->section) != 0) + || a->vbegin != b->vbegin || a->vend != b->vend || !compare_locs (a->expr, b->expr)) break; return a == NULL && b == NULL; @@ -29849,6 +30389,8 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab) dw_attr_node *a; unsigned ix; dw_loc_list_struct **slot; + bool drop_locviews = false; + bool has_locviews = false; FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) if (AT_class (a) == dw_val_class_loc_list) @@ -29859,11 +30401,33 @@ optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab) hash_loc_list (list); slot = htab->find_slot_with_hash (list, list->hash, INSERT); if (*slot == NULL) - *slot = list; + { + *slot = list; + if (loc_list_has_views (list)) + gcc_assert (list->vl_symbol); + else if (list->vl_symbol) + { + drop_locviews = true; + list->vl_symbol = NULL; + } + } else - a->dw_attr_val.v.val_loc_list = *slot; + { + if (list->vl_symbol && !(*slot)->vl_symbol) + drop_locviews = true; + a->dw_attr_val.v.val_loc_list = *slot; + } + } + else if (AT_class (a) == dw_val_class_view_list) + { + gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews); + has_locviews = true; } + + if (drop_locviews && has_locviews) + remove_AT (die, DW_AT_GNU_locviews); + FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab)); } @@ -29888,7 +30452,7 @@ index_location_lists (dw_die_ref die) /* Don't index an entry that has already been indexed or won't be output. */ if (curr->begin_entry != NULL - || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) + || skip_loc_list_entry (curr)) continue; curr->begin_entry @@ -30312,7 +30876,7 @@ dwarf2out_finish (const char *) dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, "Length of Location Lists"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + output_dwarf_version (); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); dw2_asm_output_data (1, 0, "Segment Size"); dw2_asm_output_data (4, dwarf_split_debug_info ? loc_list_idx : 0, @@ -30371,7 +30935,7 @@ dwarf2out_finish (const char *) used by the debug_info section are marked as 'used'. */ switch_to_section (debug_line_section); ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label); - if (! DWARF2_ASM_LINE_DEBUG_INFO) + if (! output_asm_line_debug_info ()) output_line_info (false); if (dwarf_split_debug_info && info_section_emitted) diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h index bc2ae4de1d3..a1856a5185e 100644 --- a/gcc/dwarf2out.h +++ b/gcc/dwarf2out.h @@ -160,7 +160,8 @@ enum dw_val_class dw_val_class_discr_list, dw_val_class_const_implicit, dw_val_class_unsigned_const_implicit, - dw_val_class_file_implicit + dw_val_class_file_implicit, + dw_val_class_view_list }; /* Describe a floating point constant value, or a vector constant value. */ @@ -203,6 +204,7 @@ struct GTY(()) dw_val_node { rtx GTY ((tag ("dw_val_class_addr"))) val_addr; unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset; dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list; + dw_die_ref GTY ((tag ("dw_val_class_view_list"))) val_view_list; dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc; HOST_WIDE_INT GTY ((default)) val_int; unsigned HOST_WIDE_INT diff --git a/gcc/final.c b/gcc/final.c index 578e5d6af4c..68397b3ded3 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -110,6 +110,7 @@ along with GCC; see the file COPYING3. If not see /* Bitflags used by final_scan_insn. */ #define SEEN_NOTE 1 #define SEEN_EMITTED 2 +#define SEEN_NEXT_VIEW 4 /* Last insn processed by final_scan_insn. */ static rtx_insn *debug_insn; @@ -1692,6 +1693,67 @@ get_some_local_dynamic_name () return 0; } +/* Arrange for us to emit a source location note before any further + real insns or section changes, by setting the SEEN_NEXT_VIEW bit in + *SEEN, as long as we are keeping track of location views. The bit + indicates we have referenced the next view at the current PC, so we + have to emit it. This should be called next to the var_location + debug hook. */ + +static inline void +set_next_view_needed (int *seen) +{ + if (debug_variable_location_views) + *seen |= SEEN_NEXT_VIEW; +} + +/* Clear the flag in *SEEN indicating we need to emit the next view. + This should be called next to the source_line debug hook. */ + +static inline void +clear_next_view_needed (int *seen) +{ + *seen &= ~SEEN_NEXT_VIEW; +} + +/* Test whether we have a pending request to emit the next view in + *SEEN, and emit it if needed, clearing the request bit. */ + +static inline void +maybe_output_next_view (int *seen) +{ + if ((*seen & SEEN_NEXT_VIEW) != 0) + { + clear_next_view_needed (seen); + (*debug_hooks->source_line) (last_linenum, last_columnnum, + last_filename, last_discriminator, + false); + } +} + +/* We want to emit param bindings (before the first begin_stmt) in the + initial view, if we are emitting views. To that end, we may + consume initial notes in the function, processing them in + final_start_function, before signaling the beginning of the + prologue, rather than in final. + + We don't test whether the DECLs are PARM_DECLs: the assumption is + that there will be a NOTE_INSN_BEGIN_STMT marker before any + non-parameter NOTE_INSN_VAR_LOCATION. It's ok if the marker is not + there, we'll just have more variable locations bound in the initial + view, which is consistent with their being bound without any code + that would give them a value. */ + +static inline bool +in_initial_view_p (rtx_insn *insn) +{ + return (!DECL_IGNORED_P (current_function_decl) + && debug_variable_location_views + && insn && GET_CODE (insn) == NOTE + && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION + || NOTE_KIND (insn) == NOTE_INSN_DELETED)); +} + /* Output assembler code for the start of a function, and initialize some of the variables in this file for the new function. The label for the function and associated @@ -1699,12 +1761,15 @@ get_some_local_dynamic_name () FIRST is the first insn of the rtl for the function being compiled. FILE is the file to write assembler code to. + SEEN should be initially set to zero, and it may be updated to + indicate we have references to the next location view, that would + require us to emit it at the current PC. OPTIMIZE_P is nonzero if we should eliminate redundant test and compare insns. */ -void -final_start_function (rtx_insn *first, FILE *file, - int optimize_p ATTRIBUTE_UNUSED) +static void +final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen, + int optimize_p ATTRIBUTE_UNUSED) { block_depth = 0; @@ -1722,8 +1787,21 @@ final_start_function (rtx_insn *first, FILE *file, if (flag_sanitize & SANITIZE_ADDRESS) asan_function_start (); + rtx_insn *first = *firstp; + if (in_initial_view_p (first)) + { + do + { + final_scan_insn (first, file, 0, 0, seen); + first = NEXT_INSN (first); + } + while (in_initial_view_p (first)); + *firstp = first; + } + if (!DECL_IGNORED_P (current_function_decl)) - debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename); + debug_hooks->begin_prologue (last_linenum, last_columnnum, + last_filename); if (!dwarf2_debug_info_emitted_p (current_function_decl)) dwarf2out_begin_prologue (0, 0, NULL); @@ -1799,6 +1877,17 @@ final_start_function (rtx_insn *first, FILE *file, profile_after_prologue (file); } +/* This is an exported final_start_function_1, callable without SEEN. */ + +void +final_start_function (rtx_insn *first, FILE *file, + int optimize_p ATTRIBUTE_UNUSED) +{ + int seen = 0; + final_start_function_1 (&first, file, &seen, optimize_p); + gcc_assert (seen == 0); +} + static void profile_after_prologue (FILE *file ATTRIBUTE_UNUSED) { @@ -1928,11 +2017,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb, /* Output assembler code for some insns: all or part of a function. For description of args, see `final_start_function', above. */ -void -final (rtx_insn *first, FILE *file, int optimize_p) +static void +final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p) { rtx_insn *insn, *next; - int seen = 0; /* Used for -dA dump. */ basic_block *start_to_bb = NULL; @@ -1999,6 +2087,8 @@ final (rtx_insn *first, FILE *file, int optimize_p) insn = final_scan_insn (insn, file, optimize_p, 0, &seen); } + maybe_output_next_view (&seen); + if (flag_debug_asm) { free (start_to_bb); @@ -2015,6 +2105,23 @@ final (rtx_insn *first, FILE *file, int optimize_p) delete_insn (insn); } } + +/* This is an exported final_1, callable without SEEN. */ + +void +final (rtx_insn *first, FILE *file, int optimize_p) +{ + /* Those that use the internal final_start_function_1/final_1 API + skip initial debug bind notes in final_start_function_1, and pass + the modified FIRST to final_1. But those that use the public + final_start_function/final APIs, final_start_function can't move + FIRST because it's not passed by reference, so if they were + skipped there, skip them again here. */ + while (in_initial_view_p (first)) + first = NEXT_INSN (first); + + final_1 (first, file, 0, optimize_p); +} const char * get_insn_template (int code, rtx insn) @@ -2155,6 +2262,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, break; case NOTE_INSN_SWITCH_TEXT_SECTIONS: + maybe_output_next_view (seen); + in_cold_section_p = !in_cold_section_p; if (in_cold_section_p) @@ -2301,6 +2410,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, break; case NOTE_INSN_BLOCK_END: + maybe_output_next_view (seen); + if (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE || write_symbols == DWARF2_DEBUG @@ -2357,7 +2468,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, case NOTE_INSN_VAR_LOCATION: case NOTE_INSN_CALL_ARG_LOCATION: if (!DECL_IGNORED_P (current_function_decl)) - debug_hooks->var_location (insn); + { + debug_hooks->var_location (insn); + set_next_view_needed (seen); + } break; case NOTE_INSN_BEGIN_STMT: @@ -2368,6 +2482,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, (*debug_hooks->source_line) (last_linenum, last_columnnum, last_filename, last_discriminator, true); + clear_next_view_needed (seen); } break; @@ -2563,6 +2678,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, switch_to_section (current_function_section ()); + if (debug_variable_location_views + && !DECL_IGNORED_P (current_function_decl)) + debug_hooks->var_location (insn); + break; } /* Output this line note if it is the first or the last line @@ -2575,7 +2694,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, (*debug_hooks->source_line) (last_linenum, last_columnnum, last_filename, last_discriminator, is_stmt); + clear_next_view_needed (seen); } + else + maybe_output_next_view (seen); + + gcc_checking_assert (!DEBUG_INSN_P (insn)); if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT) @@ -3042,7 +3166,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, /* Let the debug info back-end know about this call. We do this only after the instruction has been emitted because labels that may be created to reference the call instruction must appear after it. */ - if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl)) + if ((debug_variable_location_views || call_insn != NULL) + && !DECL_IGNORED_P (current_function_decl)) debug_hooks->var_location (insn); current_output_insn = debug_insn = 0; @@ -4481,8 +4606,10 @@ rest_of_handle_final (void) delete_vta_debug_insns (false); assemble_start_function (current_function_decl, fnname); - final_start_function (get_insns (), asm_out_file, optimize); - final (get_insns (), asm_out_file, optimize); + rtx_insn *first = get_insns (); + int seen = 0; + final_start_function_1 (&first, asm_out_file, &seen, optimize); + final_1 (first, asm_out_file, seen, optimize); if (flag_ipa_ra && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl))) collect_fn_hard_reg_usage (); diff --git a/gcc/toplev.c b/gcc/toplev.c index 35d79680ab0..23db0636fc7 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1558,6 +1558,22 @@ process_options (void) || write_symbols == VMS_AND_DWARF2_DEBUG) && !(flag_selective_scheduling || flag_selective_scheduling2)); + if (debug_variable_location_views == AUTODETECT_VALUE) + { + debug_variable_location_views = flag_var_tracking + && debug_info_level >= DINFO_LEVEL_NORMAL + && (write_symbols == DWARF2_DEBUG + || write_symbols == VMS_AND_DWARF2_DEBUG) + && !dwarf_strict; + } + else if (debug_variable_location_views == -1 && dwarf_version != 5) + { + warning_at (UNKNOWN_LOCATION, 0, + "without -gdwarf-5, -gvariable-location-views=incompat5 " + "is equivalent to -gvariable-location-views"); + debug_variable_location_views = 1; + } + if (flag_tree_cselim == AUTODETECT_VALUE) { if (HAVE_conditional_move) diff --git a/include/ChangeLog b/include/ChangeLog index e36e227b94f..dbf59719df8 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,10 @@ +2018-02-09 Alexandre Oliva + + * 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. + 2018-01-03 Jakub Jelinek Update copyright years. diff --git a/include/dwarf2.def b/include/dwarf2.def index f0ad0ca16b2..c454506d1ed 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 882e286872e..cf0039a92ab 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, + /* + has the proposal for now; only available to list members. + + A (possibly updated) copy of the proposal is available at + . */ + 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,