[llvm] [InstSimplify] Discard unnecessary `select` when the conditions are `ICmps` with EQ (PR #179183)

Gábor Spaits via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 4 04:44:10 PST 2026


https://github.com/spaits updated https://github.com/llvm/llvm-project/pull/179183

>From ab65b67bd437c4ed319945489bc8aaf2db509aa4 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Wed, 25 Feb 2026 12:54:16 +0100
Subject: [PATCH 1/2] [InstSimplify] Implement `Cond ? V : V` -> `V` when no
 Refinment allowed

Related to #179183 and #177410 .

I am not sure how profitable would this be. But I may be somewhat optimistic, since there is use for this in #177410 and optimizations can already improve code without the cases in #177410. See the tests.

When the select wasn't a poison barrier and returning an arm also isn't a refinment some optimizations can be done with selects in `simplifyWithOpsReplaced`.

The new recursive function was needed because `impliesPoison` can't really give any useful information, when a select is assumed poison and the right side of the implication isn't a user of that select. (Because of select poison semantics.) Also the behaviour of this recursive function could be added to `impliesPoison`, but then it would need extra parameters.

I have some test cases but I see that there is more to add.
Alove2 for the current cases: https://alive2.llvm.org/ce/z/pKwffE
---
 llvm/lib/Analysis/InstructionSimplify.cpp     | 82 ++++++++++++++++
 .../Transforms/InstSimplify/select-icmp.ll    | 95 +++++++++++++++++++
 2 files changed, 177 insertions(+)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 3d5ee74c0e2e8..ceadee5a7705b 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -48,6 +48,7 @@
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Support/KnownFPClass.h"
 #include <algorithm>
+#include <iterator>
 #include <optional>
 using namespace llvm;
 using namespace llvm::PatternMatch;
@@ -4395,6 +4396,50 @@ Value *llvm::simplifyFCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS,
   return ::simplifyFCmpInst(Predicate, LHS, RHS, FMF, Q, RecursionLimit);
 }
 
+// The value is only poison, if any of these values are poison.
+// It can be useful to decide if replacing a value with another would be
+// refining or introduce more poison.
+//
+// It is especially useful for select instructions. When it comes to selects and
+// impliesPoison, if select is the ValueAssumedToBePoison it is rare that it
+// yields true for any Value, that isn't a user of the select, due to the fact
+// that a select has more complex poison propagation than other instruction.
+static bool areTheseAllTheValuesThatMayCausePoisonInValue(
+    const SmallVector<const Value *, 2> ValuesAssumedPoison, const Value *V,
+    unsigned Depth) {
+  if (any_of(ValuesAssumedPoison, [V](const auto *P) { return P == V; }))
+    return true;
+
+  if (const Instruction *I = dyn_cast<Instruction>(V)) {
+    if (I->hasPoisonGeneratingAnnotations())
+      return false;
+
+    SmallVector<const Value *, 2> ValuesImplyingPoison;
+    copy_if(ValuesAssumedPoison, std::back_inserter(ValuesImplyingPoison),
+            [V](const auto *P) { return impliesPoison(P, V); });
+
+    if (ValuesImplyingPoison.empty())
+      return false;
+
+    const unsigned MaxDepth = 2;
+    if (Depth > MaxDepth)
+      return false;
+
+    return all_of(I->operand_values(),
+                  [&ValuesImplyingPoison, Depth](const auto *Op) {
+                    return areTheseAllTheValuesThatMayCausePoisonInValue(
+                        ValuesImplyingPoison, Op, Depth + 1);
+                  });
+  }
+  return false;
+}
+
+static bool areTheseAllTheValuesThatMayCausePoisonInValue(
+    const SmallVector<const Value *, 2> ValuesAssumedPoison, const Value *V) {
+  return areTheseAllTheValuesThatMayCausePoisonInValue(ValuesAssumedPoison, V,
+                                                       0);
+}
+
 static Value *simplifyWithOpsReplaced(Value *V,
                                       ArrayRef<std::pair<Value *, Value *>> Ops,
                                       const SimplifyQuery &Q,
@@ -4538,6 +4583,43 @@ static Value *simplifyWithOpsReplaced(Value *V,
       if (NewOps.size() == 2 && match(NewOps[1], m_Zero()))
         return NewOps[0];
     }
+
+    if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
+      Value *SimplifiedValue = nullptr;
+      Value *Cond = SI->getCondition();
+
+      // The select couldn't act as a poison barrirer for its old operands and
+      // the new condition can't be more poisonus than the old one.
+      if (impliesPoison(NewOps[0], Cond) &&
+          impliesPoison(SI->getTrueValue(), Cond) &&
+          impliesPoison(SI->getFalseValue(), Cond)) {
+
+        // Cond ? V : V -> V
+        // We know that after replacement both of the operands will be the same.
+        // We have to make sure that no refinment happens. This is done by
+        // checking if the select condition can only be poison if any of the
+        // arms are poison. If the condition could be poison and neither of the
+        // arms would be poison, returning the less poisonus value would be a
+        // refinment.
+        if (NewOps[1] == NewOps[2] &&
+            areTheseAllTheValuesThatMayCausePoisonInValue(
+                {SI->getFalseValue(), SI->getTrueValue()}, Cond))
+          SimplifiedValue = NewOps[1];
+
+        // TODO: Implement more non refining select optimizations here!
+
+        // If we could do any simplification check if it has any poison
+        // generating flags and handle them.
+        if (SimplifiedValue) {
+          if (SI->hasPoisonGeneratingAnnotations()) {
+            if (!DropFlags)
+              return nullptr;
+            DropFlags->push_back(SI);
+          }
+          return SimplifiedValue;
+        }
+      }
+    }
   } else {
     // The simplification queries below may return the original value. Consider:
     //   %div = udiv i32 %arg, %arg2
diff --git a/llvm/test/Transforms/InstSimplify/select-icmp.ll b/llvm/test/Transforms/InstSimplify/select-icmp.ll
index 5ee10bb954766..efe676d9fcd26 100755
--- a/llvm/test/Transforms/InstSimplify/select-icmp.ll
+++ b/llvm/test/Transforms/InstSimplify/select-icmp.ll
@@ -309,3 +309,98 @@ define <2 x ptr> @ptr_eq_replace_vector_constant(<2 x ptr> %a) {
   %sel = select <2 x i1> %cmp, <2 x ptr> %a, <2 x ptr> <ptr inttoptr (i64 42 to ptr), ptr inttoptr (i64 88 to ptr)>
   ret <2 x ptr> %sel
 }
+
+define i32 @selectICmpSelectInArmNotSimplifiedDueToMorePoison(i32 %1, i32 %2, i1 %scond) {
+; CHECK-LABEL: @selectICmpSelectInArmNotSimplifiedDueToMorePoison(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[SCOND:%.*]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP0]], i32 [[TMP4]]
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %4 = icmp eq i32 %1, %2
+  %5 = select i1 %scond, i32 %2, i32 %1
+  %6 = select i1 %4, i32 %1, i32 %5
+  ret i32 %6
+}
+
+define i32 @selectICmpSelectInArmSimplifiedDueToSameValues(i32 %1, i32 %2, i1 %scond) {
+; CHECK-LABEL: @selectICmpSelectInArmSimplifiedDueToSameValues(
+; CHECK-NEXT:    [[SAMEVALUES:%.*]] = icmp ule i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP6:%.*]] = select i1 [[SAMEVALUES]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %4 = icmp eq i32 %1, %2
+  %sameValues = icmp ule i32 %1, %2
+  %5 = select i1 %sameValues, i32 %2, i32 %1
+  %6 = select i1 %4, i32 %1, i32 %5
+  ret i32 %6
+}
+
+define i32 @selectICmpSelectInArmSimplifiedNoPoisonFlagOnCondUseDefChain(i32 %1, i32 %2, i1 %scond) {
+; CHECK-LABEL: @selectICmpSelectInArmSimplifiedNoPoisonFlagOnCondUseDefChain(
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[WITHPOISONFLAG:%.*]] = or i32 [[TMP0]], 42
+; CHECK-NEXT:    [[SAMEVALUES:%.*]] = icmp ule i32 [[WITHPOISONFLAG]], [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = select i1 [[SAMEVALUES]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP4]], i32 [[TMP0]], i32 [[TMP3]]
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %4 = icmp eq i32 %1, %2
+  %withPoisonFlag = or i32 %1, 42
+  %sameValues = icmp ule i32 %withPoisonFlag, %2
+  %5 = select i1 %sameValues, i32 %2, i32 %1
+  %6 = select i1 %4, i32 %1, i32 %5
+  ret i32 %6
+}
+
+define i32 @selectICmpSelectInArmNotSimplifiedPoisonFlagOnCondUseDefChain(i32 %1, i32 %2, i1 %scond) {
+; CHECK-LABEL: @selectICmpSelectInArmNotSimplifiedPoisonFlagOnCondUseDefChain(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[WITHPOISONFLAG:%.*]] = or disjoint i32 [[TMP0]], 42
+; CHECK-NEXT:    [[SAMEVALUES:%.*]] = icmp ule i32 [[WITHPOISONFLAG]], [[TMP1]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[SAMEVALUES]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP0]], i32 [[TMP4]]
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %4 = icmp eq i32 %1, %2
+  %withPoisonFlag = or disjoint i32 %1, 42
+  %sameValues = icmp ule i32 %withPoisonFlag, %2
+  %5 = select i1 %sameValues, i32 %2, i32 %1
+  %6 = select i1 %4, i32 %1, i32 %5
+  ret i32 %6
+}
+
+define i32 @selectICmpSelectInArmNotSimplifiedSecondSelectPoisonBarrier(i32 %1, i32 %2, i1 %scond) {
+; CHECK-LABEL: @selectICmpSelectInArmNotSimplifiedSecondSelectPoisonBarrier(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[SAMEVALUES:%.*]] = icmp ule i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[SAMEVALUES]], [[SCOND:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[OR]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP0]], i32 [[TMP4]]
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %4 = icmp eq i32 %1, %2
+  %sameValues = icmp ule i32 %1, %2
+  %or = or i1 %sameValues, %scond
+  %5 = select i1 %or, i32 %2, i32 %1
+  %6 = select i1 %4, i32 %1, i32 %5
+  ret i32 %6
+}
+
+define i32 @selectICmpSelectInArmNotSimplifiedSecondSelectPoisonBarrierPoisonFlagInCond(i32 %1, i32 %2, i1 %scond) {
+; CHECK-LABEL: @selectICmpSelectInArmNotSimplifiedSecondSelectPoisonBarrierPoisonFlagInCond(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[SAMEVALUES:%.*]] = icmp ule i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i1 [[SAMEVALUES]], [[SCOND:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[OR]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP0]], i32 [[TMP4]]
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+  %4 = icmp eq i32 %1, %2
+  %sameValues = icmp ule i32 %1, %2
+  %or = or disjoint i1 %sameValues, %scond
+  %5 = select i1 %or, i32 %2, i32 %1
+  %6 = select i1 %4, i32 %1, i32 %5
+  ret i32 %6
+}
+

>From eedae8781e75110f0f3bf4e3f2b7b60df4f8f957 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Wed, 4 Mar 2026 13:42:07 +0100
Subject: [PATCH 2/2] [InstSimplify] Decompose and/or trees to simplify selects

---
 llvm/lib/Analysis/InstructionSimplify.cpp     |  23 ++-
 llvm/lib/Analysis/ValueTracking.cpp           |   2 +-
 .../Transforms/InstSimplify/select-select.ll  | 174 ++++++++++++++++++
 3 files changed, 197 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/Transforms/InstSimplify/select-select.ll

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index ceadee5a7705b..97aa01304424e 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -35,6 +35,7 @@
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/Analysis/VectorUtils.h"
+#include "llvm/IR/Constant.h"
 #include "llvm/IR/ConstantFPRange.h"
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/DataLayout.h"
@@ -45,6 +46,7 @@
 #include "llvm/IR/Operator.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/Statepoint.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Support/KnownFPClass.h"
 #include <algorithm>
@@ -4411,9 +4413,13 @@ static bool areTheseAllTheValuesThatMayCausePoisonInValue(
     return true;
 
   if (const Instruction *I = dyn_cast<Instruction>(V)) {
+    // Having a poison generating annotation means that it can be poison
+    // without any of the given values being poison.
     if (I->hasPoisonGeneratingAnnotations())
       return false;
 
+    // Filtering out the assumed poison values, so only the relevant ones are
+    // brought forward to the next recursive call.
     SmallVector<const Value *, 2> ValuesImplyingPoison;
     copy_if(ValuesAssumedPoison, std::back_inserter(ValuesImplyingPoison),
             [V](const auto *P) { return impliesPoison(P, V); });
@@ -4431,6 +4437,11 @@ static bool areTheseAllTheValuesThatMayCausePoisonInValue(
                         ValuesImplyingPoison, Op, Depth + 1);
                   });
   }
+
+  // A constant can't cause poison, unless it is itself a poison.
+  if (const Constant *C = dyn_cast<Constant>(V))
+    return !C->containsUndefOrPoisonElement();
+
   return false;
 }
 
@@ -4603,7 +4614,7 @@ static Value *simplifyWithOpsReplaced(Value *V,
         // refinment.
         if (NewOps[1] == NewOps[2] &&
             areTheseAllTheValuesThatMayCausePoisonInValue(
-                {SI->getFalseValue(), SI->getTrueValue()}, Cond))
+                {SI->getFalseValue(), SI->getTrueValue(), NewOps[1]}, Cond))
           SimplifiedValue = NewOps[1];
 
         // TODO: Implement more non refining select optimizations here!
@@ -5280,6 +5291,16 @@ static Value *simplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
       return ConstantVector::get(NewC);
   }
 
+  CmpPredicate Pred1, Pred2;
+  Value *V1, *V2, *EQV;
+  if (match(Cond,
+            m_And(m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(V1), m_Value(EQV)),
+                  m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(V2),
+                                 m_Deferred(EQV)))))
+    if (Value *V = simplifySelectWithEquivalence(
+            {{V2, EQV}, {V1, EQV}}, TrueVal, FalseVal, Q, MaxRecurse))
+      return V;
+
   if (Value *V =
           simplifySelectWithICmpCond(Cond, TrueVal, FalseVal, Q, MaxRecurse))
     return V;
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c8f53f903428d..4c542b667a05b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7611,7 +7611,7 @@ static bool directlyImpliesPoison(const Value *ValAssumedPoison, const Value *V,
   if (ValAssumedPoison == V)
     return true;
 
-  const unsigned MaxDepth = 2;
+  const unsigned MaxDepth = 3;
   if (Depth >= MaxDepth)
     return false;
 
diff --git a/llvm/test/Transforms/InstSimplify/select-select.ll b/llvm/test/Transforms/InstSimplify/select-select.ll
new file mode 100644
index 0000000000000..393d6bb6f0253
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/select-select.ll
@@ -0,0 +1,174 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i32 @AndICmpConstant(i32 %6, i32 %44) {
+; CHECK-LABEL: @AndICmpConstant(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
+; CHECK-NEXT:    [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP6]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %or.cond.i = and i1 %47, %46
+  %48 = xor i1 %47, true
+  %49 = or i1 %46, %48
+  %spec.select.i = select i1 %49, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+
+define i32 @AndICmp(i32 %6, i32 %44, i32 %val) {
+; CHECK-LABEL: @AndICmp(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], [[VAL:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], [[VAL]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
+; CHECK-NEXT:    [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[TMP6]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+;
+  %46 = icmp eq i32 %44, %val
+  %47 = icmp eq i32 %6, %val
+  %or.cond.i = and i1 %47, %46
+  %48 = xor i1 %47, true
+  %49 = or i1 %46, %48
+  %spec.select.i = select i1 %49, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 %val, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @AndICmpRemovedNonConst(i32 %6, i32 %44, i32 %val) {
+; CHECK-LABEL: @AndICmpRemovedNonConst(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], [[VAL:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], [[VAL]]
+; CHECK-NEXT:    [[OR_COND_I:%.*]] = and i1 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP5]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[OR_COND_I]], i32 [[VAL]], i32 [[SPEC_SELECT_I]]
+; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+;
+  %46 = icmp eq i32 %44, %val
+  %47 = icmp eq i32 %6, %val
+  %or.cond.i = and i1 %47, %46
+  %48 = xor i1 %47, true
+  %spec.select.i = select i1 %48, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 %val, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @AndICmpAnd(i32 %6, i32 %44) {
+; CHECK-LABEL: @AndICmpAnd(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
+; CHECK-NEXT:    [[TMP6:%.*]] = and i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP6]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %or.cond.i = and i1 %47, %46
+  %48 = xor i1 %47, true
+  %49 = and i1 %46, %48
+  %spec.select.i = select i1 %49, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @AndICmpAnd2(i32 %6, i32 %44) {
+; CHECK-LABEL: @AndICmpAnd2(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[TMP5:%.*]] = or i1 [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP5]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %or.cond.i = and i1 %47, %46
+  %48 = and i1 %47, true
+  %49 = or i1 %46, %48
+  %spec.select.i = select i1 %49, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @negative_firstSelectPoisonBarrier(i32 %6, i32 %44, i1 %cond) {
+; CHECK-LABEL: @negative_firstSelectPoisonBarrier(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[OR_COND_I:%.*]] = and i1 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[COND:%.*]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[OR_COND_I]], i32 4, i32 [[SPEC_SELECT_I]]
+; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %or.cond.i = and i1 %47, %46
+  %spec.select.i = select i1 %cond, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @negative_selectCondOnlyMutualOneArm(i32 %6, i32 %44) {
+; CHECK-LABEL: @negative_selectCondOnlyMutualOneArm(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i1 [[TMP3]], true
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP4]], i32 [[TMP0]], i32 [[TMP1:%.*]]
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %or.cond.i = and i1 %47, %46
+  %48 = xor i1 %47, true
+  %spec.select.i = select i1 %48, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @negative_condMorePoisonThanArm(i32 %0, i32 %1) {
+; CHECK-LABEL: @negative_condMorePoisonThanArm(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[OR_COND_I:%.*]] = and i1 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = or disjoint i1 [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP5]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[OR_COND_I]], i32 4, i32 [[SPEC_SELECT_I]]
+; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+;
+  %3 = icmp eq i32 %1, 4
+  %4 = icmp eq i32 %0, 4
+  %or.cond.i = and i1 %4, %3
+  %5 = and i1 %4, true
+  %6 = or disjoint i1 %3, %5
+  %spec.select.i = select i1 %6, i32 %0, i32 %1
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  ret i32 %.0.i8
+}
+
+define i32 @negative_CmpUsed(i32 %6, i32 %44) {
+; CHECK-LABEL: @negative_CmpUsed(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[OR_COND_I:%.*]] = and i1 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
+; CHECK-NEXT:    [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    [[SPEC_SELECT_I:%.*]] = select i1 [[TMP6]], i32 [[TMP0]], i32 [[TMP1]]
+; CHECK-NEXT:    call void @use32(i1 [[OR_COND_I]])
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %or.cond.i = and i1 %47, %46
+  %48 = xor i1 %47, true
+  %49 = or i1 %46, %48
+  %spec.select.i = select i1 %49, i32 %6, i32 %44
+  %.0.i8 = select i1 %or.cond.i, i32 4, i32 %spec.select.i
+  call void @use32(i1 %or.cond.i)
+  ret i32 %.0.i8
+}
+
+declare void @use32(i1)



More information about the llvm-commits mailing list