[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