[llvm] [InstCombine] Simplify the pattern `a ne/eq (zext/sext (a ne/eq c))` (PR #65852)

Matthias Springer via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 6 02:57:43 PDT 2023


https://github.com/matthias-springer updated https://github.com/llvm/llvm-project/pull/65852

>From d9d8bcbb98e8f5aecb9733329389d61a489bd731 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 9 Sep 2023 23:07:29 +0800
Subject: [PATCH 01/10] [InstCombine] Simplify the pattern `a ne/eq (zext (a
 ne/eq c))`

---
 .../InstCombine/InstCombineCompares.cpp       |  62 ++++++
 .../test/Transforms/InstCombine/icmp-range.ll | 181 ++++++++++++++++++
 2 files changed, 243 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 9fdc46fec631679..837b8e6d2619989 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6309,7 +6309,69 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
       Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE)
     return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y);
 
+  ICmpInst::Predicate Pred1, Pred2;
   const APInt *C;
+  // icmp eq/ne X, (zext (icmp eq/ne X, C))
+  if (match(&I, m_c_ICmp(Pred1, m_Value(X),
+                         m_ZExt(m_ICmp(Pred2, m_Deferred(X), m_APInt(C))))) &&
+      ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
+    if (C->isZero()) {
+      if (Pred2 == ICmpInst::ICMP_EQ) {
+        // icmp eq X, (zext (icmp eq X, 0)) --> false
+        // icmp ne X, (zext (icmp eq X, 0)) --> true
+        return replaceInstUsesWith(
+            I,
+            Constant::getIntegerValue(
+                I.getType(),
+                APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE))));
+      } else {
+        // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
+        // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
+        return ICmpInst::Create(
+            Instruction::ICmp,
+            Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
+                                       : ICmpInst::ICMP_ULT,
+            X,
+            Constant::getIntegerValue(
+                X->getType(), APInt(X->getType()->getScalarSizeInBits(),
+                                    Pred1 == ICmpInst::ICMP_NE ? 1 : 2)));
+      }
+    } else if (C->isOne()) {
+      if (Pred2 == ICmpInst::ICMP_NE) {
+        // icmp eq X, (zext (icmp ne X, 1)) --> false
+        // icmp ne X, (zext (icmp ne X, 1)) --> true
+        return replaceInstUsesWith(
+            I,
+            Constant::getIntegerValue(
+                I.getType(),
+                APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE))));
+      } else {
+        // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
+        // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1
+        return ICmpInst::Create(
+            Instruction::ICmp,
+            Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
+                                       : ICmpInst::ICMP_ULT,
+            X,
+            Constant::getIntegerValue(
+                X->getType(), APInt(X->getType()->getScalarSizeInBits(),
+                                    Pred1 == ICmpInst::ICMP_NE ? 1 : 2)));
+      }
+    } else {
+      // C != 0 && C != 1
+      // icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
+      // icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1
+      // icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
+      // icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
+      return ICmpInst::Create(
+          Instruction::ICmp, Pred1, X,
+          Constant::getIntegerValue(
+              X->getType(),
+              APInt(X->getType()->getScalarSizeInBits(),
+                    static_cast<uint64_t>(Pred2 == ICmpInst::ICMP_NE))));
+    }
+  }
+
   if (match(I.getOperand(0), m_c_Add(m_ZExt(m_Value(X)), m_SExt(m_Value(Y)))) &&
       match(I.getOperand(1), m_APInt(C)) &&
       X->getType()->isIntOrIntVectorTy(1) &&
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 4281e09cb0309c8..15424fce33fdeea 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1034,6 +1034,187 @@ define i1 @icmp_ne_bool_1(ptr %ptr) {
   ret i1 %cmp
 }
 
+define i1 @icmp_ne_zext_eq_zero(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_zero(
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp eq i32 %a, 0
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_ne_zero(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_zero(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, 0
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_eq_zero(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_eq_zero(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp eq i32 %a, 0
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp eq i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_ne_zero(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_ne_zero(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, 0
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp eq i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_eq_one(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_one(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp eq i32 %a, 1
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_ne_one(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_one(
+; CHECK-NEXT:    ret i1 true
+;
+  %cmp = icmp ne i32 %a, 1
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_eq_one(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_eq_one(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp eq i32 %a, 1
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp eq i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_ne_one(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_ne_one(
+; CHECK-NEXT:    ret i1 false
+;
+  %cmp = icmp ne i32 %a, 1
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp eq i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_eq_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp eq i32 %a, 2
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_ne_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_non_boolean(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, 2
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_eq_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_eq_non_boolean(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp eq i32 %a, 2
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp eq i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_ne_non_boolean(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, 2
+  %conv = zext i1 %cmp to i32
+  %cmp1 = icmp eq i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %cmp = icmp eq <2 x i32> %a, <i32 0, i32 0>
+  %conv = zext <2 x i1> %cmp to <2 x i32>
+  %cmp1 = icmp ne <2 x i32> %conv, %a
+  ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_ne_zero_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_zero_vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %cmp = icmp ne <2 x i32> %a, <i32 0, i32 0>
+  %conv = zext <2 x i1> %cmp to <2 x i32>
+  %cmp1 = icmp ne <2 x i32> %conv, %a
+  ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_eq_one_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_one_vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 1, i32 1>
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %cmp = icmp eq <2 x i32> %a, <i32 1, i32 1>
+  %conv = zext <2 x i1> %cmp to <2 x i32>
+  %cmp1 = icmp ne <2 x i32> %conv, %a
+  ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_ne_one_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_one_vec(
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
+;
+  %cmp = icmp ne <2 x i32> %a, <i32 1, i32 1>
+  %conv = zext <2 x i1> %cmp to <2 x i32>
+  %cmp1 = icmp ne <2 x i32> %conv, %a
+  ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_eq_non_boolean_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean_vec(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+;
+  %cmp = icmp eq <2 x i32> %a, <i32 2, i32 2>
+  %conv = zext <2 x i1> %cmp to <2 x i32>
+  %cmp1 = icmp ne <2 x i32> %conv, %a
+  ret <2 x i1> %cmp1
+}
+
 !0 = !{i32 1, i32 6}
 !1 = !{i32 0, i32 6}
 !2 = !{i8 0, i8 1}

>From bf79e8624a1578c65ca3adc4c3c95512c0e18d53 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 18 Sep 2023 22:36:02 +0800
Subject: [PATCH 02/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 .../lib/Transforms/InstCombine/InstCombineCompares.cpp | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index d0b62c17ec94358..d1f141bcf0e7df7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6391,10 +6391,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
         // icmp eq X, (zext (icmp eq X, 0)) --> false
         // icmp ne X, (zext (icmp eq X, 0)) --> true
         return replaceInstUsesWith(
-            I,
-            Constant::getIntegerValue(
-                I.getType(),
-                APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE))));
+            I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
       } else {
         // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
         // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
@@ -6412,10 +6409,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
         // icmp eq X, (zext (icmp ne X, 1)) --> false
         // icmp ne X, (zext (icmp ne X, 1)) --> true
         return replaceInstUsesWith(
-            I,
-            Constant::getIntegerValue(
-                I.getType(),
-                APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE))));
+            I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
       } else {
         // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
         // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1

>From ba475e31713758724305acbff496cbe605888da8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 18 Sep 2023 23:00:17 +0800
Subject: [PATCH 03/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 .../Transforms/InstCombine/InstCombineCompares.cpp  | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index d1f141bcf0e7df7..c5e3ad8a55741fb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6400,9 +6400,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
             Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
                                        : ICmpInst::ICMP_ULT,
             X,
-            Constant::getIntegerValue(
-                X->getType(), APInt(X->getType()->getScalarSizeInBits(),
-                                    Pred1 == ICmpInst::ICMP_NE ? 1 : 2)));
+            ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
       }
     } else if (C->isOne()) {
       if (Pred2 == ICmpInst::ICMP_NE) {
@@ -6418,9 +6416,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
             Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
                                        : ICmpInst::ICMP_ULT,
             X,
-            Constant::getIntegerValue(
-                X->getType(), APInt(X->getType()->getScalarSizeInBits(),
-                                    Pred1 == ICmpInst::ICMP_NE ? 1 : 2)));
+            ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
       }
     } else {
       // C != 0 && C != 1
@@ -6430,10 +6426,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
       // icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
       return ICmpInst::Create(
           Instruction::ICmp, Pred1, X,
-          Constant::getIntegerValue(
-              X->getType(),
-              APInt(X->getType()->getScalarSizeInBits(),
-                    static_cast<uint64_t>(Pred2 == ICmpInst::ICMP_NE))));
+          ConstantInt::get(X->getType(), Pred2 == ICmpInst::ICMP_NE ? 1 : 0));
     }
   }
 

>From 70a70fb44d0e628a1cf485e1767ada3eaaa26b0f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 19 Sep 2023 03:30:11 +0800
Subject: [PATCH 04/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 llvm/include/llvm/IR/PatternMatch.h           | 22 ++++++++
 .../InstCombine/InstCombineCompares.cpp       | 50 +++++++++++++------
 2 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 13877538f79de6d..38d40d1ec9a839e 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -767,6 +767,28 @@ m_ImmConstant(Constant *&C) {
   return m_CombineAnd(m_Constant(C), m_Unless(m_ConstantExpr()));
 }
 
+/// Match a pattern, capturing the value if we match.
+template <typename SubPattern_t, typename Class> struct capture_ty {
+  SubPattern_t SubPattern;
+  Class *&VR;
+
+  capture_ty(const SubPattern_t &SP, Class *&V) : SubPattern(SP), VR(V) {}
+
+  template <typename ITy> bool match(ITy *V) {
+    if (auto *CV = dyn_cast<Class>(V)) {
+      VR = CV;
+      return SubPattern.match(V);
+    }
+    return false;
+  }
+};
+
+template <typename T>
+inline capture_ty<T, Instruction> m_Instruction(Instruction *&I,
+                                                const T &SubPattern) {
+  return capture_ty<T, Instruction>(SubPattern, I);
+}
+
 /// Match a specified Value*.
 struct specificval_ty {
   const Value *Val;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c5e3ad8a55741fb..aca8611026ef1ca 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6380,53 +6380,71 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
       Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE)
     return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y);
 
+  // icmp eq/ne X, (zext/sext (icmp eq/ne X, C))
   ICmpInst::Predicate Pred1, Pred2;
   const APInt *C;
-  // icmp eq/ne X, (zext (icmp eq/ne X, C))
+  Instruction *ExtI;
   if (match(&I, m_c_ICmp(Pred1, m_Value(X),
-                         m_ZExt(m_ICmp(Pred2, m_Deferred(X), m_APInt(C))))) &&
-      ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
+                         m_Instruction(ExtI,
+                                       m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
+                                                           m_APInt(C))))))) {
+    bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
+    bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
     if (C->isZero()) {
       if (Pred2 == ICmpInst::ICMP_EQ) {
-        // icmp eq X, (zext (icmp eq X, 0)) --> false
-        // icmp ne X, (zext (icmp eq X, 0)) --> true
+        // icmp eq X, (zext/sext (icmp eq X, 0)) --> false
+        // icmp ne X, (zext/sext (icmp eq X, 0)) --> true
         return replaceInstUsesWith(
             I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
-      } else {
+      } else if (!IsSExt || HasOneUse) {
         // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
         // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
+        // icmp eq X, (sext (icmp ne X, 0)) --> icmp ult (X + 1), 2
+        // icmp ne X, (sext (icmp ne X, 0)) --> icmp ugt (X + 1), 1
         return ICmpInst::Create(
             Instruction::ICmp,
             Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
                                        : ICmpInst::ICMP_ULT,
-            X,
+            IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
+                   : X,
             ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
       }
-    } else if (C->isOne()) {
+    } else if (IsSExt ? C->isAllOnes() : C->isOne()) {
       if (Pred2 == ICmpInst::ICMP_NE) {
         // icmp eq X, (zext (icmp ne X, 1)) --> false
         // icmp ne X, (zext (icmp ne X, 1)) --> true
+        // icmp eq X, (sext (icmp ne X, -1)) --> false
+        // icmp ne X, (sext (icmp ne X, -1)) --> true
         return replaceInstUsesWith(
             I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
-      } else {
+      } else if (!IsSExt || HasOneUse) {
         // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
         // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1
+        // icmp eq X, (sext (icmp eq X, -1)) --> icmp ult (X + 1), 2
+        // icmp ne X, (sext (icmp eq X, -1)) --> icmp ugt (X + 1), 1
         return ICmpInst::Create(
             Instruction::ICmp,
             Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
                                        : ICmpInst::ICMP_ULT,
-            X,
+            IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
+                   : X,
             ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
       }
     } else {
-      // C != 0 && C != 1
-      // icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
-      // icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1
-      // icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
-      // icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
+      // when C != 0 && C != 1:
+      //   icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
+      //   icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1
+      //   icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
+      //   icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
+      // when C != 0 && C != -1:
+      //   icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
+      //   icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, -1
+      //   icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
+      //   icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, -1
       return ICmpInst::Create(
           Instruction::ICmp, Pred1, X,
-          ConstantInt::get(X->getType(), Pred2 == ICmpInst::ICMP_NE ? 1 : 0));
+          ConstantInt::get(X->getType(),
+                           Pred2 == ICmpInst::ICMP_NE ? (IsSExt ? -1 : 1) : 0));
     }
   }
 

>From 418562d5dbd25167d3f9b2c61fb7265581ee99d4 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 19 Sep 2023 03:39:23 +0800
Subject: [PATCH 05/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 llvm/include/llvm/IR/PatternMatch.h           | 22 -----
 .../InstCombine/InstCombineCompares.cpp       |  6 +-
 .../Transforms/InstCombine/and-or-icmps.ll    | 17 +---
 .../test/Transforms/InstCombine/icmp-range.ll | 82 ++++++-------------
 4 files changed, 31 insertions(+), 96 deletions(-)

diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 38d40d1ec9a839e..13877538f79de6d 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -767,28 +767,6 @@ m_ImmConstant(Constant *&C) {
   return m_CombineAnd(m_Constant(C), m_Unless(m_ConstantExpr()));
 }
 
-/// Match a pattern, capturing the value if we match.
-template <typename SubPattern_t, typename Class> struct capture_ty {
-  SubPattern_t SubPattern;
-  Class *&VR;
-
-  capture_ty(const SubPattern_t &SP, Class *&V) : SubPattern(SP), VR(V) {}
-
-  template <typename ITy> bool match(ITy *V) {
-    if (auto *CV = dyn_cast<Class>(V)) {
-      VR = CV;
-      return SubPattern.match(V);
-    }
-    return false;
-  }
-};
-
-template <typename T>
-inline capture_ty<T, Instruction> m_Instruction(Instruction *&I,
-                                                const T &SubPattern) {
-  return capture_ty<T, Instruction>(SubPattern, I);
-}
-
 /// Match a specified Value*.
 struct specificval_ty {
   const Value *Val;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index aca8611026ef1ca..b72bde885de124b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6385,9 +6385,9 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
   const APInt *C;
   Instruction *ExtI;
   if (match(&I, m_c_ICmp(Pred1, m_Value(X),
-                         m_Instruction(ExtI,
-                                       m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
-                                                           m_APInt(C))))))) {
+                         m_CombineAnd(m_Instruction(ExtI),
+                                      m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
+                                                          m_APInt(C))))))) {
     bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
     bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
     if (C->isZero()) {
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 065dbf261e131bf..2c887d574d397f6 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -366,19 +366,10 @@ define void @simplify_before_foldAndOfICmps(ptr %p) {
 ; CHECK-LABEL: @simplify_before_foldAndOfICmps(
 ; CHECK-NEXT:    [[A8:%.*]] = alloca i16, align 2
 ; CHECK-NEXT:    [[L7:%.*]] = load i16, ptr [[A8]], align 2
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i16 [[L7]], -1
-; CHECK-NEXT:    [[B11:%.*]] = zext i1 [[TMP1]] to i16
-; CHECK-NEXT:    [[C10:%.*]] = icmp ugt i16 [[L7]], [[B11]]
-; CHECK-NEXT:    [[C5:%.*]] = icmp slt i16 [[L7]], 1
-; CHECK-NEXT:    [[C7:%.*]] = icmp slt i16 [[L7]], 0
-; CHECK-NEXT:    [[B15:%.*]] = xor i1 [[C7]], [[C10]]
-; CHECK-NEXT:    [[C6:%.*]] = xor i1 [[B15]], true
-; CHECK-NEXT:    [[TMP2:%.*]] = and i1 [[C5]], [[C6]]
-; CHECK-NEXT:    [[C3:%.*]] = and i1 [[TMP2]], [[C10]]
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[C10]], true
-; CHECK-NEXT:    [[C18:%.*]] = or i1 [[C7]], [[TMP3]]
-; CHECK-NEXT:    [[TMP4:%.*]] = sext i1 [[C3]] to i64
-; CHECK-NEXT:    [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP4]]
+; CHECK-NEXT:    [[C18:%.*]] = icmp slt i16 [[L7]], 1
+; CHECK-NEXT:    [[L7_LOBIT:%.*]] = ashr i16 [[L7]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[L7_LOBIT]] to i64
+; CHECK-NEXT:    [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP1]]
 ; CHECK-NEXT:    store i16 [[L7]], ptr [[P:%.*]], align 2
 ; CHECK-NEXT:    store i1 [[C18]], ptr [[P]], align 1
 ; CHECK-NEXT:    store ptr [[G26]], ptr [[P]], align 8
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index f7efff9f675373a..3a40755384f2a21 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1164,7 +1164,7 @@ define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) {
 }
 
 define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) {
-; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec
+; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec(
 ; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
 ;
   %cmp = icmp eq <2 x i32> %a, <i32 0, i32 0>
@@ -1218,10 +1218,7 @@ define <2 x i1> @icmp_ne_zext_eq_non_boolean_vec(<2 x i32> %a) {
 
 define i1 @icmp_ne_sext_eq_zero(i32 %a) {
 ; CHECK-LABEL: @icmp_ne_sext_eq_zero(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP1]]
+; CHECK-NEXT:    ret i1 true
 ;
   %cmp = icmp eq i32 %a, 0
   %conv = sext i1 %cmp to i32
@@ -1231,9 +1228,8 @@ define i1 @icmp_ne_sext_eq_zero(i32 %a) {
 
 define i1 @icmp_ne_sext_ne_zero(i32 %a) {
 ; CHECK-LABEL: @icmp_ne_sext_ne_zero(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[TMP1]], -2
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp ne i32 %a, 0
@@ -1244,10 +1240,7 @@ define i1 @icmp_ne_sext_ne_zero(i32 %a) {
 
 define i1 @icmp_eq_sext_eq_zero(i32 %a) {
 ; CHECK-LABEL: @icmp_eq_sext_eq_zero(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP1]]
+; CHECK-NEXT:    ret i1 false
 ;
   %cmp = icmp eq i32 %a, 0
   %conv = sext i1 %cmp to i32
@@ -1257,9 +1250,8 @@ define i1 @icmp_eq_sext_eq_zero(i32 %a) {
 
 define i1 @icmp_eq_sext_ne_zero(i32 %a) {
 ; CHECK-LABEL: @icmp_eq_sext_ne_zero(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[TMP1]], 2
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp ne i32 %a, 0
@@ -1270,9 +1262,8 @@ define i1 @icmp_eq_sext_ne_zero(i32 %a) {
 
 define i1 @icmp_ne_sext_eq_allones(i32 %a) {
 ; CHECK-LABEL: @icmp_ne_sext_eq_allones(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], -1
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[TMP1]], -2
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp eq i32 %a, -1
@@ -1283,10 +1274,7 @@ define i1 @icmp_ne_sext_eq_allones(i32 %a) {
 
 define i1 @icmp_ne_sext_ne_allones(i32 %a) {
 ; CHECK-LABEL: @icmp_ne_sext_ne_allones(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], -1
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP1]]
+; CHECK-NEXT:    ret i1 true
 ;
   %cmp = icmp ne i32 %a, -1
   %conv = sext i1 %cmp to i32
@@ -1296,9 +1284,8 @@ define i1 @icmp_ne_sext_ne_allones(i32 %a) {
 
 define i1 @icmp_eq_sext_eq_allones(i32 %a) {
 ; CHECK-LABEL: @icmp_eq_sext_eq_allones(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], -1
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[TMP1]], 2
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp eq i32 %a, -1
@@ -1309,10 +1296,7 @@ define i1 @icmp_eq_sext_eq_allones(i32 %a) {
 
 define i1 @icmp_eq_sext_ne_allones(i32 %a) {
 ; CHECK-LABEL: @icmp_eq_sext_ne_allones(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], -1
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP1]]
+; CHECK-NEXT:    ret i1 false
 ;
   %cmp = icmp ne i32 %a, -1
   %conv = sext i1 %cmp to i32
@@ -1322,9 +1306,7 @@ define i1 @icmp_eq_sext_ne_allones(i32 %a) {
 
 define i1 @icmp_ne_sext_eq_otherwise(i32 %a) {
 ; CHECK-LABEL: @icmp_ne_sext_eq_otherwise(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp eq i32 %a, 2
@@ -1335,9 +1317,7 @@ define i1 @icmp_ne_sext_eq_otherwise(i32 %a) {
 
 define i1 @icmp_ne_sext_ne_otherwise(i32 %a) {
 ; CHECK-LABEL: @icmp_ne_sext_ne_otherwise(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp ne i32 %a, 2
@@ -1348,9 +1328,7 @@ define i1 @icmp_ne_sext_ne_otherwise(i32 %a) {
 
 define i1 @icmp_eq_sext_eq_otherwise(i32 %a) {
 ; CHECK-LABEL: @icmp_eq_sext_eq_otherwise(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp eq i32 %a, 2
@@ -1361,9 +1339,7 @@ define i1 @icmp_eq_sext_eq_otherwise(i32 %a) {
 
 define i1 @icmp_eq_sext_ne_otherwise(i32 %a) {
 ; CHECK-LABEL: @icmp_eq_sext_ne_otherwise(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
-; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[CMP1]]
 ;
   %cmp = icmp ne i32 %a, 2
@@ -1374,10 +1350,7 @@ define i1 @icmp_eq_sext_ne_otherwise(i32 %a) {
 
 define <2 x i1> @icmp_ne_sext_eq_zero_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_ne_sext_eq_zero_vec(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT:    [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
-; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
 ;
   %cmp = icmp eq <2 x i32> %a, <i32 0, i32 0>
   %conv = sext <2 x i1> %cmp to <2 x i32>
@@ -1387,9 +1360,8 @@ define <2 x i1> @icmp_ne_sext_eq_zero_vec(<2 x i32> %a) {
 
 define <2 x i1> @icmp_ne_sext_ne_zero_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_ne_sext_ne_zero_vec(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT:    [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 -2, i32 -2>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
 ;
   %cmp = icmp ne <2 x i32> %a, <i32 0, i32 0>
@@ -1400,9 +1372,8 @@ define <2 x i1> @icmp_ne_sext_ne_zero_vec(<2 x i32> %a) {
 
 define <2 x i1> @icmp_ne_sext_eq_allones_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_ne_sext_eq_allones_vec(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
-; CHECK-NEXT:    [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 -2, i32 -2>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
 ;
   %cmp = icmp eq <2 x i32> %a, <i32 -1, i32 -1>
@@ -1413,10 +1384,7 @@ define <2 x i1> @icmp_ne_sext_eq_allones_vec(<2 x i32> %a) {
 
 define <2 x i1> @icmp_ne_sext_ne_allones_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_ne_sext_ne_allones_vec(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
-; CHECK-NEXT:    [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
-; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
+; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
 ;
   %cmp = icmp ne <2 x i32> %a, <i32 -1, i32 -1>
   %conv = sext <2 x i1> %cmp to <2 x i32>
@@ -1426,9 +1394,7 @@ define <2 x i1> @icmp_ne_sext_ne_allones_vec(<2 x i32> %a) {
 
 define <2 x i1> @icmp_ne_sext_eq_otherwise_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_ne_sext_eq_otherwise_vec(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 2, i32 2>
-; CHECK-NEXT:    [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
 ; CHECK-NEXT:    ret <2 x i1> [[CMP1]]
 ;
   %cmp = icmp eq <2 x i32> %a, <i32 2, i32 2>

>From b7565ccc7090e15f6330da274225420691a4160d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 19 Sep 2023 10:24:50 +0800
Subject: [PATCH 06/10] [InstCombine] Fix comments `zext` -> `sext`. NFC.

---
 llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index b72bde885de124b..c7b9366bfd45e41 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6437,10 +6437,10 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
       //   icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
       //   icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
       // when C != 0 && C != -1:
-      //   icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
-      //   icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, -1
-      //   icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
-      //   icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, -1
+      //   icmp eq X, (sext (icmp eq X, C)) --> icmp eq X, 0
+      //   icmp eq X, (sext (icmp ne X, C)) --> icmp eq X, -1
+      //   icmp ne X, (sext (icmp eq X, C)) --> icmp ne X, 0
+      //   icmp ne X, (sext (icmp ne X, C)) --> icmp ne X, -1
       return ICmpInst::Create(
           Instruction::ICmp, Pred1, X,
           ConstantInt::get(X->getType(),

>From 5b5052403968d4b394b30779c8912a1e732e9998 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Sep 2023 17:59:26 +0800
Subject: [PATCH 07/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 .../InstCombine/InstCombineCompares.cpp       | 39 ++++++++-----------
 1 file changed, 17 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c7b9366bfd45e41..7c7ab62c64dac89 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6390,6 +6390,13 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
                                                           m_APInt(C))))))) {
     bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
     bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
+    auto CreateRangeCheck = [&] {
+      Value *V1 = Constant::getNullValue(X->getType());
+      Value *V2 = ConstantInt::get(X->getType(), IsSExt ? -1 : 1);
+      return BinaryOperator::Create(
+          Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
+          Builder.CreateICmp(Pred1, X, V1), Builder.CreateICmp(Pred1, X, V2));
+    };
     if (C->isZero()) {
       if (Pred2 == ICmpInst::ICMP_EQ) {
         // icmp eq X, (zext/sext (icmp eq X, 0)) --> false
@@ -6397,17 +6404,11 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
         return replaceInstUsesWith(
             I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
       } else if (!IsSExt || HasOneUse) {
-        // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
-        // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
-        // icmp eq X, (sext (icmp ne X, 0)) --> icmp ult (X + 1), 2
-        // icmp ne X, (sext (icmp ne X, 0)) --> icmp ugt (X + 1), 1
-        return ICmpInst::Create(
-            Instruction::ICmp,
-            Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
-                                       : ICmpInst::ICMP_ULT,
-            IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
-                   : X,
-            ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
+        // icmp eq X, (zext (icmp ne X, 0)) --> X == 0 || X == 1
+        // icmp ne X, (zext (icmp ne X, 0)) --> X != 0 && X != 1
+        // icmp eq X, (sext (icmp ne X, 0)) --> X == 0 || X == -1
+        // icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X == -1
+        return CreateRangeCheck();
       }
     } else if (IsSExt ? C->isAllOnes() : C->isOne()) {
       if (Pred2 == ICmpInst::ICMP_NE) {
@@ -6418,17 +6419,11 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
         return replaceInstUsesWith(
             I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
       } else if (!IsSExt || HasOneUse) {
-        // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
-        // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1
-        // icmp eq X, (sext (icmp eq X, -1)) --> icmp ult (X + 1), 2
-        // icmp ne X, (sext (icmp eq X, -1)) --> icmp ugt (X + 1), 1
-        return ICmpInst::Create(
-            Instruction::ICmp,
-            Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
-                                       : ICmpInst::ICMP_ULT,
-            IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
-                   : X,
-            ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
+        // icmp eq X, (zext (icmp eq X, 1)) --> X == 0 || X == 1
+        // icmp ne X, (zext (icmp eq X, 1)) --> X != 0 && X != 1
+        // icmp eq X, (sext (icmp eq X, -1)) --> X == 0 || X == -1
+        // icmp ne X, (sext (icmp eq X, -1)) --> X != 0 && X == -1
+        return CreateRangeCheck();
       }
     } else {
       // when C != 0 && C != 1:

>From 55d52b1f05004abe6c4187dc07437580c7f5aa73 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Sep 2023 21:49:47 +0800
Subject: [PATCH 08/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7c7ab62c64dac89..9f2d0c8110f79e0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6391,11 +6391,13 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
     bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
     bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
     auto CreateRangeCheck = [&] {
-      Value *V1 = Constant::getNullValue(X->getType());
-      Value *V2 = ConstantInt::get(X->getType(), IsSExt ? -1 : 1);
+      Value *CmpV1 =
+          Builder.CreateICmp(Pred1, X, Constant::getNullValue(X->getType()));
+      Value *CmpV2 = Builder.CreateICmp(
+          Pred1, X, ConstantInt::get(X->getType(), IsSExt ? -1 : 1));
       return BinaryOperator::Create(
           Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
-          Builder.CreateICmp(Pred1, X, V1), Builder.CreateICmp(Pred1, X, V2));
+          CmpV1, CmpV2);
     };
     if (C->isZero()) {
       if (Pred2 == ICmpInst::ICMP_EQ) {

>From c0d8f8193fa1620db1f84379f2316fcf4b401e4c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 1 Oct 2023 20:10:57 +0800
Subject: [PATCH 09/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

---
 .../InstCombine/InstCombineCompares.cpp       | 10 ++++----
 .../Transforms/InstCombine/and-or-icmps.ll    | 17 ++++++++++----
 .../test/Transforms/InstCombine/icmp-range.ll | 23 +++++++++++++++++++
 3 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 9f2d0c8110f79e0..4fca8859dea7acc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6387,14 +6387,15 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
   if (match(&I, m_c_ICmp(Pred1, m_Value(X),
                          m_CombineAnd(m_Instruction(ExtI),
                                       m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
-                                                          m_APInt(C))))))) {
+                                                          m_APInt(C)))))) &&
+      ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
     bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
     bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
     auto CreateRangeCheck = [&] {
       Value *CmpV1 =
           Builder.CreateICmp(Pred1, X, Constant::getNullValue(X->getType()));
       Value *CmpV2 = Builder.CreateICmp(
-          Pred1, X, ConstantInt::get(X->getType(), IsSExt ? -1 : 1));
+          Pred1, X, ConstantInt::getSigned(X->getType(), IsSExt ? -1 : 1));
       return BinaryOperator::Create(
           Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
           CmpV1, CmpV2);
@@ -6440,8 +6441,9 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
       //   icmp ne X, (sext (icmp ne X, C)) --> icmp ne X, -1
       return ICmpInst::Create(
           Instruction::ICmp, Pred1, X,
-          ConstantInt::get(X->getType(),
-                           Pred2 == ICmpInst::ICMP_NE ? (IsSExt ? -1 : 1) : 0));
+          ConstantInt::getSigned(X->getType(), Pred2 == ICmpInst::ICMP_NE
+                                                   ? (IsSExt ? -1 : 1)
+                                                   : 0));
     }
   }
 
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 2c887d574d397f6..065dbf261e131bf 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -366,10 +366,19 @@ define void @simplify_before_foldAndOfICmps(ptr %p) {
 ; CHECK-LABEL: @simplify_before_foldAndOfICmps(
 ; CHECK-NEXT:    [[A8:%.*]] = alloca i16, align 2
 ; CHECK-NEXT:    [[L7:%.*]] = load i16, ptr [[A8]], align 2
-; CHECK-NEXT:    [[C18:%.*]] = icmp slt i16 [[L7]], 1
-; CHECK-NEXT:    [[L7_LOBIT:%.*]] = ashr i16 [[L7]], 15
-; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[L7_LOBIT]] to i64
-; CHECK-NEXT:    [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i16 [[L7]], -1
+; CHECK-NEXT:    [[B11:%.*]] = zext i1 [[TMP1]] to i16
+; CHECK-NEXT:    [[C10:%.*]] = icmp ugt i16 [[L7]], [[B11]]
+; CHECK-NEXT:    [[C5:%.*]] = icmp slt i16 [[L7]], 1
+; CHECK-NEXT:    [[C7:%.*]] = icmp slt i16 [[L7]], 0
+; CHECK-NEXT:    [[B15:%.*]] = xor i1 [[C7]], [[C10]]
+; CHECK-NEXT:    [[C6:%.*]] = xor i1 [[B15]], true
+; CHECK-NEXT:    [[TMP2:%.*]] = and i1 [[C5]], [[C6]]
+; CHECK-NEXT:    [[C3:%.*]] = and i1 [[TMP2]], [[C10]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i1 [[C10]], true
+; CHECK-NEXT:    [[C18:%.*]] = or i1 [[C7]], [[TMP3]]
+; CHECK-NEXT:    [[TMP4:%.*]] = sext i1 [[C3]] to i64
+; CHECK-NEXT:    [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP4]]
 ; CHECK-NEXT:    store i16 [[L7]], ptr [[P:%.*]], align 2
 ; CHECK-NEXT:    store i1 [[C18]], ptr [[P]], align 1
 ; CHECK-NEXT:    store ptr [[G26]], ptr [[P]], align 8
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 3a40755384f2a21..79790b7458d4219 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1403,6 +1403,29 @@ define <2 x i1> @icmp_ne_sext_eq_otherwise_vec(<2 x i32> %a) {
   ret <2 x i1> %cmp1
 }
 
+define i1 @icmp_ne_sext_ne_zero_i128(i128 %a) {
+; CHECK-LABEL: @icmp_ne_sext_ne_zero_i128(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i128 [[A:%.*]], -1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i128 [[TMP1]], -2
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i128 %a, 0
+  %conv = sext i1 %cmp to i128
+  %cmp1 = icmp ne i128 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_sext_ne_otherwise_i128(i128 %a) {
+; CHECK-LABEL: @icmp_ne_sext_ne_otherwise_i128(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i128 [[A:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i128 %a, 2
+  %conv = sext i1 %cmp to i128
+  %cmp1 = icmp ne i128 %conv, %a
+  ret i1 %cmp1
+}
+
 !0 = !{i32 1, i32 6}
 !1 = !{i32 0, i32 6}
 !2 = !{i8 0, i8 1}

>From 2285a2c6b8e66cf35aed6151c61e841f1349817f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 6 Oct 2023 17:17:53 +0800
Subject: [PATCH 10/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
 (zext (a ne/eq c))`

Add negative tests
---
 .../test/Transforms/InstCombine/icmp-range.ll | 79 +++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 17903be937057ab..7af06e03fd4b2a9 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1426,6 +1426,85 @@ define i1 @icmp_ne_sext_ne_otherwise_i128(i128 %a) {
   ret i1 %cmp1
 }
 
+; Negative tests with non-equality predicates
+define i1 @icmp_ne_sext_sgt_zero_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_ne_sext_sgt_zero_nofold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp sgt i32 %a, 0
+  %conv = sext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_slt_sext_ne_zero_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_slt_sext_ne_zero_nofold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
+; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[CONV]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, 0
+  %conv = sext i1 %cmp to i32
+  %cmp1 = icmp slt i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_sext_slt_allones_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_ne_sext_slt_allones_nofold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp slt i32 %a, -1
+  %conv = sext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_slt_sext_ne_allones_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_slt_sext_ne_allones_nofold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[CONV]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, -1
+  %conv = sext i1 %cmp to i32
+  %cmp1 = icmp slt i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_ne_sext_slt_otherwise_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_ne_sext_slt_otherwise_nofold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 2
+; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp slt i32 %a, 2
+  %conv = sext i1 %cmp to i32
+  %cmp1 = icmp ne i32 %conv, %a
+  ret i1 %cmp1
+}
+
+define i1 @icmp_slt_sext_ne_otherwise_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_slt_sext_ne_otherwise_nofold(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
+; CHECK-NEXT:    [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[CONV]], [[A]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+  %cmp = icmp ne i32 %a, 2
+  %conv = sext i1 %cmp to i32
+  %cmp1 = icmp slt i32 %conv, %a
+  ret i1 %cmp1
+}
+
 ; tests from PR59555
 define i1 @isFloat(i64 %0) {
 ; CHECK-LABEL: @isFloat(



More information about the llvm-commits mailing list