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 @@ -4871,7 +4871,7 @@ return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/true); } -static bool programUndefinedIfUndefOrPoison(const Instruction *Inst, +static bool programUndefinedIfUndefOrPoison(const Value *InstOrArg, bool PoisonOnly); static bool isGuaranteedNotToBeUndefOrPoison(const Value *V, @@ -4884,6 +4884,9 @@ if (const auto *A = dyn_cast(V)) { if (A->hasAttribute(Attribute::NoUndef)) return true; + + if (programUndefinedIfUndefOrPoison(A, PoisonOnly)) + return true; } if (auto *C = dyn_cast(V)) { @@ -5161,8 +5164,10 @@ return false; } -static bool programUndefinedIfUndefOrPoison(const Instruction *Inst, +static bool programUndefinedIfUndefOrPoison(const Value *InstOrArg, bool PoisonOnly) { + assert((isa(InstOrArg) || isa(InstOrArg)) && + "Either an argument or instruction should be given"); // We currently only look for uses of values within the same basic // block, as that makes it easier to guarantee that the uses will be // executed given that Inst is executed. @@ -5170,9 +5175,18 @@ // FIXME: Expand this to consider uses beyond the same basic block. To do // this, look out for the distinction between post-dominance and strong // post-dominance. - const BasicBlock *BB = Inst->getParent(); + const BasicBlock *BB = nullptr; + BasicBlock::const_iterator Begin; + if (auto *Inst = dyn_cast(InstOrArg)) { + BB = Inst->getParent(); + Begin = Inst->getIterator(); + Begin++; + } else { + BB = &cast(InstOrArg)->getParent()->getEntryBlock(); + Begin = BB->begin(); + } - BasicBlock::const_iterator Begin = Inst->getIterator(), End = BB->end(); + BasicBlock::const_iterator End = BB->end(); if (!PoisonOnly) { // Be conservative & just check whether a value is passed to a noundef @@ -5185,7 +5199,7 @@ if (const auto *CB = dyn_cast(&I)) { for (unsigned i = 0; i < CB->arg_size(); ++i) { if (CB->paramHasAttr(i, Attribute::NoUndef) && - CB->getArgOperand(i) == Inst) + CB->getArgOperand(i) == InstOrArg) return true; } } @@ -5199,27 +5213,26 @@ // does. SmallSet YieldsPoison; SmallSet Visited; - YieldsPoison.insert(Inst); - Visited.insert(Inst->getParent()); + + YieldsPoison.insert(InstOrArg); + auto Propagate = [&](const User *User) { + if (propagatesPoison(cast(User))) + YieldsPoison.insert(User); + }; + for_each(InstOrArg->users(), Propagate); + Visited.insert(BB); unsigned Iter = 0; while (Iter++ < MaxAnalysisRecursionDepth) { for (auto &I : make_range(Begin, End)) { - if (&I != Inst) { - if (mustTriggerUB(&I, YieldsPoison)) - return true; - if (!isGuaranteedToTransferExecutionToSuccessor(&I)) - return false; - } + if (mustTriggerUB(&I, YieldsPoison)) + return true; + if (!isGuaranteedToTransferExecutionToSuccessor(&I)) + return false; // Mark poison that propagates from I through uses of I. - if (YieldsPoison.count(&I)) { - for (const User *User : I.users()) { - const Instruction *UserI = cast(User); - if (propagatesPoison(cast(UserI))) - YieldsPoison.insert(User); - } - } + if (YieldsPoison.count(&I)) + for_each(I.users(), Propagate); } if (auto *NextBB = BB->getSingleSuccessor()) { 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 @@ -768,6 +768,16 @@ } } +TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) { + parseAssembly("declare void @f(i32 noundef)" + "define void @test(i32 %x) {\n" + " %A = bitcast i32 %x to i32\n" + " call void @f(i32 noundef %x)\n" + " ret void\n" + "}\n"); + EXPECT_EQ(isGuaranteedNotToBeUndefOrPoison(A), true); +} + TEST(ValueTracking, canCreatePoisonOrUndef) { std::string AsmHead = "declare i32 @g(i32)\n"