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 @@ -407,7 +407,7 @@ /// it shouldn't look through the phi above. void getUnderlyingObjects(const Value *V, SmallVectorImpl &Objects, - LoopInfo *LI = nullptr, unsigned MaxLookup = 6); + LoopInfo *LI = nullptr); /// This is a wrapper around getUnderlyingObjects and adds support for basic /// ptrtoint+arithmetic+inttoptr sequences. 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 @@ -4358,17 +4358,25 @@ void llvm::getUnderlyingObjects(const Value *V, SmallVectorImpl &Objects, - LoopInfo *LI, unsigned MaxLookup) { + LoopInfo *LI) { SmallPtrSet Visited; SmallVector Worklist; Worklist.push_back(V); do { const Value *P = Worklist.pop_back_val(); - P = getUnderlyingObject(P, MaxLookup); + P = getUnderlyingObject(P); if (!Visited.insert(P).second) continue; + const Value *U = P; + P = getUnderlyingObject(P); + if (U != P) { + // Repeat if getUnderlyingObject terminated on MaxLookup. + Worklist.push_back(P); + continue; + } + if (auto *SI = dyn_cast(P)) { Worklist.push_back(SI->getTrueValue()); Worklist.push_back(SI->getFalseValue()); diff --git a/llvm/test/Analysis/LoopAccessAnalysis/underlying-objects-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/underlying-objects-2.ll --- a/llvm/test/Analysis/LoopAccessAnalysis/underlying-objects-2.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/underlying-objects-2.ll @@ -93,8 +93,11 @@ ; CHECK-LABEL: function 'f_deep' ; CHECK: for_j.body: -; CHECK-NEXT: Memory dependences are safe with run-time checks -; CHECK-NEXT: Dependences: +; CHECK-NEXT: Report: unsafe dependent memory operations in loop +; CHECK-NEXT: Dependences: +; CHECK-NEXT: Unknown: +; CHECK-NEXT: %loadB = load i8, i8* %gepB9, align 1 -> +; CHECK-NEXT: store i8 2, i8* %gepB_plus_one, align 1 define void @f_deep(i8** noalias %A, i8* noalias %B, i64 %N) { for_i.preheader: diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp --- a/llvm/unittests/Analysis/ValueTrackingTest.cpp +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -2102,6 +2102,59 @@ } } +TEST_F(ValueTrackingTest, getUnderlyingObjects) { + auto M = parseModule(R"( + define i32* @test() { + %a = alloca i32 + %1 = getelementptr i32, i32* %a, i32 1 + %2 = getelementptr i32, i32* %1, i32 1 + %3 = getelementptr i32, i32* %2, i32 1 + %4 = getelementptr i32, i32* %3, i32 1 + %5 = getelementptr i32, i32* %4, i32 1 + %6 = getelementptr i32, i32* %5, i32 1 + %7 = getelementptr i32, i32* %6, i32 1 + %8 = getelementptr i32, i32* %7, i32 1 + %9 = getelementptr i32, i32* %8, i32 1 + %r = getelementptr i32, i32* %9, i32 1 + ret i32* %r + })"); + Function *F = M->getFunction("test"); + Instruction *I = &findInstructionByName(F, "r"); + SmallVector Objects; + getUnderlyingObjects(I->getOperand(0), Objects); + EXPECT_EQ(1u, Objects.size()); + EXPECT_EQ(1, isa(Objects[0])); +} + +TEST_F(ValueTrackingTest, getUnderlyingObjectsCycle) { + auto M = parseModule(R"( + define void @test() { + entry: + br label %bb1 + + bb1: + %a = phi i32* [ %r, %bb1 ] + %0 = getelementptr i32, i32* %a, i32 1 + %1 = getelementptr i32, i32* %0, i32 1 + %2 = getelementptr i32, i32* %1, i32 1 + %3 = getelementptr i32, i32* %2, i32 1 + %4 = getelementptr i32, i32* %3, i32 1 + %5 = getelementptr i32, i32* %4, i32 1 + %6 = getelementptr i32, i32* %5, i32 1 + %7 = getelementptr i32, i32* %6, i32 1 + %8 = getelementptr i32, i32* %7, i32 1 + %9 = getelementptr i32, i32* %8, i32 1 + %r = getelementptr i32, i32* %9, i32 1 + br label %bb1 + + })"); + Function *F = M->getFunction("test"); + Instruction *I = &findInstructionByName(F, "r"); + SmallVector Objects; + getUnderlyingObjects(I, Objects); + EXPECT_TRUE(Objects.empty()); +} + struct FindAllocaForValueTestParams { const char *IR; bool AnyOffsetResult;