// then it has not escaped before entering the function. Check if it escapes
// inside the function.
if (const Argument *A = dyn_cast<Argument>(V))
- if (A->hasByValAttr() || A->hasNoAliasAttr()) {
- // Don't bother analyzing arguments already known not to escape.
- if (A->hasNoCaptureAttr())
- return true;
+ if (A->hasByValAttr() || A->hasNoAliasAttr())
+ // Note even if the argument is marked nocapture we still need to check
+ // for copies made inside the function. The nocapture attribute only
+ // specifies that there are no copies made that outlive the function.
return !PointerMayBeCaptured(V, false, /*StoreCaptures=*/true);
- }
+
return false;
}
ret i32 %c
}
+declare void @test3(i32** %p, i32* %q) nounwind
+
+define i32 @test4(i32* noalias nocapture %p) nounwind {
+; CHECK: call void @test3
+; CHECK: store i32 0, i32* %p
+; CHECK: store i32 1, i32* %x
+; CHECK: %y = load i32* %p
+; CHECK: ret i32 %y
+entry:
+ %q = alloca i32*
+ ; Here test3 might store %p to %q. This doesn't violate %p's nocapture
+ ; attribute since the copy doesn't outlive the function.
+ call void @test3(i32** %q, i32* %p) nounwind
+ store i32 0, i32* %p
+ %x = load i32** %q
+ ; This store might write to %p and so we can't eliminate the subsequent
+ ; load
+ store i32 1, i32* %x
+ %y = load i32* %p
+ ret i32 %y
+}