[llvm] [InstCombine] Optimize and of overflow checks (PR #141962)

Bobby SONG via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 19 02:59:20 PDT 2026


https://github.com/bobby-b-song updated https://github.com/llvm/llvm-project/pull/141962

>From 7d6888eda95f1e2715a3d77a58972c730465f4c2 Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Thu, 29 May 2025 16:09:45 +0100
Subject: [PATCH 1/8] Add test case for issue 141479

---
 .../and-comparison-not-always-false.ll        | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll

diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
new file mode 100644
index 0000000000000..174d97d30bcf8
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+define i1 @test(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP0]], -1
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ule i32 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]]
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+;
+common.ret:
+  %2 = xor i32 %0, -1
+  %3 = icmp ule i32 %1, %2
+  %4 = xor i32 %1, -1
+  %5 = icmp ugt i32 %0, %4
+  %common.ret.op = and i1 %3, %5
+  ret i1 %common.ret.op
+}

>From b11691e95f5984138f8ce3ab18280c5db58b1a18 Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Thu, 29 May 2025 18:52:27 +0100
Subject: [PATCH 2/8] Added missed optimization: need optimization for further
 adaption

Add test for optimization

Extend the case further to signed intergers and more in/exclusive ranges

Update test for optimization
---
 llvm/lib/Analysis/InstructionSimplify.cpp     |  14 ++
 .../and-comparison-not-always-false.ll        | 125 +++++++++++++++++-
 2 files changed, 135 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 23e147ba8c6a1..e626d91a81f0b 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2178,6 +2178,20 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
       match(Op1, m_Xor(m_Specific(A), m_SpecificInt(~*C1))))
     return Constant::getNullValue(Op0->getType());
 
+  // (X <= ~Y) && (Y > ~X) --> 0
+  CmpPredicate Pred0, Pred1;
+  if (match(Op0,
+            m_c_ICmp(Pred0, m_Value(X), m_c_Xor(m_Value(Y), m_AllOnes()))) &&
+      match(Op1, m_c_ICmp(Pred1, m_Specific(Y),
+                          m_c_Xor(m_Specific(X), m_AllOnes())))) {
+    if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1))
+      return ConstantInt::getFalse(Op0->getType());
+    if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1))
+      return ConstantInt::getFalse(Op0->getType());
+    if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1))
+      return ConstantInt::getFalse(Op0->getType());
+  }
+
   if (Op0->getType()->isIntOrIntVectorTy(1)) {
     if (std::optional<bool> Implied = isImpliedCondition(Op0, Op1, Q.DL)) {
       // If Op0 is true implies Op1 is true, then Op0 is a subset of Op1.
diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
index 174d97d30bcf8..0ed39decf578c 100644
--- a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
+++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
@@ -1,13 +1,73 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-define i1 @test(i32 %0, i32 %1) {
-; CHECK-LABEL: define i1 @test(
+define i1 @test_pass_et(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test_pass_et(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+common.ret:
+  %2 = xor i32 %0, -1
+  %3 = icmp ule i32 %1, %2
+  %4 = xor i32 %1, -1
+  %5 = icmp ugt i32 %0, %4
+  %common.ret.op = and i1 %3, %5
+  ret i1 %common.ret.op
+}
+
+define i1 @test_pass_signed(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test_pass_signed(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+common.ret:
+  %2 = xor i32 %0, -1
+  %3 = icmp sle i32 %1, %2
+  %4 = xor i32 %1, -1
+  %5 = icmp sgt i32 %0, %4
+  %common.ret.op = and i1 %3, %5
+  ret i1 %common.ret.op
+}
+
+define i1 @test_pass_tt(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test_pass_tt(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+common.ret:
+  %2 = xor i32 %0, -1
+  %3 = icmp ult i32 %1, %2
+  %4 = xor i32 %1, -1
+  %5 = icmp ugt i32 %0, %4
+  %common.ret.op = and i1 %3, %5
+  ret i1 %common.ret.op
+}
+
+define i1 @test_pass_te(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test_pass_te(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    ret i1 false
+;
+common.ret:
+  %2 = xor i32 %0, -1
+  %3 = icmp ult i32 %1, %2
+  %4 = xor i32 %1, -1
+  %5 = icmp uge i32 %0, %4
+  %common.ret.op = and i1 %3, %5
+  ret i1 %common.ret.op
+}
+
+define i1 @test_nopass_ee(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test_nopass_ee(
 ; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
 ; CHECK-NEXT:  [[COMMON_RET:.*:]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP0]], -1
 ; CHECK-NEXT:    [[TMP3:%.*]] = icmp ule i32 [[TMP1]], [[TMP2]]
 ; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP1]], -1
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP0]], [[TMP4]]
 ; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
 ; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
 ;
@@ -15,7 +75,64 @@ common.ret:
   %2 = xor i32 %0, -1
   %3 = icmp ule i32 %1, %2
   %4 = xor i32 %1, -1
-  %5 = icmp ugt i32 %0, %4
+  %5 = icmp uge i32 %0, %4
   %common.ret.op = and i1 %3, %5
   ret i1 %common.ret.op
 }
+
+define i1 @test_no_change_et(i32 %0, i32 %1, i32 %2) {
+; CHECK-LABEL: define i1 @test_no_change_et(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP1]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+;
+common.ret:
+  %3 = xor i32 %0, -1
+  %4 = icmp ule i32 %1, %3
+  %5 = xor i32 %1, -1
+  %6 = icmp ugt i32 %1, %5
+  %common.ret.op = and i1 %6, %4
+  ret i1 %common.ret.op
+}
+
+define i1 @test_no_change_te(i32 %0, i32 %1, i32 %2) {
+; CHECK-LABEL: define i1 @test_no_change_te(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP1]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+;
+common.ret:
+  %3 = xor i32 %0, -1
+  %4 = icmp ult i32 %1, %3
+  %5 = xor i32 %1, -1
+  %6 = icmp uge i32 %1, %5
+  %common.ret.op = and i1 %6, %4
+  ret i1 %common.ret.op
+}
+
+define i1 @test_no_change_tt(i32 %0, i32 %1, i32 %2) {
+; CHECK-LABEL: define i1 @test_no_change_tt(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP1]], [[TMP3]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+;
+common.ret:
+  %3 = xor i32 %0, -1
+  %4 = icmp ult i32 %1, %3
+  %5 = xor i32 %1, -1
+  %6 = icmp ugt i32 %1, %5
+  %common.ret.op = and i1 %6, %4
+  ret i1 %common.ret.op
+}

>From 821f62d052cef4d3d933776f1be5371fb65128a6 Mon Sep 17 00:00:00 2001
From: Bobby SONG <s2294799 at ed.ac.uk>
Date: Fri, 12 Sep 2025 13:01:21 +0100
Subject: [PATCH 3/8] Update llvm/lib/Analysis/InstructionSimplify.cpp

Co-authored-by: Nikita Popov <github at npopov.com>

Update llvm/lib/Analysis/InstructionSimplify.cpp

Co-authored-by: Nikita Popov <github at npopov.com>
---
 llvm/lib/Analysis/InstructionSimplify.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 5d9c5c65cf387..622ab752f9013 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2179,9 +2179,9 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
   // (X <= ~Y) && (Y > ~X) --> 0
   CmpPredicate Pred0, Pred1;
   if (match(Op0,
-            m_c_ICmp(Pred0, m_Value(X), m_c_Xor(m_Value(Y), m_AllOnes()))) &&
+            m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) &&
       match(Op1, m_c_ICmp(Pred1, m_Specific(Y),
-                          m_c_Xor(m_Specific(X), m_AllOnes())))) {
+                          m_Not(m_Specific(X))))) {
     if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1))
       return ConstantInt::getFalse(Op0->getType());
     if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1))

>From 1c6aab2d0b7ecf3eec48bf16e1482f0f5ffa0ee1 Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Fri, 12 Sep 2025 16:06:37 +0100
Subject: [PATCH 4/8] Change predicate match to expect same sign state

---
 llvm/lib/Analysis/InstructionSimplify.cpp     | 14 +++++++------
 .../and-comparison-not-always-false.ll        | 20 +++++++++++++++++++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 622ab752f9013..aaa7b0a4ede84 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2182,12 +2182,14 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
             m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) &&
       match(Op1, m_c_ICmp(Pred1, m_Specific(Y),
                           m_Not(m_Specific(X))))) {
-    if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1))
-      return ConstantInt::getFalse(Op0->getType());
-    if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1))
-      return ConstantInt::getFalse(Op0->getType());
-    if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1))
-      return ConstantInt::getFalse(Op0->getType());
+    if (ICmpInst::isSigned(Pred0) == ICmpInst::isSigned(Pred1)) {
+      if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1))
+        return ConstantInt::getFalse(Op0->getType());
+      if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1))
+        return ConstantInt::getFalse(Op0->getType());
+      if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1))
+        return ConstantInt::getFalse(Op0->getType());
+    }
   }
 
   if (Op0->getType()->isIntOrIntVectorTy(1)) {
diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
index 0ed39decf578c..e336202079ca3 100644
--- a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
+++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
@@ -136,3 +136,23 @@ common.ret:
   %common.ret.op = and i1 %6, %4
   ret i1 %common.ret.op
 }
+
+define i1 @test_no_change_su(i32 %0, i32 %1) {
+; CHECK-LABEL: define i1 @test_no_change_su(
+; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
+; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP0]], -1
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp sle i32 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]]
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+;
+common.ret:
+  %2 = xor i32 %0, -1
+  %3 = icmp sle i32 %1, %2
+  %4 = xor i32 %1, -1
+  %5 = icmp ugt i32 %0, %4
+  %common.ret.op = and i1 %3, %5
+  ret i1 %common.ret.op
+}

>From 893bbf8c74e5481b7fdda6b062a21f7a2908f58c Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Mon, 15 Sep 2025 10:28:18 +0100
Subject: [PATCH 5/8] Fix formatting

---
 llvm/lib/Analysis/InstructionSimplify.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index aaa7b0a4ede84..f899c7929a017 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2178,10 +2178,8 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
 
   // (X <= ~Y) && (Y > ~X) --> 0
   CmpPredicate Pred0, Pred1;
-  if (match(Op0,
-            m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) &&
-      match(Op1, m_c_ICmp(Pred1, m_Specific(Y),
-                          m_Not(m_Specific(X))))) {
+  if (match(Op0, m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) &&
+      match(Op1, m_c_ICmp(Pred1, m_Specific(Y), m_Not(m_Specific(X))))) {
     if (ICmpInst::isSigned(Pred0) == ICmpInst::isSigned(Pred1)) {
       if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1))
         return ConstantInt::getFalse(Op0->getType());

>From d8d5504076b8ae0ac6db57cc5b50ae7abd742e38 Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Mon, 18 May 2026 12:47:01 +0100
Subject: [PATCH 6/8] Add additional optimisation checks

---
 llvm/lib/Analysis/InstructionSimplify.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 3ace9b4a02e2a..c2030e51e36be 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2190,6 +2190,12 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
     }
   }
 
+  // Same idiom as last check, but uses m_UAddWithOverflow, as suggested in pr141962
+  BinaryOperator* BO;
+  if (match(Op0, m_UAddWithOverflow(m_Value(X), m_Value(Y), m_BinOp(BO))) &&
+      match(Op1, m_UAddWithOverflow(m_Specific(Y), m_Specific(X), m_BinOp(BO))))
+    return ConstantInt::getFalse(Op0->getType());
+
   if (Op0->getType()->isIntOrIntVectorTy(1)) {
     if (std::optional<bool> Implied = isImpliedCondition(Op0, Op1, Q.DL)) {
       // If Op0 is true implies Op1 is true, then Op0 is a subset of Op1.

>From 9d2dac8f4e0aa1c906d9feda9692d2dcf7edee51 Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Mon, 18 May 2026 13:50:46 +0100
Subject: [PATCH 7/8] Used ICmpInst::isImpliedByMatchingCmp instead of dumb
 matching, added commuted tests.

---
 llvm/lib/Analysis/InstructionSimplify.cpp     |   8 +-
 .../and-comparison-not-always-false.ll        | 291 +++++++++++-------
 2 files changed, 176 insertions(+), 123 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index c2030e51e36be..7e048bf98bf9f 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2176,16 +2176,12 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
       match(Op1, m_Xor(m_Specific(A), m_SpecificInt(~*C1))))
     return Constant::getNullValue(Op0->getType());
 
-  // (X <= ~Y) && (Y > ~X) --> 0
+  // (X Pred0 ~Y) && (Y Pred1 ~X) --> 0 if Pred0 implies !Pred1.
   CmpPredicate Pred0, Pred1;
   if (match(Op0, m_c_ICmp(Pred0, m_Value(X), m_Not(m_Value(Y)))) &&
       match(Op1, m_c_ICmp(Pred1, m_Specific(Y), m_Not(m_Specific(X))))) {
     if (ICmpInst::isSigned(Pred0) == ICmpInst::isSigned(Pred1)) {
-      if (ICmpInst::isLE(Pred0) && ICmpInst::isGT(Pred1))
-        return ConstantInt::getFalse(Op0->getType());
-      if (ICmpInst::isLT(Pred0) && ICmpInst::isGE(Pred1))
-        return ConstantInt::getFalse(Op0->getType());
-      if (ICmpInst::isLT(Pred0) && ICmpInst::isGT(Pred1))
+      if (ICmpInst::isImpliedByMatchingCmp(Pred0, Pred1) == false)
         return ConstantInt::getFalse(Op0->getType());
     }
   }
diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
index e336202079ca3..f4f40fe39e52a 100644
--- a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
+++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
@@ -1,158 +1,215 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-define i1 @test_pass_et(i32 %0, i32 %1) {
+define i1 @test_pass_et(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_pass_et(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
 ; CHECK-NEXT:    ret i1 false
 ;
-common.ret:
-  %2 = xor i32 %0, -1
-  %3 = icmp ule i32 %1, %2
-  %4 = xor i32 %1, -1
-  %5 = icmp ugt i32 %0, %4
-  %common.ret.op = and i1 %3, %5
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ule i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x0, %not.x1
+  %op = and i1 %cmp0, %cmp1
+  ret i1 %op
 }
 
-define i1 @test_pass_signed(i32 %0, i32 %1) {
+define i1 @test_pass_et_commuted(i32 %x0, i32 %x1) {
+; CHECK-LABEL: define i1 @test_pass_et_commuted(
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ule i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x0, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
+}
+
+define i1 @test_pass_signed(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_pass_signed(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
 ; CHECK-NEXT:    ret i1 false
 ;
-common.ret:
-  %2 = xor i32 %0, -1
-  %3 = icmp sle i32 %1, %2
-  %4 = xor i32 %1, -1
-  %5 = icmp sgt i32 %0, %4
-  %common.ret.op = and i1 %3, %5
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp sle i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp sgt i32 %x0, %not.x1
+  %op = and i1 %cmp0, %cmp1
+  ret i1 %op
 }
 
-define i1 @test_pass_tt(i32 %0, i32 %1) {
+define i1 @test_pass_tt(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_pass_tt(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
 ; CHECK-NEXT:    ret i1 false
 ;
-common.ret:
-  %2 = xor i32 %0, -1
-  %3 = icmp ult i32 %1, %2
-  %4 = xor i32 %1, -1
-  %5 = icmp ugt i32 %0, %4
-  %common.ret.op = and i1 %3, %5
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ult i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x0, %not.x1
+  %op = and i1 %cmp0, %cmp1
+  ret i1 %op
 }
 
-define i1 @test_pass_te(i32 %0, i32 %1) {
+define i1 @test_pass_tt_commuted(i32 %x0, i32 %x1) {
+; CHECK-LABEL: define i1 @test_pass_tt_commuted(
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ult i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x0, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
+}
+
+define i1 @test_pass_te(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_pass_te(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    ret i1 false
+;
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ult i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp uge i32 %x0, %not.x1
+  %op = and i1 %cmp0, %cmp1
+  ret i1 %op
+}
+
+define i1 @test_pass_te_commuted(i32 %x0, i32 %x1) {
+; CHECK-LABEL: define i1 @test_pass_te_commuted(
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
 ; CHECK-NEXT:    ret i1 false
 ;
-common.ret:
-  %2 = xor i32 %0, -1
-  %3 = icmp ult i32 %1, %2
-  %4 = xor i32 %1, -1
-  %5 = icmp uge i32 %0, %4
-  %common.ret.op = and i1 %3, %5
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ult i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp uge i32 %x0, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
 }
 
-define i1 @test_nopass_ee(i32 %0, i32 %1) {
+define i1 @test_nopass_ee(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_nopass_ee(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
-; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT:    [[TMP3:%.*]] = icmp ule i32 [[TMP1]], [[TMP2]]
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP1]], -1
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP0]], [[TMP4]]
-; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
-; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ule i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[NOT_X1:%.*]] = xor i32 [[X1]], -1
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[X0]], [[NOT_X1]]
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    ret i1 [[OP]]
 ;
-common.ret:
-  %2 = xor i32 %0, -1
-  %3 = icmp ule i32 %1, %2
-  %4 = xor i32 %1, -1
-  %5 = icmp uge i32 %0, %4
-  %common.ret.op = and i1 %3, %5
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ule i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp uge i32 %x0, %not.x1
+  %op = and i1 %cmp0, %cmp1
+  ret i1 %op
 }
 
-define i1 @test_no_change_et(i32 %0, i32 %1, i32 %2) {
+define i1 @test_nopass_ee_commuted(i32 %x0, i32 %x1) {
+; CHECK-LABEL: define i1 @test_nopass_ee_commuted(
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp ule i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[NOT_X1:%.*]] = xor i32 [[X1]], -1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp uge i32 [[X0]], [[NOT_X1]]
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT:    ret i1 [[OP]]
+;
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ule i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp uge i32 %x0, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
+}
+
+define i1 @test_no_change_et(i32 %x0, i32 %x1, i32 %x2) {
 ; CHECK-LABEL: define i1 @test_no_change_et(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP1]], [[TMP3]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
-; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
-; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[X1]], 0
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[OP]]
 ;
-common.ret:
-  %3 = xor i32 %0, -1
-  %4 = icmp ule i32 %1, %3
-  %5 = xor i32 %1, -1
-  %6 = icmp ugt i32 %1, %5
-  %common.ret.op = and i1 %6, %4
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ule i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x1, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
 }
 
-define i1 @test_no_change_te(i32 %0, i32 %1, i32 %2) {
+define i1 @test_no_change_te(i32 %x0, i32 %x1, i32 %x2) {
 ; CHECK-LABEL: define i1 @test_no_change_te(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP1]], [[TMP3]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
-; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
-; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[X1]], 0
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[OP]]
 ;
-common.ret:
-  %3 = xor i32 %0, -1
-  %4 = icmp ult i32 %1, %3
-  %5 = xor i32 %1, -1
-  %6 = icmp uge i32 %1, %5
-  %common.ret.op = and i1 %6, %4
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ult i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp uge i32 %x1, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
 }
 
-define i1 @test_no_change_tt(i32 %0, i32 %1, i32 %2) {
+define i1 @test_no_change_tt(i32 %x0, i32 %x1, i32 %x2) {
 ; CHECK-LABEL: define i1 @test_no_change_tt(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP1]], [[TMP3]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP1]], 0
-; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
-; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[X1]], 0
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[TMP5]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[OP]]
 ;
-common.ret:
-  %3 = xor i32 %0, -1
-  %4 = icmp ult i32 %1, %3
-  %5 = xor i32 %1, -1
-  %6 = icmp ugt i32 %1, %5
-  %common.ret.op = and i1 %6, %4
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp ult i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x1, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
 }
 
-define i1 @test_no_change_su(i32 %0, i32 %1) {
+define i1 @test_no_change_su(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_no_change_su(
-; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
-; CHECK-NEXT:  [[COMMON_RET:.*:]]
-; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT:    [[TMP3:%.*]] = icmp sle i32 [[TMP1]], [[TMP2]]
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP1]], -1
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP0]], [[TMP4]]
-; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
-; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp sle i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[NOT_X1:%.*]] = xor i32 [[X1]], -1
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[X0]], [[NOT_X1]]
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[TMP3]], [[TMP5]]
+; CHECK-NEXT:    ret i1 [[OP]]
+;
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp sle i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x0, %not.x1
+  %op = and i1 %cmp0, %cmp1
+  ret i1 %op
+}
+
+define i1 @test_no_change_su_commuted(i32 %x0, i32 %x1) {
+; CHECK-LABEL: define i1 @test_no_change_su_commuted(
+; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor i32 [[X0]], -1
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp sle i32 [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[NOT_X1:%.*]] = xor i32 [[X1]], -1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i32 [[X0]], [[NOT_X1]]
+; CHECK-NEXT:    [[OP:%.*]] = and i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT:    ret i1 [[OP]]
 ;
-common.ret:
-  %2 = xor i32 %0, -1
-  %3 = icmp sle i32 %1, %2
-  %4 = xor i32 %1, -1
-  %5 = icmp ugt i32 %0, %4
-  %common.ret.op = and i1 %3, %5
-  ret i1 %common.ret.op
+  %not.x0 = xor i32 %x0, -1
+  %cmp0 = icmp sle i32 %x1, %not.x0
+  %not.x1 = xor i32 %x1, -1
+  %cmp1 = icmp ugt i32 %x0, %not.x1
+  %op = and i1 %cmp1, %cmp0
+  ret i1 %op
 }

>From 96a53c21a686dc41278168ae3326b81305d46716 Mon Sep 17 00:00:00 2001
From: Bobby Song <me at bby.ee>
Date: Mon, 18 May 2026 13:56:38 +0100
Subject: [PATCH 8/8] Add vector tests as per InstCombineContributorGuide

---
 .../and-comparison-not-always-false.ll        | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
index f4f40fe39e52a..f2c698f12539c 100644
--- a/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
+++ b/llvm/test/Transforms/InstCombine/and-comparison-not-always-false.ll
@@ -26,6 +26,50 @@ define i1 @test_pass_et_commuted(i32 %x0, i32 %x1) {
   ret i1 %op
 }
 
+define <2 x i1> @test_pass_et_vec_splat(<2 x i8> %x0, <2 x i8> %x1) {
+; CHECK-LABEL: define <2 x i1> @test_pass_et_vec_splat(
+; CHECK-SAME: <2 x i8> [[X0:%.*]], <2 x i8> [[X1:%.*]]) {
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %not.x0 = xor <2 x i8> %x0, <i8 -1, i8 -1>
+  %cmp0 = icmp ule <2 x i8> %x1, %not.x0
+  %not.x1 = xor <2 x i8> %x1, <i8 -1, i8 -1>
+  %cmp1 = icmp ugt <2 x i8> %x0, %not.x1
+  %op = and <2 x i1> %cmp0, %cmp1
+  ret <2 x i1> %op
+}
+
+define <2 x i1> @test_pass_et_vec_splat_poison(<2 x i8> %x0, <2 x i8> %x1) {
+; CHECK-LABEL: define <2 x i1> @test_pass_et_vec_splat_poison(
+; CHECK-SAME: <2 x i8> [[X0:%.*]], <2 x i8> [[X1:%.*]]) {
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %not.x0 = xor <2 x i8> %x0, <i8 -1, i8 poison>
+  %cmp0 = icmp ule <2 x i8> %x1, %not.x0
+  %not.x1 = xor <2 x i8> %x1, <i8 -1, i8 poison>
+  %cmp1 = icmp ugt <2 x i8> %x0, %not.x1
+  %op = and <2 x i1> %cmp0, %cmp1
+  ret <2 x i1> %op
+}
+
+define <2 x i1> @test_pass_et_vec_non_splat(<2 x i8> %x0, <2 x i8> %x1) {
+; CHECK-LABEL: define <2 x i1> @test_pass_et_vec_non_splat(
+; CHECK-SAME: <2 x i8> [[X0:%.*]], <2 x i8> [[X1:%.*]]) {
+; CHECK-NEXT:    [[NOT_X0:%.*]] = xor <2 x i8> [[X0]], <i8 -1, i8 -2>
+; CHECK-NEXT:    [[CMP0:%.*]] = icmp ule <2 x i8> [[X1]], [[NOT_X0]]
+; CHECK-NEXT:    [[NOT_X1:%.*]] = xor <2 x i8> [[X1]], <i8 -1, i8 -2>
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i8> [[X0]], [[NOT_X1]]
+; CHECK-NEXT:    [[OP:%.*]] = and <2 x i1> [[CMP0]], [[CMP1]]
+; CHECK-NEXT:    ret <2 x i1> [[OP]]
+;
+  %not.x0 = xor <2 x i8> %x0, <i8 -1, i8 -2>
+  %cmp0 = icmp ule <2 x i8> %x1, %not.x0
+  %not.x1 = xor <2 x i8> %x1, <i8 -1, i8 -2>
+  %cmp1 = icmp ugt <2 x i8> %x0, %not.x1
+  %op = and <2 x i1> %cmp0, %cmp1
+  ret <2 x i1> %op
+}
+
 define i1 @test_pass_signed(i32 %x0, i32 %x1) {
 ; CHECK-LABEL: define i1 @test_pass_signed(
 ; CHECK-SAME: i32 [[X0:%.*]], i32 [[X1:%.*]]) {



More information about the llvm-commits mailing list