[llvm] [SelectionDAG] Fold VECREDUCE_MUL of a constant BUILD_VECTOR (PR #210126)

Ankit Kumar Tiwari via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 20 06:45:38 PDT 2026


https://github.com/ankit-cybertron updated https://github.com/llvm/llvm-project/pull/210126

>From 4632f99f13fa9f5732a044977097155edba873ec Mon Sep 17 00:00:00 2001
From: Ankit Kumar Tiwari <ankit.cybertron at gmail.com>
Date: Thu, 16 Jul 2026 23:23:04 +0530
Subject: [PATCH 1/4] Add Base Test for AArch64

---
 .../AArch64/vecreduce-mul-constant-fold.ll    | 76 +++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll

diff --git a/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll b/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll
new file mode 100644
index 0000000000000..664975cf1ca23
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs < %s | FileCheck %s
+
+; all-constant vector -> should fold to a plain constant (24)
+define i32 @test_const() {
+; CHECK-LABEL: test_const:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    movi v0.4s, #24
+; CHECK-NEXT:    fmov w0, s0
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 3, i32 4>)
+  ret i32 %r
+}
+
+; 8-element vector, product = 40320
+define i32 @test_const_wide() {
+; CHECK-LABEL: test_const_wide:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, #40320 // =0x9d80
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v8i32(<8 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>)
+  ret i32 %r
+}
+
+; non-constant input -> should NOT fold
+define i32 @test_nonconst(<4 x i32> %v) {
+; CHECK-LABEL: test_nonconst:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov d1, v0.d[1]
+; CHECK-NEXT:    mul v0.2s, v0.2s, v1.2s
+; CHECK-NEXT:    mul v0.2s, v0.2s, v0.s[1]
+; CHECK-NEXT:    fmov w0, s0
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> %v)
+  ret i32 %r
+}
+
+; vector containing a poison element -> return poison
+define i32 @test_poison() {
+; CHECK-LABEL: test_poison:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 poison, i32 4>)
+  ret i32 %r
+}
+
+; vector containing zero and poison -> 0
+define i32 @test_zero_and_poison() {
+; CHECK-LABEL: test_zero_and_poison:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 0, i32 2, i32 poison, i32 4>)
+  ret i32 %r
+}
+
+; vector containing an undef element -> should NOT fold
+define i32 @test_undef() {
+; CHECK-LABEL: test_undef:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 undef, i32 4>)
+  ret i32 %r
+}
+
+; vector containing zero and undef -> 0
+define i32 @test_zero_and_undef() {
+; CHECK-LABEL: test_zero_and_undef:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 0, i32 2, i32 undef, i32 4>)
+  ret i32 %r
+}

>From deb999dac81383d653ced82b624fe3d5bef1c1d1 Mon Sep 17 00:00:00 2001
From: Ankit Kumar Tiwari <ankit.cybertron at gmail.com>
Date: Fri, 17 Jul 2026 12:29:11 +0530
Subject: [PATCH 2/4] Base test for RISCV

---
 .../rvv}/vecreduce-mul-constant-fold.ll       | 44 +++++++++----------
 1 file changed, 22 insertions(+), 22 deletions(-)
 rename llvm/test/CodeGen/{AArch64 => RISCV/rvv}/vecreduce-mul-constant-fold.ll (68%)

diff --git a/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll b/llvm/test/CodeGen/RISCV/rvv/vecreduce-mul-constant-fold.ll
similarity index 68%
rename from llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll
rename to llvm/test/CodeGen/RISCV/rvv/vecreduce-mul-constant-fold.ll
index 664975cf1ca23..f8dbee99c9f90 100644
--- a/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vecreduce-mul-constant-fold.ll
@@ -1,12 +1,11 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=aarch64 -verify-machineinstrs < %s | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s | FileCheck %s
 
 ; all-constant vector -> should fold to a plain constant (24)
 define i32 @test_const() {
 ; CHECK-LABEL: test_const:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    movi v0.4s, #24
-; CHECK-NEXT:    fmov w0, s0
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 24
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 3, i32 4>)
   ret i32 %r
@@ -15,8 +14,9 @@ define i32 @test_const() {
 ; 8-element vector, product = 40320
 define i32 @test_const_wide() {
 ; CHECK-LABEL: test_const_wide:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov w0, #40320 // =0x9d80
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lui a0, 10
+; CHECK-NEXT:    addi a0, a0, -640
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v8i32(<8 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>)
   ret i32 %r
@@ -25,11 +25,13 @@ define i32 @test_const_wide() {
 ; non-constant input -> should NOT fold
 define i32 @test_nonconst(<4 x i32> %v) {
 ; CHECK-LABEL: test_nonconst:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov d1, v0.d[1]
-; CHECK-NEXT:    mul v0.2s, v0.2s, v1.2s
-; CHECK-NEXT:    mul v0.2s, v0.2s, v0.s[1]
-; CHECK-NEXT:    fmov w0, s0
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vslidedown.vi v9, v8, 2
+; CHECK-NEXT:    vmul.vv v8, v8, v9
+; CHECK-NEXT:    vrgather.vi v9, v8, 1
+; CHECK-NEXT:    vmul.vv v8, v8, v9
+; CHECK-NEXT:    vmv.x.s a0, v8
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> %v)
   ret i32 %r
@@ -38,18 +40,16 @@ define i32 @test_nonconst(<4 x i32> %v) {
 ; vector containing a poison element -> return poison
 define i32 @test_poison() {
 ; CHECK-LABEL: test_poison:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov w0, wzr
+; CHECK:       # %bb.0:
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 poison, i32 4>)
   ret i32 %r
 }
 
-; vector containing zero and poison -> 0
+; vector containing zero and poison -> return poison
 define i32 @test_zero_and_poison() {
 ; CHECK-LABEL: test_zero_and_poison:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov w0, wzr
+; CHECK:       # %bb.0:
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 0, i32 2, i32 poison, i32 4>)
   ret i32 %r
@@ -58,18 +58,18 @@ define i32 @test_zero_and_poison() {
 ; vector containing an undef element -> should NOT fold
 define i32 @test_undef() {
 ; CHECK-LABEL: test_undef:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov w0, wzr
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 undef, i32 4>)
   ret i32 %r
 }
 
-; vector containing zero and undef -> 0
+; vector containing zero and undef -> should NOT fold
 define i32 @test_zero_and_undef() {
 ; CHECK-LABEL: test_zero_and_undef:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov w0, wzr
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 0, i32 2, i32 undef, i32 4>)
   ret i32 %r

>From 49c66d7a68c30bf5d504f8eda31a0bc005184a4e Mon Sep 17 00:00:00 2001
From: Ankit Kumar Tiwari <ankit.cybertron at gmail.com>
Date: Sat, 18 Jul 2026 13:44:20 +0530
Subject: [PATCH 3/4] Rebase and Add VECREDUCE_MUL check conditions

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index c61a2edd45255..42345c18806d9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7140,6 +7140,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
   case ISD::VECREDUCE_SMIN:
   case ISD::VECREDUCE_UMAX:
   case ISD::VECREDUCE_UMIN:
+  case ISD::VECREDUCE_MUL:
   case ISD::STEP_VECTOR: {
     SDValue Ops = {N1};
     if (SDValue Fold = FoldConstantArithmetic(Opcode, DL, VT, Ops))
@@ -7836,7 +7837,7 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL,
     // Constant fold integer vector reductions with constant BUILD_VECTORs.
     if ((Opcode == ISD::VECREDUCE_ADD || Opcode == ISD::VECREDUCE_SMAX ||
          Opcode == ISD::VECREDUCE_SMIN || Opcode == ISD::VECREDUCE_UMAX ||
-         Opcode == ISD::VECREDUCE_UMIN) &&
+         Opcode == ISD::VECREDUCE_UMIN || Opcode == ISD::VECREDUCE_MUL) &&
         ISD::isBuildVectorOfConstantSDNodes(N1.getNode())) {
       unsigned EltBits = N1.getValueType().getScalarSizeInBits();
       unsigned BaseOpcode = ISD::getVecReduceBaseOpcode(Opcode);

>From deb4c6b9e5a1e4a9bbf4a35992eb48121c321e9b Mon Sep 17 00:00:00 2001
From: Ankit Kumar Tiwari <ankit.cybertron at gmail.com>
Date: Mon, 20 Jul 2026 19:14:54 +0530
Subject: [PATCH 4/4] Add Test for AArch64

---
 .../AArch64/vecreduce-mul-constant-fold.ll    | 73 +++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll

diff --git a/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll b/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll
new file mode 100644
index 0000000000000..0d3c33c6ce96f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/vecreduce-mul-constant-fold.ll
@@ -0,0 +1,73 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs < %s | FileCheck %s
+
+; all-constant vector -> should fold to a plain constant (24)
+define i32 @test_const() {
+; CHECK-LABEL: test_const:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, #24 // =0x18
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 3, i32 4>)
+  ret i32 %r
+}
+
+; 8-element vector, product = 40320
+define i32 @test_const_wide() {
+; CHECK-LABEL: test_const_wide:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, #40320 // =0x9d80
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v8i32(<8 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>)
+  ret i32 %r
+}
+
+; non-constant input -> should NOT fold
+define i32 @test_nonconst(<4 x i32> %v) {
+; CHECK-LABEL: test_nonconst:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov d1, v0.d[1]
+; CHECK-NEXT:    mul v0.2s, v0.2s, v1.2s
+; CHECK-NEXT:    mul v0.2s, v0.2s, v0.s[1]
+; CHECK-NEXT:    fmov w0, s0
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> %v)
+  ret i32 %r
+}
+
+; vector containing a poison element -> return poison
+define i32 @test_poison() {
+; CHECK-LABEL: test_poison:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 poison, i32 4>)
+  ret i32 %r
+}
+
+; vector containing zero and poison -> should NOT fold
+define i32 @test_zero_and_poison() {
+; CHECK-LABEL: test_zero_and_poison:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 0, i32 2, i32 poison, i32 4>)
+  ret i32 %r
+}
+
+; vector containing an undef element -> should NOT fold
+define i32 @test_undef() {
+; CHECK-LABEL: test_undef:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 1, i32 2, i32 undef, i32 4>)
+  ret i32 %r
+}
+
+; vector containing zero and undef -> should NOT fold
+define i32 @test_zero_and_undef() {
+; CHECK-LABEL: test_zero_and_undef:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 0, i32 2, i32 undef, i32 4>)
+  ret i32 %r
+}



More information about the llvm-commits mailing list