Index: llvm/lib/Analysis/CaptureTracking.cpp =================================================================== --- llvm/lib/Analysis/CaptureTracking.cpp +++ llvm/lib/Analysis/CaptureTracking.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/Support/CommandLine.h" using namespace llvm; @@ -240,6 +241,15 @@ switch (I->getOpcode()) { case Instruction::Call: case Instruction::Invoke: { + if (auto *II = dyn_cast(I)) + if (II->getIntrinsicID() == Intrinsic::noalias || + II->getIntrinsicID() == Intrinsic::provenance_noalias || + II->getIntrinsicID() == Intrinsic::noalias_arg_guard || + II->getIntrinsicID() == Intrinsic::noalias_copy_guard) { + AddUses(I); + break; + } + auto *Call = cast(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 Index: llvm/test/Transforms/FunctionAttrs/nocapture.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -106,6 +106,40 @@ ret i32 %val } +; FNATTR: 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.p0i8.p0p0i32.i32(i32* %p, i8* null, i32** null, i32 0, 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 +} + +; FNATTR: define i32 @nc1b(i32* %q, i32* nocapture %p, i1 %b) +define i32 @nc1b(i32* %q, i32* %p, i1 %b) { +e: + %prov.p = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %p, i8* null, i32** null, i32** null, i32 0, metadata !1) + br label %l +l: + %x = phi i32* [ %p, %e ] + %prov.x = phi i32* [ %prov.p, %e ] + %y = phi i32* [ %q, %e ] + %tmp = bitcast i32* %x to i32* ; [#uses=2] + %tmp2 = select i1 %b, i32* %tmp, i32* %y + %prov.tmp2 = select i1 %b, i32* %prov.x, i32* %y + %val = load i32, i32* %tmp2 ; [#uses=1] + store i32 0, i32* %tmp, ptr_provenance i32* %prov.tmp2 + store i32* %y, i32** @g + ret i32 %val +} + ; FNATTR: 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: @@ -319,3 +353,9 @@ declare i8* @llvm.launder.invariant.group.p0i8(i8*) declare i8* @llvm.strip.invariant.group.p0i8(i8*) + +declare i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32*, i8*, i32**, i32, metadata ) nounwind +declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata ) nounwind + +!0 = !{!0, !"some domain"} +!1 = !{!1, !0, !"some scope"}