[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
Tue Feb 10 04:02:16 PST 2026


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

>From c4a689a362f507a2decb492da141fd5b03ac571b Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Fri, 6 Feb 2026 17:05:34 +0100
Subject: [PATCH 1/3] Pre commit tests

---
 .../Transforms/InstSimplify/select-select.ll  | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 llvm/test/Transforms/InstSimplify/select-select.ll

diff --git a/llvm/test/Transforms/InstSimplify/select-select.ll b/llvm/test/Transforms/InstSimplify/select-select.ll
new file mode 100644
index 0000000000000..18be61129e186
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/select-select.ll
@@ -0,0 +1,83 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i32 @foo(i32 %6, i32 %44) {
+; CHECK-LABEL: @foo(
+; 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:    [[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 ; Check if both values are 4.
+  %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 @fooAndUsed(i32 %6, i32 %44) {
+; CHECK-LABEL: @fooAndUsed(
+; 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:    [[DOT0_I8:%.*]] = select i1 [[OR_COND_I]], i32 4, i32 [[SPEC_SELECT_I]]
+; CHECK-NEXT:    call void @use32(i1 [[OR_COND_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 ; Check if both values are 4.
+  %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
+}
+
+define i32 @negSelectSelectICmpICmp(i32 %6, i32 %44) {
+; CHECK-LABEL: @negSelectSelectICmpICmp(
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
+; CHECK-NEXT:    [[DOT_I:%.*]] = select i1 [[TMP4]], i32 [[TMP1]], i32 [[TMP0]]
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[TMP3]], i32 [[TMP0]], i32 [[DOT_I]]
+; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %..i = select i1 %47, i32 %44, i32 %6
+  %.0.i8 = select i1 %46, i32 %6, i32 %..i
+  ret i32 %.0.i8
+}
+
+define void @negRealExampleBefore(ptr %0, i32 %6, i32 %44) {
+; CHECK-LABEL: @negRealExampleBefore(
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP2:%.*]], 4
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
+; CHECK-NEXT:    [[DOT_I:%.*]] = select i1 [[TMP5]], i32 [[TMP2]], i32 [[TMP1]]
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[TMP4]], i32 [[TMP1]], i32 [[DOT_I]]
+; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0:%.*]], i64 12
+; CHECK-NEXT:    store i32 [[DOT0_I8]], ptr [[TMP6]], align 4
+; CHECK-NEXT:    ret void
+;
+  %46 = icmp eq i32 %44, 4
+  %47 = icmp eq i32 %6, 4
+  %..i = select i1 %47, i32 %44, i32 %6
+  %.0.i8 = select i1 %46, i32 %6, i32 %..i
+  %50 = getelementptr inbounds nuw i8, ptr %0, i64 12
+  store i32 %.0.i8, ptr %50
+  ret void
+}
+
+declare void @use32(i1)

>From 02447b623f049092b065d9c0f3d1e253d4fec019 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Fri, 6 Feb 2026 17:10:32 +0100
Subject: [PATCH 2/3] Decompose and trees and call
 simplifySelectWithEquivalence

---
 llvm/lib/Analysis/InstructionSimplify.cpp     | 27 +++++++++++++++++++
 .../Transforms/InstSimplify/select-select.ll  |  7 ++---
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 0e0c092271a38..bc437bd00cf6a 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4482,6 +4482,21 @@ static Value *simplifyWithOpsReplaced(Value *V,
       if (NewOps.size() == 2 && match(NewOps[1], m_Zero()))
         return NewOps[0];
     }
+
+    if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
+      if (SI->hasPoisonGeneratingAnnotations()) {
+        if (!DropFlags)
+          return nullptr;
+
+        DropFlags->push_back(SI);
+      }
+
+      // If both of the arm give the same value and that value isn't poison we
+      // can simplify the select to that value.
+      if (isGuaranteedNotToBePoison(NewOps[1]) && NewOps[1] == NewOps[2])
+        return NewOps[1];
+    }
+
   } else {
     // The simplification queries below may return the original value. Consider:
     //   %div = udiv i32 %arg, %arg2
@@ -5142,6 +5157,18 @@ 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_ICmp(Pred1, m_Value(V1), m_Value(EQV)),
+                        m_ICmp(Pred2, m_Value(V2), m_Deferred(EQV))))) {
+    if (Pred1 == ICmpInst::ICMP_EQ && Pred2 == ICmpInst::ICMP_EQ) {
+      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/test/Transforms/InstSimplify/select-select.ll b/llvm/test/Transforms/InstSimplify/select-select.ll
index 18be61129e186..45d2f05016b5a 100644
--- a/llvm/test/Transforms/InstSimplify/select-select.ll
+++ b/llvm/test/Transforms/InstSimplify/select-select.ll
@@ -5,12 +5,10 @@ define i32 @foo(i32 %6, i32 %44) {
 ; CHECK-LABEL: @foo(
 ; 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:    [[DOT0_I8:%.*]] = select i1 [[OR_COND_I]], i32 4, i32 [[SPEC_SELECT_I]]
-; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
 ;
   %46 = icmp eq i32 %44, 4
   %47 = icmp eq i32 %6, 4
@@ -31,9 +29,8 @@ define i32 @fooAndUsed(i32 %6, i32 %44) {
 ; 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:    [[DOT0_I8:%.*]] = select i1 [[OR_COND_I]], i32 4, i32 [[SPEC_SELECT_I]]
 ; CHECK-NEXT:    call void @use32(i1 [[OR_COND_I]])
-; CHECK-NEXT:    ret i32 [[DOT0_I8]]
+; CHECK-NEXT:    ret i32 [[SPEC_SELECT_I]]
 ;
   %46 = icmp eq i32 %44, 4
   %47 = icmp eq i32 %6, 4

>From 156bf99df31d62956233ec2b559d9f6beacc45b8 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 10 Feb 2026 12:55:23 +0100
Subject: [PATCH 3/3] Address some of the reviews

I have addressed some of the reviews:
- Flags shall be only removed if there is simplification
- Poison checks
---
 llvm/lib/Analysis/InstructionSimplify.cpp     |  60 ++++++---
 .../Transforms/InstSimplify/select-select.ll  | 116 +++++++++++++++++-
 2 files changed, 156 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index bc437bd00cf6a..5dcddf9ba938e 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -45,9 +45,14 @@
 #include "llvm/IR/Operator.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/Statepoint.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Support/KnownFPClass.h"
+#include "llvm/Support/raw_ostream.h"
 #include <algorithm>
+#include <cassert>
 #include <optional>
 using namespace llvm;
 using namespace llvm::PatternMatch;
@@ -4484,17 +4489,22 @@ static Value *simplifyWithOpsReplaced(Value *V,
     }
 
     if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
-      if (SI->hasPoisonGeneratingAnnotations()) {
-        if (!DropFlags)
-          return nullptr;
+      Value *SimplifiedValue = nullptr;
 
-        DropFlags->push_back(SI);
-      }
+      // Cond ? V : V -> V
+      if (NewOps[1] == NewOps[2] && !impliesPoison(SI, NewOps[0]))
+        SimplifiedValue = NewOps[1];
 
-      // If both of the arm give the same value and that value isn't poison we
-      // can simplify the select to that value.
-      if (isGuaranteedNotToBePoison(NewOps[1]) && NewOps[1] == NewOps[2])
-        return NewOps[1];
+      // 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 {
@@ -5159,16 +5169,34 @@ static Value *simplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
 
   CmpPredicate Pred1, Pred2;
   Value *V1, *V2, *EQV;
-  if (match(Cond, m_And(m_ICmp(Pred1, m_Value(V1), m_Value(EQV)),
-                        m_ICmp(Pred2, m_Value(V2), m_Deferred(EQV))))) {
-    if (Pred1 == ICmpInst::ICMP_EQ && Pred2 == ICmpInst::ICMP_EQ) {
-      if (Value *V = simplifySelectWithEquivalence(
-              {{V2, EQV}, {V1, EQV}}, TrueVal, FalseVal, Q, MaxRecurse)) {
+  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)) {
+      // We should only throw away a select if we get a select in place of that
+      // because of the poison barrier property.
+      SelectInst *VasSI = dyn_cast<SelectInst>(V);
+      // Also we have to check if the removing of the current select doesn't
+      // introduce any new poison. We should only remove the current select if
+      // its condition is poison in every case where the new select condition is
+      // poison.
+      if (VasSI && impliesPoison(VasSI->getCondition(), Cond))
         return V;
-      }
     }
-  }
 
+// TODO: I'll have to finish this. There is still testing to be done here!
+//  if (match(Cond,
+//            m_Or(m_SpecificICmp(ICmpInst::ICMP_NE, m_Value(V1), m_Value(EQV)),
+//                 m_SpecificICmp(ICmpInst::ICMP_NE, m_Value(V2), m_Deferred(EQV))))) {
+//    
+//    if (Value *V = simplifySelectWithEquivalence({{V2, EQV}}, TrueVal, FalseVal, Q, MaxRecurse))
+//      return V;
+//    if (Value *V = simplifySelectWithEquivalence({{V1, EQV}}, TrueVal, FalseVal, Q, MaxRecurse))
+//      return V;
+//  }
+  
   if (Value *V =
           simplifySelectWithICmpCond(Cond, TrueVal, FalseVal, Q, MaxRecurse))
     return V;
diff --git a/llvm/test/Transforms/InstSimplify/select-select.ll b/llvm/test/Transforms/InstSimplify/select-select.ll
index 45d2f05016b5a..ebc2f988e4bbc 100644
--- a/llvm/test/Transforms/InstSimplify/select-select.ll
+++ b/llvm/test/Transforms/InstSimplify/select-select.ll
@@ -1,8 +1,27 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
 
-define i32 @foo(i32 %6, i32 %44) {
-; CHECK-LABEL: @foo(
+; FAILS! Because of poison.
+define i32 @selectSelectAndICmpFirstSelectParam(i32 %6, i32 %44, i1 %cond) {
+; CHECK-LABEL: @selectSelectAndICmpFirstSelectParam(
+; 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 ; Check if both values are 4.
+  %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 @selectSelectAndICmp(i32 %6, i32 %44) {
+; CHECK-LABEL: @selectSelectAndICmp(
 ; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4
 ; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], 4
 ; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
@@ -20,9 +39,78 @@ define i32 @foo(i32 %6, i32 %44) {
   ret i32 %.0.i8
 }
 
+define i32 @selectSelectAndICmpRemovedNonConst(i32 %6, i32 %44, i32 %val) {
+; CHECK-LABEL: @selectSelectAndICmpRemovedNonConst(
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0:%.*]], [[VAL:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = xor i1 [[TMP4]], true
+; CHECK-NEXT:    [[DOT0_I8:%.*]] = select i1 [[TMP5]], 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 ; Check if both values are 4.
+  %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 @selectSelectAndICmpRemoved(i32 %6, i32 %44) {
+; CHECK-LABEL: @selectSelectAndICmpRemoved(
+; 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 ; Check if both values are 4.
+  %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 @selectSelectAndICmpAnd(i32 %6, i32 %44) {
+; CHECK-LABEL: @selectSelectAndICmpAnd(
+; 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 ; Check if both values are 4.
+  %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 @selectSelectAndICmpAnd2(i32 %6, i32 %44) {
+; CHECK-LABEL: @selectSelectAndICmpAnd2(
+; 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 ; Check if both values are 4.
+  %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 @fooAndUsed(i32 %6, i32 %44) {
-; CHECK-LABEL: @fooAndUsed(
+define i32 @selectSelectAndICmpUsed(i32 %6, i32 %44) {
+; CHECK-LABEL: @selectSelectAndICmpUsed(
 ; 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]]
@@ -43,6 +131,26 @@ define i32 @fooAndUsed(i32 %6, i32 %44) {
   ret i32 %.0.i8
 }
 
+define i32 @selectSelectAndICmpDisjointOr(i32 %0, i32 %1) {
+; CHECK-LABEL: @selectSelectAndICmpDisjointOr(
+; 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 @negSelectSelectICmpICmp(i32 %6, i32 %44) {
 ; CHECK-LABEL: @negSelectSelectICmpICmp(
 ; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP1:%.*]], 4



More information about the llvm-commits mailing list