diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 82c87edd6297c..d9f8a76d3cbc2 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -693,6 +693,13 @@ inline Value *getArgumentAliasingToReturnedPointer(CallBase *Call, 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 index 0d6d30923bb54..785a9dd22b75b 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -387,7 +387,11 @@ UseCaptureKind llvm::DetermineUseCaptureKind( 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 index 8c29c242215d6..3dd035ac49a33 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -5968,6 +5968,31 @@ static bool isSameUnderlyingObjectInLoop(const PHINode *PN, 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 index 031a8be971abd..093d9445e39d7 100644 --- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -900,20 +900,20 @@ define void @readnone_indirec(ptr %f, ptr %p) { 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 @@ -921,7 +921,7 @@ define i1 @compare_offsets(ptr %p) { 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 index 73dd82fb921f7..8fcbbbaae6d62 100644 --- a/llvm/unittests/Analysis/CaptureTrackingTest.cpp +++ b/llvm/unittests/Analysis/CaptureTrackingTest.cpp @@ -105,11 +105,10 @@ TEST(CaptureTracking, MultipleUsesInSameInstruction) { 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 @@ TEST(CaptureTracking, MultipleUsesInSameInstruction) { // 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()); }