Am Wed, 2 Jan 2013 00:12:03 +0000 schrieb Iain Buclaw <ibuc...@ubuntu.com>:
> Only two suggestions I can give are: > > a) Make sure that indirectLess DECL_CONTEXT is topNIndex, and not > main in code generation ... OK, DECL_CONTEXT is correct. > b) Make sure that indirectLess is codegen'd and pushed before > topNIndex. What's the best way to verify this? I had a look at ObjectFile::outputFunction and the order is: algorithm2.topNIndex!().topNIndex.indirectLess algorithm2.topNIndex!().topNIndex algorithm2.topNIndex!().topNIndex.BinaryHeap!(indirectLess).BinaryHeap.percolateDown OK, I've stepped through way to much of gccs internals now trying to find out why gcc thinks indirectLess is unreachable, could be a backend bug but then I looked at the test case again: Isn't the compiler actually right in removing indirectLess? indirectLess as a nested function can't be accessed outside of the topNIndex function, correct? It's then passed to BinaryHeap, OK. BinaryHeaps percolateDown could access indirectLess, but: topNIndex never calls percolateDown. But outside of topNIndex BinaryHeap!(indirectLess).percolateDown can't be called, is that correct? So in the end it's correct that indirectLess isn't reachable? Then the problem is that gcc thinks BinaryHeap!(indirectLess).percolateDown is a unit entry point - afaics it's not as it can't be called outside of topNIndex. GCC assumes all functions marked with TREE_PUBLIC are valid entry points... So do we have to set TREE_PUBLIC=false for functions which are part of a template instance (or nested struct/class) which is only valid in a certain scope? (experimenting shows we then also have to set DECL_WEAK and DECL_COMDAT to false) Or we have to set TREE_PUBLIC(indirectLess) = true. Currently we have indirectLess=false but percolateDown=true Then there's the question why the outer function has to be a template as well for this to happen: It's because if it's not a template, gdc uses a completely different code path: There's a "!gen.functionNeedsChain (f)" check in outputFunction which is false for the failing case. (cgraph_finalize_function marks the function as reachable) cgraphunit.c:cgraph_decide_is_function_needed /* Determine if function DECL is needed. That is, visible to something either outside this translation unit, something magic in the system configury. */ /* Externally visible functions must be output. The exception is COMDAT functions that must be output only when they are needed. [...] */ if (((TREE_PUBLIC (decl) || (!optimize && !node->same_body_alias && !DECL_DISREGARD_INLINE_LIMITS (decl) && !DECL_DECLARED_INLINE_P (decl) && !(DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL))) && !flag_whole_program && !flag_lto) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) BTW: I think that this isn't happening in gcc-4.8 is pure luck. Most of the cgraph_analyze* functions have been rewritten in gcc-4.8. But I think this specific case is still bogus (we tell the backend that we can access percolateDown from outside the unit even though it requires access to a function which is only valid in a limited scope)