[llvm] Issue 180492 (PR #180596)
Gergo Stomfai via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 10 06:32:42 PST 2026
https://github.com/stomfaig updated https://github.com/llvm/llvm-project/pull/180596
>From e6148684f09e548747feda71e3679584188d006c Mon Sep 17 00:00:00 2001
From: stomfaig <stomfaig at gmail.com>
Date: Mon, 9 Feb 2026 19:00:04 +0000
Subject: [PATCH 1/3] combine icmp-shl-zext-zext-1
---
.../InstCombine/InstCombineCompares.cpp | 22 ++++
.../InstCombine/icmp-shl-zext-zext-1.ll | 123 ++++++++++++++++++
2 files changed, 145 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index bce609275ffa9..2ed6f36a771b5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7894,6 +7894,28 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
}
}
+ // icmp eq (shl (zext i1 x), (zext i1 y)), 1 --> and i1 x, (not i1 y)
+ // icmp ne (shl (zext i1 x), (zext i1 y)), 1 --> or i1 (not i1 x), y
+ {
+ Value *A, *B;
+ CmpPredicate CmpPred;
+
+ if (match(&I,
+ m_c_ICmp(CmpPred, m_Shl(m_ZExt(m_Value(A)), m_ZExt(m_Value(B))),
+ m_One())) &&
+ A->getType()->isIntegerTy(1) && B->getType()->isIntegerTy(1)) {
+
+ if (CmpPred == ICmpInst::ICMP_EQ) {
+ return replaceInstUsesWith(I,
+ Builder.CreateAnd(A, Builder.CreateNot(B)));
+ }
+ if (CmpPred == ICmpInst::ICMP_NE) {
+ return replaceInstUsesWith(I,
+ Builder.CreateOr(Builder.CreateNot(A), B));
+ }
+ }
+ }
+
// Try to optimize equality comparisons against alloca-based pointers.
if (Op0->getType()->isPointerTy() && I.isEquality()) {
assert(Op1->getType()->isPointerTy() &&
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll b/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
new file mode 100644
index 0000000000000..9f9f09b444e14
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
@@ -0,0 +1,123 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Basic test cases
+define i1 @icmp_eq(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_eq(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y]], true
+; CHECK-NEXT: [[RESULT:%.*]] = and i1 [[X]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i32
+ %y.ext = zext i1 %y to i32
+ %shl = shl i32 %x.ext, %y.ext
+ %result = icmp eq i32 %shl, 1
+ ret i1 %result
+}
+
+define i1 @icmp_ne(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_ne(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[X]], true
+; CHECK-NEXT: [[RESULT:%.*]] = or i1 [[Y]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i32
+ %y.ext = zext i1 %y to i32
+ %shl = shl i32 %x.ext, %y.ext
+ %result = icmp ne i32 %shl, 1
+ ret i1 %result
+}
+
+define i1 @icmp_eq_comm(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_comm(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y]], true
+; CHECK-NEXT: [[RESULT:%.*]] = and i1 [[X]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i32
+ %y.ext = zext i1 %y to i32
+ %shl = shl i32 %x.ext, %y.ext
+ %result = icmp eq i32 1, %shl
+ ret i1 %result
+}
+
+define i1 @icmp_ne_comm(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_ne_comm(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[X]], true
+; CHECK-NEXT: [[RESULT:%.*]] = or i1 [[Y]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i32
+ %y.ext = zext i1 %y to i32
+ %shl = shl i32 %x.ext, %y.ext
+ %result = icmp ne i32 1, %shl
+ ret i1 %result
+}
+
+; Different bit zext target bit width
+
+define i1 @icmp_eq_64(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_64(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y]], true
+; CHECK-NEXT: [[RESULT:%.*]] = and i1 [[X]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i64
+ %y.ext = zext i1 %y to i64
+ %shl = shl i64 %x.ext, %y.ext
+ %result = icmp eq i64 %shl, 1
+ ret i1 %result
+}
+
+define i1 @icmp_ne_64(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_ne_64(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[X]], true
+; CHECK-NEXT: [[RESULT:%.*]] = or i1 [[Y]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i64
+ %y.ext = zext i1 %y to i64
+ %shl = shl i64 %x.ext, %y.ext
+ %result = icmp ne i64 %shl, 1
+ ret i1 %result
+}
+
+; Negative test: Comparing against 3, not 1
+define i1 @icmp_eq_zero_negative(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_zero_negative(
+; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
+; CHECK-NEXT: [[X_EXT:%.*]] = zext i1 [[X]] to i32
+; CHECK-NEXT: [[Y_EXT:%.*]] = zext i1 [[Y]] to i32
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 [[X_EXT]], [[Y_EXT]]
+; CHECK-NEXT: [[RESULT:%.*]] = icmp eq i32 [[SHL]], 3
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i1 %x to i32
+ %y.ext = zext i1 %y to i32
+ %shl = shl i32 %x.ext, %y.ext
+ %result = icmp eq i32 %shl, 3
+ ret i1 %result
+}
+
+; Negative test: Non-i1 source type
+define i1 @icmp_eq_non_i1_negative(i8 %x, i8 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_non_i1_negative(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[X_EXT:%.*]] = zext i8 [[X]] to i32
+; CHECK-NEXT: [[Y_EXT:%.*]] = zext nneg i8 [[Y]] to i32
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X_EXT]], [[Y_EXT]]
+; CHECK-NEXT: [[RESULT:%.*]] = icmp eq i32 [[SHL]], 1
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+ %x.ext = zext i8 %x to i32
+ %y.ext = zext i8 %y to i32
+ %shl = shl i32 %x.ext, %y.ext
+ %result = icmp eq i32 %shl, 1
+ ret i1 %result
+}
>From 9e5adfaec1ec97e0a3ae72796f69f65b5af15cc7 Mon Sep 17 00:00:00 2001
From: stomfaig <stomfaig at gmail.com>
Date: Mon, 9 Feb 2026 19:29:02 +0000
Subject: [PATCH 2/3] clarify comment
---
llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll b/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
index 9f9f09b444e14..18b6ad25e8bd7 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
@@ -58,8 +58,7 @@ define i1 @icmp_ne_comm(i1 %x, i1 %y) {
ret i1 %result
}
-; Different bit zext target bit width
-
+; Different zext target bit width
define i1 @icmp_eq_64(i1 %x, i1 %y) {
; CHECK-LABEL: define i1 @icmp_eq_64(
; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
>From 9546bc3ff1df983c238930d75af43449c642f963 Mon Sep 17 00:00:00 2001
From: stomfaig <stomfaig at gmail.com>
Date: Tue, 10 Feb 2026 14:32:14 +0000
Subject: [PATCH 3/3] resolve comments
---
.../InstCombine/InstCombineCompares.cpp | 15 ++-
.../InstCombine/icmp-shl-zext-zext-1.ll | 109 ++++++++++++++----
2 files changed, 92 insertions(+), 32 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 2ed6f36a771b5..c509d5f894fab 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7900,19 +7900,18 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
Value *A, *B;
CmpPredicate CmpPred;
- if (match(&I,
- m_c_ICmp(CmpPred, m_Shl(m_ZExt(m_Value(A)), m_ZExt(m_Value(B))),
- m_One())) &&
- A->getType()->isIntegerTy(1) && B->getType()->isIntegerTy(1)) {
+ if (match(&I, m_ICmp(CmpPred, m_Shl(m_ZExt(m_Value(A)), m_ZExt(m_Value(B))),
+ m_One())) &&
+ A->getType()->isIntOrIntVectorTy(1) &&
+ B->getType()->isIntOrIntVectorTy(1)) {
- if (CmpPred == ICmpInst::ICMP_EQ) {
+ if (CmpPred == ICmpInst::ICMP_EQ)
return replaceInstUsesWith(I,
Builder.CreateAnd(A, Builder.CreateNot(B)));
- }
- if (CmpPred == ICmpInst::ICMP_NE) {
+
+ if (CmpPred == ICmpInst::ICMP_NE)
return replaceInstUsesWith(I,
Builder.CreateOr(Builder.CreateNot(A), B));
- }
}
}
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll b/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
index 18b6ad25e8bd7..0f3e8b42014d8 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-zext-zext-1.ll
@@ -30,32 +30,33 @@ define i1 @icmp_ne(i1 %x, i1 %y) {
ret i1 %result
}
-define i1 @icmp_eq_comm(i1 %x, i1 %y) {
-; CHECK-LABEL: define i1 @icmp_eq_comm(
-; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y]], true
-; CHECK-NEXT: [[RESULT:%.*]] = and i1 [[X]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; Basic test cases with vector types
+define <4 x i1> @icmp_eq_vec(<4 x i1> %x, <4 x i1> %y) {
+; CHECK-LABEL: define <4 x i1> @icmp_eq_vec(
+; CHECK-SAME: <4 x i1> [[X:%.*]], <4 x i1> [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[Y]], splat (i1 true)
+; CHECK-NEXT: [[RESULT:%.*]] = and <4 x i1> [[X]], [[TMP1]]
+; CHECK-NEXT: ret <4 x i1> [[RESULT]]
;
- %x.ext = zext i1 %x to i32
- %y.ext = zext i1 %y to i32
- %shl = shl i32 %x.ext, %y.ext
- %result = icmp eq i32 1, %shl
- ret i1 %result
+ %x.ext = zext <4 x i1> %x to <4 x i32>
+ %y.ext = zext <4 x i1> %y to <4 x i32>
+ %shl = shl <4 x i32> %x.ext, %y.ext
+ %result = icmp eq <4 x i32> %shl, <i32 1, i32 1, i32 1, i32 1>
+ ret <4 x i1> %result
}
-define i1 @icmp_ne_comm(i1 %x, i1 %y) {
-; CHECK-LABEL: define i1 @icmp_ne_comm(
-; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[X]], true
-; CHECK-NEXT: [[RESULT:%.*]] = or i1 [[Y]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+define <4 x i1> @icmp_ne_vec(<4 x i1> %x, <4 x i1> %y) {
+; CHECK-LABEL: define <4 x i1> @icmp_ne_vec(
+; CHECK-SAME: <4 x i1> [[X:%.*]], <4 x i1> [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[X]], splat (i1 true)
+; CHECK-NEXT: [[RESULT:%.*]] = or <4 x i1> [[Y]], [[TMP1]]
+; CHECK-NEXT: ret <4 x i1> [[RESULT]]
;
- %x.ext = zext i1 %x to i32
- %y.ext = zext i1 %y to i32
- %shl = shl i32 %x.ext, %y.ext
- %result = icmp ne i32 1, %shl
- ret i1 %result
+ %x.ext = zext <4 x i1> %x to <4 x i32>
+ %y.ext = zext <4 x i1> %y to <4 x i32>
+ %shl = shl <4 x i32> %x.ext, %y.ext
+ %result = icmp ne <4 x i32> %shl, <i32 1, i32 1, i32 1, i32 1>
+ ret <4 x i1> %result
}
; Different zext target bit width
@@ -87,9 +88,37 @@ define i1 @icmp_ne_64(i1 %x, i1 %y) {
ret i1 %result
}
+define <4 x i1> @icmp_eq_vec_64(<4 x i1> %x, <4 x i1> %y) {
+; CHECK-LABEL: define <4 x i1> @icmp_eq_vec_64(
+; CHECK-SAME: <4 x i1> [[X:%.*]], <4 x i1> [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[Y]], splat (i1 true)
+; CHECK-NEXT: [[RESULT:%.*]] = and <4 x i1> [[X]], [[TMP1]]
+; CHECK-NEXT: ret <4 x i1> [[RESULT]]
+;
+ %x.ext = zext <4 x i1> %x to <4 x i64>
+ %y.ext = zext <4 x i1> %y to <4 x i64>
+ %shl = shl <4 x i64> %x.ext, %y.ext
+ %result = icmp eq <4 x i64> %shl, <i64 1, i64 1, i64 1, i64 1>
+ ret <4 x i1> %result
+}
+
+define <4 x i1> @icmp_ne_vec_64(<4 x i1> %x, <4 x i1> %y) {
+; CHECK-LABEL: define <4 x i1> @icmp_ne_vec_64(
+; CHECK-SAME: <4 x i1> [[X:%.*]], <4 x i1> [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[X]], splat (i1 true)
+; CHECK-NEXT: [[RESULT:%.*]] = or <4 x i1> [[Y]], [[TMP1]]
+; CHECK-NEXT: ret <4 x i1> [[RESULT]]
+;
+ %x.ext = zext <4 x i1> %x to <4 x i64>
+ %y.ext = zext <4 x i1> %y to <4 x i64>
+ %shl = shl <4 x i64> %x.ext, %y.ext
+ %result = icmp ne <4 x i64> %shl, <i64 1, i64 1, i64 1, i64 1>
+ ret <4 x i1> %result
+}
+
; Negative test: Comparing against 3, not 1
-define i1 @icmp_eq_zero_negative(i1 %x, i1 %y) {
-; CHECK-LABEL: define i1 @icmp_eq_zero_negative(
+define i1 @icmp_eq_non_one_negative(i1 %x, i1 %y) {
+; CHECK-LABEL: define i1 @icmp_eq_non_one_negative(
; CHECK-SAME: i1 [[X:%.*]], i1 [[Y:%.*]]) {
; CHECK-NEXT: [[X_EXT:%.*]] = zext i1 [[X]] to i32
; CHECK-NEXT: [[Y_EXT:%.*]] = zext i1 [[Y]] to i32
@@ -104,6 +133,22 @@ define i1 @icmp_eq_zero_negative(i1 %x, i1 %y) {
ret i1 %result
}
+define <4 x i1> @icmp_eq_non_one_negative_vec(<4 x i1> %x, <4 x i1> %y) {
+; CHECK-LABEL: define <4 x i1> @icmp_eq_non_one_negative_vec(
+; CHECK-SAME: <4 x i1> [[X:%.*]], <4 x i1> [[Y:%.*]]) {
+; CHECK-NEXT: [[X_EXT:%.*]] = zext <4 x i1> [[X]] to <4 x i64>
+; CHECK-NEXT: [[Y_EXT:%.*]] = zext <4 x i1> [[Y]] to <4 x i64>
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw <4 x i64> [[X_EXT]], [[Y_EXT]]
+; CHECK-NEXT: [[RESULT:%.*]] = icmp eq <4 x i64> [[SHL]], <i64 3, i64 3, i64 1, i64 1>
+; CHECK-NEXT: ret <4 x i1> [[RESULT]]
+;
+ %x.ext = zext <4 x i1> %x to <4 x i64>
+ %y.ext = zext <4 x i1> %y to <4 x i64>
+ %shl = shl <4 x i64> %x.ext, %y.ext
+ %result = icmp eq <4 x i64> %shl, <i64 3, i64 3, i64 1, i64 1>
+ ret <4 x i1> %result
+}
+
; Negative test: Non-i1 source type
define i1 @icmp_eq_non_i1_negative(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @icmp_eq_non_i1_negative(
@@ -120,3 +165,19 @@ define i1 @icmp_eq_non_i1_negative(i8 %x, i8 %y) {
%result = icmp eq i32 %shl, 1
ret i1 %result
}
+
+define <4 x i1> @icmp_eq_non_i1_negative_vec(<4 x i8> %x, <4 x i8> %y) {
+; CHECK-LABEL: define <4 x i1> @icmp_eq_non_i1_negative_vec(
+; CHECK-SAME: <4 x i8> [[X:%.*]], <4 x i8> [[Y:%.*]]) {
+; CHECK-NEXT: [[X_EXT:%.*]] = zext <4 x i8> [[X]] to <4 x i64>
+; CHECK-NEXT: [[Y_EXT:%.*]] = zext nneg <4 x i8> [[Y]] to <4 x i64>
+; CHECK-NEXT: [[SHL:%.*]] = shl <4 x i64> [[X_EXT]], [[Y_EXT]]
+; CHECK-NEXT: [[RESULT:%.*]] = icmp eq <4 x i64> [[SHL]], splat (i64 1)
+; CHECK-NEXT: ret <4 x i1> [[RESULT]]
+;
+ %x.ext = zext <4 x i8> %x to <4 x i64>
+ %y.ext = zext <4 x i8> %y to <4 x i64>
+ %shl = shl <4 x i64> %x.ext, %y.ext
+ %result = icmp eq <4 x i64> %shl, <i64 1, i64 1, i64 1, i64 1>
+ ret <4 x i1> %result
+}
More information about the llvm-commits
mailing list