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,7 +1433,8 @@ struct FindAllocaForValueTestParams { const char *IR; - bool Result; + bool AnyOffsetResult; + bool ZeroOffsetResult; }; class FindAllocaForValueTest @@ -1449,7 +1450,7 @@ %r = bitcast i64* %a to i32* ret void })", - true}, + true, true}, {R"( define void @test() { @@ -1457,7 +1458,15 @@ %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"( define void @test(i1 %cond) { @@ -1472,7 +1481,7 @@ exit: ret void })", - true}, + true, true}, {R"( define void @test(i1 %cond) { @@ -1480,7 +1489,7 @@ %r = select i1 %cond, i32* %a, i32* %a ret void })", - true}, + true, true}, {R"( define void @test(i1 %cond) { @@ -1489,7 +1498,7 @@ %r = select i1 %cond, i32* %a, i32* %b ret void })", - false}, + false, false}, {R"( define void @test(i1 %cond) { @@ -1506,7 +1515,7 @@ exit: ret void })", - true}, + true, false}, {R"( define void @test(i1 %cond) { @@ -1523,7 +1532,7 @@ exit: ret void })", - false}, + false, false}, {R"( define void @test(i1 %cond, i64* %a) { @@ -1531,7 +1540,7 @@ %r = bitcast i64* %a to i32* ret void })", - false}, + false, false}, {R"( define void @test(i1 %cond) { @@ -1547,7 +1556,7 @@ exit: ret void })", - false}, + false, false}, }; TEST_P(FindAllocaForValueTest, findAllocaForValue) { @@ -1555,7 +1564,15 @@ Function *F = M->getFunction("test"); Instruction *I = &findInstructionByName(F, "r"); const AllocaInst *AI = findAllocaForValue(I); - EXPECT_EQ(!!AI, GetParam().Result); + EXPECT_EQ(!!AI, GetParam().AnyOffsetResult); +} + +TEST_P(FindAllocaForValueTest, findAllocaForValueZeroOffset) { + auto M = parseModule(GetParam().IR); + Function *F = M->getFunction("test"); + Instruction *I = &findInstructionByName(F, "r"); + const AllocaInst *AI = findAllocaForValue(I, true); + EXPECT_EQ(!!AI, GetParam().ZeroOffsetResult); } INSTANTIATE_TEST_CASE_P(FindAllocaForValueTest, FindAllocaForValueTest,