public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* LTO early debug, day 2
@ 2015-04-14 13:35 Richard Biener
  2015-04-14 16:27 ` Aldy Hernandez
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Biener @ 2015-04-14 13:35 UTC (permalink / raw)
  To: Aldy Hernandez, Jason Merrill, GCC Patches

[-- Attachment #1: Type: text/plain, Size: 10115 bytes --]

So I've been successful with funneling

class X { public: X(int r) : res(r) {} int get() { return res; }
private: int res; };
int main() { X x(0); return x.get (); }

all the way through LTO and gdb recognizing all the nice early debug info
for X:

> gdb ./a.out
(gdb) start
Temporary breakpoint 1 at 0x400514: file t.C, line 2.
Starting program: /home/abuild/rguenther/obj-debug-early-g/gcc/a.out

Temporary breakpoint 1, main () at t.C:2
2       int main() { X x(0); return x.get (); }
(gdb) info locals
x = {res = -8560}
(gdb) ptype x
type = class X {
  private:
    int res;

  public:
    X(int);
    int get(void);
}

the late dwarf generation is a bit awkward because it insists on creating
type DIEs for all sort of contexts when we process scope vars.  The type
DIEs already exist, but only in early debug info.  I suspect we need to do
quite some dwarf2out refactoring to split early from late debug generation
in areas like that.  For the C++ example above we get some stray unused
type DIEs still.

So what is missing?  Missing is the driver side - currently you need to
re-link the executable with the compile-time object file:

> ./xg++ -B. -B ../x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs t.C -g -dA -flto -flto-partition=none -save-temps
/tmp/ccY1C3Bg.lto.o:(.debug_info+0x23): undefined reference to `t.C.14231d22'
/tmp/ccY1C3Bg.lto.o:(.debug_info+0x28): undefined reference to `t.C.14231d22'
/tmp/ccY1C3Bg.lto.o:(.debug_info+0x47): undefined reference to `t.C.14231d22'
/tmp/ccY1C3Bg.lto.o:(.debug_info+0x4f): undefined reference to `t.C.14231d22'
/tmp/ccY1C3Bg.lto.o:(.debug_info+0x58): undefined reference to `t.C.14231d22'
/tmp/ccY1C3Bg.lto.o:(.debug_info+0x77): more undefined references to
`t.C.14231d22' follow
collect2: error: ld returned 1 exit status
> ./as --64 -o /tmp/ccY1C3Bg.lto.o t.s
> ./xgcc -B. t.o /tmp/ccY1C3Bg.lto.o -fno-lto

that's for tomorrow to simplify.  I've attached the current patch
ontop of the branch as well
as a.out.

I'm now creating a sinlge CU DIE during LTRANS and import the early
generated CUs
there, re-parenting all generated code to the LTRANS CU DIE.  That
seems to work best
with current gdb.

For the above example the early generated DWARF part is

 <0><166>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <167>   DW_AT_producer    : (indirect string, offset: 0x195): GNU C++ 5.0.0
20150316 (experimental) -mtune=generic -march=x86-64 -g -flto -flto-partition=no
ne
    <16b>   DW_AT_language    : 4       (C++)
    <16c>   DW_AT_name        : t.C
    <170>   DW_AT_comp_dir    : (indirect string, offset: 0x16d):
/abuild/rguenther/obj-debug-early-g/gcc
 <1><174>: Abbrev Number: 2 (DW_TAG_class_type)
    <175>   DW_AT_name        : X
    <177>   DW_AT_byte_size   : 4
    <178>   DW_AT_decl_file   : 1
    <179>   DW_AT_decl_line   : 1
    <17a>   DW_AT_sibling     : <0x1c2>
 <2><17e>: Abbrev Number: 3 (DW_TAG_member)
    <17f>   DW_AT_name        : res
    <183>   DW_AT_decl_file   : 1
    <184>   DW_AT_decl_line   : 1
    <185>   DW_AT_type        : <0x1c2>
    <189>   DW_AT_data_member_location: 0
 <2><18a>: Abbrev Number: 4 (DW_TAG_subprogram)
    <18b>   DW_AT_external    : 1
    <18b>   DW_AT_name        : X
    <18d>   DW_AT_decl_file   : 1
    <18e>   DW_AT_decl_line   : 1
    <18f>   DW_AT_linkage_name: (indirect string, offset: 0x163): _ZN1XC4Ei
    <193>   DW_AT_accessibility: 1      (public)
    <194>   DW_AT_declaration : 1
    <194>   DW_AT_object_pointer: <0x19c>
    <198>   DW_AT_sibling     : <0x1a7>
 <3><19c>: Abbrev Number: 5 (DW_TAG_formal_parameter)
    <19d>   DW_AT_type        : <0x1c9>
    <1a1>   DW_AT_artificial  : 1
 <3><1a1>: Abbrev Number: 6 (DW_TAG_formal_parameter)
    <1a2>   DW_AT_type        : <0x1c2>
 <3><1a6>: Abbrev Number: 0
 <2><1a7>: Abbrev Number: 7 (DW_TAG_subprogram)
    <1a8>   DW_AT_external    : 1
    <1a8>   DW_AT_name        : get
    <1ac>   DW_AT_decl_file   : 1
    <1ad>   DW_AT_decl_line   : 1
    <1ae>   DW_AT_linkage_name: (indirect string, offset: 0x200): _ZN1X3getEv
    <1b2>   DW_AT_type        : <0x1c2>
    <1b6>   DW_AT_accessibility: 1      (public)
    <1b7>   DW_AT_declaration : 1
    <1b7>   DW_AT_object_pointer: <0x1bb>
 <3><1bb>: Abbrev Number: 5 (DW_TAG_formal_parameter)
    <1bc>   DW_AT_type        : <0x1c9>
    <1c0>   DW_AT_artificial  : 1
 <3><1c0>: Abbrev Number: 0
 <2><1c1>: Abbrev Number: 0
 <1><1c2>: Abbrev Number: 8 (DW_TAG_base_type)
    <1c3>   DW_AT_byte_size   : 4
    <1c4>   DW_AT_encoding    : 5       (signed)
    <1c5>   DW_AT_name        : int
 <1><1c9>: Abbrev Number: 9 (DW_TAG_pointer_type)
    <1ca>   DW_AT_byte_size   : 8
    <1cb>   DW_AT_type        : <0x174>
 <1><1cf>: Abbrev Number: 10 (DW_TAG_subprogram)
    <1d0>   DW_AT_external    : 1
    <1d0>   DW_AT_name        : (indirect string, offset: 0x211): main
    <1d4>   DW_AT_decl_file   : 1
    <1d5>   DW_AT_decl_line   : 2
    <1d6>   DW_AT_type        : <0x1c2>
    <1da>   DW_AT_sibling     : <0x1e8>
 <2><1de>: Abbrev Number: 11 (DW_TAG_variable)
    <1df>   DW_AT_name        : x
    <1e1>   DW_AT_decl_file   : 1
    <1e2>   DW_AT_decl_line   : 2
    <1e3>   DW_AT_type        : <0x174>
 <2><1e7>: Abbrev Number: 0
 <1><1e8>: Abbrev Number: 12 (DW_TAG_subprogram)
    <1e9>   DW_AT_specification: <0x1a7>
    <1ed>   DW_AT_object_pointer: <0x1f5>
    <1f1>   DW_AT_sibling     : <0x1ff>
 <2><1f5>: Abbrev Number: 13 (DW_TAG_formal_parameter)
    <1f6>   DW_AT_name        : (indirect string, offset: 0x20c): this
    <1fa>   DW_AT_type        : <0x1ff>
    <1fe>   DW_AT_artificial  : 1
 <2><1fe>: Abbrev Number: 0
 <1><1ff>: Abbrev Number: 14 (DW_TAG_const_type)
    <200>   DW_AT_type        : <0x1c9>
 <1><204>: Abbrev Number: 15 (DW_TAG_subprogram)
    <205>   DW_AT_specification: <0x18a>
    <209>   DW_AT_inline      : 2       (declared as inline but ignored)
    <20a>   DW_AT_object_pointer: <0x212>
    <20e>   DW_AT_sibling     : <0x225>
 <2><212>: Abbrev Number: 13 (DW_TAG_formal_parameter)
    <213>   DW_AT_name        : (indirect string, offset: 0x20c): this
    <217>   DW_AT_type        : <0x1ff>
    <21b>   DW_AT_artificial  : 1
 <2><21b>: Abbrev Number: 16 (DW_TAG_formal_parameter)
    <21c>   DW_AT_name        : r
    <21e>   DW_AT_decl_file   : 1
    <21f>   DW_AT_decl_line   : 1
    <220>   DW_AT_type        : <0x1c2>
 <2><224>: Abbrev Number: 0
 <1><225>: Abbrev Number: 17 (DW_TAG_subprogram)
    <226>   DW_AT_abstract_origin: <0x204>
    <22a>   DW_AT_linkage_name: (indirect string, offset: 0x1f6): _ZN1XC2Ei
    <22e>   DW_AT_object_pointer: <0x232>
 <2><232>: Abbrev Number: 18 (DW_TAG_formal_parameter)
    <233>   DW_AT_abstract_origin: <0x212>
 <2><237>: Abbrev Number: 18 (DW_TAG_formal_parameter)
    <238>   DW_AT_abstract_origin: <0x21b>
 <2><23c>: Abbrev Number: 0
 <1><23d>: Abbrev Number: 0

while late during LTRANS we generate

 <0><249>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <24a>   DW_AT_producer    :
    <24b>   DW_AT_language    : 4       (C++)
    <24c>   DW_AT_low_pc      : 0x4004e6
    <254>   DW_AT_high_pc     : 0x4d
    <25c>   DW_AT_stmt_list   : 0x10c
 <1><260>: Abbrev Number: 2 (DW_TAG_imported_unit)
    <261>   DW_AT_import      : <0x166> [Abbrev Number: 1]
 <1><265>: Abbrev Number: 3 (DW_TAG_subprogram)
    <266>   DW_AT_abstract_origin: <0x225>
    <26a>   DW_AT_low_pc      : 0x4004e6
    <272>   DW_AT_high_pc     : 0x16
    <27a>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <27c>   DW_AT_object_pointer: <0x284>
    <280>   DW_AT_GNU_all_call_sites: 1
    <280>   DW_AT_sibling     : <0x295>
 <2><284>: Abbrev Number: 4 (DW_TAG_formal_parameter)
    <285>   DW_AT_abstract_origin: <0x232>
    <289>   DW_AT_artificial  : 1
    <289>   DW_AT_location    : 2 byte block: 91 68     (DW_OP_fbreg: -24)
 <2><28c>: Abbrev Number: 5 (DW_TAG_formal_parameter)
    <28d>   DW_AT_abstract_origin: <0x237>
    <291>   DW_AT_location    : 2 byte block: 91 64     (DW_OP_fbreg: -28)
 <2><294>: Abbrev Number: 0
 <1><295>: Abbrev Number: 3 (DW_TAG_subprogram)
    <296>   DW_AT_abstract_origin: <0x1e8>
    <29a>   DW_AT_low_pc      : 0x4004fc
    <2a2>   DW_AT_high_pc     : 0x10
    <2aa>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <2ac>   DW_AT_object_pointer: <0x2b4>
    <2b0>   DW_AT_GNU_all_call_sites: 1
    <2b0>   DW_AT_sibling     : <0x2bd>
 <2><2b4>: Abbrev Number: 4 (DW_TAG_formal_parameter)
    <2b5>   DW_AT_abstract_origin: <0x1f5>
    <2b9>   DW_AT_artificial  : 1
    <2b9>   DW_AT_location    : 2 byte block: 91 68     (DW_OP_fbreg: -24)
 <2><2bc>: Abbrev Number: 0
 <1><2bd>: Abbrev Number: 6 (DW_TAG_subprogram)
    <2be>   DW_AT_abstract_origin: <0x1cf>
    <2c2>   DW_AT_low_pc      : 0x40050c
    <2ca>   DW_AT_high_pc     : 0x27
    <2d2>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <2d4>   DW_AT_GNU_all_tail_call_sites: 1
    <2d4>   DW_AT_sibling     : <0x2e1>
 <2><2d8>: Abbrev Number: 7 (DW_TAG_variable)
    <2d9>   DW_AT_abstract_origin: <0x1de>
    <2dd>   DW_AT_location    : 2 byte block: 91 60     (DW_OP_fbreg: -32)
 <2><2e0>: Abbrev Number: 0
 <1><2e1>: Abbrev Number: 8 (DW_TAG_structure_type)
    <2e2>   DW_AT_name        : X
    <2e4>   DW_AT_byte_size   : 4
    <2e5>   DW_AT_decl_file   : 1
    <2e6>   DW_AT_decl_line   : 1
    <2e7>   DW_AT_sibling     : <0x2f9>
 <2><2eb>: Abbrev Number: 9 (DW_TAG_member)
    <2ec>   DW_AT_name        : res
    <2f0>   DW_AT_decl_file   : 1
    <2f1>   DW_AT_decl_line   : 1
    <2f2>   DW_AT_type        : <0x2f9>
    <2f6>   DW_AT_data_member_location: 0
    <2f7>   DW_AT_accessibility: 3      (private)
 <2><2f8>: Abbrev Number: 0
 <1><2f9>: Abbrev Number: 10 (DW_TAG_base_type)
    <2fa>   DW_AT_byte_size   : 4
    <2fb>   DW_AT_encoding    : 5       (signed)
    <2fc>   DW_AT_name        : int
 <1><300>: Abbrev Number: 0

notice the stray unused type DIEs at 0x2e1 and following.

We'll ultimatively have issues with fat LTO objects and with the
linker refusing to link
objects with slim LTO data just for its debug info.  Currently I'm
working to make
the slim-LTO but not marked as slim mode work only.

Richard.

[-- Attachment #2: early-lto-debug-day2 --]
[-- Type: application/octet-stream, Size: 35799 bytes --]

diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index b817aaf..78e594e 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -44,6 +44,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hash-map.h"
 #include "ggc.h"
 #include "tm_p.h"
+#include "function.h"
+#include "emit-rtl.h"
 
 \f
 /* Output an unaligned integer with the given value and size.  Prefer not
@@ -216,6 +218,34 @@ dw2_asm_output_offset (int size, const char *label,
   va_end (ap);
 }
 
+void
+dw2_asm_output_offset_offset (int size, const char *label, HOST_WIDE_INT offset,
+			      section *base ATTRIBUTE_UNUSED,
+			      const char *comment, ...)
+{
+  va_list ap;
+
+  va_start (ap, comment);
+
+#ifdef ASM_OUTPUT_DWARF_OFFSET
+  FIXME
+  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
+#else
+  dw2_assemble_integer (size, gen_rtx_PLUS (Pmode,
+					    gen_rtx_SYMBOL_REF (Pmode, label),
+					    gen_int_mode (offset, Pmode)));
+#endif
+
+  if (flag_debug_asm && comment)
+    {
+      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+      vfprintf (asm_out_file, comment, ap);
+    }
+  fputc ('\n', asm_out_file);
+
+  va_end (ap);
+}
+
 #if 0
 
 /* Output a self-relative reference to a label, possibly in a
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index d4a5706..c7d49df 100644
--- a/gcc/dwarf2asm.h
+++ b/gcc/dwarf2asm.h
@@ -40,6 +40,10 @@ extern void dw2_asm_output_offset (int, const char *, section *,
 				   const char *, ...)
      ATTRIBUTE_NULL_PRINTF_4;
 
+extern void dw2_asm_output_offset_offset (int, const char *, HOST_WIDE_INT,
+					  section *, const char *, ...)
+     ATTRIBUTE_NULL_PRINTF_5;
+
 extern void dw2_asm_output_addr (int, const char *, const char *, ...)
      ATTRIBUTE_NULL_PRINTF_3;
 
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 0976415..25fdad3 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2637,6 +2637,12 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
   /* Die was generated early via dwarf2out_early_global_decl.  */
   BOOL_BITFIELD dumped_early : 1;
+  /* For an external ref to die_symbol if die_offset contains an extra
+     offset to that symbol.  */
+  BOOL_BITFIELD with_offset : 1;
+  /* For a DIE removed from the DIE tree.  TYPE_SYMTAB_DIE is supposed
+     to be ignored (and cleared lazily).  */
+  BOOL_BITFIELD removed : 1;
   /* Lots of spare bits.  */
 }
 die_node;
@@ -4977,7 +4983,10 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
 static inline dw_die_ref
 lookup_type_die (tree type)
 {
-  return TYPE_SYMTAB_DIE (type);
+  dw_die_ref die = TYPE_SYMTAB_DIE (type);
+  if (die && die->removed)
+    TYPE_SYMTAB_DIE (type) = die = NULL;
+  return die;
 }
 
 /* Given a TYPE_DIE representing the type TYPE, if TYPE is an
@@ -5042,7 +5051,145 @@ decl_die_hasher::equal (die_node *x, tree y)
 static inline dw_die_ref
 lookup_decl_die (tree decl)
 {
-  return decl_die_table->find_with_hash (decl, DECL_UID (decl));
+  dw_die_ref die = decl_die_table->find_with_hash (decl, DECL_UID (decl));
+  if (die && die->removed)
+    {
+      decl_die_table->remove_elt_with_hash (decl, DECL_UID (decl));
+      die = NULL;
+    }
+  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.  */
+
+bool
+lookup_die_ref_for_decl (tree decl, const char **sym,
+			 unsigned HOST_WIDE_INT *off)
+{
+  dw_die_ref die;
+
+  if (TREE_CODE (decl) == BLOCK)
+    die = BLOCK_DIE (decl);
+  else
+    die = lookup_decl_die (decl);
+  if (!die)
+    return false;
+
+  /* ???  During WPA maintain a simpler decl vs. DIE ref association.
+     For now ICE.  */
+  if (flag_wpa)
+    {
+      sorry ("not implemented, use -flto-partition=none");
+      gcc_unreachable ();
+    }
+
+  /* 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.  */
+
+void
+register_die_ref_for_decl (tree decl, const char *sym,
+			   unsigned HOST_WIDE_INT off)
+{
+  /* ???  During WPA maintain a simpler decl vs. DIE ref association.
+     For now ICE.  */
+  if (flag_wpa)
+    {
+      sorry ("not implemented, use -flto-partition=none");
+      gcc_unreachable ();
+    }
+
+  dw_die_ref die
+    = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+  gcc_assert (!die);
+  if (!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);
+      else
+	ctx = DECL_CONTEXT (decl);
+      while (ctx && TYPE_P (ctx))
+	ctx = TYPE_CONTEXT (ctx);
+      if (ctx)
+	parent = (TREE_CODE (ctx) == BLOCK
+		  ? BLOCK_DIE (ctx) : lookup_decl_die (ctx));
+      /* Create a DIE "stub".  */
+      switch (TREE_CODE (decl))
+	{
+	case TRANSLATION_UNIT_DECL:
+#if 0
+	  die = new_die (DW_TAG_compile_unit, NULL, decl);
+	  break;
+#else
+	  {
+	    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);
+	    /* Re-target all CU decls to the LTRANS CU DIE.  */
+	    equate_decl_number_to_die (decl, die);
+	    return;
+	  }
+#endif
+	case FUNCTION_DECL:
+	  die = new_die (DW_TAG_subprogram, parent, decl);
+	  break;
+	case VAR_DECL:
+	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 BLOCK:
+	  die = new_die (DW_TAG_lexical_block, parent, decl);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      die->dumped_early = true;
+      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).  */
@@ -5521,7 +5668,11 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
 			       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);
@@ -6784,7 +6935,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";
@@ -6813,7 +6964,15 @@ compute_section_prefix (dw_die_ref unit_die)
       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;
 }
 
@@ -8935,7 +9094,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)",
@@ -9114,8 +9277,13 @@ 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);
+		  if (AT_ref (a)->with_offset)
+		    dw2_asm_output_offset_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
@@ -9266,7 +9434,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
   calc_die_sizes (die);
 
   oldsym = die->die_id.die_symbol;
-  if (oldsym)
+  if (oldsym && die->comdat_type_p)
     {
       tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
 
@@ -9278,10 +9446,35 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
   else
     {
       switch_to_section (debug_info_section);
-      ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
+      /* With LTO we emit multiple stand-alone CUs that are not
+         "split-out" ones.
+	 ???  We probably should do this differently and re-parent
+	 everything to the main CU, importing all referenced ones?  */
+      if (!info_section_emitted)
+	ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
       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 output by output_die and account
+     for the extra offset produced by the CU heade (which has fixed size?).  */
+  if (flag_generate_lto)
+    {
+      gcc_assert (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);
+      targetm.asm_out.globalize_label (asm_out_file, oldsym);
+      ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+    }
+
   /* Output debugging information.  */
   output_compilation_unit_header ();
   output_die (die);
@@ -18790,6 +18983,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 	      };  */
 	   || !is_cu_die (context_die))
 	   && (DECL_ARTIFICIAL (decl)
+	       // Unless we do this we can't prune file/line in prune_dies
+	       || get_AT_ref (old_die, DW_AT_abstract_origin)
 	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
 		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
 		       == (unsigned) s.line))))
@@ -19596,7 +19791,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 
 		 See dwarf2out_decl and its use of
 		 local_function_static to see how this happened.  */
-	      gcc_assert (local_function_static (decl));
 	      var_die = old_die;
 	      goto gen_variable_die_location;
 	    }
@@ -21061,7 +21255,28 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
 					     stmt, context_die);
     }
   else
-    gen_decl_die (decl, origin, context_die);
+    {
+      if (DECL_P (decl))
+	die = lookup_decl_die (decl);
+
+      if (die && die->die_parent != context_die)
+	{
+	  /* We associate vars with their DECL_CONTEXT first which misses
+	     their BLOCK association.  Move them.  */
+	  gcc_assert (in_lto_p && die->die_parent != NULL);
+	  /* ???  Moving is expensive.  Better fix DECL_CONTEXT?  */
+	  dw_die_ref prev = die->die_parent->die_child;
+	  while (prev->die_sib != die)
+	    prev = prev->die_sib;
+	  remove_child_with_prev (die, prev);
+	  add_child_die (context_die, die);
+	}
+
+      /* ???  The following gets stray type DIEs created even for decls
+	 that were created early.  */
+
+      gen_decl_die (decl, origin, context_die);
+    }
 }
 
 /* Generate all of the decls declared within a given scope and (recursively)
@@ -21455,7 +21670,10 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 	}
 
       /* 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.  */
+	       && !(lookup_decl_die (decl)
+		    && lookup_decl_die (decl)->dumped_early))
 	{
 	  /* Before we describe the FUNCTION_DECL itself, make sure that we
 	     have its containing type.  */
@@ -21522,6 +21740,12 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       if (debug_info_level <= DINFO_LEVEL_TERSE)
 	break;
 
+	{
+      /* ???  Avoid generating stray type DIEs during late LTO dwarf dumping.
+         All types have been dumped early.  */
+      dw_die_ref die = lookup_decl_die (decl);
+      if (!die || !die->dumped_early)
+	{
       /* Output any DIEs that are needed to specify the type of this data
 	 object.  */
       if (decl_by_reference_p (decl_or_origin))
@@ -21533,6 +21757,8 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
       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);
@@ -25087,6 +25313,69 @@ dwarf2out_finish (const char *filename)
   comdat_type_node *ctnode;
   dw_die_ref main_comp_unit_die;
 
+  /* Create parent - child relationship if we streamed in DIE reference
+     stubs.  */
+  if (in_lto_p)
+    {
+      bool changed;
+      do
+	{
+	  changed = false;
+	  for (limbo_die_node **node = &limbo_die_list;
+	       *node; )
+	    {
+	      if ((*node)->die->die_tag == DW_TAG_compile_unit)
+		{
+		  if ((*node)->die == comp_unit_die ())
+		    *node = (*node)->next;
+		  else
+		    node = &(*node)->next;
+		  continue;
+		}
+
+	      tree t = (*node)->created_for;
+	      tree context = NULL_TREE;
+	      if (DECL_P (t))
+		context = DECL_CONTEXT (t);
+	      else if (TREE_CODE (t) == BLOCK)
+		context = BLOCK_SUPERCONTEXT (t);
+	      /* ???  We don't output DIEs for wrapping scopes.  Skip
+	         as many DIEs as needed.  */
+	      while (TREE_CODE (context) == BLOCK
+		     && !BLOCK_DIE (context))
+		context = BLOCK_SUPERCONTEXT (context);
+	      /* ???  We fail to re-parent BLOCK scope variables as
+	         dependent on frontend their DECL_CONTEXT is not the
+		 containing scope but the containing function.  */
+	      if (context && DECL_P (context))
+		{
+		  dw_die_ref ctx = lookup_decl_die (context);
+		  if (ctx)
+		    {
+		      add_child_die (ctx, (*node)->die);
+		      *node = (*node)->next;
+		      changed = true;
+		      continue;
+		    }
+		}
+	      else if (context && TREE_CODE (context) == BLOCK)
+		{
+		  dw_die_ref ctx = BLOCK_DIE (context);
+		  if (ctx)
+		    {
+		      add_child_die (ctx, (*node)->die);
+		      *node = (*node)->next;
+		      changed = true;
+		      continue;
+		    }
+		}
+
+	      node = &(*node)->next;
+	    }
+	}
+      while (changed);
+    }
+
   /* If the limbo list has anything, it should be things that were
      created after the compilation proper.  Anything from the early
      dwarf pass, should have parents and should never be in the limbo
@@ -25096,36 +25385,7 @@ dwarf2out_finish (const char *filename)
 		|| !node->die->dumped_early);
 
   /* Flush out any latecomers to the limbo party.  */
-  dwarf2out_early_finish();
-
-  /* PCH might result in DW_AT_producer string being restored from the
-     header compilation, so always fill it with empty string initially
-     and overwrite only here.  */
-  dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
-  producer_string = gen_producer_string ();
-  producer->dw_attr_val.v.val_str->refcount--;
-  producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
-
-  gen_scheduled_generic_parms_dies ();
-  gen_remaining_tmpl_value_param_die_attribute ();
-
-  /* Add the name for the main input file now.  We delayed this from
-     dwarf2out_init to avoid complications with PCH.
-     For LTO produced units use a fixed artificial name to avoid
-     leaking tempfile names into the dwarf.  */
-  if (!in_lto_p)
-    add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
-  else
-    add_name_attribute (comp_unit_die (), "<artificial>");
-  if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
-    add_comp_dir_attribute (comp_unit_die ());
-  else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
-    {
-      bool p = false;
-      file_table->traverse<bool *, file_table_relative_p> (&p);
-      if (p)
-	add_comp_dir_attribute (comp_unit_die ());
-    }
+  //dwarf2out_early_finish();
 
 #if ENABLE_ASSERT_CHECKING
   {
@@ -25134,44 +25394,6 @@ dwarf2out_finish (const char *filename)
   }
 #endif
   resolve_addr (comp_unit_die ());
-  move_marked_base_types ();
-
-  /* Walk through the list of incomplete types again, trying once more to
-     emit full debugging info for them.  */
-  retry_incomplete_types ();
-
-  if (flag_eliminate_unused_debug_types)
-    prune_unused_types ();
-
-  /* FIXME debug-early: Prune DIEs for unused decls.  */
-
-  /* Generate separate COMDAT sections for type DIEs. */
-  if (use_debug_types)
-    {
-      break_out_comdat_types (comp_unit_die ());
-
-      /* Each new type_unit DIE was added to the limbo die list when created.
-         Since these have all been added to comdat_type_list, clear the
-         limbo die list.  */
-      limbo_die_list = NULL;
-
-      /* For each new comdat type unit, copy declarations for incomplete
-         types to make the new unit self-contained (i.e., no direct
-         references to the main compile unit).  */
-      for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
-        copy_decls_for_unworthy_types (ctnode->root_die);
-      copy_decls_for_unworthy_types (comp_unit_die ());
-
-      /* In the process of copying declarations from one unit to another,
-         we may have left some declarations behind that are no longer
-         referenced.  Prune them.  */
-      prune_unused_types ();
-    }
-
-  /* Generate separate CUs for each of the include files we've seen.
-     They will go into limbo_die_list.  */
-  if (flag_eliminate_dwarf2_dups)
-    break_out_includes (comp_unit_die ());
 
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
@@ -25438,12 +25660,101 @@ dwarf2out_finish (const char *filename)
     output_indirect_strings ();
 }
 
+/* Reset DIEs so we can output them again, pruning those we do not
+   need late.  */
+
+static void
+prune_dies (dw_die_ref die, const char *sym)
+{
+  dw_die_ref c, prev;
+
+  /* Add an abstract origin to debug_info_section_label + offset.  */
+  if (die->die_tag == DW_TAG_variable
+      || die->die_tag == DW_TAG_formal_parameter
+      || die->die_tag == DW_TAG_subprogram
+      || die->die_tag == DW_TAG_lexical_block)
+      //|| die->die_tag == DW_TAG_compile_unit)  // gdb doesn't like this
+    {
+      /* Remove stuff we refer to via the abstract origin.  */
+#if 1 // we should be able to remove everything, but ...
+      vec_safe_truncate (die->die_attr, 0);
+#else
+      // at least remove references to types, names and locations
+      remove_AT (die, DW_AT_decl_file);
+      remove_AT (die, DW_AT_decl_line);
+      remove_AT (die, DW_AT_type);
+      remove_AT (die, DW_AT_name);
+#endif
+
+      /* Add a reference to the early output DIE.  */
+      add_AT_external_die_ref (die, DW_AT_abstract_origin,
+			       sym ? sym
+			       : IDENTIFIER_POINTER
+			          (get_identifier (debug_info_section_label)),
+			       die->die_offset);
+    }
+
+  /* Remove stuff we re-generate.  */
+  die->die_mark = 0;
+  die->die_offset = 0;
+  die->die_abbrev = 0;
+  remove_AT (die, DW_AT_sibling);
+
+  prev = die->die_child;
+  if (prev)
+    do {
+      c = prev->die_sib;
+      /* Remove non-decl DIEs.  */
+      if (c->die_tag != DW_TAG_variable
+	  && c->die_tag != DW_TAG_formal_parameter
+	  && c->die_tag != DW_TAG_subprogram
+	  && c->die_tag != DW_TAG_compile_unit
+	  && c->die_tag != DW_TAG_lexical_block)
+	{
+	  /* Remove DIE.  */
+	  bool was_last = (c == die->die_child);
+	  remove_child_with_prev (c, prev);
+	  /* TYPE_SYMBTAB_DIE (and lookup_type_die) will still find
+	     the removed DIE.  Same for lookup_decl_die.  */
+	  c->removed = 1;
+	  /* Re-parent children so we'll visit them next.  */
+	  if (c->die_child)
+	    {
+	      dw_die_ref cc;
+	      FOR_EACH_CHILD (c, cc, cc->die_parent = c->die_parent);
+	      c->die_child->die_sib = prev->die_sib;
+	      prev->die_sib = c->die_child;
+	      continue;
+	    }
+	  if (was_last)
+	    break;
+	  continue;
+	}
+      else
+	{
+	  prune_dies (c, sym);
+	  prev = c;
+	}
+    } while (c != die->die_child);
+}
+
 /* Perform any cleanups needed after the early debug generation pass
    has run.  */
 
 static void
 dwarf2out_early_finish (void)
 {
+  comdat_type_node *ctnode;
+
+  /* Pick the first TRANSLATION_UNIT_DECL we didn't create a DIE for
+     and equate it with our default CU DIE.  LTO output needs to be
+     able to lookup DIEs for translation unit decls.  */
+  unsigned i;
+  tree decl;
+  FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, decl)
+    if (!lookup_decl_die (decl))
+      equate_decl_number_to_die (decl, comp_unit_die ());
+
   /* Traverse the limbo die list, and add parent/child links.  The only
      dies without parents that should be here are concrete instances of
      inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
@@ -25496,6 +25807,179 @@ dwarf2out_early_finish (void)
     }
 
   limbo_die_list = NULL;
+
+  /* PCH might result in DW_AT_producer string being restored from the
+     header compilation, so always fill it with empty string initially
+     and overwrite only here.  */
+  dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
+  producer_string = gen_producer_string ();
+  producer->dw_attr_val.v.val_str->refcount--;
+  producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
+
+  gen_scheduled_generic_parms_dies ();
+  gen_remaining_tmpl_value_param_die_attribute ();
+
+  /* Add the name for the main input file now.  We delayed this from
+     dwarf2out_init to avoid complications with PCH.
+     For LTO produced units use a fixed artificial name to avoid
+     leaking tempfile names into the dwarf.  */
+  if (!in_lto_p)
+    add_name_attribute (comp_unit_die (), remap_debug_filename (main_input_filename));
+  else
+    add_name_attribute (comp_unit_die (), "<artificial>");
+  if (!IS_ABSOLUTE_PATH (main_input_filename) || targetm.force_at_comp_dir)
+    add_comp_dir_attribute (comp_unit_die ());
+  else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
+    {
+      bool p = false;
+      file_table->traverse<bool *, file_table_relative_p> (&p);
+      if (p)
+	add_comp_dir_attribute (comp_unit_die ());
+    }
+
+  move_marked_base_types ();
+
+  /* Walk through the list of incomplete types again, trying once more to
+     emit full debugging info for them.  */
+  retry_incomplete_types ();
+
+  if (flag_eliminate_unused_debug_types)
+    prune_unused_types ();
+
+  /* FIXME debug-early: Prune DIEs for unused decls.  */
+
+  /* Generate separate COMDAT sections for type DIEs. */
+  if (use_debug_types)
+    {
+      break_out_comdat_types (comp_unit_die ());
+
+      /* Each new type_unit DIE was added to the limbo die list when created.
+         Since these have all been added to comdat_type_list, clear the
+         limbo die list.  */
+      limbo_die_list = NULL;
+
+      /* For each new comdat type unit, copy declarations for incomplete
+         types to make the new unit self-contained (i.e., no direct
+         references to the main compile unit).  */
+      for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+        copy_decls_for_unworthy_types (ctnode->root_die);
+      copy_decls_for_unworthy_types (comp_unit_die ());
+
+      /* In the process of copying declarations from one unit to another,
+         we may have left some declarations behind that are no longer
+         referenced.  Prune them.  */
+      prune_unused_types ();
+    }
+
+  /* Generate separate CUs for each of the include files we've seen.
+     They will go into limbo_die_list.  */
+  if (flag_eliminate_dwarf2_dups)
+    break_out_includes (comp_unit_die ());
+
+
+
+  /* ???  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 (node = limbo_die_list; node; node = node->next)
+    add_sibling_attributes (node->die);
+  for (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 (node = limbo_die_list; node; node = node->next)
+    output_comp_unit (node->die, 0);
+
+  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 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 ());
+
+  /* If we generate LTO stick a unique symbol to the main debuginfo section.  */
+  if (flag_generate_lto)
+    compute_section_prefix_1 (comp_unit_die (), false);
+
+  /* Output the main compilation unit if non-empty or if .debug_macinfo
+     or .debug_macro will be emitted.  */
+  output_comp_unit (comp_unit_die (), have_macinfo);
+
+  /* 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)
+    {
+      switch_to_section (debug_macinfo_section);
+      ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+      output_macinfo ();
+      dw2_asm_output_data (1, 0, "End compilation unit");
+    }
+
+
+  /* If we emitted any indirect strings, output the string table too.  */
+  if (debug_str_hash || skeleton_debug_str_hash)
+    output_indirect_strings ();
+
+
+  /* ???  Prune stuff so that dwarf2out_finish runs successfully.  */
+  /* ???  If generating LTO don't do this, we need the output state
+     to be preserved until LTO out.  This of course will break
+     fat LTO objects - no idea what to do for them but to emit
+     "split" info as well (and thus have another after_lto_emit hook
+     or simply do the pruning at regular dwarf2out_finish...).  */
+  if (!flag_generate_lto)
+    {
+      prune_dies (comp_unit_die (), comp_unit_die ()->die_id.die_symbol);
+      for (node = limbo_die_list; node; node = node->next)
+	prune_dies (node->die, node->die->die_id.die_symbol);
+    }
+
+  debug_str_hash = NULL;  /* Contents are GCed.  */
+
+  /* ???  Need new labels if we output some stuff early.  */
+  ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
+			       DEBUG_ABBREV_SECTION_LABEL, 1);
+  ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
+			       DEBUG_INFO_SECTION_LABEL, 1);
 }
 
 /* Reset all state within dwarf2out.c so that we can rerun the compiler
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index a045b97..eee9e4f 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1181,6 +1181,8 @@ lto_input_variable_constructor (struct lto_file_decl_data *file_data,
 }
 
 
+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.  */
 
@@ -1201,6 +1203,23 @@ lto_read_tree_1 (struct lto_input_block *ib, struct data_in *data_in, tree expr)
       && 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.c:register_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 *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);
+	}
+    }
+
   /* We should never try to instantiate an MD or NORMAL builtin here.  */
   if (TREE_CODE (expr) == FUNCTION_DECL)
     gcc_assert (!streamer_handle_as_builtin_p (expr));
@@ -1362,6 +1381,15 @@ lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
     {
       unsigned len, entry_len;
       lto_input_scc (ib, data_in, &len, &entry_len);
+
+      /* Register DECLs with the debuginfo machinery.  */
+      while (!dref_queue.is_empty ())
+	{
+	  extern void register_die_ref_for_decl (tree, const char *,
+						 unsigned HOST_WIDE_INT);
+	  dref_entry e = dref_queue.pop ();
+	  register_die_ref_for_decl (e.decl, e.sym, e.off);
+	}
     }
   return lto_input_tree_1 (ib, data_in, tag, 0);
 }
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 671bac3..fa36363 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -400,6 +400,28 @@ lto_write_tree_1 (struct output_block *ob, tree expr, bool ref_p)
 			 (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.c:register_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)
+    {
+      extern bool lookup_die_ref_for_decl (tree, const char **,
+					   unsigned HOST_WIDE_INT *);
+      const char *sym;
+      unsigned HOST_WIDE_INT off;
+      if (debug_info_level > DINFO_LEVEL_NONE
+	  && lookup_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
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index c8862a2..7f7fd09 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -1154,4 +1154,13 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, type_decl)
 DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
 DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
 
+struct dref_entry {
+    tree decl;
+    const char *sym;
+    unsigned HOST_WIDE_INT off;
+};
+
+extern vec<dref_entry> dref_queue;
+
+
 #endif /* GCC_LTO_STREAMER_H  */
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 760975f..b3d71fe 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -1838,6 +1838,9 @@ unify_scc (struct streamer_tree_cache_d *cache, unsigned from,
 	      ggc_free (scc->entries[i]);
 	    }
 
+	  /* Drop DIE references.  */
+	  dref_queue.truncate (0);
+
 	  break;
 	}
 
@@ -1914,7 +1917,6 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
 	  if (len == 1
 	      && (TREE_CODE (first) == IDENTIFIER_NODE
 		  || TREE_CODE (first) == INTEGER_CST
-		  || TREE_CODE (first) == TRANSLATION_UNIT_DECL
 		  || streamer_handle_as_builtin_p (first)))
 	    continue;
 
@@ -1950,10 +1952,6 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
 	      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)
-		debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
 	      if (!flag_ltrans)
 		{
 		  /* Register variables and functions with the
@@ -1969,6 +1967,16 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
 		    vec_safe_push (tree_with_vars, t);
 		}
 	    }
+
+	  /* Register DECLs with the debuginfo machinery.  */
+	  while (!dref_queue.is_empty ())
+	    {
+	      extern void register_die_ref_for_decl (tree, const char *,
+						     unsigned HOST_WIDE_INT);
+	      dref_entry e = dref_queue.pop ();
+	      register_die_ref_for_decl (e.decl, e.sym, e.off);
+	    }
+
 	  if (seen_type)
 	    num_type_scc_trees += len;
 	}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 5e3bd08..5b1c041 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -705,7 +705,10 @@ compile_file (void)
 
   /* Let linker plugin know that this is a slim object and must be LTOed
      even when user did not ask for it.  */
-  if (flag_generate_lto && !flag_fat_lto_objects)
+  /* ???  As we now put early debug info into even slim objects they
+     are kind-of "fat" again.  Make sure the linker doesn't refuse
+     to operate in non-LTO mode on them.  */
+  if (flag_generate_lto && !flag_fat_lto_objects && 0)
     {
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
       ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, NULL_TREE, "__gnu_lto_slim",

[-- Attachment #3: a.out --]
[-- Type: application/octet-stream, Size: 13744 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: LTO early debug, day 2
  2015-04-14 13:35 LTO early debug, day 2 Richard Biener
@ 2015-04-14 16:27 ` Aldy Hernandez
  2015-04-14 17:02   ` Richard Biener
  0 siblings, 1 reply; 3+ messages in thread
From: Aldy Hernandez @ 2015-04-14 16:27 UTC (permalink / raw)
  To: Richard Biener, Jason Merrill, GCC Patches

On 04/14/2015 06:35 AM, Richard Biener wrote:

Richard, thank you so much for working on this.  It's good to see your 
progress here.

> the late dwarf generation is a bit awkward because it insists on creating
> type DIEs for all sort of contexts when we process scope vars.  The type

Types should be reused, are they not being reused from early to late dwarf?

> DIEs already exist, but only in early debug info.  I suspect we need to do
> quite some dwarf2out refactoring to split early from late debug generation
> in areas like that.  For the C++ example above we get some stray unused
> type DIEs still.

A pass to remove unused DIEs is on my TODO list.

Aldy

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: LTO early debug, day 2
  2015-04-14 16:27 ` Aldy Hernandez
@ 2015-04-14 17:02   ` Richard Biener
  0 siblings, 0 replies; 3+ messages in thread
From: Richard Biener @ 2015-04-14 17:02 UTC (permalink / raw)
  To: Aldy Hernandez, Jason Merrill, GCC Patches

On April 14, 2015 6:27:14 PM GMT+02:00, Aldy Hernandez <aldyh@redhat.com> wrote:
>On 04/14/2015 06:35 AM, Richard Biener wrote:
>
>Richard, thank you so much for working on this.  It's good to see your 
>progress here.
>
>> the late dwarf generation is a bit awkward because it insists on
>creating
>> type DIEs for all sort of contexts when we process scope vars.  The
>type
>
>Types should be reused, are they not being reused from early to late
>dwarf?

They are not there in the late phase because they should not be needed
(They are inherited from early debug
But not explicitly rematerialized).

In fact the whole plan is to eventually
Not even have the 'tree' side of the types
Anymore.

Richard.

>
>> DIEs already exist, but only in early debug info.  I suspect we need
>to do
>> quite some dwarf2out refactoring to split early from late debug
>generation
>> in areas like that.  For the C++ example above we get some stray
>unused
>> type DIEs still.
>
>A pass to remove unused DIEs is on my TODO list.
>
>Aldy


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-04-14 17:02 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-14 13:35 LTO early debug, day 2 Richard Biener
2015-04-14 16:27 ` Aldy Hernandez
2015-04-14 17:02   ` 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).