public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [debug-early] C++ clones and limbo DIEs
@ 2015-01-16  3:11 Aldy Hernandez
  2015-01-16  4:30 ` Jason Merrill
  0 siblings, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-16  3:11 UTC (permalink / raw)
  To: jason merrill; +Cc: Richard Biener, gcc-patches

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

Hi Jason.  Hi Richard.

While adjusting the limbdo_die_list for early debug I noticed we weren't 
early generating C++ constructors/destructors.  This got me on a detour 
of sorts.

I noticed dwarf2out's gen_member_die() disallows generation of clones 
earlier, by design:

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

I played around trying to disable this "feature", but my approach ran 
into various walls, and I decided instead to attack it from the 
front-end side. The attached patch generates early DIEs for the C++ 
clones in the C++ parser. I'd be (un)happy to revisit the dwarf2out 
approach if it's deemed more appropriate.

Now back to limbdo_die_list... My approach is to flush the limbo list, 
generically, after the front-ends have finished, by adding a new 
"early_finish" debug hook.  This gets rid of any permanence into LTO 
time.  Then I flush it out again, if the middle end (or LTO, etc) has 
added any limbo DIEs.  I wish we didn't need to flush the limbo list 
past the compilation proper, but some things like Cilk+ generate 
function trees way late in the game, so we end up generating limbo DIEs 
past where I'd like to.  Please see the comment in the source code.

All in all, this patch should get rid of any middle-end dependence on 
the early debug generated limbo DIEs.

Are you happy with this?  I'd like to get your input before committing 
to this approach.

Thanks.
Aldy

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 10736 bytes --]

commit cd20df2a48ce4f0d4e64626d61f8f61a810cf742
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Wed Jan 14 13:33:40 2015 -0800

    	* cp/decl2.c (c_parse_final_cleanups): Emit early debug
    	information for clones.
    	* dbxout.c (dbx_debug_hooks): Add early_finish field.
    	(xcoff_debug_hooks): Same.
    	* sdbout.c (sdb_debug_hooks): Same.
    	* vmsdbgout.c (vmsdbg_debug_hooks): Same.
    	* debug.c (do_nothing_debug_hooks): Same.
    	* debug.h (struct gcc_debug_hooks): Same.
    	* dwarf2out.c (dwarf2_debug_hooks): Same.
    	(dwarf2out_finish): Move limbo list handling to...
    	(dwarf2out_early_finish): ...here.
    	* toplev.c (compile_file): Call debug_hooks->early_finish.

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 691688b..b9a407a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4737,6 +4737,13 @@ c_parse_final_cleanups (void)
      generate initial debug information.  */
   timevar_stop (TV_PHASE_PARSING);
   timevar_start (TV_PHASE_DBGINFO);
+
+  /* Emit debug information for clones.  */
+  symtab_node *node;
+  FOR_EACH_DEFINED_SYMBOL (node)
+    if (DECL_ABSTRACT_ORIGIN (node->decl))
+      debug_hooks->early_global_decl (DECL_ABSTRACT_ORIGIN (node->decl));
+
   walk_namespaces (emit_debug_for_namespace, 0);
   if (vec_safe_length (pending_statics) != 0)
     {
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 e3ccda2..80d43af 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2424,6 +2424,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 +2452,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
 {
   dwarf2out_init,
   dwarf2out_finish,
+  dwarf2out_early_finish,
   dwarf2out_assembly_start,
   dwarf2out_define,
   dwarf2out_undef,
@@ -24739,10 +24741,27 @@ 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;
 
+  /* Technically limbo_die_list should either be empty because
+     dwarf2out_early_finish took care of everything, or should _only_
+     have inline instances that will be created late (which is OK,
+     because they'll be pointing to the early generated abstract).
+
+     However, functions can be created after the parsers are done
+     (e.g. create_cilk_helper_decl), which will populate the
+     limbo_die_list again.  Eventually all late function creation
+     should be banned, or these new functions should be created with a
+     proper context_die, thus avoiding limbo.  For now, it doesn't
+     hurt, since late creation should have all the location
+     information needed (and if it doesn't, we don't care-- the code
+     is undebuggable).
+
+     If there was anything created late, flush it out.  */
+  if (limbo_die_list)
+    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.  */
@@ -24767,55 +24786,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;
@@ -24860,9 +24830,10 @@ dwarf2out_finish (const char *filename)
   if (flag_eliminate_dwarf2_dups)
     break_out_includes (comp_unit_die ());
 
-  /* Traverse the DIE's and add add sibling attributes to those DIE's
+  /* Traverse the DIE's and 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)
@@ -25124,6 +25095,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..12fa509 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -586,6 +586,10 @@ compile_file (void)
   if (flag_syntax_only || flag_wpa)
     return;
 
+  /* Clean up anything that needs cleaning up after initial debug
+     generation.  */
+  (*debug_hooks->early_finish) ();
+
   ggc_protect_identifiers = false;
 
   /* Run the actual compilation process.  */
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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16  3:11 [debug-early] C++ clones and limbo DIEs Aldy Hernandez
@ 2015-01-16  4:30 ` Jason Merrill
  2015-01-16 11:03   ` Richard Biener
  2015-01-16 17:54   ` Aldy Hernandez
  0 siblings, 2 replies; 36+ messages in thread
From: Jason Merrill @ 2015-01-16  4:30 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

On 01/15/2015 09:58 PM, Aldy Hernandez wrote:
> The attached patch generates early DIEs for the C++
> clones in the C++ parser.

This strikes me as an unnecessary abstraction violation.

> +  /* Emit debug information for clones.  */
> +  symtab_node *node;
> +  FOR_EACH_DEFINED_SYMBOL (node)
> +    if (DECL_ABSTRACT_ORIGIN (node->decl))
> +      debug_hooks->early_global_decl (DECL_ABSTRACT_ORIGIN (node->decl));

And I note that you aren't even doing anything with the clone here, 
which suggests even more strongly that this is not what we want to do.

> Now back to limbdo_die_list... My approach is to flush the limbo list,
> generically, after the front-ends have finished, by adding a new
> "early_finish" debug hook.  This gets rid of any permanence into LTO
> time.  Then I flush it out again, if the middle end (or LTO, etc) has
> added any limbo DIEs.

Can you remove the first flush and just do it in the second place?

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16  4:30 ` Jason Merrill
@ 2015-01-16 11:03   ` Richard Biener
  2015-01-16 16:38     ` Jason Merrill
  2015-01-28 19:44     ` Aldy Hernandez
  2015-01-16 17:54   ` Aldy Hernandez
  1 sibling, 2 replies; 36+ messages in thread
From: Richard Biener @ 2015-01-16 11:03 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Aldy Hernandez, gcc-patches

On Fri, Jan 16, 2015 at 4:11 AM, Jason Merrill <jason@redhat.com> wrote:
> On 01/15/2015 09:58 PM, Aldy Hernandez wrote:
>>
>> The attached patch generates early DIEs for the C++
>> clones in the C++ parser.
>
>
> This strikes me as an unnecessary abstraction violation.

I'd hope that in the very distant future all early DIEs would be "created"
by the frontends (that is, dwarf2out.c wouldn't walk into parents/siblings
so much).

>> +  /* Emit debug information for clones.  */
>> +  symtab_node *node;
>> +  FOR_EACH_DEFINED_SYMBOL (node)
>> +    if (DECL_ABSTRACT_ORIGIN (node->decl))
>> +      debug_hooks->early_global_decl (DECL_ABSTRACT_ORIGIN (node->decl));
>
>
> And I note that you aren't even doing anything with the clone here, which
> suggests even more strongly that this is not what we want to do.

There must be a better place in the frontend to call early_global_decl
for those?  Maybe the point where we create the clone?

>> Now back to limbdo_die_list... My approach is to flush the limbo list,
>> generically, after the front-ends have finished, by adding a new
>> "early_finish" debug hook.  This gets rid of any permanence into LTO
>> time.  Then I flush it out again, if the middle end (or LTO, etc) has
>> added any limbo DIEs.
>
>
> Can you remove the first flush and just do it in the second place?

I hoped we wouldn't need the limbo list at all ... that is, parent DIEs
are always present when we create children.  I think that should
work in principle if the frontends would create DIEs while parsing.

Note that dwarf2out forces parent DIE creation in some cases
but not in some others - it would be interesting to sort out which
parent DIEs it thinks it cannot create when we create the DIE
for a sibling.  Maybe it's just poor ordering of early_global_decl
calls?

Richard.

> Jason
>

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16 11:03   ` Richard Biener
@ 2015-01-16 16:38     ` Jason Merrill
  2015-01-16 18:09       ` Aldy Hernandez
  2015-01-16 18:51       ` Richard Biener
  2015-01-28 19:44     ` Aldy Hernandez
  1 sibling, 2 replies; 36+ messages in thread
From: Jason Merrill @ 2015-01-16 16:38 UTC (permalink / raw)
  To: Richard Biener; +Cc: Aldy Hernandez, gcc-patches

On 01/16/2015 05:55 AM, Richard Biener wrote:
> I'd hope that in the very distant future all early DIEs would be "created"
> by the frontends (that is, dwarf2out.c wouldn't walk into parents/siblings
> so much).

Are you thinking that the front end would immediately call a debug hook 
for every block, local variable and such, or just for higher level entities?

> I hoped we wouldn't need the limbo list at all ... that is, parent DIEs
> are always present when we create children.  I think that should
> work in principle if the frontends would create DIEs while parsing.

So create the function DIE as soon as we see the declaration?  That 
seems reasonable.  Then that would be the point of early debug, not 
later at EOF.

> Note that dwarf2out forces parent DIE creation in some cases
> but not in some others - it would be interesting to sort out which
> parent DIEs it thinks it cannot create when we create the DIE
> for a sibling.  Maybe it's just poor ordering of early_global_decl
> calls?

Agreed.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16  4:30 ` Jason Merrill
  2015-01-16 11:03   ` Richard Biener
@ 2015-01-16 17:54   ` Aldy Hernandez
  2015-01-16 21:38     ` Jason Merrill
  1 sibling, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-16 17:54 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

On 01/15/2015 07:11 PM, Jason Merrill wrote:
> On 01/15/2015 09:58 PM, Aldy Hernandez wrote:

>> Now back to limbdo_die_list... My approach is to flush the limbo list,
>> generically, after the front-ends have finished, by adding a new
>> "early_finish" debug hook.  This gets rid of any permanence into LTO
>> time.  Then I flush it out again, if the middle end (or LTO, etc) has
>> added any limbo DIEs.
>
> Can you remove the first flush and just do it in the second place?

If I only flush the limbo list in the second place, that's basically 
what mainline does, albeit abstracted into a function.  I thought the 
whole point was to get rid of the limbo list, or at least keep it from 
being a structure that has to go through LTO streaming.

Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16 16:38     ` Jason Merrill
@ 2015-01-16 18:09       ` Aldy Hernandez
  2015-01-16 18:51       ` Richard Biener
  1 sibling, 0 replies; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-16 18:09 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener; +Cc: gcc-patches

On 01/16/2015 08:31 AM, Jason Merrill wrote:
> On 01/16/2015 05:55 AM, Richard Biener wrote:
>> I'd hope that in the very distant future all early DIEs would be
>> "created"
>> by the frontends (that is, dwarf2out.c wouldn't walk into
>> parents/siblings
>> so much).
>
> Are you thinking that the front end would immediately call a debug hook
> for every block, local variable and such, or just for higher level
> entities?

In the very distant future, as in, when Aldy is retired and living in a 
tropical island somewhere? :).

>
>> I hoped we wouldn't need the limbo list at all ... that is, parent DIEs
>> are always present when we create children.  I think that should
>> work in principle if the frontends would create DIEs while parsing.
>
> So create the function DIE as soon as we see the declaration?  That
> seems reasonable.  Then that would be the point of early debug, not
> later at EOF.

I'm certainly game to exploring this option, though I think we should be 
able to get this working at EOF.  The reason why I didn't take this 
approach originally is because it seemed like a lot more hassle, 
especially since we have to do the same thing for all other front-ends.

>
>> Note that dwarf2out forces parent DIE creation in some cases
>> but not in some others - it would be interesting to sort out which
>> parent DIEs it thinks it cannot create when we create the DIE
>> for a sibling.  Maybe it's just poor ordering of early_global_decl
>> calls?
>
> Agreed.

Regrettably, I have to agree as well.  I can investigate why some DIEs 
end up orphaned and report back.

Thanks.
Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16 16:38     ` Jason Merrill
  2015-01-16 18:09       ` Aldy Hernandez
@ 2015-01-16 18:51       ` Richard Biener
  1 sibling, 0 replies; 36+ messages in thread
From: Richard Biener @ 2015-01-16 18:51 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Aldy Hernandez, gcc-patches

On January 16, 2015 5:31:49 PM CET, Jason Merrill <jason@redhat.com> wrote:
>On 01/16/2015 05:55 AM, Richard Biener wrote:
>> I'd hope that in the very distant future all early DIEs would be
>"created"
>> by the frontends (that is, dwarf2out.c wouldn't walk into
>parents/siblings
>> so much).
>
>Are you thinking that the front end would immediately call a debug hook
>
>for every block, local variable and such, or just for higher level
>entities?

For every block, local variable and such.
Yes.  The FE then also has the chance to append whatever FE specific attributes without langhooks in dwarf2out.

>> I hoped we wouldn't need the limbo list at all ... that is, parent
>DIEs
>> are always present when we create children.  I think that should
>> work in principle if the frontends would create DIEs while parsing.
>
>So create the function DIE as soon as we see the declaration?  That 
>seems reasonable.  Then that would be the point of early debug, not 
>later at EOF.

Yes.

Richard.

>> Note that dwarf2out forces parent DIE creation in some cases
>> but not in some others - it would be interesting to sort out which
>> parent DIEs it thinks it cannot create when we create the DIE
>> for a sibling.  Maybe it's just poor ordering of early_global_decl
>> calls?
>
>Agreed.
>
>Jason


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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16 17:54   ` Aldy Hernandez
@ 2015-01-16 21:38     ` Jason Merrill
  2015-01-23 19:53       ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-01-16 21:38 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

On 01/16/2015 12:50 PM, Aldy Hernandez wrote:
>> Can you remove the first flush and just do it in the second place?
>
> If I only flush the limbo list in the second place, that's basically
> what mainline does, albeit abstracted into a function.  I thought the
> whole point was to get rid of the limbo list, or at least keep it from
> being a structure that has to go through LTO streaming.

It would expect it to be before free_lang_data and LTO streaming.

Jason


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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16 21:38     ` Jason Merrill
@ 2015-01-23 19:53       ` Aldy Hernandez
  2015-01-26  9:21         ` Richard Biener
  2015-01-27 22:33         ` Jason Merrill
  0 siblings, 2 replies; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-23 19:53 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

Phew... ok, I'm a little stuck here with the interaction between 
dwarf2out and LTO, and I'm hoping y'all can shed some light.  Please 
bear with me through the verbosity, it gets clearer (I hope) near the end.

On 01/16/2015 12:45 PM, Jason Merrill wrote:
> On 01/16/2015 12:50 PM, Aldy Hernandez wrote:
>>> Can you remove the first flush and just do it in the second place?
>>
>> If I only flush the limbo list in the second place, that's basically
>> what mainline does, albeit abstracted into a function.  I thought the
>> whole point was to get rid of the limbo list, or at least keep it from
>> being a structure that has to go through LTO streaming.
>
> It would expect it to be before free_lang_data and LTO streaming.

The reason this wouldn't make a difference is because, as it stands, 
dwarf for the clones are not generated until final.c:

   if (!DECL_IGNORED_P (current_function_decl))
     debug_hooks->function_decl (current_function_decl);

which happens after free_lang_data.

However, we can generate early dwarf for the clones right from the 
parser, and things _mostly_ work:

diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index 62e32d2..5539244 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -539,6 +539,11 @@ maybe_clone_body (tree fn)
        /* Start processing the function.  */
        start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);

+      /* Generate early dwarf for the clone now that we have a body
+	 for it.  */
+	debug_hooks->early_global_decl (clone);
+
        /* Tell cgraph if both ctors or both dtors are known to have
  	 the same body.  */
        if (can_alias

And I say _mostly_ work, because now local statics will have the 
DECL_ABSTRACT_P bit set, making LTO think that things live in another 
partition, and are no longer trivially needed.  For instance:

struct TYPE { TYPE (int);  } ;

TYPE::TYPE (int some_argument)
{
   static int static_p = 5;
}

With the above patch, early dwarf generation will call gen_decl_die, 
which eventually does:

       /* If we're emitting a clone, emit info for the abstract 
instance.  */
       if (origin || DECL_ORIGIN (decl) != decl)
	dwarf2out_abstract_function (origin
				     ? DECL_ORIGIN (origin)
				     : DECL_ABSTRACT_ORIGIN (decl));

Where decl and DECL_ABSTRACT_ORIGIN(decl) are:
(gdb) p decl
$87 = <function_decl 0x7ffff030f0d8 __base_ctor >
(gdb) p decl.decl_common.abstract_origin
$88 = <function_decl 0x7ffff02fbe58 TYPE>

Now dwarf2out_abstract_function() will set DECL_ABSTRACT_P for all the 
children of the abstract origin:

   was_abstract = DECL_ABSTRACT_P (decl);
   set_decl_abstract_flags (decl, 1);
   dwarf2out_decl (decl);
   if (! was_abstract)
     set_decl_abstract_flags (decl, 0);

Unfortunately, this sets DECL_ABSTRACT_P for the "static_p" above, and 
refuses to unset it after the call to dwarf2out_decl.

Through some miraculous gymnastics, LTO streams out symbols without the 
"analyzed" bit set if things are not "in partition", which happens 
because symtab_node::get_partitioning_class() returns SYMBOL_EXTERNAL 
(ahem, not in partition) when the DECL_ABSTRACT_P bit is set.

So... dwarf2out_abstract_function() sets the DECL_ABSTRACT_P bit, and 
LTO thinks that local statics in a clone are in another partition, which 
causes the analyzed bit to be dropped on the floor, which causes 
symbol_table::remove_unreferenced_decls() to no longer think that local 
statics are trivially needed.  And if the local static is no longer 
needed, varpool will not output its definition in the assembly file.

I am very uncomfortable with a call to dwarf2out_abstract_function() 
changing the behavior of the LTO streamer (and the optimizers), but it 
looks like twiddling the DECL_ABSTRACT_P flag (and refusing to reset it) 
is by design.

I am all ears on solutions on either the LTO or the dwarf side.

Thanks.
Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-23 19:53       ` Aldy Hernandez
@ 2015-01-26  9:21         ` Richard Biener
  2015-01-27 22:33         ` Jason Merrill
  1 sibling, 0 replies; 36+ messages in thread
From: Richard Biener @ 2015-01-26  9:21 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jason Merrill, gcc-patches, Jan Hubicka

On Fri, Jan 23, 2015 at 7:45 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> Phew... ok, I'm a little stuck here with the interaction between dwarf2out
> and LTO, and I'm hoping y'all can shed some light.  Please bear with me
> through the verbosity, it gets clearer (I hope) near the end.
>
>
> On 01/16/2015 12:45 PM, Jason Merrill wrote:
>>
>> On 01/16/2015 12:50 PM, Aldy Hernandez wrote:
>>>>
>>>> Can you remove the first flush and just do it in the second place?
>>>
>>>
>>> If I only flush the limbo list in the second place, that's basically
>>> what mainline does, albeit abstracted into a function.  I thought the
>>> whole point was to get rid of the limbo list, or at least keep it from
>>> being a structure that has to go through LTO streaming.
>>
>>
>> It would expect it to be before free_lang_data and LTO streaming.
>
>
> The reason this wouldn't make a difference is because, as it stands, dwarf
> for the clones are not generated until final.c:
>
>   if (!DECL_IGNORED_P (current_function_decl))
>     debug_hooks->function_decl (current_function_decl);
>
> which happens after free_lang_data.
>
> However, we can generate early dwarf for the clones right from the parser,
> and things _mostly_ work:

I think that is the correct thing to do.

> diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
> index 62e32d2..5539244 100644
> --- a/gcc/cp/optimize.c
> +++ b/gcc/cp/optimize.c
> @@ -539,6 +539,11 @@ maybe_clone_body (tree fn)
>        /* Start processing the function.  */
>        start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
>
> +      /* Generate early dwarf for the clone now that we have a body
> +        for it.  */
> +       debug_hooks->early_global_decl (clone);
> +
>        /* Tell cgraph if both ctors or both dtors are known to have
>          the same body.  */
>        if (can_alias
>
> And I say _mostly_ work, because now local statics will have the
> DECL_ABSTRACT_P bit set, making LTO think that things live in another
> partition, and are no longer trivially needed.  For instance:
>
> struct TYPE { TYPE (int);  } ;
>
> TYPE::TYPE (int some_argument)
> {
>   static int static_p = 5;
> }
>
> With the above patch, early dwarf generation will call gen_decl_die, which
> eventually does:
>
>       /* If we're emitting a clone, emit info for the abstract instance.  */
>       if (origin || DECL_ORIGIN (decl) != decl)
>         dwarf2out_abstract_function (origin
>                                      ? DECL_ORIGIN (origin)
>                                      : DECL_ABSTRACT_ORIGIN (decl));
>
> Where decl and DECL_ABSTRACT_ORIGIN(decl) are:
> (gdb) p decl
> $87 = <function_decl 0x7ffff030f0d8 __base_ctor >
> (gdb) p decl.decl_common.abstract_origin
> $88 = <function_decl 0x7ffff02fbe58 TYPE>
>
> Now dwarf2out_abstract_function() will set DECL_ABSTRACT_P for all the
> children of the abstract origin:
>
>   was_abstract = DECL_ABSTRACT_P (decl);
>   set_decl_abstract_flags (decl, 1);
>   dwarf2out_decl (decl);
>   if (! was_abstract)
>     set_decl_abstract_flags (decl, 0);
>
> Unfortunately, this sets DECL_ABSTRACT_P for the "static_p" above, and
> refuses to unset it after the call to dwarf2out_decl.

I think the C++ FE does sth odd here by having an abstract origin that
is not abstract (If I understand you correctly here).  That is, the dwarf2out.c
code above should be able to do

  gcc_assert (was_abstract);

instead of setting abstract flags here.  Otherwise the abstract origin
wasn't and abstract origin.

Or I am completely missing something - which means LTO is wrong
to interpret DECL_ABSTRACT as it does:

/* Nonzero for a given ..._DECL node means that this node represents an
   "abstract instance" of the given declaration (e.g. in the original
   declaration of an inline function).  When generating symbolic debugging
   information, we mustn't try to generate any address information for nodes
   marked as "abstract instances" because we don't actually generate
   any code or allocate any data space for such instances.  */
#define DECL_ABSTRACT_P(NODE) \
  (DECL_COMMON_CHECK (NODE)->decl_common.abstract_flag)

The above suggests LTO is correct in not outputting the decl.

So it is either the C++ FE that is wrong in declaring this an abstract origin
or dwarf2out.c is wrong in simply making all abstract origins (and its chilren)
abstract because being an abstract origin doesn't require being abstract.

Jason?

> Through some miraculous gymnastics, LTO streams out symbols without the
> "analyzed" bit set if things are not "in partition", which happens because
> symtab_node::get_partitioning_class() returns SYMBOL_EXTERNAL (ahem, not in
> partition) when the DECL_ABSTRACT_P bit is set.
>
> So... dwarf2out_abstract_function() sets the DECL_ABSTRACT_P bit, and LTO
> thinks that local statics in a clone are in another partition, which causes
> the analyzed bit to be dropped on the floor, which causes
> symbol_table::remove_unreferenced_decls() to no longer think that local
> statics are trivially needed.  And if the local static is no longer needed,
> varpool will not output its definition in the assembly file.
>
> I am very uncomfortable with a call to dwarf2out_abstract_function()
> changing the behavior of the LTO streamer (and the optimizers), but it looks
> like twiddling the DECL_ABSTRACT_P flag (and refusing to reset it) is by
> design.
>
> I am all ears on solutions on either the LTO or the dwarf side.
>
> Thanks.
> Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-23 19:53       ` Aldy Hernandez
  2015-01-26  9:21         ` Richard Biener
@ 2015-01-27 22:33         ` Jason Merrill
  2015-01-28 19:24           ` Aldy Hernandez
  1 sibling, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-01-27 22:33 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

On 01/23/2015 01:45 PM, Aldy Hernandez wrote:
>> It would expect [the flush] to be before free_lang_data and LTO streaming.
>
> The reason this wouldn't make a difference is because, as it stands,
> dwarf for the clones are not generated until final.c:
>
>    if (!DECL_IGNORED_P (current_function_decl))
>      debug_hooks->function_decl (current_function_decl);
>
> which happens after free_lang_data.

I agree that the current code doesn't have this effect, but we're 
talking about changing things, right? :)

> Unfortunately, this sets DECL_ABSTRACT_P for the "static_p" above, and
> refuses to unset it after the call to dwarf2out_decl.

Well, that sounds like a bug.  Why isn't it being unset?  Is it because 
DECL_ABSTRACT_P was already set for the function, so we don't call 
set_decl_abstract_flags (decl, 0)?  Perhaps a solution to that would be 
to avoid calling set_decl_abstract_flags (decl, 1) if the function is 
already marked as abstract.  Or to teach set_decl_abstract_flags not to 
mess with static local variables.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-27 22:33         ` Jason Merrill
@ 2015-01-28 19:24           ` Aldy Hernandez
  2015-01-28 19:32             ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-28 19:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

On 01/27/2015 12:51 PM, Jason Merrill wrote:
> On 01/23/2015 01:45 PM, Aldy Hernandez wrote:
>>> It would expect [the flush] to be before free_lang_data and LTO
>>> streaming.
>>
>> The reason this wouldn't make a difference is because, as it stands,
>> dwarf for the clones are not generated until final.c:
>>
>>    if (!DECL_IGNORED_P (current_function_decl))
>>      debug_hooks->function_decl (current_function_decl);
>>
>> which happens after free_lang_data.
>
> I agree that the current code doesn't have this effect, but we're
> talking about changing things, right? :)

Oh, my bad.  I completely misread your original comment.  Yes, yes... we 
can move the flushing of the limbo list to free_lang_data.  See attached 
patch.

>
>> Unfortunately, this sets DECL_ABSTRACT_P for the "static_p" above, and
>> refuses to unset it after the call to dwarf2out_decl.
>
> Well, that sounds like a bug.  Why isn't it being unset?  Is it because
> DECL_ABSTRACT_P was already set for the function, so we don't call
> set_decl_abstract_flags (decl, 0)?  Perhaps a solution to that would be
> to avoid calling set_decl_abstract_flags (decl, 1) if the function is
> already marked as abstract.  Or to teach set_decl_abstract_flags not to
> mess with static local variables.

Its' being unset because DECL_ABSTRACT_P was already set.  I propose we 
avoid calling set_decl_abstract_flags() for this scenario, as you 
suggest, and if this causes any problems, look into your second approach.

The attached patch gets rid of our limbo dependency past LTO streaming 
by flushing it out early, and adding some sanity checks throughout.

Cilk required some special handholding.  It seems to be the only culprit 
of late FUNCTION_DECL creation.

Now that we call dwarf2out_decl() for clones early on, I had to adjust 
gen_subprogram_die() to make sure we're not duplicating work and 
creating a new DIE if we already have on with DW_AT_abstract_origin.

I also kept lookup_filename() uses from ICEing now that we hit this code 
path.  It shouldn't affect other code paths (since it was ICEing before 
;-)).

With the attached patch we take care of C++ clones early, and get rid of 
our dependence on the limbo DIE list into LTO land.  No guality regressions.

Are we all in agreement with this approach?

Thanks for everyone's help BTW.
Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-28 19:24           ` Aldy Hernandez
@ 2015-01-28 19:32             ` Aldy Hernandez
  2015-01-28 19:47               ` Jason Merrill
  0 siblings, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-28 19:32 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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

And now with the actual patch ;-).

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 15969 bytes --]

	* c-family/cilk.c (create_cilk_wrapper_body): Emit debug
	information for wrappers.
	* cp/decl2.c (emit_debug_for_namespace): Add FIXME note for
	templates.
	* cp/optimize.c (maybe_clone_body): Emit early debug for clones.
	* 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.
	(gen_subprogram_die): Do not create a new DIE if we have an
	old DIE and it has DW_AT_abstract_origin set.
	(lookup_filename): Return NULL when no file name.
	(optimize_location_lists): Abstract flushing of limbo list to...
	(dwarf2out_early_finish): ...here. New function.
	(dwarf2out_abstract_function): Do not set DECL_ABSTRACT_P
	recursively if DECL_ABSTRACT_P of parent is set.
	* toplev.c (toplev::main): Add temporary debugging aid.
	* tree.c (free_lang_data): Call debug_hooks->early_finish.

diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c
index 82dd2cb..c9a4a4b 100644
--- a/gcc/c-family/cilk.c
+++ b/gcc/c-family/cilk.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "diagnostic.h"
 #include "cilk.h"
+#include "debug.h"
 
 enum add_variable_type {
     /* Reference to previously-defined variable.  */
@@ -573,6 +574,14 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd)
 
   pop_cfun_to (outer);
 
+  /* It is rather unfortunate that Cilk creates trees this late
+     (during gimplification).  However, until this gets fixed,
+     specially handle emitting DWARF for this new function and
+     immediately clean up the limbo_die_list where the new function's
+     DIE will inevitably end up.  */
+  debug_hooks->early_global_decl (fndecl);
+  debug_hooks->early_finish ();
+
   /* Recognize the new function.  */
   call_graph_add_fn (fndecl);
   return fndecl;
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/cp/optimize.c b/gcc/cp/optimize.c
index 62e32d2..ab3e93e 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -539,6 +539,10 @@ maybe_clone_body (tree fn)
       /* Start processing the function.  */
       start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
 
+      /* Generate early dwarf for the clone now that we have a body
+	 for it.  */
+      debug_hooks->early_global_decl (clone);
+
       /* Tell cgraph if both ctors or both dtors are known to have
 	 the same body.  */
       if (can_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 e3ccda2..bf9268a 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,
@@ -4903,6 +4906,25 @@ 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 some corner case (Cilk), is creating definitions too late,
+	 it should itself take care of calling
+	 dwarf2out_early_global_decl() and flushing the limbo_die_list
+	 afterwards via dwarf2out_early_finish().  See cilk.c for an
+	 example of such stupidity.  */
+      if (tag_value != DW_TAG_compile_unit
+	  && !early_dwarf_dumping
+	  /* 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_tree (t);
+	  gcc_unreachable ();
+	}
+
       limbo_node = ggc_cleared_alloc<limbo_die_node> ();
       limbo_node->die = die;
       limbo_node->created_for = t;
@@ -18277,9 +18299,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;
@@ -18443,14 +18466,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.  */
@@ -21738,6 +21770,9 @@ lookup_filename (const char *file_name)
 {
   struct dwarf_file_data * created;
 
+  if (!file_name)
+    return NULL;
+
   /* Check to see if the file name that was searched on the previous
      call matches this file name.  If so, return the index.  */
   if (file_table_last_lookup
@@ -24739,10 +24774,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.  */
@@ -24767,55 +24811,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;
@@ -24863,6 +24858,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)
@@ -25124,6 +25120,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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-16 11:03   ` Richard Biener
  2015-01-16 16:38     ` Jason Merrill
@ 2015-01-28 19:44     ` Aldy Hernandez
  1 sibling, 0 replies; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-28 19:44 UTC (permalink / raw)
  To: Richard Biener, Jason Merrill; +Cc: gcc-patches

On 01/16/2015 02:55 AM, Richard Biener wrote:
> On Fri, Jan 16, 2015 at 4:11 AM, Jason Merrill <jason@redhat.com> wrote:
>> On 01/15/2015 09:58 PM, Aldy Hernandez wrote:

> I hoped we wouldn't need the limbo list at all ... that is, parent DIEs
> are always present when we create children.  I think that should
> work in principle if the frontends would create DIEs while parsing.

By the way, don't think I ignored this suggestion.  I played around with 
this approach for the C++ front-end, and gave up after having to keep 
track of a few too many things to get the parenthood right.  It's 
totally doable; it was just easier to flush out the limbo DIE list as 
with my current patch.  Ok, call me lazy :).

> Note that dwarf2out forces parent DIE creation in some cases
> but not in some others - it would be interesting to sort out which
> parent DIEs it thinks it cannot create when we create the DIE
> for a sibling.  Maybe it's just poor ordering of early_global_decl
> calls?

In my current patch, I added an ICE to make sure we're not creating 
limbo destined DIEs past early dwarf dumping.  The only exception to 
this (temporarily) is that the ltrans stage is adding things late, but 
that's only because we're not streaming dwarf as the ultimate plan is. 
I've documented all this.

Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-28 19:32             ` Aldy Hernandez
@ 2015-01-28 19:47               ` Jason Merrill
  2015-01-30 22:15                 ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-01-28 19:47 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

On 01/28/2015 01:29 PM, Aldy Hernandez wrote:
> +  /* It is rather unfortunate that Cilk creates trees this late
> +     (during gimplification).  However, until this gets fixed,
> +     specially handle emitting DWARF for this new function and
> +     immediately clean up the limbo_die_list where the new function's
> +     DIE will inevitably end up.  */

Why does it go on limbo_die_list at all?

> I noticed dwarf2out's gen_member_die() disallows generation of clones earlier, by design:
>
>      /* Don't include clones in the member list.  */
>      if (DECL_ABSTRACT_ORIGIN (member))
>        continue;
>
> I played around trying to disable this "feature", but my approach ran into various walls, and I decided instead to attack it from the front-end side. The attached patch generates early DIEs for the C++ clones in the C++ parser. I'd be (un)happy to revisit the dwarf2out approach if it's deemed more appropriate.

I'd still like to understand why disabling this doesn't work; I don't 
like the special handling of clones in the front end.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-28 19:47               ` Jason Merrill
@ 2015-01-30 22:15                 ` Aldy Hernandez
  2015-01-30 22:23                   ` Jason Merrill
  0 siblings, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-30 22:15 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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

On 01/28/2015 10:51 AM, Jason Merrill wrote:
> On 01/28/2015 01:29 PM, Aldy Hernandez wrote:
>> +  /* It is rather unfortunate that Cilk creates trees this late +
>> (during gimplification).  However, until this gets fixed, +
>> specially handle emitting DWARF for this new function and +
>> immediately clean up the limbo_die_list where the new function's +
>> DIE will inevitably end up.  */
>
> Why does it go on limbo_die_list at all?

Good point.  They are ending up in limbo because, during late dwarf
generation, dwarf2out_decl is clearing its context_die, as they are
nested functions:

       /* If we're a nested function, initially use a parent of NULL; if
we're
	 a plain function, this will be fixed up in decls_for_scope.  If
	 we're a method, it will be ignored, since we already have a DIE.  */
       if (decl_function_context (decl)
	  /* But if we're in terse mode, we don't care about scope.  */
	  && debug_info_level > DINFO_LEVEL_TERSE)
	context_die = NULL;

We could avoid special casing Cilk, and just allow late limbo DIEs of
nested functions, since decls_for_scope will set their ancestry
correctly shortly afterwards (that is, they don't remain in limbo long-- 
or into LTO).  I have verified this to be true with the
  patch.

>
>> I noticed dwarf2out's gen_member_die() disallows generation of
>> clones earlier, by design:
>>
>> /* Don't include clones in the member list.  */ if
>> (DECL_ABSTRACT_ORIGIN (member)) continue;
>>
> I'd still like to understand why disabling this doesn't work; I don't
>  like the special handling of clones in the front end.

The attached patch disables this, and fixes the fallout.  Instead of 
explaining what required tweaking, the `#if 0'ed out code with 
appropriate comments explains the relevant changes.  Do you agree?

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.  We can optimize this later.

I have added some debugging code to help catch late limbo DIE creation 
as well as a few things to help the process.  We can remove them at 
merge time.

I special cased allowing late limbo type DIES that occur for template 
interactions.  No sense complicating my life with templates until we 
iron out the clones.  I will take a look at templates next.

I also got rid of my decl_abstract change to 
dwarf2out_abstract_function() (the static variable plus LTO issue) 
because it's not being triggered anymore with the attached patch.

Would you be so kind as to look at this approach?  It has no guality 
regressions, and the C++ clones seem to have correct DIEs.  I can remove 
the #if 0 code once we're in agreement.

Thanks.
Aldy

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 17138 bytes --]

	* 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.
	Remove declaration assert.
	(gen_member_die): Allow DIE clones to be generated.
	(struct die_struct): Add tmp_created_for field.
	(lookup_filename): Return NULL when no file name.
	(optimize_location_lists): Abstract flushing of limbo list to...
	(dwarf2out_early_finish): ...here. New function.
	(print_die): Output tmp_created_for field.
	* toplev.c (toplev::main): Add temporary debugging aid.
	* tree.c (free_lang_data): Call debug_hooks->early_finish.

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..7e1c000 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);
@@ -18414,12 +18451,16 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
      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.  */
 
+  /* ?? 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
 
   /* Now that the C++ front end lazily declares artificial member fns, we
      might need to retrofit the declaration into its class.  */
@@ -18433,21 +18474,34 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
   /* An inlined instance, tag a new DIE with DW_AT_abstract_origin.  */
   if (origin != NULL)
     {
+      // ?? Make C++ clones work since they're tagged as
+      // declarations but are class scoped instead.
+#if 0
       gcc_assert (!declaration || local_scope_p (context_die));
+#endif
 
       /* Fixup die_parent for the abstract instance of a nested
 	 inline function.  */
       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.  */
@@ -20125,9 +20179,9 @@ gen_member_die (tree type, dw_die_ref context_die)
   /* Now output info about the function members (if any).  */
   for (member = TYPE_METHODS (type); member; member = DECL_CHAIN (member))
     {
-      /* Don't include clones in the member list.  */
-      if (DECL_ABSTRACT_ORIGIN (member))
-	continue;
+      if (DECL_ABSTRACT_ORIGIN (member) && flag_dump_early_debug_stats)
+	fprintf(stderr, "generating dwarf for member clone: %s\n",
+		IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (member)));
 
       child = lookup_decl_die (member);
       if (child)
@@ -21733,6 +21787,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 +24783,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 +24820,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 +24867,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 +25129,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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-30 22:15                 ` Aldy Hernandez
@ 2015-01-30 22:23                   ` Jason Merrill
  2015-01-31  7:28                     ` Aldy Hernandez
  2015-02-01  8:42                     ` Richard Biener
  0 siblings, 2 replies; 36+ messages in thread
From: Jason Merrill @ 2015-01-30 22:23 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

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.

> 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()?

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-30 22:23                   ` Jason Merrill
@ 2015-01-31  7:28                     ` Aldy Hernandez
  2015-02-01  6:27                       ` Jason Merrill
  2015-02-01  8:42                     ` Richard Biener
  1 sibling, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-01-31  7:28 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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

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

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 17852 bytes --]

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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-31  7:28                     ` Aldy Hernandez
@ 2015-02-01  6:27                       ` Jason Merrill
  2015-02-01  8:43                         ` Richard Biener
  2015-02-02  3:15                         ` Aldy Hernandez
  0 siblings, 2 replies; 36+ messages in thread
From: Jason Merrill @ 2015-02-01  6:27 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

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

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-01-30 22:23                   ` Jason Merrill
  2015-01-31  7:28                     ` Aldy Hernandez
@ 2015-02-01  8:42                     ` Richard Biener
  2015-02-02  1:48                       ` Jason Merrill
  1 sibling, 1 reply; 36+ messages in thread
From: Richard Biener @ 2015-02-01  8:42 UTC (permalink / raw)
  To: Jason Merrill, Aldy Hernandez; +Cc: gcc-patches

On January 30, 2015 11:04:23 PM CET, Jason Merrill <jason@redhat.com> 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.
>
>> 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()?

I always thought a user expects debug information for all entities in the source, not only those useb by the (optimized) binary.

Richard.

>Jason


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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-01  6:27                       ` Jason Merrill
@ 2015-02-01  8:43                         ` Richard Biener
  2015-02-02  3:15                         ` Aldy Hernandez
  1 sibling, 0 replies; 36+ messages in thread
From: Richard Biener @ 2015-02-01  8:43 UTC (permalink / raw)
  To: Jason Merrill, Aldy Hernandez; +Cc: gcc-patches

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


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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-01  8:42                     ` Richard Biener
@ 2015-02-02  1:48                       ` Jason Merrill
  0 siblings, 0 replies; 36+ messages in thread
From: Jason Merrill @ 2015-02-02  1:48 UTC (permalink / raw)
  To: Richard Biener, Aldy Hernandez; +Cc: gcc-patches

On 02/01/2015 03:42 AM, Richard Biener wrote:
> I always thought a user expects debug information for all entities in the source, not only those useb by the (optimized) binary.

Right, but the clones aren't in the source individually; the primary 
constructor that they are cloned from should always be in the debug 
info, but we don't need to emit anything for the clones unless they have 
a concrete instance.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-01  6:27                       ` Jason Merrill
  2015-02-01  8:43                         ` Richard Biener
@ 2015-02-02  3:15                         ` Aldy Hernandez
  2015-02-02  4:16                           ` Jason Merrill
  1 sibling, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-02  3:15 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-02  3:15                         ` Aldy Hernandez
@ 2015-02-02  4:16                           ` Jason Merrill
  2015-02-05  0:27                             ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-02-02  4:16 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

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

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-02  4:16                           ` Jason Merrill
@ 2015-02-05  0:27                             ` Aldy Hernandez
  2015-02-05 20:11                               ` Jason Merrill
  0 siblings, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-05  0:27 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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

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

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 31994 bytes --]

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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-05  0:27                             ` Aldy Hernandez
@ 2015-02-05 20:11                               ` Jason Merrill
  2015-02-06  1:15                                 ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-02-05 20:11 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

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

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-05 20:11                               ` Jason Merrill
@ 2015-02-06  1:15                                 ` Aldy Hernandez
  2015-02-06 14:02                                   ` Jason Merrill
  0 siblings, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-06  1:15 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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


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

Done.

>
>> +  /* 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?

Absolutely nothing, basically  because #if 0 would have been too 
obvious.  It was actually there to test if you were on your game.  You 
passed :).

Static locals were actually being handled by the recursion through 
dwarf2out_decl when generating DIEs for functions.  And changing the 
context for symbols above to non-function context as you suggest, 
handled class member functions containing statics.

>> +  // ?? 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.

Fair enough.

The attached patch still passes the guality tests with no regressions. 
My apologies for the lack of ChangeLog entries.  I've given up on them, 
especially on multiple iterations.  And it seems I'll have to rewrite 
them at merge time anyhow.

How does this look?

Aldy

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 30887 bytes --]

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..f099cce 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -2326,6 +2326,17 @@ symbol_table::finalize_compilation_unit (void)
   if (flag_dump_passes)
     dump_passes ();
 
+  /* Generate early debug for global symbols.  Anything local will be
+     handled by either handling reachable functions further down (and
+     by consequence, locally scoped symbols), or by generating DIEs
+     for types.  */
+  symtab_node *snode;
+  FOR_EACH_SYMBOL (snode)
+    if (TREE_CODE (snode->decl) != FUNCTION_DECL
+	&& DECL_CONTEXT (snode->decl)
+	&& TREE_CODE (DECL_CONTEXT (snode->decl)) != FUNCTION_DECL)
+      (*debug_hooks->early_global_decl) (snode->decl);
+
   /* Gimplify and lower all functions, compute reachability and
      remove unreachable nodes.  */
   analyze_functions ();
@@ -2336,6 +2347,18 @@ symbol_table::finalize_compilation_unit (void)
   /* Gimplify and lower thunks.  */
   analyze_functions ();
 
+  /* Emit early debug for reachable functions, and by consequence,
+     locally scoped symbols.  */
+  struct cgraph_node *cnode;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+    if (DECL_CONTEXT (cnode->decl)
+	&& TREE_CODE (DECL_CONTEXT (cnode->decl)) != FUNCTION_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/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..54c82eb 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);
@@ -18274,7 +18312,8 @@ 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)
     set_decl_abstract_flags (decl, 0);
@@ -18403,24 +18442,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 +18548,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 +18613,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 +21424,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 +21758,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 +21858,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 +24854,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 +24892,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 +24939,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 +25201,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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-06  1:15                                 ` Aldy Hernandez
@ 2015-02-06 14:02                                   ` Jason Merrill
  2015-02-06 16:42                                     ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-02-06 14:02 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

On 02/05/2015 08:15 PM, Aldy Hernandez wrote:
> Absolutely nothing, basically  because #if 0 would have been too obvious.  It was actually there to test if you were on your game.  You passed

Yay?

> The attached patch still passes the guality tests with no regressions. My apologies for the lack of ChangeLog entries.  I've given up on them, especially on multiple iterations.  And it seems I'll have to rewrite them at merge time anyhow.

That makes total sense to me.

> +	&& DECL_CONTEXT (snode->decl)
> +	&& TREE_CODE (DECL_CONTEXT (snode->decl)) != FUNCTION_DECL)

I think this should be !decl_function_context (snode->decl), in case 
there's a class or BLOCK between the symbol and its enclosing function.

>  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.

Note that we also want to emit debug info about some types that are not 
referenced by symbols, such as when a type is used in a cast.

> +/* Perform any cleanups needed after the early debug generation pass
> +   has run.  */
> +
> +static void
> +dwarf2out_early_finish (void)

Since this is also called from dwarf2out_finish, let's call it something 
more descriptive, say, flush_limbo_dies?

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-06 14:02                                   ` Jason Merrill
@ 2015-02-06 16:42                                     ` Aldy Hernandez
  2015-02-06 17:40                                       ` Jason Merrill
  2015-02-10 10:52                                       ` Richard Biener
  0 siblings, 2 replies; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-06 16:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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


>> +    && DECL_CONTEXT (snode->decl)
>> +    && TREE_CODE (DECL_CONTEXT (snode->decl)) != FUNCTION_DECL)
>
> I think this should be !decl_function_context (snode->decl), in case
> there's a class or BLOCK between the symbol and its enclosing function.

Done, also for the iteration through reachable functions.

>
>>  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.
>
> Note that we also want to emit debug info about some types that are not
> referenced by symbols, such as when a type is used in a cast.

Fair enough.  I've removed the comment.

>> +/* Perform any cleanups needed after the early debug generation pass
>> +   has run.  */
>> +
>> +static void
>> +dwarf2out_early_finish (void)
>
> Since this is also called from dwarf2out_finish, let's call it something
> more descriptive, say, flush_limbo_dies?

I was actually thinking of using dwarf2out_early_finish() to mop things 
up as we generate early (or stream out) other auxiliary tables 
(pubname_table, pubtype_table, file_table, etc).  More details on that 
later.  If so, can I leave it as is?

How is this version?  No regressions on guality.  Target libraries build 
fine.

Aldy

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 30113 bytes --]

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..3b57dfe 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -2326,6 +2326,16 @@ symbol_table::finalize_compilation_unit (void)
   if (flag_dump_passes)
     dump_passes ();
 
+  /* Generate early debug for global symbols.  Any local symbols will
+     be handled by either handling reachable functions further down
+     (and by consequence, locally scoped symbols), or by generating
+     DIEs for types.  */
+  symtab_node *snode;
+  FOR_EACH_SYMBOL (snode)
+    if (TREE_CODE (snode->decl) != FUNCTION_DECL
+	&& !decl_function_context (snode->decl))
+      (*debug_hooks->early_global_decl) (snode->decl);
+
   /* Gimplify and lower all functions, compute reachability and
      remove unreachable nodes.  */
   analyze_functions ();
@@ -2336,6 +2346,17 @@ symbol_table::finalize_compilation_unit (void)
   /* Gimplify and lower thunks.  */
   analyze_functions ();
 
+  /* Emit early debug for reachable functions, and by consequence,
+     locally scoped symbols.  */
+  struct cgraph_node *cnode;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
+    if (!decl_function_context (cnode->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/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..036194d 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);
@@ -18274,7 +18312,8 @@ 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)
     set_decl_abstract_flags (decl, 0);
@@ -18403,24 +18442,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 +18548,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 +18613,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);
@@ -21319,7 +21425,12 @@ static void
 dwarf2out_type_decl (tree decl, int local)
 {
   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 +21747,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 +21847,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 +24843,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 +24881,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 +24928,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 +25190,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,

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-06 16:42                                     ` Aldy Hernandez
@ 2015-02-06 17:40                                       ` Jason Merrill
  2015-02-06 17:47                                         ` Aldy Hernandez
  2015-02-10 10:52                                       ` Richard Biener
  1 sibling, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-02-06 17:40 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Biener, gcc-patches

On 02/06/2015 11:42 AM, Aldy Hernandez wrote:
> I was actually thinking of using dwarf2out_early_finish() to mop things up as we generate early (or stream out) other auxiliary tables (pubname_table, pubtype_table, file_table, etc).  More details on that later.  If so, can I leave it as is?

OK.

> +  /* 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;

Maybe add a FIXME comment to remove/#if this out at merge time?  I don't 
want to add an unnecessary pointer to every DIE in the released compiler.

OK with that change.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-06 17:40                                       ` Jason Merrill
@ 2015-02-06 17:47                                         ` Aldy Hernandez
  0 siblings, 0 replies; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-06 17:47 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches


> OK with that change.

Sweet!  Thanks for everything.

Though he's been silent, I bet Richi is secretly dancing :-).

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-06 16:42                                     ` Aldy Hernandez
  2015-02-06 17:40                                       ` Jason Merrill
@ 2015-02-10 10:52                                       ` Richard Biener
  2015-02-10 17:58                                         ` Jason Merrill
  2015-02-12 18:04                                         ` Aldy Hernandez
  1 sibling, 2 replies; 36+ messages in thread
From: Richard Biener @ 2015-02-10 10:52 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jason Merrill, gcc-patches

On Fri, Feb 6, 2015 at 5:42 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>
>>> +    && DECL_CONTEXT (snode->decl)
>>> +    && TREE_CODE (DECL_CONTEXT (snode->decl)) != FUNCTION_DECL)
>>
>>
>> I think this should be !decl_function_context (snode->decl), in case
>> there's a class or BLOCK between the symbol and its enclosing function.
>
>
> Done, also for the iteration through reachable functions.
>
>>
>>>  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.
>>
>>
>> Note that we also want to emit debug info about some types that are not
>> referenced by symbols, such as when a type is used in a cast.
>
>
> Fair enough.  I've removed the comment.
>
>>> +/* Perform any cleanups needed after the early debug generation pass
>>> +   has run.  */
>>> +
>>> +static void
>>> +dwarf2out_early_finish (void)
>>
>>
>> Since this is also called from dwarf2out_finish, let's call it something
>> more descriptive, say, flush_limbo_dies?
>
>
> I was actually thinking of using dwarf2out_early_finish() to mop things up
> as we generate early (or stream out) other auxiliary tables (pubname_table,
> pubtype_table, file_table, etc).  More details on that later.  If so, can I
> leave it as is?
>
> How is this version?  No regressions on guality.  Target libraries build
> fine.

Finally having a look at the patch.  And indeed - this is how I thought
it should work.

Of course I wonder why you need to separate handling of functions and
variables.  What breaks if you emit debug info for functions before
the first analyze_functions () call?

I also wonder why you restrict it to functions with a GIMPLE body.

I'd have expected for a TU like

void foo (int, int);
int main()
{
  return 0;
}

to be able to do

(gdb) start
(gdb) ptype foo

and get a prototype for foo?  (ok, that may be -g3 stuff)

Likewise for

struct foo { int i; };
int main ()
{
  return 0;
}

and I realize that this needs frontend support - the middle-end really
only gets "reachable" stuff reliably.

Thus for -g3 we may end up retaining (or adding) some FE calls
to early_global{_decl,_type}?

(not that I care about the above cases in practice, but in theory?)

Thanks for doing all this work!

Richard.

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-10 10:52                                       ` Richard Biener
@ 2015-02-10 17:58                                         ` Jason Merrill
  2015-02-12 18:04                                         ` Aldy Hernandez
  1 sibling, 0 replies; 36+ messages in thread
From: Jason Merrill @ 2015-02-10 17:58 UTC (permalink / raw)
  To: Richard Biener, Aldy Hernandez; +Cc: gcc-patches

On 02/10/2015 05:52 AM, Richard Biener wrote:
> I also wonder why you restrict it to functions with a GIMPLE body.
>
> Likewise for
>
> struct foo { int i; };

I guess these should depend on -feliminate-unused-debug-symbols and 
-feliminate-unused-debug-types.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-10 10:52                                       ` Richard Biener
  2015-02-10 17:58                                         ` Jason Merrill
@ 2015-02-12 18:04                                         ` Aldy Hernandez
  2015-02-12 19:27                                           ` Jason Merrill
  1 sibling, 1 reply; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-12 18:04 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches

On 02/10/2015 02:52 AM, Richard Biener wrote:
> On Fri, Feb 6, 2015 at 5:42 PM, Aldy Hernandez <aldyh@redhat.com> wrote:

> Of course I wonder why you need to separate handling of functions and variables

The variables need to be handled earlier, else the call to 
analyze_functions() will remove some optimized global variables away, 
and we'll never see them.  I believe that Jason said they were needed 
up-thread.

> variables.  What breaks if you emit debug info for functions before
> the first analyze_functions () call?
 >
 > I also wonder why you restrict it to functions with a GIMPLE body.

The functions, on the other hand, need to be handled after the second 
call to analyze_function (and with a GIMPLE body) else we get far more 
function DIEs than mainline currently does, especially wrt C++ clones. 
Otherwise, we get DIEs for base constructors, complete constructors, and 
what-have-yous.  Jason wanted less DIEs, more attune to what mainline is 
currently doing.

>
> I'd have expected for a TU like
>
> void foo (int, int);
> int main()
> {
>    return 0;
> }
>
> to be able to do
>
> (gdb) start
> (gdb) ptype foo
>
> and get a prototype for foo?  (ok, that may be -g3 stuff)

This may need frontend support.  I don't think we get any of these 
prototype symbols in cgraphunit, at least not in the symbol table 
(FOR_EACH_SYMBOL).  Perhaps a call from the front-ends, similar to what 
we do with types with debug_hooks->type_decl().  But... do really want 
that?  Is there a practical use?

>
> Likewise for
>
> struct foo { int i; };
> int main ()
> {
>    return 0;
> }

This is already working if compiled with 
-fno-eliminate-unused-debug-types, probably by virtue of types being 
called from the front-ends with debug_hooks->type_decl().  We could 
certainly enable -fno-eliminate-unused-debug-{symbols,types} for -g3 if 
desirable.

> Thanks for doing all this work!

Thanks for volunteering to do the LTO bits ;-).

Aldy

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-12 18:04                                         ` Aldy Hernandez
@ 2015-02-12 19:27                                           ` Jason Merrill
  2015-02-16 20:46                                             ` Aldy Hernandez
  0 siblings, 1 reply; 36+ messages in thread
From: Jason Merrill @ 2015-02-12 19:27 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener; +Cc: gcc-patches

On 02/12/2015 01:04 PM, Aldy Hernandez wrote:
> On 02/10/2015 02:52 AM, Richard Biener wrote:
>> On Fri, Feb 6, 2015 at 5:42 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>
>> Of course I wonder why you need to separate handling of functions and
>> variables
>
> The variables need to be handled earlier, else the call to
> analyze_functions() will remove some optimized global variables away,
> and we'll never see them.  I believe that Jason said they were needed
> up-thread.
>
>> variables.  What breaks if you emit debug info for functions before
>> the first analyze_functions () call?
>  >
>  > I also wonder why you restrict it to functions with a GIMPLE body.
>
> The functions, on the other hand, need to be handled after the second
> call to analyze_function (and with a GIMPLE body) else we get far more
> function DIEs than mainline currently does, especially wrt C++ clones.
> Otherwise, we get DIEs for base constructors, complete constructors, and
> what-have-yous.  Jason wanted less DIEs, more attune to what mainline is
> currently doing.

I think it makes sense to generate DIEs for everything defined in the TU 
if we don't have -feliminate-unused-debug-symbols.  But since clones are 
artificial, emit them only if they're used.

>> void foo (int, int);
>> and get a prototype for foo?  (ok, that may be -g3 stuff)
>
> This may need frontend support.  I don't think we get any of these
> prototype symbols in cgraphunit, at least not in the symbol table
> (FOR_EACH_SYMBOL).  Perhaps a call from the front-ends, similar to what
> we do with types with debug_hooks->type_decl().  But... do really want
> that?  Is there a practical use?

We haven't done that, historically.  But it would be useful for ABI 
verification by, comparing the debug info for the declarations to the 
debug info for the definition in the shared library.

Jason

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

* Re: [debug-early] C++ clones and limbo DIEs
  2015-02-12 19:27                                           ` Jason Merrill
@ 2015-02-16 20:46                                             ` Aldy Hernandez
  0 siblings, 0 replies; 36+ messages in thread
From: Aldy Hernandez @ 2015-02-16 20:46 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

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

On 02/12/2015 11:27 AM, Jason Merrill wrote:
> On 02/12/2015 01:04 PM, Aldy Hernandez wrote:
>> On 02/10/2015 02:52 AM, Richard Biener wrote:
>>> On Fri, Feb 6, 2015 at 5:42 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>>
>>> Of course I wonder why you need to separate handling of functions and
>>> variables
>>
>> The variables need to be handled earlier, else the call to
>> analyze_functions() will remove some optimized global variables away,
>> and we'll never see them.  I believe that Jason said they were needed
>> up-thread.
>>
>>> variables.  What breaks if you emit debug info for functions before
>>> the first analyze_functions () call?
>>  >
>>  > I also wonder why you restrict it to functions with a GIMPLE body.
>>
>> The functions, on the other hand, need to be handled after the second
>> call to analyze_function (and with a GIMPLE body) else we get far more
>> function DIEs than mainline currently does, especially wrt C++ clones.
>> Otherwise, we get DIEs for base constructors, complete constructors, and
>> what-have-yous.  Jason wanted less DIEs, more attune to what mainline is
>> currently doing.
>
> I think it makes sense to generate DIEs for everything defined in the TU
> if we don't have -feliminate-unused-debug-symbols.  But since clones are
> artificial, emit them only if they're used.

Ok, just so we're on the same page.  I'm thinking that for 
-fNO-eliminate-unused-debug-symbols, we can iterate through 
FOR_EACH_DEFINED_FUNCTION before unreachable functions have been 
removed.  There we can output all non-clones.

Then for the -feliminate-unused-debug-symbols case, we can output 
reachable functions after the unreachable ones have been removed.  Here 
we can also dump the clones we ignored for 
-fNO-eliminate-unused-debug-symbols above, since we only want to emit 
them if they're reachable (regardless of -feliminate-unused-debug-symbols).

In either case, we always ignore those without a gimple body, otherwise 
we end up generating DIEs for the _ZN1AC2Ei constructor in the attached 
function unnecessarily.  See how the bits end up in the attached testcase:

(Oh, and we determine clonehood with DECL_ABSTRACT_ORIGIN)

Before any calls to analyze_functions()
---------------------------------------
Function: 'int main()' (Mangled: main) gimple_body=1 DECL_ABSTRACT_ORIGIN=0
Function: 'A::A(int)' (Mangled: _ZN1AC1Ei) gimple_body=0 
DECL_ABSTRACT_ORIGIN=1
Function: 'A::A(int)' (Mangled: _ZN1AC2Ei) gimple_body=1 
DECL_ABSTRACT_ORIGIN=1
Function: 'void foo(int)' (Mangled: _Z3fooi) gimple_body=1 
DECL_ABSTRACT_ORIGIN=0
Function: 'int bar()' (Mangled: _Z3barv) gimple_body=1 
DECL_ABSTRACT_ORIGIN=0
Function: 'void unreachable_func()' (Mangled: _ZL16unreachable_funcv) 
gimple_body=1 DECL_ABSTRACT_ORIGIN=0

After reachability analysis
(after first call to analyze_functions())
-----------------------------------------
Function: 'int main()' (Mangled: main) gimple_body=1 DECL_ABSTRACT_ORIGIN=0
Function: 'A::A(int)' (Mangled: _ZN1AC1Ei) gimple_body=0 
DECL_ABSTRACT_ORIGIN=1
Function: 'A::A(int)' (Mangled: _ZN1AC2Ei) gimple_body=1 
DECL_ABSTRACT_ORIGIN=1
Function: 'void foo(int)' (Mangled: _Z3fooi) gimple_body=1 
DECL_ABSTRACT_ORIGIN=0
Function: 'int bar()' (Mangled: _Z3barv) gimple_body=1 
DECL_ABSTRACT_ORIGIN=0

Is this what you had in mind?  I can provide a patch to make things clearer.

Aldy

[-- Attachment #2: b.ii --]
[-- Type: text/plain, Size: 406 bytes --]

extern "C" void abort ();
struct A { A (int); int a; };

int i;

static void unreachable_func()
{
  i = 5;
}


__attribute__((noinline, noclone)) int
bar (void)
{
  return 40;
}

__attribute__((noinline, noclone)) void
foo (int x)
{
  __asm volatile ("" : : "r" (x) : "memory");
}

A::A (int x)
{
  static int p = bar ();
  foo (p);
  a = ++p;
}

int
main ()
{
  A a (42);
  if (a.a != 41)
    abort ();
}

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

end of thread, other threads:[~2015-02-16 20:46 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-16  3:11 [debug-early] C++ clones and limbo DIEs Aldy Hernandez
2015-01-16  4:30 ` Jason Merrill
2015-01-16 11:03   ` Richard Biener
2015-01-16 16:38     ` Jason Merrill
2015-01-16 18:09       ` Aldy Hernandez
2015-01-16 18:51       ` Richard Biener
2015-01-28 19:44     ` Aldy Hernandez
2015-01-16 17:54   ` Aldy Hernandez
2015-01-16 21:38     ` Jason Merrill
2015-01-23 19:53       ` Aldy Hernandez
2015-01-26  9:21         ` Richard Biener
2015-01-27 22:33         ` Jason Merrill
2015-01-28 19:24           ` Aldy Hernandez
2015-01-28 19:32             ` Aldy Hernandez
2015-01-28 19:47               ` Jason Merrill
2015-01-30 22:15                 ` Aldy Hernandez
2015-01-30 22:23                   ` Jason Merrill
2015-01-31  7:28                     ` Aldy Hernandez
2015-02-01  6:27                       ` Jason Merrill
2015-02-01  8:43                         ` Richard Biener
2015-02-02  3:15                         ` Aldy Hernandez
2015-02-02  4:16                           ` Jason Merrill
2015-02-05  0:27                             ` Aldy Hernandez
2015-02-05 20:11                               ` Jason Merrill
2015-02-06  1:15                                 ` Aldy Hernandez
2015-02-06 14:02                                   ` Jason Merrill
2015-02-06 16:42                                     ` Aldy Hernandez
2015-02-06 17:40                                       ` Jason Merrill
2015-02-06 17:47                                         ` Aldy Hernandez
2015-02-10 10:52                                       ` Richard Biener
2015-02-10 17:58                                         ` Jason Merrill
2015-02-12 18:04                                         ` Aldy Hernandez
2015-02-12 19:27                                           ` Jason Merrill
2015-02-16 20:46                                             ` Aldy Hernandez
2015-02-01  8:42                     ` Richard Biener
2015-02-02  1:48                       ` Jason Merrill

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).