[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