diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -628,6 +628,13 @@ bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing( const CallBase *Call, bool MustPreserveNullness); +/// This method is a wrapper around getUnderlyingObject to look through PHI +/// nodes. This method will attempt to build a new underlying object based on +/// the incoming values. This method can have high compile time implications and +/// cannot be used as a direct replacement for getUnderlyingObject. +const Value *getUnderlyingObjectLookThrough(const Value *V, + unsigned MaxLookup = 6); + /// This method strips off any GEP address adjustments and pointer casts from /// the specified value, returning the original object being addressed. Note /// that the returned value has pointer type if the specified value does. If diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -411,7 +411,11 @@ if (IsDereferenceableOrNull && IsDereferenceableOrNull(O, DL)) return UseCaptureKind::NO_CAPTURE; } - } + } else if (cast(I)->isEquality() && + getUnderlyingObjectLookThrough(I->getOperand(Idx)) == + getUnderlyingObjectLookThrough(I->getOperand(OtherIdx))) + // Equality comparisons against the same pointer do not capture. + return UseCaptureKind::NO_CAPTURE; // Otherwise, be conservative. There are crazy ways to capture pointers // using comparisons. diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -5654,6 +5654,31 @@ return true; } +const Value *llvm::getUnderlyingObjectLookThrough(const Value *V, unsigned MaxLookup) { + V = getUnderlyingObject(V, MaxLookup); + + const PHINode *PN = dyn_cast(V); + if (!PN) + return V; + + // We can look through PHIs if each underlying value has the same underlying + // object, or is the phi itself. + const Value *NewUnderlying = PN; + for (const Value *Incoming : PN->incoming_values()) { + const Value *IncomingUnderlying = getUnderlyingObject(Incoming, MaxLookup); + if (IncomingUnderlying == PN || IncomingUnderlying == NewUnderlying) + continue; + if (NewUnderlying == PN) + // Found a new possible underlying object. + NewUnderlying = IncomingUnderlying; + else + // There are >= 2 possible underlying objects. We cannot determine a new + // underlying object. + return V; + } + return NewUnderlying; +} + const Value *llvm::getUnderlyingObject(const Value *V, unsigned MaxLookup) { if (!V->getType()->isPointerTy()) return V; diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll --- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -333,20 +333,20 @@ ret void } -; FNATTR: define i1 @identity_icmp(ptr readnone %p) +; FNATTR: define i1 @identity_icmp(ptr nocapture readnone %p) define i1 @identity_icmp(ptr %p) { %r = icmp eq ptr %p, %p ret i1 %r } -; FNATTR: define i1 @compare_against_offset(ptr readnone %p) +; FNATTR: define i1 @compare_against_offset(ptr nocapture readnone %p) define i1 @compare_against_offset(ptr %p) { %offset = getelementptr inbounds i32, ptr %p, i64 1 %r = icmp eq ptr %p, %offset ret i1 %r } -; FNATTR: define i1 @compare_offsets(ptr readnone %p) +; FNATTR: define i1 @compare_offsets(ptr nocapture readnone %p) define i1 @compare_offsets(ptr %p) { %offset1 = getelementptr inbounds i32, ptr %p, i64 1 %offset2 = getelementptr inbounds i32, ptr %p, i64 2 @@ -354,7 +354,7 @@ ret i1 %r } -; FNATTR: define void @phi_induction(ptr writeonly %p, i64 %n, i32 %x) +; FNATTR: define void @phi_induction(ptr nocapture writeonly %p, i64 %n, i32 %x) define void @phi_induction(ptr %p, i64 %n, i32 %x) { start: %end = getelementptr inbounds i32, ptr %p, i64 %n diff --git a/llvm/unittests/Analysis/CaptureTrackingTest.cpp b/llvm/unittests/Analysis/CaptureTrackingTest.cpp --- a/llvm/unittests/Analysis/CaptureTrackingTest.cpp +++ b/llvm/unittests/Analysis/CaptureTrackingTest.cpp @@ -105,11 +105,10 @@ BasicBlock *BB = &F->getEntryBlock(); Instruction *Call = &*BB->begin(); Instruction *CmpXChg = Call->getNextNode(); - Instruction *ICmp = CmpXChg->getNextNode(); CollectingCaptureTracker CT; PointerMayBeCaptured(Arg, &CT); - EXPECT_EQ(7u, CT.Captures.size()); + EXPECT_EQ(5u, CT.Captures.size()); // Call arg 1 EXPECT_EQ(Call, CT.Captures[0]->getUser()); EXPECT_EQ(0u, CT.Captures[0]->getOperandNo()); @@ -125,10 +124,4 @@ // Cmpxchg new value operand EXPECT_EQ(CmpXChg, CT.Captures[4]->getUser()); EXPECT_EQ(2u, CT.Captures[4]->getOperandNo()); - // ICmp first operand - EXPECT_EQ(ICmp, CT.Captures[5]->getUser()); - EXPECT_EQ(0u, CT.Captures[5]->getOperandNo()); - // ICmp second operand - EXPECT_EQ(ICmp, CT.Captures[6]->getUser()); - EXPECT_EQ(1u, CT.Captures[6]->getOperandNo()); }