[llvm] [RISCV][P-ext] Select scalar mulhr/mulhru/mulhrsu for RV32 v2i32 (PR #215938)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 12 20:28:43 PDT 2026
https://github.com/sihuan created https://github.com/llvm/llvm-project/pull/215938
The `combinePExtTruncate` DAGCombine bailed out on RV32 for both
`v4i16` and `v2i32` 64-bit packed types. The `v4i16` case is correct
(no paired rounding multiply-high for 16-bit lanes), but `v2i32` was
incorrectly excluded.
RV32 provides scalar `mulhr`/`mulhru`/`mulhrsu` instructions. Since
`v2i32` on RV32 is a GPRPair, splitting into two scalar operations in
the combine — while the widening multiply shape is still visible —
reuses those instructions directly.
The non-rounding forms (`mulh`/`mulhu`/`mulhsu`) already scalarize
correctly through the generic legalizer, so only the rounding case
needs explicit handling here.
>From 20d999b11f2554472a7b8070d342c79a3ff554d5 Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Thu, 23 Jul 2026 08:33:30 +0000
Subject: [PATCH] [RISCV][P-ext] Select scalar mulhr/mulhru/mulhrsu for RV32
v2i32
RV32 has no paired rounding multiply-high instruction, so the packed
v2i32 pattern previously fell back to a wide multiply sequence. Split it
into two i32 lanes in the truncate combine and reuse the scalar
mulhr/mulhru/mulhrsu instructions. The non-rounding forms already
scalarize to mulh/mulhu/mulhsu, so only the rounding case is handled
here.
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 17 ++++++++++-
llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 32 ++++++---------------
2 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b060542bf0bf4..03c000b86b2e6 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -17884,7 +17884,7 @@ static SDValue combinePExtTruncate(SDNode *N, SelectionDAG &DAG,
// MULH*/MULHR*: shift amount must be element size, only for i16/i32
if (ShAmtVal != EltBits || (EltBits != 16 && EltBits != 32))
return SDValue();
- if (!Subtarget.is64Bit() && (VT == MVT::v2i32 || VT == MVT::v4i16))
+ if (!Subtarget.is64Bit() && VT == MVT::v4i16)
return SDValue();
if (IsRounding) {
if (LHSIsSExt && RHSIsSExt) {
@@ -17911,6 +17911,21 @@ static SDValue combinePExtTruncate(SDNode *N, SelectionDAG &DAG,
} else
return SDValue();
}
+
+ // RV32 has scalar rounded multiply-high instructions, but no paired form.
+ // Split v2i32 while the widening multiply shape is still visible.
+ if (!Subtarget.is64Bit() && VT == MVT::v2i32) {
+ if (!IsRounding)
+ return SDValue();
+ SDLoc DL(N);
+ SDValue ALo = DAG.getExtractVectorElt(DL, MVT::i32, A, 0);
+ SDValue AHi = DAG.getExtractVectorElt(DL, MVT::i32, A, 1);
+ SDValue BLo = DAG.getExtractVectorElt(DL, MVT::i32, B, 0);
+ SDValue BHi = DAG.getExtractVectorElt(DL, MVT::i32, B, 1);
+ SDValue Lo = DAG.getNode(Opc, DL, MVT::i32, ALo, BLo);
+ SDValue Hi = DAG.getNode(Opc, DL, MVT::i32, AHi, BHi);
+ return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Lo, Hi);
+ }
break;
}
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 0ea81f0cef552..490634197f29b 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -2769,12 +2769,8 @@ define <4 x i16> @test_pmulhr_h(<4 x i16> %a, <4 x i16> %b) {
define <2 x i32> @test_pmulhr_w(<2 x i32> %a, <2 x i32> %b) {
; RV32-LABEL: test_pmulhr_w:
; RV32: # %bb.0:
-; RV32-NEXT: wmul a4, a0, a2
-; RV32-NEXT: wmul a0, a1, a3
-; RV32-NEXT: lui a2, 524288
-; RV32-NEXT: waddau a0, a2, zero
-; RV32-NEXT: waddau a4, a2, zero
-; RV32-NEXT: mv a0, a5
+; RV32-NEXT: mulhr a1, a1, a3
+; RV32-NEXT: mulhr a0, a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: test_pmulhr_w:
@@ -2814,12 +2810,8 @@ define <4 x i16> @test_pmulhru_h(<4 x i16> %a, <4 x i16> %b) {
define <2 x i32> @test_pmulhru_w(<2 x i32> %a, <2 x i32> %b) {
; RV32-LABEL: test_pmulhru_w:
; RV32: # %bb.0:
-; RV32-NEXT: wmulu a4, a0, a2
-; RV32-NEXT: wmulu a0, a1, a3
-; RV32-NEXT: lui a2, 524288
-; RV32-NEXT: waddau a0, a2, zero
-; RV32-NEXT: waddau a4, a2, zero
-; RV32-NEXT: mv a0, a5
+; RV32-NEXT: mulhru a1, a1, a3
+; RV32-NEXT: mulhru a0, a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: test_pmulhru_w:
@@ -2879,12 +2871,8 @@ define <4 x i16> @test_pmulhrsu_h_commuted(<4 x i16> %a, <4 x i16> %b) {
define <2 x i32> @test_pmulhrsu_w(<2 x i32> %a, <2 x i32> %b) {
; RV32-LABEL: test_pmulhrsu_w:
; RV32: # %bb.0:
-; RV32-NEXT: wmulsu a4, a0, a2
-; RV32-NEXT: wmulsu a0, a1, a3
-; RV32-NEXT: lui a2, 524288
-; RV32-NEXT: waddau a0, a2, zero
-; RV32-NEXT: waddau a4, a2, zero
-; RV32-NEXT: mv a0, a5
+; RV32-NEXT: mulhrsu a1, a1, a3
+; RV32-NEXT: mulhrsu a0, a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: test_pmulhrsu_w:
@@ -2903,12 +2891,8 @@ define <2 x i32> @test_pmulhrsu_w(<2 x i32> %a, <2 x i32> %b) {
define <2 x i32> @test_pmulhrsu_w_commuted(<2 x i32> %a, <2 x i32> %b) {
; RV32-LABEL: test_pmulhrsu_w_commuted:
; RV32: # %bb.0:
-; RV32-NEXT: wmulsu a4, a2, a0
-; RV32-NEXT: wmulsu a0, a3, a1
-; RV32-NEXT: lui a2, 524288
-; RV32-NEXT: waddau a0, a2, zero
-; RV32-NEXT: waddau a4, a2, zero
-; RV32-NEXT: mv a0, a5
+; RV32-NEXT: mulhrsu a1, a3, a1
+; RV32-NEXT: mulhrsu a0, a2, a0
; RV32-NEXT: ret
;
; RV64-LABEL: test_pmulhrsu_w_commuted:
More information about the llvm-commits
mailing list