diff mbox

[debug-early] C++ clones and limbo DIEs

Message ID 54D2B907.1040309@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez Feb. 5, 2015, 12:27 a.m. UTC
Howdy!

Such simple requests.  Such a pain in the ass to implement :).

I know Richard will be tickled pink with the attached patch-- well, at 
least with the general approach, as generically handling DECLs has been 
his desire all along.  I hope I got it right, as it was a royal pain to 
get the libraries built, and the guality tests to pass with no 
regressions.  Our dwarf implementation is finicky to say the least.

With this patch we generate symbols and functions generically, and get 
rid of a plethora of front-end code attempting to generate debug 
information at different places.

I do have a question about generating C++ namespace alias debug info in 
the code marked with ??, if you care to answer.

I wrote a huge comment on gen_subprogram_die() explaining the multitude 
of times this, and other gen_*_die, functions get called.  If only, it 
helps me keep things straight.  If you dislike it, we could remove it at 
merge time, but I honestly don't understand how anyone could understand 
all this without intimate knowledge of the code (that is, it's sure not 
obvious from a cursory look at the code).

In a perhaps distant future, I'd like to remove dwarf2out_type_decl() 
entirely, though its presence is currently needed to get DIEs generated 
in the right order.  Again, finicky.  But alas, this doesn't bother me 
too much.

I could seriously benefit from review on this code, as I've been looking 
at it far too long.

Aldy

Comments

Jason Merrill Feb. 5, 2015, 8:11 p.m. UTC | #1
On 02/04/2015 07:27 PM, Aldy Hernandez wrote:
> +	/* Anything who's context is not a TRANSLATION_UNIT_DECL will
> +	   be handled by either handling reachable functions below, or
> +	   by generating DIEs for types.  */

"whose"

And what about namespace-scope variables?  Maybe instead of checking for 
TRANSLATION_UNIT_DECL context this should check non-function context.

> +  /* This is the second iteration through the global symbols.  Here we
> +     pick up function statics that have been discovered by the call to
> +     analyze_functions() above.  */
> +  FOR_EACH_SYMBOL (snode)
> +    if (TREE_CODE (snode->decl) != FUNCTION_DECL
> +	&& DECL_CONTEXT (snode->decl)
> +	/* Anything who's context is not a TRANSLATION_UNIT_DECL will
> +	   be handled by either handling reachable functions below, or
> +	   by generating DIEs for types.  */
> +	&& TREE_CODE (DECL_CONTEXT (snode->decl)) == TRANSLATION_UNIT_DECL)

The comment says this catches "function statics", by which I assume you 
mean static local variables, but then you check for TU context, so what 
does this actually do?

> +  // ?? Do we need this?
>    /* Emit debug info for namespace alias.  */
>    if (!building_stmt_list_p ())
>      (*debug_hooks->early_global_decl) (alias);

Well, it isn't a symbol, so it won't be caught by 
finalize_compilation_unit.  So we either need to handle it here or in 
emit_debug_for_namespace.

Jason
diff mbox

Patch

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d1e1f74..7e1305c 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10657,10 +10657,7 @@  c_write_global_declarations_1 (tree globals)
      here, and start the TV_PHASE_DBGINFO timer.  Is it worth it, or
      would it convolute things?  */
   for (decl = globals; decl; decl = DECL_CHAIN (decl))
-    {
-      check_global_declaration_1 (decl);
-      debug_hooks->early_global_decl (decl);
-    }
+    check_global_declaration_1 (decl);
   /* ?? Similarly here. Stop TV_PHASE_DBGINFO and start
      TV_PHASE_DEFERRED again.  */
 }
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index fed1a3e..92756d1 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -2326,16 +2326,57 @@  symbol_table::finalize_compilation_unit (void)
   if (flag_dump_passes)
     dump_passes ();
 
+  /* Unfortunately, we need to iterate through the symbols twice to
+     generate early debug information for them.  Once to pick up
+     global statics that may be (later) removed by the reachability
+     code.  And once more, after build_cgraph_edges() discovers
+     static symbols hidden within functions.  */
+  symtab_node *snode;
+  FOR_EACH_SYMBOL (snode)
+    if (TREE_CODE (snode->decl) != FUNCTION_DECL
+	&& DECL_CONTEXT (snode->decl)
+	/* Anything who's context is not a TRANSLATION_UNIT_DECL will
+	   be handled by either handling reachable functions below, or
+	   by generating DIEs for types.  */
+	&& TREE_CODE (DECL_CONTEXT (snode->decl)) == TRANSLATION_UNIT_DECL)
+      (*debug_hooks->early_global_decl) (snode->decl);
+
   /* Gimplify and lower all functions, compute reachability and
      remove unreachable nodes.  */
   analyze_functions ();
 
+  /* This is the second iteration through the global symbols.  Here we
+     pick up function statics that have been discovered by the call to
+     analyze_functions() above.  */
+  FOR_EACH_SYMBOL (snode)
+    if (TREE_CODE (snode->decl) != FUNCTION_DECL
+	&& DECL_CONTEXT (snode->decl)
+	/* Anything who's context is not a TRANSLATION_UNIT_DECL will
+	   be handled by either handling reachable functions below, or
+	   by generating DIEs for types.  */
+	&& TREE_CODE (DECL_CONTEXT (snode->decl)) == TRANSLATION_UNIT_DECL)
+      (*debug_hooks->early_global_decl) (snode->decl);
+
   /* Mark alias targets necessary and emit diagnostics.  */
   handle_alias_pairs ();
 
   /* Gimplify and lower thunks.  */
   analyze_functions ();
 
+  /* Emit early debug for reachable functions.  */
+  struct cgraph_node *cnode;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+    if (DECL_CONTEXT (cnode->decl)
+	/* Anything who's context is not a TRANSLATION_UNIT_DECL will
+	   be handled by generating DIEs for types (or declaring
+	   things in their namespace).  */
+	&& TREE_CODE (DECL_CONTEXT (cnode->decl)) == TRANSLATION_UNIT_DECL)
+      (*debug_hooks->early_global_decl) (cnode->decl);
+
+  /* Clean up anything that needs cleaning up after initial debug
+     generation.  */
+  (*debug_hooks->early_finish) ();
+
   /* Finally drive the pass manager.  */
   compile ();
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 691688b..96740e8e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4333,11 +4333,10 @@  dump_tu (void)
     }
 }
 
-/* Issue warnings for globals in NAME_SPACE (unused statics, etc) and
-   generate debug information for said globals.  */
+/* Issue warnings for globals in NAME_SPACE (unused statics, etc).  */
 
 static int
-emit_debug_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
+check_statics_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
 {
   cp_binding_level *level = NAMESPACE_LEVEL (name_space);
   vec<tree, va_gc> *statics = level->static_decls;
@@ -4346,9 +4345,6 @@  emit_debug_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
 
   check_global_declarations (vec, len);
 
-  for (tree t = level->names; t; t = TREE_CHAIN(t))
-    debug_hooks->early_global_decl (t);
-
   return 0;
 }
 
@@ -4737,15 +4733,10 @@  c_parse_final_cleanups (void)
      generate initial debug information.  */
   timevar_stop (TV_PHASE_PARSING);
   timevar_start (TV_PHASE_DBGINFO);
-  walk_namespaces (emit_debug_for_namespace, 0);
+  walk_namespaces (check_statics_for_namespace, 0);
   if (vec_safe_length (pending_statics) != 0)
-    {
-      check_global_declarations (pending_statics->address (),
-				 pending_statics->length ());
-      emit_debug_global_declarations (pending_statics->address (),
-				      pending_statics->length (),
-				      EMIT_DEBUG_EARLY);
-    }
+    check_global_declarations (pending_statics->address (),
+			       pending_statics->length ());
 
   perform_deferred_noexcept_checks ();
 
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index dcdf292..0256db6 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3860,6 +3860,7 @@  do_namespace_alias (tree alias, tree name_space)
   DECL_CONTEXT (alias) = FROB_CONTEXT (current_scope ());
   pushdecl (alias);
 
+  // ?? Do we need this?
   /* Emit debug info for namespace alias.  */
   if (!building_stmt_list_p ())
     (*debug_hooks->early_global_decl) (alias);
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 430a2eb..202ef8a 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -359,6 +359,7 @@  const struct gcc_debug_hooks dbx_debug_hooks =
   dbxout_init,
   dbxout_finish,
   debug_nothing_void,
+  debug_nothing_void,
   debug_nothing_int_charstar,
   debug_nothing_int_charstar,
   dbxout_start_source_file,
@@ -400,6 +401,7 @@  const struct gcc_debug_hooks xcoff_debug_hooks =
   dbxout_init,
   dbxout_finish,
   debug_nothing_void,
+  debug_nothing_void,
   debug_nothing_int_charstar,
   debug_nothing_int_charstar,
   dbxout_start_source_file,
diff --git a/gcc/debug.c b/gcc/debug.c
index 449d3a1..d0e00c0 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -27,6 +27,7 @@  const struct gcc_debug_hooks do_nothing_debug_hooks =
 {
   debug_nothing_charstar,
   debug_nothing_charstar,
+  debug_nothing_void,			/* early_finish */
   debug_nothing_void,
   debug_nothing_int_charstar,
   debug_nothing_int_charstar,
diff --git a/gcc/debug.h b/gcc/debug.h
index f9485bc..a8d3f23 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -30,6 +30,9 @@  struct gcc_debug_hooks
   /* Output debug symbols.  */
   void (* finish) (const char *main_filename);
 
+  /* Run cleanups necessary after early debug generation.  */
+  void (* early_finish) (void);
+
   /* Called from cgraph_optimize before starting to assemble
      functions/variables/toplevel asms.  */
   void (* assembly_start) (void);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 33738d9..f342fb4 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -106,6 +106,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "gdb/gdb-index.h"
 #include "rtl-iter.h"
+#include "print-tree.h"
 
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
 static rtx_insn *last_var_location_insn;
@@ -2424,6 +2425,7 @@  build_cfa_aligned_loc (dw_cfa_location *cfa,
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
+static void dwarf2out_early_finish (void);
 static void dwarf2out_assembly_start (void);
 static void dwarf2out_define (unsigned int, const char *);
 static void dwarf2out_undef (unsigned int, const char *);
@@ -2451,6 +2453,7 @@  const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_early_finish,
   dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
@@ -2611,6 +2614,9 @@  typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   int die_mark;
   unsigned int decl_id;
   enum dwarf_tag die_tag;
+  /* No one should depend on this, as it is a temporary debugging aid
+     to indicate the DECL for which this DIE was created for.  */
+  tree tmp_created_for;
   /* 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 */
@@ -4890,6 +4896,7 @@  new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
   dw_die_ref die = ggc_cleared_alloc<die_node> ();
 
   die->die_tag = tag_value;
+  die->tmp_created_for = t;
 
   if (early_dwarf_dumping)
     die->dumped_early = true;
@@ -4900,6 +4907,30 @@  new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
     {
       limbo_die_node *limbo_node;
 
+      /* No DIEs created after early dwarf should end up in limbo,
+	 because the limbo list should not persist past LTO
+	 streaming.  */
+      if (tag_value != DW_TAG_compile_unit
+	  && !early_dwarf_dumping
+	  /* Allow nested functions to live in limbo because they will
+	     only temporarily live there, as decls_for_scope will fix
+	     them up.  */
+	  && (TREE_CODE (t) != FUNCTION_DECL
+	      || !decl_function_context (t))
+	  /* FIXME: Allow types for now.  We are getting some internal
+	     template types from inlining (building libstdc++).
+	     Templates need to be looked at.  */
+	  && !TYPE_P (t)
+	  /* FIXME: Allow late limbo DIE creation for LTO, especially
+	     in the ltrans stage, but once we implement LTO dwarf
+	     streaming, we should remove this exception.  */
+	  && !in_lto_p)
+	{
+	  fprintf (stderr, "symbol ended up in limbo too late:");
+	  debug_generic_stmt (t);
+	  gcc_unreachable ();
+	}
+
       limbo_node = ggc_cleared_alloc<limbo_die_node> ();
       limbo_node->die = die;
       limbo_node->created_for = t;
@@ -5399,6 +5430,13 @@  print_die (dw_die_ref die, FILE *outfile)
 	fprintf (outfile, ": %s", name);
       fputc (')', outfile);
     }
+  if (die->tmp_created_for
+      && DECL_P (die->tmp_created_for)
+      && CODE_CONTAINS_STRUCT
+           (TREE_CODE (die->tmp_created_for), TS_DECL_WITH_VIS)
+      && DECL_ASSEMBLER_NAME_SET_P (die->tmp_created_for))
+    fprintf (outfile, "(mangle: %s)",
+	     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (die->tmp_created_for)));
   fputc ('\n', outfile);
   print_spaces (outfile);
   fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
@@ -18403,24 +18441,93 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
   tree origin = decl_ultimate_origin (decl);
   dw_die_ref subr_die;
   dw_die_ref old_die = lookup_decl_die (decl);
+
+  /* This function gets called multiple times for different stages of
+     the debug process.  For example, for func() in this code:
+
+	namespace S
+	{
+	  void func() { ... }
+	}
+
+     ...we get called 4 times.  Twice in early debug and twice in
+     late debug:
+
+     Early debug
+     -----------
+
+       1. Once while generating func() within the namespace.  This is
+          the declaration.  The declaration bit below is set, as the
+          context is the namespace.
+
+	  A new DIE will be generated with DW_AT_declaration set.
+
+       2. Once for func() itself.  This is the specification.  The
+          declaration bit below is clear as the context is the CU.
+
+	  We will use the cached DIE from (1) to create a new DIE with
+	  DW_AT_specification pointing to the declaration in (1).
+
+     Late debug via rest_of_handle_final()
+     -------------------------------------
+
+       3. Once generating func() within the namespace.  This is also the
+          declaration, as in (1), but this time we will early exit below
+          as we have a cached DIE and a declaration needs no additional
+          annotations (no locations), as the source declaration line
+          info is enough.
+
+       4. Once for func() itself.  As in (2), this is the specification,
+          but this time we will re-use the cached DIE, and just annotate
+          it with the location information that should now be available.
+
+     For something without namespaces, but with abstract instances, we
+     are also called a multiple times:
+
+        class Base
+	{
+	public:
+	  Base ();	  // constructor declaration (1)
+	};
+
+	Base::Base () { } // constructor specification (2)
+
+    Early debug
+    -----------
+
+       1. Once for the Base() constructor by virtue of it being a
+          member of the Base class.  This is done via
+          rest_of_type_compilation.
+
+	  This is a declaration, so a new DIE will be created with
+	  DW_AT_declaration.
+
+       2. Once for the Base() constructor definition, but this time
+          while generating the abstract instance of the base
+          constructor (__base_ctor) which is being generated via early
+          debug of reachable functions.
+
+	  Even though we have a cached version of the declaration (1),
+	  we will create a DW_AT_specification of the declaration DIE
+	  in (1).
+
+       3. Once for the __base_ctor itself, but this time, we generate
+          an DW_AT_abstract_origin version of the DW_AT_specification in
+	  (2).
+
+    Late debug via rest_of_handle_final
+    -----------------------------------
+
+       4. One final time for the __base_ctor (which will have a cached
+          DIE with DW_AT_abstract_origin created in (3).  This time,
+          we will just annotate the location information now
+          available.
+  */
   int declaration = (current_function_decl != decl
 		     || class_or_namespace_scope_p (context_die));
 
   premark_used_types (DECL_STRUCT_FUNCTION (decl));
 
-  /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
-     started to generate the abstract instance of an inline, decided to output
-     its containing class, and proceeded to emit the declaration of the inline
-     from the member list for the class.  If so, DECLARATION takes priority;
-     we'll get back to the abstract instance when done with the class.  */
-
-  /* The class-scope declaration DIE must be the primary DIE.  */
-  if (origin && declaration && class_or_namespace_scope_p (context_die))
-    {
-      origin = NULL;
-      gcc_assert (!old_die);
-    }
-
   /* Now that the C++ front end lazily declares artificial member fns, we
      might need to retrofit the declaration into its class.  */
   if (!declaration && !origin && !old_die
@@ -18440,14 +18547,23 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
       if (old_die && old_die->die_parent == NULL)
 	add_child_die (context_die, old_die);
 
-      subr_die = new_die (DW_TAG_subprogram, context_die, decl);
-      add_abstract_origin_attribute (subr_die, origin);
-      /*  This is where the actual code for a cloned function is.
-	  Let's emit linkage name attribute for it.  This helps
-	  debuggers to e.g, set breakpoints into
-	  constructors/destructors when the user asks "break
-	  K::K".  */
-      add_linkage_name (subr_die, decl);
+      if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+	{
+	  /* If we have a DW_AT_abstract_origin we have a working
+	     cached version.  */
+	  subr_die = old_die;
+	}
+      else
+	{
+	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+	  add_abstract_origin_attribute (subr_die, origin);
+	  /*  This is where the actual code for a cloned function is.
+	      Let's emit linkage name attribute for it.  This helps
+	      debuggers to e.g, set breakpoints into
+	      constructors/destructors when the user asks "break
+	      K::K".  */
+	  add_linkage_name (subr_die, decl);
+	}
     }
   /* A cached copy, possibly from early dwarf generation.  Reuse as
      much as possible.  */
@@ -18496,24 +18612,13 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  subr_die = old_die;
 
-	  /* ??? Hmmm, early dwarf generation happened earlier, so no
-	     sense in removing the parameters.  Let's keep them and
-	     augment them with location information later.  */
-#if 0
-	  /* Clear out the declaration attribute and the formal parameters.
-	     Do not remove all children, because it is possible that this
-	     declaration die was forced using force_decl_die(). In such
-	     cases die that forced declaration die (e.g. TAG_imported_module)
-	     is one of the children that we do not want to remove.  */
-	  remove_AT (subr_die, DW_AT_declaration);
-	  remove_AT (subr_die, DW_AT_object_pointer);
-	  remove_child_TAG (subr_die, DW_TAG_formal_parameter);
-#else
-	  /* We don't need the DW_AT_declaration the second or third
-	     time around anyhow.  */
+	  /* Clear out the declaration attribute, but leave the
+	     parameters so they can be augmented with location
+	     information later.  */
 	  remove_AT (subr_die, DW_AT_declaration);
-#endif
 	}
+      /* Make a specification pointing to the previously built
+	 declaration.  */
       else
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -21318,8 +21423,24 @@  dwarf2out_late_global_decl (tree decl)
 static void
 dwarf2out_type_decl (tree decl, int local)
 {
+  /* ?? Technically, we shouldn't need this hook at all, as all
+     symbols (and by consequence their types) will be outputed from
+     finalize_compilation_unit.  However,
+     dwarf2out_imported_module_or_decl_1() needs FIELD_DECLs belonging
+     to a type to be previously available (at_import_die).
+
+     For now, output DIEs for types here, but eventually we should
+     beat dwarf2out_imported_module_or_decl_1 into submission (either
+     by calling it after early debug has run in
+     finalize_compilation_unit(), or by lazily creating the FIELD_DECL
+     DIEs from within dwarf2out_imported_module_or_decl_1.  */
   if (!local)
-    dwarf2out_decl (decl);
+    {
+      bool t = early_dwarf_dumping;
+      early_dwarf_dumping = true;
+      dwarf2out_decl (decl);
+      early_dwarf_dumping = t;
+    }
 }
 
 /* Output debug information for imported module or decl DECL.
@@ -21636,7 +21757,10 @@  dwarf2out_decl (tree decl)
   /* If we early created a DIE, make sure it didn't get re-created by
      mistake.  */
   if (early_die && early_die->dumped_early)
-    gcc_assert (early_die == die);
+    gcc_assert (early_die == die
+		/* We can have a differing DIE if and only if, the
+		   new one is a specification of the old one.  */
+		|| get_AT_ref (die, DW_AT_specification) == early_die);
 #endif
   return die;
 }
@@ -21733,6 +21857,9 @@  lookup_filename (const char *file_name)
 {
   struct dwarf_file_data * created;
 
+  if (!file_name)
+    return NULL;
+
   dwarf_file_data **slot
     = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
 				       INSERT);
@@ -24726,10 +24853,20 @@  optimize_location_lists (dw_die_ref die)
 static void
 dwarf2out_finish (const char *filename)
 {
-  limbo_die_node *node, *next_node;
   comdat_type_node *ctnode;
   dw_die_ref main_comp_unit_die;
 
+  /* 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
+     list this late.  */
+  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+    gcc_assert (node->die->die_tag == DW_TAG_compile_unit
+		|| !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.  */
@@ -24754,55 +24891,6 @@  dwarf2out_finish (const char *filename)
 	add_comp_dir_attribute (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.
-     For concrete instances, we can get the parent die from the abstract
-     instance.  */
-  for (node = limbo_die_list; node; node = next_node)
-    {
-      dw_die_ref die = node->die;
-      next_node = node->next;
-
-      if (die->die_parent == NULL)
-	{
-	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
-
-	  if (origin && origin->die_parent)
-	    add_child_die (origin->die_parent, die);
-	  else if (is_cu_die (die))
-	    ;
-	  else if (seen_error ())
-	    /* It's OK to be confused by errors in the input.  */
-	    add_child_die (comp_unit_die (), die);
-	  else
-	    {
-	      /* In certain situations, the lexical block containing a
-		 nested function can be optimized away, which results
-		 in the nested function die being orphaned.  Likewise
-		 with the return type of that nested function.  Force
-		 this to be a child of the containing function.
-
-		 It may happen that even the containing function got fully
-		 inlined and optimized out.  In that case we are lost and
-		 assign the empty child.  This should not be big issue as
-		 the function is likely unreachable too.  */
-	      gcc_assert (node->created_for);
-
-	      if (DECL_P (node->created_for))
-		origin = get_context_die (DECL_CONTEXT (node->created_for));
-	      else if (TYPE_P (node->created_for))
-		origin = scope_die_for (node->created_for, comp_unit_die ());
-	      else
-		origin = comp_unit_die ();
-
-	      add_child_die (origin, die);
-	    }
-	}
-    }
-
-  limbo_die_list = NULL;
-
 #if ENABLE_ASSERT_CHECKING
   {
     dw_die_ref die = comp_unit_die (), c;
@@ -24850,6 +24938,7 @@  dwarf2out_finish (const char *filename)
   /* Traverse the DIE's and add add sibling attributes to those DIE's
      that have children.  */
   add_sibling_attributes (comp_unit_die ());
+  limbo_die_node *node;
   for (node = limbo_die_list; node; node = node->next)
     add_sibling_attributes (node->die);
   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
@@ -25111,6 +25200,66 @@  dwarf2out_finish (const char *filename)
     output_indirect_strings ();
 }
 
+/* Perform any cleanups needed after the early debug generation pass
+   has run.  */
+
+static void
+dwarf2out_early_finish (void)
+{
+  /* 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.
+     For concrete instances, we can get the parent die from the abstract
+     instance.
+
+     The point here is to flush out the limbo list so that it is empty
+     and we don't need to stream it for LTO.  */
+  limbo_die_node *node, *next_node;
+  for (node = limbo_die_list; node; node = next_node)
+    {
+      dw_die_ref die = node->die;
+      next_node = node->next;
+
+      if (die->die_parent == NULL)
+	{
+	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+	  if (origin && origin->die_parent)
+	    add_child_die (origin->die_parent, die);
+	  else if (is_cu_die (die))
+	    ;
+	  else if (seen_error ())
+	    /* It's OK to be confused by errors in the input.  */
+	    add_child_die (comp_unit_die (), die);
+	  else
+	    {
+	      /* In certain situations, the lexical block containing a
+		 nested function can be optimized away, which results
+		 in the nested function die being orphaned.  Likewise
+		 with the return type of that nested function.  Force
+		 this to be a child of the containing function.
+
+		 It may happen that even the containing function got fully
+		 inlined and optimized out.  In that case we are lost and
+		 assign the empty child.  This should not be big issue as
+		 the function is likely unreachable too.  */
+	      gcc_assert (node->created_for);
+
+	      if (DECL_P (node->created_for))
+		origin = get_context_die (DECL_CONTEXT (node->created_for));
+	      else if (TYPE_P (node->created_for))
+		origin = scope_die_for (node->created_for, comp_unit_die ());
+	      else
+		origin = comp_unit_die ();
+
+	      add_child_die (origin, die);
+	    }
+	}
+    }
+
+  limbo_die_list = NULL;
+}
+
 /* Reset all state within dwarf2out.c so that we can rerun the compiler
    within the same process.  For use by toplev::finalize.  */
 
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 3d217d4..4d41b4e 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -242,8 +242,7 @@  gfc_be_parse_file (void)
      diagnostics before gfc_finish().  */
   gfc_diagnostics_finish ();
 
-  /* Do the debug dance.  */
-  global_decl_processing_and_early_debug ();
+  global_decl_processing ();
 }
 
 
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 1fa3060..efd4cd4 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -4709,7 +4709,6 @@  gfc_emit_parameter_debug_info (gfc_symbol *sym)
 					      TREE_TYPE (decl),
 					      sym->attr.dimension,
 					      false, false);
-  debug_hooks->early_global_decl (decl);
 }
 
 
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 215c4e5..c9c50dd 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3000,8 +3000,6 @@  Gcc_backend::write_global_definitions(
 
   wrapup_global_declarations(defs, i);
 
-  emit_debug_global_declarations (defs, i, EMIT_DEBUG_EARLY);
-
   /* ?? Can we leave this call here, thus getting called before
      finalize_compilation_unit?
 
diff --git a/gcc/java/class.c b/gcc/java/class.c
index bea7720..3d84a57 100644
--- a/gcc/java/class.c
+++ b/gcc/java/class.c
@@ -116,10 +116,6 @@  static GTY(()) vec<tree, va_gc> *registered_class;
    currently being compiled.  */
 static GTY(()) tree this_classdollar;
 
-/* A list of static class fields.  This is to emit proper debug
-   info for them.  */
-vec<tree, va_gc> *pending_static_fields;
-
 /* Return the node that most closely represents the class whose name
    is IDENT.  Start the search from NODE (followed by its siblings).
    Return NULL if an appropriate node does not exist.  */
@@ -888,8 +884,6 @@  add_field (tree klass, tree name, tree field_type, int flags)
       /* Considered external unless we are compiling it into this
 	 object file.  */
       DECL_EXTERNAL (field) = (is_compiled_class (klass) != 2);
-      if (!DECL_EXTERNAL (field))
-	vec_safe_push (pending_static_fields, field);
     }
 
   return field;
diff --git a/gcc/java/decl.c b/gcc/java/decl.c
index fbd09a3..7f02b4e 100644
--- a/gcc/java/decl.c
+++ b/gcc/java/decl.c
@@ -1964,11 +1964,7 @@  java_mark_class_local (tree klass)
 
   for (t = TYPE_FIELDS (klass); t ; t = DECL_CHAIN (t))
     if (FIELD_STATIC (t))
-      {
-	if (DECL_EXTERNAL (t))
-	  vec_safe_push (pending_static_fields, t);
-	java_mark_decl_local (t);
-      }
+      java_mark_decl_local (t);
 
   for (t = TYPE_METHODS (klass); t ; t = DECL_CHAIN (t))
     if (!METHOD_ABSTRACT (t))
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index 4ea8feb..142661f 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -1194,8 +1194,6 @@  extern void rewrite_reflection_indexes (void *);
 
 int cxx_keyword_p (const char *name, int length);
 
-extern GTY(()) vec<tree, va_gc> *pending_static_fields;
-
 #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
 
 /* Access flags etc for a method (a FUNCTION_DECL): */
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index e163d03..a65c5c7 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -1993,12 +1993,8 @@  java_parse_file (void)
   java_emit_static_constructor ();
   gcc_assert (global_bindings_p ());
 
-  /* Do final processing on globals and emit early debug information.  */
-  tree *vec = vec_safe_address (pending_static_fields);
-  int len = vec_safe_length (pending_static_fields);
-  global_decl_processing_and_early_debug ();
-  emit_debug_global_declarations (vec, len, EMIT_DEBUG_EARLY);
-  vec_free (pending_static_fields);
+  /* Do final processing on globals.  */
+  global_decl_processing ();
 }
 
 
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 1c0edc1..c035490 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -306,12 +306,12 @@  lhd_decl_ok_for_sibcall (const_tree decl ATTRIBUTE_UNUSED)
   return true;
 }
 
-/* Generic global declaration processing and early debug generation.
-   This is meant to be called by the front-ends at the end of parsing.
-   C/C++ do their own thing, but other front-ends may call this.  */
+/* Generic global declaration processing.  This is meant to be called
+   by the front-ends at the end of parsing.  C/C++ do their own thing,
+   but other front-ends may call this.  */
 
 void
-global_decl_processing_and_early_debug (void)
+global_decl_processing (void)
 {
   tree globals, decl, *vec;
   int len, i;
@@ -336,10 +336,6 @@  global_decl_processing_and_early_debug (void)
   check_global_declarations (vec, len);
   timevar_stop (TV_PHASE_DEFERRED);
 
-  timevar_start (TV_PHASE_DBGINFO);
-  emit_debug_global_declarations (vec, len, EMIT_DEBUG_EARLY);
-  timevar_stop (TV_PHASE_DBGINFO);
-
   timevar_start (TV_PHASE_PARSING);
   free (vec);
 }
diff --git a/gcc/sdbout.c b/gcc/sdbout.c
index d7b2d6b..43b8cf2 100644
--- a/gcc/sdbout.c
+++ b/gcc/sdbout.c
@@ -279,6 +279,7 @@  const struct gcc_debug_hooks sdb_debug_hooks =
 {
   sdbout_init,			         /* init */
   sdbout_finish,		         /* finish */
+  debug_nothing_void,			 /* early_finish */
   debug_nothing_void,			 /* assembly_start */
   debug_nothing_int_charstar,	         /* define */
   debug_nothing_int_charstar,	         /* undef */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 42a2cdc..4897d57 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -538,13 +538,11 @@  check_global_declarations (tree *v, int len)
     check_global_declaration_1 (v[i]);
 }
 
-/* Emit debugging information for all global declarations in VEC.
-   WHEN is either EMIT_DEBUG_EARLY or EMIT_DEBUG_LATE depending on if
-   we are generating early debug (at the end of parsing), or the late
-   (post compilation) version.  */
+/* Emit late debugging information (post compilation) for all global
+   declarations in VEC.  */
 
 void
-emit_debug_global_declarations (tree *vec, int len, enum emit_debug when)
+emit_debug_global_declarations (tree *vec, int len)
 {
   int i;
 
@@ -554,14 +552,7 @@  emit_debug_global_declarations (tree *vec, int len, enum emit_debug when)
 
   timevar_push (TV_SYMOUT);
   for (i = 0; i < len; i++)
-    {
-      if (when == EMIT_DEBUG_EARLY)
-	debug_hooks->early_global_decl (vec[i]);
-      else if (when == EMIT_DEBUG_LATE)
-	debug_hooks->late_global_decl (vec[i]);
-      else
-	gcc_unreachable ();
-    }
+    debug_hooks->late_global_decl (vec[i]);
   timevar_pop (TV_SYMOUT);
 }
 
@@ -2136,6 +2127,21 @@  toplev::main (int argc, char **argv)
   if (version_flag)
     print_version (stderr, "");
 
+  /* FIXME: Temporary debugging aid to know which LTO phase we are in
+     without having to pass -v to the driver and all its verbosity.  */
+  if (0)
+    {
+      fprintf(stderr, "MAIN: cc1*\n");
+      if (flag_lto)
+	fprintf(stderr, "\tMAIN: flag_lto\n");
+      if (in_lto_p)
+	fprintf(stderr, "\tMAIN: in_lto_p\n");
+      if (flag_wpa)
+	fprintf(stderr, "\tMAIN: flag_wpa\n");
+      if (flag_ltrans)
+	fprintf(stderr, "\tMAIN: flag_ltrans\n");
+    }
+
   if (help_flag)
     print_plugins_help (stderr, "");
 
diff --git a/gcc/toplev.h b/gcc/toplev.h
index ce83539..5d40a4a 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -60,13 +60,9 @@  extern bool wrapup_global_declarations (tree *, int);
 extern void check_global_declaration_1 (tree);
 extern void check_global_declarations (tree *, int);
 
-enum emit_debug {
-  EMIT_DEBUG_EARLY,
-  EMIT_DEBUG_LATE
-};
-extern void emit_debug_global_declarations (tree *, int, enum emit_debug);
+extern void emit_debug_global_declarations (tree *, int);
 
-extern void global_decl_processing_and_early_debug (void);
+extern void global_decl_processing (void);
 
 extern void dump_memory_report (bool);
 extern void dump_profile_report (void);
diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
index 5cb66bc..6da48eb 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -179,6 +179,7 @@  static void vmsdbgout_abstract_function (tree);
 const struct gcc_debug_hooks vmsdbg_debug_hooks
 = {vmsdbgout_init,
    vmsdbgout_finish,
+   debug_nothing_void,
    vmsdbgout_assembly_start,
    vmsdbgout_define,
    vmsdbgout_undef,