From patchwork Wed Nov 24 04:48:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [PR,debug/46583] don't prune local type decls Date: Tue, 23 Nov 2010 18:48:50 -0000 From: Alexandre Oliva X-Patchwork-Id: 72789 Message-Id: To: gcc-patches@gcc.gnu.org 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 ;-) for gcc/ChangeLog from Alexandre Oliva PR debug/46583 * tree-ssa-live.c (remove_unused_scope_block_p): Keep type decls. for gcc/testsuite/ChangeLog from Alexandre Oliva 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 < >()); +}