Patchwork [PR,debug/46583] don't prune local type decls

login
register
mail settings
Submitter Alexandre Oliva
Date Nov. 24, 2010, 4:48 a.m.
Message ID <orfwurqqbx.fsf@livre.localdomain>
Download mbox | patch
Permalink /patch/72789/
State New
Headers show

Comments

Alexandre Oliva - Nov. 24, 2010, 4:48 a.m.
Dropping type decls from block locals before inlining affects DECL_UID
ordering, which may in turn cause -g/-g0 codegen differences.  In the
given testcase, it's just a -fcompare-debug error, but the test could
presumably be expanded to trigger actual differences in codegen.

The problem is that, when we discard a typedef decl from a lexical
block, and then inline or clone it, we fail to remap it and its
underlying type at that moment.  We may remap other decls before we even
get a chance to get to it: if some variable decl uses that type, we'll
remap the variable before remapping the type, so we've already
introduced differences.  It would get worse if other significant decls
stood in between the typedef and the variable decl.

The problem is further complicated because the decision on whether the
variable can be nonlocalized depends on whether its type, if needing
remapping, was already remapped when the time comes to remap the
variable.  So, if we've removed the typedef from its lexical block and
there's no intervening use of the type, we won't have remapped it yet,
and the variable will be kept in the local list.  I'm not sure whether
this may have additional implications for codegen.

I'm a bit concerned that the problem might be even more serious:
discarding random variable declarations might change the order of
remapping of types, and change which variables are regarded as
nonlocalized, both of which might have implications to codegen (the
first one certainly would).

Now, in C and C++, only local types would have to be remapped in this
way (global types would reuse the same type AFAIK), and then, if we keep
local type decls around, we'll remap them before we get to the
variables, and everything should be fine.  I'm concerned, however, that
this may not hold for other languages, or maybe even in GNU-extended
versions of C (nested functions referencing local types of the enclosing
function come to mind).

Anyhow, it seems to me that dropping local type decls from lexical
scopes doesn't buy us much, and even though it is indeed a sledgehammer,
as richi put it, this fixes the problem, and I can't envision other
simpler solutions that wouldn't risk running into the problems mentioned
above, so...

Regstrapped on x86_64-linux-gnu and i686-pc-linux-gnu.  Ok to install?


One solution I do envision, which might help, would be to try to figure
out which types are unused, and discard those.  Say, scan all variables
within a lexical scope (including nested blocks), deciding which ones
can be discarded, and then, as we move out of the nesting, we can
decide, from last to first, which types are unused, and mark as used
types refereced from retained variables and other types that are used,
removing those that, when reached during this backward scan, remain
marked as unused.  Or something along these lines, taking nested
functions into account, if needed, and anything else I may have missed
;-)

Patch

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/46583
	* tree-ssa-live.c (remove_unused_scope_block_p): Keep type decls.

for  gcc/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/46583
	* g++.dg/debug/pr46583.C: New.

Index: gcc/tree-ssa-live.c
===================================================================
--- gcc/tree-ssa-live.c.orig	2010-11-21 04:57:04.505193778 -0200
+++ gcc/tree-ssa-live.c	2010-11-21 04:53:31.279647303 -0200
@@ -491,11 +491,16 @@  remove_unused_scope_block_p (tree scope)
 	 can be considered dead.  We only want to keep around blocks user can
 	 breakpoint into and ask about value of optimized out variables.
 
-	 Similarly we need to keep around types at least until all variables of
-	 all nested blocks are gone.  We track no information on whether given
-	 type is used or not.  */
+	 Similarly we need to keep around types at least until all
+	 variables of all nested blocks are gone.  We track no
+	 information on whether given type is used or not, so we have
+	 to keep them even when not emitting debug information,
+	 otherwise we may end up remapping variables and their (local)
+	 types in different orders depending on whether debug
+	 information is being generated.  */
 
-      else if (debug_info_level == DINFO_LEVEL_NORMAL
+      else if (TREE_CODE (*t) == TYPE_DECL
+	       || debug_info_level == DINFO_LEVEL_NORMAL
 	       || debug_info_level == DINFO_LEVEL_VERBOSE)
 	;
       else
Index: gcc/testsuite/g++.dg/debug/pr46583.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/g++.dg/debug/pr46583.C	2010-11-21 04:56:07.361194389 -0200
@@ -0,0 +1,40 @@ 
+// PR debug/46583
+// { dg-do compile }
+// { dg-options "-O -fno-inline -fipa-cp -fipa-cp-clone -fcompare-debug" }
+
+template < typename = unsigned long >struct A
+{
+  unsigned long elems[3];
+  unsigned long *begin ()
+  {
+    return 0;
+  }
+};
+
+void
+bar (unsigned long *a1, unsigned long, unsigned long *a3, unsigned const &)
+{
+  *a3 = *a1;
+}
+
+A < >operatorM (A < >a1, unsigned long a2)
+{
+  typedef A < >G;
+  G a3;
+  bar (a1.begin (), a2, a3.begin (), 0);
+  return a3;
+}
+
+struct B
+{
+  B (A < >m):n (operatorM (m, 1))
+  {
+  }
+  A < >n;
+};
+
+void
+foo ()
+{
+  B (A < >());
+}