* [PATCH][2/2] Early LTO debug -- main part
@ 2016-10-21 11:26 Richard Biener
2016-11-11 8:07 ` [PING][PATCH][2/2] " Richard Biener
0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2016-10-21 11:26 UTC (permalink / raw)
To: gcc-patches
This is the main part of the early LTO debug support. The main parts
of the changes are to dwarf2out.c where most of the changes are related
to the fact that we eventually have to output debug info twice, once
for the early LTO part and once for the fat part of the object file.
Bootstrapped and tested on x86_64-unknown-linux-gnu with ASAN and TSAN
extra FAILs (see PR78063, a libbacktrace missing feature or libsanitizer
being too pessimistic). There's an extra
XPASS: gcc.dg/guality/inline-params.c -O2 -flto -fuse-linker-plugin
-fno-fat-lto-objects execution test
the previously reported extra VLA guality FAILs are gone.
I've compared testresults with -flto -g added for all languages and
only see expected differences (libstdc++ pretty printers now work,
most scan-assembler-times debug testcases fail because we have everything
twice now).
See https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01842.html for
the last posting of this patch which has a high-level overview of
Early LTO debug. You may want to refer to the slides I presented
at the GNU Cauldron as well.
Thanks,
Richard.
2016-10-21 Richard Biener <rguenther@suse.de>
* debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and
register_external_die hooks.
(debug_false_tree_charstarstar_uhwistar): Declare.
(debug_nothing_tree_charstar_uhwi): Likewise.
* debug.c (do_nothing_debug_hooks): Adjust.
(debug_false_tree_charstarstar_uhwistar): New do nothing.
(debug_nothing_tree_charstar_uhwi): Likewise.
* dbxout.c (dbx_debug_hooks): Adjust.
(xcoff_debug_hooks): Likewise.
* sdbout.c (sdb_debug_hooks): Likewise.
* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
* dwarf2out.c (macinfo_label_base): New global.
(dwarf2out_register_external_die): New function for the
register_external_die hook.
(dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl.
(dwarf2_debug_hooks): Use them.
(dwarf2_lineno_debug_hooks): Adjust.
(struct die_struct): Add with_offset flag.
(DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION,
DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION,
DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION,
DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION,
DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros
defining section names for the early LTO debug variants.
(reset_indirect_string): New helper.
(add_AT_external_die_ref): Helper for dwarf2out_register_external_die.
(print_dw_val): Add support for offsetted symbol references.
(compute_section_prefix_1): Split out worker to distinguish
the comdat from the LTO case.
(compute_section_prefix): Wrap old comdat case here.
(output_die): Skip DIE symbol output for the LTO added one.
Handle DIE symbol references with offset.
(output_comp_unit): Guard section name mangling properly.
For LTO debug sections emit a symbol at the section beginning
which we use to refer to its DIEs.
(add_abstract_origin_attribute): For DIEs registered via
dwarf2out_register_external_die directly refer to the early
DIE rather than indirectly through the shadow one we created.
(gen_array_type_die): When generating early LTO debug do
not emit DW_AT_string_length.
(gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs
late when in LTO.
(gen_subprogram_die): Adjust the check for whether we face
a concrete instance DIE for an inline we can reuse for the
late LTO case. Likewise avoid another specification DIE
for early built declarations/definitions for the late LTO case.
(gen_variable_die): Add type references for late duplicated VLA dies
when in late LTO.
(gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function,
we have the abstract instance already.
(process_scope_var): Adjust decl DIE contexts in LTO which
first puts them in limbo.
(gen_decl_die): Do not generate type DIEs late apart from
types for VLAs or for decls we do not yet have a DIE.
(dwarf2out_early_global_decl): Make sure to create DIEs
for abstract instances of a decl first.
(dwarf2out_late_global_decl): Adjust comment.
(output_macinfo_op): With multiple macro sections use
macinfo_label_base to distinguish labels.
(output_macinfo): Likewise. Update macinfo_label_base.
Pass in the line info label.
(init_sections_and_labels): Add early LTO debug flag parameter
and generate different sections and names if set. Add generation
counter for the labels so we can have multiple of them.
(reset_dies): Helper to allow DIEs to be output multiple times.
(dwarf2out_finish): When outputting DIEs to the fat part of an
LTO object first reset DIEs.
(dwarf2out_early_finish): Output early DIEs when generating LTO.
Cleanups we can do (and need) when removing the "old" LTO path and add
the early LTO path.
(set_decl_abstract_flags): Remove.
(set_block_abstract_flags): Likewise.
(dwarf2out_abstract_function): Treat the early generated DIEs
as the abstract copy and only add DW_AT_inline and
DW_AT_artificial here.
* lto-streamer-in.c: Include debug.h.
(dref_queue): New global.
(lto_read_tree_1): Stream in DIE references.
(lto_input_tree): Register DIE references.
(input_function): Stream DECL_DEBUG_ARGS.
* lto-streamer-out.c: Include debug.h.
(lto_write_tree_1): Output DIE references.
(DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN.
(output_function): Stream DECL_DEBUG_ARGS.
* tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers):
Stream DECL_ABSTRACT_ORIGIN.
* tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise.
* lto-streamer.h (struct dref_entry): Declare.
(dref_queue): Likewise.
* lto-wrapper.c (debug_obj): New global.
(tool_cleanup): Unlink it if required.
(debug_objcopy): New function.
(run_gcc): Handle early debug sections in the IL files by
extracting them to separate files, partially linkin them and
feeding the result back as result to the linker.
* config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION,
DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION,
DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug
sections into a separate segment.
* config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO
segments.
(darwin_asm_dwarf_section): Likewise.
(darwin_asm_output_dwarf_offset): Likewise.
lto/
* lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs.
(lto_read_decls): Process TRANSLATION_UNIT_DECLs. Remove
TYPE_DECL debug processing, register DIE references from
prevailing SCCs with the debug machinery.
(lto_section_with_id): Handle LTO debug sections.
Index: early-lto-debug/gcc/dwarf2out.c
===================================================================
--- early-lto-debug.orig/gcc/dwarf2out.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/dwarf2out.c 2016-10-21 12:24:42.095686608 +0200
@@ -161,6 +161,7 @@ static GTY(()) section *debug_aranges_se
static GTY(()) section *debug_addr_section;
static GTY(()) section *debug_macinfo_section;
static const char *debug_macinfo_section_name;
+static unsigned macinfo_label_base = 1;
static GTY(()) section *debug_line_section;
static GTY(()) section *debug_skeleton_line_section;
static GTY(()) section *debug_loc_section;
@@ -2487,6 +2488,10 @@ static void dwarf2out_begin_function (tr
static void dwarf2out_end_function (unsigned int);
static void dwarf2out_register_main_translation_unit (tree unit);
static void dwarf2out_set_name (tree, tree);
+static void dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off);
+static bool dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off);
/* The debug hooks structure. */
@@ -2521,6 +2526,8 @@ const struct gcc_debug_hooks dwarf2_debu
dwarf2out_late_global_decl,
dwarf2out_type_decl, /* type_decl */
dwarf2out_imported_module_or_decl,
+ dwarf2out_die_ref_for_decl,
+ dwarf2out_register_external_die,
debug_nothing_tree, /* deferred_inline_function */
/* The DWARF 2 backend tries to reduce debugging bloat by not
emitting the abstract description of inline functions until
@@ -2562,6 +2569,8 @@ const struct gcc_debug_hooks dwarf2_line
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
@@ -2689,6 +2698,9 @@ typedef struct GTY((chain_circular ("%h.
/* Die is used and must not be pruned as unused. */
BOOL_BITFIELD die_perennial_p : 1;
BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+ /* For an external ref to die_symbol if die_offset contains an extra
+ offset to that symbol. */
+ BOOL_BITFIELD with_offset : 1;
/* Whether this DIE was removed from the DIE tree, for example via
prune_unused_types. We don't consider those present from the
DIE lookup routines. */
@@ -3493,12 +3505,24 @@ new_addr_loc_descr (rtx addr, enum dtpre
#ifndef DEBUG_DWO_INFO_SECTION
#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_INFO_SECTION
+#define DEBUG_LTO_DWO_INFO_SECTION ".gnu.debuglto_.debug_info.dwo"
+#endif
+#ifndef DEBUG_LTO_INFO_SECTION
+#define DEBUG_LTO_INFO_SECTION ".gnu.debuglto_.debug_info"
+#endif
#ifndef DEBUG_ABBREV_SECTION
#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
#ifndef DEBUG_DWO_ABBREV_SECTION
#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_ABBREV_SECTION
+#define DEBUG_LTO_DWO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev.dwo"
+#endif
+#ifndef DEBUG_LTO_ABBREV_SECTION
+#define DEBUG_LTO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev"
+#endif
#ifndef DEBUG_ARANGES_SECTION
#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
@@ -3511,18 +3535,33 @@ new_addr_loc_descr (rtx addr, enum dtpre
#ifndef DEBUG_DWO_MACINFO_SECTION
#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_MACINFO_SECTION
+#define DEBUG_LTO_DWO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo.dwo"
+#endif
+#ifndef DEBUG_LTO_MACINFO_SECTION
+#define DEBUG_LTO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo"
+#endif
#ifndef DEBUG_DWO_MACRO_SECTION
#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo"
#endif
#ifndef DEBUG_MACRO_SECTION
#define DEBUG_MACRO_SECTION ".debug_macro"
#endif
+#ifndef DEBUG_LTO_DWO_MACRO_SECTION
+#define DEBUG_LTO_DWO_MACRO_SECTION ".gnu.debuglto_.debug_macro.dwo"
+#endif
+#ifndef DEBUG_LTO_MACRO_SECTION
+#define DEBUG_LTO_MACRO_SECTION ".gnu.debuglto_.debug_macro"
+#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
#ifndef DEBUG_DWO_LINE_SECTION
#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
#endif
+#ifndef DEBUG_LTO_LINE_SECTION
+#define DEBUG_LTO_LINE_SECTION ".gnu.debuglto_.debug_line.dwo"
+#endif
#ifndef DEBUG_LOC_SECTION
#define DEBUG_LOC_SECTION ".debug_loc"
#endif
@@ -3545,12 +3584,21 @@ new_addr_loc_descr (rtx addr, enum dtpre
#ifndef DEBUG_DWO_STR_OFFSETS_SECTION
#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_STR_OFFSETS_SECTION
+#define DEBUG_LTO_DWO_STR_OFFSETS_SECTION ".gnu.debuglto_.debug_str_offsets.dwo"
+#endif
#ifndef DEBUG_STR_DWO_SECTION
#define DEBUG_STR_DWO_SECTION ".debug_str.dwo"
#endif
+#ifndef DEBUG_LTO_STR_DWO_SECTION
+#define DEBUG_LTO_STR_DWO_SECTION ".gnu.debuglto_.debug_str.dwo"
+#endif
#ifndef DEBUG_STR_SECTION
#define DEBUG_STR_SECTION ".debug_str"
#endif
+#ifndef DEBUG_LTO_STR_SECTION
+#define DEBUG_LTO_STR_SECTION ".gnu.debuglto_.debug_str"
+#endif
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
#endif
@@ -4152,6 +4200,24 @@ set_indirect_string (struct indirect_str
}
}
+/* A helper function for dwarf2out_finish, called to reset indirect
+ string decisions done for early LTO dwarf output before fat object
+ dwarf output. */
+
+int
+reset_indirect_string (indirect_string_node **h, void *)
+{
+ struct indirect_string_node *node = *h;
+ if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+ {
+ free (node->label);
+ node->label = NULL;
+ node->form = (dwarf_form) 0;
+ node->index = 0;
+ }
+ return 1;
+}
+
/* Find out whether a string should be output inline in DIE
or out-of-line in .debug_str section. */
@@ -5157,6 +5223,186 @@ lookup_decl_die (tree decl)
return *die;
}
+
+/* For DECL which might have early dwarf output query a SYMBOL + OFFSET
+ style reference. Return true if we found one refering to a DIE for
+ DECL, otherwise return false. */
+
+static bool
+dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off)
+{
+ dw_die_ref die;
+
+ if (flag_wpa && !decl_die_table)
+ return false;
+
+ if (TREE_CODE (decl) == BLOCK)
+ die = BLOCK_DIE (decl);
+ else
+ die = lookup_decl_die (decl);
+ if (!die)
+ return false;
+
+ /* During WPA stage we currently use DIEs to store the
+ decl <-> label + offset map. That's quite inefficient but it
+ works for now. */
+ if (flag_wpa)
+ {
+ dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
+ if (!ref)
+ {
+ gcc_assert (die == comp_unit_die ());
+ return false;
+ }
+ *off = ref->die_offset;
+ *sym = ref->die_id.die_symbol;
+ return true;
+ }
+
+ /* Similar to get_ref_die_offset_label, but using the "correct"
+ label. */
+ *off = die->die_offset;
+ while (die->die_parent)
+ die = die->die_parent;
+ /* For the containing CU DIE we compute a die_symbol in
+ compute_section_prefix. */
+ gcc_assert (die->die_tag == DW_TAG_compile_unit
+ && die->die_id.die_symbol != NULL);
+ *sym = die->die_id.die_symbol;
+ return true;
+}
+
+/* Add a reference of kind ATTR_KIND to a DIE at SYMBOL + OFFSET to DIE. */
+
+static void
+add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *symbol, HOST_WIDE_INT offset)
+{
+ /* Create a fake DIE that contains the reference. Don't use
+ new_die because we don't want to end up in the limbo list. */
+ dw_die_ref ref = ggc_cleared_alloc<die_node> ();
+ ref->die_tag = die->die_tag;
+ ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
+ ref->die_offset = offset;
+ ref->with_offset = 1;
+ add_AT_die_ref (die, attr_kind, ref);
+}
+
+/* Create a DIE for DECL if required and add a reference to a DIE
+ at SYMBOL + OFFSET which contains attributes dumped early. */
+
+static void
+dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off)
+{
+ if (debug_info_level == DINFO_LEVEL_NONE)
+ return;
+
+ if (flag_wpa && !decl_die_table)
+ decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
+
+ dw_die_ref die
+ = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+ gcc_assert (!die);
+
+ tree ctx;
+ dw_die_ref parent = NULL;
+ /* Need to lookup a DIE for the decls context - the containing
+ function or translation unit. */
+ if (TREE_CODE (decl) == BLOCK)
+ {
+ ctx = BLOCK_SUPERCONTEXT (decl);
+ /* ??? We do not output DIEs for all scopes thus skip as
+ many DIEs as needed. */
+ while (TREE_CODE (ctx) == BLOCK
+ && !BLOCK_DIE (ctx))
+ ctx = BLOCK_SUPERCONTEXT (ctx);
+ }
+ else
+ ctx = DECL_CONTEXT (decl);
+ while (ctx && TYPE_P (ctx))
+ ctx = TYPE_CONTEXT (ctx);
+ if (ctx)
+ {
+ if (TREE_CODE (ctx) == BLOCK)
+ parent = BLOCK_DIE (ctx);
+ else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
+ /* Keep the 1:1 association during WPA. */
+ && !flag_wpa)
+ /* Otherwise all late annotations go to the main CU which
+ imports the original CUs. */
+ parent = comp_unit_die ();
+ else if (TREE_CODE (ctx) == FUNCTION_DECL
+ && TREE_CODE (decl) != PARM_DECL
+ && TREE_CODE (decl) != BLOCK)
+ /* Leave function local entities parent determination to when
+ we process scope vars. */
+ ;
+ else
+ parent = lookup_decl_die (ctx);
+ }
+ else
+ /* ??? In some cases the C++ FE (at least) fails to
+ set DECL_CONTEXT properly. Simply globalize stuff
+ in this case. For example
+ __dso_handle created via iostream line 74 col 25. */
+ parent = comp_unit_die ();
+ /* Create a DIE "stub". */
+ switch (TREE_CODE (decl))
+ {
+ case TRANSLATION_UNIT_DECL:
+ if (! flag_wpa)
+ {
+ die = comp_unit_die ();
+ dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
+ add_AT_external_die_ref (import, DW_AT_import, sym, off);
+ /* We re-target all CU decls to the LTRANS CU DIE, so no need
+ to create a DIE for the original CUs. */
+ return;
+ }
+ /* Keep the 1:1 association during WPA. */
+ die = new_die (DW_TAG_compile_unit, NULL, decl);
+ break;
+ case NAMESPACE_DECL:
+ /* ??? LANG issue - DW_TAG_module for fortran. Either look
+ at the input language (if we have enough DECL_CONTEXT to follow)
+ or use a bit in tree_decl_with_vis to record the distinction. */
+ die = new_die (DW_TAG_namespace, parent, decl);
+ break;
+ case FUNCTION_DECL:
+ die = new_die (DW_TAG_subprogram, parent, decl);
+ break;
+ case VAR_DECL:
+ die = new_die (DW_TAG_variable, parent, decl);
+ break;
+ case RESULT_DECL:
+ die = new_die (DW_TAG_variable, parent, decl);
+ break;
+ case PARM_DECL:
+ die = new_die (DW_TAG_formal_parameter, parent, decl);
+ break;
+ case CONST_DECL:
+ die = new_die (DW_TAG_constant, parent, decl);
+ break;
+ case LABEL_DECL:
+ die = new_die (DW_TAG_label, parent, decl);
+ break;
+ case BLOCK:
+ die = new_die (DW_TAG_lexical_block, parent, decl);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (TREE_CODE (decl) == BLOCK)
+ BLOCK_DIE (decl) = die;
+ else
+ equate_decl_number_to_die (decl, die);
+
+ /* Add a reference to the DIE providing early debug at $sym + off. */
+ add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
+}
+
/* Returns a hash value for X (which really is a var_loc_list). */
inline hashval_t
@@ -5642,7 +5888,11 @@ print_dw_val (dw_val_node *val, bool rec
die->die_id.die_type_node->signature);
}
else if (die->die_id.die_symbol)
- fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ {
+ fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ if (die->with_offset)
+ fprintf (outfile, " + %ld", die->die_offset);
+ }
else
fprintf (outfile, "die -> %ld", die->die_offset);
fprintf (outfile, " (%p)", (void *) die);
@@ -6935,7 +7185,7 @@ static unsigned int comdat_symbol_number
children, and set comdat_symbol_id accordingly. */
static void
-compute_section_prefix (dw_die_ref unit_die)
+compute_section_prefix_1 (dw_die_ref unit_die, bool comdat_p)
{
const char *die_name = get_AT_string (unit_die, DW_AT_name);
const char *base = die_name ? lbasename (die_name) : "anonymous";
@@ -6954,7 +7204,11 @@ compute_section_prefix (dw_die_ref unit_
unmark_all_dies (unit_die);
md5_finish_ctx (&ctx, checksum);
- sprintf (name, "%s.", base);
+ /* When we this for comp_unit_die () we have a DW_AT_name that might
+ not start with a letter but with anything valid for filenames and
+ clean_symbol_name doesn't fix that up. Prepend 'g' if the first
+ character is not a letter. */
+ sprintf (name, "%s%s.", ISALPHA (*base) ? "" : "g", base);
clean_symbol_name (name);
p = name + strlen (name);
@@ -6964,7 +7218,15 @@ compute_section_prefix (dw_die_ref unit_
p += 2;
}
- comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+ unit_die->die_id.die_symbol = xstrdup (name);
+ unit_die->comdat_type_p = comdat_p;
+}
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+ compute_section_prefix_1 (unit_die, true);
+ comdat_symbol_id = unit_die->die_id.die_symbol;
comdat_symbol_number = 0;
}
@@ -9224,7 +9486,11 @@ output_die (dw_die_ref die)
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
- if (! die->comdat_type_p && die->die_id.die_symbol)
+ if (! die->comdat_type_p && die->die_id.die_symbol
+ /* Don't output the symbol twice. For LTO we want the label
+ on the section beginning, not on the actual DIE. */
+ && (!flag_generate_lto
+ || die->die_tag != DW_TAG_compile_unit))
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
@@ -9403,8 +9669,20 @@ output_die (dw_die_ref die)
size = DWARF2_ADDR_SIZE;
else
size = DWARF_OFFSET_SIZE;
- dw2_asm_output_offset (size, sym, debug_info_section, "%s",
- name);
+ /* ??? We cannot unconditionally output die_offset if
+ non-zero - at least -feliminate-dwarf2-dups will
+ create references to those DIEs via symbols. And we
+ do not clear its DIE offset after outputting it
+ (and the label refers to the actual DIEs, not the
+ DWARF CU unit header which is when using label + offset
+ would be the correct thing to do).
+ ??? This is the reason for the with_offset flag. */
+ if (AT_ref (a)->with_offset)
+ dw2_asm_output_offset (size, sym, AT_ref (a)->die_offset,
+ debug_info_section, "%s", name);
+ else
+ dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+ name);
}
}
else
@@ -9590,7 +9868,7 @@ output_comp_unit (dw_die_ref die, int ou
calc_die_sizes (die);
oldsym = die->die_id.die_symbol;
- if (oldsym)
+ if (oldsym && die->comdat_type_p)
{
tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
@@ -9606,6 +9884,33 @@ output_comp_unit (dw_die_ref die, int ou
info_section_emitted = true;
}
+ /* For LTO cross unit DIE refs we want a symbol on the start of the
+ debuginfo section, not on the CU DIE.
+ ??? We could simply use the symbol as it would be output by output_die
+ and account for the extra offset produced by the CU header which has fixed
+ size. OTOH it currently only supports linkonce globals which would
+ be less than ideal?. */
+ if (flag_generate_lto && oldsym)
+ {
+ /* ??? No way to get visibility assembled without a decl. */
+ tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (oldsym), char_type_node);
+ TREE_PUBLIC (decl) = true;
+ TREE_STATIC (decl) = true;
+ DECL_ARTIFICIAL (decl) = true;
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = true;
+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+#ifdef ASM_WEAKEN_LABEL
+ /* We prefer a .weak because that handles duplicates from duplicate
+ archive members in a graceful way. */
+ ASM_WEAKEN_LABEL (asm_out_file, oldsym);
+#else
+ targetm.asm_out.globalize_label (asm_out_file, oldsym);
+#endif
+ ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+ }
+
/* Output debugging information. */
output_compilation_unit_header ();
output_die (die);
@@ -13331,6 +13636,9 @@ parameter_ref_descriptor (rtx rtl)
if (dwarf_strict)
return NULL;
gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
+ /* With LTO during LTRANS we get the late DIE that refers to the early
+ DIE, thus we add another indirection here. This seems to confuse
+ gdb enough to make gcc.dg/guality/pr68860-1.c FAIL with LTO. */
ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
if (ref)
@@ -18791,7 +19099,20 @@ add_abstract_origin_attribute (dw_die_re
}
if (DECL_P (origin))
- origin_die = lookup_decl_die (origin);
+ {
+ dw_die_ref c;
+ origin_die = lookup_decl_die (origin);
+ /* "Unwrap" the decls DIE which we put in the imported unit context.
+ ??? If we finish dwarf2out_function_decl refactoring we can
+ do this in a better way from the start and only lazily emit
+ the early DIE references. */
+ if (in_lto_p
+ && origin_die
+ && (c = get_AT_ref (origin_die, DW_AT_abstract_origin))
+ /* ??? Identify this better. */
+ && c->with_offset)
+ origin_die = c;
+ }
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
else if (TREE_CODE (origin) == BLOCK)
@@ -19346,7 +19667,12 @@ gen_array_type_die (tree type, dw_die_re
size = int_size_in_bytes (type);
if (size >= 0)
add_AT_unsigned (array_die, DW_AT_byte_size, size);
- else if (TYPE_DOMAIN (type) != NULL_TREE
+ /* ??? We can't annotate types late, but for LTO we may not
+ generate a location early either (gfortran.dg/save_5.f90).
+ The proper way is to handle it like VLAs though it is told
+ that DW_AT_string_length does not support this. */
+ else if (! (early_dwarf && flag_generate_lto)
+ && TYPE_DOMAIN (type) != NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE)
{
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
@@ -19801,7 +20127,9 @@ gen_formal_parameter_die (tree node, tre
thing. */
if (parm_die && parm_die->die_parent != context_die)
{
- if (!DECL_ABSTRACT_P (node))
+ /* ??? The DIE parent is the "abstract" copy and the context_die
+ is the specification "copy". */
+ if (!DECL_ABSTRACT_P (node) && !in_lto_p)
{
/* This can happen when creating an inlined instance, in
which case we need to create a new DIE that will get
@@ -20075,7 +20403,6 @@ gen_type_die_for_member (tree type, tree
/* Forward declare these functions, because they are mutually recursive
with their set_block_* pairing functions. */
static void set_decl_origin_self (tree);
-static void set_decl_abstract_flags (tree, vec<tree> &);
/* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
@@ -20148,151 +20475,45 @@ set_decl_origin_self (tree decl)
}
}
\f
-/* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
- and if it wasn't 1 before, push it to abstract_vec vector.
- For all local decls and all local sub-blocks (recursively) do it
- too. */
-
-static void
-set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
-{
- tree local_decl;
- tree subblock;
- unsigned int i;
-
- if (!BLOCK_ABSTRACT (stmt))
- {
- abstract_vec.safe_push (stmt);
- BLOCK_ABSTRACT (stmt) = 1;
- }
-
- for (local_decl = BLOCK_VARS (stmt);
- local_decl != NULL_TREE;
- local_decl = DECL_CHAIN (local_decl))
- if (! DECL_EXTERNAL (local_decl))
- set_decl_abstract_flags (local_decl, abstract_vec);
-
- for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
- {
- local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
- if ((VAR_P (local_decl) && !TREE_STATIC (local_decl))
- || TREE_CODE (local_decl) == PARM_DECL)
- set_decl_abstract_flags (local_decl, abstract_vec);
- }
-
- for (subblock = BLOCK_SUBBLOCKS (stmt);
- subblock != NULL_TREE;
- subblock = BLOCK_CHAIN (subblock))
- set_block_abstract_flags (subblock, abstract_vec);
-}
-
-/* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
- to 1 and if it wasn't 1 before, push to abstract_vec vector.
- In the case where the decl is a FUNCTION_DECL also set the abstract
- flags for all of the parameters, local vars, local
- blocks and sub-blocks (recursively). */
-
-static void
-set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
-{
- if (!DECL_ABSTRACT_P (decl))
- {
- abstract_vec.safe_push (decl);
- DECL_ABSTRACT_P (decl) = 1;
- }
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- tree arg;
-
- for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
- if (!DECL_ABSTRACT_P (arg))
- {
- abstract_vec.safe_push (arg);
- DECL_ABSTRACT_P (arg) = 1;
- }
- if (DECL_INITIAL (decl) != NULL_TREE
- && DECL_INITIAL (decl) != error_mark_node)
- set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
- }
-}
-
-/* Generate the DWARF2 info for the "abstract" instance of a function which we
- may later generate inlined and/or out-of-line instances of.
-
- FIXME: In the early-dwarf world, this function, and most of the
- DECL_ABSTRACT code should be obsoleted. The early DIE _is_
- the abstract instance. All we would need to do is annotate
- the early DIE with the appropriate DW_AT_inline in late
- dwarf (perhaps in gen_inlined_subroutine_die).
-
- However, we can't do this yet, because LTO streaming of DIEs
- has not been implemented yet. */
+/* Mark the early DIE for DECL as the abstract instance. */
static void
dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
- tree save_fn;
- tree context;
- hash_table<decl_loc_hasher> *old_decl_loc_table;
- hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
- int old_call_site_count, old_tail_call_site_count;
- struct call_arg_loc_node *old_call_arg_locations;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
+ if (DECL_IGNORED_P (decl))
+ return;
+
old_die = lookup_decl_die (decl);
- if (old_die && get_AT (old_die, DW_AT_inline))
+ /* With early debug we always have an old DIE. */
+ gcc_assert (old_die != NULL);
+ if (get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
- /* We can be called while recursively when seeing block defining inlined subroutine
- DIE. Be sure to not clobber the outer location table nor use it or we would
- get locations in abstract instantces. */
- old_decl_loc_table = decl_loc_table;
- decl_loc_table = NULL;
- old_cached_dw_loc_list_table = cached_dw_loc_list_table;
- cached_dw_loc_list_table = NULL;
- old_call_arg_locations = call_arg_locations;
- call_arg_locations = NULL;
- old_call_site_count = call_site_count;
- call_site_count = -1;
- old_tail_call_site_count = tail_call_site_count;
- tail_call_site_count = -1;
-
- /* Be sure we've emitted the in-class declaration DIE (if any) first, so
- we don't get confused by DECL_ABSTRACT_P. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
+ /* Go ahead and put DW_AT_inline on the DIE. */
+ if (DECL_DECLARED_INLINE_P (decl))
{
- context = decl_class_context (decl);
- if (context)
- gen_type_die_for_member
- (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_inlined);
+ else
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
+ }
+ else
+ {
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_inlined);
+ else
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_not_inlined);
}
- /* Pretend we've just finished compiling this function. */
- save_fn = current_function_decl;
- current_function_decl = decl;
-
- auto_vec<tree, 64> abstract_vec;
- set_decl_abstract_flags (decl, abstract_vec);
- dwarf2out_decl (decl);
- unsigned int i;
- tree t;
- FOR_EACH_VEC_ELT (abstract_vec, i, t)
- if (TREE_CODE (t) == BLOCK)
- BLOCK_ABSTRACT (t) = 0;
- else
- DECL_ABSTRACT_P (t) = 0;
-
- current_function_decl = save_fn;
- decl_loc_table = old_decl_loc_table;
- cached_dw_loc_list_table = old_cached_dw_loc_list_table;
- call_arg_locations = old_call_arg_locations;
- call_site_count = old_call_site_count;
- tail_call_site_count = old_tail_call_site_count;
+ if (DECL_DECLARED_INLINE_P (decl)
+ && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
+ add_AT_flag (old_die, DW_AT_artificial, 1);
}
/* Helper function of premark_used_types() which gets called through
@@ -20513,7 +20734,12 @@ gen_subprogram_die (tree decl, dw_die_re
if (old_die && old_die->die_parent == NULL)
add_child_die (context_die, old_die);
- if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+ dw_die_ref c;
+ if (old_die
+ && (c = get_AT_ref (old_die, DW_AT_abstract_origin))
+ /* ??? In LTO all origin DIEs still refer to the early
+ debug copy. Detect that. */
+ && get_AT (c, DW_AT_inline))
{
/* If we have a DW_AT_abstract_origin we have a working
cached version. */
@@ -20581,7 +20807,9 @@ gen_subprogram_die (tree decl, dw_die_re
|| (old_die->die_parent
&& old_die->die_parent->die_tag == DW_TAG_module)
|| context_die == NULL)
- && (DECL_ARTIFICIAL (decl)
+ /* ??? This all (and above) should probably be simply
+ a ! early_dwarf check somehow. */
+ && ((DECL_ARTIFICIAL (decl) || in_lto_p)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) s.line))))
@@ -21410,6 +21638,24 @@ gen_variable_die (tree decl, tree origin
/* If a DIE was dumped early, it still needs location info.
Skip to where we fill the location bits. */
var_die = old_die;
+
+ /* ??? In LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Thus we dumped them again, also add a
+ reference to them. */
+ tree type = TREE_TYPE (decl_or_origin);
+ if (in_lto_p
+ && variably_modified_type_p
+ (type, decl_function_context (decl_or_origin)))
+ {
+ if (decl_by_reference_p (decl_or_origin))
+ add_type_attribute (var_die, TREE_TYPE (type),
+ TYPE_UNQUALIFIED, false, context_die);
+ else
+ add_type_attribute (var_die, type, decl_quals (decl_or_origin),
+ false, context_die);
+ }
+
goto gen_variable_die_location;
}
}
@@ -21781,12 +22027,6 @@ gen_inlined_subroutine_die (tree stmt, d
gcc_checking_assert (DECL_ABSTRACT_P (decl)
|| cgraph_function_possibly_inlined_p (decl));
- /* Emit info for the abstract instance first, if we haven't yet. We
- must emit this even if the block is abstract, otherwise when we
- emit the block below (or elsewhere), we may end up trying to emit
- a die whose origin die hasn't been emitted, and crashing. */
- dwarf2out_abstract_function (decl);
-
if (! BLOCK_ABSTRACT (stmt))
{
dw_die_ref subr_die
@@ -23319,7 +23559,20 @@ process_scope_var (tree stmt, tree decl,
stmt, context_die);
}
else
- gen_decl_die (decl, origin, NULL, context_die);
+ {
+ if (decl && DECL_P (decl))
+ {
+ die = lookup_decl_die (decl);
+
+ /* Early created DIEs do not have a parent as the decls refer
+ to the function as DECL_CONTEXT rather than the BLOCK. */
+ if (in_lto_p
+ && die && die->die_parent == NULL)
+ add_child_die (context_die, die);
+ }
+
+ gen_decl_die (decl, origin, NULL, context_die);
+ }
}
/* Generate all of the decls declared within a given scope and (recursively)
@@ -23731,6 +23984,9 @@ gen_decl_die (tree decl, tree origin, st
/* If we're emitting an out-of-line copy of an inline function,
emit info for the abstract instance and set up to refer to it. */
+ /* ??? We have output an abstract instance early already and
+ could just re-use that. This is how LTO treats all functions
+ for example. */
else if (cgraph_function_possibly_inlined_p (decl)
&& ! DECL_ABSTRACT_P (decl)
&& ! class_or_namespace_scope_p (context_die)
@@ -23744,7 +24000,9 @@ gen_decl_die (tree decl, tree origin, st
}
/* Otherwise we're emitting the primary DIE for this decl. */
- else if (debug_info_level > DINFO_LEVEL_TERSE)
+ else if (debug_info_level > DINFO_LEVEL_TERSE
+ /* Do not generate stray type DIEs in late LTO dumping. */
+ && early_dwarf)
{
/* Before we describe the FUNCTION_DECL itself, make sure that we
have its containing type. */
@@ -23811,20 +24069,37 @@ gen_decl_die (tree decl, tree origin, st
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
- /* Output any DIEs that are needed to specify the type of this data
- object. */
- if (decl_by_reference_p (decl_or_origin))
- gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
- else
- gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ /* Avoid generating stray type DIEs during late dwarf dumping.
+ All types have been dumped early. */
+ if (! (decl ? lookup_decl_die (decl) : NULL)
+ /* ??? But in LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Dump them again as happens for inlining
+ which copies both the decl and the types. */
+ /* ??? And even non-LTO needs to re-visit type DIEs to fill
+ in VLA bound information for example. */
+ || (/* in_lto_p && */
+ decl && variably_modified_type_p (TREE_TYPE (decl),
+ current_function_decl)))
+ {
+ /* Output any DIEs that are needed to specify the type of this data
+ object. */
+ if (decl_by_reference_p (decl_or_origin))
+ gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+ else
+ gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ }
- /* And its containing type. */
- class_origin = decl_class_context (decl_or_origin);
- if (class_origin != NULL_TREE)
- gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+ if (early_dwarf)
+ {
+ /* And its containing type. */
+ class_origin = decl_class_context (decl_or_origin);
+ if (class_origin != NULL_TREE)
+ gen_type_die_for_member (class_origin, decl_or_origin, context_die);
- /* And its containing namespace. */
- context_die = declare_in_namespace (decl_or_origin, context_die);
+ /* And its containing namespace. */
+ context_die = declare_in_namespace (decl_or_origin, context_die);
+ }
/* Now output the DIE to represent the data object itself. This gets
complicated because of the possibility that the VAR_DECL really
@@ -23934,6 +24209,16 @@ dwarf2out_early_global_decl (tree decl)
dwarf2out_decl (context);
}
+ /* Emit an abstract origin of a function first. This happens
+ with C++ constructor clones for example and makes
+ dwarf2out_abstract_function happy which requires the early
+ DIE of the abstract instance to be present. */
+ if (DECL_ABSTRACT_ORIGIN (decl))
+ {
+ current_function_decl = DECL_ABSTRACT_ORIGIN (decl);
+ dwarf2out_decl (DECL_ABSTRACT_ORIGIN (decl));
+ }
+
current_function_decl = decl;
}
dwarf2out_decl (decl);
@@ -23956,7 +24241,9 @@ dwarf2out_late_global_decl (tree decl)
{
dw_die_ref die = lookup_decl_die (decl);
- /* We have to generate early debug late for LTO. */
+ /* We may have to generate early debug late for LTO in case debug
+ was not enabled at compile-time or the target doesn't support
+ the LTO early debug scheme. */
if (! die && in_lto_p)
{
dwarf2out_decl (decl);
@@ -25314,7 +25601,8 @@ output_macinfo_op (macinfo_entry *ref)
case DW_MACRO_GNU_transparent_include:
dw2_asm_output_data (1, ref->code, "Transparent include");
ASM_GENERATE_INTERNAL_LABEL (label,
- DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+ DEBUG_MACRO_SECTION_LABEL,
+ ref->lineno + macinfo_label_base);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
break;
default:
@@ -25488,7 +25776,7 @@ save_macinfo_strings (void)
/* Output macinfo section(s). */
static void
-output_macinfo (void)
+output_macinfo (const char *debug_line_label, bool early_lto_debug)
{
unsigned i;
unsigned long length = vec_safe_length (macinfo_table);
@@ -25513,9 +25801,7 @@ output_macinfo (void)
dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
else
dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE,
- (!dwarf_split_debug_info ? debug_line_section_label
- : debug_skeleton_line_section_label),
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_label,
debug_line_section, NULL);
}
@@ -25570,6 +25856,10 @@ output_macinfo (void)
if (!macinfo_htab)
return;
+ /* Save the number of transparent includes so we can adjust the
+ label number for the fat LTO object DWARF. */
+ unsigned macinfo_label_base_adj = macinfo_htab->elements ();
+
delete macinfo_htab;
macinfo_htab = NULL;
@@ -25590,11 +25880,13 @@ output_macinfo (void)
dw2_asm_output_data (1, 0, "End compilation unit");
targetm.asm_out.named_section (debug_macinfo_section_name,
SECTION_DEBUG
- | SECTION_LINKONCE,
+ | SECTION_LINKONCE
+ | (early_lto_debug
+ ? SECTION_EXCLUDE : 0),
comdat_key);
ASM_GENERATE_INTERNAL_LABEL (label,
DEBUG_MACRO_SECTION_LABEL,
- ref->lineno);
+ ref->lineno + macinfo_label_base);
ASM_OUTPUT_LABEL (asm_out_file, label);
ref->code = 0;
ref->info = NULL;
@@ -25614,94 +25906,186 @@ output_macinfo (void)
default:
gcc_unreachable ();
}
+
+ macinfo_label_base += macinfo_label_base_adj;
}
-/* Initialize the various sections and labels for dwarf output. */
+/* Initialize the various sections and labels for dwarf output and prefix
+ them with PREFIX if non-NULL. */
static void
-init_sections_and_labels (void)
+init_sections_and_labels (bool early_lto_debug)
{
- if (!dwarf_split_debug_info)
- {
- debug_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- debug_loc_section = get_section (DEBUG_LOC_SECTION,
- SECTION_DEBUG, NULL);
- debug_macinfo_section_name
- = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
- debug_macinfo_section = get_section (debug_macinfo_section_name,
+ /* As we may get called multiple times have a generation count for labels. */
+ static unsigned generation = 0;
+
+ if (early_lto_debug)
+ {
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_macinfo_section_name = (dwarf_strict
+ ? DEBUG_LTO_MACINFO_SECTION
+ : DEBUG_LTO_MACRO_SECTION);
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ /* For macro info we have to refer to a debug_line section, so similar
+ to split-dwarf emit a skeleton one for early debug. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ }
+ else
+ {
+ /* ??? Which of the following do we need early? */
+ debug_info_section = get_section (DEBUG_LTO_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_LTO_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_skeleton_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+ generation);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
+ the main .o, but the skeleton_line goes into the split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ debug_str_offsets_section
+ = get_section (DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL,
+ generation);
+ debug_str_dwo_section = get_section (DEBUG_LTO_STR_DWO_SECTION,
+ DEBUG_STR_DWO_SECTION_FLAGS, NULL);
+ debug_macinfo_section_name
+ = (dwarf_strict
+ ? DEBUG_LTO_DWO_MACINFO_SECTION : DEBUG_LTO_DWO_MACRO_SECTION);
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ }
+ debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS
+ | SECTION_EXCLUDE, NULL);
+ }
+ else
+ {
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_loc_section = get_section (DEBUG_LOC_SECTION,
SECTION_DEBUG, NULL);
- }
- else
- {
- debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- debug_addr_section = get_section (DEBUG_ADDR_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
- DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
-
- /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
- the main .o, but the skeleton_line goes into the split off dwo. */
- debug_skeleton_line_section
- = get_section (DEBUG_DWO_LINE_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
- DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
- debug_str_offsets_section = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
- DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
- debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
- DEBUG_STR_DWO_SECTION_FLAGS, NULL);
- debug_macinfo_section_name
- = dwarf_strict ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
- debug_macinfo_section = get_section (debug_macinfo_section_name,
+ debug_macinfo_section_name
+ = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG, NULL);
+ }
+ else
+ {
+ debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_addr_section = get_section (DEBUG_ADDR_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+ generation);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections
+ stay in the main .o, but the skeleton_line goes into the
+ split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_DWO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ debug_str_offsets_section
+ = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL,
+ generation);
+ debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
- }
- debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_line_section = get_section (DEBUG_LINE_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
+ DEBUG_STR_DWO_SECTION_FLAGS,
+ NULL);
+ debug_macinfo_section_name
+ = dwarf_strict ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ }
+ debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
- debug_str_section = get_section (DEBUG_STR_SECTION,
- DEBUG_STR_SECTION_FLAGS, NULL);
- debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
+ debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_str_section = get_section (DEBUG_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
+ debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ }
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
- DEBUG_ABBREV_SECTION_LABEL, 0);
+ DEBUG_ABBREV_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
- DEBUG_INFO_SECTION_LABEL, 0);
+ DEBUG_INFO_SECTION_LABEL, generation);
+ info_section_emitted = false;
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
- DEBUG_LINE_SECTION_LABEL, 0);
+ DEBUG_LINE_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
- DEBUG_RANGES_SECTION_LABEL, 0);
+ DEBUG_RANGES_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
- DEBUG_ADDR_SECTION_LABEL, 0);
+ DEBUG_ADDR_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
dwarf_strict
? DEBUG_MACINFO_SECTION_LABEL
- : DEBUG_MACRO_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
+ : DEBUG_MACRO_SECTION_LABEL, generation);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL,
+ generation);
+
+ ++generation;
}
/* Set up for Dwarf output at the start of compilation. */
@@ -27899,6 +28283,22 @@ flush_limbo_die_list (void)
}
}
+/* Reset DIEs so we can output them again. */
+
+static void
+reset_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ /* Remove stuff we re-generate. */
+ die->die_mark = 0;
+ die->die_offset = 0;
+ die->die_abbrev = 0;
+ remove_AT (die, DW_AT_sibling);
+
+ FOR_EACH_CHILD (die, c, reset_dies (c));
+}
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
@@ -27924,6 +28324,47 @@ dwarf2out_finish (const char *)
gen_remaining_tmpl_value_param_die_attribute ();
+ if (flag_generate_lto)
+ {
+ gcc_assert (flag_fat_lto_objects);
+
+ /* Prune stuff so that dwarf2out_finish runs successfully
+ for the fat part of the object. */
+ reset_dies (comp_unit_die ());
+ for (limbo_die_node *node = cu_die_list; node; node = node->next)
+ reset_dies (node->die);
+
+ hash_table<comdat_type_hasher> comdat_type_table (100);
+ for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+ {
+ comdat_type_node **slot
+ = comdat_type_table.find_slot (ctnode, INSERT);
+
+ /* Don't reset types twice. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ reset_dies (ctnode->root_die);
+
+ *slot = ctnode;
+ }
+
+ /* Reset die CU symbol so we don't output it twice. */
+ comp_unit_die ()->die_id.die_symbol = NULL;
+
+ /* Remove DW_AT_macro from the early output. */
+ if (have_macinfo)
+ remove_AT (comp_unit_die (),
+ dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros);
+
+ /* Remove indirect string decisions. */
+ debug_str_hash->traverse<void *, reset_indirect_string> (NULL);
+ }
+
#if ENABLE_ASSERT_CHECKING
{
dw_die_ref die = comp_unit_die (), c;
@@ -27934,7 +28375,7 @@ dwarf2out_finish (const char *)
move_marked_base_types ();
/* Initialize sections and labels used for actual assembler output. */
- init_sections_and_labels ();
+ init_sections_and_labels (false);
/* Traverse the DIE's and add sibling attributes to those DIE's that
have children. */
@@ -28180,7 +28621,8 @@ dwarf2out_finish (const char *)
{
switch_to_section (debug_macinfo_section);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
- output_macinfo ();
+ output_macinfo (!dwarf_split_debug_info ? debug_line_section_label
+ : debug_skeleton_line_section_label, false);
dw2_asm_output_data (1, 0, "End compilation unit");
}
@@ -28315,6 +28757,118 @@ dwarf2out_early_finish (const char *file
/* The early debug phase is now finished. */
early_dwarf_finished = true;
+
+ /* Do not generate DWARF assembler now when not producing LTO bytecode. */
+ if (!flag_generate_lto)
+ return;
+
+ /* Now as we are going to output for LTO initialize sections and labels
+ to the LTO variants. We don't need a random-seed postfix as other
+ LTO sections as linking the LTO debug sections into one in a partial
+ link is fine. */
+ init_sections_and_labels (true);
+
+ /* ??? Mostly duplicated from dwarf2out_finish. */
+
+ /* Traverse the DIE's and add add sibling attributes to those DIE's
+ that have children. */
+ add_sibling_attributes (comp_unit_die ());
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ add_sibling_attributes (node->die);
+ for (comdat_type_node *ctnode = comdat_type_list;
+ ctnode != NULL; ctnode = ctnode->next)
+ add_sibling_attributes (ctnode->root_die);
+
+ if (have_macinfo)
+ add_AT_macptr (comp_unit_die (),
+ dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+ macinfo_section_label);
+
+ save_macinfo_strings ();
+
+ /* Output all of the compilation units. We put the main one last so that
+ the offsets are available to output_pubnames. */
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ output_comp_unit (node->die, 0);
+
+ hash_table<comdat_type_hasher> comdat_type_table (100);
+ for (comdat_type_node *ctnode = comdat_type_list;
+ ctnode != NULL; ctnode = ctnode->next)
+ {
+ comdat_type_node **slot = comdat_type_table.find_slot (ctnode, INSERT);
+
+ /* Don't output duplicate types. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
+ (!dwarf_split_debug_info
+ ? debug_line_section_label
+ : debug_skeleton_line_section_label));
+
+ output_comdat_type_unit (ctnode);
+ *slot = ctnode;
+ }
+
+ /* The AT_pubnames attribute needs to go in all skeleton dies, including
+ both the main_cu and all skeleton TUs. Making this call unconditional
+ would end up either adding a second copy of the AT_pubnames attribute, or
+ requiring a special case in add_top_level_skeleton_die_attrs. */
+ if (!dwarf_split_debug_info)
+ add_AT_pubnames (comp_unit_die ());
+
+ /* Stick a unique symbol to the main debuginfo section. */
+ compute_section_prefix_1 (comp_unit_die (), false);
+
+ /* Output the main compilation unit. We always need it if only for
+ the CU symbol. */
+ output_comp_unit (comp_unit_die (), true);
+
+ /* Output the abbreviation table. */
+ if (abbrev_die_table_in_use != 1)
+ {
+ switch_to_section (debug_abbrev_section);
+ ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
+ output_abbrev_section ();
+ }
+
+ /* Have to end the macro section. */
+ if (have_macinfo)
+ {
+ /* We have to save macinfo state if we need to output it again
+ for the FAT part of the object. */
+ vec<macinfo_entry, va_gc> *saved_macinfo_table = macinfo_table;
+ if (flag_fat_lto_objects)
+ macinfo_table = macinfo_table->copy ();
+
+ switch_to_section (debug_macinfo_section);
+ ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+ output_macinfo (debug_skeleton_line_section_label, true);
+ dw2_asm_output_data (1, 0, "End compilation unit");
+
+ /* Emit a skeleton debug_line section. */
+ switch_to_section (debug_skeleton_line_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
+ output_line_info (true);
+
+ if (flag_fat_lto_objects)
+ {
+ vec_free (macinfo_table);
+ macinfo_table = saved_macinfo_table;
+ }
+ }
+
+
+ /* If we emitted any indirect strings, output the string table too. */
+ if (debug_str_hash || skeleton_debug_str_hash)
+ output_indirect_strings ();
+
+ /* Switch back to the text section. */
+ switch_to_section (text_section);
}
/* Reset all state within dwarf2out.c so that we can rerun the compiler
Index: early-lto-debug/gcc/debug.h
===================================================================
--- early-lto-debug.orig/gcc/debug.h 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/debug.h 2016-10-21 09:16:45.521070306 +0200
@@ -146,6 +146,14 @@ struct gcc_debug_hooks
void (* imported_module_or_decl) (tree decl, tree name,
tree context, bool child);
+ /* Return true if a DIE for the tree is available and return a symbol
+ and offset that can be used to refer to it externally. */
+ bool (* die_ref_for_decl) (tree, const char **, unsigned HOST_WIDE_INT *);
+
+ /* Early debug information for the tree is available at symbol plus
+ offset externally. */
+ void (* register_external_die) (tree, const char *, unsigned HOST_WIDE_INT);
+
/* DECL is an inline function, whose body is present, but which is
not being output at this point. */
void (* deferred_inline_function) (tree decl);
@@ -205,6 +213,10 @@ extern void debug_nothing_tree_tree_tree
extern bool debug_true_const_tree (const_tree);
extern void debug_nothing_rtx_insn (rtx_insn *);
extern void debug_nothing_rtx_code_label (rtx_code_label *);
+extern bool debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *);
+extern void debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT);
/* Hooks for various debug formats. */
extern const struct gcc_debug_hooks do_nothing_debug_hooks;
Index: early-lto-debug/gcc/debug.c
===================================================================
--- early-lto-debug.orig/gcc/debug.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/debug.c 2016-10-21 09:16:45.521070306 +0200
@@ -48,6 +48,8 @@ const struct gcc_debug_hooks do_nothing_
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
@@ -138,3 +140,16 @@ debug_nothing_tree_int (tree decl ATTRIB
int local ATTRIBUTE_UNUSED)
{
}
+
+bool
+debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *)
+{
+ return false;
+}
+
+void
+debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT)
+{
+}
Index: early-lto-debug/gcc/dbxout.c
===================================================================
--- early-lto-debug.orig/gcc/dbxout.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/dbxout.c 2016-10-21 09:16:45.521070306 +0200
@@ -371,6 +371,8 @@ const struct gcc_debug_hooks dbx_debug_h
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
@@ -411,6 +413,8 @@ const struct gcc_debug_hooks xcoff_debug
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
Index: early-lto-debug/gcc/sdbout.c
===================================================================
--- early-lto-debug.orig/gcc/sdbout.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/sdbout.c 2016-10-21 09:16:45.521070306 +0200
@@ -300,6 +300,8 @@ const struct gcc_debug_hooks sdb_debug_h
sdbout_late_global_decl, /* late_global_decl */
sdbout_symbol, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
sdbout_label, /* label */
Index: early-lto-debug/gcc/lto/lto.c
===================================================================
--- early-lto-debug.orig/gcc/lto/lto.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto/lto.c 2016-10-21 09:16:45.525070353 +0200
@@ -1628,6 +1628,9 @@ unify_scc (struct data_in *data_in, unsi
free_node (scc->entries[i]);
}
+ /* Drop DIE references. */
+ dref_queue.truncate (0);
+
break;
}
@@ -1703,8 +1706,7 @@ lto_read_decls (struct lto_file_decl_dat
from);
if (len == 1
&& (TREE_CODE (first) == IDENTIFIER_NODE
- || TREE_CODE (first) == INTEGER_CST
- || TREE_CODE (first) == TRANSLATION_UNIT_DECL))
+ || TREE_CODE (first) == INTEGER_CST))
continue;
/* Try to unify the SCC with already existing ones. */
@@ -1743,16 +1745,6 @@ lto_read_decls (struct lto_file_decl_dat
if (TREE_CODE (t) == INTEGER_CST
&& !TREE_OVERFLOW (t))
cache_integer_cst (t);
- /* Register TYPE_DECLs with the debuginfo machinery. */
- if (!flag_wpa
- && TREE_CODE (t) == TYPE_DECL)
- {
- /* Dwarf2out needs location information.
- TODO: Moving this out of the streamer loop may noticealy
- improve ltrans linemap memory use. */
- data_in->location_cache.apply_location_cache ();
- debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
- }
if (!flag_ltrans)
{
/* Register variables and functions with the
@@ -1768,6 +1760,14 @@ lto_read_decls (struct lto_file_decl_dat
vec_safe_push (tree_with_vars, t);
}
}
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
+
if (seen_type)
num_type_scc_trees += len;
}
@@ -1947,7 +1947,12 @@ lto_section_with_id (const char *name, u
if (strncmp (name, section_name_prefix, strlen (section_name_prefix)))
return 0;
s = strrchr (name, '.');
- return s && sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
+ if (!s)
+ return 0;
+ /* If the section is not suffixed with an ID return. */
+ if ((size_t)(s - name) == strlen (section_name_prefix))
+ return 0;
+ return sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
}
/* Create file_data of each sub file id */
Index: early-lto-debug/gcc/lto-streamer-in.c
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer-in.c 2016-10-21 09:12:46.534320925 +0200
+++ early-lto-debug/gcc/lto-streamer-in.c 2016-10-21 09:16:45.525070353 +0200
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.
#include "except.h"
#include "cgraph.h"
#include "cfgloop.h"
+#include "debug.h"
struct freeing_string_slot_hasher : string_slot_hasher
@@ -1038,6 +1039,16 @@ input_function (tree fn_decl, struct dat
DECL_RESULT (fn_decl) = stream_read_tree (ib, data_in);
DECL_ARGUMENTS (fn_decl) = streamer_read_chain (ib, data_in);
+ /* Read debug args if available. */
+ unsigned n_debugargs = streamer_read_uhwi (ib);
+ if (n_debugargs)
+ {
+ vec<tree, va_gc> **debugargs = decl_debug_args_insert (fn_decl);
+ vec_safe_grow (*debugargs, n_debugargs);
+ for (unsigned i = 0; i < n_debugargs; ++i)
+ (**debugargs)[i] = stream_read_tree (ib, data_in);
+ }
+
/* Read the tree of lexical scopes for the function. */
DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
unsigned block_leaf_count = streamer_read_uhwi (ib);
@@ -1274,6 +1285,10 @@ lto_input_variable_constructor (struct l
}
+/* Queue of acummulated decl -> DIE mappings. Similar to locations those
+ are only applied to prevailing tree nodes during tree merging. */
+vec<dref_entry> dref_queue;
+
/* Read the physical representation of a tree node EXPR from
input block IB using the per-file context in DATA_IN. */
@@ -1294,6 +1309,23 @@ lto_read_tree_1 (struct lto_input_block
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_register_external_die. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *str = streamer_read_string (data_in, ib);
+ if (str)
+ {
+ unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+ dref_entry e = { expr, str, off };
+ dref_queue.safe_push (e);
+ }
+ }
+
#ifdef LTO_STREAMER_DEBUG
/* Remove the mapping to RESULT's original address set by
streamer_alloc_tree. */
@@ -1444,6 +1476,13 @@ lto_input_tree (struct lto_input_block *
{
unsigned len, entry_len;
lto_input_scc (ib, data_in, &len, &entry_len);
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
}
return lto_input_tree_1 (ib, data_in, tag, 0);
}
Index: early-lto-debug/gcc/lto-streamer-out.c
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer-out.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto-streamer-out.c 2016-10-21 09:16:45.525070353 +0200
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.
#include "cfgloop.h"
#include "builtins.h"
#include "gomp-constants.h"
+#include "debug.h"
static void lto_write_tree (struct output_block*, tree, bool);
@@ -406,6 +407,26 @@ lto_write_tree_1 (struct output_block *o
(ob->decl_state->symtab_node_encoder, expr);
stream_write_tree (ob, initial, ref_p);
}
+
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_die_ref_for_decl. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+ {
+ streamer_write_string (ob, ob->main_stream, sym, true);
+ streamer_write_uhwi (ob, off);
+ }
+ else
+ streamer_write_string (ob, ob->main_stream, NULL, true);
+ }
}
/* Write a physical representation of tree node EXPR to output block
@@ -765,6 +786,7 @@ DFS::DFS_write_tree_body (struct output_
declarations which should be eliminated by decl merging. Be sure none
leaks to this point. */
gcc_assert (DECL_ABSTRACT_ORIGIN (expr) != error_mark_node);
+ DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
if ((VAR_P (expr)
|| TREE_CODE (expr) == PARM_DECL)
@@ -2059,6 +2081,17 @@ output_function (struct cgraph_node *nod
stream_write_tree (ob, DECL_RESULT (function), true);
streamer_write_chain (ob, DECL_ARGUMENTS (function), true);
+ /* Output debug args if available. */
+ vec<tree, va_gc> **debugargs = decl_debug_args_lookup (function);
+ if (! debugargs)
+ streamer_write_uhwi (ob, 0);
+ else
+ {
+ streamer_write_uhwi (ob, (*debugargs)->length ());
+ for (unsigned i = 0; i < (*debugargs)->length (); ++i)
+ stream_write_tree (ob, (**debugargs)[i], true);
+ }
+
/* Output DECL_INITIAL for the function, which contains the tree of
lexical scopes. */
stream_write_tree (ob, DECL_INITIAL (function), true);
Index: early-lto-debug/gcc/lto-streamer.h
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer.h 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto-streamer.h 2016-10-21 09:16:45.525070353 +0200
@@ -1225,4 +1225,14 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ
DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
+/* Entry for the delayed registering of decl -> DIE references. */
+struct dref_entry {
+ tree decl;
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+};
+
+extern vec<dref_entry> dref_queue;
+
+
#endif /* GCC_LTO_STREAMER_H */
Index: early-lto-debug/gcc/lto-wrapper.c
===================================================================
--- early-lto-debug.orig/gcc/lto-wrapper.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto-wrapper.c 2016-10-21 09:16:45.525070353 +0200
@@ -70,6 +70,7 @@ static char **output_names;
static char **offload_names;
static char *offload_objects_file_name;
static char *makefile;
+static char *debug_obj;
const char tool_name[] = "lto-wrapper";
@@ -88,6 +89,8 @@ tool_cleanup (bool)
maybe_unlink (offload_objects_file_name);
if (makefile)
maybe_unlink (makefile);
+ if (debug_obj)
+ maybe_unlink (debug_obj);
for (i = 0; i < nr; ++i)
{
maybe_unlink (input_names[i]);
@@ -940,6 +943,67 @@ find_and_merge_options (int fd, off_t fi
return true;
}
+/* Copy early debug info sections from INFILE to a new file whose name
+ is returned. Return NULL on error. */
+
+const char *
+debug_objcopy (const char *infile)
+{
+ const char *outfile;
+ const char *errmsg;
+ int err;
+
+ const char *p;
+ off_t inoff = 0;
+ long loffset;
+ int consumed;
+ if ((p = strrchr (infile, '@'))
+ && p != infile
+ && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (p) == (unsigned int) consumed)
+ {
+ char *fname = xstrdup (infile);
+ fname[p - infile] = '\0';
+ infile = fname;
+ inoff = (off_t) loffset;
+ }
+ int infd = open (infile, O_RDONLY);
+ if (infd == -1)
+ return NULL;
+ simple_object_read *inobj = simple_object_start_read (infd, inoff,
+ "__GNU_LTO",
+ &errmsg, &err);
+ if (!inobj)
+ return NULL;
+
+ off_t off, len;
+ if (simple_object_find_section (inobj, ".gnu.debuglto_.debug_info",
+ &off, &len, &errmsg, &err) != 1)
+ {
+ if (errmsg)
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+
+ simple_object_release_read (inobj);
+ close (infd);
+ return NULL;
+ }
+
+ outfile = make_temp_file ("debugobjtem");
+ errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err);
+ if (errmsg)
+ {
+ unlink_if_ordinary (outfile);
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+ }
+
+ simple_object_release_read (inobj);
+ close (infd);
+
+ return outfile;
+}
+
+
+
/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
static void
@@ -964,8 +1028,10 @@ run_gcc (unsigned argc, char *argv[])
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
- unsigned lto_argc = 0;
- char **lto_argv;
+ unsigned lto_argc = 0, ltoobj_argc = 0;
+ char **lto_argv, **ltoobj_argv;
+ bool skip_debug = false;
+ unsigned n_debugobj;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
@@ -984,6 +1050,7 @@ run_gcc (unsigned argc, char *argv[])
/* Allocate array for input object files with LTO IL,
and for possible preceding arguments. */
lto_argv = XNEWVEC (char *, argc);
+ ltoobj_argv = XNEWVEC (char *, argc);
/* Look at saved options in the IL files. */
for (i = 1; i < argc; ++i)
@@ -1026,7 +1093,7 @@ run_gcc (unsigned argc, char *argv[])
collect_gcc))
{
have_lto = true;
- lto_argv[lto_argc++] = argv[i];
+ ltoobj_argv[ltoobj_argc++] = argv[i];
}
close (fd);
}
@@ -1087,6 +1154,17 @@ run_gcc (unsigned argc, char *argv[])
}
}
+ /* Output lto-wrapper invocation command. */
+ if (verbose)
+ {
+ for (i = 0; i < argc; ++i)
+ {
+ fputs (argv[i], stderr);
+ fputc (' ', stderr);
+ }
+ fputc ('\n', stderr);
+ }
+
if (no_partition)
{
lto_mode = LTO_MODE_LTO;
@@ -1276,18 +1354,105 @@ cont1:
obstack_ptr_grow (&argv_obstack, "-fwpa");
}
- /* Append the input objects and possible preceding arguments. */
+ /* Append input arguments. */
for (i = 0; i < lto_argc; ++i)
obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+ /* Append the input objects. */
+ for (i = 0; i < ltoobj_argc; ++i)
+ obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
+ /* Handle early generated debug information. At compile-time
+ we output early DWARF debug info into .gnu.debuglto_ prefixed
+ sections. LTRANS object DWARF debug info refers to that.
+ So we need to transfer the .gnu.debuglto_ sections to the final
+ link. Ideally the linker plugin interface would allow us to
+ not claim those sections and instruct the linker to keep
+ them, renaming them in the process. For now we extract and
+ rename those sections via a simple-object interface to produce
+ regular objects containing only the early debug info. We
+ then partially link those to a single early debug info object
+ and pass that as additional output back to the linker plugin. */
+
+ /* Prepare the partial link to gather the compile-time generated
+ debug-info into a single input for the final link. */
+ debug_obj = make_temp_file ("debugobj");
+ obstack_ptr_grow (&argv_obstack, collect_gcc);
+ for (i = 1; i < decoded_options_count; ++i)
+ {
+ /* Retain linker choice and -B. */
+ if (decoded_options[i].opt_index == OPT_B
+ || decoded_options[i].opt_index == OPT_fuse_ld_bfd
+ || decoded_options[i].opt_index == OPT_fuse_ld_gold)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Retain all target options, this preserves -m32 for example. */
+ if (cl_options[decoded_options[i].opt_index].flags & CL_TARGET)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Recognize -g0. */
+ if (decoded_options[i].opt_index == OPT_g
+ && strcmp (decoded_options[i].arg, "0") == 0)
+ skip_debug = true;
+ }
+ obstack_ptr_grow (&argv_obstack, "-r");
+ obstack_ptr_grow (&argv_obstack, "-nostdlib");
+ obstack_ptr_grow (&argv_obstack, "-o");
+ obstack_ptr_grow (&argv_obstack, debug_obj);
+
+ /* Copy the early generated debug info from the objects to temporary
+ files and append those to the partial link commandline. */
+ n_debugobj = 0;
+ if (! skip_debug)
+ for (i = 0; i < ltoobj_argc; ++i)
+ {
+ const char *tem;
+ if ((tem = debug_objcopy (ltoobj_argv[i])))
+ {
+ obstack_ptr_grow (&argv_obstack, tem);
+ n_debugobj++;
+ }
+ }
+
+ /* Link them all into a single object. Ideally this would reduce
+ disk space usage mainly due to .debug_str merging but unfortunately
+ GNU ld doesn't perform this with -r. */
+ if (n_debugobj)
+ {
+ obstack_ptr_grow (&argv_obstack, NULL);
+ const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+ fork_execute (debug_link_argv[0],
+ CONST_CAST (char **, debug_link_argv), false);
+
+ /* And dispose the temporaries. */
+ for (i = 0; debug_link_argv[i]; ++i)
+ ;
+ for (--i; i > 0; --i)
+ {
+ if (strcmp (debug_link_argv[i], debug_obj) == 0)
+ break;
+ maybe_unlink (debug_link_argv[i]);
+ }
+ }
+ else
+ {
+ unlink_if_ordinary (debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ skip_debug = true;
+ }
+
if (lto_mode == LTO_MODE_LTO)
{
printf ("%s\n", flto_out);
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
free (flto_out);
flto_out = NULL;
}
@@ -1436,6 +1601,12 @@ cont:
for (i = 0; i < nr; ++i)
maybe_unlink (input_names[i]);
}
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
for (i = 0; i < nr; ++i)
{
fputs (output_names[i], stdout);
Index: early-lto-debug/gcc/tree-streamer-in.c
===================================================================
--- early-lto-debug.orig/gcc/tree-streamer-in.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/tree-streamer-in.c 2016-10-21 09:16:45.529070399 +0200
@@ -706,10 +706,7 @@ lto_input_ts_decl_common_tree_pointers (
DECL_SIZE (expr) = stream_read_tree (ib, data_in);
DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
-
- /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
Index: early-lto-debug/gcc/tree-streamer-out.c
===================================================================
--- early-lto-debug.orig/gcc/tree-streamer-out.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/tree-streamer-out.c 2016-10-21 09:16:45.529070399 +0200
@@ -583,10 +583,7 @@ write_ts_decl_common_tree_pointers (stru
special handling in LTO, it must be handled by streamer hooks. */
stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
-
- /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ stream_write_tree (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
Index: early-lto-debug/gcc/config/darwin.c
===================================================================
--- early-lto-debug.orig/gcc/config/darwin.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/config/darwin.c 2016-10-21 09:16:45.529070399 +0200
@@ -1919,7 +1919,8 @@ darwin_asm_lto_end (void)
}
static void
-darwin_asm_dwarf_section (const char *name, unsigned int flags, tree decl);
+darwin_asm_dwarf_section (const char *name, unsigned int flags,
+ tree decl, bool is_for_lto);
/* Called for the TARGET_ASM_NAMED_SECTION hook. */
@@ -1961,7 +1962,9 @@ darwin_asm_named_section (const char *na
vec_safe_push (lto_section_names, e);
}
else if (strncmp (name, "__DWARF,", 8) == 0)
- darwin_asm_dwarf_section (name, flags, decl);
+ darwin_asm_dwarf_section (name, flags, decl, false);
+ else if (strncmp (name, "__GNU_DWARF_LTO,", 16) == 0)
+ darwin_asm_dwarf_section (name, flags, decl, true);
else
fprintf (asm_out_file, "\t.section %s\n", name);
}
@@ -2739,19 +2742,37 @@ static GTY (()) vec<dwarf_sect_used_entr
static void
darwin_asm_dwarf_section (const char *name, unsigned int flags,
- tree ARG_UNUSED (decl))
+ tree ARG_UNUSED (decl), bool is_for_lto)
{
unsigned i;
- int namelen;
- const char * sname;
+ int namelen, extra = 0;
+ const char *sect, *lto_add = "";
+ char sname[64];
dwarf_sect_used_entry *ref;
bool found = false;
- gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
- == (SECTION_DEBUG | SECTION_NAMED));
- /* We know that the name starts with __DWARF, */
- sname = name + 8;
- namelen = strchr (sname, ',') - sname;
- gcc_assert (namelen);
+
+ gcc_checking_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+ == (SECTION_DEBUG | SECTION_NAMED));
+
+ /* We know that the name starts with __DWARF, or __GNU_DAWRF_LTO */
+ sect = strchr (name, ',') + 1;
+ namelen = strchr (sect, ',') - sect;
+ gcc_checking_assert (namelen);
+
+ /* The section switch is output as written... */
+ fprintf (asm_out_file, "\t.section %s\n", name);
+
+ /* ... but the string we keep to make section start labels needs
+ adjustment for lto cases. */
+ if (is_for_lto)
+ {
+ lto_add = "_lto";
+ extra = 4;
+ }
+
+ snprintf (sname, 64, "%.*s%.*s", namelen, sect, extra, lto_add);
+ namelen += extra;
+
if (dwarf_sect_names_table == NULL)
vec_alloc (dwarf_sect_names_table, 16);
else
@@ -2769,7 +2790,6 @@ darwin_asm_dwarf_section (const char *na
}
}
- fprintf (asm_out_file, "\t.section %s\n", name);
if (!found)
{
dwarf_sect_used_entry e;
@@ -2822,14 +2842,24 @@ darwin_asm_output_dwarf_offset (FILE *fi
HOST_WIDE_INT offset, section *base)
{
char sname[64];
- int namelen;
+ int namelen, extra = 0;
+ bool is_for_lto;
+ const char *lto_add = "";
+
+ gcc_checking_assert (base->common.flags & SECTION_NAMED);
+ is_for_lto = strncmp (base->named.name, "__GNU_DWARF_LTO,", 16) == 0;
+ gcc_checking_assert (is_for_lto
+ || strncmp (base->named.name, "__DWARF,", 8) == 0);
+ const char *name = strchr (base->named.name, ',') + 1;
+ gcc_checking_assert (name);
- gcc_assert (base->common.flags & SECTION_NAMED);
- gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
- gcc_assert (strchr (base->named.name + 8, ','));
-
- namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
- sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
+ namelen = strchr (name, ',') - (name);
+ if (is_for_lto)
+ {
+ lto_add = "_lto";
+ extra = 4;
+ }
+ snprintf (sname, 64, "*Lsection%.*s%.*s", namelen, name, extra, lto_add);
darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
}
Index: early-lto-debug/gcc/config/darwin.h
===================================================================
--- early-lto-debug.orig/gcc/config/darwin.h 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/config/darwin.h 2016-10-21 09:16:45.529070399 +0200
@@ -420,7 +420,14 @@ extern GTY(()) int darwin_ms_struct;
#define DEBUG_PUBTYPES_SECTION "__DWARF,__debug_pubtypes,regular,debug"
#define DEBUG_STR_SECTION "__DWARF,__debug_str,regular,debug"
#define DEBUG_RANGES_SECTION "__DWARF,__debug_ranges,regular,debug"
-#define DEBUG_MACRO_SECTION "__DWARF,__debug_macro,regular,debug"
+#define DEBUG_MACRO_SECTION "__DWARF,__debug_macro,regular,debug"
+
+#define DEBUG_LTO_INFO_SECTION "__GNU_DWARF_LTO,__debug_info,regular,debug"
+#define DEBUG_LTO_ABBREV_SECTION "__GNU_DWARF_LTO,__debug_abbrev,regular,debug"
+#define DEBUG_LTO_MACINFO_SECTION "__GNU_DWARF_LTO,__debug_macinfo,regular,debug"
+#define DEBUG_LTO_LINE_SECTION "__GNU_DWARF_LTO,__debug_line,regular,debug"
+#define DEBUG_LTO_STR_SECTION "__GNU_DWARF_LTO,__debug_str,regular,debug"
+#define DEBUG_LTO_MACRO_SECTION "__GNU_DWARF_LTO,__debug_macro,regular,debug"
#define TARGET_WANT_DEBUG_PUB_SECTIONS true
Index: early-lto-debug/gcc/vmsdbgout.c
===================================================================
--- early-lto-debug.orig/gcc/vmsdbgout.c 2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/vmsdbgout.c 2016-10-21 09:16:45.529070399 +0200
@@ -196,6 +196,8 @@ const struct gcc_debug_hooks vmsdbg_debu
vmsdbgout_late_global_decl,
vmsdbgout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
vmsdbgout_abstract_function,
debug_nothing_rtx_code_label, /* label */
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PING][PATCH][2/2] Early LTO debug -- main part
2016-10-21 11:26 [PATCH][2/2] Early LTO debug -- main part Richard Biener
@ 2016-11-11 8:07 ` Richard Biener
2016-11-22 22:50 ` Jason Merrill
0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2016-11-11 8:07 UTC (permalink / raw)
To: gcc-patches
On Fri, 21 Oct 2016, Richard Biener wrote:
>
> This is the main part of the early LTO debug support. The main parts
> of the changes are to dwarf2out.c where most of the changes are related
> to the fact that we eventually have to output debug info twice, once
> for the early LTO part and once for the fat part of the object file.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu with ASAN and TSAN
> extra FAILs (see PR78063, a libbacktrace missing feature or libsanitizer
> being too pessimistic). There's an extra
>
> XPASS: gcc.dg/guality/inline-params.c -O2 -flto -fuse-linker-plugin
> -fno-fat-lto-objects execution test
>
> the previously reported extra VLA guality FAILs are gone.
>
> I've compared testresults with -flto -g added for all languages and
> only see expected differences (libstdc++ pretty printers now work,
> most scan-assembler-times debug testcases fail because we have everything
> twice now).
>
> See https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01842.html for
> the last posting of this patch which has a high-level overview of
> Early LTO debug. You may want to refer to the slides I presented
> at the GNU Cauldron as well.
I have refreshed the patch after the DWARF5 changes, re-LTO-bootstrapped
and retested (also comparing -g -flto with/without the patch) with no
changes in results. Patch [1/2] still applies without changes.
Thanks,
Richard.
2016-10-21 Richard Biener <rguenther@suse.de>
* debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and
register_external_die hooks.
(debug_false_tree_charstarstar_uhwistar): Declare.
(debug_nothing_tree_charstar_uhwi): Likewise.
* debug.c (do_nothing_debug_hooks): Adjust.
(debug_false_tree_charstarstar_uhwistar): New do nothing.
(debug_nothing_tree_charstar_uhwi): Likewise.
* dbxout.c (dbx_debug_hooks): Adjust.
(xcoff_debug_hooks): Likewise.
* sdbout.c (sdb_debug_hooks): Likewise.
* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
* dwarf2out.c (macinfo_label_base): New global.
(dwarf2out_register_external_die): New function for the
register_external_die hook.
(dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl.
(dwarf2_debug_hooks): Use them.
(dwarf2_lineno_debug_hooks): Adjust.
(struct die_struct): Add with_offset flag.
(DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION,
DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION,
DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION,
DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION,
DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros
defining section names for the early LTO debug variants.
(reset_indirect_string): New helper.
(add_AT_external_die_ref): Helper for dwarf2out_register_external_die.
(print_dw_val): Add support for offsetted symbol references.
(compute_section_prefix_1): Split out worker to distinguish
the comdat from the LTO case.
(compute_section_prefix): Wrap old comdat case here.
(output_die): Skip DIE symbol output for the LTO added one.
Handle DIE symbol references with offset.
(output_comp_unit): Guard section name mangling properly.
For LTO debug sections emit a symbol at the section beginning
which we use to refer to its DIEs.
(add_abstract_origin_attribute): For DIEs registered via
dwarf2out_register_external_die directly refer to the early
DIE rather than indirectly through the shadow one we created.
(gen_array_type_die): When generating early LTO debug do
not emit DW_AT_string_length.
(gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs
late when in LTO.
(gen_subprogram_die): Adjust the check for whether we face
a concrete instance DIE for an inline we can reuse for the
late LTO case. Likewise avoid another specification DIE
for early built declarations/definitions for the late LTO case.
(gen_variable_die): Add type references for late duplicated VLA dies
when in late LTO.
(gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function,
we have the abstract instance already.
(process_scope_var): Adjust decl DIE contexts in LTO which
first puts them in limbo.
(gen_decl_die): Do not generate type DIEs late apart from
types for VLAs or for decls we do not yet have a DIE.
(dwarf2out_early_global_decl): Make sure to create DIEs
for abstract instances of a decl first.
(dwarf2out_late_global_decl): Adjust comment.
(output_macinfo_op): With multiple macro sections use
macinfo_label_base to distinguish labels.
(output_macinfo): Likewise. Update macinfo_label_base.
Pass in the line info label.
(init_sections_and_labels): Add early LTO debug flag parameter
and generate different sections and names if set. Add generation
counter for the labels so we can have multiple of them.
(reset_dies): Helper to allow DIEs to be output multiple times.
(dwarf2out_finish): When outputting DIEs to the fat part of an
LTO object first reset DIEs.
(dwarf2out_early_finish): Output early DIEs when generating LTO.
Cleanups we can do (and need) when removing the "old" LTO path and add
the early LTO path.
(set_decl_abstract_flags): Remove.
(set_block_abstract_flags): Likewise.
(dwarf2out_abstract_function): Treat the early generated DIEs
as the abstract copy and only add DW_AT_inline and
DW_AT_artificial here.
* lto-streamer-in.c: Include debug.h.
(dref_queue): New global.
(lto_read_tree_1): Stream in DIE references.
(lto_input_tree): Register DIE references.
(input_function): Stream DECL_DEBUG_ARGS.
* lto-streamer-out.c: Include debug.h.
(lto_write_tree_1): Output DIE references.
(DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN.
(output_function): Stream DECL_DEBUG_ARGS.
* tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers):
Stream DECL_ABSTRACT_ORIGIN.
* tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise.
* lto-streamer.h (struct dref_entry): Declare.
(dref_queue): Likewise.
* lto-wrapper.c (debug_obj): New global.
(tool_cleanup): Unlink it if required.
(debug_objcopy): New function.
(run_gcc): Handle early debug sections in the IL files by
extracting them to separate files, partially linkin them and
feeding the result back as result to the linker.
* config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION,
DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION,
DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug
sections into a separate segment.
* config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO
segments.
(darwin_asm_dwarf_section): Likewise.
(darwin_asm_output_dwarf_offset): Likewise.
lto/
* lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs.
(lto_read_decls): Process TRANSLATION_UNIT_DECLs. Remove
TYPE_DECL debug processing, register DIE references from
prevailing SCCs with the debug machinery.
(lto_section_with_id): Handle LTO debug sections.
Index: early-lto-debug/gcc/dwarf2out.c
===================================================================
--- early-lto-debug.orig/gcc/dwarf2out.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/dwarf2out.c 2016-11-10 12:53:35.087921558 +0100
@@ -161,6 +161,7 @@ static GTY(()) section *debug_aranges_se
static GTY(()) section *debug_addr_section;
static GTY(()) section *debug_macinfo_section;
static const char *debug_macinfo_section_name;
+static unsigned macinfo_label_base = 1;
static GTY(()) section *debug_line_section;
static GTY(()) section *debug_skeleton_line_section;
static GTY(()) section *debug_loc_section;
@@ -2669,6 +2670,10 @@ static void dwarf2out_begin_function (tr
static void dwarf2out_end_function (unsigned int);
static void dwarf2out_register_main_translation_unit (tree unit);
static void dwarf2out_set_name (tree, tree);
+static void dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off);
+static bool dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off);
/* The debug hooks structure. */
@@ -2703,6 +2708,8 @@ const struct gcc_debug_hooks dwarf2_debu
dwarf2out_late_global_decl,
dwarf2out_type_decl, /* type_decl */
dwarf2out_imported_module_or_decl,
+ dwarf2out_die_ref_for_decl,
+ dwarf2out_register_external_die,
debug_nothing_tree, /* deferred_inline_function */
/* The DWARF 2 backend tries to reduce debugging bloat by not
emitting the abstract description of inline functions until
@@ -2744,6 +2751,8 @@ const struct gcc_debug_hooks dwarf2_line
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
@@ -2872,6 +2881,9 @@ typedef struct GTY((chain_circular ("%h.
/* Die is used and must not be pruned as unused. */
BOOL_BITFIELD die_perennial_p : 1;
BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+ /* For an external ref to die_symbol if die_offset contains an extra
+ offset to that symbol. */
+ BOOL_BITFIELD with_offset : 1;
/* Whether this DIE was removed from the DIE tree, for example via
prune_unused_types. We don't consider those present from the
DIE lookup routines. */
@@ -3657,12 +3669,24 @@ new_addr_loc_descr (rtx addr, enum dtpre
#ifndef DEBUG_DWO_INFO_SECTION
#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_INFO_SECTION
+#define DEBUG_LTO_DWO_INFO_SECTION ".gnu.debuglto_.debug_info.dwo"
+#endif
+#ifndef DEBUG_LTO_INFO_SECTION
+#define DEBUG_LTO_INFO_SECTION ".gnu.debuglto_.debug_info"
+#endif
#ifndef DEBUG_ABBREV_SECTION
#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
#ifndef DEBUG_DWO_ABBREV_SECTION
#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_ABBREV_SECTION
+#define DEBUG_LTO_DWO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev.dwo"
+#endif
+#ifndef DEBUG_LTO_ABBREV_SECTION
+#define DEBUG_LTO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev"
+#endif
#ifndef DEBUG_ARANGES_SECTION
#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
@@ -3675,18 +3699,33 @@ new_addr_loc_descr (rtx addr, enum dtpre
#ifndef DEBUG_DWO_MACINFO_SECTION
#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_MACINFO_SECTION
+#define DEBUG_LTO_DWO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo.dwo"
+#endif
+#ifndef DEBUG_LTO_MACINFO_SECTION
+#define DEBUG_LTO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo"
+#endif
#ifndef DEBUG_DWO_MACRO_SECTION
#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo"
#endif
#ifndef DEBUG_MACRO_SECTION
#define DEBUG_MACRO_SECTION ".debug_macro"
#endif
+#ifndef DEBUG_LTO_DWO_MACRO_SECTION
+#define DEBUG_LTO_DWO_MACRO_SECTION ".gnu.debuglto_.debug_macro.dwo"
+#endif
+#ifndef DEBUG_LTO_MACRO_SECTION
+#define DEBUG_LTO_MACRO_SECTION ".gnu.debuglto_.debug_macro"
+#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
#ifndef DEBUG_DWO_LINE_SECTION
#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
#endif
+#ifndef DEBUG_LTO_LINE_SECTION
+#define DEBUG_LTO_LINE_SECTION ".gnu.debuglto_.debug_line.dwo"
+#endif
#ifndef DEBUG_LOC_SECTION
#define DEBUG_LOC_SECTION ".debug_loc"
#endif
@@ -3715,12 +3754,21 @@ new_addr_loc_descr (rtx addr, enum dtpre
#ifndef DEBUG_DWO_STR_OFFSETS_SECTION
#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_STR_OFFSETS_SECTION
+#define DEBUG_LTO_DWO_STR_OFFSETS_SECTION ".gnu.debuglto_.debug_str_offsets.dwo"
+#endif
#ifndef DEBUG_STR_DWO_SECTION
#define DEBUG_STR_DWO_SECTION ".debug_str.dwo"
#endif
+#ifndef DEBUG_LTO_STR_DWO_SECTION
+#define DEBUG_LTO_STR_DWO_SECTION ".gnu.debuglto_.debug_str.dwo"
+#endif
#ifndef DEBUG_STR_SECTION
#define DEBUG_STR_SECTION ".debug_str"
#endif
+#ifndef DEBUG_LTO_STR_SECTION
+#define DEBUG_LTO_STR_SECTION ".gnu.debuglto_.debug_str"
+#endif
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
#endif
@@ -4333,6 +4381,24 @@ set_indirect_string (struct indirect_str
}
}
+/* A helper function for dwarf2out_finish, called to reset indirect
+ string decisions done for early LTO dwarf output before fat object
+ dwarf output. */
+
+int
+reset_indirect_string (indirect_string_node **h, void *)
+{
+ struct indirect_string_node *node = *h;
+ if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+ {
+ free (node->label);
+ node->label = NULL;
+ node->form = (dwarf_form) 0;
+ node->index = 0;
+ }
+ return 1;
+}
+
/* Find out whether a string should be output inline in DIE
or out-of-line in .debug_str section. */
@@ -5357,6 +5423,186 @@ lookup_decl_die (tree decl)
return *die;
}
+
+/* For DECL which might have early dwarf output query a SYMBOL + OFFSET
+ style reference. Return true if we found one refering to a DIE for
+ DECL, otherwise return false. */
+
+static bool
+dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off)
+{
+ dw_die_ref die;
+
+ if (flag_wpa && !decl_die_table)
+ return false;
+
+ if (TREE_CODE (decl) == BLOCK)
+ die = BLOCK_DIE (decl);
+ else
+ die = lookup_decl_die (decl);
+ if (!die)
+ return false;
+
+ /* During WPA stage we currently use DIEs to store the
+ decl <-> label + offset map. That's quite inefficient but it
+ works for now. */
+ if (flag_wpa)
+ {
+ dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
+ if (!ref)
+ {
+ gcc_assert (die == comp_unit_die ());
+ return false;
+ }
+ *off = ref->die_offset;
+ *sym = ref->die_id.die_symbol;
+ return true;
+ }
+
+ /* Similar to get_ref_die_offset_label, but using the "correct"
+ label. */
+ *off = die->die_offset;
+ while (die->die_parent)
+ die = die->die_parent;
+ /* For the containing CU DIE we compute a die_symbol in
+ compute_section_prefix. */
+ gcc_assert (die->die_tag == DW_TAG_compile_unit
+ && die->die_id.die_symbol != NULL);
+ *sym = die->die_id.die_symbol;
+ return true;
+}
+
+/* Add a reference of kind ATTR_KIND to a DIE at SYMBOL + OFFSET to DIE. */
+
+static void
+add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *symbol, HOST_WIDE_INT offset)
+{
+ /* Create a fake DIE that contains the reference. Don't use
+ new_die because we don't want to end up in the limbo list. */
+ dw_die_ref ref = ggc_cleared_alloc<die_node> ();
+ ref->die_tag = die->die_tag;
+ ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
+ ref->die_offset = offset;
+ ref->with_offset = 1;
+ add_AT_die_ref (die, attr_kind, ref);
+}
+
+/* Create a DIE for DECL if required and add a reference to a DIE
+ at SYMBOL + OFFSET which contains attributes dumped early. */
+
+static void
+dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off)
+{
+ if (debug_info_level == DINFO_LEVEL_NONE)
+ return;
+
+ if (flag_wpa && !decl_die_table)
+ decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
+
+ dw_die_ref die
+ = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+ gcc_assert (!die);
+
+ tree ctx;
+ dw_die_ref parent = NULL;
+ /* Need to lookup a DIE for the decls context - the containing
+ function or translation unit. */
+ if (TREE_CODE (decl) == BLOCK)
+ {
+ ctx = BLOCK_SUPERCONTEXT (decl);
+ /* ??? We do not output DIEs for all scopes thus skip as
+ many DIEs as needed. */
+ while (TREE_CODE (ctx) == BLOCK
+ && !BLOCK_DIE (ctx))
+ ctx = BLOCK_SUPERCONTEXT (ctx);
+ }
+ else
+ ctx = DECL_CONTEXT (decl);
+ while (ctx && TYPE_P (ctx))
+ ctx = TYPE_CONTEXT (ctx);
+ if (ctx)
+ {
+ if (TREE_CODE (ctx) == BLOCK)
+ parent = BLOCK_DIE (ctx);
+ else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
+ /* Keep the 1:1 association during WPA. */
+ && !flag_wpa)
+ /* Otherwise all late annotations go to the main CU which
+ imports the original CUs. */
+ parent = comp_unit_die ();
+ else if (TREE_CODE (ctx) == FUNCTION_DECL
+ && TREE_CODE (decl) != PARM_DECL
+ && TREE_CODE (decl) != BLOCK)
+ /* Leave function local entities parent determination to when
+ we process scope vars. */
+ ;
+ else
+ parent = lookup_decl_die (ctx);
+ }
+ else
+ /* ??? In some cases the C++ FE (at least) fails to
+ set DECL_CONTEXT properly. Simply globalize stuff
+ in this case. For example
+ __dso_handle created via iostream line 74 col 25. */
+ parent = comp_unit_die ();
+ /* Create a DIE "stub". */
+ switch (TREE_CODE (decl))
+ {
+ case TRANSLATION_UNIT_DECL:
+ if (! flag_wpa)
+ {
+ die = comp_unit_die ();
+ dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
+ add_AT_external_die_ref (import, DW_AT_import, sym, off);
+ /* We re-target all CU decls to the LTRANS CU DIE, so no need
+ to create a DIE for the original CUs. */
+ return;
+ }
+ /* Keep the 1:1 association during WPA. */
+ die = new_die (DW_TAG_compile_unit, NULL, decl);
+ break;
+ case NAMESPACE_DECL:
+ /* ??? LANG issue - DW_TAG_module for fortran. Either look
+ at the input language (if we have enough DECL_CONTEXT to follow)
+ or use a bit in tree_decl_with_vis to record the distinction. */
+ die = new_die (DW_TAG_namespace, parent, decl);
+ break;
+ case FUNCTION_DECL:
+ die = new_die (DW_TAG_subprogram, parent, decl);
+ break;
+ case VAR_DECL:
+ die = new_die (DW_TAG_variable, parent, decl);
+ break;
+ case RESULT_DECL:
+ die = new_die (DW_TAG_variable, parent, decl);
+ break;
+ case PARM_DECL:
+ die = new_die (DW_TAG_formal_parameter, parent, decl);
+ break;
+ case CONST_DECL:
+ die = new_die (DW_TAG_constant, parent, decl);
+ break;
+ case LABEL_DECL:
+ die = new_die (DW_TAG_label, parent, decl);
+ break;
+ case BLOCK:
+ die = new_die (DW_TAG_lexical_block, parent, decl);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (TREE_CODE (decl) == BLOCK)
+ BLOCK_DIE (decl) = die;
+ else
+ equate_decl_number_to_die (decl, die);
+
+ /* Add a reference to the DIE providing early debug at $sym + off. */
+ add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
+}
+
/* Returns a hash value for X (which really is a var_loc_list). */
inline hashval_t
@@ -5844,7 +6090,11 @@ print_dw_val (dw_val_node *val, bool rec
die->die_id.die_type_node->signature);
}
else if (die->die_id.die_symbol)
- fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ {
+ fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ if (die->with_offset)
+ fprintf (outfile, " + %ld", die->die_offset);
+ }
else
fprintf (outfile, "die -> %ld", die->die_offset);
fprintf (outfile, " (%p)", (void *) die);
@@ -7152,7 +7402,7 @@ static unsigned int comdat_symbol_number
children, and set comdat_symbol_id accordingly. */
static void
-compute_section_prefix (dw_die_ref unit_die)
+compute_section_prefix_1 (dw_die_ref unit_die, bool comdat_p)
{
const char *die_name = get_AT_string (unit_die, DW_AT_name);
const char *base = die_name ? lbasename (die_name) : "anonymous";
@@ -7171,7 +7421,11 @@ compute_section_prefix (dw_die_ref unit_
unmark_all_dies (unit_die);
md5_finish_ctx (&ctx, checksum);
- sprintf (name, "%s.", base);
+ /* When we this for comp_unit_die () we have a DW_AT_name that might
+ not start with a letter but with anything valid for filenames and
+ clean_symbol_name doesn't fix that up. Prepend 'g' if the first
+ character is not a letter. */
+ sprintf (name, "%s%s.", ISALPHA (*base) ? "" : "g", base);
clean_symbol_name (name);
p = name + strlen (name);
@@ -7181,7 +7435,15 @@ compute_section_prefix (dw_die_ref unit_
p += 2;
}
- comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+ unit_die->die_id.die_symbol = xstrdup (name);
+ unit_die->comdat_type_p = comdat_p;
+}
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+ compute_section_prefix_1 (unit_die, true);
+ comdat_symbol_id = unit_die->die_id.die_symbol;
comdat_symbol_number = 0;
}
@@ -9872,7 +10134,11 @@ output_die (dw_die_ref die)
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
- if (! die->comdat_type_p && die->die_id.die_symbol)
+ if (! die->comdat_type_p && die->die_id.die_symbol
+ /* Don't output the symbol twice. For LTO we want the label
+ on the section beginning, not on the actual DIE. */
+ && (!flag_generate_lto
+ || die->die_tag != DW_TAG_compile_unit))
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
@@ -10065,8 +10331,20 @@ output_die (dw_die_ref die)
size = DWARF2_ADDR_SIZE;
else
size = DWARF_OFFSET_SIZE;
- dw2_asm_output_offset (size, sym, debug_info_section, "%s",
- name);
+ /* ??? We cannot unconditionally output die_offset if
+ non-zero - at least -feliminate-dwarf2-dups will
+ create references to those DIEs via symbols. And we
+ do not clear its DIE offset after outputting it
+ (and the label refers to the actual DIEs, not the
+ DWARF CU unit header which is when using label + offset
+ would be the correct thing to do).
+ ??? This is the reason for the with_offset flag. */
+ if (AT_ref (a)->with_offset)
+ dw2_asm_output_offset (size, sym, AT_ref (a)->die_offset,
+ debug_info_section, "%s", name);
+ else
+ dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+ name);
}
}
else
@@ -10290,7 +10568,7 @@ output_comp_unit (dw_die_ref die, int ou
calc_die_sizes (die);
oldsym = die->die_id.die_symbol;
- if (oldsym)
+ if (oldsym && die->comdat_type_p)
{
tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
@@ -10306,6 +10584,33 @@ output_comp_unit (dw_die_ref die, int ou
info_section_emitted = true;
}
+ /* For LTO cross unit DIE refs we want a symbol on the start of the
+ debuginfo section, not on the CU DIE.
+ ??? We could simply use the symbol as it would be output by output_die
+ and account for the extra offset produced by the CU header which has fixed
+ size. OTOH it currently only supports linkonce globals which would
+ be less than ideal?. */
+ if (flag_generate_lto && oldsym)
+ {
+ /* ??? No way to get visibility assembled without a decl. */
+ tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (oldsym), char_type_node);
+ TREE_PUBLIC (decl) = true;
+ TREE_STATIC (decl) = true;
+ DECL_ARTIFICIAL (decl) = true;
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = true;
+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+#ifdef ASM_WEAKEN_LABEL
+ /* We prefer a .weak because that handles duplicates from duplicate
+ archive members in a graceful way. */
+ ASM_WEAKEN_LABEL (asm_out_file, oldsym);
+#else
+ targetm.asm_out.globalize_label (asm_out_file, oldsym);
+#endif
+ ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+ }
+
/* Output debugging information. */
output_compilation_unit_header (dwo_id
? DW_UT_split_compile : DW_UT_compile);
@@ -14412,6 +14717,9 @@ parameter_ref_descriptor (rtx rtl)
if (dwarf_strict)
return NULL;
gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
+ /* With LTO during LTRANS we get the late DIE that refers to the early
+ DIE, thus we add another indirection here. This seems to confuse
+ gdb enough to make gcc.dg/guality/pr68860-1.c FAIL with LTO. */
ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
if (ref)
@@ -19999,7 +20307,20 @@ add_abstract_origin_attribute (dw_die_re
}
if (DECL_P (origin))
- origin_die = lookup_decl_die (origin);
+ {
+ dw_die_ref c;
+ origin_die = lookup_decl_die (origin);
+ /* "Unwrap" the decls DIE which we put in the imported unit context.
+ ??? If we finish dwarf2out_function_decl refactoring we can
+ do this in a better way from the start and only lazily emit
+ the early DIE references. */
+ if (in_lto_p
+ && origin_die
+ && (c = get_AT_ref (origin_die, DW_AT_abstract_origin))
+ /* ??? Identify this better. */
+ && c->with_offset)
+ origin_die = c;
+ }
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
else if (TREE_CODE (origin) == BLOCK)
@@ -20556,7 +20877,12 @@ gen_array_type_die (tree type, dw_die_re
size = int_size_in_bytes (type);
if (size >= 0)
add_AT_unsigned (array_die, DW_AT_byte_size, size);
- else if (TYPE_DOMAIN (type) != NULL_TREE
+ /* ??? We can't annotate types late, but for LTO we may not
+ generate a location early either (gfortran.dg/save_5.f90).
+ The proper way is to handle it like VLAs though it is told
+ that DW_AT_string_length does not support this. */
+ else if (! (early_dwarf && flag_generate_lto)
+ && TYPE_DOMAIN (type) != NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE)
{
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
@@ -21023,7 +21349,9 @@ gen_formal_parameter_die (tree node, tre
thing. */
if (parm_die && parm_die->die_parent != context_die)
{
- if (!DECL_ABSTRACT_P (node))
+ /* ??? The DIE parent is the "abstract" copy and the context_die
+ is the specification "copy". */
+ if (!DECL_ABSTRACT_P (node) && !in_lto_p)
{
/* This can happen when creating an inlined instance, in
which case we need to create a new DIE that will get
@@ -21297,7 +21625,6 @@ gen_type_die_for_member (tree type, tree
/* Forward declare these functions, because they are mutually recursive
with their set_block_* pairing functions. */
static void set_decl_origin_self (tree);
-static void set_decl_abstract_flags (tree, vec<tree> &);
/* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
@@ -21370,151 +21697,45 @@ set_decl_origin_self (tree decl)
}
}
\f
-/* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
- and if it wasn't 1 before, push it to abstract_vec vector.
- For all local decls and all local sub-blocks (recursively) do it
- too. */
-
-static void
-set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
-{
- tree local_decl;
- tree subblock;
- unsigned int i;
-
- if (!BLOCK_ABSTRACT (stmt))
- {
- abstract_vec.safe_push (stmt);
- BLOCK_ABSTRACT (stmt) = 1;
- }
-
- for (local_decl = BLOCK_VARS (stmt);
- local_decl != NULL_TREE;
- local_decl = DECL_CHAIN (local_decl))
- if (! DECL_EXTERNAL (local_decl))
- set_decl_abstract_flags (local_decl, abstract_vec);
-
- for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
- {
- local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
- if ((VAR_P (local_decl) && !TREE_STATIC (local_decl))
- || TREE_CODE (local_decl) == PARM_DECL)
- set_decl_abstract_flags (local_decl, abstract_vec);
- }
-
- for (subblock = BLOCK_SUBBLOCKS (stmt);
- subblock != NULL_TREE;
- subblock = BLOCK_CHAIN (subblock))
- set_block_abstract_flags (subblock, abstract_vec);
-}
-
-/* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
- to 1 and if it wasn't 1 before, push to abstract_vec vector.
- In the case where the decl is a FUNCTION_DECL also set the abstract
- flags for all of the parameters, local vars, local
- blocks and sub-blocks (recursively). */
-
-static void
-set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
-{
- if (!DECL_ABSTRACT_P (decl))
- {
- abstract_vec.safe_push (decl);
- DECL_ABSTRACT_P (decl) = 1;
- }
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- tree arg;
-
- for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
- if (!DECL_ABSTRACT_P (arg))
- {
- abstract_vec.safe_push (arg);
- DECL_ABSTRACT_P (arg) = 1;
- }
- if (DECL_INITIAL (decl) != NULL_TREE
- && DECL_INITIAL (decl) != error_mark_node)
- set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
- }
-}
-
-/* Generate the DWARF2 info for the "abstract" instance of a function which we
- may later generate inlined and/or out-of-line instances of.
-
- FIXME: In the early-dwarf world, this function, and most of the
- DECL_ABSTRACT code should be obsoleted. The early DIE _is_
- the abstract instance. All we would need to do is annotate
- the early DIE with the appropriate DW_AT_inline in late
- dwarf (perhaps in gen_inlined_subroutine_die).
-
- However, we can't do this yet, because LTO streaming of DIEs
- has not been implemented yet. */
+/* Mark the early DIE for DECL as the abstract instance. */
static void
dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
- tree save_fn;
- tree context;
- hash_table<decl_loc_hasher> *old_decl_loc_table;
- hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
- int old_call_site_count, old_tail_call_site_count;
- struct call_arg_loc_node *old_call_arg_locations;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
+ if (DECL_IGNORED_P (decl))
+ return;
+
old_die = lookup_decl_die (decl);
- if (old_die && get_AT (old_die, DW_AT_inline))
+ /* With early debug we always have an old DIE. */
+ gcc_assert (old_die != NULL);
+ if (get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
- /* We can be called while recursively when seeing block defining inlined subroutine
- DIE. Be sure to not clobber the outer location table nor use it or we would
- get locations in abstract instantces. */
- old_decl_loc_table = decl_loc_table;
- decl_loc_table = NULL;
- old_cached_dw_loc_list_table = cached_dw_loc_list_table;
- cached_dw_loc_list_table = NULL;
- old_call_arg_locations = call_arg_locations;
- call_arg_locations = NULL;
- old_call_site_count = call_site_count;
- call_site_count = -1;
- old_tail_call_site_count = tail_call_site_count;
- tail_call_site_count = -1;
-
- /* Be sure we've emitted the in-class declaration DIE (if any) first, so
- we don't get confused by DECL_ABSTRACT_P. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
+ /* Go ahead and put DW_AT_inline on the DIE. */
+ if (DECL_DECLARED_INLINE_P (decl))
{
- context = decl_class_context (decl);
- if (context)
- gen_type_die_for_member
- (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_inlined);
+ else
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
+ }
+ else
+ {
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_inlined);
+ else
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_not_inlined);
}
- /* Pretend we've just finished compiling this function. */
- save_fn = current_function_decl;
- current_function_decl = decl;
-
- auto_vec<tree, 64> abstract_vec;
- set_decl_abstract_flags (decl, abstract_vec);
- dwarf2out_decl (decl);
- unsigned int i;
- tree t;
- FOR_EACH_VEC_ELT (abstract_vec, i, t)
- if (TREE_CODE (t) == BLOCK)
- BLOCK_ABSTRACT (t) = 0;
- else
- DECL_ABSTRACT_P (t) = 0;
-
- current_function_decl = save_fn;
- decl_loc_table = old_decl_loc_table;
- cached_dw_loc_list_table = old_cached_dw_loc_list_table;
- call_arg_locations = old_call_arg_locations;
- call_site_count = old_call_site_count;
- tail_call_site_count = old_tail_call_site_count;
+ if (DECL_DECLARED_INLINE_P (decl)
+ && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
+ add_AT_flag (old_die, DW_AT_artificial, 1);
}
/* Helper function of premark_used_types() which gets called through
@@ -21736,7 +21957,12 @@ gen_subprogram_die (tree decl, dw_die_re
if (old_die && old_die->die_parent == NULL)
add_child_die (context_die, old_die);
- if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+ dw_die_ref c;
+ if (old_die
+ && (c = get_AT_ref (old_die, DW_AT_abstract_origin))
+ /* ??? In LTO all origin DIEs still refer to the early
+ debug copy. Detect that. */
+ && get_AT (c, DW_AT_inline))
{
/* If we have a DW_AT_abstract_origin we have a working
cached version. */
@@ -21804,7 +22030,9 @@ gen_subprogram_die (tree decl, dw_die_re
|| (old_die->die_parent
&& old_die->die_parent->die_tag == DW_TAG_module)
|| context_die == NULL)
- && (DECL_ARTIFICIAL (decl)
+ /* ??? This all (and above) should probably be simply
+ a ! early_dwarf check somehow. */
+ && ((DECL_ARTIFICIAL (decl) || in_lto_p)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) s.line))))
@@ -22667,6 +22895,24 @@ gen_variable_die (tree decl, tree origin
/* If a DIE was dumped early, it still needs location info.
Skip to where we fill the location bits. */
var_die = old_die;
+
+ /* ??? In LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Thus we dumped them again, also add a
+ reference to them. */
+ tree type = TREE_TYPE (decl_or_origin);
+ if (in_lto_p
+ && variably_modified_type_p
+ (type, decl_function_context (decl_or_origin)))
+ {
+ if (decl_by_reference_p (decl_or_origin))
+ add_type_attribute (var_die, TREE_TYPE (type),
+ TYPE_UNQUALIFIED, false, context_die);
+ else
+ add_type_attribute (var_die, type, decl_quals (decl_or_origin),
+ false, context_die);
+ }
+
goto gen_variable_die_location;
}
}
@@ -23056,12 +23302,6 @@ gen_inlined_subroutine_die (tree stmt, d
gcc_checking_assert (DECL_ABSTRACT_P (decl)
|| cgraph_function_possibly_inlined_p (decl));
- /* Emit info for the abstract instance first, if we haven't yet. We
- must emit this even if the block is abstract, otherwise when we
- emit the block below (or elsewhere), we may end up trying to emit
- a die whose origin die hasn't been emitted, and crashing. */
- dwarf2out_abstract_function (decl);
-
if (! BLOCK_ABSTRACT (stmt))
{
dw_die_ref subr_die
@@ -24651,7 +24891,20 @@ process_scope_var (tree stmt, tree decl,
stmt, context_die);
}
else
- gen_decl_die (decl, origin, NULL, context_die);
+ {
+ if (decl && DECL_P (decl))
+ {
+ die = lookup_decl_die (decl);
+
+ /* Early created DIEs do not have a parent as the decls refer
+ to the function as DECL_CONTEXT rather than the BLOCK. */
+ if (in_lto_p
+ && die && die->die_parent == NULL)
+ add_child_die (context_die, die);
+ }
+
+ gen_decl_die (decl, origin, NULL, context_die);
+ }
}
/* Generate all of the decls declared within a given scope and (recursively)
@@ -25063,6 +25316,9 @@ gen_decl_die (tree decl, tree origin, st
/* If we're emitting an out-of-line copy of an inline function,
emit info for the abstract instance and set up to refer to it. */
+ /* ??? We have output an abstract instance early already and
+ could just re-use that. This is how LTO treats all functions
+ for example. */
else if (cgraph_function_possibly_inlined_p (decl)
&& ! DECL_ABSTRACT_P (decl)
&& ! class_or_namespace_scope_p (context_die)
@@ -25076,7 +25332,9 @@ gen_decl_die (tree decl, tree origin, st
}
/* Otherwise we're emitting the primary DIE for this decl. */
- else if (debug_info_level > DINFO_LEVEL_TERSE)
+ else if (debug_info_level > DINFO_LEVEL_TERSE
+ /* Do not generate stray type DIEs in late LTO dumping. */
+ && early_dwarf)
{
/* Before we describe the FUNCTION_DECL itself, make sure that we
have its containing type. */
@@ -25143,20 +25401,37 @@ gen_decl_die (tree decl, tree origin, st
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
- /* Output any DIEs that are needed to specify the type of this data
- object. */
- if (decl_by_reference_p (decl_or_origin))
- gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
- else
- gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ /* Avoid generating stray type DIEs during late dwarf dumping.
+ All types have been dumped early. */
+ if (! (decl ? lookup_decl_die (decl) : NULL)
+ /* ??? But in LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Dump them again as happens for inlining
+ which copies both the decl and the types. */
+ /* ??? And even non-LTO needs to re-visit type DIEs to fill
+ in VLA bound information for example. */
+ || (/* in_lto_p && */
+ decl && variably_modified_type_p (TREE_TYPE (decl),
+ current_function_decl)))
+ {
+ /* Output any DIEs that are needed to specify the type of this data
+ object. */
+ if (decl_by_reference_p (decl_or_origin))
+ gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+ else
+ gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ }
- /* And its containing type. */
- class_origin = decl_class_context (decl_or_origin);
- if (class_origin != NULL_TREE)
- gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+ if (early_dwarf)
+ {
+ /* And its containing type. */
+ class_origin = decl_class_context (decl_or_origin);
+ if (class_origin != NULL_TREE)
+ gen_type_die_for_member (class_origin, decl_or_origin, context_die);
- /* And its containing namespace. */
- context_die = declare_in_namespace (decl_or_origin, context_die);
+ /* And its containing namespace. */
+ context_die = declare_in_namespace (decl_or_origin, context_die);
+ }
/* Now output the DIE to represent the data object itself. This gets
complicated because of the possibility that the VAR_DECL really
@@ -25266,6 +25541,16 @@ dwarf2out_early_global_decl (tree decl)
dwarf2out_decl (context);
}
+ /* Emit an abstract origin of a function first. This happens
+ with C++ constructor clones for example and makes
+ dwarf2out_abstract_function happy which requires the early
+ DIE of the abstract instance to be present. */
+ if (DECL_ABSTRACT_ORIGIN (decl))
+ {
+ current_function_decl = DECL_ABSTRACT_ORIGIN (decl);
+ dwarf2out_decl (DECL_ABSTRACT_ORIGIN (decl));
+ }
+
current_function_decl = decl;
}
dwarf2out_decl (decl);
@@ -25288,7 +25573,9 @@ dwarf2out_late_global_decl (tree decl)
{
dw_die_ref die = lookup_decl_die (decl);
- /* We have to generate early debug late for LTO. */
+ /* We may have to generate early debug late for LTO in case debug
+ was not enabled at compile-time or the target doesn't support
+ the LTO early debug scheme. */
if (! die && in_lto_p)
{
dwarf2out_decl (decl);
@@ -26645,7 +26932,8 @@ output_macinfo_op (macinfo_entry *ref)
case DW_MACRO_import:
dw2_asm_output_data (1, ref->code, "Import");
ASM_GENERATE_INTERNAL_LABEL (label,
- DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+ DEBUG_MACRO_SECTION_LABEL,
+ ref->lineno + macinfo_label_base);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
break;
default:
@@ -26819,7 +27107,7 @@ save_macinfo_strings (void)
/* Output macinfo section(s). */
static void
-output_macinfo (void)
+output_macinfo (const char *debug_line_label, bool early_lto_debug)
{
unsigned i;
unsigned long length = vec_safe_length (macinfo_table);
@@ -26845,9 +27133,7 @@ output_macinfo (void)
dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
else
dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE,
- (!dwarf_split_debug_info ? debug_line_section_label
- : debug_skeleton_line_section_label),
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_label,
debug_line_section, NULL);
}
@@ -26901,6 +27187,10 @@ output_macinfo (void)
if (!macinfo_htab)
return;
+ /* Save the number of transparent includes so we can adjust the
+ label number for the fat LTO object DWARF. */
+ unsigned macinfo_label_base_adj = macinfo_htab->elements ();
+
delete macinfo_htab;
macinfo_htab = NULL;
@@ -26920,11 +27210,13 @@ output_macinfo (void)
dw2_asm_output_data (1, 0, "End compilation unit");
targetm.asm_out.named_section (debug_macinfo_section_name,
SECTION_DEBUG
- | SECTION_LINKONCE,
+ | SECTION_LINKONCE
+ | (early_lto_debug
+ ? SECTION_EXCLUDE : 0),
comdat_key);
ASM_GENERATE_INTERNAL_LABEL (label,
DEBUG_MACRO_SECTION_LABEL,
- ref->lineno);
+ ref->lineno + macinfo_label_base);
ASM_OUTPUT_LABEL (asm_out_file, label);
ref->code = 0;
ref->info = NULL;
@@ -26945,109 +27237,192 @@ output_macinfo (void)
default:
gcc_unreachable ();
}
+
+ macinfo_label_base += macinfo_label_base_adj;
}
-/* Initialize the various sections and labels for dwarf output. */
+/* Initialize the various sections and labels for dwarf output and prefix
+ them with PREFIX if non-NULL. */
static void
-init_sections_and_labels (void)
+init_sections_and_labels (bool early_lto_debug)
{
- if (!dwarf_split_debug_info)
+ /* As we may get called multiple times have a generation count for labels. */
+ static unsigned generation = 0;
+
+ if (early_lto_debug)
{
- debug_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- debug_loc_section = get_section (dwarf_version >= 5
- ? DEBUG_LOCLISTS_SECTION
- : DEBUG_LOC_SECTION,
- SECTION_DEBUG, NULL);
- debug_macinfo_section_name
- = (dwarf_strict && dwarf_version < 5)
- ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
- debug_macinfo_section = get_section (debug_macinfo_section_name,
- SECTION_DEBUG, NULL);
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_macinfo_section_name = ((dwarf_strict && dwarf_version < 5)
+ ? DEBUG_LTO_MACINFO_SECTION
+ : DEBUG_LTO_MACRO_SECTION);
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ /* For macro info we have to refer to a debug_line section, so similar
+ to split-dwarf emit a skeleton one for early debug. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ }
+ else
+ {
+ /* ??? Which of the following do we need early? */
+ debug_info_section = get_section (DEBUG_LTO_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_LTO_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_skeleton_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+ generation);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
+ the main .o, but the skeleton_line goes into the split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ debug_str_offsets_section
+ = get_section (DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL,
+ generation);
+ debug_str_dwo_section = get_section (DEBUG_LTO_STR_DWO_SECTION,
+ DEBUG_STR_DWO_SECTION_FLAGS, NULL);
+ debug_macinfo_section_name
+ = (dwarf_strict
+ ? DEBUG_LTO_DWO_MACINFO_SECTION : DEBUG_LTO_DWO_MACRO_SECTION);
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ }
+ debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS
+ | SECTION_EXCLUDE, NULL);
}
else
{
- debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- debug_addr_section = get_section (DEBUG_ADDR_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
- DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
-
- /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
- the main .o, but the skeleton_line goes into the split off dwo. */
- debug_skeleton_line_section
- = get_section (DEBUG_DWO_LINE_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
- DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
- debug_str_offsets_section = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
- DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
- debug_loc_section = get_section (dwarf_version >= 5
- ? DEBUG_DWO_LOCLISTS_SECTION
- : DEBUG_DWO_LOC_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
- DEBUG_STR_DWO_SECTION_FLAGS, NULL);
- debug_macinfo_section_name
- = (dwarf_strict && dwarf_version < 5)
- ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
- debug_macinfo_section = get_section (debug_macinfo_section_name,
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_macinfo_section_name
+ = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG, NULL);
+ }
+ else
+ {
+ debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_addr_section = get_section (DEBUG_ADDR_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+ generation);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections
+ stay in the main .o, but the skeleton_line goes into the
+ split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_DWO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ debug_str_offsets_section
+ = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL,
+ generation);
+ debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
- }
- debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_line_section = get_section (DEBUG_LINE_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
+ DEBUG_STR_DWO_SECTION_FLAGS,
+ NULL);
+ debug_macinfo_section_name
+ = (dwarf_strict && dwarf_version < 5)
+ ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ }
+ debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_line_section = get_section (DEBUG_LINE_SECTION,
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)
- 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,
- SECTION_DEBUG, NULL);
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
+ debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_str_section = get_section (DEBUG_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
+ debug_ranges_section = get_section (dwarf_version >= 5
+ ? DEBUG_RNGLISTS_SECTION
+ : DEBUG_RANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ }
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
- DEBUG_ABBREV_SECTION_LABEL, 0);
+ DEBUG_ABBREV_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
- DEBUG_INFO_SECTION_LABEL, 0);
+ DEBUG_INFO_SECTION_LABEL, generation);
+ info_section_emitted = false;
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
- DEBUG_LINE_SECTION_LABEL, 0);
+ DEBUG_LINE_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
- DEBUG_RANGES_SECTION_LABEL, 0);
+ DEBUG_RANGES_SECTION_LABEL, generation);
if (dwarf_version >= 5 && dwarf_split_debug_info)
ASM_GENERATE_INTERNAL_LABEL (ranges_base_label,
- DEBUG_RANGES_SECTION_LABEL, 1);
+ DEBUG_RANGES_SECTION_LABEL, 2 + generation);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
- DEBUG_ADDR_SECTION_LABEL, 0);
+ DEBUG_ADDR_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
(dwarf_strict && dwarf_version < 5)
? DEBUG_MACINFO_SECTION_LABEL
- : DEBUG_MACRO_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
+ : DEBUG_MACRO_SECTION_LABEL, generation);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL,
+ generation);
+
+ ++generation;
}
/* Set up for Dwarf output at the start of compilation. */
@@ -29272,6 +29647,22 @@ flush_limbo_die_list (void)
}
}
+/* Reset DIEs so we can output them again. */
+
+static void
+reset_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ /* Remove stuff we re-generate. */
+ die->die_mark = 0;
+ die->die_offset = 0;
+ die->die_abbrev = 0;
+ remove_AT (die, DW_AT_sibling);
+
+ FOR_EACH_CHILD (die, c, reset_dies (c));
+}
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
@@ -29298,6 +29689,47 @@ dwarf2out_finish (const char *)
gen_remaining_tmpl_value_param_die_attribute ();
+ if (flag_generate_lto)
+ {
+ gcc_assert (flag_fat_lto_objects);
+
+ /* Prune stuff so that dwarf2out_finish runs successfully
+ for the fat part of the object. */
+ reset_dies (comp_unit_die ());
+ for (limbo_die_node *node = cu_die_list; node; node = node->next)
+ reset_dies (node->die);
+
+ hash_table<comdat_type_hasher> comdat_type_table (100);
+ for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+ {
+ comdat_type_node **slot
+ = comdat_type_table.find_slot (ctnode, INSERT);
+
+ /* Don't reset types twice. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ reset_dies (ctnode->root_die);
+
+ *slot = ctnode;
+ }
+
+ /* Reset die CU symbol so we don't output it twice. */
+ comp_unit_die ()->die_id.die_symbol = NULL;
+
+ /* Remove DW_AT_macro from the early output. */
+ if (have_macinfo)
+ remove_AT (comp_unit_die (),
+ dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros);
+
+ /* Remove indirect string decisions. */
+ debug_str_hash->traverse<void *, reset_indirect_string> (NULL);
+ }
+
#if ENABLE_ASSERT_CHECKING
{
dw_die_ref die = comp_unit_die (), c;
@@ -29308,7 +29740,7 @@ dwarf2out_finish (const char *)
move_marked_base_types ();
/* Initialize sections and labels used for actual assembler output. */
- init_sections_and_labels ();
+ init_sections_and_labels (false);
/* Traverse the DIE's and add sibling attributes to those DIE's that
have children. */
@@ -29610,7 +30042,8 @@ dwarf2out_finish (const char *)
{
switch_to_section (debug_macinfo_section);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
- output_macinfo ();
+ output_macinfo (!dwarf_split_debug_info ? debug_line_section_label
+ : debug_skeleton_line_section_label, false);
dw2_asm_output_data (1, 0, "End compilation unit");
}
@@ -29772,6 +30205,118 @@ dwarf2out_early_finish (const char *file
/* The early debug phase is now finished. */
early_dwarf_finished = true;
+
+ /* Do not generate DWARF assembler now when not producing LTO bytecode. */
+ if (!flag_generate_lto)
+ return;
+
+ /* Now as we are going to output for LTO initialize sections and labels
+ to the LTO variants. We don't need a random-seed postfix as other
+ LTO sections as linking the LTO debug sections into one in a partial
+ link is fine. */
+ init_sections_and_labels (true);
+
+ /* ??? Mostly duplicated from dwarf2out_finish. */
+
+ /* Traverse the DIE's and add add sibling attributes to those DIE's
+ that have children. */
+ add_sibling_attributes (comp_unit_die ());
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ add_sibling_attributes (node->die);
+ for (comdat_type_node *ctnode = comdat_type_list;
+ ctnode != NULL; ctnode = ctnode->next)
+ add_sibling_attributes (ctnode->root_die);
+
+ if (have_macinfo)
+ add_AT_macptr (comp_unit_die (),
+ dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+ macinfo_section_label);
+
+ save_macinfo_strings ();
+
+ /* Output all of the compilation units. We put the main one last so that
+ the offsets are available to output_pubnames. */
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ output_comp_unit (node->die, 0, NULL);
+
+ hash_table<comdat_type_hasher> comdat_type_table (100);
+ for (comdat_type_node *ctnode = comdat_type_list;
+ ctnode != NULL; ctnode = ctnode->next)
+ {
+ comdat_type_node **slot = comdat_type_table.find_slot (ctnode, INSERT);
+
+ /* Don't output duplicate types. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
+ (!dwarf_split_debug_info
+ ? debug_line_section_label
+ : debug_skeleton_line_section_label));
+
+ output_comdat_type_unit (ctnode);
+ *slot = ctnode;
+ }
+
+ /* The AT_pubnames attribute needs to go in all skeleton dies, including
+ both the main_cu and all skeleton TUs. Making this call unconditional
+ would end up either adding a second copy of the AT_pubnames attribute, or
+ requiring a special case in add_top_level_skeleton_die_attrs. */
+ if (!dwarf_split_debug_info)
+ add_AT_pubnames (comp_unit_die ());
+
+ /* Stick a unique symbol to the main debuginfo section. */
+ compute_section_prefix_1 (comp_unit_die (), false);
+
+ /* Output the main compilation unit. We always need it if only for
+ the CU symbol. */
+ output_comp_unit (comp_unit_die (), true, NULL);
+
+ /* Output the abbreviation table. */
+ if (vec_safe_length (abbrev_die_table) != 1)
+ {
+ switch_to_section (debug_abbrev_section);
+ ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
+ output_abbrev_section ();
+ }
+
+ /* Have to end the macro section. */
+ if (have_macinfo)
+ {
+ /* We have to save macinfo state if we need to output it again
+ for the FAT part of the object. */
+ vec<macinfo_entry, va_gc> *saved_macinfo_table = macinfo_table;
+ if (flag_fat_lto_objects)
+ macinfo_table = macinfo_table->copy ();
+
+ switch_to_section (debug_macinfo_section);
+ ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+ output_macinfo (debug_skeleton_line_section_label, true);
+ dw2_asm_output_data (1, 0, "End compilation unit");
+
+ /* Emit a skeleton debug_line section. */
+ switch_to_section (debug_skeleton_line_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
+ output_line_info (true);
+
+ if (flag_fat_lto_objects)
+ {
+ vec_free (macinfo_table);
+ macinfo_table = saved_macinfo_table;
+ }
+ }
+
+
+ /* If we emitted any indirect strings, output the string table too. */
+ if (debug_str_hash || skeleton_debug_str_hash)
+ output_indirect_strings ();
+
+ /* Switch back to the text section. */
+ switch_to_section (text_section);
}
/* Reset all state within dwarf2out.c so that we can rerun the compiler
Index: early-lto-debug/gcc/debug.h
===================================================================
--- early-lto-debug.orig/gcc/debug.h 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/debug.h 2016-11-10 12:37:27.428990721 +0100
@@ -146,6 +146,14 @@ struct gcc_debug_hooks
void (* imported_module_or_decl) (tree decl, tree name,
tree context, bool child);
+ /* Return true if a DIE for the tree is available and return a symbol
+ and offset that can be used to refer to it externally. */
+ bool (* die_ref_for_decl) (tree, const char **, unsigned HOST_WIDE_INT *);
+
+ /* Early debug information for the tree is available at symbol plus
+ offset externally. */
+ void (* register_external_die) (tree, const char *, unsigned HOST_WIDE_INT);
+
/* DECL is an inline function, whose body is present, but which is
not being output at this point. */
void (* deferred_inline_function) (tree decl);
@@ -205,6 +213,10 @@ extern void debug_nothing_tree_tree_tree
extern bool debug_true_const_tree (const_tree);
extern void debug_nothing_rtx_insn (rtx_insn *);
extern void debug_nothing_rtx_code_label (rtx_code_label *);
+extern bool debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *);
+extern void debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT);
/* Hooks for various debug formats. */
extern const struct gcc_debug_hooks do_nothing_debug_hooks;
Index: early-lto-debug/gcc/debug.c
===================================================================
--- early-lto-debug.orig/gcc/debug.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/debug.c 2016-11-10 12:37:27.428990721 +0100
@@ -48,6 +48,8 @@ const struct gcc_debug_hooks do_nothing_
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
@@ -138,3 +140,16 @@ debug_nothing_tree_int (tree decl ATTRIB
int local ATTRIBUTE_UNUSED)
{
}
+
+bool
+debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *)
+{
+ return false;
+}
+
+void
+debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT)
+{
+}
Index: early-lto-debug/gcc/dbxout.c
===================================================================
--- early-lto-debug.orig/gcc/dbxout.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/dbxout.c 2016-11-10 12:37:27.432990766 +0100
@@ -371,6 +371,8 @@ const struct gcc_debug_hooks dbx_debug_h
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
@@ -411,6 +413,8 @@ const struct gcc_debug_hooks xcoff_debug
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
Index: early-lto-debug/gcc/sdbout.c
===================================================================
--- early-lto-debug.orig/gcc/sdbout.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/sdbout.c 2016-11-10 12:37:27.432990766 +0100
@@ -300,6 +300,8 @@ const struct gcc_debug_hooks sdb_debug_h
sdbout_late_global_decl, /* late_global_decl */
sdbout_symbol, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
sdbout_label, /* label */
Index: early-lto-debug/gcc/lto/lto.c
===================================================================
--- early-lto-debug.orig/gcc/lto/lto.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/lto/lto.c 2016-11-10 12:37:27.432990766 +0100
@@ -1628,6 +1628,9 @@ unify_scc (struct data_in *data_in, unsi
free_node (scc->entries[i]);
}
+ /* Drop DIE references. */
+ dref_queue.truncate (0);
+
break;
}
@@ -1703,8 +1706,7 @@ lto_read_decls (struct lto_file_decl_dat
from);
if (len == 1
&& (TREE_CODE (first) == IDENTIFIER_NODE
- || TREE_CODE (first) == INTEGER_CST
- || TREE_CODE (first) == TRANSLATION_UNIT_DECL))
+ || TREE_CODE (first) == INTEGER_CST))
continue;
/* Try to unify the SCC with already existing ones. */
@@ -1743,16 +1745,6 @@ lto_read_decls (struct lto_file_decl_dat
if (TREE_CODE (t) == INTEGER_CST
&& !TREE_OVERFLOW (t))
cache_integer_cst (t);
- /* Register TYPE_DECLs with the debuginfo machinery. */
- if (!flag_wpa
- && TREE_CODE (t) == TYPE_DECL)
- {
- /* Dwarf2out needs location information.
- TODO: Moving this out of the streamer loop may noticealy
- improve ltrans linemap memory use. */
- data_in->location_cache.apply_location_cache ();
- debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
- }
if (!flag_ltrans)
{
/* Register variables and functions with the
@@ -1768,6 +1760,14 @@ lto_read_decls (struct lto_file_decl_dat
vec_safe_push (tree_with_vars, t);
}
}
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
+
if (seen_type)
num_type_scc_trees += len;
}
@@ -1947,7 +1947,12 @@ lto_section_with_id (const char *name, u
if (strncmp (name, section_name_prefix, strlen (section_name_prefix)))
return 0;
s = strrchr (name, '.');
- return s && sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
+ if (!s)
+ return 0;
+ /* If the section is not suffixed with an ID return. */
+ if ((size_t)(s - name) == strlen (section_name_prefix))
+ return 0;
+ return sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
}
/* Create file_data of each sub file id */
Index: early-lto-debug/gcc/lto-streamer-in.c
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer-in.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/lto-streamer-in.c 2016-11-10 12:37:27.432990766 +0100
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.
#include "except.h"
#include "cgraph.h"
#include "cfgloop.h"
+#include "debug.h"
struct freeing_string_slot_hasher : string_slot_hasher
@@ -1038,6 +1039,16 @@ input_function (tree fn_decl, struct dat
DECL_RESULT (fn_decl) = stream_read_tree (ib, data_in);
DECL_ARGUMENTS (fn_decl) = streamer_read_chain (ib, data_in);
+ /* Read debug args if available. */
+ unsigned n_debugargs = streamer_read_uhwi (ib);
+ if (n_debugargs)
+ {
+ vec<tree, va_gc> **debugargs = decl_debug_args_insert (fn_decl);
+ vec_safe_grow (*debugargs, n_debugargs);
+ for (unsigned i = 0; i < n_debugargs; ++i)
+ (**debugargs)[i] = stream_read_tree (ib, data_in);
+ }
+
/* Read the tree of lexical scopes for the function. */
DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
unsigned block_leaf_count = streamer_read_uhwi (ib);
@@ -1274,6 +1285,10 @@ lto_input_variable_constructor (struct l
}
+/* Queue of acummulated decl -> DIE mappings. Similar to locations those
+ are only applied to prevailing tree nodes during tree merging. */
+vec<dref_entry> dref_queue;
+
/* Read the physical representation of a tree node EXPR from
input block IB using the per-file context in DATA_IN. */
@@ -1294,6 +1309,23 @@ lto_read_tree_1 (struct lto_input_block
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_register_external_die. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *str = streamer_read_string (data_in, ib);
+ if (str)
+ {
+ unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+ dref_entry e = { expr, str, off };
+ dref_queue.safe_push (e);
+ }
+ }
+
#ifdef LTO_STREAMER_DEBUG
/* Remove the mapping to RESULT's original address set by
streamer_alloc_tree. */
@@ -1444,6 +1476,13 @@ lto_input_tree (struct lto_input_block *
{
unsigned len, entry_len;
lto_input_scc (ib, data_in, &len, &entry_len);
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
}
return lto_input_tree_1 (ib, data_in, tag, 0);
}
Index: early-lto-debug/gcc/lto-streamer-out.c
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer-out.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/lto-streamer-out.c 2016-11-10 12:37:27.432990766 +0100
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.
#include "cfgloop.h"
#include "builtins.h"
#include "gomp-constants.h"
+#include "debug.h"
static void lto_write_tree (struct output_block*, tree, bool);
@@ -406,6 +407,26 @@ lto_write_tree_1 (struct output_block *o
(ob->decl_state->symtab_node_encoder, expr);
stream_write_tree (ob, initial, ref_p);
}
+
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_die_ref_for_decl. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+ {
+ streamer_write_string (ob, ob->main_stream, sym, true);
+ streamer_write_uhwi (ob, off);
+ }
+ else
+ streamer_write_string (ob, ob->main_stream, NULL, true);
+ }
}
/* Write a physical representation of tree node EXPR to output block
@@ -765,6 +786,7 @@ DFS::DFS_write_tree_body (struct output_
declarations which should be eliminated by decl merging. Be sure none
leaks to this point. */
gcc_assert (DECL_ABSTRACT_ORIGIN (expr) != error_mark_node);
+ DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
if ((VAR_P (expr)
|| TREE_CODE (expr) == PARM_DECL)
@@ -2059,6 +2081,17 @@ output_function (struct cgraph_node *nod
stream_write_tree (ob, DECL_RESULT (function), true);
streamer_write_chain (ob, DECL_ARGUMENTS (function), true);
+ /* Output debug args if available. */
+ vec<tree, va_gc> **debugargs = decl_debug_args_lookup (function);
+ if (! debugargs)
+ streamer_write_uhwi (ob, 0);
+ else
+ {
+ streamer_write_uhwi (ob, (*debugargs)->length ());
+ for (unsigned i = 0; i < (*debugargs)->length (); ++i)
+ stream_write_tree (ob, (**debugargs)[i], true);
+ }
+
/* Output DECL_INITIAL for the function, which contains the tree of
lexical scopes. */
stream_write_tree (ob, DECL_INITIAL (function), true);
Index: early-lto-debug/gcc/lto-streamer.h
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer.h 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/lto-streamer.h 2016-11-10 12:37:27.432990766 +0100
@@ -1225,4 +1225,14 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ
DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
+/* Entry for the delayed registering of decl -> DIE references. */
+struct dref_entry {
+ tree decl;
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+};
+
+extern vec<dref_entry> dref_queue;
+
+
#endif /* GCC_LTO_STREAMER_H */
Index: early-lto-debug/gcc/lto-wrapper.c
===================================================================
--- early-lto-debug.orig/gcc/lto-wrapper.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/lto-wrapper.c 2016-11-10 12:37:27.432990766 +0100
@@ -70,6 +70,7 @@ static char **output_names;
static char **offload_names;
static char *offload_objects_file_name;
static char *makefile;
+static char *debug_obj;
const char tool_name[] = "lto-wrapper";
@@ -88,6 +89,8 @@ tool_cleanup (bool)
maybe_unlink (offload_objects_file_name);
if (makefile)
maybe_unlink (makefile);
+ if (debug_obj)
+ maybe_unlink (debug_obj);
for (i = 0; i < nr; ++i)
{
maybe_unlink (input_names[i]);
@@ -940,6 +943,67 @@ find_and_merge_options (int fd, off_t fi
return true;
}
+/* Copy early debug info sections from INFILE to a new file whose name
+ is returned. Return NULL on error. */
+
+const char *
+debug_objcopy (const char *infile)
+{
+ const char *outfile;
+ const char *errmsg;
+ int err;
+
+ const char *p;
+ off_t inoff = 0;
+ long loffset;
+ int consumed;
+ if ((p = strrchr (infile, '@'))
+ && p != infile
+ && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (p) == (unsigned int) consumed)
+ {
+ char *fname = xstrdup (infile);
+ fname[p - infile] = '\0';
+ infile = fname;
+ inoff = (off_t) loffset;
+ }
+ int infd = open (infile, O_RDONLY);
+ if (infd == -1)
+ return NULL;
+ simple_object_read *inobj = simple_object_start_read (infd, inoff,
+ "__GNU_LTO",
+ &errmsg, &err);
+ if (!inobj)
+ return NULL;
+
+ off_t off, len;
+ if (simple_object_find_section (inobj, ".gnu.debuglto_.debug_info",
+ &off, &len, &errmsg, &err) != 1)
+ {
+ if (errmsg)
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+
+ simple_object_release_read (inobj);
+ close (infd);
+ return NULL;
+ }
+
+ outfile = make_temp_file ("debugobjtem");
+ errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err);
+ if (errmsg)
+ {
+ unlink_if_ordinary (outfile);
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+ }
+
+ simple_object_release_read (inobj);
+ close (infd);
+
+ return outfile;
+}
+
+
+
/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
static void
@@ -964,8 +1028,10 @@ run_gcc (unsigned argc, char *argv[])
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
- unsigned lto_argc = 0;
- char **lto_argv;
+ unsigned lto_argc = 0, ltoobj_argc = 0;
+ char **lto_argv, **ltoobj_argv;
+ bool skip_debug = false;
+ unsigned n_debugobj;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
@@ -984,6 +1050,7 @@ run_gcc (unsigned argc, char *argv[])
/* Allocate array for input object files with LTO IL,
and for possible preceding arguments. */
lto_argv = XNEWVEC (char *, argc);
+ ltoobj_argv = XNEWVEC (char *, argc);
/* Look at saved options in the IL files. */
for (i = 1; i < argc; ++i)
@@ -1026,7 +1093,7 @@ run_gcc (unsigned argc, char *argv[])
collect_gcc))
{
have_lto = true;
- lto_argv[lto_argc++] = argv[i];
+ ltoobj_argv[ltoobj_argc++] = argv[i];
}
close (fd);
}
@@ -1087,6 +1154,17 @@ run_gcc (unsigned argc, char *argv[])
}
}
+ /* Output lto-wrapper invocation command. */
+ if (verbose)
+ {
+ for (i = 0; i < argc; ++i)
+ {
+ fputs (argv[i], stderr);
+ fputc (' ', stderr);
+ }
+ fputc ('\n', stderr);
+ }
+
if (no_partition)
{
lto_mode = LTO_MODE_LTO;
@@ -1276,18 +1354,105 @@ cont1:
obstack_ptr_grow (&argv_obstack, "-fwpa");
}
- /* Append the input objects and possible preceding arguments. */
+ /* Append input arguments. */
for (i = 0; i < lto_argc; ++i)
obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+ /* Append the input objects. */
+ for (i = 0; i < ltoobj_argc; ++i)
+ obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
+ /* Handle early generated debug information. At compile-time
+ we output early DWARF debug info into .gnu.debuglto_ prefixed
+ sections. LTRANS object DWARF debug info refers to that.
+ So we need to transfer the .gnu.debuglto_ sections to the final
+ link. Ideally the linker plugin interface would allow us to
+ not claim those sections and instruct the linker to keep
+ them, renaming them in the process. For now we extract and
+ rename those sections via a simple-object interface to produce
+ regular objects containing only the early debug info. We
+ then partially link those to a single early debug info object
+ and pass that as additional output back to the linker plugin. */
+
+ /* Prepare the partial link to gather the compile-time generated
+ debug-info into a single input for the final link. */
+ debug_obj = make_temp_file ("debugobj");
+ obstack_ptr_grow (&argv_obstack, collect_gcc);
+ for (i = 1; i < decoded_options_count; ++i)
+ {
+ /* Retain linker choice and -B. */
+ if (decoded_options[i].opt_index == OPT_B
+ || decoded_options[i].opt_index == OPT_fuse_ld_bfd
+ || decoded_options[i].opt_index == OPT_fuse_ld_gold)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Retain all target options, this preserves -m32 for example. */
+ if (cl_options[decoded_options[i].opt_index].flags & CL_TARGET)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Recognize -g0. */
+ if (decoded_options[i].opt_index == OPT_g
+ && strcmp (decoded_options[i].arg, "0") == 0)
+ skip_debug = true;
+ }
+ obstack_ptr_grow (&argv_obstack, "-r");
+ obstack_ptr_grow (&argv_obstack, "-nostdlib");
+ obstack_ptr_grow (&argv_obstack, "-o");
+ obstack_ptr_grow (&argv_obstack, debug_obj);
+
+ /* Copy the early generated debug info from the objects to temporary
+ files and append those to the partial link commandline. */
+ n_debugobj = 0;
+ if (! skip_debug)
+ for (i = 0; i < ltoobj_argc; ++i)
+ {
+ const char *tem;
+ if ((tem = debug_objcopy (ltoobj_argv[i])))
+ {
+ obstack_ptr_grow (&argv_obstack, tem);
+ n_debugobj++;
+ }
+ }
+
+ /* Link them all into a single object. Ideally this would reduce
+ disk space usage mainly due to .debug_str merging but unfortunately
+ GNU ld doesn't perform this with -r. */
+ if (n_debugobj)
+ {
+ obstack_ptr_grow (&argv_obstack, NULL);
+ const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+ fork_execute (debug_link_argv[0],
+ CONST_CAST (char **, debug_link_argv), false);
+
+ /* And dispose the temporaries. */
+ for (i = 0; debug_link_argv[i]; ++i)
+ ;
+ for (--i; i > 0; --i)
+ {
+ if (strcmp (debug_link_argv[i], debug_obj) == 0)
+ break;
+ maybe_unlink (debug_link_argv[i]);
+ }
+ }
+ else
+ {
+ unlink_if_ordinary (debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ skip_debug = true;
+ }
+
if (lto_mode == LTO_MODE_LTO)
{
printf ("%s\n", flto_out);
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
free (flto_out);
flto_out = NULL;
}
@@ -1436,6 +1601,12 @@ cont:
for (i = 0; i < nr; ++i)
maybe_unlink (input_names[i]);
}
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
for (i = 0; i < nr; ++i)
{
fputs (output_names[i], stdout);
Index: early-lto-debug/gcc/tree-streamer-in.c
===================================================================
--- early-lto-debug.orig/gcc/tree-streamer-in.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/tree-streamer-in.c 2016-11-10 12:37:27.432990766 +0100
@@ -706,10 +706,7 @@ lto_input_ts_decl_common_tree_pointers (
DECL_SIZE (expr) = stream_read_tree (ib, data_in);
DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
-
- /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
Index: early-lto-debug/gcc/tree-streamer-out.c
===================================================================
--- early-lto-debug.orig/gcc/tree-streamer-out.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/tree-streamer-out.c 2016-11-10 12:37:27.432990766 +0100
@@ -583,10 +583,7 @@ write_ts_decl_common_tree_pointers (stru
special handling in LTO, it must be handled by streamer hooks. */
stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
-
- /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ stream_write_tree (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
Index: early-lto-debug/gcc/config/darwin.c
===================================================================
--- early-lto-debug.orig/gcc/config/darwin.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/config/darwin.c 2016-11-10 12:37:27.436990811 +0100
@@ -1919,7 +1919,8 @@ darwin_asm_lto_end (void)
}
static void
-darwin_asm_dwarf_section (const char *name, unsigned int flags, tree decl);
+darwin_asm_dwarf_section (const char *name, unsigned int flags,
+ tree decl, bool is_for_lto);
/* Called for the TARGET_ASM_NAMED_SECTION hook. */
@@ -1961,7 +1962,9 @@ darwin_asm_named_section (const char *na
vec_safe_push (lto_section_names, e);
}
else if (strncmp (name, "__DWARF,", 8) == 0)
- darwin_asm_dwarf_section (name, flags, decl);
+ darwin_asm_dwarf_section (name, flags, decl, false);
+ else if (strncmp (name, "__GNU_DWARF_LTO,", 16) == 0)
+ darwin_asm_dwarf_section (name, flags, decl, true);
else
fprintf (asm_out_file, "\t.section %s\n", name);
}
@@ -2739,19 +2742,37 @@ static GTY (()) vec<dwarf_sect_used_entr
static void
darwin_asm_dwarf_section (const char *name, unsigned int flags,
- tree ARG_UNUSED (decl))
+ tree ARG_UNUSED (decl), bool is_for_lto)
{
unsigned i;
- int namelen;
- const char * sname;
+ int namelen, extra = 0;
+ const char *sect, *lto_add = "";
+ char sname[64];
dwarf_sect_used_entry *ref;
bool found = false;
- gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
- == (SECTION_DEBUG | SECTION_NAMED));
- /* We know that the name starts with __DWARF, */
- sname = name + 8;
- namelen = strchr (sname, ',') - sname;
- gcc_assert (namelen);
+
+ gcc_checking_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+ == (SECTION_DEBUG | SECTION_NAMED));
+
+ /* We know that the name starts with __DWARF, or __GNU_DAWRF_LTO */
+ sect = strchr (name, ',') + 1;
+ namelen = strchr (sect, ',') - sect;
+ gcc_checking_assert (namelen);
+
+ /* The section switch is output as written... */
+ fprintf (asm_out_file, "\t.section %s\n", name);
+
+ /* ... but the string we keep to make section start labels needs
+ adjustment for lto cases. */
+ if (is_for_lto)
+ {
+ lto_add = "_lto";
+ extra = 4;
+ }
+
+ snprintf (sname, 64, "%.*s%.*s", namelen, sect, extra, lto_add);
+ namelen += extra;
+
if (dwarf_sect_names_table == NULL)
vec_alloc (dwarf_sect_names_table, 16);
else
@@ -2769,7 +2790,6 @@ darwin_asm_dwarf_section (const char *na
}
}
- fprintf (asm_out_file, "\t.section %s\n", name);
if (!found)
{
dwarf_sect_used_entry e;
@@ -2822,14 +2842,24 @@ darwin_asm_output_dwarf_offset (FILE *fi
HOST_WIDE_INT offset, section *base)
{
char sname[64];
- int namelen;
+ int namelen, extra = 0;
+ bool is_for_lto;
+ const char *lto_add = "";
+
+ gcc_checking_assert (base->common.flags & SECTION_NAMED);
+ is_for_lto = strncmp (base->named.name, "__GNU_DWARF_LTO,", 16) == 0;
+ gcc_checking_assert (is_for_lto
+ || strncmp (base->named.name, "__DWARF,", 8) == 0);
+ const char *name = strchr (base->named.name, ',') + 1;
+ gcc_checking_assert (name);
- gcc_assert (base->common.flags & SECTION_NAMED);
- gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
- gcc_assert (strchr (base->named.name + 8, ','));
-
- namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
- sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
+ namelen = strchr (name, ',') - (name);
+ if (is_for_lto)
+ {
+ lto_add = "_lto";
+ extra = 4;
+ }
+ snprintf (sname, 64, "*Lsection%.*s%.*s", namelen, name, extra, lto_add);
darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
}
Index: early-lto-debug/gcc/config/darwin.h
===================================================================
--- early-lto-debug.orig/gcc/config/darwin.h 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/config/darwin.h 2016-11-10 12:37:27.436990811 +0100
@@ -420,7 +420,14 @@ extern GTY(()) int darwin_ms_struct;
#define DEBUG_PUBTYPES_SECTION "__DWARF,__debug_pubtypes,regular,debug"
#define DEBUG_STR_SECTION "__DWARF,__debug_str,regular,debug"
#define DEBUG_RANGES_SECTION "__DWARF,__debug_ranges,regular,debug"
-#define DEBUG_MACRO_SECTION "__DWARF,__debug_macro,regular,debug"
+#define DEBUG_MACRO_SECTION "__DWARF,__debug_macro,regular,debug"
+
+#define DEBUG_LTO_INFO_SECTION "__GNU_DWARF_LTO,__debug_info,regular,debug"
+#define DEBUG_LTO_ABBREV_SECTION "__GNU_DWARF_LTO,__debug_abbrev,regular,debug"
+#define DEBUG_LTO_MACINFO_SECTION "__GNU_DWARF_LTO,__debug_macinfo,regular,debug"
+#define DEBUG_LTO_LINE_SECTION "__GNU_DWARF_LTO,__debug_line,regular,debug"
+#define DEBUG_LTO_STR_SECTION "__GNU_DWARF_LTO,__debug_str,regular,debug"
+#define DEBUG_LTO_MACRO_SECTION "__GNU_DWARF_LTO,__debug_macro,regular,debug"
#define TARGET_WANT_DEBUG_PUB_SECTIONS true
Index: early-lto-debug/gcc/vmsdbgout.c
===================================================================
--- early-lto-debug.orig/gcc/vmsdbgout.c 2016-11-10 12:37:01.776701544 +0100
+++ early-lto-debug/gcc/vmsdbgout.c 2016-11-10 12:37:27.436990811 +0100
@@ -196,6 +196,8 @@ const struct gcc_debug_hooks vmsdbg_debu
vmsdbgout_late_global_decl,
vmsdbgout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
vmsdbgout_abstract_function,
debug_nothing_rtx_code_label, /* label */
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PING][PATCH][2/2] Early LTO debug -- main part
2016-11-11 8:07 ` [PING][PATCH][2/2] " Richard Biener
@ 2016-11-22 22:50 ` Jason Merrill
2016-11-24 13:50 ` Richard Biener
0 siblings, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2016-11-22 22:50 UTC (permalink / raw)
To: Richard Biener, gcc-patches
On 11/11/2016 03:06 AM, Richard Biener wrote:
> + /* ??? In some cases the C++ FE (at least) fails to
> + set DECL_CONTEXT properly. Simply globalize stuff
> + in this case. For example
> + __dso_handle created via iostream line 74 col 25. */
The comment for DECL_CONTEXT says that a VAR_DECL can have 'NULL_TREE or
a TRANSLATION_UNIT_DECL if the given decl has "file scope"'
So this doesn't seem like a FE bug.
> + /* ??? We cannot unconditionally output die_offset if
> + non-zero - at least -feliminate-dwarf2-dups will
> + create references to those DIEs via symbols. And we
> + do not clear its DIE offset after outputting it
> + (and the label refers to the actual DIEs, not the
> + DWARF CU unit header which is when using label + offset
> + would be the correct thing to do).
I'd be happy to remove or disable -feliminate-dwarf2-dups at this point,
since it's already useless for C++ without reimplementation.
> + /* "Unwrap" the decls DIE which we put in the imported unit context.
> + ??? If we finish dwarf2out_function_decl refactoring we can
> + do this in a better way from the start and only lazily emit
> + the early DIE references. */
Can you elaborate more on the refactoring? dwarf2out_function_decl is
already very small, I'm guessing you mean gen_subprogram_die?
> + /* ??? We can't annotate types late, but for LTO we may not
> + generate a location early either (gfortran.dg/save_5.f90).
> + The proper way is to handle it like VLAs though it is told
> + that DW_AT_string_length does not support this. */
I think go ahead and handle it like VLAs, this is an obvious
generalization and should go into the spec soon enough. This can happen
later.
> + /* ??? This all (and above) should probably be simply
> + a ! early_dwarf check somehow. */
> + && ((DECL_ARTIFICIAL (decl) || in_lto_p)
> || (get_AT_file (old_die, DW_AT_decl_file) == file_index
> && (get_AT_unsigned (old_die, DW_AT_decl_line)
> == (unsigned) s.line))))
Why doesn't the existing source position check handle the LTO case?
Also the extra parens aren't necessary.
> /* If we're emitting an out-of-line copy of an inline function,
> emit info for the abstract instance and set up to refer to it. */
> + /* ??? We have output an abstract instance early already and
> + could just re-use that. This is how LTO treats all functions
> + for example. */
Isn't this what you do now?
> + /* Avoid generating stray type DIEs during late dwarf dumping.
> + All types have been dumped early. */
> + if (! (decl ? lookup_decl_die (decl) : NULL)
Why do you still want to gen_type_die if decl_or_origin is origin?
> +init_sections_and_labels (bool early_lto_debug)
You're changing this function to do the same thing in four slightly
different ways rather than two. I'd rather control each piece as
appropriate; we ought to make SECTION_DEBUG or
SECTION_DEBUG|SECTION_EXCLUDE a local variable, and select between
*_SECTION and the DWO variant at each statement rather than in different
blocks.
> + /* Remove DW_AT_macro from the early output. */
> + if (have_macinfo)
> + remove_AT (comp_unit_die (),
> + dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros);
This will need adjustment for Jakub's DWARF 5 work. Please make the
choice of AT value a macro.
> + /* ??? Mostly duplicated from dwarf2out_finish. */
:(
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PING][PATCH][2/2] Early LTO debug -- main part
2016-11-22 22:50 ` Jason Merrill
@ 2016-11-24 13:50 ` Richard Biener
2016-11-24 14:57 ` Richard Biener
2016-11-28 17:21 ` Jason Merrill
0 siblings, 2 replies; 7+ messages in thread
From: Richard Biener @ 2016-11-24 13:50 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches
On Tue, 22 Nov 2016, Jason Merrill wrote:
> On 11/11/2016 03:06 AM, Richard Biener wrote:
> > + /* ??? In some cases the C++ FE (at least) fails to
> > + set DECL_CONTEXT properly. Simply globalize stuff
> > + in this case. For example
> > + __dso_handle created via iostream line 74 col 25. */
>
> The comment for DECL_CONTEXT says that a VAR_DECL can have 'NULL_TREE or a
> TRANSLATION_UNIT_DECL if the given decl has "file scope"'
>
> So this doesn't seem like a FE bug.
True - though with LTO we rely on all entities be associated with
a TRANSLATION_UNIT_DECL (well, "rely" only in terms of how debuginfo
is emitted with or without this patch). It should be easy to fix this
up in the LTO streamer though.
> > + /* ??? We cannot unconditionally output die_offset if
> > + non-zero - at least -feliminate-dwarf2-dups will
> > + create references to those DIEs via symbols. And we
> > + do not clear its DIE offset after outputting it
> > + (and the label refers to the actual DIEs, not the
> > + DWARF CU unit header which is when using label + offset
> > + would be the correct thing to do).
>
> I'd be happy to remove or disable -feliminate-dwarf2-dups at this point, since
> it's already useless for C++ without reimplementation.
Ok, I'd favor removal in that case, I'll see to that independently
of this patch.
> > + /* "Unwrap" the decls DIE which we put in the imported unit context.
> > + ??? If we finish dwarf2out_function_decl refactoring we can
> > + do this in a better way from the start and only lazily emit
> > + the early DIE references. */
>
> Can you elaborate more on the refactoring? dwarf2out_function_decl is already
> very small, I'm guessing you mean gen_subprogram_die?
Yes, refactor gen_subprogram_die into the early part and the part needed
by dwarf2out_function_decl.
> > + /* ??? We can't annotate types late, but for LTO we may not
> > + generate a location early either (gfortran.dg/save_5.f90).
> > + The proper way is to handle it like VLAs though it is told
> > + that DW_AT_string_length does not support this. */
>
> I think go ahead and handle it like VLAs, this is an obvious generalization
> and should go into the spec soon enough. This can happen later.
Ok, note that VLAs are now handled by re-emitting types late to avoid
some guality regressions. With inlining VLA types also get copied
so we'd need to re-design how we handle them a bit. I'll see what
the DWARF people come up with.
> > + /* ??? This all (and above) should probably be simply
> > + a ! early_dwarf check somehow. */
> > + && ((DECL_ARTIFICIAL (decl) || in_lto_p)
> > || (get_AT_file (old_die, DW_AT_decl_file) == file_index
> > && (get_AT_unsigned (old_die, DW_AT_decl_line)
> > == (unsigned) s.line))))
>
> Why doesn't the existing source position check handle the LTO case? Also the
> extra parens aren't necessary.
Because in LTRANS we do not see those attributes anymore but they are
present in the early created DIEs. The LTRANS old_die looks basically
like
DW_TAG_subprogram
DW_AT_abstract_origin : <reference to early DIE via $symbol + offset>
refactoring gen_subprogram might also help here (I tried this three
times alrady but it quickly becomes unwieldly).
> > /* If we're emitting an out-of-line copy of an inline function,
> > emit info for the abstract instance and set up to refer to it. */
> > + /* ??? We have output an abstract instance early already and
> > + could just re-use that. This is how LTO treats all functions
> > + for example. */
>
> Isn't this what you do now?
Yes. dwarf2out_abstract_function only sets DW_AT_inline after the patch.
I'll adjust the comment to
/* If we're emitting a possibly inlined function emit it as
abstract instance. */
>
> > + /* Avoid generating stray type DIEs during late dwarf dumping.
> > + All types have been dumped early. */
> > + if (! (decl ? lookup_decl_die (decl) : NULL)
>
> Why do you still want to gen_type_die if decl_or_origin is origin?
Probably an oversight on my side -- will change.
> > +init_sections_and_labels (bool early_lto_debug)
>
> You're changing this function to do the same thing in four slightly different
> ways rather than two. I'd rather control each piece as appropriate; we ought
> to make SECTION_DEBUG or SECTION_DEBUG|SECTION_EXCLUDE a local variable, and
> select between *_SECTION and the DWO variant at each statement rather than in
> different blocks.
Note that the section names change between LTO, LTO_DWO, DWO and
regular section names. It's basically modeled after what we have now
which switches between regular and DWO section names. We might
be able to refactor this with a new array
enum section_kind { NORMAL, DWO, LTO, LTO_DWO };
char **section_names[section_kind][] = { { DEBUG_INFO_SECTION, ... },
{ DEBUG_DWO_INFO_SECTION, ... },
{ DEBUG_LTO_INFO_SECTION, ... },
{ DEBUG_LTO_DWO_INFO_SECTION, .. } };
would you prefer that?
> > + /* Remove DW_AT_macro from the early output. */
> > + if (have_macinfo)
> > + remove_AT (comp_unit_die (),
> > + dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros);
>
> This will need adjustment for Jakub's DWARF 5 work. Please make the choice of
> AT value a macro.
Ah, I see elsewhere
if (have_macinfo)
add_AT_macptr (comp_unit_die (),
dwarf_version >= 5 ? DW_AT_macros
: dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
macinfo_section_label);
I'll add
/* Attribute used to refer to the macro section. */
#define DEBUG_MACRO_ATTRIBUTE (dwarf_version >= 5 ? DW_AT_macros \
: dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros)
> > + /* ??? Mostly duplicated from dwarf2out_finish. */
>
> :(
Whoops - that got off my radar somehow. I'll try to factor out sth
like a output_dwarf function.
Thanks for the review.
Richard.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PING][PATCH][2/2] Early LTO debug -- main part
2016-11-24 13:50 ` Richard Biener
@ 2016-11-24 14:57 ` Richard Biener
2016-11-28 17:21 ` Jason Merrill
1 sibling, 0 replies; 7+ messages in thread
From: Richard Biener @ 2016-11-24 14:57 UTC (permalink / raw)
To: Jason Merrill; +Cc: gcc-patches
On Thu, 24 Nov 2016, Richard Biener wrote:
> On Tue, 22 Nov 2016, Jason Merrill wrote:
>
> > On 11/11/2016 03:06 AM, Richard Biener wrote:
> > > + /* ??? In some cases the C++ FE (at least) fails to
> > > + set DECL_CONTEXT properly. Simply globalize stuff
> > > + in this case. For example
> > > + __dso_handle created via iostream line 74 col 25. */
> >
> > The comment for DECL_CONTEXT says that a VAR_DECL can have 'NULL_TREE or a
> > TRANSLATION_UNIT_DECL if the given decl has "file scope"'
> >
> > So this doesn't seem like a FE bug.
>
> True - though with LTO we rely on all entities be associated with
> a TRANSLATION_UNIT_DECL (well, "rely" only in terms of how debuginfo
> is emitted with or without this patch). It should be easy to fix this
> up in the LTO streamer though.
>
> > > + /* ??? We cannot unconditionally output die_offset if
> > > + non-zero - at least -feliminate-dwarf2-dups will
> > > + create references to those DIEs via symbols. And we
> > > + do not clear its DIE offset after outputting it
> > > + (and the label refers to the actual DIEs, not the
> > > + DWARF CU unit header which is when using label + offset
> > > + would be the correct thing to do).
> >
> > I'd be happy to remove or disable -feliminate-dwarf2-dups at this point, since
> > it's already useless for C++ without reimplementation.
>
> Ok, I'd favor removal in that case, I'll see to that independently
> of this patch.
>
> > > + /* "Unwrap" the decls DIE which we put in the imported unit context.
> > > + ??? If we finish dwarf2out_function_decl refactoring we can
> > > + do this in a better way from the start and only lazily emit
> > > + the early DIE references. */
> >
> > Can you elaborate more on the refactoring? dwarf2out_function_decl is already
> > very small, I'm guessing you mean gen_subprogram_die?
>
> Yes, refactor gen_subprogram_die into the early part and the part needed
> by dwarf2out_function_decl.
>
> > > + /* ??? We can't annotate types late, but for LTO we may not
> > > + generate a location early either (gfortran.dg/save_5.f90).
> > > + The proper way is to handle it like VLAs though it is told
> > > + that DW_AT_string_length does not support this. */
> >
> > I think go ahead and handle it like VLAs, this is an obvious generalization
> > and should go into the spec soon enough. This can happen later.
>
> Ok, note that VLAs are now handled by re-emitting types late to avoid
> some guality regressions. With inlining VLA types also get copied
> so we'd need to re-design how we handle them a bit. I'll see what
> the DWARF people come up with.
>
> > > + /* ??? This all (and above) should probably be simply
> > > + a ! early_dwarf check somehow. */
> > > + && ((DECL_ARTIFICIAL (decl) || in_lto_p)
> > > || (get_AT_file (old_die, DW_AT_decl_file) == file_index
> > > && (get_AT_unsigned (old_die, DW_AT_decl_line)
> > > == (unsigned) s.line))))
> >
> > Why doesn't the existing source position check handle the LTO case? Also the
> > extra parens aren't necessary.
>
> Because in LTRANS we do not see those attributes anymore but they are
> present in the early created DIEs. The LTRANS old_die looks basically
> like
>
> DW_TAG_subprogram
> DW_AT_abstract_origin : <reference to early DIE via $symbol + offset>
>
> refactoring gen_subprogram might also help here (I tried this three
> times alrady but it quickly becomes unwieldly).
>
> > > /* If we're emitting an out-of-line copy of an inline function,
> > > emit info for the abstract instance and set up to refer to it. */
> > > + /* ??? We have output an abstract instance early already and
> > > + could just re-use that. This is how LTO treats all functions
> > > + for example. */
> >
> > Isn't this what you do now?
>
> Yes. dwarf2out_abstract_function only sets DW_AT_inline after the patch.
> I'll adjust the comment to
>
> /* If we're emitting a possibly inlined function emit it as
> abstract instance. */
>
> >
> > > + /* Avoid generating stray type DIEs during late dwarf dumping.
> > > + All types have been dumped early. */
> > > + if (! (decl ? lookup_decl_die (decl) : NULL)
> >
> > Why do you still want to gen_type_die if decl_or_origin is origin?
>
> Probably an oversight on my side -- will change.
>
> > > +init_sections_and_labels (bool early_lto_debug)
> >
> > You're changing this function to do the same thing in four slightly different
> > ways rather than two. I'd rather control each piece as appropriate; we ought
> > to make SECTION_DEBUG or SECTION_DEBUG|SECTION_EXCLUDE a local variable, and
> > select between *_SECTION and the DWO variant at each statement rather than in
> > different blocks.
>
> Note that the section names change between LTO, LTO_DWO, DWO and
> regular section names. It's basically modeled after what we have now
> which switches between regular and DWO section names. We might
> be able to refactor this with a new array
>
> enum section_kind { NORMAL, DWO, LTO, LTO_DWO };
> char **section_names[section_kind][] = { { DEBUG_INFO_SECTION, ... },
> { DEBUG_DWO_INFO_SECTION, ... },
> { DEBUG_LTO_INFO_SECTION, ... },
> { DEBUG_LTO_DWO_INFO_SECTION, .. } };
>
> would you prefer that?
>
> > > + /* Remove DW_AT_macro from the early output. */
> > > + if (have_macinfo)
> > > + remove_AT (comp_unit_die (),
> > > + dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros);
> >
> > This will need adjustment for Jakub's DWARF 5 work. Please make the choice of
> > AT value a macro.
>
> Ah, I see elsewhere
>
> if (have_macinfo)
> add_AT_macptr (comp_unit_die (),
> dwarf_version >= 5 ? DW_AT_macros
> : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
> macinfo_section_label);
>
> I'll add
>
> /* Attribute used to refer to the macro section. */
> #define DEBUG_MACRO_ATTRIBUTE (dwarf_version >= 5 ? DW_AT_macros \
> : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros)
>
>
> > > + /* ??? Mostly duplicated from dwarf2out_finish. */
> >
> > :(
>
> Whoops - that got off my radar somehow. I'll try to factor out sth
> like a output_dwarf function.
Ok, so while there are duplications there are a lot of omissions
(everything outputting location stuff) plus some LTO specific changes.
The dwarf2out_finish output part is 328 lines of code while the
redacted "copy" in dwarf2out_early_finish is 187 lines. I don't
see much that can be literally shared, some dwarf2out refactoring
could make thinks like
/* Traverse the DIE's and add add sibling attributes to those DIE's
that have children. */
add_sibling_attributes (comp_unit_die ());
for (limbo_die_node *node = limbo_die_list; node; node = node->next)
add_sibling_attributes (node->die);
for (comdat_type_node *ctnode = comdat_type_list;
ctnode != NULL; ctnode = ctnode->next)
add_sibling_attributes (ctnode->root_die);
smaller (if we'd had only a single list of CUs).
Or
/* Output the abbreviation table. */
if (vec_safe_length (abbrev_die_table) != 1)
{
switch_to_section (debug_abbrev_section);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
output_abbrev_section ();
}
could be fully put into output_abbrev_section ().
Other than that there's not much to do I fear. For now I'll amend
the ??? comment (and remove the ???).
Thanks,
Richard.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PING][PATCH][2/2] Early LTO debug -- main part
2016-11-24 13:50 ` Richard Biener
2016-11-24 14:57 ` Richard Biener
@ 2016-11-28 17:21 ` Jason Merrill
2017-05-19 10:33 ` Richard Biener
1 sibling, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2016-11-28 17:21 UTC (permalink / raw)
To: Richard Biener; +Cc: gcc-patches List
On Thu, Nov 24, 2016 at 8:50 AM, Richard Biener <rguenther@suse.de> wrote:
>> > + /* ??? We can't annotate types late, but for LTO we may not
>> > + generate a location early either (gfortran.dg/save_5.f90).
>> > + The proper way is to handle it like VLAs though it is told
>> > + that DW_AT_string_length does not support this. */
>>
>> I think go ahead and handle it like VLAs, this is an obvious generalization
>> and should go into the spec soon enough. This can happen later.
>
> Ok, note that VLAs are now handled by re-emitting types late to avoid
> some guality regressions. With inlining VLA types also get copied
> so we'd need to re-design how we handle them a bit.
> I'll see what the DWARF people come up with.
Does the discussion in
https://sourceware.org/bugzilla/show_bug.cgi?id=20426 cover the issue?
>> > + /* ??? This all (and above) should probably be simply
>> > + a ! early_dwarf check somehow. */
>> > + && ((DECL_ARTIFICIAL (decl) || in_lto_p)
>> > || (get_AT_file (old_die, DW_AT_decl_file) == file_index
>> > && (get_AT_unsigned (old_die, DW_AT_decl_line)
>> > == (unsigned) s.line))))
>>
>> Why doesn't the existing source position check handle the LTO case? Also the
>> extra parens aren't necessary.
>
> Because in LTRANS we do not see those attributes anymore but they are
> present in the early created DIEs.
Ah, OK. But the comment seems wrong, since we go through here in
early dwarf for local class methods.
>> > +init_sections_and_labels (bool early_lto_debug)
>>
>> You're changing this function to do the same thing in four slightly different
>> ways rather than two. I'd rather control each piece as appropriate; we ought
>> to make SECTION_DEBUG or SECTION_DEBUG|SECTION_EXCLUDE a local variable, and
>> select between *_SECTION and the DWO variant at each statement rather than in
>> different blocks.
>
> Note that the section names change between LTO, LTO_DWO, DWO and
> regular section names. It's basically modeled after what we have now
> which switches between regular and DWO section names. We might
> be able to refactor this with a new array
>
> enum section_kind { NORMAL, DWO, LTO, LTO_DWO };
> char **section_names[section_kind][] = { { DEBUG_INFO_SECTION, ... },
> { DEBUG_DWO_INFO_SECTION, ... },
> { DEBUG_LTO_INFO_SECTION, ... },
> { DEBUG_LTO_DWO_INFO_SECTION, .. } };
>
> would you prefer that?
That sounds better, thanks.
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PING][PATCH][2/2] Early LTO debug -- main part
2016-11-28 17:21 ` Jason Merrill
@ 2017-05-19 10:33 ` Richard Biener
0 siblings, 0 replies; 7+ messages in thread
From: Richard Biener @ 2017-05-19 10:33 UTC (permalink / raw)
To: Jason Merrill; +Cc: Richard Biener, gcc-patches List
Late response now that I'm finished refreshing the patches.
On Mon, Nov 28, 2016 at 6:20 PM, Jason Merrill <jason@redhat.com> wrote:
> On Thu, Nov 24, 2016 at 8:50 AM, Richard Biener <rguenther@suse.de> wrote:
>>> > + /* ??? We can't annotate types late, but for LTO we may not
>>> > + generate a location early either (gfortran.dg/save_5.f90).
>>> > + The proper way is to handle it like VLAs though it is told
>>> > + that DW_AT_string_length does not support this. */
>>>
>>> I think go ahead and handle it like VLAs, this is an obvious generalization
>>> and should go into the spec soon enough. This can happen later.
>>
>> Ok, note that VLAs are now handled by re-emitting types late to avoid
>> some guality regressions. With inlining VLA types also get copied
>> so we'd need to re-design how we handle them a bit.
>> I'll see what the DWARF people come up with.
>
> Does the discussion in
> https://sourceware.org/bugzilla/show_bug.cgi?id=20426 cover the issue?
This covers the VLA issue, yes. With the DW_OP_GNU_variable_value extension
we might be able to handle those better though gdb still lacks support.
For the Fortran case quoted above it might be possible to use
DW_OP_GNU_variable_value
as well but I'll leave that for followup improvements (handling it
"like VLAs" without
this extension isn't possible Jakub told me).
I've removed the reference to VLAs in the comment, added a -flto -g variant of
save_5.f90 to the testsuite and refer to that.
>
>>> > + /* ??? This all (and above) should probably be simply
>>> > + a ! early_dwarf check somehow. */
>>> > + && ((DECL_ARTIFICIAL (decl) || in_lto_p)
>>> > || (get_AT_file (old_die, DW_AT_decl_file) == file_index
>>> > && (get_AT_unsigned (old_die, DW_AT_decl_line)
>>> > == (unsigned) s.line))))
>>>
>>> Why doesn't the existing source position check handle the LTO case? Also the
>>> extra parens aren't necessary.
>>
>> Because in LTRANS we do not see those attributes anymore but they are
>> present in the early created DIEs.
>
> Ah, OK. But the comment seems wrong, since we go through here in
> early dwarf for local class methods.
Changed the comment to
/* ??? In LTO we do not see any of the location attributes. */
>>> > +init_sections_and_labels (bool early_lto_debug)
>>>
>>> You're changing this function to do the same thing in four slightly different
>>> ways rather than two. I'd rather control each piece as appropriate; we ought
>>> to make SECTION_DEBUG or SECTION_DEBUG|SECTION_EXCLUDE a local variable, and
>>> select between *_SECTION and the DWO variant at each statement rather than in
>>> different blocks.
>>
>> Note that the section names change between LTO, LTO_DWO, DWO and
>> regular section names. It's basically modeled after what we have now
>> which switches between regular and DWO section names. We might
>> be able to refactor this with a new array
>>
>> enum section_kind { NORMAL, DWO, LTO, LTO_DWO };
>> char **section_names[section_kind][] = { { DEBUG_INFO_SECTION, ... },
>> { DEBUG_DWO_INFO_SECTION, ... },
>> { DEBUG_LTO_INFO_SECTION, ... },
>> { DEBUG_LTO_DWO_INFO_SECTION, .. } };
>>
>> would you prefer that?
>
> That sounds better, thanks.
I tried a few variants but they all end up even more awkward ...
Given the ugliness is isolated in init_sections_and_labels I think
keeping it the
way it is is best.
Updated patches posted separately (I posted the diff to the previous
state already).
Thanks,
Richard.
>
> Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-05-19 10:32 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-21 11:26 [PATCH][2/2] Early LTO debug -- main part Richard Biener
2016-11-11 8:07 ` [PING][PATCH][2/2] " Richard Biener
2016-11-22 22:50 ` Jason Merrill
2016-11-24 13:50 ` Richard Biener
2016-11-24 14:57 ` Richard Biener
2016-11-28 17:21 ` Jason Merrill
2017-05-19 10:33 ` Richard Biener
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).