diff mbox

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

Message ID 54CC1885.5010105@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez Jan. 30, 2015, 11:49 p.m. UTC
On 01/30/2015 02:04 PM, Jason Merrill wrote:
> On 01/30/2015 03:36 PM, Aldy Hernandez wrote:
>>   /* 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.  */
>
> This comment is out of date; in this case decl_ultimate_origin will
> return NULL_TREE, so origin is null, so we shouldn't need to deal with
> this here.
>
>> +  /* ?? We must not reset `origin', so C++ clones get a proper
>> +     DW_AT_abstract_origin tagged DIE further on.  */
>> +#if 0
>>    /* 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);
>>      }
>> +#endif
>
> So I think this block is unnecessary.

Sweet, removed.

>> Obviously, now we will get more DIEs than before (complete
>> constructors, base constructors, and what have yous).  Whereas
>> previously we only generated a DIE for the used ones.
>
> Hmm, that's unfortunate.
>
> What if we leave the clone skipping alone here and emit early debug
> about all reachable functions in
> symbol_table::finalize_compilation_unit, between analyze_functions() and
> compile()?

Now you're just messing with me :).

I'm not a huge fan of doing things so late, but in the interest of not 
having to clean things up later... I have implemented your suggestion, 
and in the process got rid of some code from the last revision that is 
no longer necessary.  I'm not saying it wasn't correct, it's just that 
some asserts were no longer triggered, etc, so no point in touching more 
things than I need to.

FYI, I am using FOR_EACH_FUNCTION_WITH_GIMPLE_BODY in 
symbol_table::finalize_compilation_unit() instead of 
FOR_EACH_DEFINED_FUNCTION because:

	- FOR_EACH_DEFINED_FUNCTION iterates through comp_ctor and base_ctor, 
whereas mainline is only iterating through base_ctor (i.e. more DIEs 
than expected).

	- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY iterates only through the 
base_ctor as in mainline.

	- I also tried FOR_EACH_DEFINED_FUNCTION with node->get_availability() 
 > AVAIL_INTERPOSABLE, but that also iterated through more ctors than 
mainline.

Though all approaches are better than doing it in gen_member_die():

       /* Don't include clones in the member list.  */
       if (DECL_ABSTRACT_ORIGIN (member))
	continue;

This approach was the worst, iterating through two base_ctors and 2 
comp_ctors.

How is this one?

Aldy

Comments

Jason Merrill Feb. 1, 2015, 6:22 a.m. UTC | #1
On 01/30/2015 06:49 PM, Aldy Hernandez wrote:
> +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
> +    if (DECL_ABSTRACT_ORIGIN (node->decl))

If we do this for all functions, not just those with 
DECL_ABSTRACT_ORIGIN set...

> +  /* FIXME: What does this do for templates?  I think we don't want to
> +     send a template off to early_global_decl, but rather walk through
> +     its specializations and emit them.  */
>    for (tree t = level->names; t; t = TREE_CHAIN(t))
>      debug_hooks->early_global_decl (t);

...could we drop this hunk?

Can we also call early_finish in finalize_compilation_unit, rather than 
in free_lang_data?

Jason
Richard Biener Feb. 1, 2015, 8:43 a.m. UTC | #2
On February 1, 2015 7:22:29 AM CET, Jason Merrill <jason@redhat.com> wrote:
>On 01/30/2015 06:49 PM, Aldy Hernandez wrote:
>> +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
>> +    if (DECL_ABSTRACT_ORIGIN (node->decl))
>
>If we do this for all functions, not just those with 
>DECL_ABSTRACT_ORIGIN set...
>
>> +  /* FIXME: What does this do for templates?  I think we don't want
>to
>> +     send a template off to early_global_decl, but rather walk
>through
>> +     its specializations and emit them.  */
>>    for (tree t = level->names; t; t = TREE_CHAIN(t))
>>      debug_hooks->early_global_decl (t);
>
>...could we drop this hunk?
>
>Can we also call early_finish in finalize_compilation_unit, rather than
>
>in free_lang_data?

That would be sweet indeed.

Richard.

>Jason
Aldy Hernandez Feb. 2, 2015, 3:15 a.m. UTC | #3
On 01/31/2015 10:22 PM, Jason Merrill wrote:
> On 01/30/2015 06:49 PM, Aldy Hernandez wrote:
>> +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
>> +    if (DECL_ABSTRACT_ORIGIN (node->decl))
>
> If we do this for all functions, not just those with
> DECL_ABSTRACT_ORIGIN set...
>
>> +  /* FIXME: What does this do for templates?  I think we don't want to
>> +     send a template off to early_global_decl, but rather walk through
>> +     its specializations and emit them.  */
>>    for (tree t = level->names; t; t = TREE_CHAIN(t))
>>      debug_hooks->early_global_decl (t);
>
> ...could we drop this hunk?

Well, we'd also have to output globals, which we're currently not doing 
in finalize_compilation_unit.  But if you're ok with generating early 
dwarf for functions as well as globals/statics from 
finalize_compilation_unit() then we could get rid of virtually every 
call to early_global_decl() from the front-ends.

So instead of FOR_EACH_*FUNCTION*, we could have:

+  symtab_node *node;
+  FOR_EACH_SYMBOL (node)
+  {
+    cgraph_node *cn = dyn_cast <cgraph_node *> (node);
+    /* Global symbols get early debug information regardless, but
+       functions need to be visible.  */
+    if (!cn || cn->has_gimple_body_p ())
+      (*debug_hooks->early_global_decl) (node->decl);
+  }

Is this what you have in mind, or did you want to handle globals separately?

Do keep in mind that the above snippet would have the side-effect of not 
creating debug information for optimized away global statics.  I assume 
this is intended or acceptable?

Thanks.
Aldy
Jason Merrill Feb. 2, 2015, 4:15 a.m. UTC | #4
On 02/01/2015 10:15 PM, Aldy Hernandez wrote:
> Well, we'd also have to output globals, which we're currently not doing
> in finalize_compilation_unit.  But if you're ok with generating early
> dwarf for functions as well as globals/statics from
> finalize_compilation_unit() then we could get rid of virtually every
> call to early_global_decl() from the front-ends.
>
> So instead of FOR_EACH_*FUNCTION*, we could have:
>
> +  symtab_node *node;
> +  FOR_EACH_SYMBOL (node)
> +  {
> +    cgraph_node *cn = dyn_cast <cgraph_node *> (node);
> +    /* Global symbols get early debug information regardless, but
> +       functions need to be visible.  */
> +    if (!cn || cn->has_gimple_body_p ())
> +      (*debug_hooks->early_global_decl) (node->decl);
> +  }
>
> Is this what you have in mind, or did you want to handle globals
> separately?
>
> Do keep in mind that the above snippet would have the side-effect of not
> creating debug information for optimized away global statics.  I assume
> this is intended or acceptable?

Hmm, I think we want to have debug info for variables that have been 
optimized out, certainly for constant variables where we don't care if 
it's emitted, we express the constant value in the debug info.  Maybe 
handle variables before the call to analyze_functions?

Jason
diff mbox

Patch

diff --git a/gcc/ChangeLog.debug-early b/gcc/ChangeLog.debug-early
index 282705f..bc374f5 100644
--- a/gcc/ChangeLog.debug-early
+++ b/gcc/ChangeLog.debug-early
@@ -1,5 +1,30 @@ 
 2015-01-27  Aldy Hernandez  <aldyh@redhat.com>
 
+	* cgraphunit.c (symbol_table::finalize_compilation_unit): Emit
+	early debug for clones.
+	* cp/decl2.c (emit_debug_for_namespace): Add FIXME note for
+	templates.
+	* dbxout.c (dbx_debug_hooks): Add early_finish field.
+	* sdbout.c (sdb_debug_hooks): Same.
+	* vmsdbgout.c (vmsdbg_debug_hooks): Same.
+	* debug.h (gcc_debug_hooks): Same.
+	* dwarf2out.c (dwarf2_debug_hooks): Same.
+	(new_die): Inhibit limbo dies unless generating early dwarf.
+	Set tmp_created_for field.
+	(gen_subprogram_die): Do not create a new DIE if we have an
+	old DIE and it has DW_AT_abstract_origin set.
+	Do not reset origin.
+	(struct die_struct): Add tmp_created_for field.
+	(optimize_location_lists): Abstract flushing of limbo list to...
+	(dwarf2out_early_finish): ...here. New function.
+	(print_die): Output tmp_created_for field.
+	(dwarf2out_abstract_function): Do not call recursively set
+	DECL_ABSTRACT_P if the parent was already an abstract.
+	* toplev.c (toplev::main): Add temporary debugging aid.
+	* tree.c (free_lang_data): Call debug_hooks->early_finish.
+
+2015-01-27  Aldy Hernandez  <aldyh@redhat.com>
+
 	* dwarf2out.c (file_table_last_lookup): Remove unset variable.
 	(lookup_filename): Remove file_table_last_lookup use.
 	(dwarf2out_c_finalize): Same.
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index fed1a3e..36e23a4 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -2336,6 +2336,19 @@  symbol_table::finalize_compilation_unit (void)
   /* Gimplify and lower thunks.  */
   analyze_functions ();
 
+  /* Emit early dwarf information for clones now that we know which
+     ones are actually needed.  This is especially useful for C++
+     clones which have been skipped in gen_member_die().  */
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+    if (DECL_ABSTRACT_ORIGIN (node->decl))
+      {
+	tree save_fndecl = current_function_decl;
+	current_function_decl = node->decl;
+	(*debug_hooks->early_global_decl) (current_function_decl);
+	current_function_decl = save_fndecl;
+      }
+
   /* Finally drive the pass manager.  */
   compile ();
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 691688b..70abc99 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4346,6 +4346,9 @@  emit_debug_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
 
   check_global_declarations (vec, len);
 
+  /* FIXME: What does this do for templates?  I think we don't want to
+     send a template off to early_global_decl, but rather walk through
+     its specializations and emit them.  */
   for (tree t = level->names; t; t = TREE_CHAIN(t))
     debug_hooks->early_global_decl (t);
 
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..1b2f696 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,12 @@  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))
+    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);
@@ -18274,9 +18311,10 @@  dwarf2out_abstract_function (tree decl)
   current_function_decl = decl;
 
   was_abstract = DECL_ABSTRACT_P (decl);
-  set_decl_abstract_flags (decl, 1);
+  if (!was_abstract)
+    set_decl_abstract_flags (decl, 1);
   dwarf2out_decl (decl);
-  if (! was_abstract)
+  if (!was_abstract)
     set_decl_abstract_flags (decl, 0);
 
   current_function_decl = save_fn;
@@ -18408,19 +18446,6 @@  gen_subprogram_die (tree decl, dw_die_ref 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 +18465,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.  */
@@ -24726,10 +24760,19 @@  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->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 +24797,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 +24844,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 +25106,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/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..6b58ed2 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -2136,6 +2136,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/tree.c b/gcc/tree.c
index 8743763..80b4287 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -5730,6 +5730,10 @@  free_lang_data (void)
 {
   unsigned i;
 
+  /* Clean up anything that needs cleaning up after initial debug
+     generation.  */
+  (*debug_hooks->early_finish) ();
+
   /* If we are the LTO frontend we have freed lang-specific data already.  */
   if (in_lto_p
       /* FIXME: Eventually we need to remove this so the function
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,