https://github.com/sihuan updated 
https://github.com/llvm/llvm-project/pull/218875

>From c0a8a1ed40207fb727b044a17c3c6a5ee3dc004b Mon Sep 17 00:00:00 2001
From: SiHuaN <[email protected]>
Date: Thu, 13 Aug 2026 18:49:25 +0000
Subject: [PATCH 1/3] [RISCV][P-ext] Add packed multiply-parts intrinsics

---
 clang/include/clang/Basic/BuiltinsRISCV.td    |  43 ++
 clang/lib/CodeGen/TargetBuiltins/RISCV.cpp    | 131 ++++++
 clang/lib/Headers/riscv_packed_simd.h         |  43 ++
 .../riscv_packed_simd.c                       | 281 +++++++++++++
 llvm/include/llvm/IR/IntrinsicsRISCV.td       |  30 ++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   | 156 ++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td      |  44 ++
 llvm/test/CodeGen/RISCV/rvp-simd-32.ll        | 202 ++++++++++
 llvm/test/CodeGen/RISCV/rvp-simd-64.ll        | 378 ++++++++++++++++++
 .../RISCV/rvp-simd-intrinsic-invalid.ll       |  26 ++
 10 files changed, 1334 insertions(+)

diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td 
b/clang/include/clang/Basic/BuiltinsRISCV.td
index b292ffc0140e8..c60214e4b3559 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -318,6 +318,49 @@ def pmulq_i16x4  : RISCVBuiltin<"_Vector<4, 
short>(_Vector<4, short>, _Vector<4,
 def pmulqr_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, 
_Vector<4, short>)">;
 def pmulq_i32x2  : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>)">;
 def pmulqr_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>)">;
+// Packed Multiply Parts (32-bit)
+def pmul_b00_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, 
_Vector<4, signed char>)">;
+def pmul_b01_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, 
_Vector<4, signed char>)">;
+def pmul_b11_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, 
_Vector<4, signed char>)">;
+def pmulu_b00_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<4, 
unsigned char>, _Vector<4, unsigned char>)">;
+def pmulu_b01_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<4, 
unsigned char>, _Vector<4, unsigned char>)">;
+def pmulu_b11_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<4, 
unsigned char>, _Vector<4, unsigned char>)">;
+def pmulsu_b00_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed 
char>, _Vector<4, unsigned char>)">;
+def pmulsu_b11_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed 
char>, _Vector<4, unsigned char>)">;
+def mul_h00_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, short>)">;
+def mul_h01_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, short>)">;
+def mul_h11_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, short>)">;
+def mulu_h00_u32 : RISCVBuiltin<"unsigned int(_Vector<2, unsigned short>, 
_Vector<2, unsigned short>)">;
+def mulu_h01_u32 : RISCVBuiltin<"unsigned int(_Vector<2, unsigned short>, 
_Vector<2, unsigned short>)">;
+def mulu_h11_u32 : RISCVBuiltin<"unsigned int(_Vector<2, unsigned short>, 
_Vector<2, unsigned short>)">;
+def mulsu_h00_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, unsigned 
short>)">;
+def mulsu_h11_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, unsigned 
short>)">;
+
+// Packed Multiply Parts (64-bit)
+def pmul_b00_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, 
_Vector<8, signed char>)">;
+def pmul_b01_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, 
_Vector<8, signed char>)">;
+def pmul_b11_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, 
_Vector<8, signed char>)">;
+def pmulu_b00_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<8, 
unsigned char>, _Vector<8, unsigned char>)">;
+def pmulu_b01_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<8, 
unsigned char>, _Vector<8, unsigned char>)">;
+def pmulu_b11_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<8, 
unsigned char>, _Vector<8, unsigned char>)">;
+def pmulsu_b00_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed 
char>, _Vector<8, unsigned char>)">;
+def pmulsu_b11_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed 
char>, _Vector<8, unsigned char>)">;
+def pmul_h00_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, 
_Vector<4, short>)">;
+def pmul_h01_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, 
_Vector<4, short>)">;
+def pmul_h11_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, 
_Vector<4, short>)">;
+def pmulu_h00_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<4, 
unsigned short>, _Vector<4, unsigned short>)">;
+def pmulu_h01_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<4, 
unsigned short>, _Vector<4, unsigned short>)">;
+def pmulu_h11_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<4, 
unsigned short>, _Vector<4, unsigned short>)">;
+def pmulsu_h00_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, 
_Vector<4, unsigned short>)">;
+def pmulsu_h11_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, 
_Vector<4, unsigned short>)">;
+def mul_w00_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, int>)">;
+def mul_w01_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, int>)">;
+def mul_w11_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, int>)">;
+def mulu_w00_u64 : RISCVBuiltin<"uint64_t(_Vector<2, unsigned int>, _Vector<2, 
unsigned int>)">;
+def mulu_w01_u64 : RISCVBuiltin<"uint64_t(_Vector<2, unsigned int>, _Vector<2, 
unsigned int>)">;
+def mulu_w11_u64 : RISCVBuiltin<"uint64_t(_Vector<2, unsigned int>, _Vector<2, 
unsigned int>)">;
+def mulsu_w00_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, unsigned 
int>)">;
+def mulsu_w11_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, unsigned 
int>)">;
 
 // Packed "Q-format" Multiply Parts Accumulate (32-bit)
 def mqacc_h00_i32  : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 91f451e34c2c9..af12697c5d493 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1625,6 +1625,137 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
     IntrinsicTypes = {ResultType, Ops.back()->getType()};
     break;
   }
+  // Packed Multiply Parts.
+  case RISCV::BI__builtin_riscv_pmul_b00_i16x2:
+  case RISCV::BI__builtin_riscv_pmul_b01_i16x2:
+  case RISCV::BI__builtin_riscv_pmul_b11_i16x2:
+  case RISCV::BI__builtin_riscv_pmulu_b00_u16x2:
+  case RISCV::BI__builtin_riscv_pmulu_b01_u16x2:
+  case RISCV::BI__builtin_riscv_pmulu_b11_u16x2:
+  case RISCV::BI__builtin_riscv_pmulsu_b00_i16x2:
+  case RISCV::BI__builtin_riscv_pmulsu_b11_i16x2:
+  case RISCV::BI__builtin_riscv_pmul_b00_i16x4:
+  case RISCV::BI__builtin_riscv_pmul_b01_i16x4:
+  case RISCV::BI__builtin_riscv_pmul_b11_i16x4:
+  case RISCV::BI__builtin_riscv_pmulu_b00_u16x4:
+  case RISCV::BI__builtin_riscv_pmulu_b01_u16x4:
+  case RISCV::BI__builtin_riscv_pmulu_b11_u16x4:
+  case RISCV::BI__builtin_riscv_pmulsu_b00_i16x4:
+  case RISCV::BI__builtin_riscv_pmulsu_b11_i16x4:
+  case RISCV::BI__builtin_riscv_pmul_h00_i32x2:
+  case RISCV::BI__builtin_riscv_pmul_h01_i32x2:
+  case RISCV::BI__builtin_riscv_pmul_h11_i32x2:
+  case RISCV::BI__builtin_riscv_pmulu_h00_u32x2:
+  case RISCV::BI__builtin_riscv_pmulu_h01_u32x2:
+  case RISCV::BI__builtin_riscv_pmulu_h11_u32x2:
+  case RISCV::BI__builtin_riscv_pmulsu_h00_i32x2:
+  case RISCV::BI__builtin_riscv_pmulsu_h11_i32x2: {
+    switch (BuiltinID) {
+    default:
+      llvm_unreachable("unexpected builtin ID");
+    case RISCV::BI__builtin_riscv_pmul_b00_i16x2:
+    case RISCV::BI__builtin_riscv_pmul_b00_i16x4:
+    case RISCV::BI__builtin_riscv_pmul_h00_i32x2:
+      ID = Intrinsic::riscv_pmul_00;
+      break;
+    case RISCV::BI__builtin_riscv_pmul_b01_i16x2:
+    case RISCV::BI__builtin_riscv_pmul_b01_i16x4:
+    case RISCV::BI__builtin_riscv_pmul_h01_i32x2:
+      ID = Intrinsic::riscv_pmul_01;
+      break;
+    case RISCV::BI__builtin_riscv_pmul_b11_i16x2:
+    case RISCV::BI__builtin_riscv_pmul_b11_i16x4:
+    case RISCV::BI__builtin_riscv_pmul_h11_i32x2:
+      ID = Intrinsic::riscv_pmul_11;
+      break;
+    case RISCV::BI__builtin_riscv_pmulu_b00_u16x2:
+    case RISCV::BI__builtin_riscv_pmulu_b00_u16x4:
+    case RISCV::BI__builtin_riscv_pmulu_h00_u32x2:
+      ID = Intrinsic::riscv_pmulu_00;
+      break;
+    case RISCV::BI__builtin_riscv_pmulu_b01_u16x2:
+    case RISCV::BI__builtin_riscv_pmulu_b01_u16x4:
+    case RISCV::BI__builtin_riscv_pmulu_h01_u32x2:
+      ID = Intrinsic::riscv_pmulu_01;
+      break;
+    case RISCV::BI__builtin_riscv_pmulu_b11_u16x2:
+    case RISCV::BI__builtin_riscv_pmulu_b11_u16x4:
+    case RISCV::BI__builtin_riscv_pmulu_h11_u32x2:
+      ID = Intrinsic::riscv_pmulu_11;
+      break;
+    case RISCV::BI__builtin_riscv_pmulsu_b00_i16x2:
+    case RISCV::BI__builtin_riscv_pmulsu_b00_i16x4:
+    case RISCV::BI__builtin_riscv_pmulsu_h00_i32x2:
+      ID = Intrinsic::riscv_pmulsu_00;
+      break;
+    case RISCV::BI__builtin_riscv_pmulsu_b11_i16x2:
+    case RISCV::BI__builtin_riscv_pmulsu_b11_i16x4:
+    case RISCV::BI__builtin_riscv_pmulsu_h11_i32x2:
+      ID = Intrinsic::riscv_pmulsu_11;
+      break;
+    }
+
+    IntrinsicTypes = {ResultType};
+    break;
+  }
+
+  // Scalar Multiply Parts.
+  case RISCV::BI__builtin_riscv_mul_h00_i32:
+  case RISCV::BI__builtin_riscv_mul_w00_i64:
+  case RISCV::BI__builtin_riscv_mul_h01_i32:
+  case RISCV::BI__builtin_riscv_mul_w01_i64:
+  case RISCV::BI__builtin_riscv_mul_h11_i32:
+  case RISCV::BI__builtin_riscv_mul_w11_i64:
+  case RISCV::BI__builtin_riscv_mulu_h00_u32:
+  case RISCV::BI__builtin_riscv_mulu_w00_u64:
+  case RISCV::BI__builtin_riscv_mulu_h01_u32:
+  case RISCV::BI__builtin_riscv_mulu_w01_u64:
+  case RISCV::BI__builtin_riscv_mulu_h11_u32:
+  case RISCV::BI__builtin_riscv_mulu_w11_u64:
+  case RISCV::BI__builtin_riscv_mulsu_h00_i32:
+  case RISCV::BI__builtin_riscv_mulsu_w00_i64:
+  case RISCV::BI__builtin_riscv_mulsu_h11_i32:
+  case RISCV::BI__builtin_riscv_mulsu_w11_i64: {
+    switch (BuiltinID) {
+    default:
+      llvm_unreachable("unexpected builtin ID");
+    case RISCV::BI__builtin_riscv_mul_h00_i32:
+    case RISCV::BI__builtin_riscv_mul_w00_i64:
+      ID = Intrinsic::riscv_mul_00;
+      break;
+    case RISCV::BI__builtin_riscv_mul_h01_i32:
+    case RISCV::BI__builtin_riscv_mul_w01_i64:
+      ID = Intrinsic::riscv_mul_01;
+      break;
+    case RISCV::BI__builtin_riscv_mul_h11_i32:
+    case RISCV::BI__builtin_riscv_mul_w11_i64:
+      ID = Intrinsic::riscv_mul_11;
+      break;
+    case RISCV::BI__builtin_riscv_mulu_h00_u32:
+    case RISCV::BI__builtin_riscv_mulu_w00_u64:
+      ID = Intrinsic::riscv_mulu_00;
+      break;
+    case RISCV::BI__builtin_riscv_mulu_h01_u32:
+    case RISCV::BI__builtin_riscv_mulu_w01_u64:
+      ID = Intrinsic::riscv_mulu_01;
+      break;
+    case RISCV::BI__builtin_riscv_mulu_h11_u32:
+    case RISCV::BI__builtin_riscv_mulu_w11_u64:
+      ID = Intrinsic::riscv_mulu_11;
+      break;
+    case RISCV::BI__builtin_riscv_mulsu_h00_i32:
+    case RISCV::BI__builtin_riscv_mulsu_w00_i64:
+      ID = Intrinsic::riscv_mulsu_00;
+      break;
+    case RISCV::BI__builtin_riscv_mulsu_h11_i32:
+    case RISCV::BI__builtin_riscv_mulsu_w11_i64:
+      ID = Intrinsic::riscv_mulsu_11;
+      break;
+    }
+
+    IntrinsicTypes = {ResultType, Ops[0]->getType()};
+    break;
+  }
 
   // Packed "Q-format" Multiply Parts Accumulate
   case RISCV::BI__builtin_riscv_mqacc_h00_i32:
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index 946dd936d49cd..45171aeda546f 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -851,6 +851,49 @@ __packed_binary_builtin(pmulq_i16x4, int16x4_t, 
__builtin_riscv_pmulq_i16x4)
 __packed_binary_builtin(pmulqr_i16x4, int16x4_t, __builtin_riscv_pmulqr_i16x4)
 __packed_binary_builtin(pmulq_i32x2, int32x2_t, __builtin_riscv_pmulq_i32x2)
 __packed_binary_builtin(pmulqr_i32x2, int32x2_t, __builtin_riscv_pmulqr_i32x2)
+/* Packed Multiply Parts (32-bit) */
+__packed_binary_builtin_mixed(pmul_b00_i16x2, int16x2_t, int8x4_t, int8x4_t, 
__builtin_riscv_pmul_b00_i16x2)
+__packed_binary_builtin_mixed(pmul_b01_i16x2, int16x2_t, int8x4_t, int8x4_t, 
__builtin_riscv_pmul_b01_i16x2)
+__packed_binary_builtin_mixed(pmul_b11_i16x2, int16x2_t, int8x4_t, int8x4_t, 
__builtin_riscv_pmul_b11_i16x2)
+__packed_binary_builtin_mixed(pmulu_b00_u16x2, uint16x2_t, uint8x4_t, 
uint8x4_t, __builtin_riscv_pmulu_b00_u16x2)
+__packed_binary_builtin_mixed(pmulu_b01_u16x2, uint16x2_t, uint8x4_t, 
uint8x4_t, __builtin_riscv_pmulu_b01_u16x2)
+__packed_binary_builtin_mixed(pmulu_b11_u16x2, uint16x2_t, uint8x4_t, 
uint8x4_t, __builtin_riscv_pmulu_b11_u16x2)
+__packed_binary_builtin_mixed(pmulsu_b00_i16x2, int16x2_t, int8x4_t, 
uint8x4_t, __builtin_riscv_pmulsu_b00_i16x2)
+__packed_binary_builtin_mixed(pmulsu_b11_i16x2, int16x2_t, int8x4_t, 
uint8x4_t, __builtin_riscv_pmulsu_b11_i16x2)
+__packed_binary_builtin_mixed(mul_h00_i32, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_mul_h00_i32)
+__packed_binary_builtin_mixed(mul_h01_i32, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_mul_h01_i32)
+__packed_binary_builtin_mixed(mul_h11_i32, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_mul_h11_i32)
+__packed_binary_builtin_mixed(mulu_h00_u32, uint32_t, uint16x2_t, uint16x2_t, 
__builtin_riscv_mulu_h00_u32)
+__packed_binary_builtin_mixed(mulu_h01_u32, uint32_t, uint16x2_t, uint16x2_t, 
__builtin_riscv_mulu_h01_u32)
+__packed_binary_builtin_mixed(mulu_h11_u32, uint32_t, uint16x2_t, uint16x2_t, 
__builtin_riscv_mulu_h11_u32)
+__packed_binary_builtin_mixed(mulsu_h00_i32, int32_t, int16x2_t, uint16x2_t, 
__builtin_riscv_mulsu_h00_i32)
+__packed_binary_builtin_mixed(mulsu_h11_i32, int32_t, int16x2_t, uint16x2_t, 
__builtin_riscv_mulsu_h11_i32)
+
+/* Packed Multiply Parts (64-bit) */
+__packed_binary_builtin_mixed(pmul_b00_i16x4, int16x4_t, int8x8_t, int8x8_t, 
__builtin_riscv_pmul_b00_i16x4)
+__packed_binary_builtin_mixed(pmul_b01_i16x4, int16x4_t, int8x8_t, int8x8_t, 
__builtin_riscv_pmul_b01_i16x4)
+__packed_binary_builtin_mixed(pmul_b11_i16x4, int16x4_t, int8x8_t, int8x8_t, 
__builtin_riscv_pmul_b11_i16x4)
+__packed_binary_builtin_mixed(pmulu_b00_u16x4, uint16x4_t, uint8x8_t, 
uint8x8_t, __builtin_riscv_pmulu_b00_u16x4)
+__packed_binary_builtin_mixed(pmulu_b01_u16x4, uint16x4_t, uint8x8_t, 
uint8x8_t, __builtin_riscv_pmulu_b01_u16x4)
+__packed_binary_builtin_mixed(pmulu_b11_u16x4, uint16x4_t, uint8x8_t, 
uint8x8_t, __builtin_riscv_pmulu_b11_u16x4)
+__packed_binary_builtin_mixed(pmulsu_b00_i16x4, int16x4_t, int8x8_t, 
uint8x8_t, __builtin_riscv_pmulsu_b00_i16x4)
+__packed_binary_builtin_mixed(pmulsu_b11_i16x4, int16x4_t, int8x8_t, 
uint8x8_t, __builtin_riscv_pmulsu_b11_i16x4)
+__packed_binary_builtin_mixed(pmul_h00_i32x2, int32x2_t, int16x4_t, int16x4_t, 
__builtin_riscv_pmul_h00_i32x2)
+__packed_binary_builtin_mixed(pmul_h01_i32x2, int32x2_t, int16x4_t, int16x4_t, 
__builtin_riscv_pmul_h01_i32x2)
+__packed_binary_builtin_mixed(pmul_h11_i32x2, int32x2_t, int16x4_t, int16x4_t, 
__builtin_riscv_pmul_h11_i32x2)
+__packed_binary_builtin_mixed(pmulu_h00_u32x2, uint32x2_t, uint16x4_t, 
uint16x4_t, __builtin_riscv_pmulu_h00_u32x2)
+__packed_binary_builtin_mixed(pmulu_h01_u32x2, uint32x2_t, uint16x4_t, 
uint16x4_t, __builtin_riscv_pmulu_h01_u32x2)
+__packed_binary_builtin_mixed(pmulu_h11_u32x2, uint32x2_t, uint16x4_t, 
uint16x4_t, __builtin_riscv_pmulu_h11_u32x2)
+__packed_binary_builtin_mixed(pmulsu_h00_i32x2, int32x2_t, int16x4_t, 
uint16x4_t, __builtin_riscv_pmulsu_h00_i32x2)
+__packed_binary_builtin_mixed(pmulsu_h11_i32x2, int32x2_t, int16x4_t, 
uint16x4_t, __builtin_riscv_pmulsu_h11_i32x2)
+__packed_binary_builtin_mixed(mul_w00_i64, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_mul_w00_i64)
+__packed_binary_builtin_mixed(mul_w01_i64, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_mul_w01_i64)
+__packed_binary_builtin_mixed(mul_w11_i64, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_mul_w11_i64)
+__packed_binary_builtin_mixed(mulu_w00_u64, uint64_t, uint32x2_t, uint32x2_t, 
__builtin_riscv_mulu_w00_u64)
+__packed_binary_builtin_mixed(mulu_w01_u64, uint64_t, uint32x2_t, uint32x2_t, 
__builtin_riscv_mulu_w01_u64)
+__packed_binary_builtin_mixed(mulu_w11_u64, uint64_t, uint32x2_t, uint32x2_t, 
__builtin_riscv_mulu_w11_u64)
+__packed_binary_builtin_mixed(mulsu_w00_i64, int64_t, int32x2_t, uint32x2_t, 
__builtin_riscv_mulsu_w00_i64)
+__packed_binary_builtin_mixed(mulsu_w11_i64, int64_t, int32x2_t, uint32x2_t, 
__builtin_riscv_mulsu_w11_i64)
 
 /* Packed "Q-format" Multiply Parts Accumulate (32-bit) */
 __packed_ternary_builtin_cast(mqacc_h00_i32, int, int16x2_t, 
__builtin_riscv_mqacc_h00_i32)
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 28e3a8911739d..7385b4b3a642e 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -3532,3 +3532,284 @@ int64_t test_mqracc_w01_i64(int64_t rd, int32x2_t a, 
int32x2_t b) {
 int64_t test_mqracc_w11_i64(int64_t rd, int32x2_t a, int32x2_t b) {
   return __riscv_mqracc_w11_i64(rd, a, b);
 }
+
+// Packed Multiply Parts.
+// CHECK-LABEL: test_pmul_b00_i16x2:
+// RV32:        pmul.h.b00
+// RV64:        pmul.h.b00
+int16x2_t test_pmul_b00_i16x2(int8x4_t a, int8x4_t b) {
+  return __riscv_pmul_b00_i16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmul_b01_i16x2:
+// RV32:        pmul.h.b01
+// RV64:        pmul.h.b01
+int16x2_t test_pmul_b01_i16x2(int8x4_t a, int8x4_t b) {
+  return __riscv_pmul_b01_i16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmul_b11_i16x2:
+// RV32:        pmul.h.b11
+// RV64:        pmul.h.b11
+int16x2_t test_pmul_b11_i16x2(int8x4_t a, int8x4_t b) {
+  return __riscv_pmul_b11_i16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_b00_u16x2:
+// RV32:        pmulu.h.b00
+// RV64:        pmulu.h.b00
+uint16x2_t test_pmulu_b00_u16x2(uint8x4_t a, uint8x4_t b) {
+  return __riscv_pmulu_b00_u16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_b01_u16x2:
+// RV32:        pmulu.h.b01
+// RV64:        pmulu.h.b01
+uint16x2_t test_pmulu_b01_u16x2(uint8x4_t a, uint8x4_t b) {
+  return __riscv_pmulu_b01_u16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_b11_u16x2:
+// RV32:        pmulu.h.b11
+// RV64:        pmulu.h.b11
+uint16x2_t test_pmulu_b11_u16x2(uint8x4_t a, uint8x4_t b) {
+  return __riscv_pmulu_b11_u16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulsu_b00_i16x2:
+// RV32:        pmulsu.h.b00
+// RV64:        pmulsu.h.b00
+int16x2_t test_pmulsu_b00_i16x2(int8x4_t a, uint8x4_t b) {
+  return __riscv_pmulsu_b00_i16x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulsu_b11_i16x2:
+// RV32:        pmulsu.h.b11
+// RV64:        pmulsu.h.b11
+int16x2_t test_pmulsu_b11_i16x2(int8x4_t a, uint8x4_t b) {
+  return __riscv_pmulsu_b11_i16x2(a, b);
+}
+
+// CHECK-LABEL: test_mul_h00_i32:
+// RV32:        mul.h00
+// RV64:        pmul.w.h00
+int32_t test_mul_h00_i32(int16x2_t a, int16x2_t b) {
+  return __riscv_mul_h00_i32(a, b);
+}
+
+// CHECK-LABEL: test_mul_h01_i32:
+// RV32:        mul.h01
+// RV64:        pmul.w.h01
+int32_t test_mul_h01_i32(int16x2_t a, int16x2_t b) {
+  return __riscv_mul_h01_i32(a, b);
+}
+
+// CHECK-LABEL: test_mul_h11_i32:
+// RV32:        mul.h11
+// RV64:        pmul.w.h11
+int32_t test_mul_h11_i32(int16x2_t a, int16x2_t b) {
+  return __riscv_mul_h11_i32(a, b);
+}
+
+// CHECK-LABEL: test_mulu_h00_u32:
+// RV32:        mulu.h00
+// RV64:        pmulu.w.h00
+uint32_t test_mulu_h00_u32(uint16x2_t a, uint16x2_t b) {
+  return __riscv_mulu_h00_u32(a, b);
+}
+
+// CHECK-LABEL: test_mulu_h01_u32:
+// RV32:        mulu.h01
+// RV64:        pmulu.w.h01
+uint32_t test_mulu_h01_u32(uint16x2_t a, uint16x2_t b) {
+  return __riscv_mulu_h01_u32(a, b);
+}
+
+// CHECK-LABEL: test_mulu_h11_u32:
+// RV32:        mulu.h11
+// RV64:        pmulu.w.h11
+uint32_t test_mulu_h11_u32(uint16x2_t a, uint16x2_t b) {
+  return __riscv_mulu_h11_u32(a, b);
+}
+
+// CHECK-LABEL: test_mulsu_h00_i32:
+// RV32:        mulsu.h00
+// RV64:        pmulsu.w.h00
+int32_t test_mulsu_h00_i32(int16x2_t a, uint16x2_t b) {
+  return __riscv_mulsu_h00_i32(a, b);
+}
+
+// CHECK-LABEL: test_mulsu_h11_i32:
+// RV32:        mulsu.h11
+// RV64:        pmulsu.w.h11
+int32_t test_mulsu_h11_i32(int16x2_t a, uint16x2_t b) {
+  return __riscv_mulsu_h11_i32(a, b);
+}
+
+// CHECK-LABEL: test_pmul_b00_i16x4:
+// RV32-COUNT-2: pmul.h.b00
+// RV64:         pmul.h.b00
+int16x4_t test_pmul_b00_i16x4(int8x8_t a, int8x8_t b) {
+  return __riscv_pmul_b00_i16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmul_b01_i16x4:
+// RV32-COUNT-2: pmul.h.b01
+// RV64:         pmul.h.b01
+int16x4_t test_pmul_b01_i16x4(int8x8_t a, int8x8_t b) {
+  return __riscv_pmul_b01_i16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmul_b11_i16x4:
+// RV32-COUNT-2: pmul.h.b11
+// RV64:         pmul.h.b11
+int16x4_t test_pmul_b11_i16x4(int8x8_t a, int8x8_t b) {
+  return __riscv_pmul_b11_i16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_b00_u16x4:
+// RV32-COUNT-2: pmulu.h.b00
+// RV64:         pmulu.h.b00
+uint16x4_t test_pmulu_b00_u16x4(uint8x8_t a, uint8x8_t b) {
+  return __riscv_pmulu_b00_u16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_b01_u16x4:
+// RV32-COUNT-2: pmulu.h.b01
+// RV64:         pmulu.h.b01
+uint16x4_t test_pmulu_b01_u16x4(uint8x8_t a, uint8x8_t b) {
+  return __riscv_pmulu_b01_u16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_b11_u16x4:
+// RV32-COUNT-2: pmulu.h.b11
+// RV64:         pmulu.h.b11
+uint16x4_t test_pmulu_b11_u16x4(uint8x8_t a, uint8x8_t b) {
+  return __riscv_pmulu_b11_u16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmulsu_b00_i16x4:
+// RV32-COUNT-2: pmulsu.h.b00
+// RV64:         pmulsu.h.b00
+int16x4_t test_pmulsu_b00_i16x4(int8x8_t a, uint8x8_t b) {
+  return __riscv_pmulsu_b00_i16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmulsu_b11_i16x4:
+// RV32-COUNT-2: pmulsu.h.b11
+// RV64:         pmulsu.h.b11
+int16x4_t test_pmulsu_b11_i16x4(int8x8_t a, uint8x8_t b) {
+  return __riscv_pmulsu_b11_i16x4(a, b);
+}
+
+// CHECK-LABEL: test_pmul_h00_i32x2:
+// RV32-COUNT-2: mul.h00
+// RV64:         pmul.w.h00
+int32x2_t test_pmul_h00_i32x2(int16x4_t a, int16x4_t b) {
+  return __riscv_pmul_h00_i32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmul_h01_i32x2:
+// RV32-COUNT-2: mul.h01
+// RV64:         pmul.w.h01
+int32x2_t test_pmul_h01_i32x2(int16x4_t a, int16x4_t b) {
+  return __riscv_pmul_h01_i32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmul_h11_i32x2:
+// RV32-COUNT-2: mul.h11
+// RV64:         pmul.w.h11
+int32x2_t test_pmul_h11_i32x2(int16x4_t a, int16x4_t b) {
+  return __riscv_pmul_h11_i32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_h00_u32x2:
+// RV32-COUNT-2: mulu.h00
+// RV64:         pmulu.w.h00
+uint32x2_t test_pmulu_h00_u32x2(uint16x4_t a, uint16x4_t b) {
+  return __riscv_pmulu_h00_u32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_h01_u32x2:
+// RV32-COUNT-2: mulu.h01
+// RV64:         pmulu.w.h01
+uint32x2_t test_pmulu_h01_u32x2(uint16x4_t a, uint16x4_t b) {
+  return __riscv_pmulu_h01_u32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulu_h11_u32x2:
+// RV32-COUNT-2: mulu.h11
+// RV64:         pmulu.w.h11
+uint32x2_t test_pmulu_h11_u32x2(uint16x4_t a, uint16x4_t b) {
+  return __riscv_pmulu_h11_u32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulsu_h00_i32x2:
+// RV32-COUNT-2: mulsu.h00
+// RV64:         pmulsu.w.h00
+int32x2_t test_pmulsu_h00_i32x2(int16x4_t a, uint16x4_t b) {
+  return __riscv_pmulsu_h00_i32x2(a, b);
+}
+
+// CHECK-LABEL: test_pmulsu_h11_i32x2:
+// RV32-COUNT-2: mulsu.h11
+// RV64:         pmulsu.w.h11
+int32x2_t test_pmulsu_h11_i32x2(int16x4_t a, uint16x4_t b) {
+  return __riscv_pmulsu_h11_i32x2(a, b);
+}
+
+// CHECK-LABEL: test_mul_w00_i64:
+// RV32:        wmul{{[[:space:]]}}
+// RV64:        mul.w00
+int64_t test_mul_w00_i64(int32x2_t a, int32x2_t b) {
+  return __riscv_mul_w00_i64(a, b);
+}
+
+// CHECK-LABEL: test_mul_w01_i64:
+// RV32:        wmul{{[[:space:]]}}
+// RV64:        mul.w01
+int64_t test_mul_w01_i64(int32x2_t a, int32x2_t b) {
+  return __riscv_mul_w01_i64(a, b);
+}
+
+// CHECK-LABEL: test_mul_w11_i64:
+// RV32:        wmul{{[[:space:]]}}
+// RV64:        mul.w11
+int64_t test_mul_w11_i64(int32x2_t a, int32x2_t b) {
+  return __riscv_mul_w11_i64(a, b);
+}
+
+// CHECK-LABEL: test_mulu_w00_u64:
+// RV32:        wmulu{{[[:space:]]}}
+// RV64:        mulu.w00
+uint64_t test_mulu_w00_u64(uint32x2_t a, uint32x2_t b) {
+  return __riscv_mulu_w00_u64(a, b);
+}
+
+// CHECK-LABEL: test_mulu_w01_u64:
+// RV32:        wmulu{{[[:space:]]}}
+// RV64:        mulu.w01
+uint64_t test_mulu_w01_u64(uint32x2_t a, uint32x2_t b) {
+  return __riscv_mulu_w01_u64(a, b);
+}
+
+// CHECK-LABEL: test_mulu_w11_u64:
+// RV32:        wmulu{{[[:space:]]}}
+// RV64:        mulu.w11
+uint64_t test_mulu_w11_u64(uint32x2_t a, uint32x2_t b) {
+  return __riscv_mulu_w11_u64(a, b);
+}
+
+// CHECK-LABEL: test_mulsu_w00_i64:
+// RV32:        wmulsu{{[[:space:]]}}
+// RV64:        mulsu.w00
+int64_t test_mulsu_w00_i64(int32x2_t a, uint32x2_t b) {
+  return __riscv_mulsu_w00_i64(a, b);
+}
+
+// CHECK-LABEL: test_mulsu_w11_i64:
+// RV32:        wmulsu{{[[:space:]]}}
+// RV64:        mulsu.w11
+int64_t test_mulsu_w11_i64(int32x2_t a, uint32x2_t b) {
+  return __riscv_mulsu_w11_i64(a, b);
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 9c810ecc2a624..1466f5b553ad4 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2124,6 +2124,36 @@ class RVPBinaryIntrinsic
   def int_riscv_pmhraccu  : RVPTernaryIntrinsic;
   def int_riscv_pmhaccsu  : RVPTernaryIntrinsic;
   def int_riscv_pmhraccsu : RVPTernaryIntrinsic;
+  // Packed Multiply Parts. The packed forms multiply the selected element of
+  // every pair, so the operands are the result with each element split in two.
+  class RVPPackedMulPartsIntrinsic
+      : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
+                              [LLVMSubdivide2VectorType<0>,
+                               LLVMSubdivide2VectorType<0>],
+                              [IntrNoMem, IntrSpeculatable]>;
+  def int_riscv_pmul_00   : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmul_01   : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmul_11   : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmulu_00  : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmulu_01  : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmulu_11  : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmulsu_00 : RVPPackedMulPartsIntrinsic;
+  def int_riscv_pmulsu_11 : RVPPackedMulPartsIntrinsic;
+
+  // The scalar forms select one element from each packed operand and keep that
+  // single product: <2 x i16> pairs with i32 and <2 x i32> with i64.
+  class RVPScalarMulPartsIntrinsic
+      : DefaultAttrsIntrinsic<[llvm_anyint_ty],
+                              [llvm_anyvector_ty, LLVMMatchType<1>],
+                              [IntrNoMem, IntrSpeculatable]>;
+  def int_riscv_mul_00   : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mul_01   : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mul_11   : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mulu_00  : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mulu_01  : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mulu_11  : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mulsu_00 : RVPScalarMulPartsIntrinsic;
+  def int_riscv_mulsu_11 : RVPScalarMulPartsIntrinsic;
 
   // Packed Absolute Difference Sum.
   def int_riscv_pabdsumu
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index fb403aa3bc274..266169fb1465f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12329,6 +12329,67 @@ static unsigned getRVPQFormatAccOpcode(Intrinsic::ID 
IntNo) {
   }
 }
 
+struct RVPMulPartsForms {
+  Intrinsic::ID Packed;
+  Intrinsic::ID Scalar;
+};
+
+static RVPMulPartsForms getRVPMulPartsForms(unsigned IntNo) {
+  switch (IntNo) {
+  default:
+    llvm_unreachable("Unexpected RISC-V multiply-parts intrinsic");
+  case Intrinsic::riscv_pmul_00:
+  case Intrinsic::riscv_mul_00:
+    return {Intrinsic::riscv_pmul_00, Intrinsic::riscv_mul_00};
+  case Intrinsic::riscv_pmul_01:
+  case Intrinsic::riscv_mul_01:
+    return {Intrinsic::riscv_pmul_01, Intrinsic::riscv_mul_01};
+  case Intrinsic::riscv_pmul_11:
+  case Intrinsic::riscv_mul_11:
+    return {Intrinsic::riscv_pmul_11, Intrinsic::riscv_mul_11};
+  case Intrinsic::riscv_pmulu_00:
+  case Intrinsic::riscv_mulu_00:
+    return {Intrinsic::riscv_pmulu_00, Intrinsic::riscv_mulu_00};
+  case Intrinsic::riscv_pmulu_01:
+  case Intrinsic::riscv_mulu_01:
+    return {Intrinsic::riscv_pmulu_01, Intrinsic::riscv_mulu_01};
+  case Intrinsic::riscv_pmulu_11:
+  case Intrinsic::riscv_mulu_11:
+    return {Intrinsic::riscv_pmulu_11, Intrinsic::riscv_mulu_11};
+  case Intrinsic::riscv_pmulsu_00:
+  case Intrinsic::riscv_mulsu_00:
+    return {Intrinsic::riscv_pmulsu_00, Intrinsic::riscv_mulsu_00};
+  case Intrinsic::riscv_pmulsu_11:
+  case Intrinsic::riscv_mulsu_11:
+    return {Intrinsic::riscv_pmulsu_11, Intrinsic::riscv_mulsu_11};
+  }
+}
+
+/// Return {opcode, rs1 lane, rs2 lane} for the word form of \p IntNo.
+static std::tuple<unsigned, unsigned, unsigned>
+getRVPWordMulPartsOpcodeAndLanes(unsigned IntNo) {
+  switch (IntNo) {
+  default:
+    llvm_unreachable("Unexpected RISC-V multiply-parts intrinsic");
+  case Intrinsic::riscv_mul_00:
+    return {ISD::SMUL_LOHI, 0, 0};
+  case Intrinsic::riscv_mul_01:
+    return {ISD::SMUL_LOHI, 0, 1};
+  case Intrinsic::riscv_mul_11:
+    return {ISD::SMUL_LOHI, 1, 1};
+  case Intrinsic::riscv_mulu_00:
+    return {ISD::UMUL_LOHI, 0, 0};
+  case Intrinsic::riscv_mulu_01:
+    return {ISD::UMUL_LOHI, 0, 1};
+  case Intrinsic::riscv_mulu_11:
+    return {ISD::UMUL_LOHI, 1, 1};
+  case Intrinsic::riscv_mulsu_00:
+    return {RISCVISD::WMULSU, 0, 0};
+  case Intrinsic::riscv_mulsu_11:
+    return {RISCVISD::WMULSU, 1, 1};
+  }
+}
+
 SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
                                                      SelectionDAG &DAG) const {
   unsigned IntNo = Op.getConstantOperandVal(0);
@@ -12357,6 +12418,36 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
     EVT PtrVT = getPointerTy(DAG.getDataLayout());
     return DAG.getRegister(RISCV::X4, PtrVT);
   }
+  case Intrinsic::riscv_pmul_00:
+  case Intrinsic::riscv_pmul_01:
+  case Intrinsic::riscv_pmul_11:
+  case Intrinsic::riscv_pmulu_00:
+  case Intrinsic::riscv_pmulu_01:
+  case Intrinsic::riscv_pmulu_11:
+  case Intrinsic::riscv_pmulsu_00:
+  case Intrinsic::riscv_pmulsu_11: {
+    // On RV32 a 64-bit result lives in a GPR pair; compute each half with the
+    // 32-bit form of the same product.
+    MVT VT = Op.getSimpleValueType();
+    if (!Subtarget.isPExtPackedDoubleType(VT))
+      return SDValue();
+
+    bool IsSingleProduct = VT == MVT::v2i32;
+    MVT HalfVT = IsSingleProduct ? MVT::i32 : VT.getHalfNumVectorElementsVT();
+    SDValue Id = IsSingleProduct
+                     ? DAG.getTargetConstant(getRVPMulPartsForms(IntNo).Scalar,
+                                             DL, MVT::i32)
+                     : Op.getOperand(0);
+    auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Op.getOperand(1), DL);
+    auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Op.getOperand(2), DL);
+    SDValue Lo =
+        DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, HalfVT, Id, Rs1Lo, Rs2Lo);
+    SDValue Hi =
+        DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, HalfVT, Id, Rs1Hi, Rs2Hi);
+    return DAG.getNode(IsSingleProduct ? ISD::BUILD_VECTOR
+                                       : ISD::CONCAT_VECTORS,
+                       DL, VT, Lo, Hi);
+  }
   case Intrinsic::riscv_pas:
   case Intrinsic::riscv_psa:
   case Intrinsic::riscv_psas:
@@ -16870,6 +16961,71 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
       Results.push_back(DAG.getExtractSubvector(DL, VT, Res, 0));
       return;
     }
+    case Intrinsic::riscv_pmul_00:
+    case Intrinsic::riscv_pmul_01:
+    case Intrinsic::riscv_pmul_11:
+    case Intrinsic::riscv_pmulu_00:
+    case Intrinsic::riscv_pmulu_01:
+    case Intrinsic::riscv_pmulu_11:
+    case Intrinsic::riscv_pmulsu_00:
+    case Intrinsic::riscv_pmulsu_11: {
+      MVT VT = N->getSimpleValueType(0);
+      if (!Subtarget.is64Bit() || VT != MVT::v2i16)
+        return;
+
+      SDValue Undef = DAG.getUNDEF(MVT::v4i8);
+      SDValue Rs1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8,
+                                N->getOperand(1), Undef);
+      SDValue Rs2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8,
+                                N->getOperand(2), Undef);
+      SDValue Res = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v4i16,
+                                N->getOperand(0), Rs1, Rs2);
+      Results.push_back(DAG.getExtractSubvector(DL, VT, Res, 0));
+      return;
+    }
+    case Intrinsic::riscv_mul_00:
+    case Intrinsic::riscv_mul_01:
+    case Intrinsic::riscv_mul_11:
+    case Intrinsic::riscv_mulu_00:
+    case Intrinsic::riscv_mulu_01:
+    case Intrinsic::riscv_mulu_11:
+    case Intrinsic::riscv_mulsu_00:
+    case Intrinsic::riscv_mulsu_11: {
+      // mul.hXX exists only on RV32 and mul.wXX only on RV64; the other XLEN
+      // has to build the product here.
+      MVT VT = N->getSimpleValueType(0);
+      MVT SrcVT = N->getOperand(1).getSimpleValueType();
+      if (Subtarget.hasStdExtP() && Subtarget.is64Bit() && VT == MVT::i32 &&
+          SrcVT == MVT::v2i16) {
+        // The halfword product is the first element of the packed one.
+        SDValue Undef = DAG.getUNDEF(SrcVT);
+        SDValue Rs1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16,
+                                  N->getOperand(1), Undef);
+        SDValue Rs2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16,
+                                  N->getOperand(2), Undef);
+        SDValue Id = DAG.getTargetConstant(getRVPMulPartsForms(IntNo).Packed,
+                                           DL, MVT::i32);
+        SDValue Res =
+            DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i32, Id, Rs1, Rs2);
+        Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32,
+                                      DAG.getBitcast(MVT::i64, Res)));
+        return;
+      }
+      if (Subtarget.hasStdExtP() && !Subtarget.is64Bit() && VT == MVT::i64 &&
+          SrcVT == MVT::v2i32) {
+        auto [Opc, Rs1Lane, Rs2Lane] = getRVPWordMulPartsOpcodeAndLanes(IntNo);
+        SDValue Rs1 =
+            DAG.getExtractVectorElt(DL, MVT::i32, N->getOperand(1), Rs1Lane);
+        SDValue Rs2 =
+            DAG.getExtractVectorElt(DL, MVT::i32, N->getOperand(2), Rs2Lane);
+        SDValue Res =
+            DAG.getNode(Opc, DL, DAG.getVTList(MVT::i32, MVT::i32), Rs1, Rs2);
+        Results.push_back(
+            DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Res, Res.getValue(1)));
+        return;
+      }
+      reportFatalUsageError("unsupported llvm.riscv multiply-parts intrinsic");
+    }
     case Intrinsic::riscv_paadd:
     case Intrinsic::riscv_paaddu:
     case Intrinsic::riscv_pasub:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 06cf949cca56b..79e40bacfbd40 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1785,6 +1785,10 @@ class PatAbdSum<SDPatternOperator OpNode, RVInst Inst, 
ValueType VecVT>
 class PatAbdSumAcc<SDPatternOperator OpNode, RVInst Inst, ValueType VecVT>
     : Pat<(XLenVT (OpNode (XLenVT GPR:$rd), (VecVT GPR:$rs1), (VecVT 
GPR:$rs2))),
           (Inst GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+class PatMulParts<SDPatternOperator OpNode, RVInst Inst, ValueType ResultVT,
+                  ValueType SourceVT>
+    : Pat<(ResultVT (OpNode (SourceVT GPR:$rs1), (SourceVT GPR:$rs2))),
+          (Inst GPR:$rs1, GPR:$rs2)>;
 
 class PatGprGprGpr<SDPatternOperator OpNode, RVInst Inst, ValueType VT>
     : Pat<(VT (OpNode (VT GPR:$rd), (VT GPR:$rs1), (VT GPR:$rs2))),
@@ -2295,7 +2299,27 @@ let Predicates = [HasStdExtP] in {
   def : Pat<(XLenVecI16VT (riscv_ppairoe_h GPR:$rs1, GPR:$rs2)),
             (PPAIROE_H GPR:$rs1, GPR:$rs2)>;
 
+  // Packed byte multiply-parts patterns.
+  def : PatMulParts<int_riscv_pmul_00, PMUL_H_B00, XLenVecI16VT, XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmul_01, PMUL_H_B01, XLenVecI16VT, XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmul_11, PMUL_H_B11, XLenVecI16VT, XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmulu_00, PMULU_H_B00, XLenVecI16VT, 
XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmulu_01, PMULU_H_B01, XLenVecI16VT, 
XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmulu_11, PMULU_H_B11, XLenVecI16VT, 
XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmulsu_00, PMULSU_H_B00, XLenVecI16VT, 
XLenVecI8VT>;
+  def : PatMulParts<int_riscv_pmulsu_11, PMULSU_H_B11, XLenVecI16VT, 
XLenVecI8VT>;
+
 let append Predicates = [IsRV32] in {
+  // Scalar halfword multiply-parts patterns.
+  def : PatMulParts<int_riscv_mul_00, MUL_H00, i32, v2i16>;
+  def : PatMulParts<int_riscv_mul_01, MUL_H01, i32, v2i16>;
+  def : PatMulParts<int_riscv_mul_11, MUL_H11, i32, v2i16>;
+  def : PatMulParts<int_riscv_mulu_00, MULU_H00, i32, v2i16>;
+  def : PatMulParts<int_riscv_mulu_01, MULU_H01, i32, v2i16>;
+  def : PatMulParts<int_riscv_mulu_11, MULU_H11, i32, v2i16>;
+  def : PatMulParts<int_riscv_mulsu_00, MULSU_H00, i32, v2i16>;
+  def : PatMulParts<int_riscv_mulsu_11, MULSU_H11, i32, v2i16>;
+
   def : PatGpr<bitreverse, REV_RV32>;
 
   def : Pat<(XLenVT (riscv_sati GPR:$rs1, timm:$imm)),
@@ -2926,6 +2950,26 @@ let append Predicates = [IsRV64] in {
   def : PatGprGpr<riscv_asub, PASUB_W, v2i32>;
   def : PatGprGpr<riscv_asubu, PASUBU_W, v2i32>;
 
+  // Packed halfword multiply-parts patterns.
+  def : PatMulParts<int_riscv_pmul_00, PMUL_W_H00, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmul_01, PMUL_W_H01, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmul_11, PMUL_W_H11, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmulu_00, PMULU_W_H00, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmulu_01, PMULU_W_H01, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmulu_11, PMULU_W_H11, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmulsu_00, PMULSU_W_H00, v2i32, v4i16>;
+  def : PatMulParts<int_riscv_pmulsu_11, PMULSU_W_H11, v2i32, v4i16>;
+
+  // Scalar word multiply-parts patterns.
+  def : PatMulParts<int_riscv_mul_00, MUL_W00, i64, v2i32>;
+  def : PatMulParts<int_riscv_mul_01, MUL_W01, i64, v2i32>;
+  def : PatMulParts<int_riscv_mul_11, MUL_W11, i64, v2i32>;
+  def : PatMulParts<int_riscv_mulu_00, MULU_W00, i64, v2i32>;
+  def : PatMulParts<int_riscv_mulu_01, MULU_W01, i64, v2i32>;
+  def : PatMulParts<int_riscv_mulu_11, MULU_W11, i64, v2i32>;
+  def : PatMulParts<int_riscv_mulsu_00, MULSU_W00, i64, v2i32>;
+  def : PatMulParts<int_riscv_mulsu_11, MULSU_W11, i64, v2i32>;
+
   // 32-bit multiply high patterns
   def : PatGprGpr<mulhs, PMULH_W, v2i32>;
   def : PatGprGpr<mulhu, PMULHU_W, v2i32>;
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index f1209617b6a90..08635cd9539c8 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -3240,3 +3240,205 @@ define i32 @test_mqracc_h11_i32(i32 %rd, <2 x i16> %a, 
<2 x i16> %b) {
   %r = call i32 @llvm.riscv.mqracc.h11.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
   ret i32 %r
 }
+
+; Packed Multiply Parts.
+declare <2 x i16> @llvm.riscv.pmul.00.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmul.01.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmul.11.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmulu.00.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmulu.01.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmulu.11.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmulsu.00.v2i16(<4 x i8>, <4 x i8>)
+declare <2 x i16> @llvm.riscv.pmulsu.11.v2i16(<4 x i8>, <4 x i8>)
+declare i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mul.01.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mul.11.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mulu.00.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mulu.01.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mulu.11.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mulsu.00.i32.v2i16(<2 x i16>, <2 x i16>)
+declare i32 @llvm.riscv.mulsu.11.i32.v2i16(<2 x i16>, <2 x i16>)
+
+define <2 x i16> @test_pmul_b00_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmul_b00_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmul.h.b00 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmul.00.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmul_b01_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmul_b01_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmul.h.b01 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmul.01.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmul_b11_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmul_b11_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmul.h.b11 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmul.11.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmulu_b00_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmulu_b00_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulu.h.b00 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmulu.00.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmulu_b01_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmulu_b01_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulu.h.b01 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmulu.01.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmulu_b11_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmulu_b11_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulu.h.b11 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmulu.11.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmulsu_b00_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmulsu_b00_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulsu.h.b00 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmulsu.00.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define <2 x i16> @test_pmulsu_b11_v2i16(<4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pmulsu_b11_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulsu.h.b11 a0, a0, a1
+; CHECK-NEXT:    ret
+  %r = call <2 x i16> @llvm.riscv.pmulsu.11.v2i16(<4 x i8> %a, <4 x i8> %b)
+  ret <2 x i16> %r
+}
+
+define i32 @test_mul_h00_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mul_h00_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mul.h00 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mul_h00_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.w.h00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mul_h01_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mul_h01_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mul.h01 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mul_h01_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.w.h01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mul.01.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mul_h11_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mul_h11_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mul.h11 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mul_h11_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.w.h11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mul.11.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mulu_h00_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mulu_h00_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulu.h00 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulu_h00_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.w.h00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mulu.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mulu_h01_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mulu_h01_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulu.h01 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulu_h01_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.w.h01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mulu.01.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mulu_h11_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mulu_h11_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulu.h11 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulu_h11_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.w.h11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mulu.11.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mulsu_h00_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mulsu_h00_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulsu.h00 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulsu_h00_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulsu.w.h00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mulsu.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_mulsu_h11_i32(<2 x i16> %a, <2 x i16> %b) {
+; RV32-LABEL: test_mulsu_h11_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulsu.h11 a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulsu_h11_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulsu.w.h11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i32 @llvm.riscv.mulsu.11.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %r
+}
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 51b86057ccdbe..0de86ef220252 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -7113,3 +7113,381 @@ define i64 @test_mqracc_w11_i64(i64 %rd, <2 x i32> %a, 
<2 x i32> %b) {
   %r = call i64 @llvm.riscv.mqracc.w11.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
   ret i64 %r
 }
+
+; Packed Multiply Parts.
+declare <4 x i16> @llvm.riscv.pmul.00.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmul.01.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmul.11.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmulu.00.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmulu.01.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmulu.11.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmulsu.00.v4i16(<8 x i8>, <8 x i8>)
+declare <4 x i16> @llvm.riscv.pmulsu.11.v4i16(<8 x i8>, <8 x i8>)
+declare <2 x i32> @llvm.riscv.pmul.00.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmul.01.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmul.11.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmulu.00.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmulu.01.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmulu.11.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmulsu.00.v2i32(<4 x i16>, <4 x i16>)
+declare <2 x i32> @llvm.riscv.pmulsu.11.v2i32(<4 x i16>, <4 x i16>)
+declare i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mul.01.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mul.11.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mulu.00.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mulu.01.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mulu.11.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mulsu.00.i64.v2i32(<2 x i32>, <2 x i32>)
+declare i64 @llvm.riscv.mulsu.11.i64.v2i32(<2 x i32>, <2 x i32>)
+
+define <4 x i16> @test_pmul_b00_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmul_b00_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmul.h.b00 a1, a1, a3
+; RV32-NEXT:    pmul.h.b00 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmul_b00_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.h.b00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmul.00.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmul_b01_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmul_b01_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmul.h.b01 a1, a1, a3
+; RV32-NEXT:    pmul.h.b01 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmul_b01_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.h.b01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmul.01.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmul_b11_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmul_b11_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmul.h.b11 a1, a1, a3
+; RV32-NEXT:    pmul.h.b11 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmul_b11_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.h.b11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmul.11.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmulu_b00_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmulu_b00_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulu.h.b00 a1, a1, a3
+; RV32-NEXT:    pmulu.h.b00 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulu_b00_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.h.b00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmulu.00.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmulu_b01_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmulu_b01_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulu.h.b01 a1, a1, a3
+; RV32-NEXT:    pmulu.h.b01 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulu_b01_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.h.b01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmulu.01.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmulu_b11_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmulu_b11_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulu.h.b11 a1, a1, a3
+; RV32-NEXT:    pmulu.h.b11 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulu_b11_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.h.b11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmulu.11.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmulsu_b00_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmulsu_b00_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulsu.h.b00 a1, a1, a3
+; RV32-NEXT:    pmulsu.h.b00 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulsu_b00_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulsu.h.b00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmulsu.00.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <4 x i16> @test_pmulsu_b11_v4i16(<8 x i8> %a, <8 x i8> %b) {
+; RV32-LABEL: test_pmulsu_b11_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulsu.h.b11 a1, a1, a3
+; RV32-NEXT:    pmulsu.h.b11 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulsu_b11_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulsu.h.b11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <4 x i16> @llvm.riscv.pmulsu.11.v4i16(<8 x i8> %a, <8 x i8> %b)
+  ret <4 x i16> %r
+}
+
+define <2 x i32> @test_pmul_h00_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmul_h00_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mul.h00 a1, a1, a3
+; RV32-NEXT:    mul.h00 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmul_h00_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.w.h00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmul.00.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmul_h01_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmul_h01_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mul.h01 a1, a1, a3
+; RV32-NEXT:    mul.h01 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmul_h01_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.w.h01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmul.01.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmul_h11_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmul_h11_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mul.h11 a1, a1, a3
+; RV32-NEXT:    mul.h11 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmul_h11_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmul.w.h11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmul.11.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmulu_h00_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmulu_h00_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulu.h00 a1, a1, a3
+; RV32-NEXT:    mulu.h00 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulu_h00_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.w.h00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmulu.00.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmulu_h01_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmulu_h01_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulu.h01 a1, a1, a3
+; RV32-NEXT:    mulu.h01 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulu_h01_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.w.h01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmulu.01.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmulu_h11_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmulu_h11_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulu.h11 a1, a1, a3
+; RV32-NEXT:    mulu.h11 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulu_h11_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulu.w.h11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmulu.11.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmulsu_h00_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmulsu_h00_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulsu.h00 a1, a1, a3
+; RV32-NEXT:    mulsu.h00 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulsu_h00_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulsu.w.h00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmulsu.00.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmulsu_h11_v2i32(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pmulsu_h11_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulsu.h11 a1, a1, a3
+; RV32-NEXT:    mulsu.h11 a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulsu_h11_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulsu.w.h11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmulsu.11.v2i32(<4 x i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define i64 @test_mul_w00_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mul_w00_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmul a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mul_w00_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mul.w00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mul_w01_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mul_w01_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmul a0, a0, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mul_w01_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mul.w01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mul.01.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mul_w11_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mul_w11_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmul a0, a1, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mul_w11_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mul.w11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mul.11.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mulu_w00_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mulu_w00_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmulu a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulu_w00_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mulu.w00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mulu.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mulu_w01_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mulu_w01_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmulu a0, a0, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulu_w01_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mulu.w01 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mulu.01.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mulu_w11_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mulu_w11_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmulu a0, a1, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulu_w11_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mulu.w11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mulu.11.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mulsu_w00_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mulsu_w00_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmulsu a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulsu_w00_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mulsu.w00 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mulsu.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_mulsu_w11_i64(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_mulsu_w11_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmulsu a0, a1, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulsu_w11_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    mulsu.w11 a0, a0, a1
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.mulsu.11.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %r
+}
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll
index 28b1d7c53a6e7..20858559a4521 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll
@@ -7,9 +7,16 @@
 ; RUN: sed -n '/^; BEGIN-PZEXT$/,/^; END-PZEXT$/p' %s \
 ; RUN:   | not llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \
 ; RUN:   -o /dev/null 2>&1 | FileCheck %s --check-prefix=PZEXT
+; RUN: sed -n '/^; BEGIN-MUL-H$/,/^; END-MUL-H$/p' %s \
+; RUN:   | not llc -mtriple=riscv64 -mattr=+m \
+; RUN:   -o /dev/null 2>&1 | FileCheck %s --check-prefix=MULPARTS
+; RUN: sed -n '/^; BEGIN-MUL-W$/,/^; END-MUL-W$/p' %s \
+; RUN:   | not llc -mtriple=riscv32 -mattr=+v,+m \
+; RUN:   -o /dev/null 2>&1 | FileCheck %s --check-prefix=MULPARTS
 
 ; PSEXT: LLVM ERROR: unsupported llvm.riscv.psext intrinsic
 ; PZEXT: LLVM ERROR: unsupported llvm.riscv.pzext intrinsic
+; MULPARTS: LLVM ERROR: unsupported llvm.riscv multiply-parts intrinsic
 
 ; BEGIN-PSEXT-LEGAL
 define <4 x i16> @bad_psext_legal_type(<4 x i16> %a) {
@@ -37,3 +44,22 @@ define <2 x i32> @bad_pzext(<2 x i32> %a) {
 
 declare <2 x i32> @llvm.riscv.pzext.b.v2i32(<2 x i32>)
 ; END-PZEXT
+
+; The multiply-parts intrinsics are only legalizable with the P extension.
+; BEGIN-MUL-H
+define i32 @bad_mul_h00_without_p(<2 x i16> %a, <2 x i16> %b) {
+  %res = call i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b)
+  ret i32 %res
+}
+
+declare i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16>, <2 x i16>)
+; END-MUL-H
+
+; BEGIN-MUL-W
+define i64 @bad_mul_w00_without_p(<2 x i32> %a, <2 x i32> %b) {
+  %res = call i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b)
+  ret i64 %res
+}
+
+declare i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32>, <2 x i32>)
+; END-MUL-W

>From 25665aa38fc141aa783b1da95cdc1996974a4a2e Mon Sep 17 00:00:00 2001
From: SiHuaN <[email protected]>
Date: Thu, 27 Aug 2026 08:37:28 +0000
Subject: [PATCH 2/3] Address review: lower packed multiply-parts to
 PMUL_HALVES nodes

Custom lower the packed intrinsics to the existing RISCVISD::PMUL_HALVES_*
nodes instead of matching the intrinsics in isel patterns. The byte-form
node patterns become XLen-generic so one set covers both targets, and the
missing v2i32 halfword patterns are filled in.
---
 clang/include/clang/Basic/BuiltinsRISCV.td  |   1 +
 clang/lib/Headers/riscv_packed_simd.h       |   1 +
 llvm/include/llvm/IR/IntrinsicsRISCV.td     |   1 +
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 101 ++++++++++++--------
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td    |  76 +++++++--------
 5 files changed, 100 insertions(+), 80 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td 
b/clang/include/clang/Basic/BuiltinsRISCV.td
index c60214e4b3559..b5aa5861d3dd2 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -318,6 +318,7 @@ def pmulq_i16x4  : RISCVBuiltin<"_Vector<4, 
short>(_Vector<4, short>, _Vector<4,
 def pmulqr_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, 
_Vector<4, short>)">;
 def pmulq_i32x2  : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>)">;
 def pmulqr_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>)">;
+
 // Packed Multiply Parts (32-bit)
 def pmul_b00_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, 
_Vector<4, signed char>)">;
 def pmul_b01_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, 
_Vector<4, signed char>)">;
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index 45171aeda546f..d6826d3b1f7cd 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -851,6 +851,7 @@ __packed_binary_builtin(pmulq_i16x4, int16x4_t, 
__builtin_riscv_pmulq_i16x4)
 __packed_binary_builtin(pmulqr_i16x4, int16x4_t, __builtin_riscv_pmulqr_i16x4)
 __packed_binary_builtin(pmulq_i32x2, int32x2_t, __builtin_riscv_pmulq_i32x2)
 __packed_binary_builtin(pmulqr_i32x2, int32x2_t, __builtin_riscv_pmulqr_i32x2)
+
 /* Packed Multiply Parts (32-bit) */
 __packed_binary_builtin_mixed(pmul_b00_i16x2, int16x2_t, int8x4_t, int8x4_t, 
__builtin_riscv_pmul_b00_i16x2)
 __packed_binary_builtin_mixed(pmul_b01_i16x2, int16x2_t, int8x4_t, int8x4_t, 
__builtin_riscv_pmul_b01_i16x2)
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 1466f5b553ad4..74b5e9e653a8e 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2124,6 +2124,7 @@ class RVPBinaryIntrinsic
   def int_riscv_pmhraccu  : RVPTernaryIntrinsic;
   def int_riscv_pmhaccsu  : RVPTernaryIntrinsic;
   def int_riscv_pmhraccsu : RVPTernaryIntrinsic;
+
   // Packed Multiply Parts. The packed forms multiply the selected element of
   // every pair, so the operands are the result with each element split in two.
   class RVPPackedMulPartsIntrinsic
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 266169fb1465f..5c915d154c458 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12329,39 +12329,61 @@ static unsigned getRVPQFormatAccOpcode(Intrinsic::ID 
IntNo) {
   }
 }
 
-struct RVPMulPartsForms {
-  Intrinsic::ID Packed;
-  Intrinsic::ID Scalar;
-};
-
-static RVPMulPartsForms getRVPMulPartsForms(unsigned IntNo) {
+/// Return the packed multiply-halves node for a multiply-parts intrinsic. The
+/// scalar spelling maps to the same node; its product is the first element.
+static unsigned getRVPMulHalvesOpcode(unsigned IntNo) {
   switch (IntNo) {
   default:
     llvm_unreachable("Unexpected RISC-V multiply-parts intrinsic");
   case Intrinsic::riscv_pmul_00:
   case Intrinsic::riscv_mul_00:
-    return {Intrinsic::riscv_pmul_00, Intrinsic::riscv_mul_00};
+    return RISCVISD::PMUL_HALVES_00;
   case Intrinsic::riscv_pmul_01:
   case Intrinsic::riscv_mul_01:
-    return {Intrinsic::riscv_pmul_01, Intrinsic::riscv_mul_01};
+    return RISCVISD::PMUL_HALVES_01;
   case Intrinsic::riscv_pmul_11:
   case Intrinsic::riscv_mul_11:
-    return {Intrinsic::riscv_pmul_11, Intrinsic::riscv_mul_11};
+    return RISCVISD::PMUL_HALVES_11;
   case Intrinsic::riscv_pmulu_00:
   case Intrinsic::riscv_mulu_00:
-    return {Intrinsic::riscv_pmulu_00, Intrinsic::riscv_mulu_00};
+    return RISCVISD::PMULU_HALVES_00;
   case Intrinsic::riscv_pmulu_01:
   case Intrinsic::riscv_mulu_01:
-    return {Intrinsic::riscv_pmulu_01, Intrinsic::riscv_mulu_01};
+    return RISCVISD::PMULU_HALVES_01;
   case Intrinsic::riscv_pmulu_11:
   case Intrinsic::riscv_mulu_11:
-    return {Intrinsic::riscv_pmulu_11, Intrinsic::riscv_mulu_11};
+    return RISCVISD::PMULU_HALVES_11;
   case Intrinsic::riscv_pmulsu_00:
   case Intrinsic::riscv_mulsu_00:
-    return {Intrinsic::riscv_pmulsu_00, Intrinsic::riscv_mulsu_00};
+    return RISCVISD::PMULSU_HALVES_00;
   case Intrinsic::riscv_pmulsu_11:
   case Intrinsic::riscv_mulsu_11:
-    return {Intrinsic::riscv_pmulsu_11, Intrinsic::riscv_mulsu_11};
+    return RISCVISD::PMULSU_HALVES_11;
+  }
+}
+
+/// Return the scalar multiply-parts intrinsic computing the first product of
+/// packed intrinsic \p IntNo.
+static Intrinsic::ID getRVPScalarMulPartsIntrinsic(unsigned IntNo) {
+  switch (IntNo) {
+  default:
+    llvm_unreachable("Unexpected RISC-V packed multiply-parts intrinsic");
+  case Intrinsic::riscv_pmul_00:
+    return Intrinsic::riscv_mul_00;
+  case Intrinsic::riscv_pmul_01:
+    return Intrinsic::riscv_mul_01;
+  case Intrinsic::riscv_pmul_11:
+    return Intrinsic::riscv_mul_11;
+  case Intrinsic::riscv_pmulu_00:
+    return Intrinsic::riscv_mulu_00;
+  case Intrinsic::riscv_pmulu_01:
+    return Intrinsic::riscv_mulu_01;
+  case Intrinsic::riscv_pmulu_11:
+    return Intrinsic::riscv_mulu_11;
+  case Intrinsic::riscv_pmulsu_00:
+    return Intrinsic::riscv_mulsu_00;
+  case Intrinsic::riscv_pmulsu_11:
+    return Intrinsic::riscv_mulsu_11;
   }
 }
 
@@ -12426,27 +12448,31 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
   case Intrinsic::riscv_pmulu_11:
   case Intrinsic::riscv_pmulsu_00:
   case Intrinsic::riscv_pmulsu_11: {
-    // On RV32 a 64-bit result lives in a GPR pair; compute each half with the
-    // 32-bit form of the same product.
     MVT VT = Op.getSimpleValueType();
+    SDValue Rs1 = Op.getOperand(1);
+    SDValue Rs2 = Op.getOperand(2);
+    unsigned Opc = getRVPMulHalvesOpcode(IntNo);
     if (!Subtarget.isPExtPackedDoubleType(VT))
-      return SDValue();
+      return DAG.getNode(Opc, DL, VT, Rs1, Rs2);
 
-    bool IsSingleProduct = VT == MVT::v2i32;
-    MVT HalfVT = IsSingleProduct ? MVT::i32 : VT.getHalfNumVectorElementsVT();
-    SDValue Id = IsSingleProduct
-                     ? DAG.getTargetConstant(getRVPMulPartsForms(IntNo).Scalar,
-                                             DL, MVT::i32)
-                     : Op.getOperand(0);
-    auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Op.getOperand(1), DL);
-    auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Op.getOperand(2), DL);
-    SDValue Lo =
-        DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, HalfVT, Id, Rs1Lo, Rs2Lo);
-    SDValue Hi =
-        DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, HalfVT, Id, Rs1Hi, Rs2Hi);
-    return DAG.getNode(IsSingleProduct ? ISD::BUILD_VECTOR
-                                       : ISD::CONCAT_VECTORS,
-                       DL, VT, Lo, Hi);
+    // On RV32 a 64-bit result lives in a GPR pair; compute each half with the
+    // 32-bit form of the same product.
+    auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Rs1, DL);
+    auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Rs2, DL);
+    if (VT == MVT::v2i32) {
+      // Each half is a single product, described by the scalar intrinsic.
+      SDValue Id = DAG.getTargetConstant(getRVPScalarMulPartsIntrinsic(IntNo),
+                                         DL, MVT::i32);
+      SDValue Lo =
+          DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32, Id, Rs1Lo, Rs2Lo);
+      SDValue Hi =
+          DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32, Id, Rs1Hi, Rs2Hi);
+      return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Lo, Hi);
+    }
+    MVT HalfVT = VT.getHalfNumVectorElementsVT();
+    SDValue Lo = DAG.getNode(Opc, DL, HalfVT, Rs1Lo, Rs2Lo);
+    SDValue Hi = DAG.getNode(Opc, DL, HalfVT, Rs1Hi, Rs2Hi);
+    return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
   }
   case Intrinsic::riscv_pas:
   case Intrinsic::riscv_psa:
@@ -16978,8 +17004,8 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
                                 N->getOperand(1), Undef);
       SDValue Rs2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8,
                                 N->getOperand(2), Undef);
-      SDValue Res = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v4i16,
-                                N->getOperand(0), Rs1, Rs2);
+      SDValue Res =
+          DAG.getNode(getRVPMulHalvesOpcode(IntNo), DL, MVT::v4i16, Rs1, Rs2);
       Results.push_back(DAG.getExtractSubvector(DL, VT, Res, 0));
       return;
     }
@@ -17003,12 +17029,9 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
                                   N->getOperand(1), Undef);
         SDValue Rs2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16,
                                   N->getOperand(2), Undef);
-        SDValue Id = DAG.getTargetConstant(getRVPMulPartsForms(IntNo).Packed,
-                                           DL, MVT::i32);
         SDValue Res =
-            DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i32, Id, Rs1, Rs2);
-        Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32,
-                                      DAG.getBitcast(MVT::i64, Res)));
+            DAG.getNode(getRVPMulHalvesOpcode(IntNo), DL, MVT::v2i32, Rs1, 
Rs2);
+        Results.push_back(DAG.getExtractVectorElt(DL, MVT::i32, Res, 0));
         return;
       }
       if (Subtarget.hasStdExtP() && !Subtarget.is64Bit() && VT == MVT::i64 &&
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 79e40bacfbd40..d66754514437b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -2299,15 +2299,31 @@ let Predicates = [HasStdExtP] in {
   def : Pat<(XLenVecI16VT (riscv_ppairoe_h GPR:$rs1, GPR:$rs2)),
             (PPAIROE_H GPR:$rs1, GPR:$rs2)>;
 
-  // Packed byte multiply-parts patterns.
-  def : PatMulParts<int_riscv_pmul_00, PMUL_H_B00, XLenVecI16VT, XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmul_01, PMUL_H_B01, XLenVecI16VT, XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmul_11, PMUL_H_B11, XLenVecI16VT, XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmulu_00, PMULU_H_B00, XLenVecI16VT, 
XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmulu_01, PMULU_H_B01, XLenVecI16VT, 
XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmulu_11, PMULU_H_B11, XLenVecI16VT, 
XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmulsu_00, PMULSU_H_B00, XLenVecI16VT, 
XLenVecI8VT>;
-  def : PatMulParts<int_riscv_pmulsu_11, PMULSU_H_B11, XLenVecI16VT, 
XLenVecI8VT>;
+  // Packed byte multiply halves patterns.
+  def : Pat<(XLenVecI16VT (riscv_pmul_halves_00 (XLenVecI8VT GPR:$rs1),
+                                              (XLenVecI8VT GPR:$rs2))),
+            (PMUL_H_B00 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmul_halves_01 (XLenVecI8VT GPR:$rs1),
+                                              (XLenVecI8VT GPR:$rs2))),
+            (PMUL_H_B01 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmul_halves_11 (XLenVecI8VT GPR:$rs1),
+                                              (XLenVecI8VT GPR:$rs2))),
+            (PMUL_H_B11 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmulu_halves_00 (XLenVecI8VT GPR:$rs1),
+                                               (XLenVecI8VT GPR:$rs2))),
+            (PMULU_H_B00 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmulu_halves_01 (XLenVecI8VT GPR:$rs1),
+                                               (XLenVecI8VT GPR:$rs2))),
+            (PMULU_H_B01 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmulu_halves_11 (XLenVecI8VT GPR:$rs1),
+                                               (XLenVecI8VT GPR:$rs2))),
+            (PMULU_H_B11 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmulsu_halves_00 (XLenVecI8VT GPR:$rs1),
+                                                (XLenVecI8VT GPR:$rs2))),
+            (PMULSU_H_B00 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(XLenVecI16VT (riscv_pmulsu_halves_11 (XLenVecI8VT GPR:$rs1),
+                                                (XLenVecI8VT GPR:$rs2))),
+            (PMULSU_H_B11 GPR:$rs1, GPR:$rs2)>;
 
 let append Predicates = [IsRV32] in {
   // Scalar halfword multiply-parts patterns.
@@ -2950,16 +2966,6 @@ let append Predicates = [IsRV64] in {
   def : PatGprGpr<riscv_asub, PASUB_W, v2i32>;
   def : PatGprGpr<riscv_asubu, PASUBU_W, v2i32>;
 
-  // Packed halfword multiply-parts patterns.
-  def : PatMulParts<int_riscv_pmul_00, PMUL_W_H00, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmul_01, PMUL_W_H01, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmul_11, PMUL_W_H11, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmulu_00, PMULU_W_H00, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmulu_01, PMULU_W_H01, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmulu_11, PMULU_W_H11, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmulsu_00, PMULSU_W_H00, v2i32, v4i16>;
-  def : PatMulParts<int_riscv_pmulsu_11, PMULSU_W_H11, v2i32, v4i16>;
-
   // Scalar word multiply-parts patterns.
   def : PatMulParts<int_riscv_mul_00, MUL_W00, i64, v2i32>;
   def : PatMulParts<int_riscv_mul_01, MUL_W01, i64, v2i32>;
@@ -3004,34 +3010,22 @@ let append Predicates = [IsRV64] in {
             (PACK (MUL_W00 GPR:$rs1, GPR:$rs2), (MUL_W11 GPR:$rs1, GPR:$rs2))>;
 
   // Packed multiply halves patterns.
-  def : Pat<(v4i16 (riscv_pmul_halves_00 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMUL_H_B00 GPR:$rs1, GPR:$rs2)>;
-  def : Pat<(v4i16 (riscv_pmul_halves_01 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMUL_H_B01 GPR:$rs1, GPR:$rs2)>;
-  def : Pat<(v4i16 (riscv_pmul_halves_11 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMUL_H_B11 GPR:$rs1, GPR:$rs2)>;
-
+  def : Pat<(v2i32 (riscv_pmul_halves_00 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
+            (PMUL_W_H00 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(v2i32 (riscv_pmul_halves_01 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
             (PMUL_W_H01 GPR:$rs1, GPR:$rs2)>;
-
-  def : Pat<(v4i16 (riscv_pmulu_halves_00 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMULU_H_B00 GPR:$rs1, GPR:$rs2)>;
-  def : Pat<(v4i16 (riscv_pmulu_halves_01 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMULU_H_B01 GPR:$rs1, GPR:$rs2)>;
-  def : Pat<(v4i16 (riscv_pmulu_halves_11 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMULU_H_B11 GPR:$rs1, GPR:$rs2)>;
-
+  def : Pat<(v2i32 (riscv_pmul_halves_11 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
+            (PMUL_W_H11 GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v2i32 (riscv_pmulu_halves_00 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
+            (PMULU_W_H00 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(v2i32 (riscv_pmulu_halves_01 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
             (PMULU_W_H01 GPR:$rs1, GPR:$rs2)>;
-
-  def : Pat<(v4i16 (riscv_pmulsu_halves_00 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMULSU_H_B00 GPR:$rs1, GPR:$rs2)>;
-  def : Pat<(v4i16 (riscv_pmulsu_halves_11 (v8i8 GPR:$rs1), (v8i8 GPR:$rs2))),
-            (PMULSU_H_B11 GPR:$rs1, GPR:$rs2)>;
-
+  def : Pat<(v2i32 (riscv_pmulu_halves_11 (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
+            (PMULU_W_H11 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(v2i32 (riscv_pmulsu_halves_00 (v4i16 GPR:$rs1), (v4i16 
GPR:$rs2))),
             (PMULSU_W_H00 GPR:$rs1, GPR:$rs2)>;
-
+  def : Pat<(v2i32 (riscv_pmulsu_halves_11 (v4i16 GPR:$rs1), (v4i16 
GPR:$rs2))),
+            (PMULSU_W_H11 GPR:$rs1, GPR:$rs2)>;
   // 32-bit logical shift left/right patterns
   def : PatGprImm<riscv_pshl, PSLLI_W, uimm5, v2i32>;
   def : PatGprImm<riscv_psrl, PSRLI_W, uimm5, v2i32>;

>From d243b628035a662eba3c3e2e6349ea12b4c8157e Mon Sep 17 00:00:00 2001
From: SiHuaN <[email protected]>
Date: Fri, 28 Aug 2026 07:14:37 +0000
Subject: [PATCH 3/3] Align continuation lines of the byte multiply-halves
 patterns

---
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index d66754514437b..0590ceb16d0d3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -2301,28 +2301,28 @@ let Predicates = [HasStdExtP] in {
 
   // Packed byte multiply halves patterns.
   def : Pat<(XLenVecI16VT (riscv_pmul_halves_00 (XLenVecI8VT GPR:$rs1),
-                                              (XLenVecI8VT GPR:$rs2))),
+                                                (XLenVecI8VT GPR:$rs2))),
             (PMUL_H_B00 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmul_halves_01 (XLenVecI8VT GPR:$rs1),
-                                              (XLenVecI8VT GPR:$rs2))),
+                                                (XLenVecI8VT GPR:$rs2))),
             (PMUL_H_B01 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmul_halves_11 (XLenVecI8VT GPR:$rs1),
-                                              (XLenVecI8VT GPR:$rs2))),
+                                                (XLenVecI8VT GPR:$rs2))),
             (PMUL_H_B11 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmulu_halves_00 (XLenVecI8VT GPR:$rs1),
-                                               (XLenVecI8VT GPR:$rs2))),
+                                                 (XLenVecI8VT GPR:$rs2))),
             (PMULU_H_B00 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmulu_halves_01 (XLenVecI8VT GPR:$rs1),
-                                               (XLenVecI8VT GPR:$rs2))),
+                                                 (XLenVecI8VT GPR:$rs2))),
             (PMULU_H_B01 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmulu_halves_11 (XLenVecI8VT GPR:$rs1),
-                                               (XLenVecI8VT GPR:$rs2))),
+                                                 (XLenVecI8VT GPR:$rs2))),
             (PMULU_H_B11 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmulsu_halves_00 (XLenVecI8VT GPR:$rs1),
-                                                (XLenVecI8VT GPR:$rs2))),
+                                                  (XLenVecI8VT GPR:$rs2))),
             (PMULSU_H_B00 GPR:$rs1, GPR:$rs2)>;
   def : Pat<(XLenVecI16VT (riscv_pmulsu_halves_11 (XLenVecI8VT GPR:$rs1),
-                                                (XLenVecI8VT GPR:$rs2))),
+                                                  (XLenVecI8VT GPR:$rs2))),
             (PMULSU_H_B11 GPR:$rs1, GPR:$rs2)>;
 
 let append Predicates = [IsRV32] in {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to