[clang] [llvm] [RISCV][P-ext] Support Packed Multiply High (PR #211223)
Hongyu Chen via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 30 08:56:24 PDT 2026
https://github.com/XChy updated https://github.com/llvm/llvm-project/pull/211223
>From 95a2a3865ac9f84dc34bb890022c59ec6241c39a Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 18 Jul 2026 02:31:50 +0800
Subject: [PATCH 1/3] [RISCV][P-ext] Support Packed Multiply High
---
clang/include/clang/Basic/BuiltinsRISCV.td | 22 +++
clang/lib/CodeGen/TargetBuiltins/RISCV.cpp | 49 +++++
clang/lib/Headers/riscv_packed_simd.h | 29 +++
.../riscv_packed_simd.c | 120 ++++++++++++
llvm/include/llvm/IR/IntrinsicsRISCV.td | 8 +
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 71 ++++++-
llvm/test/CodeGen/RISCV/rvp-simd-32.ll | 55 ++++++
llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 181 ++++++++++++++++++
8 files changed, 531 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td b/clang/include/clang/Basic/BuiltinsRISCV.td
index 1e55ab0bc56d5..2eb5ec1f3fea2 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -247,6 +247,28 @@ def pmerge_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4,
def pmerge_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned int>, _Vector<2, unsigned int>, _Vector<2, unsigned int>)">;
def pmerge_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, int>, _Vector<2, unsigned int>)">;
+// Packed Multiply High (32-bit)
+def pmulh_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, _Vector<2, short>)">;
+def pmulhr_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, _Vector<2, short>)">;
+def pmulhu_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<2, unsigned short>, _Vector<2, unsigned short>)">;
+def pmulhru_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<2, unsigned short>, _Vector<2, unsigned short>)">;
+def pmulhsu_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, _Vector<2, unsigned short>)">;
+def pmulhrsu_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, _Vector<2, unsigned short>)">;
+
+// Packed Multiply High (64-bit)
+def pmulh_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4, short>)">;
+def pmulh_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, int>)">;
+def pmulhr_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4, short>)">;
+def pmulhr_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, int>)">;
+def pmulhu_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<4, unsigned short>, _Vector<4, unsigned short>)">;
+def pmulhu_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned int>, _Vector<2, unsigned int>)">;
+def pmulhru_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<4, unsigned short>, _Vector<4, unsigned short>)">;
+def pmulhru_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned int>, _Vector<2, unsigned int>)">;
+def pmulhsu_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4, unsigned short>)">;
+def pmulhsu_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, unsigned int>)">;
+def pmulhrsu_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4, unsigned short>)">;
+def pmulhrsu_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, unsigned int>)">;
+
// Packed Absolute Difference Sum (32-bit)
def pabdsumu_u8x4_u32 : RISCVBuiltin<"unsigned int(_Vector<4, unsigned char>, _Vector<4, unsigned char>)">;
def pabdsumau_u8x4_u32 : RISCVBuiltin<"unsigned int(unsigned int, _Vector<4, unsigned char>, _Vector<4, unsigned char>)">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 65e43e928e1f0..7d428aa7b0823 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1259,6 +1259,25 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_pmerge_i16x4:
case RISCV::BI__builtin_riscv_pmerge_u32x2:
case RISCV::BI__builtin_riscv_pmerge_i32x2:
+ // Packed Multiply High
+ case RISCV::BI__builtin_riscv_pmulh_i16x2:
+ case RISCV::BI__builtin_riscv_pmulh_i16x4:
+ case RISCV::BI__builtin_riscv_pmulh_i32x2:
+ case RISCV::BI__builtin_riscv_pmulhr_i16x2:
+ case RISCV::BI__builtin_riscv_pmulhr_i16x4:
+ case RISCV::BI__builtin_riscv_pmulhr_i32x2:
+ case RISCV::BI__builtin_riscv_pmulhu_u16x2:
+ case RISCV::BI__builtin_riscv_pmulhu_u16x4:
+ case RISCV::BI__builtin_riscv_pmulhu_u32x2:
+ case RISCV::BI__builtin_riscv_pmulhru_u16x2:
+ case RISCV::BI__builtin_riscv_pmulhru_u16x4:
+ case RISCV::BI__builtin_riscv_pmulhru_u32x2:
+ case RISCV::BI__builtin_riscv_pmulhsu_i16x2:
+ case RISCV::BI__builtin_riscv_pmulhsu_i16x4:
+ case RISCV::BI__builtin_riscv_pmulhsu_i32x2:
+ case RISCV::BI__builtin_riscv_pmulhrsu_i16x2:
+ case RISCV::BI__builtin_riscv_pmulhrsu_i16x4:
+ case RISCV::BI__builtin_riscv_pmulhrsu_i32x2:
// Packed Saturating Absolute Value
case RISCV::BI__builtin_riscv_psabs_i8x4:
case RISCV::BI__builtin_riscv_psabs_i16x2:
@@ -1356,6 +1375,36 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_pmerge_i32x2:
ID = Intrinsic::riscv_pmerge;
break;
+ case RISCV::BI__builtin_riscv_pmulh_i16x2:
+ case RISCV::BI__builtin_riscv_pmulh_i16x4:
+ case RISCV::BI__builtin_riscv_pmulh_i32x2:
+ ID = Intrinsic::riscv_pmulh;
+ break;
+ case RISCV::BI__builtin_riscv_pmulhr_i16x2:
+ case RISCV::BI__builtin_riscv_pmulhr_i16x4:
+ case RISCV::BI__builtin_riscv_pmulhr_i32x2:
+ ID = Intrinsic::riscv_pmulhr;
+ break;
+ case RISCV::BI__builtin_riscv_pmulhu_u16x2:
+ case RISCV::BI__builtin_riscv_pmulhu_u16x4:
+ case RISCV::BI__builtin_riscv_pmulhu_u32x2:
+ ID = Intrinsic::riscv_pmulhu;
+ break;
+ case RISCV::BI__builtin_riscv_pmulhru_u16x2:
+ case RISCV::BI__builtin_riscv_pmulhru_u16x4:
+ case RISCV::BI__builtin_riscv_pmulhru_u32x2:
+ ID = Intrinsic::riscv_pmulhru;
+ break;
+ case RISCV::BI__builtin_riscv_pmulhsu_i16x2:
+ case RISCV::BI__builtin_riscv_pmulhsu_i16x4:
+ case RISCV::BI__builtin_riscv_pmulhsu_i32x2:
+ ID = Intrinsic::riscv_pmulhsu;
+ break;
+ case RISCV::BI__builtin_riscv_pmulhrsu_i16x2:
+ case RISCV::BI__builtin_riscv_pmulhrsu_i16x4:
+ case RISCV::BI__builtin_riscv_pmulhrsu_i32x2:
+ ID = Intrinsic::riscv_pmulhrsu;
+ break;
case RISCV::BI__builtin_riscv_psabs_i8x4:
case RISCV::BI__builtin_riscv_psabs_i16x2:
case RISCV::BI__builtin_riscv_psabs_i8x8:
diff --git a/clang/lib/Headers/riscv_packed_simd.h b/clang/lib/Headers/riscv_packed_simd.h
index 5324a3676651e..7eded04e28038 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -71,6 +71,12 @@ typedef uint32_t uint32x2_t __attribute__((__vector_size__(8)));
return builtin(__rs1, __rs2); \
}
+#define __packed_binary_builtin_mixed(name, rty, ty1, ty2, builtin) \
+ static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty1 __rs1, \
+ ty2 __rs2) { \
+ return builtin(__rs1, __rs2); \
+ }
+
#define __packed_sh1add(name, ty) \
static __inline__ ty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1, ty __rs2) { \
return (__rs1 << 1) + __rs2; \
@@ -672,6 +678,28 @@ __packed_merge_builtin(pmerge_i16x4, int16x4_t, uint16x4_t, __builtin_riscv_pmer
__packed_merge_builtin(pmerge_u32x2, uint32x2_t, uint32x2_t, __builtin_riscv_pmerge_u32x2)
__packed_merge_builtin(pmerge_i32x2, int32x2_t, uint32x2_t, __builtin_riscv_pmerge_i32x2)
+/* Packed Multiply High (32-bit) */
+__packed_binary_builtin(pmulh_i16x2, int16x2_t, __builtin_riscv_pmulh_i16x2)
+__packed_binary_builtin(pmulhr_i16x2, int16x2_t, __builtin_riscv_pmulhr_i16x2)
+__packed_binary_builtin(pmulhu_u16x2, uint16x2_t, __builtin_riscv_pmulhu_u16x2)
+__packed_binary_builtin(pmulhru_u16x2, uint16x2_t, __builtin_riscv_pmulhru_u16x2)
+__packed_binary_builtin_mixed(pmulhsu_i16x2, int16x2_t, int16x2_t, uint16x2_t, __builtin_riscv_pmulhsu_i16x2)
+__packed_binary_builtin_mixed(pmulhrsu_i16x2, int16x2_t, int16x2_t, uint16x2_t, __builtin_riscv_pmulhrsu_i16x2)
+
+/* Packed Multiply High (64-bit) */
+__packed_binary_builtin(pmulh_i16x4, int16x4_t, __builtin_riscv_pmulh_i16x4)
+__packed_binary_builtin(pmulh_i32x2, int32x2_t, __builtin_riscv_pmulh_i32x2)
+__packed_binary_builtin(pmulhr_i16x4, int16x4_t, __builtin_riscv_pmulhr_i16x4)
+__packed_binary_builtin(pmulhr_i32x2, int32x2_t, __builtin_riscv_pmulhr_i32x2)
+__packed_binary_builtin(pmulhu_u16x4, uint16x4_t, __builtin_riscv_pmulhu_u16x4)
+__packed_binary_builtin(pmulhu_u32x2, uint32x2_t, __builtin_riscv_pmulhu_u32x2)
+__packed_binary_builtin(pmulhru_u16x4, uint16x4_t, __builtin_riscv_pmulhru_u16x4)
+__packed_binary_builtin(pmulhru_u32x2, uint32x2_t, __builtin_riscv_pmulhru_u32x2)
+__packed_binary_builtin_mixed(pmulhsu_i16x4, int16x4_t, int16x4_t, uint16x4_t, __builtin_riscv_pmulhsu_i16x4)
+__packed_binary_builtin_mixed(pmulhsu_i32x2, int32x2_t, int32x2_t, uint32x2_t, __builtin_riscv_pmulhsu_i32x2)
+__packed_binary_builtin_mixed(pmulhrsu_i16x4, int16x4_t, int16x4_t, uint16x4_t, __builtin_riscv_pmulhrsu_i16x4)
+__packed_binary_builtin_mixed(pmulhrsu_i32x2, int32x2_t, int32x2_t, uint32x2_t, __builtin_riscv_pmulhrsu_i32x2)
+
/* Packed Absolute Difference Sum (32-bit) */
__packed_abdsum(pabdsumu_u8x4_u32, uint32_t, uint8x4_t, __builtin_riscv_pabdsumu_u8x4_u32)
__packed_abdsum_acc(pabdsumau_u8x4_u32, uint32_t, uint8x4_t, __builtin_riscv_pabdsumau_u8x4_u32)
@@ -804,6 +832,7 @@ __packed_reinterpret(u32x2_i32x2, int32x2_t, uint32x2_t)
#undef __packed_binary_op
#undef __packed_unary_op
#undef __packed_binary_builtin
+#undef __packed_binary_builtin_mixed
#undef __packed_sh1add
#undef __packed_sh1sadd
#undef __packed_cmp
diff --git a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
index ee3bc75e3a727..a5620444a9d5c 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2382,6 +2382,126 @@ int32x2_t test_pmerge_mvmn_i32x2(int32x2_t rs2, int32x2_t rs1, uint32x2_t rd) {
return __riscv_pmerge_i32x2(rs1, rs2, rd);
}
+// CHECK-LABEL: test_pmulh_i16x2:
+// CHECK: pmulh.h
+int16x2_t test_pmulh_i16x2(int16x2_t rs1, int16x2_t rs2) {
+ return __riscv_pmulh_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhr_i16x2:
+// CHECK: pmulhr.h
+int16x2_t test_pmulhr_i16x2(int16x2_t rs1, int16x2_t rs2) {
+ return __riscv_pmulhr_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhu_u16x2:
+// CHECK: pmulhu.h
+uint16x2_t test_pmulhu_u16x2(uint16x2_t rs1, uint16x2_t rs2) {
+ return __riscv_pmulhu_u16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhru_u16x2:
+// CHECK: pmulhru.h
+uint16x2_t test_pmulhru_u16x2(uint16x2_t rs1, uint16x2_t rs2) {
+ return __riscv_pmulhru_u16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhsu_i16x2:
+// CHECK: pmulhsu.h
+int16x2_t test_pmulhsu_i16x2(int16x2_t rs1, uint16x2_t rs2) {
+ return __riscv_pmulhsu_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhrsu_i16x2:
+// CHECK: pmulhrsu.h
+int16x2_t test_pmulhrsu_i16x2(int16x2_t rs1, uint16x2_t rs2) {
+ return __riscv_pmulhrsu_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulh_i16x4:
+// RV32-COUNT-2: pmulh.h
+// RV64: pmulh.h
+int16x4_t test_pmulh_i16x4(int16x4_t rs1, int16x4_t rs2) {
+ return __riscv_pmulh_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhr_i16x4:
+// RV32-COUNT-2: pmulhr.h
+// RV64: pmulhr.h
+int16x4_t test_pmulhr_i16x4(int16x4_t rs1, int16x4_t rs2) {
+ return __riscv_pmulhr_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhu_u16x4:
+// RV32-COUNT-2: pmulhu.h
+// RV64: pmulhu.h
+uint16x4_t test_pmulhu_u16x4(uint16x4_t rs1, uint16x4_t rs2) {
+ return __riscv_pmulhu_u16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhru_u16x4:
+// RV32-COUNT-2: pmulhru.h
+// RV64: pmulhru.h
+uint16x4_t test_pmulhru_u16x4(uint16x4_t rs1, uint16x4_t rs2) {
+ return __riscv_pmulhru_u16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhsu_i16x4:
+// RV32-COUNT-2: pmulhsu.h
+// RV64: pmulhsu.h
+int16x4_t test_pmulhsu_i16x4(int16x4_t rs1, uint16x4_t rs2) {
+ return __riscv_pmulhsu_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhrsu_i16x4:
+// RV32-COUNT-2: pmulhrsu.h
+// RV64: pmulhrsu.h
+int16x4_t test_pmulhrsu_i16x4(int16x4_t rs1, uint16x4_t rs2) {
+ return __riscv_pmulhrsu_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulh_i32x2:
+// RV32-COUNT-2: mulh
+// RV64: pmulh.w
+int32x2_t test_pmulh_i32x2(int32x2_t rs1, int32x2_t rs2) {
+ return __riscv_pmulh_i32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhr_i32x2:
+// RV32-COUNT-2: mulhr
+// RV64: pmulhr.w
+int32x2_t test_pmulhr_i32x2(int32x2_t rs1, int32x2_t rs2) {
+ return __riscv_pmulhr_i32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhu_u32x2:
+// RV32-COUNT-2: mulhu
+// RV64: pmulhu.w
+uint32x2_t test_pmulhu_u32x2(uint32x2_t rs1, uint32x2_t rs2) {
+ return __riscv_pmulhu_u32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhru_u32x2:
+// RV32-COUNT-2: mulhru
+// RV64: pmulhru.w
+uint32x2_t test_pmulhru_u32x2(uint32x2_t rs1, uint32x2_t rs2) {
+ return __riscv_pmulhru_u32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhsu_i32x2:
+// RV32-COUNT-2: mulhsu
+// RV64: pmulhsu.w
+int32x2_t test_pmulhsu_i32x2(int32x2_t rs1, uint32x2_t rs2) {
+ return __riscv_pmulhsu_i32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhrsu_i32x2:
+// RV32-COUNT-2: mulhrsu
+// RV64: pmulhrsu.w
+int32x2_t test_pmulhrsu_i32x2(int32x2_t rs1, uint32x2_t rs2) {
+ return __riscv_pmulhrsu_i32x2(rs1, rs2);
+}
+
// CHECK-LABEL: test_prev_i8x4:
// CHECK: rev8
int8x4_t test_prev_i8x4(int8x4_t a) { return __riscv_prev_i8x4(a); }
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 6e3de3bfbc309..517d0e51ec406 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2109,6 +2109,14 @@ class RVPBinaryIntrinsic
def int_riscv_pzext_b : RVPExtIntrinsic;
def int_riscv_pzext_h : RVPExtIntrinsic;
+ // Packed Multiply High.
+ def int_riscv_pmulh : RVPBinaryIntrinsic;
+ def int_riscv_pmulhr : RVPBinaryIntrinsic;
+ def int_riscv_pmulhu : RVPBinaryIntrinsic;
+ def int_riscv_pmulhru : RVPBinaryIntrinsic;
+ def int_riscv_pmulhsu : RVPBinaryIntrinsic;
+ def int_riscv_pmulhrsu : RVPBinaryIntrinsic;
+
// Packed Absolute Difference Sum.
def int_riscv_pabdsumu
: DefaultAttrsIntrinsic<[llvm_anyint_ty],
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f2849ea2921ee..dde6a86f395c2 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12030,6 +12030,25 @@ static SDValue lowerPZExt(SDValue Src, const SDLoc &DL, SelectionDAG &DAG,
return DAG.getBitcast(VT, Res);
}
+static unsigned getRVPMulHighOpcode(unsigned IntNo) {
+ switch (IntNo) {
+ default:
+ llvm_unreachable("Unexpected RISC-V packed multiply high intrinsic");
+ case Intrinsic::riscv_pmulh:
+ return ISD::MULHS;
+ case Intrinsic::riscv_pmulhr:
+ return RISCVISD::MULHR;
+ case Intrinsic::riscv_pmulhu:
+ return ISD::MULHU;
+ case Intrinsic::riscv_pmulhru:
+ return RISCVISD::MULHRU;
+ case Intrinsic::riscv_pmulhsu:
+ return RISCVISD::MULHSU;
+ case Intrinsic::riscv_pmulhrsu:
+ return RISCVISD::MULHRSU;
+ }
+}
+
SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
unsigned IntNo = Op.getConstantOperandVal(0);
@@ -12302,6 +12321,44 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32, AbdsumauId, Lo,
Rs1Hi, Rs2Hi);
}
+ case Intrinsic::riscv_pmulh:
+ case Intrinsic::riscv_pmulhr:
+ case Intrinsic::riscv_pmulhu:
+ case Intrinsic::riscv_pmulhru:
+ case Intrinsic::riscv_pmulhsu:
+ case Intrinsic::riscv_pmulhrsu: {
+ EVT VT = Op.getValueType();
+ unsigned Opc = getRVPMulHighOpcode(IntNo);
+
+ // RV32 has no single instruction for 64-bit packed multiply high. Split
+ // v4i16 into two v2i16 packed operations, and split v2i32 into scalar i32
+ // operations so isel can use MULH*.
+ if (!Subtarget.is64Bit() && VT == MVT::v4i16) {
+ auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Op.getOperand(1), DL);
+ auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Op.getOperand(2), DL);
+ SDValue Id = Op.getOperand(0);
+ SDValue Lo = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i16, Id,
+ Rs1Lo, Rs2Lo);
+ SDValue Hi = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i16, Id,
+ Rs1Hi, Rs2Hi);
+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
+ }
+
+ if (!Subtarget.is64Bit() && VT == MVT::v2i32) {
+ auto Extract = [&](SDValue V, unsigned Idx) {
+ return DAG.getExtractVectorElt(DL, MVT::i32, V, Idx);
+ };
+ SDValue Rs1 = Op.getOperand(1);
+ SDValue Rs2 = Op.getOperand(2);
+ SDValue Lo = DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 0),
+ Extract(Rs2, 0));
+ SDValue Hi = DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 1),
+ Extract(Rs2, 1));
+ return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Lo, Hi);
+ }
+
+ return DAG.getNode(Opc, DL, VT, Op.getOperand(1), Op.getOperand(2));
+ }
case Intrinsic::riscv_pmerge: {
EVT VT = Op.getValueType();
auto buildMerge = [&](SDValue Rs1, SDValue Rs2, SDValue Mask,
@@ -16386,9 +16443,15 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
case Intrinsic::riscv_paas:
case Intrinsic::riscv_pasa:
case Intrinsic::riscv_pmerge:
- case Intrinsic::riscv_psabs:
case Intrinsic::riscv_pmulq:
- case Intrinsic::riscv_pmulqr: {
+ case Intrinsic::riscv_pmulqr:
+ case Intrinsic::riscv_pmulh:
+ case Intrinsic::riscv_pmulhr:
+ case Intrinsic::riscv_pmulhu:
+ case Intrinsic::riscv_pmulhru:
+ case Intrinsic::riscv_pmulhsu:
+ case Intrinsic::riscv_pmulhrsu:
+ case Intrinsic::riscv_psabs: {
EVT VT = N->getValueType(0);
if (!Subtarget.is64Bit() || (VT != MVT::v4i8 && VT != MVT::v2i16))
return;
@@ -16423,8 +16486,8 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
Opc = RISCVISD::MULQR;
break;
default:
- // pas/psa/psas/pssa/paas/pasa and pmerge: re-emit at the widened type
- // rather than lowering to a generic node.
+ // pas/psa/psas/pssa/paas/pasa, pmerge, and pmulh*: re-emit at the
+ // widened type rather than lowering to a generic node.
Opc = ISD::INTRINSIC_WO_CHAIN;
break;
}
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index 42a20b2b89af7..5d72e96d4babd 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -2709,6 +2709,61 @@ define <2 x i16> @test_riscv_pzext_b_v2i16(<2 x i16> %a) {
ret <2 x i16> %res
}
+; Packed multiply high
+define <2 x i16> @test_pmulh_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulh_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pmulh.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pmulh.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhr_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhr_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pmulhr.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pmulhr.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhu_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhu_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pmulhu.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pmulhu.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhru_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhru_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pmulhru.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pmulhru.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhsu_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhsu_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pmulhsu.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pmulhsu.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhrsu_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhrsu_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pmulhrsu.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pmulhrsu.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+ ret <2 x i16> %res
+}
+
; Packed absolute difference sum
define i32 @test_pabdsumu_u8x4_u32(<4 x i8> %a, <4 x i8> %b) {
; RV32-LABEL: test_pabdsumu_u8x4_u32:
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 21b2f96b6727b..2918b5aed4917 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -5982,6 +5982,187 @@ define <2 x i32> @test_riscv_pzext_h_v2i32(<2 x i32> %a) {
ret <2 x i32> %res
}
+; Packed multiply high
+define <4 x i16> @test_pmulh_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulh_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pmulh.h a1, a1, a3
+; RV32-NEXT: pmulh.h a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulh_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulh.h a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pmulh.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+ ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhr_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhr_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pmulhr.h a1, a1, a3
+; RV32-NEXT: pmulhr.h a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhr_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhr.h a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pmulhr.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+ ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhu_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhu_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pmulhu.h a1, a1, a3
+; RV32-NEXT: pmulhu.h a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhu_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhu.h a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pmulhu.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+ ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhru_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhru_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pmulhru.h a1, a1, a3
+; RV32-NEXT: pmulhru.h a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhru_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhru.h a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pmulhru.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+ ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhsu_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhsu_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pmulhsu.h a1, a1, a3
+; RV32-NEXT: pmulhsu.h a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhsu_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhsu.h a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pmulhsu.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+ ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhrsu_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhrsu_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pmulhrsu.h a1, a1, a3
+; RV32-NEXT: pmulhrsu.h a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhrsu_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhrsu.h a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pmulhrsu.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+ ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pmulh_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulh_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: mulh a1, a1, a3
+; RV32-NEXT: mulh a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulh_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulh.w a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pmulh.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhr_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhr_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: mulhr a1, a1, a3
+; RV32-NEXT: mulhr a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhr_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhr.w a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pmulhr.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhu_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhu_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: mulhu a1, a1, a3
+; RV32-NEXT: mulhu a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhu_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhu.w a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pmulhu.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhru_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhru_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: mulhru a1, a1, a3
+; RV32-NEXT: mulhru a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhru_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhru.w a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pmulhru.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhsu_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhsu_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: mulhsu a1, a1, a3
+; RV32-NEXT: mulhsu a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhsu_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhsu.w a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pmulhsu.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhrsu_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhrsu_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: mulhrsu a1, a1, a3
+; RV32-NEXT: mulhrsu a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pmulhrsu_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pmulhrsu.w a0, a0, a1
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pmulhrsu.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+ ret <2 x i32> %res
+}
+
; Packed absolute difference sum
define i32 @test_pabdsumu_u8x8_u32(<8 x i8> %a, <8 x i8> %b) {
; RV32-LABEL: test_pabdsumu_u8x8_u32:
>From 0a763cf260cf809040510f50300980a6d8510fee Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Fri, 24 Jul 2026 00:14:41 +0800
Subject: [PATCH 2/3] format
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index dde6a86f395c2..f27079e3e132a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12350,10 +12350,10 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
};
SDValue Rs1 = Op.getOperand(1);
SDValue Rs2 = Op.getOperand(2);
- SDValue Lo = DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 0),
- Extract(Rs2, 0));
- SDValue Hi = DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 1),
- Extract(Rs2, 1));
+ SDValue Lo =
+ DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 0), Extract(Rs2, 0));
+ SDValue Hi =
+ DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 1), Extract(Rs2, 1));
return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Lo, Hi);
}
>From 00b2d526b949596729146b6e9d93c0f0729144b3 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Fri, 24 Jul 2026 19:31:56 +0800
Subject: [PATCH 3/3] resolve comments
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f27079e3e132a..edba40c326fdd 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12336,11 +12336,8 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
if (!Subtarget.is64Bit() && VT == MVT::v4i16) {
auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Op.getOperand(1), DL);
auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Op.getOperand(2), DL);
- SDValue Id = Op.getOperand(0);
- SDValue Lo = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i16, Id,
- Rs1Lo, Rs2Lo);
- SDValue Hi = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i16, Id,
- Rs1Hi, Rs2Hi);
+ SDValue Lo = DAG.getNode(Opc, DL, MVT::v2i16, Rs1Lo, Rs2Lo);
+ SDValue Hi = DAG.getNode(Opc, DL, MVT::v2i16, Rs1Hi, Rs2Hi);
return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
}
@@ -16485,9 +16482,17 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
case Intrinsic::riscv_pmulqr:
Opc = RISCVISD::MULQR;
break;
+ case Intrinsic::riscv_pmulh:
+ case Intrinsic::riscv_pmulhr:
+ case Intrinsic::riscv_pmulhu:
+ case Intrinsic::riscv_pmulhru:
+ case Intrinsic::riscv_pmulhsu:
+ case Intrinsic::riscv_pmulhrsu:
+ Opc = getRVPMulHighOpcode(IntNo);
+ break;
default:
- // pas/psa/psas/pssa/paas/pasa, pmerge, and pmulh*: re-emit at the
- // widened type rather than lowering to a generic node.
+ // pas/psa/psas/pssa/paas/pasa and pmerge: re-emit at the widened type
+ // rather than lowering to a generic node.
Opc = ISD::INTRINSIC_WO_CHAIN;
break;
}
More information about the cfe-commits
mailing list