Index: lib/Analysis/CaptureTracking.cpp =================================================================== --- lib/Analysis/CaptureTracking.cpp +++ lib/Analysis/CaptureTracking.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" using namespace llvm; @@ -233,9 +234,35 @@ Instruction *I = cast(U->getUser()); V = U->get(); + auto Passthrough = [&]() { + // The original value is not captured via this if the new value isn't. + Count = 0; + for (Use &UU : I->uses()) { + // If there are lots of uses, conservatively say that the value + // is captured to avoid taking too much compile time. + if (Count++ >= Threshold) { + Tracker->tooManyUses(); + return false; + } + + if (Visited.insert(&UU).second) + if (Tracker->shouldExplore(&UU)) + Worklist.push_back(&UU); + } + + return true; + }; + switch (I->getOpcode()) { case Instruction::Call: case Instruction::Invoke: { + if (auto *II = dyn_cast(I)) + if (II->getIntrinsicID() == Intrinsic::noalias) { + if (!Passthrough()) + return; + break; + } + CallSite CS(I); // Not captured if the callee is readonly, doesn't return a copy through // its return value and doesn't unwind (a readonly function can leak bits @@ -312,18 +339,8 @@ case Instruction::PHI: case Instruction::Select: case Instruction::AddrSpaceCast: - // The original value is not captured via this if the new value isn't. - Count = 0; - for (Use &UU : I->uses()) { - // If there are lots of uses, conservatively say that the value - // is captured to avoid taking too much compile time. - if (Count++ >= Threshold) - return Tracker->tooManyUses(); - - if (Visited.insert(&UU).second) - if (Tracker->shouldExplore(&UU)) - Worklist.push_back(&UU); - } + if (!Passthrough()) + return; break; case Instruction::ICmp: { // Don't count comparisons of a no-alias return value against null as Index: test/Transforms/FunctionAttrs/nocapture.ll =================================================================== --- test/Transforms/FunctionAttrs/nocapture.ll +++ test/Transforms/FunctionAttrs/nocapture.ll @@ -91,6 +91,22 @@ ret i32 %val } +; CHECK: define i32 @nc1a(i32* %q, i32* nocapture %p, i1 %b) +define i32 @nc1a(i32* %q, i32* %p, i1 %b) { +e: + %pa = call i32* @llvm.noalias.p0i32(i32* %p, metadata !1) + br label %l +l: + %x = phi i32* [ %pa, %e ] + %y = phi i32* [ %q, %e ] + %tmp = bitcast i32* %x to i32* ; [#uses=2] + %tmp2 = select i1 %b, i32* %tmp, i32* %y + %val = load i32, i32* %tmp2 ; [#uses=1] + store i32 0, i32* %tmp + store i32* %y, i32** @g + ret i32 %val +} + ; CHECK: define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b) define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* %p, i1 %b) { e: @@ -218,3 +234,9 @@ store volatile i32 0, i32* %gep, align 4 ret void } + +declare i32* @llvm.noalias.p0i32(i32*, metadata) nounwind + +!0 = !{!0, !"some domain"} +!1 = !{!1, !0, !"some scope"} +