call graph not complete

Consider C code

void foo();

int main(void) {

foo();

return 0;

}

void foo(void) {

int a =10;

}

Bitcode generated by clang with –O0 is :

define i32 @main() nounwind {

entry:

%retval = alloca i32 ; <i32*> [#uses=3]

store i32 0, i32* %retval

call void (…)* bitcast (void ()* @foo to void (…)*)()

store i32 0, i32* %retval

%0 = load i32* %retval ; [#uses=1]

ret i32 %0

}

define void @foo() nounwind {

entry:

%a = alloca i32, align 4 ; <i32*> [#uses=1]

store i32 10, i32* %a

ret void

}

Bitcode generated by llvm-ld with –disable-opt and –basiccg options is:

define i32 @main() nounwind {

entry:

%retval = alloca i32 ; <i32*> [#uses=3]

store i32 0, i32* %retval

call void (…)* bitcast (void ()* @foo to void (…)*)()

store i32 0, i32* %retval

%0 = load i32* %retval ; [#uses=1]

ret i32 %0

}

define void @foo() nounwind {

entry:

%a = alloca i32, align 4 ; <i32*> [#uses=1]

store i32 10, i32* %a

ret void

}

My point is why is the call to foo not resolved correctly in llvm-ld. Here if I try to make use of the call graph pass to get the call graph, I do not get the complete call graph.

Thanks

Vasudev

Hi,

Bitcode generated by llvm-ld with –disable-opt and –basiccg options is:

...

My point is why is the call to foo not resolved correctly in llvm-ld.

Resolving an call to a direct call is an optimization. But you turned all
optimizations off.

Ciao,

Duncan.

Duncan Sands wrote:

Hi,

Bitcode generated by llvm-ld with –disable-opt and –basiccg options is:
    
...

My point is why is the call to foo not resolved correctly in llvm-ld.
    
Resolving an call to a direct call is an optimization. But you turned all
optimizations off.
  

How can we just selectively turn only that optimization ON?
We don't want to turn on a whole lot of other stuff that instcombine does as they mess up debugging in our case.

- Sanjiv

Hi Sanjiv,

How can we just selectively turn only that optimization ON?

you can't. That said, you could write your own pass that does it.

We don't want to turn on a whole lot of other stuff that instcombine does as they mess up debugging in our case.

If instcombine makes debug info useless, then that's rather bad. Can
you please explain more about this.

Ciao,

Duncan.

Duncan Sands wrote:

Hi Sanjiv,

How can we just selectively turn only that optimization ON?

you can't. That said, you could write your own pass that does it.

We don't want to turn on a whole lot of other stuff that instcombine does as they mess up debugging in our case.

If instcombine makes debug info useless, then that's rather bad. Can
you please explain more about this.

multiple loads/stores to individual bitfields of a type are combined into single load/store and there are no generated code for certain C statements.

Sanjiv Gupta wrote:

Duncan Sands wrote:
  

Hi Sanjiv,

How can we just selectively turn only that optimization ON?
      

you can't. That said, you could write your own pass that does it.

We don't want to turn on a whole lot of other stuff that instcombine does as they mess up debugging in our case.
      

If instcombine makes debug info useless, then that's rather bad. Can
you please explain more about this.
    

multiple loads/stores to individual bitfields of a type are combined into single load/store and there are no generated code for certain C statements.

I think I was not clear enough in my previous email.
Our requirement is a little peculiar. We want debugging to work better when no optimizations are specified but at the same time we want the call resolve to happen as we do function frame overlaying on top of the call graph.

So, it does not necessarily mean that -instcombine is messing up the debug info.

- Sanjiv

Duncan Sands wrote:

Hi,

Bitcode generated by llvm-ld with –disable-opt and –basiccg options is:
    
...

My point is why is the call to foo not resolved correctly in llvm-ld.
    
Resolving an call to a direct call is an optimization. But you turned all
optimizations off.

BTW, why do clang generates an indirect call in the first place for the program given in the original post? Does c99 tell us to generate an indirect call when the prototype is like this
  void foo();

?

- Sanjiv

C99 doesn’t tell us to generate an indirect call, but it does tell us that we can’t make assumptions about the actual signature of foo (other than the return type). That matters here because it means we have no idea what that signature is when we’re generating code for main(). You could easily write:

void foo();
int main() {
foo();
}

void foo(int i) {
}

If we codegenned this as a direct call, we’d get:

define i32 @main() nounwind {
entry:
call void (…)* @foo()
ret i32 0
}

define void @foo(i32) nounwind {
entry:
ret void
}

This is a type error, because @foo is not of type void (…)*.

We could work around this specific problem by delaying code-generation for @main until we see the definition of foo, but that still wouldn’t work for e.g. link-time optimization.

John.

Duncan Sands wrote:

Hi,

Bitcode generated by llvm-ld with –disable-opt and –basiccg options is:
    
...

My point is why is the call to foo not resolved correctly in llvm-ld.
    
Resolving an call to a direct call is an optimization. But you turned all
optimizations off.

Ciao,

Duncan.

Resolving an call to a direct call is an optimization. But you turned all
optimizations off.

Ciao,

Duncan.
  

Shouldn't the call resolution be part of call graph analysis?

- Sanjiv

Hi,

Shouldn't the call resolution be part of call graph analysis?

since it's an analysis, it shouldn't be modifying bitcode, for example by
simplifying calls. That said, it would be easy to teach it to look through
this kind of simple bitcast.

Ciao,

Duncan.