[debug-early] C++: emit early debug info for all globals, not just statics
diff mbox

Message ID 542C72A9.9090602@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez Oct. 1, 2014, 9:31 p.m. UTC
While hunting another bug, I noticed that the namespace code dumping 
early debug information was only dumping statics.  Ooops... The patch 
below fixes this oversight.

Jason also suggested that we could look into emitting debug info for 
DECLs directly in rest_of_decl_compilation as we currently do for 
rest_of_type_compilation.  I have added a note to that effect, as 
something to look into later.  I'd rather not rock the boat now that 
things are somewhat stable and I'm busy looking into gdb failures.

Committed to branch.

Aldy
commit 1e055f3a98ca3bf271506511c30298a7f156c96f
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Wed Oct 1 14:26:06 2014 -0700

    	* cp/decl2.c (emit_debug_for_namespace): Emit early debug
    	information for all DECLs instead of just the statics.
    	Include debug.h.
    	* passes.c (rest_of_decl_compilation): Add reminder that we could
    	emit early debug information here.

Comments

Jason Merrill Oct. 2, 2014, 3:46 p.m. UTC | #1
On 10/01/2014 05:31 PM, Aldy Hernandez wrote:
> +  for (tree t = level->names; t; t = TREE_CHAIN(t))
> +    if (TREE_CODE (t) != TYPE_DECL
> +	&& TREE_CODE (t) != PARM_DECL
> +	&& !DECL_IS_BUILTIN (t))
> +      debug_hooks->early_global_decl (t);

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.

Why do you need to check for PARM_DECL?  There shouldn't be any 
PARM_DECL at namespace scope.

Why do you want to skip TYPE_DECL?  I think we should leave the decision 
about whether to emit a typedef to the debugging back end.

Jason
Aldy Hernandez Oct. 2, 2014, 6:21 p.m. UTC | #2
On 10/02/14 08:46, Jason Merrill wrote:
> On 10/01/2014 05:31 PM, Aldy Hernandez wrote:
>> +  for (tree t = level->names; t; t = TREE_CHAIN(t))
>> +    if (TREE_CODE (t) != TYPE_DECL
>> +    && TREE_CODE (t) != PARM_DECL
>> +    && !DECL_IS_BUILTIN (t))
>> +      debug_hooks->early_global_decl (t);
>
> 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.

Hmm, I'll look into this.

> Why do you need to check for PARM_DECL?  There shouldn't be any
> PARM_DECL at namespace scope.
>
> Why do you want to skip TYPE_DECL?  I think we should leave the decision
> about whether to emit a typedef to the debugging back end.

Actually, I think we/I need to rethink this whole globals thing. 
Currently we're early dumping global *_DECLs, and hoping dwarf2out 
recursion will also pick up types and any derivatives from the *_DECLs, 
but taking a closer look I've noticed a lot of things are not being 
dumped early.

For instance:


	foo()
	{
	  typedef int ITYPE;
	  ITYPE var = 5;
	}

For the above code, var's DIE gets outputted _after_ the compilation 
proper has been run here:

   if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK
       && (!DECL_STRUCT_FUNCTION (decl)
	  || DECL_STRUCT_FUNCTION (decl)->gimple_df))
	...
	...
	decls_for_scope (outer_scope, subr_die, 0);

I think we should be outputting DIEs for locals at the end of parsing, 
so my patch going through level->names IMO is wrong.  We should be 
dumping all *_DECLs created by the FE, not just globally scoped ones.

This means that we'll need to clean up unreachable/unused DIEs after the 
flow graph has been built.

Another example currently not being dumped early is...

	function()
	{
	  class Local {
	  public:
	    void loc_foo (void) { }
	  };
	
	  Local l;
	  l.loc_foo ();
	}

...since loc_foo() is not in level->names.  Again, this seems like an 
argument for early dumping all *_DECLs directly from 
rest_of_decl_compilation() (as you've hinted) and then cleaning up 
unused DIEs after we have flow information.

Does this seem reasonable?

Aldy
Richard Biener Oct. 2, 2014, 7:56 p.m. UTC | #3
On October 2, 2014 8:21:51 PM CEST, Aldy Hernandez <aldyh@redhat.com> wrote:
>On 10/02/14 08:46, Jason Merrill wrote:
>> On 10/01/2014 05:31 PM, Aldy Hernandez wrote:
>>> +  for (tree t = level->names; t; t = TREE_CHAIN(t))
>>> +    if (TREE_CODE (t) != TYPE_DECL
>>> +    && TREE_CODE (t) != PARM_DECL
>>> +    && !DECL_IS_BUILTIN (t))
>>> +      debug_hooks->early_global_decl (t);
>>
>> 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.
>
>Hmm, I'll look into this.
>
>> Why do you need to check for PARM_DECL?  There shouldn't be any
>> PARM_DECL at namespace scope.
>>
>> Why do you want to skip TYPE_DECL?  I think we should leave the
>decision
>> about whether to emit a typedef to the debugging back end.
>
>Actually, I think we/I need to rethink this whole globals thing. 
>Currently we're early dumping global *_DECLs, and hoping dwarf2out 
>recursion will also pick up types and any derivatives from the *_DECLs,
>
>but taking a closer look I've noticed a lot of things are not being 
>dumped early.
>
>For instance:
>
>
>	foo()
>	{
>	  typedef int ITYPE;
>	  ITYPE var = 5;
>	}
>
>For the above code, var's DIE gets outputted _after_ the compilation 
>proper has been run here:
>
>if (! declaration && outer_scope && TREE_CODE (outer_scope) !=
>ERROR_MARK
>       && (!DECL_STRUCT_FUNCTION (decl)
>	  || DECL_STRUCT_FUNCTION (decl)->gimple_df))
>	...
>	...
>	decls_for_scope (outer_scope, subr_die, 0);
>
>I think we should be outputting DIEs for locals at the end of parsing, 

Yes we should.

>so my patch going through level->names IMO is wrong.  We should be 
>dumping all *_DECLs created by the FE, not just globally scoped ones.
>
>This means that we'll need to clean up unreachable/unused DIEs after
>the 
>flow graph has been built.

If they are there after parsing a debugger should see them.  Even if it just prints <optimized out>.

>Another example currently not being dumped early is...
>
>	function()
>	{
>	  class Local {
>	  public:
>	    void loc_foo (void) { }
>	  };
>	
>	  Local l;
>	  l.loc_foo ();
>	}
>
>...since loc_foo() is not in level->names.  Again, this seems like an 
>argument for early dumping all *_DECLs directly from 
>rest_of_decl_compilation() (as you've hinted) and then cleaning up 
>unused DIEs after we have flow information.
>
>Does this seem reasonable?

Yes, but I don't see why we need the cleanup step. The decls are real after all.

Richard.

>Aldy
Aldy Hernandez Oct. 2, 2014, 10:23 p.m. UTC | #4
On 10/02/14 12:56, Richard Biener wrote:

> Yes, but I don't see why we need the cleanup step. The decls are real after all.

You won't hear me complain.

I was just worried people were going to start complaining about larger 
.debug_info sections, since I see that the current code, as it stands in 
mainline, doesn't dump (some of) the *_DECLs not currently reachable.

But hey... less work for me!

Thanks.
Aldy
Jason Merrill Oct. 3, 2014, 2:12 p.m. UTC | #5
On 10/02/2014 02:21 PM, Aldy Hernandez wrote:
> Actually, I think we/I need to rethink this whole globals thing.
> Currently we're early dumping global *_DECLs, and hoping dwarf2out
> recursion will also pick up types and any derivatives from the *_DECLs,
> but taking a closer look I've noticed a lot of things are not being
> dumped early.
>
> For instance:
>
>
>      foo()
>      {
>        typedef int ITYPE;
>        ITYPE var = 5;
>      }
>
> For the above code, var's DIE gets outputted _after_ the compilation
> proper has been run here:
>
>    if (! declaration && outer_scope && TREE_CODE (outer_scope) !=
> ERROR_MARK
>        && (!DECL_STRUCT_FUNCTION (decl)
>        || DECL_STRUCT_FUNCTION (decl)->gimple_df))
>      ...
>      ...
>      decls_for_scope (outer_scope, subr_die, 0);
>
> I think we should be outputting DIEs for locals at the end of parsing,
> so my patch going through level->names IMO is wrong.  We should be
> dumping all *_DECLs created by the FE, not just globally scoped ones.

The way to dump locals is by recursion.  If the current process isn't 
hitting these, that's a bug, but I don't think it means we need to 
fundamentally change the approach.  Why aren't we hitting that 
decls_for_scope when we early dump foo?

> Another example currently not being dumped early is...
>
>      function()
>      {
>        class Local {
>        public:
>          void loc_foo (void) { }
>        };
>
>        Local l;
>        l.loc_foo ();
>      }
>
> ...since loc_foo() is not in level->names.

Again, dumping function() should imply dumping Local and its members.

Jason

Patch
diff mbox

diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 64cd968..1479f03 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -54,6 +54,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-family/c-ada-spec.h"
 #include "asan.h"
+#include "debug.h"
 
 extern cpp_reader *parse_in;
 
@@ -4298,7 +4299,13 @@  emit_debug_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
   int len = statics->length ();
 
   check_global_declarations (vec, len);
-  emit_debug_global_declarations (vec, len, EMIT_DEBUG_EARLY);
+
+  for (tree t = level->names; t; t = TREE_CHAIN(t))
+    if (TREE_CODE (t) != TYPE_DECL
+	&& TREE_CODE (t) != PARM_DECL
+	&& !DECL_IS_BUILTIN (t))
+      debug_hooks->early_global_decl (t);
+
   return 0;
 }
 
diff --git a/gcc/passes.c b/gcc/passes.c
index 5001c3d..aabd365 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -268,6 +268,12 @@  rest_of_decl_compilation (tree decl,
   else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
 	   && TREE_STATIC (decl))
     varpool_node::get_create (decl);
+
+  /* ?? Theoretically, we should be able to to call
+     debug_hooks->early_global_decl() here just as we do for
+     rest_of_type_compilation below.  This would require changing how
+     we're currently calling early_global_decl() in all the
+     front-ends.  Something to look into later.  */
 }
 
 /* Called after finishing a record, union or enumeral type.  */