Meaning of the nocapture attribute (possible bug?)

Regarding the nocapture attribute the language ref says: "the callee does not make any copies of the pointer that outlive the callee itself".

From I inferred that it is OK for the callee to make a copy of the

pointer that doesn't outlive the call. However if I write some code that does this the optimizers don't do what I'd expect. Consider the following the example:

declare void @g(i32** %p, i32* %q) nounwind

define i32 @f(i32* noalias nocapture %p) nounwind {
entry:
   %q = alloca i32*
   call void @g(i32** %q, i32* %p) nounwind
   store i32 0, i32* %p
   %0 = load i32** %q
   store i32 1, i32* %0
   %1 = load i32* %p
   ret i32 %1
}

I would expect it to be valid for g() to store the value of its second argument to the object pointed to by its first argument. Because of this I would expect a possible memory dependency between the last load (%1 = load i32* %p) and the last store (store i32 1, i32* %0). However if I run the example through opt -basicaa -gvn then the return instruction is optimized to ret i32 0 suggesting basicaa doesn't think there is any such dependency.

Is this a bug in the basic alias analysis pass or am I misunderstanding the semantics of nocapture?

Hi Richard, I think it is a bug.

Ciao, Duncan.

Thanks for your reply, I've filed this as PR14045:

http://llvm.org/bugs/show_bug.cgi?id=14045

Is this code valid?

Function f takes a "nocapture" pointer p, and passes it to function g that does not have nocapture in its parameter list. There is nothing to stop g from "capturing" p.

-Krzysztof

Hi Krzysztof,

Is this code valid?

yes, I think so.

Function f takes a "nocapture" pointer p, and passes it to function g that does
not have nocapture in its parameter list. There is nothing to stop g from
"capturing" p.

It would be wrong for the optimizers to deduce a nocapture attribute for f in
this context, as they don't know anything about the semantics of g. However if
whoever produced this bitcode knows the semantics of g, for example because it
is some funky routine in their runtime, then it could be correct. For example, consider this definition of g:

define void @g(i32** %q, i32* %p) {
   store i32* %p, i32** %q
   ret void
}

In general this function captures the %p argument. But in the special way it
is used from f, it doesn't result in f capturing its %p argument.

Ciao, Duncan.

Ok, that makes sense.

-K