Index: lib/Analysis/CaptureTracking.cpp =================================================================== --- lib/Analysis/CaptureTracking.cpp +++ lib/Analysis/CaptureTracking.cpp @@ -25,6 +25,8 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" using namespace llvm; @@ -188,9 +190,30 @@ 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) + return Tracker->tooManyUses(); + + if (Visited.insert(&UU).second) + if (Tracker->shouldExplore(&UU)) + Worklist.push_back(&UU); + } + }; + switch (I->getOpcode()) { case Instruction::Call: case Instruction::Invoke: { + if (IntrinsicInst *II = dyn_cast(I)) + if (II->getIntrinsicID() == Intrinsic::noalias) { + Passthrough(); + 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 @@ -231,18 +254,7 @@ 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); - } + Passthrough(); break; case Instruction::ICmp: // Don't count comparisons of a no-alias return value against null as @@ -251,7 +263,7 @@ if (ConstantPointerNull *CPN = dyn_cast(I->getOperand(1))) if (CPN->getType()->getAddressSpace() == 0) - if (isNoAliasCall(V->stripPointerCasts())) + if (isNoAliasCall(V->stripPointerCasts(true))) break; // Otherwise, be conservative. There are crazy ways to capture pointers // using comparisons. 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: @@ -193,3 +209,8 @@ ret void } +declare i32* @llvm.noalias.p0i32(i32*, metadata) nounwind + +!0 = !{!0, !"some domain"} +!1 = !{!1, !0, !"some scope"} +