[llvm] [VectorCombine] Fix crash in foldEquivalentReductionCmp on i1 vector (PR #179917)

Valeriy Savchenko via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 5 03:54:28 PST 2026


https://github.com/SavchenkoValeriy created https://github.com/llvm/llvm-project/pull/179917

When we check for validity of `and` to `umin` fold, we check lower two bits, which leads to a crash for `i1` vectors. `i1` vectors are actually the easiest case because `or` is equivalent to `umax` and `and` is equivalent to `umin` unconditionally.

>From 4cc9fb21ed36bfc38f06236a245c0fe56f467fd3 Mon Sep 17 00:00:00 2001
From: Valeriy Savchenko <vsavchenko at apple.com>
Date: Thu, 5 Feb 2026 11:50:29 +0000
Subject: [PATCH] [VectorCombine] Fix crash in foldEquivalentReductionCmp on i1
 vector

---
 .../Transforms/Vectorize/VectorCombine.cpp    |  8 ++
 .../AArch64/fold-equivalent-reduction-cmp.ll  | 74 +++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index fbb3b820c4f05..5a3933a02b5a7 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -4597,6 +4597,10 @@ bool VectorCombine::foldEquivalentReductionCmp(Instruction &I) {
     return false;
 
   const auto IsValidOrUmaxCmp = [&]() {
+    // or === umax for i1
+    if (CmpVal->getBitWidth() == 1)
+      return true;
+
     // Cases a and e
     bool IsEquality =
         (CmpVal->isZero() || CmpVal->isOne()) && ICmpInst::isEquality(Pred);
@@ -4609,6 +4613,10 @@ bool VectorCombine::foldEquivalentReductionCmp(Instruction &I) {
   };
 
   const auto IsValidAndUminCmp = [&]() {
+    // and === umin for i1
+    if (CmpVal->getBitWidth() == 1)
+      return true;
+
     const auto LeadingOnes = CmpVal->countl_one();
 
     // Cases g and k
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/fold-equivalent-reduction-cmp.ll b/llvm/test/Transforms/VectorCombine/AArch64/fold-equivalent-reduction-cmp.ll
index 9ebc2c0c892a8..26d7647e5afde 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/fold-equivalent-reduction-cmp.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/fold-equivalent-reduction-cmp.ll
@@ -339,4 +339,78 @@ define i1 @or_eq_0_scalable_negative(<vscale x 4 x i32> %x) {
   ret i1 %cmp
 }
 
+; i1 vector tests - for i1, or===umax and and===umin
+
+define i1 @or_eq_0_v4i1(<4 x i1> %x) {
+; CHECK-LABEL: define i1 @or_eq_0_v4i1(
+; CHECK-SAME: <4 x i1> [[X:%.*]]) {
+; CHECK-NEXT:    [[RED:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i1 [[RED]], false
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %red = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> %x)
+  %cmp = icmp eq i1 %red, 0
+  ret i1 %cmp
+}
+
+define i1 @or_ne_0_v4i1(<4 x i1> %x) {
+; CHECK-LABEL: define i1 @or_ne_0_v4i1(
+; CHECK-SAME: <4 x i1> [[X:%.*]]) {
+; CHECK-NEXT:    [[RED:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i1 [[RED]], false
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %red = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> %x)
+  %cmp = icmp ne i1 %red, 0
+  ret i1 %cmp
+}
+
+define i1 @and_eq_allones_v4i1(<4 x i1> %x) {
+; CHECK-LABEL: define i1 @and_eq_allones_v4i1(
+; CHECK-SAME: <4 x i1> [[X:%.*]]) {
+; CHECK-NEXT:    [[RED:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i1 [[RED]], true
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %red = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> %x)
+  %cmp = icmp eq i1 %red, -1
+  ret i1 %cmp
+}
+
+define i1 @and_ne_allones_v4i1(<4 x i1> %x) {
+; CHECK-LABEL: define i1 @and_ne_allones_v4i1(
+; CHECK-SAME: <4 x i1> [[X:%.*]]) {
+; CHECK-NEXT:    [[RED:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i1 [[RED]], true
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %red = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> %x)
+  %cmp = icmp ne i1 %red, -1
+  ret i1 %cmp
+}
+
+define i1 @umax_eq_0_v4i1(<4 x i1> %x) {
+; CHECK-LABEL: define i1 @umax_eq_0_v4i1(
+; CHECK-SAME: <4 x i1> [[X:%.*]]) {
+; CHECK-NEXT:    [[RED:%.*]] = call i1 @llvm.vector.reduce.umax.v4i1(<4 x i1> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i1 [[RED]], false
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %red = call i1 @llvm.vector.reduce.umax.v4i1(<4 x i1> %x)
+  %cmp = icmp eq i1 %red, 0
+  ret i1 %cmp
+}
+
+define i1 @umin_eq_allones_v4i1(<4 x i1> %x) {
+; CHECK-LABEL: define i1 @umin_eq_allones_v4i1(
+; CHECK-SAME: <4 x i1> [[X:%.*]]) {
+; CHECK-NEXT:    [[RED:%.*]] = call i1 @llvm.vector.reduce.umin.v4i1(<4 x i1> [[X]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i1 [[RED]], true
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %red = call i1 @llvm.vector.reduce.umin.v4i1(<4 x i1> %x)
+  %cmp = icmp eq i1 %red, -1
+  ret i1 %cmp
+}
+
 declare void @use(i32)



More information about the llvm-commits mailing list