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 @@ -413,10 +413,12 @@ bool getUnderlyingObjectsForCodeGen(const Value *V, SmallVectorImpl &Objects); - /// Finds alloca where the value comes from. - AllocaInst *findAllocaForValue(Value *V); - inline const AllocaInst *findAllocaForValue(const Value *V) { - return findAllocaForValue(const_cast(V)); + /// Returns unique alloca where the value comes from, or nullptr. + /// If OffsetZero is true check that V points to the begining of the alloca. + AllocaInst *findAllocaForValue(Value *V, bool OffsetZero = false); + inline const AllocaInst *findAllocaForValue(const Value *V, + bool OffsetZero = false) { + return findAllocaForValue(const_cast(V), OffsetZero); } /// Return true if the only users of this pointer are lifetime markers. 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 @@ -4331,7 +4331,8 @@ } static AllocaInst * -findAllocaForValue(Value *V, DenseMap &AllocaForValue) { +findAllocaForValue(Value *V, DenseMap &AllocaForValue, + bool OffsetZero) { if (AllocaInst *AI = dyn_cast(V)) return AI; // See if we've already calculated (or started to calculate) alloca for a @@ -4344,36 +4345,46 @@ AllocaForValue[V] = nullptr; AllocaInst *Res = nullptr; if (CastInst *CI = dyn_cast(V)) - Res = findAllocaForValue(CI->getOperand(0), AllocaForValue); - else if (auto *SI = dyn_cast(V)) { - Res = findAllocaForValue(SI->getTrueValue(), AllocaForValue); - if (!Res) - return nullptr; - AllocaInst *F = findAllocaForValue(SI->getFalseValue(), AllocaForValue); - if (F != Res) - return nullptr; - } else if (PHINode *PN = dyn_cast(V)) { + Res = findAllocaForValue(CI->getOperand(0), AllocaForValue, OffsetZero); + else if (PHINode *PN = dyn_cast(V)) { for (Value *IncValue : PN->incoming_values()) { // Allow self-referencing phi-nodes. if (IncValue == PN) continue; - AllocaInst *IncValueAI = findAllocaForValue(IncValue, AllocaForValue); + AllocaInst *IncValueAI = + findAllocaForValue(IncValue, AllocaForValue, OffsetZero); // AI for incoming values should exist and should all be equal. if (IncValueAI == nullptr || (Res != nullptr && IncValueAI != Res)) return nullptr; Res = IncValueAI; } - } else if (GetElementPtrInst *EP = dyn_cast(V)) { - Res = findAllocaForValue(EP->getPointerOperand(), AllocaForValue); + } else if (auto *SI = dyn_cast(V)) { + Res = findAllocaForValue(SI->getTrueValue(), AllocaForValue, OffsetZero); + if (!Res) + return nullptr; + AllocaInst *F = + findAllocaForValue(SI->getFalseValue(), AllocaForValue, OffsetZero); + if (F != Res) + return nullptr; + } else if (GetElementPtrInst *GEP = dyn_cast(V)) { + if (OffsetZero) { + for (unsigned i = 1; i < GEP->getNumOperands(); ++i) { + ConstantInt *OpC = dyn_cast(GEP->getOperand(i)); + if (!OpC || !OpC->isZero()) + return nullptr; + } + } + Res = findAllocaForValue(GEP->getPointerOperand(), AllocaForValue, + OffsetZero); } if (Res) AllocaForValue[V] = Res; return Res; } -AllocaInst *llvm::findAllocaForValue(Value *V) { +AllocaInst *llvm::findAllocaForValue(Value *V, bool OffsetZero) { DenseMap AllocaForValue; - return ::findAllocaForValue(V, AllocaForValue); + return ::findAllocaForValue(V, AllocaForValue, OffsetZero); } static bool onlyUsedByLifetimeMarkersOrDroppableInstsHelper( 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 @@ -1433,28 +1433,38 @@ class FindAllocaForValueTest : public ValueTrackingTest, - public ::testing::WithParamInterface> { + public ::testing::WithParamInterface< + std::pair>> { protected: }; -const std::pair FindAllocaForValueTests[] = { - {R"( +const std::pair> FindAllocaForValueTests[] = + { + {R"( define void @test() { %a = alloca i64 %r = bitcast i64* %a to i32* ret void })", - true}, + {true, true}}, - {R"( + {R"( define void @test() { %a = alloca i32 %r = getelementptr i32, i32* %a, i32 1 ret void })", - true}, + {true, false}}, + + {R"( + define void @test() { + %a = alloca i32 + %r = getelementptr i32, i32* %a, i32 0 + ret void + })", + {true, true}}, - {R"( + {R"( define void @test(i1 %cond) { entry: %a = alloca i32 @@ -1467,26 +1477,26 @@ exit: ret void })", - true}, + {true, true}}, - {R"( + {R"( define void @test(i1 %cond) { %a = alloca i32 %r = select i1 %cond, i32* %a, i32* %a ret void })", - true}, + {true, true}}, - {R"( + {R"( define void @test(i1 %cond) { %a = alloca i32 %b = alloca i32 %r = select i1 %cond, i32* %a, i32* %b ret void })", - false}, + {false, false}}, - {R"( + {R"( define void @test(i1 %cond) { entry: %a = alloca i64 @@ -1501,9 +1511,9 @@ exit: ret void })", - true}, + {true, false}}, - {R"( + {R"( define void @test(i1 %cond) { entry: %a = alloca i64 @@ -1518,17 +1528,17 @@ exit: ret void })", - false}, + {false, false}}, - {R"( + {R"( define void @test(i1 %cond, i64* %a) { entry: %r = bitcast i64* %a to i32* ret void })", - false}, + {false, false}}, - {R"( + {R"( define void @test(i1 %cond) { entry: %a = alloca i32 @@ -1542,7 +1552,7 @@ exit: ret void })", - false}, + {false, false}}, }; TEST_P(FindAllocaForValueTest, findAllocaForValue) { @@ -1550,7 +1560,15 @@ Function *F = M->getFunction("test"); Instruction *I = &findInstructionByName(F, "r"); const AllocaInst *AI = findAllocaForValue(I); - EXPECT_EQ(!!AI, GetParam().second); + EXPECT_EQ(!!AI, GetParam().second.first); +} + +TEST_P(FindAllocaForValueTest, findAllocaForValueZeroOffset) { + auto M = parseModule(GetParam().first); + Function *F = M->getFunction("test"); + Instruction *I = &findInstructionByName(F, "r"); + const AllocaInst *AI = findAllocaForValue(I, true); + EXPECT_EQ(!!AI, GetParam().second.second); } INSTANTIATE_TEST_CASE_P(FindAllocaForValueTest, FindAllocaForValueTest,