[llvm] [InstCombine] Fix vector_reduce_mul(sext <n x i1>). (PR #199401)
via llvm-commits
llvm-commits at lists.llvm.org
Sat May 23 23:33:38 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Justin Lebar (jlebar)
<details>
<summary>Changes</summary>
Before this patch, instcombine folded
vector_reduce_mul(sext (<n x i1> val))
to
zext(vector_reduce_and(<n x i1> val)).
But this is incorrect when n is odd: The result of the reduction is -1,
not 1.
This bug was found by a large run of Opus 4.7 looking for bugs in LLVM.
---
Full diff: https://github.com/llvm/llvm-project/pull/199401.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+31-14)
- (modified) llvm/test/Transforms/InstCombine/reduction-mul-sext-zext-i1.ll (+25)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 360326f47594d..b567d5a0b665b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4111,14 +4111,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
}
case Intrinsic::vector_reduce_mul: {
if (IID == Intrinsic::vector_reduce_mul) {
- // Multiplicative reduction over the vector with (potentially-extended)
- // i1 element type is actually a (potentially zero-extended)
- // logical `and` reduction over the original non-extended value:
- // vector_reduce_mul(?ext(<n x i1>))
- // -->
- // zext(vector_reduce_and(<n x i1>))
Value *Arg = II->getArgOperand(0);
- Value *Vect;
if (Value *NewOp =
simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
@@ -4126,13 +4119,37 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
return II;
}
- if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
- if (auto *VTy = dyn_cast<VectorType>(Vect->getType()))
- if (VTy->getElementType() == Builder.getInt1Ty()) {
- Value *Res = Builder.CreateAndReduce(Vect);
- Res = Builder.CreateZExt(Res, II->getType());
- return replaceInstUsesWith(CI, Res);
- }
+ auto IsI1Vec = [&](Value *V) {
+ auto *VTy = dyn_cast<VectorType>(V->getType());
+ return VTy && VTy->getElementType() == Builder.getInt1Ty();
+ };
+
+ // vector_reduce_mul(zext(<n x i1>)) --> zext(vector_reduce_and(<n x i1>))
+ Value *Vect;
+ if (match(Arg, m_ZExt(m_Value(Vect))) && IsI1Vec(Vect)) {
+ Value *Res = Builder.CreateAndReduce(Vect);
+ return replaceInstUsesWith(CI, Builder.CreateZExt(Res, II->getType()));
+ }
+
+ // vector_reduce_mul(sext(<n x i1>)) -->
+ // sext(vector_reduce_and(<n x i1>)) if n is odd
+ // zext(vector_reduce_and(<n x i1>)) if n is even.
+ // This is because if the vector is all `true`, we are multiplying n -1s.
+ // Therefore the answer is -1 if n is odd, or 1 if n is even.
+ if (match(Arg, m_SExt(m_Value(Vect)))) {
+ if (auto *VTy = dyn_cast<FixedVectorType>(Vect->getType());
+ VTy && VTy->getElementType() == Builder.getInt1Ty()) {
+ Value *Res = Builder.CreateAndReduce(Vect);
+ Res = (VTy->getNumElements() & 1)
+ ? Builder.CreateSExt(Res, II->getType())
+ : Builder.CreateZExt(Res, II->getType());
+ return replaceInstUsesWith(CI, Res);
+ }
+ }
+
+ // vector_reduce_mul(<n x i1>) --> vector_reduce_and(<n x i1>)
+ if (IsI1Vec(Arg)) {
+ return replaceInstUsesWith(CI, Builder.CreateAndReduce(Arg));
}
}
[[fallthrough]];
diff --git a/llvm/test/Transforms/InstCombine/reduction-mul-sext-zext-i1.ll b/llvm/test/Transforms/InstCombine/reduction-mul-sext-zext-i1.ll
index f70820801602c..c867e076d9b4a 100644
--- a/llvm/test/Transforms/InstCombine/reduction-mul-sext-zext-i1.ll
+++ b/llvm/test/Transforms/InstCombine/reduction-mul-sext-zext-i1.ll
@@ -95,8 +95,33 @@ define i64 @reduce_mul_zext_external_use(<8 x i1> %x) {
ret i64 %res
}
+define i8 @reduce_mul_sext_odd_lanes(<3 x i1> %x) {
+; CHECK-LABEL: @reduce_mul_sext_odd_lanes(
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast <3 x i1> [[X:%.*]] to i3
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i3 [[TMP1]], -1
+; CHECK-NEXT: [[RES:%.*]] = sext i1 [[TMP2]] to i8
+; CHECK-NEXT: ret i8 [[RES]]
+;
+ %sext = sext <3 x i1> %x to <3 x i8>
+ %res = call i8 @llvm.vector.reduce.mul.v3i8(<3 x i8> %sext)
+ ret i8 %res
+}
+
+define i8 @reduce_mul_zext_odd_lanes(<3 x i1> %x) {
+; CHECK-LABEL: @reduce_mul_zext_odd_lanes(
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast <3 x i1> [[X:%.*]] to i3
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i3 [[TMP1]], -1
+; CHECK-NEXT: [[RES:%.*]] = zext i1 [[TMP2]] to i8
+; CHECK-NEXT: ret i8 [[RES]]
+;
+ %zext = zext <3 x i1> %x to <3 x i8>
+ %res = call i8 @llvm.vector.reduce.mul.v3i8(<3 x i8> %zext)
+ ret i8 %res
+}
+
declare i1 @llvm.vector.reduce.mul.v8i32(<8 x i1> %a)
declare i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> %a)
declare i64 @llvm.vector.reduce.mul.v8i64(<8 x i64> %a)
declare i16 @llvm.vector.reduce.mul.v16i16(<16 x i16> %a)
declare i8 @llvm.vector.reduce.mul.v128i8(<128 x i8> %a)
+declare i8 @llvm.vector.reduce.mul.v3i8(<3 x i8> %a)
``````````
</details>
https://github.com/llvm/llvm-project/pull/199401
More information about the llvm-commits
mailing list