[llvm] 9b3c2a7 - [ValueTracking] Use assume's noundef operand bundle
Juneyoung Lee via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 14 04:16:45 PDT 2020
Author: Juneyoung Lee
Date: 2020-10-14T20:16:33+09:00
New Revision: 9b3c2a72e4cb3b0ae27f87064c11f728452b2af9
URL: https://github.com/llvm/llvm-project/commit/9b3c2a72e4cb3b0ae27f87064c11f728452b2af9
DIFF: https://github.com/llvm/llvm-project/commit/9b3c2a72e4cb3b0ae27f87064c11f728452b2af9.diff
LOG: [ValueTracking] Use assume's noundef operand bundle
This patch updates `isGuaranteedNotToBeUndefOrPoison` to use `llvm.assume`'s `noundef` operand bundle.
Reviewed By: jdoerfert
Differential Revision: https://reviews.llvm.org/D89219
Added:
Modified:
llvm/include/llvm/Analysis/ValueTracking.h
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/lib/Analysis/ValueTracking.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/lib/Transforms/Scalar/DivRemPairs.cpp
llvm/lib/Transforms/Scalar/JumpThreading.cpp
llvm/lib/Transforms/Scalar/SCCP.cpp
llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp
llvm/test/Transforms/Inline/arg-attr-propagation.ll
llvm/unittests/Analysis/ValueTrackingTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 8ddbcbf4d643..d14e181f379f 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -630,10 +630,11 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6;
/// and returns true if it is guaranteed to be never undef or poison
/// immediately before the CtxI.
bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
+ AssumptionCache *AC = nullptr,
const Instruction *CtxI = nullptr,
const DominatorTree *DT = nullptr,
unsigned Depth = 0);
- bool isGuaranteedNotToBePoison(const Value *V,
+ bool isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC = nullptr,
const Instruction *CtxI = nullptr,
const DominatorTree *DT = nullptr,
unsigned Depth = 0);
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index c13966169eeb..e0b275aea9a1 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4093,11 +4093,11 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
// long as the other value isn't poison.
// select ?, undef, X -> X
if (Q.isUndefValue(TrueVal) &&
- isGuaranteedNotToBeUndefOrPoison(FalseVal, Q.CxtI, Q.DT))
+ isGuaranteedNotToBeUndefOrPoison(FalseVal, Q.AC, Q.CxtI, Q.DT))
return FalseVal;
// select ?, X, undef -> X
if (Q.isUndefValue(FalseVal) &&
- isGuaranteedNotToBeUndefOrPoison(TrueVal, Q.CxtI, Q.DT))
+ isGuaranteedNotToBeUndefOrPoison(TrueVal, Q.AC, Q.CxtI, Q.DT))
return TrueVal;
// Deal with partial undef vector constants: select ?, VecC, VecC' --> VecC''
@@ -5627,7 +5627,7 @@ Value *llvm::SimplifyCall(CallBase *Call, const SimplifyQuery &Q) {
/// Given operands for a Freeze, see if we can fold the result.
static Value *SimplifyFreezeInst(Value *Op0, const SimplifyQuery &Q) {
// Use a utility function defined in ValueTracking.
- if (llvm::isGuaranteedNotToBeUndefOrPoison(Op0, Q.CxtI, Q.DT))
+ if (llvm::isGuaranteedNotToBeUndefOrPoison(Op0, Q.AC, Q.CxtI, Q.DT))
return Op0;
// We have room for improvement.
return nullptr;
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 979d25b554a9..c6672fce445d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1801,7 +1801,8 @@ static void computeKnownBitsFromOperator(const Operator *I,
}
break;
case Instruction::Freeze:
- if (isGuaranteedNotToBePoison(I->getOperand(0), Q.CxtI, Q.DT, Depth + 1))
+ if (isGuaranteedNotToBePoison(I->getOperand(0), Q.AC, Q.CxtI, Q.DT,
+ Depth + 1))
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
break;
}
@@ -2516,7 +2517,7 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts, unsigned Depth,
else if (const FreezeInst *FI = dyn_cast<FreezeInst>(V)) {
auto *Op = FI->getOperand(0);
if (isKnownNonZero(Op, Depth, Q) &&
- isGuaranteedNotToBePoison(Op, Q.CxtI, Q.DT, Depth))
+ isGuaranteedNotToBePoison(Op, Q.AC, Q.CxtI, Q.DT, Depth))
return true;
}
@@ -4816,6 +4817,7 @@ static bool programUndefinedIfUndefOrPoison(const Value *V,
bool PoisonOnly);
static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
+ AssumptionCache *AC,
const Instruction *CtxI,
const DominatorTree *DT,
unsigned Depth, bool PoisonOnly) {
@@ -4857,7 +4859,8 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
return true;
auto OpCheck = [&](const Value *V) {
- return isGuaranteedNotToBeUndefOrPoison(V, CtxI, DT, Depth + 1, PoisonOnly);
+ return isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth + 1,
+ PoisonOnly);
};
if (auto *Opr = dyn_cast<Operator>(V)) {
@@ -4876,8 +4879,8 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
bool IsWellDefined = true;
for (unsigned i = 0; i < Num; ++i) {
auto *TI = PN->getIncomingBlock(i)->getTerminator();
- if (!isGuaranteedNotToBeUndefOrPoison(PN->getIncomingValue(i), TI, DT,
- Depth + 1, PoisonOnly)) {
+ if (!isGuaranteedNotToBeUndefOrPoison(PN->getIncomingValue(i), AC, TI,
+ DT, Depth + 1, PoisonOnly)) {
IsWellDefined = false;
break;
}
@@ -4932,19 +4935,24 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
Dominator = Dominator->getIDom();
}
+ SmallVector<Attribute::AttrKind, 2> AttrKinds{Attribute::NoUndef};
+ if (getKnowledgeValidInContext(V, AttrKinds, CtxI, DT, AC))
+ return true;
+
return false;
}
-bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V,
+bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC,
const Instruction *CtxI,
const DominatorTree *DT,
unsigned Depth) {
- return ::isGuaranteedNotToBeUndefOrPoison(V, CtxI, DT, Depth, false);
+ return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, false);
}
-bool llvm::isGuaranteedNotToBePoison(const Value *V, const Instruction *CtxI,
+bool llvm::isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC,
+ const Instruction *CtxI,
const DominatorTree *DT, unsigned Depth) {
- return ::isGuaranteedNotToBeUndefOrPoison(V, CtxI, DT, Depth, true);
+ return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, true);
}
OverflowResult llvm::computeOverflowForSignedAdd(const AddOperator *Add,
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 6b07bbd1aff8..98bd770b8a57 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -7897,10 +7897,13 @@ struct AANoUndefImpl : AANoUndef {
AANoUndef::StateType &State) {
const Value *UseV = U->get();
const DominatorTree *DT = nullptr;
- if (Function *F = getAnchorScope())
- DT = A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
- *F);
- State.setKnown(isGuaranteedNotToBeUndefOrPoison(UseV, I, DT));
+ AssumptionCache *AC = nullptr;
+ InformationCache &InfoCache = A.getInfoCache();
+ if (Function *F = getAnchorScope()) {
+ DT = InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*F);
+ AC = InfoCache.getAnalysisResultForFunction<AssumptionAnalysis>(*F);
+ }
+ State.setKnown(isGuaranteedNotToBeUndefOrPoison(UseV, AC, I, DT));
bool TrackUse = false;
// Track use for instructions which must produce undef or poison bits when
// at least one operand contains such bits.
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 2501c564c3ff..55266ff7c7eb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1184,11 +1184,13 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
// X == Y ? X : Z with X == Y ? Y : Z, as that would lead to an infinite
// replacement cycle.
Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1);
- if (TrueVal != CmpLHS && isGuaranteedNotToBeUndefOrPoison(CmpRHS, &Sel, &DT))
+ if (TrueVal != CmpLHS &&
+ isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT))
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
- if (TrueVal != CmpRHS && isGuaranteedNotToBeUndefOrPoison(CmpLHS, &Sel, &DT))
+ if (TrueVal != CmpRHS &&
+ isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT))
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
index 42a5fb1135a6..3c6c444d6649 100644
--- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
+++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
@@ -315,14 +315,14 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,
// %rem = sub %x, %mul // %rem = undef - undef = undef
// If X is not frozen, %rem becomes undef after transformation.
// TODO: We need a undef-specific checking function in ValueTracking
- if (!isGuaranteedNotToBeUndefOrPoison(X, DivInst, &DT)) {
+ if (!isGuaranteedNotToBeUndefOrPoison(X, nullptr, DivInst, &DT)) {
auto *FrX = new FreezeInst(X, X->getName() + ".frozen", DivInst);
DivInst->setOperand(0, FrX);
Sub->setOperand(0, FrX);
}
// Same for Y. If X = 1 and Y = (undef | 1), %rem in src is either 1 or 0,
// but %rem in tgt can be one of many integer values.
- if (!isGuaranteedNotToBeUndefOrPoison(Y, DivInst, &DT)) {
+ if (!isGuaranteedNotToBeUndefOrPoison(Y, nullptr, DivInst, &DT)) {
auto *FrY = new FreezeInst(Y, Y->getName() + ".frozen", DivInst);
DivInst->setOperand(1, FrY);
Mul->setOperand(1, FrY);
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 646b28a49470..a50d8ec8582a 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -2861,7 +2861,8 @@ bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) {
// Expand the select.
Value *Cond = SI->getCondition();
if (InsertFreezeWhenUnfoldingSelect &&
- !isGuaranteedNotToBeUndefOrPoison(Cond, SI, &DTU->getDomTree()))
+ !isGuaranteedNotToBeUndefOrPoison(Cond, nullptr, SI,
+ &DTU->getDomTree()))
Cond = new FreezeInst(Cond, "cond.fr", SI);
Instruction *Term = SplitBlockAndInsertIfThen(Cond, SI, false);
BasicBlock *SplitBB = SI->getParent();
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index 5bd4a1dbcbe9..b3732c11babe 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -2105,7 +2105,7 @@ bool llvm::runIPSCCP(
// poison nor undef. Poison will be outside any range and currently
// values outside of the specified range cause immediate undefined
// behavior.
- if (!isGuaranteedNotToBeUndefOrPoison(CB, CB))
+ if (!isGuaranteedNotToBeUndefOrPoison(CB, nullptr, CB))
continue;
// Do not touch existing metadata for now.
diff --git a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
index a3d0c0421e94..3daff3b4430b 100644
--- a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
+++ b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
@@ -52,6 +52,7 @@ namespace {
bool isUsefullToPreserve(Attribute::AttrKind Kind) {
switch (Kind) {
case Attribute::NonNull:
+ case Attribute::NoUndef:
case Attribute::Alignment:
case Attribute::Dereferenceable:
case Attribute::DereferenceableOrNull:
diff --git a/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp b/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp
index 1ae17c64b8f6..1f649fe6c748 100644
--- a/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp
+++ b/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp
@@ -109,7 +109,7 @@ void CanonicalizeFreezeInLoopsImpl::InsertFreezeAndForgetFromSCEV(Use &U) {
auto *ValueToFr = U.get();
assert(L->contains(UserI->getParent()) &&
"Should not process an instruction that isn't inside the loop");
- if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, UserI, &DT))
+ if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, nullptr, UserI, &DT))
return;
LLVM_DEBUG(dbgs() << "canonfr: inserting freeze:\n");
@@ -176,7 +176,7 @@ bool CanonicalizeFreezeInLoopsImpl::run() {
assert(StepI && "Step instruction should have been found");
// Drop flags from the step instruction.
- if (!isGuaranteedNotToBeUndefOrPoison(StepI, StepI, &DT)) {
+ if (!isGuaranteedNotToBeUndefOrPoison(StepI, nullptr, StepI, &DT)) {
LLVM_DEBUG(dbgs() << "canonfr: drop flags: " << *StepI << "\n");
StepI->dropPoisonGeneratingFlags();
SE.forgetValue(StepI);
diff --git a/llvm/test/Transforms/Inline/arg-attr-propagation.ll b/llvm/test/Transforms/Inline/arg-attr-propagation.ll
index 32d4da94ee3d..10dc001a3015 100644
--- a/llvm/test/Transforms/Inline/arg-attr-propagation.ll
+++ b/llvm/test/Transforms/Inline/arg-attr-propagation.ll
@@ -7,31 +7,41 @@
define i32 @callee(i32* dereferenceable(32) %t1) {
; CHECK-LABEL: define {{[^@]+}}@callee
-; CHECK-SAME: (i32* dereferenceable(32) [[T1:%.*]])
-; CHECK-NEXT: [[T2:%.*]] = load i32, i32* [[T1]]
+; CHECK-SAME: (i32* dereferenceable(32) [[T1:%.*]]) {
+; CHECK-NEXT: [[T2:%.*]] = load i32, i32* [[T1]], align 4
; CHECK-NEXT: ret i32 [[T2]]
;
%t2 = load i32, i32* %t1
ret i32 %t2
}
+define i32 @callee2(i32* dereferenceable(32) %t1, i32 noundef %t2) {
+; CHECK-LABEL: define {{[^@]+}}@callee2
+; CHECK-SAME: (i32* dereferenceable(32) [[T1:%.*]], i32 noundef [[T2:%.*]]) {
+; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[T1]], align 4
+; CHECK-NEXT: ret i32 [[V]]
+;
+ %v = load i32, i32* %t1
+ ret i32 %v
+}
+
; FIXME: All dereferenceability information is lost.
; The caller argument could be known nonnull and dereferenceable(32).
-define i32 @caller1(i32* %t1) {
+define i32 @caller1(i32* %t1, i32 %t2) {
; NO_ASSUME-LABEL: define {{[^@]+}}@caller1
-; NO_ASSUME-SAME: (i32* [[T1:%.*]])
-; NO_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
-; NO_ASSUME-NEXT: ret i32 [[T2_I]]
+; NO_ASSUME-SAME: (i32* [[T1:%.*]], i32 [[T2:%.*]]) {
+; NO_ASSUME-NEXT: [[V_I:%.*]] = load i32, i32* [[T1]], align 4
+; NO_ASSUME-NEXT: ret i32 [[V_I]]
;
; USE_ASSUME-LABEL: define {{[^@]+}}@caller1
-; USE_ASSUME-SAME: (i32* [[T1:%.*]])
-; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[T1]], i64 32) ]
-; USE_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
-; USE_ASSUME-NEXT: ret i32 [[T2_I]]
+; USE_ASSUME-SAME: (i32* [[T1:%.*]], i32 [[T2:%.*]]) {
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[T1]], i64 32), "noundef"(i32 [[T2]]) ]
+; USE_ASSUME-NEXT: [[V_I:%.*]] = load i32, i32* [[T1]], align 4
+; USE_ASSUME-NEXT: ret i32 [[V_I]]
;
- %t2 = tail call i32 @callee(i32* dereferenceable(32) %t1)
- ret i32 %t2
+ %v = tail call i32 @callee2(i32* dereferenceable(32) %t1, i32 noundef %t2)
+ ret i32 %v
}
; The caller argument is nonnull, but that can be explicit.
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 5a55928ba8e0..f2cafa6aa510 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -25,10 +25,18 @@ using namespace llvm;
namespace {
-static Instruction &findInstructionByName(Function *F, StringRef Name) {
+static Instruction *findInstructionByNameOrNull(Function *F, StringRef Name) {
for (Instruction &I : instructions(F))
if (I.getName() == Name)
- return I;
+ return &I;
+
+ return nullptr;
+}
+
+static Instruction &findInstructionByName(Function *F, StringRef Name) {
+ auto *I = findInstructionByNameOrNull(F, Name);
+ if (I)
+ return *I;
llvm_unreachable("Expected value not found");
}
@@ -56,14 +64,21 @@ class ValueTrackingTest : public testing::Test {
if (!F)
return;
- A = &findInstructionByName(F, "A");
+ A = findInstructionByNameOrNull(F, "A");
ASSERT_TRUE(A) << "@test must have an instruction %A";
+
+ CxtI = findInstructionByNameOrNull(F, "CxtI");
+ CxtI2 = findInstructionByNameOrNull(F, "CxtI2");
+ CxtI3 = findInstructionByNameOrNull(F, "CxtI3");
}
LLVMContext Context;
std::unique_ptr<Module> M;
Function *F = nullptr;
Instruction *A = nullptr;
+
+ // Context instructions (optional)
+ Instruction *CxtI = nullptr, *CxtI2 = nullptr, *CxtI3 = nullptr;
};
class MatchSelectPatternTest : public ValueTrackingTest {
@@ -763,7 +778,8 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBePoison_exploitBranchCond) {
if (&BB == &F->getEntryBlock())
continue;
- EXPECT_EQ(isGuaranteedNotToBePoison(A, BB.getTerminator(), &DT), true)
+ EXPECT_EQ(isGuaranteedNotToBePoison(A, nullptr, BB.getTerminator(), &DT),
+ true)
<< "isGuaranteedNotToBePoison does not hold at " << *BB.getTerminator();
}
}
@@ -786,7 +802,7 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBePoison_phi) {
DominatorTree DT(*F);
for (auto &BB : *F) {
if (BB.getName() == "LOOP") {
- EXPECT_EQ(isGuaranteedNotToBePoison(A, A, &DT), true)
+ EXPECT_EQ(isGuaranteedNotToBePoison(A, nullptr, A, &DT), true)
<< "isGuaranteedNotToBePoison does not hold";
}
}
@@ -802,6 +818,33 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) {
EXPECT_EQ(isGuaranteedNotToBeUndefOrPoison(A), true);
}
+TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_assume) {
+ parseAssembly("declare i1 @f_i1()\n"
+ "declare i32 @f_i32()\n"
+ "declare void @llvm.assume(i1)\n"
+ "define void @test() {\n"
+ " %A = call i32 @f_i32()\n"
+ " %cond = call i1 @f_i1()\n"
+ " %CxtI = add i32 0, 0\n"
+ " br i1 %cond, label %BB1, label %EXIT\n"
+ "BB1:\n"
+ " %CxtI2 = add i32 0, 0\n"
+ " %cond2 = call i1 @f_i1()\n"
+ " call void @llvm.assume(i1 true) [ \"noundef\"(i32 %A) ]\n"
+ " br i1 %cond2, label %BB2, label %EXIT\n"
+ "BB2:\n"
+ " %CxtI3 = add i32 0, 0\n"
+ " ret void\n"
+ "EXIT:\n"
+ " ret void\n"
+ "}");
+ AssumptionCache AC(*F);
+ DominatorTree DT(*F);
+ EXPECT_FALSE(isGuaranteedNotToBeUndefOrPoison(A, &AC, CxtI, &DT));
+ EXPECT_FALSE(isGuaranteedNotToBeUndefOrPoison(A, &AC, CxtI2, &DT));
+ EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(A, &AC, CxtI3, &DT));
+}
+
TEST(ValueTracking, canCreatePoisonOrUndef) {
std::string AsmHead =
"declare i32 @g(i32)\n"
More information about the llvm-commits
mailing list