Debugging "missing callgraph edge for call stmt"

Johannes Pfau nospam at example.com
Thu Jan 3 08:12:32 PST 2013


Am Wed, 2 Jan 2013 00:12:03 +0000
schrieb Iain Buclaw <ibuclaw at 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) 


More information about the D.gnu mailing list