RFC: handle cached local static DIEs
diff mbox

Message ID 5489D81A.60801@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez Dec. 11, 2014, 5:44 p.m. UTC
Hi Jason.

After my last set of dwarf changes for locals, I found some target 
library building failures which I am now fixing.

The problem at hand is that, by design, the caching code in 
gen_variable_die() refuses to use a previously cached DIE if the current 
context and the cached context are different:

        else if (old_die->die_parent != context_die)
         {
           /* If the contexts differ, it means we're not talking about
              the same thing.  Clear things so we can get a new DIE.
              This can happen when creating an inlined instance, in
              which case we need to create a new DIE that will get
              annotated with DW_AT_abstract_origin.  */
           old_die = NULL;
           gcc_assert (!DECL_ABSTRACT_P (decl));
         }

This is causing problems with local statics which are handled at 
dwarf2out_late_global_decl, and which originally have a context of the 
compilation unit (by virtue of the dwarf2out_decl call).  This context 
then gets changed here:

       /* For local statics lookup proper context die.  */
       if (TREE_STATIC (decl)
	  && DECL_CONTEXT (decl)
	  && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
	context_die = lookup_decl_die (DECL_CONTEXT (decl));

This new context may be correct for front/middle-end purposes, but is 
not the DIE context I am expecting in gen_variable_die.  For example, in 
the following example, the DECL_CONTEXT for the static is funky's 
DW_TAG_subprogram, whereas the caching code is expecting the 
DW_TAG_lexical_block:

	void funky()
	{
	  {
	    static const char *nested_static_const = "testing123";
	  }
	}

My proposed way of handling it (attached) is by tightening the check in 
gen_variable_die(), and special casing this scenario (assuming, there is 
no other way to get a differing context).  This works, and fixes all the 
failures, without introducing any regressions.

Another approach would be to use whatever context is already cached with 
just "context_die = lookup_decl_die (decl)", but that feels like cheating.

Are you OK with the attached approach, or do you have something else in 
mind?

Thanks.
Aldy
commit 515a20666d0ea73f2380bae6d9b8ec1d5bb2f001
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Thu Dec 11 09:26:25 2014 -0800

    	* dwarf2out.c (gen_subprogram_die): Handle as cached die if
    	dumped_early bit is set.
    	(dwarf2out_decl): Abstract local static check...
    	(local_function_static): ...into here.
    	(gen_variable_die): Handle different contexts in a cached die
    	gracefully for the non inline case.

Comments

Jason Merrill Dec. 11, 2014, 7:19 p.m. UTC | #1
On 12/11/2014 12:44 PM, Aldy Hernandez wrote:
> This context then gets changed here:
>
>        /* For local statics lookup proper context die.  */
>        if (TREE_STATIC (decl)
>        && DECL_CONTEXT (decl)
>        && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
>      context_die = lookup_decl_die (DECL_CONTEXT (decl));

Can we remove this and just leave the context as NULL until it gets 
fixed up?

Jason
Jason Merrill Dec. 11, 2014, 7:23 p.m. UTC | #2
On 12/11/2014 02:19 PM, Jason Merrill wrote:
> On 12/11/2014 12:44 PM, Aldy Hernandez wrote:
>> This context then gets changed here:
>>
>>        /* For local statics lookup proper context die.  */
>>        if (TREE_STATIC (decl)
>>        && DECL_CONTEXT (decl)
>>        && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
>>      context_die = lookup_decl_die (DECL_CONTEXT (decl));
>
> Can we remove this and just leave the context as NULL until it gets
> fixed up?

Never mind, it looks like that'll require more work in gen_variable_die. 
  Your patch looks fine.

Jason
Aldy Hernandez Dec. 11, 2014, 7:26 p.m. UTC | #3
On 12/11/14 11:23, Jason Merrill wrote:
> On 12/11/2014 02:19 PM, Jason Merrill wrote:
>> On 12/11/2014 12:44 PM, Aldy Hernandez wrote:
>>> This context then gets changed here:
>>>
>>>        /* For local statics lookup proper context die.  */
>>>        if (TREE_STATIC (decl)
>>>        && DECL_CONTEXT (decl)
>>>        && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
>>>      context_die = lookup_decl_die (DECL_CONTEXT (decl));
>>
>> Can we remove this and just leave the context as NULL until it gets
>> fixed up?
>
> Never mind, it looks like that'll require more work in gen_variable_die.
>   Your patch looks fine.

Hah, I was just going to say that :).

I will push my patch to the branch.

Thanks for your input.
Aldy

Patch
diff mbox

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index e4a7973..5d55d1f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -18511,7 +18511,9 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	 apply; we just use the old DIE.  */
       expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
       struct dwarf_file_data * file_index = lookup_filename (s.file);
-      if (((is_cu_die (old_die->die_parent) || context_die == NULL)
+      if (((is_cu_die (old_die->die_parent)
+	    || context_die == NULL
+	    || dumped_early)
 	   && (DECL_ARTIFICIAL (decl)
 	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
 		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
@@ -19132,6 +19134,17 @@  decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration)
 	  && get_AT_flag (old_die, DW_AT_declaration) == 1);
 }
 
+/* Return true if DECL is a local static.  */
+
+static inline bool
+local_function_static (tree decl)
+{
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  return TREE_STATIC (decl)
+    && DECL_CONTEXT (decl)
+    && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
 /* Generate a DIE to represent a declared data object.
    Either DECL or ORIGIN must be non-null.  */
 
@@ -19283,13 +19296,35 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	}
       else if (old_die->die_parent != context_die)
 	{
-	  /* If the contexts differ, it means we're not talking about
-	     the same thing.  Clear things so we can get a new DIE.
-	     This can happen when creating an inlined instance, in
-	     which case we need to create a new DIE that will get
-	     annotated with DW_AT_abstract_origin.  */
-	  old_die = NULL;
-	  gcc_assert (!DECL_ABSTRACT_P (decl));
+	  /* If the contexts differ, it means we _MAY_ not be talking
+	     about the same thing.  */
+	  if (origin)
+	    {
+	      /* If we will be creating an inlined instance, we need a
+		 new DIE that will get annotated with
+		 DW_AT_abstract_origin.  Clear things so we can get a
+		 new DIE.  */
+	      gcc_assert (!DECL_ABSTRACT_P (decl));
+	      old_die = NULL;
+	    }
+	  else
+	    {
+	      /* Otherwise, the only reasonable alternate way of
+		 getting here is during the final dwarf pass, when
+		 being called on a local static.  We can end up with
+		 different contexts because the context_die is set to
+		 the context of the containing function, whereas the
+		 cached die (old_die) is correctly set to the
+		 (possible) enclosing lexical scope
+		 (DW_TAG_lexical_block).  In which case, special
+		 handle it (hack).
+
+		 See dwarf2out_decl and its use of
+		 local_function_static to see how this happened.  */
+	      gcc_assert (local_function_static (decl));
+	      var_die = old_die;
+	      goto gen_variable_die_location;
+	    }
 	}
       else
 	{
@@ -21563,9 +21598,7 @@  dwarf2out_decl (tree decl)
 	return NULL;
 
       /* For local statics lookup proper context die.  */
-      if (TREE_STATIC (decl)
-	  && DECL_CONTEXT (decl)
-	  && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+      if (local_function_static (decl))
 	context_die = lookup_decl_die (DECL_CONTEXT (decl));
 
       /* If we are in terse mode, don't generate any DIEs to represent any