[llvm] 8a3efcd - [ValueTracking] Consider single poison operands in propgatesPoison.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 19 03:48:10 PST 2022


Author: Florian Hahn
Date: 2022-12-19T11:47:51Z
New Revision: 8a3efcd40b48543d5b77ff9d6e0d1950847e824e

URL: https://github.com/llvm/llvm-project/commit/8a3efcd40b48543d5b77ff9d6e0d1950847e824e
DIFF: https://github.com/llvm/llvm-project/commit/8a3efcd40b48543d5b77ff9d6e0d1950847e824e.diff

LOG: [ValueTracking] Consider single poison operands in propgatesPoison.

This patch updates propgatesPoison to take a Use as argument and
propagatesPoison now returns true if the passed in operand causes the
user to yield poison if the operand is poison

This allows propagating poison if the condition of a select is poison.
This helps improve results for programUndefinedIfUndefOrPoison.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D111643

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/ValueTracking.h
    llvm/lib/Analysis/ScalarEvolution.cpp
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
    llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
    llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll
    llvm/test/Analysis/ScalarEvolution/exit-count-select.ll
    llvm/test/Analysis/ScalarEvolution/nsw.ll
    llvm/test/Instrumentation/PoisonChecking/ub-checks.ll
    llvm/unittests/Analysis/ValueTrackingTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index e5eb505fb704b..2419b8976c5fd 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -603,20 +603,22 @@ bool isGuaranteedToTransferExecutionToSuccessor(
 bool isGuaranteedToExecuteForEveryIteration(const Instruction *I,
                                             const Loop *L);
 
-/// Return true if I yields poison or raises UB if any of its operands is
-/// poison.
-/// Formally, given I = `r = op v1 v2 .. vN`, propagatesPoison returns true
-/// if, for all i, r is evaluated to poison or op raises UB if vi = poison.
-/// If vi is a vector or an aggregate and r is a single value, any poison
-/// element in vi should make r poison or raise UB.
+/// Return true if \p PoisonOp's user yields poison or raises UB if its
+/// operand \p PoisonOp is poison.
+///
+/// If \p PoisonOp is a vector or an aggregate and the operation's result is a
+/// single value, any poison element in /p PoisonOp should make the result
+/// poison or raise UB.
+///
 /// To filter out operands that raise UB on poison, you can use
 /// getGuaranteedNonPoisonOp.
-bool propagatesPoison(const Operator *I);
+bool propagatesPoison(const Use &PoisonOp);
 
 /// Insert operands of I into Ops such that I will trigger undefined behavior
 /// if I is executed and that operand has a poison value.
 void getGuaranteedNonPoisonOps(const Instruction *I,
                                SmallPtrSetImpl<const Value *> &Ops);
+
 /// Insert operands of I into Ops such that I will trigger undefined behavior
 /// if I is executed and that operand is not a well-defined value
 /// (i.e. has undef bits or poison).

diff  --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index bcfb8a88e1a7e..3c445aace3035 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -7294,8 +7294,9 @@ bool ScalarEvolution::isAddRecNeverPoison(const Instruction *I, const Loop *L) {
   while (!PoisonStack.empty() && !LatchControlDependentOnPoison) {
     const Instruction *Poison = PoisonStack.pop_back_val();
 
-    for (const auto *PoisonUser : Poison->users()) {
-      if (propagatesPoison(cast<Operator>(PoisonUser))) {
+    for (const Use &U : Poison->uses()) {
+      const User *PoisonUser = U.getUser();
+      if (propagatesPoison(U)) {
         if (Pushed.insert(cast<Instruction>(PoisonUser)).second)
           PoisonStack.push_back(cast<Instruction>(PoisonUser));
       } else if (auto *BI = dyn_cast<BranchInst>(PoisonUser)) {

diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index dbd5d3cbdb245..36fcec9b2e9fc 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5330,15 +5330,12 @@ static bool directlyImpliesPoison(const Value *ValAssumedPoison,
     return false;
 
   if (const auto *I = dyn_cast<Instruction>(V)) {
-    if (propagatesPoison(cast<Operator>(I)))
-      return any_of(I->operands(), [=](const Value *Op) {
-        return directlyImpliesPoison(ValAssumedPoison, Op, Depth + 1);
-      });
+    if (any_of(I->operands(), [=](const Use &Op) {
+          return propagatesPoison(Op) &&
+                 directlyImpliesPoison(ValAssumedPoison, Op, Depth + 1);
+        }))
+      return true;
 
-    // 'select ValAssumedPoison, _, _' is poison.
-    if (const auto *SI = dyn_cast<SelectInst>(I))
-      return directlyImpliesPoison(ValAssumedPoison, SI->getCondition(),
-                                   Depth + 1);
     // V  = extractvalue V0, idx
     // V2 = extractvalue V0, idx2
     // V0's elements are all poison or not. (e.g., add_with_overflow)
@@ -5496,7 +5493,8 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
       else if (PoisonOnly && isa<Operator>(Cond)) {
         // For poison, we can analyze further
         auto *Opr = cast<Operator>(Cond);
-        if (propagatesPoison(Opr) && is_contained(Opr->operand_values(), V))
+        if (any_of(Opr->operands(),
+                   [V](const Use &U) { return V == U && propagatesPoison(U); }))
           return true;
       }
     }
@@ -5618,13 +5616,15 @@ bool llvm::isGuaranteedToExecuteForEveryIteration(const Instruction *I,
   llvm_unreachable("Instruction not contained in its own parent basic block.");
 }
 
-bool llvm::propagatesPoison(const Operator *I) {
+bool llvm::propagatesPoison(const Use &PoisonOp) {
+  const Operator *I = cast<Operator>(PoisonOp.getUser());
   switch (I->getOpcode()) {
   case Instruction::Freeze:
-  case Instruction::Select:
   case Instruction::PHI:
   case Instruction::Invoke:
     return false;
+  case Instruction::Select:
+    return PoisonOp.getOperandNo() == 0;
   case Instruction::Call:
     if (auto *II = dyn_cast<IntrinsicInst>(I)) {
       switch (II->getIntrinsicID()) {
@@ -5805,14 +5805,11 @@ static bool programUndefinedIfUndefOrPoison(const Value *V,
       if (!isGuaranteedToTransferExecutionToSuccessor(&I))
         return false;
 
-      // If this instruction propagates poison, mark it as poison if any of
-      // its operands are poison
-      if (propagatesPoison(cast<Operator>(&I))) {
-        for (const Value *Op : I.operands()) {
-          if (YieldsPoison.count(Op)) {
-            YieldsPoison.insert(&I);
-            break;
-          }
+      // If an operand is poison and propagates it, mark I as yielding poison.
+      for (const Use &Op : I.operands()) {
+        if (YieldsPoison.count(Op) && propagatesPoison(Op)) {
+          YieldsPoison.insert(&I);
+          break;
         }
       }
     }

diff  --git a/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp b/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
index e26c3b15e4c7b..54dd20fc9ac95 100644
--- a/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
@@ -289,9 +289,10 @@ static bool rewrite(Function &F) {
           }
 
       SmallVector<Value*, 4> Checks;
-      if (propagatesPoison(cast<Operator>(&I)))
-        for (Value *V : I.operands())
-          Checks.push_back(getPoisonFor(ValToPoison, V));
+      for (const Use &U : I.operands()) {
+        if (ValToPoison.count(U) && propagatesPoison(U))
+          Checks.push_back(getPoisonFor(ValToPoison, U));
+      }
 
       if (canCreatePoison(cast<Operator>(&I)))
         generateCreationChecks(I, Checks);

diff  --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 55a22ae1d642d..7c8be1d4ea5ca 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -788,7 +788,9 @@ static bool mustExecuteUBIfPoisonOnPathTo(Instruction *Root,
 
     // If we can't analyze propagation through this instruction, just skip it
     // and transitive users.  Safe as false is a conservative result.
-    if (!propagatesPoison(cast<Operator>(I)) && I != Root)
+    if (I != Root && !any_of(I->operands(), [&KnownPoison](const Use &U) {
+          return KnownPoison.contains(U) && propagatesPoison(U);
+        }))
       continue;
 
     if (KnownPoison.insert(I).second)

diff  --git a/llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll b/llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll
index d95f26f3ef42f..ad89bb5e3a877 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll
@@ -139,9 +139,9 @@ define i32 @logical_or_3ops_duplicate(i32 %n, i32 %m, i32 %k) {
 ; CHECK-NEXT:    %cond_p4 = select i1 %cond_p0, i1 true, i1 %cond_p1
 ; CHECK-NEXT:    --> (true + ((true + %cond_p0) umin_seq (true + %cond_p1))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %cond_p5 = select i1 %cond_p4, i1 true, i1 %cond_p2
-; CHECK-NEXT:    --> (true + ((true + %cond_p0) umin_seq (true + %cond_p1) umin_seq (true + %cond_p2))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (true + ((true + %cond_p0) umin_seq ((true + %cond_p1) umin (true + %cond_p2)))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %cond = select i1 %cond_p5, i1 true, i1 %cond_p3
-; CHECK-NEXT:    --> (true + ((true + %cond_p0) umin_seq (true + %cond_p1) umin_seq (true + %cond_p2) umin_seq (true + %cond_p3))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (true + ((true + %cond_p0) umin_seq ((true + %cond_p1) umin (true + %cond_p2)) umin_seq (true + %cond_p3))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_or_3ops_duplicate
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (%n umin_seq %m umin_seq %k)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -432,7 +432,7 @@ define i32 @logical_and_2ops_and_constant(i32 %n, i32 %m, i32 %k) {
 ; CHECK-NEXT:    %umin = call i32 @llvm.umin.i32(i32 %n, i32 42)
 ; CHECK-NEXT:    --> (42 umin %n) U: [0,43) S: [0,43) Exits: (42 umin %n) LoopDispositions: { %loop: Invariant }
 ; CHECK-NEXT:    %cond = select i1 %cond_p1, i1 true, i1 %cond_p0
-; CHECK-NEXT:    --> (true + ((true + %cond_p1) umin_seq (true + %cond_p0))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (true + ((true + %cond_p1) umin (true + %cond_p0))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_2ops_and_constant
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (42 umin %n)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is 42
@@ -574,7 +574,7 @@ define i32 @logical_and_implies_poison1(i32 %n) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((1 + %n) umin %n)) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p0 umin %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_poison1
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((1 + %n) umin %n)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -607,7 +607,7 @@ define i32 @logical_and_implies_poison2(i32 %n) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((1 + %n) umin %n)) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p1 umin %cond_p0) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_poison2
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((1 + %n) umin %n)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -640,7 +640,7 @@ define i32 @logical_and_implies_poison3(i32 %n, i32 %m) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin %n)) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p1 umin %cond_p0) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_poison3
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((%n + %m) umin %n)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -704,7 +704,7 @@ define i32 @logical_and_implies_poison_noundef(i32 %n, i32 noundef %m) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin %m)) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p0 umin %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_poison_noundef
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (%n umin %m)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -768,7 +768,7 @@ define i32 @logical_and_implies_poison_complex1(i32 %n, i32 %m) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin (1 + %n + %m))) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p0 umin %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_poison_complex1
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((%n + %m) umin (1 + %n + %m))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -804,7 +804,7 @@ define i32 @logical_and_implies_poison_complex2(i32 %n, i32 %m, i32 %l) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin (%n + %m + %l))) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p0 umin %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_poison_complex2
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((%n + %m) umin (%n + %m + %l))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -874,9 +874,9 @@ define i32 @logical_and_implies_multiple_ops(i32 %n, i32 %m) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (((1 + %n) umin %n) umin_seq %m)) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p0 umin %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %cond2 = select i1 %cond, i1 %cond_p2, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1 umin_seq %cond_p2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> ((%cond_p0 umin %cond_p1) umin_seq %cond_p2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_multiple_ops
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (((1 + %n) umin %n) umin_seq %m)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
@@ -907,18 +907,18 @@ define i32 @logical_and_implies_multiple_ops2(i32 %n, i32 %m) {
 ; CHECK-NEXT:    %add = add i32 %n, 1
 ; CHECK-NEXT:    --> (1 + %n) U: full-set S: full-set
 ; CHECK-NEXT:    %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
-; CHECK-NEXT:    --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%n umin_seq %m umin_seq (1 + %n)) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%n umin_seq ((1 + %n) umin %m)) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
-; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin_seq %m umin_seq (1 + %n))) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin_seq ((1 + %n) umin %m))) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
 ; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %cond2 = select i1 %cond, i1 %cond_p2, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1 umin_seq %cond_p2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p0 umin_seq (%cond_p1 umin %cond_p2)) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_implies_multiple_ops2
-; CHECK-NEXT:  Loop %loop: backedge-taken count is (%n umin_seq %m umin_seq (1 + %n))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is (%n umin_seq ((1 + %n) umin %m))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is (%n umin_seq %m umin_seq (1 + %n))
-; CHECK-NEXT:  Loop %loop: Predicated backedge-taken count is (%n umin_seq %m umin_seq (1 + %n))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is (%n umin_seq ((1 + %n) umin %m))
+; CHECK-NEXT:  Loop %loop: Predicated backedge-taken count is (%n umin_seq ((1 + %n) umin %m))
 ; CHECK-NEXT:   Predicates:
 ; CHECK:       Loop %loop: Trip multiple is 1
 ;
@@ -1352,7 +1352,7 @@ define i32 @logical_and_zero_arg2(i32 %n) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
-; CHECK-NEXT:    --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: false LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_p1 umin %cond_p0) U: full-set S: full-set Exits: false LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_zero_arg2
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is 0
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is 0

diff  --git a/llvm/test/Analysis/ScalarEvolution/exit-count-select.ll b/llvm/test/Analysis/ScalarEvolution/exit-count-select.ll
index 7bdb7c6d045ca..6fbd7f2dfde0a 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-count-select.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-count-select.ll
@@ -11,7 +11,7 @@ define void @logical_and_m_const(i32 %n) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: [1,4) S: [1,4) Exits: (1 + (2 umin %n))<nuw><nsw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_i, i1 %cond_i2, i1 false
-; CHECK-NEXT:    --> (%cond_i umin_seq %cond_i2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_i2 umin %cond_i) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_and_m_const
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (2 umin %n)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is 2
@@ -140,7 +140,7 @@ define void @logical_or_m_const(i32 %n) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: [1,4) S: [1,4) Exits: (1 + (2 umin %n))<nuw><nsw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %cond = select i1 %cond_i, i1 true, i1 %cond_i2
-; CHECK-NEXT:    --> (true + ((true + %cond_i) umin_seq (true + %cond_i2))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (true + ((true + %cond_i) umin (true + %cond_i2))) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @logical_or_m_const
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (2 umin %n)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is 2

diff  --git a/llvm/test/Analysis/ScalarEvolution/nsw.ll b/llvm/test/Analysis/ScalarEvolution/nsw.ll
index e21f951aca59d..876b7cec4d9b6 100644
--- a/llvm/test/Analysis/ScalarEvolution/nsw.ll
+++ b/llvm/test/Analysis/ScalarEvolution/nsw.ll
@@ -412,7 +412,7 @@ define void @select_cond_poison_propagation(ptr %p, i32 %x) nounwind {
 ; CHECK-NEXT:    %iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%loop> U: [0,-2147483648) S: [0,-2147483648) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.next = add nsw i32 %iv, 1
-; CHECK-NEXT:    --> {1,+,1}<nuw><%loop> U: [1,0) S: [1,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-2147483648) S: [1,-2147483648) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %sel = select i1 %cmp, i32 10, i32 20
 ; CHECK-NEXT:    --> %sel U: [0,31) S: [0,31) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %cond = call i1 @cond()

diff  --git a/llvm/test/Instrumentation/PoisonChecking/ub-checks.ll b/llvm/test/Instrumentation/PoisonChecking/ub-checks.ll
index a5703ae02e17d..9f9b16eaa8821 100644
--- a/llvm/test/Instrumentation/PoisonChecking/ub-checks.ll
+++ b/llvm/test/Instrumentation/PoisonChecking/ub-checks.ll
@@ -140,6 +140,8 @@ define noundef i32 @select_cond_may_be_poison(i32 %a, i32 %b) {
 ; CHECK-NEXT:    [[ADD:%.*]] = add nuw i32 [[A]], 1
 ; CHECK-NEXT:    [[T:%.*]] = trunc i32 [[ADD]] to i1
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[T]], i32 [[ADD]], i32 [[B:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[TMP2]], true
+; CHECK-NEXT:    call void @__poison_checker_assert(i1 [[TMP3]])
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %add = add nuw i32 %a, 1

diff  --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 7e59841a5aafb..ef130522f10f4 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -847,68 +847,89 @@ TEST(ValueTracking, propagatesPoison) {
       "i1 %cond, i8* %p) {\n";
   std::string AsmTail = "  ret void\n}";
   // (propagates poison?, IR instruction)
-  SmallVector<std::pair<bool, std::string>, 32> Data = {
-      {true, "add i32 %x, %y"},
-      {true, "add nsw nuw i32 %x, %y"},
-      {true, "ashr i32 %x, %y"},
-      {true, "lshr exact i32 %x, 31"},
-      {true, "fadd float %fx, %fy"},
-      {true, "fsub float %fx, %fy"},
-      {true, "fmul float %fx, %fy"},
-      {true, "fdiv float %fx, %fy"},
-      {true, "frem float %fx, %fy"},
-      {true, "fneg float %fx"},
-      {true, "fcmp oeq float %fx, %fy"},
-      {true, "icmp eq i32 %x, %y"},
-      {true, "getelementptr i8, i8* %p, i32 %x"},
-      {true, "getelementptr inbounds i8, i8* %p, i32 %x"},
-      {true, "bitcast float %fx to i32"},
-      {false, "select i1 %cond, i32 %x, i32 %y"},
-      {false, "freeze i32 %x"},
-      {true, "udiv i32 %x, %y"},
-      {true, "urem i32 %x, %y"},
-      {true, "sdiv exact i32 %x, %y"},
-      {true, "srem i32 %x, %y"},
-      {false, "call i32 @g(i32 %x)"},
-      {true, "call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)"},
-      {true, "call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)"},
-      {true, "call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %y)"},
-      {true, "call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)"},
-      {true, "call {i32, i1} @llvm.usub.with.overflow.i32(i32 %x, i32 %y)"},
-      {true, "call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %y)"},
-      {false, "call float @llvm.sqrt.f32(float %fx)"},
-      {false, "call float @llvm.powi.f32.i32(float %fx, i32 %x)"},
-      {false, "call float @llvm.sin.f32(float %fx)"},
-      {false, "call float @llvm.cos.f32(float %fx)"},
-      {false, "call float @llvm.pow.f32(float %fx, float %fy)"},
-      {false, "call float @llvm.exp.f32(float %fx)"},
-      {false, "call float @llvm.exp2.f32(float %fx)"},
-      {false, "call float @llvm.log.f32(float %fx)"},
-      {false, "call float @llvm.log10.f32(float %fx)"},
-      {false, "call float @llvm.log2.f32(float %fx)"},
-      {false, "call float @llvm.fma.f32(float %fx, float %fx, float %fy)"},
-      {false, "call float @llvm.fabs.f32(float %fx)"},
-      {false, "call float @llvm.minnum.f32(float %fx, float %fy)"},
-      {false, "call float @llvm.maxnum.f32(float %fx, float %fy)"},
-      {false, "call float @llvm.minimum.f32(float %fx, float %fy)"},
-      {false, "call float @llvm.maximum.f32(float %fx, float %fy)"},
-      {false, "call float @llvm.copysign.f32(float %fx, float %fy)"},
-      {false, "call float @llvm.floor.f32(float %fx)"},
-      {false, "call float @llvm.ceil.f32(float %fx)"},
-      {false, "call float @llvm.trunc.f32(float %fx)"},
-      {false, "call float @llvm.rint.f32(float %fx)"},
-      {false, "call float @llvm.nearbyint.f32(float %fx)"},
-      {false, "call float @llvm.round.f32(float %fx)"},
-      {false, "call float @llvm.roundeven.f32(float %fx)"},
-      {false, "call i32 @llvm.lround.f32(float %fx)"},
-      {false, "call i64 @llvm.llround.f32(float %fx)"},
-      {false, "call i32 @llvm.lrint.f32(float %fx)"},
-      {false, "call i64 @llvm.llrint.f32(float %fx)"},
-      {false, "call float @llvm.fmuladd.f32(float %fx, float %fx, float %fy)"}};
+  SmallVector<std::tuple<bool, std::string, unsigned>, 32> Data = {
+      {true, "add i32 %x, %y", 0},
+      {true, "add i32 %x, %y", 1},
+      {true, "add nsw nuw i32 %x, %y", 0},
+      {true, "add nsw nuw i32 %x, %y", 1},
+      {true, "ashr i32 %x, %y", 0},
+      {true, "ashr i32 %x, %y", 1},
+      {true, "lshr exact i32 %x, 31", 0},
+      {true, "lshr exact i32 %x, 31", 1},
+      {true, "fadd float %fx, %fy", 0},
+      {true, "fadd float %fx, %fy", 1},
+      {true, "fsub float %fx, %fy", 0},
+      {true, "fsub float %fx, %fy", 1},
+      {true, "fmul float %fx, %fy", 0},
+      {true, "fmul float %fx, %fy", 1},
+      {true, "fdiv float %fx, %fy", 0},
+      {true, "fdiv float %fx, %fy", 1},
+      {true, "frem float %fx, %fy", 0},
+      {true, "frem float %fx, %fy", 1},
+      {true, "fneg float %fx", 0},
+      {true, "fcmp oeq float %fx, %fy", 0},
+      {true, "fcmp oeq float %fx, %fy", 1},
+      {true, "icmp eq i32 %x, %y", 0},
+      {true, "icmp eq i32 %x, %y", 1},
+      {true, "getelementptr i8, i8* %p, i32 %x", 0},
+      {true, "getelementptr i8, i8* %p, i32 %x", 1},
+      {true, "getelementptr inbounds i8, i8* %p, i32 %x", 0},
+      {true, "getelementptr inbounds i8, i8* %p, i32 %x", 1},
+      {true, "bitcast float %fx to i32", 0},
+      {true, "select i1 %cond, i32 %x, i32 %y", 0},
+      {false, "select i1 %cond, i32 %x, i32 %y", 1},
+      {false, "select i1 %cond, i32 %x, i32 %y", 2},
+      {false, "freeze i32 %x", 0},
+      {true, "udiv i32 %x, %y", 0},
+      {true, "udiv i32 %x, %y", 1},
+      {true, "urem i32 %x, %y", 0},
+      {true, "urem i32 %x, %y", 1},
+      {true, "sdiv exact i32 %x, %y", 0},
+      {true, "sdiv exact i32 %x, %y", 1},
+      {true, "srem i32 %x, %y", 0},
+      {true, "srem i32 %x, %y", 1},
+      {false, "call i32 @g(i32 %x)", 0},
+      {false, "call i32 @g(i32 %x)", 1},
+      {true, "call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)", 0},
+      {true, "call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)", 0},
+      {true, "call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %y)", 0},
+      {true, "call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)", 0},
+      {true, "call {i32, i1} @llvm.usub.with.overflow.i32(i32 %x, i32 %y)", 0},
+      {true, "call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %y)", 0},
+      {false, "call float @llvm.sqrt.f32(float %fx)", 0},
+      {false, "call float @llvm.powi.f32.i32(float %fx, i32 %x)", 0},
+      {false, "call float @llvm.sin.f32(float %fx)", 0},
+      {false, "call float @llvm.cos.f32(float %fx)", 0},
+      {false, "call float @llvm.pow.f32(float %fx, float %fy)", 0},
+      {false, "call float @llvm.exp.f32(float %fx)", 0},
+      {false, "call float @llvm.exp2.f32(float %fx)", 0},
+      {false, "call float @llvm.log.f32(float %fx)", 0},
+      {false, "call float @llvm.log10.f32(float %fx)", 0},
+      {false, "call float @llvm.log2.f32(float %fx)", 0},
+      {false, "call float @llvm.fma.f32(float %fx, float %fx, float %fy)", 0},
+      {false, "call float @llvm.fabs.f32(float %fx)", 0},
+      {false, "call float @llvm.minnum.f32(float %fx, float %fy)", 0},
+      {false, "call float @llvm.maxnum.f32(float %fx, float %fy)", 0},
+      {false, "call float @llvm.minimum.f32(float %fx, float %fy)", 0},
+      {false, "call float @llvm.maximum.f32(float %fx, float %fy)", 0},
+      {false, "call float @llvm.copysign.f32(float %fx, float %fy)", 0},
+      {false, "call float @llvm.floor.f32(float %fx)", 0},
+      {false, "call float @llvm.ceil.f32(float %fx)", 0},
+      {false, "call float @llvm.trunc.f32(float %fx)", 0},
+      {false, "call float @llvm.rint.f32(float %fx)", 0},
+      {false, "call float @llvm.nearbyint.f32(float %fx)", 0},
+      {false, "call float @llvm.round.f32(float %fx)", 0},
+      {false, "call float @llvm.roundeven.f32(float %fx)", 0},
+      {false, "call i32 @llvm.lround.f32(float %fx)", 0},
+      {false, "call i64 @llvm.llround.f32(float %fx)", 0},
+      {false, "call i32 @llvm.lrint.f32(float %fx)", 0},
+      {false, "call i64 @llvm.llrint.f32(float %fx)", 0},
+      {false, "call float @llvm.fmuladd.f32(float %fx, float %fx, float %fy)",
+       0}};
 
   std::string AssemblyStr = AsmHead;
   for (auto &Itm : Data)
-    AssemblyStr += Itm.second + "\n";
+    AssemblyStr += std::get<1>(Itm) + "\n";
   AssemblyStr += AsmTail;
 
   LLVMContext Context;
@@ -925,7 +946,9 @@ TEST(ValueTracking, propagatesPoison) {
   for (auto &I : BB) {
     if (isa<ReturnInst>(&I))
       break;
-    EXPECT_EQ(propagatesPoison(cast<Operator>(&I)), Data[Index].first)
+    bool ExpectedVal = std::get<0>(Data[Index]);
+    unsigned OpIdx = std::get<2>(Data[Index]);
+    EXPECT_EQ(propagatesPoison(I.getOperandUse(OpIdx)), ExpectedVal)
         << "Incorrect answer at instruction " << Index << " = " << I;
     Index++;
   }


        


More information about the llvm-commits mailing list