https://github.com/TelGome updated 
https://github.com/llvm/llvm-project/pull/236303

>From f03b8cd1a076a236489b2f5adcfa04b6b1335096 Mon Sep 17 00:00:00 2001
From: Dongyan Chen <[email protected]>
Date: Wed, 28 Oct 2026 02:14:25 +0000
Subject: [PATCH 1/2] [RISCV][P-ext] Support Packed Multiplication with
 Horizontal Addition and Accumulate intrinsics

Add the remaining 30 intrinsics of the "Packed Multiplication with
Horizontal Addition and Accumulate".
---
 clang/include/clang/Basic/BuiltinsRISCV.td    |  34 ++
 clang/lib/CodeGen/TargetBuiltins/RISCV.cpp    |  92 ++++
 clang/lib/Headers/riscv_packed_simd.h         |  34 ++
 clang/test/CodeGen/RISCV/rvp-intrinsics.c     | 466 ++++++++++++++++++
 .../riscv_packed_simd.c                       | 251 +++++++++-
 llvm/include/llvm/IR/IntrinsicsRISCV.td       |  13 +
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   | 208 ++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td      |  63 +++
 llvm/test/CodeGen/RISCV/rvp-simd-64.ll        | 389 +++++++++++++++
 9 files changed, 1540 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td 
b/clang/include/clang/Basic/BuiltinsRISCV.td
index 704547a6830048..5f10c8dfd49210 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -408,6 +408,40 @@ def pm4add_i16x4 : RISCVBuiltin<"int64_t(_Vector<4, 
short>, _Vector<4, short>)">
 def pm4addu_u16x4 : RISCVBuiltin<"uint64_t(_Vector<4, unsigned short>, 
_Vector<4, unsigned short>)">;
 def pm4addsu_i16x4 : RISCVBuiltin<"int64_t(_Vector<4, short>, _Vector<4, 
unsigned short>)">;
 
+// Packed Multiplication with Horizontal Addition and Accumulate (32-bit)
+def pm4adda_i8x4 : RISCVBuiltin<"int(int, _Vector<4, signed char>, _Vector<4, 
signed char>)">;
+def pm4addau_u8x4 : RISCVBuiltin<"unsigned int(unsigned int, _Vector<4, 
unsigned char>, _Vector<4, unsigned char>)">;
+def pm4addasu_i8x4 : RISCVBuiltin<"int(int, _Vector<4, signed char>, 
_Vector<4, unsigned char>)">;
+def pm2adda_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
+def pm2adda_x_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
+def pm2addau_u16x2 : RISCVBuiltin<"unsigned int(unsigned int, _Vector<2, 
unsigned short>, _Vector<2, unsigned short>)">;
+def pmq2adda_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
+def pmqr2adda_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
+def pm2suba_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
+def pm2suba_x_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
short>)">;
+def pm2addasu_i16x2 : RISCVBuiltin<"int(int, _Vector<2, short>, _Vector<2, 
unsigned short>)">;
+
+// Packed Multiplication with Horizontal Addition and Accumulate (64-bit)
+def pm2adda_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<4, 
short>, _Vector<4, short>)">;
+def pm2adda_x_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, 
_Vector<4, short>, _Vector<4, short>)">;
+def pm2addau_u16x4 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, 
unsigned int>, _Vector<4, unsigned short>, _Vector<4, unsigned short>)">;
+def pmq2adda_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<4, 
short>, _Vector<4, short>)">;
+def pmqr2adda_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, 
_Vector<4, short>, _Vector<4, short>)">;
+def pm2suba_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<4, 
short>, _Vector<4, short>)">;
+def pm2suba_x_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, 
_Vector<4, short>, _Vector<4, short>)">;
+def pm2addasu_i16x4 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, 
_Vector<4, short>, _Vector<4, unsigned short>)">;
+def pm2adda_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, _Vector<2, 
int>)">;
+def pm2adda_x_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, 
_Vector<2, int>)">;
+def pm2addau_u32x2 : RISCVBuiltin<"uint64_t(uint64_t, _Vector<2, unsigned 
int>, _Vector<2, unsigned int>)">;
+def pmq2adda_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, 
_Vector<2, int>)">;
+def pmqr2adda_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, 
_Vector<2, int>)">;
+def pm2suba_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, _Vector<2, 
int>)">;
+def pm2suba_x_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, 
_Vector<2, int>)">;
+def pm2addasu_i32x2 : RISCVBuiltin<"int64_t(int64_t, _Vector<2, int>, 
_Vector<2, unsigned int>)">;
+def pm4adda_i16x4 : RISCVBuiltin<"int64_t(int64_t, _Vector<4, short>, 
_Vector<4, short>)">;
+def pm4addau_u16x4 : RISCVBuiltin<"uint64_t(uint64_t, _Vector<4, unsigned 
short>, _Vector<4, unsigned short>)">;
+def pm4addasu_i16x4 : RISCVBuiltin<"int64_t(int64_t, _Vector<4, short>, 
_Vector<4, unsigned short>)">;
+
 // Packed Widening Multiply Accumulate
 def pwmacc_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
short>, _Vector<2, short>)">;
 def pwmaccu_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned 
int>, _Vector<2, unsigned short>, _Vector<2, unsigned short>)">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 0d6bc6c66c1a01..e61f8950b51bac 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1968,6 +1968,98 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
     break;
   }
 
+  // Packed Multiplication with Horizontal Addition and Accumulate.
+  case RISCV::BI__builtin_riscv_pm2adda_i16x2:
+  case RISCV::BI__builtin_riscv_pm2adda_i16x4:
+  case RISCV::BI__builtin_riscv_pm2adda_i32x2:
+  case RISCV::BI__builtin_riscv_pm2adda_x_i16x2:
+  case RISCV::BI__builtin_riscv_pm2adda_x_i16x4:
+  case RISCV::BI__builtin_riscv_pm2adda_x_i32x2:
+  case RISCV::BI__builtin_riscv_pm2addau_u16x2:
+  case RISCV::BI__builtin_riscv_pm2addau_u16x4:
+  case RISCV::BI__builtin_riscv_pm2addau_u32x2:
+  case RISCV::BI__builtin_riscv_pmq2adda_i16x2:
+  case RISCV::BI__builtin_riscv_pmq2adda_i16x4:
+  case RISCV::BI__builtin_riscv_pmq2adda_i32x2:
+  case RISCV::BI__builtin_riscv_pmqr2adda_i16x2:
+  case RISCV::BI__builtin_riscv_pmqr2adda_i16x4:
+  case RISCV::BI__builtin_riscv_pmqr2adda_i32x2:
+  case RISCV::BI__builtin_riscv_pm2suba_i16x2:
+  case RISCV::BI__builtin_riscv_pm2suba_i16x4:
+  case RISCV::BI__builtin_riscv_pm2suba_i32x2:
+  case RISCV::BI__builtin_riscv_pm2suba_x_i16x2:
+  case RISCV::BI__builtin_riscv_pm2suba_x_i16x4:
+  case RISCV::BI__builtin_riscv_pm2suba_x_i32x2:
+  case RISCV::BI__builtin_riscv_pm2addasu_i16x2:
+  case RISCV::BI__builtin_riscv_pm2addasu_i16x4:
+  case RISCV::BI__builtin_riscv_pm2addasu_i32x2:
+  case RISCV::BI__builtin_riscv_pm4adda_i8x4:
+  case RISCV::BI__builtin_riscv_pm4adda_i16x4:
+  case RISCV::BI__builtin_riscv_pm4addau_u8x4:
+  case RISCV::BI__builtin_riscv_pm4addau_u16x4:
+  case RISCV::BI__builtin_riscv_pm4addasu_i8x4:
+  case RISCV::BI__builtin_riscv_pm4addasu_i16x4: {
+    switch (BuiltinID) {
+    default:
+      llvm_unreachable("unexpected builtin ID");
+    case RISCV::BI__builtin_riscv_pm2adda_i16x2:
+    case RISCV::BI__builtin_riscv_pm2adda_i16x4:
+    case RISCV::BI__builtin_riscv_pm2adda_i32x2:
+      ID = Intrinsic::riscv_pm2adda;
+      break;
+    case RISCV::BI__builtin_riscv_pm2adda_x_i16x2:
+    case RISCV::BI__builtin_riscv_pm2adda_x_i16x4:
+    case RISCV::BI__builtin_riscv_pm2adda_x_i32x2:
+      ID = Intrinsic::riscv_pm2adda_x;
+      break;
+    case RISCV::BI__builtin_riscv_pm2addau_u16x2:
+    case RISCV::BI__builtin_riscv_pm2addau_u16x4:
+    case RISCV::BI__builtin_riscv_pm2addau_u32x2:
+      ID = Intrinsic::riscv_pm2addau;
+      break;
+    case RISCV::BI__builtin_riscv_pmq2adda_i16x2:
+    case RISCV::BI__builtin_riscv_pmq2adda_i16x4:
+    case RISCV::BI__builtin_riscv_pmq2adda_i32x2:
+      ID = Intrinsic::riscv_pmq2adda;
+      break;
+    case RISCV::BI__builtin_riscv_pmqr2adda_i16x2:
+    case RISCV::BI__builtin_riscv_pmqr2adda_i16x4:
+    case RISCV::BI__builtin_riscv_pmqr2adda_i32x2:
+      ID = Intrinsic::riscv_pmqr2adda;
+      break;
+    case RISCV::BI__builtin_riscv_pm2suba_i16x2:
+    case RISCV::BI__builtin_riscv_pm2suba_i16x4:
+    case RISCV::BI__builtin_riscv_pm2suba_i32x2:
+      ID = Intrinsic::riscv_pm2suba;
+      break;
+    case RISCV::BI__builtin_riscv_pm2suba_x_i16x2:
+    case RISCV::BI__builtin_riscv_pm2suba_x_i16x4:
+    case RISCV::BI__builtin_riscv_pm2suba_x_i32x2:
+      ID = Intrinsic::riscv_pm2suba_x;
+      break;
+    case RISCV::BI__builtin_riscv_pm2addasu_i16x2:
+    case RISCV::BI__builtin_riscv_pm2addasu_i16x4:
+    case RISCV::BI__builtin_riscv_pm2addasu_i32x2:
+      ID = Intrinsic::riscv_pm2addasu;
+      break;
+    case RISCV::BI__builtin_riscv_pm4adda_i8x4:
+    case RISCV::BI__builtin_riscv_pm4adda_i16x4:
+      ID = Intrinsic::riscv_pm4adda;
+      break;
+    case RISCV::BI__builtin_riscv_pm4addau_u8x4:
+    case RISCV::BI__builtin_riscv_pm4addau_u16x4:
+      ID = Intrinsic::riscv_pm4addau;
+      break;
+    case RISCV::BI__builtin_riscv_pm4addasu_i8x4:
+    case RISCV::BI__builtin_riscv_pm4addasu_i16x4:
+      ID = Intrinsic::riscv_pm4addasu;
+      break;
+    }
+
+    IntrinsicTypes = {ResultType, Ops[1]->getType()};
+    break;
+  }
+
   // Packed Reduction Sum
   case RISCV::BI__builtin_riscv_predsum_i8x4_i32:
   case RISCV::BI__builtin_riscv_predsum_i16x2_i32:
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index 89f678a63e94e6..4f3af7d39dc520 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -1220,6 +1220,20 @@ __packed_ternary_builtin_mixed(pwmacc_i32x2, int32x2_t, 
int16x2_t, int16x2_t, __
 __packed_ternary_builtin_mixed(pwmaccu_u32x2, uint32x2_t, uint16x2_t, 
uint16x2_t, __builtin_riscv_pwmaccu_u32x2)
 __packed_ternary_builtin_mixed(pwmaccsu_i32x2, int32x2_t, int16x2_t, 
uint16x2_t, __builtin_riscv_pwmaccsu_i32x2)
 
+/* Packed Multiplication with Horizontal Addition and Accumulate (32-bit) */
+__packed_ternary_builtin_mixed(pm4adda_i8x4, int32_t, int8x4_t, int8x4_t, 
__builtin_riscv_pm4adda_i8x4)
+__packed_ternary_builtin_mixed(pm4addau_u8x4, uint32_t, uint8x4_t, uint8x4_t, 
__builtin_riscv_pm4addau_u8x4)
+__packed_ternary_builtin_mixed(pm4addasu_i8x4, int32_t, int8x4_t, uint8x4_t, 
__builtin_riscv_pm4addasu_i8x4)
+__packed_ternary_builtin_mixed(pm2adda_i16x2, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_pm2adda_i16x2)
+__packed_ternary_builtin_mixed(pm2adda_x_i16x2, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_pm2adda_x_i16x2)
+__packed_ternary_builtin_mixed(pm2addau_u16x2, uint32_t, uint16x2_t, 
uint16x2_t, __builtin_riscv_pm2addau_u16x2)
+__packed_ternary_builtin_mixed(pmq2adda_i16x2, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_pmq2adda_i16x2)
+__packed_ternary_builtin_mixed(pmqr2adda_i16x2, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_pmqr2adda_i16x2)
+__packed_ternary_builtin_mixed(pm2suba_i16x2, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_pm2suba_i16x2)
+__packed_ternary_builtin_mixed(pm2suba_x_i16x2, int32_t, int16x2_t, int16x2_t, 
__builtin_riscv_pm2suba_x_i16x2)
+__packed_ternary_builtin_mixed(pm2addasu_i16x2, int32_t, int16x2_t, 
uint16x2_t, __builtin_riscv_pm2addasu_i16x2)
+
+
   /* Packed Multiplication with Horizontal Addition and Accumulate (64-bit) */
 static __inline__ int32x2_t __DEFAULT_FN_ATTRS
 __riscv_pm4adda_i8x8(int32x2_t __rd, int8x8_t __rs1, int8x8_t __rs2) {
@@ -1238,6 +1252,26 @@ __riscv_pm4addasu_i8x8(int32x2_t __rd, int8x8_t __rs1, 
uint8x8_t __rs2) {
                      (uint32x2_t)__riscv_pm4addsu_i8x8(__rs1, __rs2));
 }
 
+__packed_ternary_builtin_mixed(pm2adda_i16x4, int32x2_t, int16x4_t, int16x4_t, 
__builtin_riscv_pm2adda_i16x4)
+__packed_ternary_builtin_mixed(pm2adda_x_i16x4, int32x2_t, int16x4_t, 
int16x4_t, __builtin_riscv_pm2adda_x_i16x4)
+__packed_ternary_builtin_mixed(pm2addau_u16x4, uint32x2_t, uint16x4_t, 
uint16x4_t, __builtin_riscv_pm2addau_u16x4)
+__packed_ternary_builtin_mixed(pmq2adda_i16x4, int32x2_t, int16x4_t, 
int16x4_t, __builtin_riscv_pmq2adda_i16x4)
+__packed_ternary_builtin_mixed(pmqr2adda_i16x4, int32x2_t, int16x4_t, 
int16x4_t, __builtin_riscv_pmqr2adda_i16x4)
+__packed_ternary_builtin_mixed(pm2suba_i16x4, int32x2_t, int16x4_t, int16x4_t, 
__builtin_riscv_pm2suba_i16x4)
+__packed_ternary_builtin_mixed(pm2suba_x_i16x4, int32x2_t, int16x4_t, 
int16x4_t, __builtin_riscv_pm2suba_x_i16x4)
+__packed_ternary_builtin_mixed(pm2addasu_i16x4, int32x2_t, int16x4_t, 
uint16x4_t, __builtin_riscv_pm2addasu_i16x4)
+__packed_ternary_builtin_mixed(pm2adda_i32x2, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_pm2adda_i32x2)
+__packed_ternary_builtin_mixed(pm2adda_x_i32x2, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_pm2adda_x_i32x2)
+__packed_ternary_builtin_mixed(pm2addau_u32x2, uint64_t, uint32x2_t, 
uint32x2_t, __builtin_riscv_pm2addau_u32x2)
+__packed_ternary_builtin_mixed(pmq2adda_i32x2, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_pmq2adda_i32x2)
+__packed_ternary_builtin_mixed(pmqr2adda_i32x2, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_pmqr2adda_i32x2)
+__packed_ternary_builtin_mixed(pm2suba_i32x2, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_pm2suba_i32x2)
+__packed_ternary_builtin_mixed(pm2suba_x_i32x2, int64_t, int32x2_t, int32x2_t, 
__builtin_riscv_pm2suba_x_i32x2)
+__packed_ternary_builtin_mixed(pm2addasu_i32x2, int64_t, int32x2_t, 
uint32x2_t, __builtin_riscv_pm2addasu_i32x2)
+__packed_ternary_builtin_mixed(pm4adda_i16x4, int64_t, int16x4_t, int16x4_t, 
__builtin_riscv_pm4adda_i16x4)
+__packed_ternary_builtin_mixed(pm4addau_u16x4, uint64_t, uint16x4_t, 
uint16x4_t, __builtin_riscv_pm4addau_u16x4)
+__packed_ternary_builtin_mixed(pm4addasu_i16x4, int64_t, int16x4_t, 
uint16x4_t, __builtin_riscv_pm4addasu_i16x4)
+
 /* Packed Multiplication with Widening Horizontal Addition */
 __packed_binary_builtin_mixed(pm2wadd_i64, int64_t, int16x2_t, int16x2_t, 
__builtin_riscv_pm2wadd_i64)
 __packed_binary_builtin_mixed(pm2wadd_x_i64, int64_t, int16x2_t, int16x2_t, 
__builtin_riscv_pm2wadd_x_i64)
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c 
b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index 0fa253c1cba893..598db5ca5863c2 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -13026,3 +13026,469 @@ int64_t test_maccsu_w00_i64(int64_t rd, int32x2_t a, 
uint32x2_t b) {
 int64_t test_maccsu_w11_i64(int64_t rd, int32x2_t a, uint32x2_t b) {
   return __riscv_maccsu_w11_i64(rd, a, b);
 }
+
+/* Packed Multiplication with Horizontal Addition and Accumulate */
+
+// RV32-LABEL: define dso_local i32 @test_pm4adda_i8x4(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm4adda.i32.v4i8(i32 
[[RD]], <4 x i8> [[TMP0]], <4 x i8> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm4adda_i8x4(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm4adda.i32.v4i8(i32 
[[RD]], <4 x i8> [[TMP0]], <4 x i8> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm4adda_i8x4(int32_t rd, int8x4_t rs1, int8x4_t rs2) {
+  return __riscv_pm4adda_i8x4(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm4addau_u8x4(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm4addau.i32.v4i8(i32 
[[RD]], <4 x i8> [[TMP0]], <4 x i8> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm4addau_u8x4(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm4addau.i32.v4i8(i32 
[[RD]], <4 x i8> [[TMP0]], <4 x i8> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+uint32_t test_pm4addau_u8x4(uint32_t rd, uint8x4_t rs1, uint8x4_t rs2) {
+  return __riscv_pm4addau_u8x4(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm4addasu_i8x4(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm4addasu.i32.v4i8(i32 
[[RD]], <4 x i8> [[TMP0]], <4 x i8> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm4addasu_i8x4(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm4addasu.i32.v4i8(i32 
[[RD]], <4 x i8> [[TMP0]], <4 x i8> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm4addasu_i8x4(int32_t rd, int8x4_t rs1, uint8x4_t rs2) {
+  return __riscv_pm4addasu_i8x4(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm2adda_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2adda.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm2adda_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2adda.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm2adda_i16x2(int32_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pm2adda_i16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm2adda_x_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2adda.x.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm2adda_x_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2adda.x.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm2adda_x_i16x2(int32_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pm2adda_x_i16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm2addau_u16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2addau.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm2addau_u16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2addau.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+uint32_t test_pm2addau_u16x2(uint32_t rd, uint16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pm2addau_u16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pmq2adda_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pmq2adda.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pmq2adda_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pmq2adda.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pmq2adda_i16x2(int32_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pmq2adda_i16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pmqr2adda_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pmqr2adda.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pmqr2adda_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pmqr2adda.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pmqr2adda_i16x2(int32_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pmqr2adda_i16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm2suba_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2suba.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm2suba_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2suba.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm2suba_i16x2(int32_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pm2suba_i16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm2suba_x_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2suba.x.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm2suba_x_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2suba.x.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm2suba_x_i16x2(int32_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pm2suba_x_i16x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pm2addasu_i16x2(
+// RV32-SAME: i32 noundef [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2addasu.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_pm2addasu_i16x2(
+// RV64-SAME: i32 noundef signext [[RD:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.pm2addasu.i32.v2i16(i32 
[[RD]], <2 x i16> [[TMP0]], <2 x i16> [[TMP1]])
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int32_t test_pm2addasu_i16x2(int32_t rd, int16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pm2addasu_i16x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2adda_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pm2adda.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pm2adda_i16x4(int32x2_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pm2adda_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2adda_x_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pm2adda.x.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pm2adda_x_i16x4(int32x2_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pm2adda_x_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2addau_u16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pm2addau.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+uint32x2_t test_pm2addau_u16x4(uint32x2_t rd, uint16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pm2addau_u16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pmq2adda_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pmq2adda.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pmq2adda_i16x4(int32x2_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pmq2adda_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pmqr2adda_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pmqr2adda.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pmqr2adda_i16x4(int32x2_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pmqr2adda_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2suba_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pm2suba.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pm2suba_i16x4(int32x2_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pm2suba_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2suba_x_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pm2suba.x.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pm2suba_x_i16x4(int32x2_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pm2suba_x_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2addasu_i16x4(
+// CHECK-SAME: i64 noundef [[RD_COERCE:%.*]], i64 noundef [[RS1_COERCE:%.*]], 
i64 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> 
@llvm.riscv.pm2addasu.v2i32.v4i16(<2 x i32> [[TMP0]], <4 x i16> [[TMP1]], <4 x 
i16> [[TMP2]])
+// CHECK-NEXT:    [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
+// CHECK-NEXT:    ret i64 [[TMP4]]
+//
+int32x2_t test_pm2addasu_i16x4(int32x2_t rd, int16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pm2addasu_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2adda_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm2adda.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm2adda_i32x2(int64_t rd, int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pm2adda_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2adda_x_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm2adda.x.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm2adda_x_i32x2(int64_t rd, int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pm2adda_x_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2addau_u32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm2addau.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+uint64_t test_pm2addau_u32x2(uint64_t rd, uint32x2_t rs1, uint32x2_t rs2) {
+  return __riscv_pm2addau_u32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pmq2adda_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pmq2adda.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pmq2adda_i32x2(int64_t rd, int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pmq2adda_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pmqr2adda_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pmqr2adda.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pmqr2adda_i32x2(int64_t rd, int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pmqr2adda_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2suba_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm2suba.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm2suba_i32x2(int64_t rd, int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pm2suba_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2suba_x_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm2suba.x.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm2suba_x_i32x2(int64_t rd, int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pm2suba_x_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm2addasu_i32x2(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <2 x i32>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm2addasu.i64.v2i32(i64 
[[RD]], <2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm2addasu_i32x2(int64_t rd, int32x2_t rs1, uint32x2_t rs2) {
+  return __riscv_pm2addasu_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm4adda_i16x4(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm4adda.i64.v4i16(i64 
[[RD]], <4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm4adda_i16x4(int64_t rd, int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pm4adda_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm4addau_u16x4(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm4addau.i64.v4i16(i64 
[[RD]], <4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+uint64_t test_pm4addau_u16x4(uint64_t rd, uint16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pm4addau_u16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: define dso_local i64 @test_pm4addasu_i16x4(
+// CHECK-SAME: i64 noundef [[RD:%.*]], i64 noundef [[RS1_COERCE:%.*]], i64 
noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP1:%.*]] = bitcast i64 [[RS2_COERCE]] to <4 x i16>
+// CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.pm4addasu.i64.v4i16(i64 
[[RD]], <4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+// CHECK-NEXT:    ret i64 [[TMP2]]
+//
+int64_t test_pm4addasu_i16x4(int64_t rd, int16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pm4addasu_i16x4(rd, rs1, rs2);
+}
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 8ce714923c25d8..d19560c1fff471 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -4642,31 +4642,262 @@ int32x2_t test_pwmaccsu_i32x2(int32x2_t rd, int16x2_t 
rs1, uint16x2_t rs2) {
   return __riscv_pwmaccsu_i32x2(rd, rs1, rs2);
 }
 
-// Packed Byte Multiplication with Horizontal Addition and Accumulate.
+// Packed Multiplication with Horizontal Addition and Accumulate.
+// CHECK-LABEL: test_pm4adda_i8x4:
+// RV32:        pm4adda.b
+// RV64:        pm4adda.b
+int32_t test_pm4adda_i8x4(int32_t rd, int8x4_t a, int8x4_t b) {
+  return __riscv_pm4adda_i8x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2adda_i16x2:
+// RV32:        pm2adda.h
+// RV64:        pm2adda.h
+int32_t test_pm2adda_i16x2(int32_t rd, int16x2_t a, int16x2_t b) {
+  return __riscv_pm2adda_i16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2adda_x_i16x2:
+// RV32:        pm2adda.hx
+// RV64:        pm2adda.hx
+int32_t test_pm2adda_x_i16x2(int32_t rd, int16x2_t a, int16x2_t b) {
+  return __riscv_pm2adda_x_i16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm4addau_u8x4:
+// RV32:        pm4addau.b
+// RV64:        pm4addau.b
+uint32_t test_pm4addau_u8x4(uint32_t rd, uint8x4_t a, uint8x4_t b) {
+  return __riscv_pm4addau_u8x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2addau_u16x2:
+// RV32:        pm2addau.h
+// RV64:        pm2addau.h
+uint32_t test_pm2addau_u16x2(uint32_t rd, uint16x2_t a, uint16x2_t b) {
+  return __riscv_pm2addau_u16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pmq2adda_i16x2:
+// RV32:        pmq2adda.h
+// RV64:        pmq2adda.h
+int32_t test_pmq2adda_i16x2(int32_t rd, int16x2_t a, int16x2_t b) {
+  return __riscv_pmq2adda_i16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pmqr2adda_i16x2:
+// RV32:        pmqr2adda.h
+// RV64:        pmqr2adda.h
+int32_t test_pmqr2adda_i16x2(int32_t rd, int16x2_t a, int16x2_t b) {
+  return __riscv_pmqr2adda_i16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2suba_i16x2:
+// RV32:        pm2suba.h
+// RV64:        pm2suba.h
+int32_t test_pm2suba_i16x2(int32_t rd, int16x2_t a, int16x2_t b) {
+  return __riscv_pm2suba_i16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2suba_x_i16x2:
+// RV32:        pm2suba.hx
+// RV64:        pm2suba.hx
+int32_t test_pm2suba_x_i16x2(int32_t rd, int16x2_t a, int16x2_t b) {
+  return __riscv_pm2suba_x_i16x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm4addasu_i8x4:
+// RV32:        pm4addasu.b
+// RV64:        pm4addasu.b
+int32_t test_pm4addasu_i8x4(int32_t rd, int8x4_t a, uint8x4_t b) {
+  return __riscv_pm4addasu_i8x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2addasu_i16x2:
+// RV32:        pm2addasu.h
+// RV64:        pm2addasu.h
+int32_t test_pm2addasu_i16x2(int32_t rd, int16x2_t a, uint16x2_t b) {
+  return __riscv_pm2addasu_i16x2(rd, a, b);
+}
+
 // CHECK-LABEL: test_pm4adda_i8x8:
-// RV32:        pm4adda.b{{[[:space:]]}}
-// RV32:        pm4adda.b{{[[:space:]]}}
-// RV64:        pm4adda.b{{[[:space:]]}}
+// RV32:        pm4adda.b
+// RV32:        pm4adda.b
+// RV64:        pm4adda.b
 int32x2_t test_pm4adda_i8x8(int32x2_t rd, int8x8_t a, int8x8_t b) {
   return __riscv_pm4adda_i8x8(rd, a, b);
 }
 
+// CHECK-LABEL: test_pm2adda_i16x4:
+// RV32:        pm2adda.h
+// RV32:        pm2adda.h
+// RV64:        pm2adda.h
+int32x2_t test_pm2adda_i16x4(int32x2_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pm2adda_i16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2adda_x_i16x4:
+// RV32:        pm2adda.hx
+// RV32:        pm2adda.hx
+// RV64:        pm2adda.hx
+int32x2_t test_pm2adda_x_i16x4(int32x2_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pm2adda_x_i16x4(rd, a, b);
+}
+
 // CHECK-LABEL: test_pm4addau_u8x8:
-// RV32:        pm4addau.b{{[[:space:]]}}
-// RV32:        pm4addau.b{{[[:space:]]}}
-// RV64:        pm4addau.b{{[[:space:]]}}
+// RV32:        pm4addau.b
+// RV32:        pm4addau.b
+// RV64:        pm4addau.b
 uint32x2_t test_pm4addau_u8x8(uint32x2_t rd, uint8x8_t a, uint8x8_t b) {
   return __riscv_pm4addau_u8x8(rd, a, b);
 }
 
+// CHECK-LABEL: test_pm2addau_u16x4:
+// RV32:        pm2addau.h
+// RV32:        pm2addau.h
+// RV64:        pm2addau.h
+uint32x2_t test_pm2addau_u16x4(uint32x2_t rd, uint16x4_t a, uint16x4_t b) {
+  return __riscv_pm2addau_u16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pmq2adda_i16x4:
+// RV32:        pmq2adda.h
+// RV32:        pmq2adda.h
+// RV64:        pmq2adda.h
+int32x2_t test_pmq2adda_i16x4(int32x2_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pmq2adda_i16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pmqr2adda_i16x4:
+// RV32:        pmqr2adda.h
+// RV32:        pmqr2adda.h
+// RV64:        pmqr2adda.h
+int32x2_t test_pmqr2adda_i16x4(int32x2_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pmqr2adda_i16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2suba_i16x4:
+// RV32:        pm2suba.h
+// RV32:        pm2suba.h
+// RV64:        pm2suba.h
+int32x2_t test_pm2suba_i16x4(int32x2_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pm2suba_i16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2suba_x_i16x4:
+// RV32:        pm2suba.hx
+// RV32:        pm2suba.hx
+// RV64:        pm2suba.hx
+int32x2_t test_pm2suba_x_i16x4(int32x2_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pm2suba_x_i16x4(rd, a, b);
+}
+
 // CHECK-LABEL: test_pm4addasu_i8x8:
-// RV32:        pm4addasu.b{{[[:space:]]}}
-// RV32:        pm4addasu.b{{[[:space:]]}}
-// RV64:        pm4addasu.b{{[[:space:]]}}
+// RV32:        pm4addasu.b
+// RV32:        pm4addasu.b
+// RV64:        pm4addasu.b
 int32x2_t test_pm4addasu_i8x8(int32x2_t rd, int8x8_t a, uint8x8_t b) {
   return __riscv_pm4addasu_i8x8(rd, a, b);
 }
 
+// CHECK-LABEL: test_pm2addasu_i16x4:
+// RV32:        pm2addasu.h
+// RV32:        pm2addasu.h
+// RV64:        pm2addasu.h
+int32x2_t test_pm2addasu_i16x4(int32x2_t rd, int16x4_t a, uint16x4_t b) {
+  return __riscv_pm2addasu_i16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2adda_i32x2:
+// RV32:        wmacc
+// RV32:        wmacc
+// RV64:        pm2adda.w
+int64_t test_pm2adda_i32x2(int64_t rd, int32x2_t a, int32x2_t b) {
+  return __riscv_pm2adda_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2adda_x_i32x2:
+// RV32:        wmacc
+// RV32:        wmacc
+// RV64:        pm2adda.wx
+int64_t test_pm2adda_x_i32x2(int64_t rd, int32x2_t a, int32x2_t b) {
+  return __riscv_pm2adda_x_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2addau_u32x2:
+// RV32:        wmaccu
+// RV32:        wmaccu
+// RV64:        pm2addau.w
+uint64_t test_pm2addau_u32x2(uint64_t rd, uint32x2_t a, uint32x2_t b) {
+  return __riscv_pm2addau_u32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pmq2adda_i32x2:
+// RV32:        mqwacc
+// RV32:        mqwacc
+// RV64:        pmq2adda.w
+int64_t test_pmq2adda_i32x2(int64_t rd, int32x2_t a, int32x2_t b) {
+  return __riscv_pmq2adda_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2suba_i32x2:
+// RV32:        wmul
+// RV32:        wmacc
+// RV32:        subd
+// RV64:        pm2suba.w
+int64_t test_pm2suba_i32x2(int64_t rd, int32x2_t a, int32x2_t b) {
+  return __riscv_pm2suba_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2suba_x_i32x2:
+// RV32:        wmul
+// RV32:        wmacc
+// RV32:        subd
+// RV64:        pm2suba.wx
+int64_t test_pm2suba_x_i32x2(int64_t rd, int32x2_t a, int32x2_t b) {
+  return __riscv_pm2suba_x_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm2addasu_i32x2:
+// RV32:        wmaccsu
+// RV32:        wmaccsu
+// RV64:        pm2addasu.w
+int64_t test_pm2addasu_i32x2(int64_t rd, int32x2_t a, uint32x2_t b) {
+  return __riscv_pm2addasu_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pmqr2adda_i32x2:
+// RV32:        mqrwacc
+// RV32:        mqrwacc
+// RV64:        pmqr2adda.w
+int64_t test_pmqr2adda_i32x2(int64_t rd, int32x2_t a, int32x2_t b) {
+  return __riscv_pmqr2adda_i32x2(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm4adda_i16x4:
+// RV32:        pm2wadda.h
+// RV32:        pm2wadda.h
+// RV64:        pm4adda.h
+int64_t test_pm4adda_i16x4(int64_t rd, int16x4_t a, int16x4_t b) {
+  return __riscv_pm4adda_i16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm4addau_u16x4:
+// RV32:        pm2waddau.h
+// RV32:        pm2waddau.h
+// RV64:        pm4addau.h
+uint64_t test_pm4addau_u16x4(uint64_t rd, uint16x4_t a, uint16x4_t b) {
+  return __riscv_pm4addau_u16x4(rd, a, b);
+}
+
+// CHECK-LABEL: test_pm4addasu_i16x4:
+// RV32:        pm2waddasu.h
+// RV32:        pm2waddasu.h
+// RV64:        pm4addasu.h
+int64_t test_pm4addasu_i16x4(int64_t rd, int16x4_t a, uint16x4_t b) {
+  return __riscv_pm4addasu_i16x4(rd, a, b);
+}
+
 // Packed Multiplication with Widening Horizontal Addition.
 // CHECK-LABEL: test_pm2wadd_i64:
 // RV32:        pm2wadd.h
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 397f0f4efa9b67..d23af8c42340b2 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2348,6 +2348,19 @@ class RVPBinaryIntrinsic
   def int_riscv_pm2wsuba_x : RVPHorizontalMulAccIntrinsic;
   def int_riscv_pm2waddasu : RVPHorizontalMulAccIntrinsic;
 
+  // Packed Multiplication with Horizontal Addition and Accumulate.
+  def int_riscv_pm2adda    : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm2adda_x  : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm2addau   : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pmq2adda   : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pmqr2adda  : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm2suba    : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm2suba_x  : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm2addasu  : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm4adda    : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm4addau   : RVPHorizontalMulAccIntrinsic;
+  def int_riscv_pm4addasu  : RVPHorizontalMulAccIntrinsic;
+
   // 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 c21df65ea71d1b..329411a956deff 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12686,6 +12686,30 @@ static unsigned getRVPHorizontalMulAccOpcode(unsigned 
IntNo) {
   }
 }
 
+static unsigned getRVPMulAddAccOpcode(unsigned IntNo) {
+  switch (IntNo) {
+  default:
+    llvm_unreachable("Unexpected RISC-V packed multiplication with horizontal "
+                     "addition/subtraction accumulate intrinsic");
+  case Intrinsic::riscv_pm2adda:
+    return RISCVISD::PM2ADDA;
+  case Intrinsic::riscv_pm2adda_x:
+    return RISCVISD::PM2ADDA_X;
+  case Intrinsic::riscv_pm2addau:
+    return RISCVISD::PM2ADDAU;
+  case Intrinsic::riscv_pmq2adda:
+    return RISCVISD::PMQ2ADDA;
+  case Intrinsic::riscv_pmqr2adda:
+    return RISCVISD::PMQR2ADDA;
+  case Intrinsic::riscv_pm2suba:
+    return RISCVISD::PM2SUBA;
+  case Intrinsic::riscv_pm2suba_x:
+    return RISCVISD::PM2SUBA_X;
+  case Intrinsic::riscv_pm2addasu:
+    return RISCVISD::PM2ADDASU;
+  }
+}
+
 static SDValue lowerRV32HorizontalMul64(unsigned IntNo, SDValue Rs1,
                                         SDValue Rs2, const SDLoc &DL,
                                         SelectionDAG &DAG) {
@@ -13843,6 +13867,59 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
                           : RISCVISD::PM4ADDA;
     return DAG.getNode(AccOpc, DL, MVT::i64, Rd, A, B);
   }
+  case Intrinsic::riscv_pm2adda:
+  case Intrinsic::riscv_pm2adda_x:
+  case Intrinsic::riscv_pm2addau:
+  case Intrinsic::riscv_pmq2adda:
+  case Intrinsic::riscv_pmqr2adda:
+  case Intrinsic::riscv_pm2suba:
+  case Intrinsic::riscv_pm2suba_x:
+  case Intrinsic::riscv_pm2addasu: {
+
+    MVT VT = Op.getSimpleValueType();
+    SDValue Rd = Op.getOperand(1);
+    SDValue Rs1 = Op.getOperand(2);
+    SDValue Rs2 = Op.getOperand(3);
+    unsigned Opc = getRVPMulAddAccOpcode(IntNo);
+
+    if (VT == MVT::i32)
+      return DAG.getNode(Opc, DL, MVT::i32, Rd, Rs1, Rs2);
+
+    if (VT == MVT::v2i32) {
+      if (Subtarget.is64Bit())
+        return DAG.getNode(Opc, DL, MVT::v2i32, Rd, Rs1, Rs2);
+
+      auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Rs1, DL);
+      auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Rs2, DL);
+      SDValue RdLo = DAG.getExtractVectorElt(DL, MVT::i32, Rd, 0);
+      SDValue RdHi = DAG.getExtractVectorElt(DL, MVT::i32, Rd, 1);
+      SDValue Lo = DAG.getNode(Opc, DL, MVT::i32, RdLo, Rs1Lo, Rs2Lo);
+      SDValue Hi = DAG.getNode(Opc, DL, MVT::i32, RdHi, Rs1Hi, Rs2Hi);
+      return DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v2i32, Lo, Hi);
+    }
+
+    assert(Subtarget.is64Bit() && VT == MVT::i64 &&
+           "Unexpected packed multiply-horizontal-add-accumulate result");
+    return DAG.getNode(Opc, DL, MVT::i64, Rd, Rs1, Rs2);
+  }
+  case Intrinsic::riscv_pm4adda:
+  case Intrinsic::riscv_pm4addau:
+  case Intrinsic::riscv_pm4addasu: {
+
+    MVT VT = Op.getSimpleValueType();
+    SDValue Rd = Op.getOperand(1);
+    SDValue Rs1 = Op.getOperand(2);
+    SDValue Rs2 = Op.getOperand(3);
+    unsigned Opc = IntNo == Intrinsic::riscv_pm4addau    ? RISCVISD::PM4ADDAU
+                   : IntNo == Intrinsic::riscv_pm4addasu ? RISCVISD::PM4ADDASU
+                                                         : RISCVISD::PM4ADDA;
+
+    if (VT == MVT::i32)
+      return DAG.getNode(Opc, DL, MVT::i32, Rd, Rs1, Rs2);
+    assert(Subtarget.is64Bit() && VT == MVT::i64 &&
+           "Unexpected packed multiply-horizontal-add-accumulate result");
+    return DAG.getNode(Opc, DL, MVT::i64, Rd, Rs1, Rs2);
+  }
   case Intrinsic::riscv_pmerge: {
     EVT VT = Op.getValueType();
     auto buildMerge = [&](SDValue Rs1, SDValue Rs2, SDValue Mask,
@@ -18083,6 +18160,137 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode 
*N,
       return;
     }
 
+    case Intrinsic::riscv_pm2adda:
+    case Intrinsic::riscv_pm2adda_x:
+    case Intrinsic::riscv_pm2addau:
+    case Intrinsic::riscv_pmq2adda:
+    case Intrinsic::riscv_pmqr2adda:
+    case Intrinsic::riscv_pm2suba:
+    case Intrinsic::riscv_pm2suba_x:
+    case Intrinsic::riscv_pm2addasu: {
+
+      if (N->getSimpleValueType(0) == MVT::i32) {
+        SDValue Rd = N->getOperand(1);
+        SDValue Rs1 = N->getOperand(2);
+        SDValue Rs2 = N->getOperand(3);
+        SDValue WideRd = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, 
Rd);
+        SDValue Undef = DAG.getUNDEF(MVT::v2i16);
+        SDValue WideRs1 =
+            DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16, Rs1, Undef);
+        SDValue WideRs2 =
+            DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16, Rs2, Undef);
+        SDValue Res = DAG.getNode(getRVPMulAddAccOpcode(IntNo), DL, MVT::v2i32,
+                                  WideRd, WideRs1, WideRs2);
+        Results.push_back(DAG.getExtractVectorElt(DL, MVT::i32, Res, 0));
+        return;
+      }
+
+      assert(!Subtarget.is64Bit() && N->getSimpleValueType(0) == MVT::i64 &&
+             "Unexpected multiply-horizontal-add-accumulate legalization");
+      SDValue Rs1 = N->getOperand(2);
+      SDValue Rs2 = N->getOperand(3);
+      auto [RdLo, RdHi] =
+          DAG.SplitScalar(N->getOperand(1), DL, MVT::i32, MVT::i32);
+      SDVTList VTs = DAG.getVTList(MVT::i32, MVT::i32);
+      auto Extract = [&](SDValue V, unsigned Idx) {
+        return DAG.getExtractVectorElt(DL, MVT::i32, V, Idx);
+      };
+      SDValue Rs1Lo = Extract(Rs1, 0);
+      SDValue Rs1Hi = Extract(Rs1, 1);
+      SDValue Rs2Lo = Extract(Rs2, 0);
+      SDValue Rs2Hi = Extract(Rs2, 1);
+
+      if (IntNo == Intrinsic::riscv_pmq2adda ||
+          IntNo == Intrinsic::riscv_pmqr2adda) {
+        unsigned AccOpc = IntNo == Intrinsic::riscv_pmq2adda
+                              ? RISCVISD::MQWACC
+                              : RISCVISD::MQRWACC;
+        SDValue Acc = DAG.getNode(AccOpc, DL, VTs, {RdLo, RdHi, Rs1Lo, Rs2Lo});
+        Acc =
+            DAG.getNode(AccOpc, DL, VTs, {Acc, Acc.getValue(1), Rs1Hi, Rs2Hi});
+        Results.push_back(
+            DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Acc, Acc.getValue(1)));
+        return;
+      }
+
+      if (IntNo == Intrinsic::riscv_pm2suba ||
+          IntNo == Intrinsic::riscv_pm2suba_x) {
+        if (IntNo == Intrinsic::riscv_pm2suba_x)
+          std::swap(Rs2Lo, Rs2Hi);
+        SDValue LoMul = DAG.getNode(ISD::SMUL_LOHI, DL, VTs, Rs1Lo, Rs2Lo);
+        SDValue Acc = DAG.getNode(RISCVISD::ADDD, DL, VTs, RdLo, RdHi, LoMul,
+                                  LoMul.getValue(1));
+        SDValue HiMul = DAG.getNode(ISD::SMUL_LOHI, DL, VTs, Rs1Hi, Rs2Hi);
+        SDValue Res = DAG.getNode(RISCVISD::SUBD, DL, VTs, Acc, 
Acc.getValue(1),
+                                  HiMul, HiMul.getValue(1));
+        Results.push_back(
+            DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Res, Res.getValue(1)));
+        return;
+      }
+
+      if (IntNo == Intrinsic::riscv_pm2adda_x)
+        std::swap(Rs2Lo, Rs2Hi);
+
+      unsigned MulOpc = ISD::SMUL_LOHI;
+      if (IntNo == Intrinsic::riscv_pm2addau)
+        MulOpc = ISD::UMUL_LOHI;
+      else if (IntNo == Intrinsic::riscv_pm2addasu)
+        MulOpc = RISCVISD::WMULSU;
+
+      SDValue LoMul = DAG.getNode(MulOpc, DL, VTs, Rs1Lo, Rs2Lo);
+      SDValue Acc = DAG.getNode(RISCVISD::ADDD, DL, VTs, RdLo, RdHi, LoMul,
+                                LoMul.getValue(1));
+      SDValue HiMul = DAG.getNode(MulOpc, DL, VTs, Rs1Hi, Rs2Hi);
+      SDValue Res = DAG.getNode(RISCVISD::ADDD, DL, VTs, Acc, Acc.getValue(1),
+                                HiMul, HiMul.getValue(1));
+      Results.push_back(
+          DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Res, Res.getValue(1)));
+      return;
+    }
+
+    case Intrinsic::riscv_pm4adda:
+    case Intrinsic::riscv_pm4addau:
+    case Intrinsic::riscv_pm4addasu: {
+
+      if (N->getSimpleValueType(0) == MVT::i32) {
+        SDValue Rd = N->getOperand(1);
+        SDValue Rs1 = N->getOperand(2);
+        SDValue Rs2 = N->getOperand(3);
+        unsigned Opc = IntNo == Intrinsic::riscv_pm4addau ? RISCVISD::PM4ADDAU
+                       : IntNo == Intrinsic::riscv_pm4addasu
+                           ? RISCVISD::PM4ADDASU
+                           : RISCVISD::PM4ADDA;
+        SDValue WideRd = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, 
Rd);
+        SDValue Undef = DAG.getUNDEF(MVT::v4i8);
+        SDValue WideRs1 =
+            DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8, Rs1, Undef);
+        SDValue WideRs2 =
+            DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8, Rs2, Undef);
+        SDValue Res =
+            DAG.getNode(Opc, DL, MVT::v2i32, WideRd, WideRs1, WideRs2);
+        Results.push_back(DAG.getExtractVectorElt(DL, MVT::i32, Res, 0));
+        return;
+      }
+
+      assert(!Subtarget.is64Bit() && N->getSimpleValueType(0) == MVT::i64 &&
+             "Unexpected widening horizontal multiply-accumulate 
legalization");
+      SDValue Rs1 = N->getOperand(2);
+      SDValue Rs2 = N->getOperand(3);
+      auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Rs1, DL);
+      auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Rs2, DL);
+      auto [RdLo, RdHi] =
+          DAG.SplitScalar(N->getOperand(1), DL, MVT::i32, MVT::i32);
+      SDValue Rd = DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v2i32, RdLo, RdHi);
+      unsigned AccOpc = IntNo == Intrinsic::riscv_pm4addau ? 
RISCVISD::PM2WADDAU
+                        : IntNo == Intrinsic::riscv_pm4addasu
+                            ? RISCVISD::PM2WADDASU
+                            : RISCVISD::PM2WADDA;
+      SDValue Acc = DAG.getNode(AccOpc, DL, MVT::v2i32, Rd, Rs1Lo, Rs2Lo);
+      Acc = DAG.getNode(AccOpc, DL, MVT::v2i32, Acc, Rs1Hi, Rs2Hi);
+      Results.push_back(DAG.getBitcast(MVT::i64, Acc));
+      return;
+    }
+
     case Intrinsic::riscv_pmul_00:
     case Intrinsic::riscv_pmul_01:
     case Intrinsic::riscv_pmul_11:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 4b192a236d4148..860ab3d3fcad39 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -2095,6 +2095,19 @@ def riscv_pm4adda   : RVSDNode<"PM4ADDA", 
SDT_RISCVHorizontalMulAcc>;
 def riscv_pm4addau  : RVSDNode<"PM4ADDAU", SDT_RISCVHorizontalMulAcc>;
 def riscv_pm4addasu : RVSDNode<"PM4ADDASU", SDT_RISCVHorizontalMulAcc>;
 
+// Packed multiplication with horizontal addition and accumulate. Each node
+// is Pat'd at every width its public intrinsic is overloaded at (i32/v2i16,
+// v2i32/v4i16, and i64/v2i32), mirroring how the non-acc riscv_pm2add family
+// is itself Pat'd at all three widths.
+def riscv_pm2adda    : RVSDNode<"PM2ADDA", SDT_RISCVHorizontalMulAcc>;
+def riscv_pm2adda_x  : RVSDNode<"PM2ADDA_X", SDT_RISCVHorizontalMulAcc>;
+def riscv_pm2addau   : RVSDNode<"PM2ADDAU", SDT_RISCVHorizontalMulAcc>;
+def riscv_pmq2adda   : RVSDNode<"PMQ2ADDA", SDT_RISCVHorizontalMulAcc>;
+def riscv_pmqr2adda  : RVSDNode<"PMQR2ADDA", SDT_RISCVHorizontalMulAcc>;
+def riscv_pm2suba    : RVSDNode<"PM2SUBA", SDT_RISCVHorizontalMulAcc>;
+def riscv_pm2suba_x  : RVSDNode<"PM2SUBA_X", SDT_RISCVHorizontalMulAcc>;
+def riscv_pm2addasu  : RVSDNode<"PM2ADDASU", SDT_RISCVHorizontalMulAcc>;
+
 // "Q-format" multiplication
 def riscv_mulq  : RVSDNode<"MULQ",  SDTIntBinOp, [SDNPCommutative]>;
 def riscv_mulqr : RVSDNode<"MULQR", SDTIntBinOp, [SDNPCommutative]>;
@@ -2630,6 +2643,30 @@ let append Predicates = [IsRV32] in {
   def : PatHorizontalMulAdd<riscv_pm4add, PM4ADDA_B, i32, v4i8>;
   def : PatHorizontalMulAdd<riscv_pm4addu, PM4ADDAU_B, i32, v4i8>;
   def : PatHorizontalMulAdd<riscv_pm4addsu, PM4ADDASU_B, i32, v4i8>;
+  def : PatHorizontalMulAdd<riscv_pm2add, PM2ADDA_H, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pm2add_x, PM2ADDA_HX, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pm2addu, PM2ADDAU_H, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pmq2add, PMQ2ADDA_H, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pmqr2add, PMQR2ADDA_H, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pm2sub, PM2SUBA_H, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pm2sub_x, PM2SUBA_HX, i32, v2i16>;
+  def : PatHorizontalMulAdd<riscv_pm2addsu, PM2ADDASU_H, i32, v2i16>;
+
+  // Direct ternary-accumulate forms of the above (used by the new
+  // pm2adda/pm2suba/etc. public intrinsics at every width they're
+  // overloaded at; i32/v2i16 here, v2i32/v4i16 and i64/v2i32 further
+  // below in the RV64-only block).
+  def : PatHorizontalMulAcc<riscv_pm2adda, PM2ADDA_H, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pm2adda_x, PM2ADDA_HX, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pm2addau, PM2ADDAU_H, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pmq2adda, PMQ2ADDA_H, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pmqr2adda, PMQR2ADDA_H, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pm2suba, PM2SUBA_H, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pm2suba_x, PM2SUBA_HX, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pm2addasu, PM2ADDASU_H, i32, v2i16>;
+  def : PatHorizontalMulAcc<riscv_pm4adda, PM4ADDA_B, i32, v4i8>;
+  def : PatHorizontalMulAcc<riscv_pm4addau, PM4ADDAU_B, i32, v4i8>;
+  def : PatHorizontalMulAcc<riscv_pm4addasu, PM4ADDASU_B, i32, v4i8>;
 
   def : PatHorizontalMul<riscv_pm4add, PM4ADD_B, i32, v4i8>;
   def : PatHorizontalMul<riscv_pm2add, PM2ADD_H, i32, v2i16>;
@@ -3509,6 +3546,9 @@ let append Predicates = [IsRV64] in {
   def : PatHorizontalMulAdd<riscv_pm4add, PM4ADDA_B, v2i32, v8i8>;
   def : PatHorizontalMulAdd<riscv_pm4addu, PM4ADDAU_B, v2i32, v8i8>;
   def : PatHorizontalMulAdd<riscv_pm4addsu, PM4ADDASU_B, v2i32, v8i8>;
+  def : PatHorizontalMulAcc<riscv_pm4adda, PM4ADDA_B, v2i32, v8i8>;
+  def : PatHorizontalMulAcc<riscv_pm4addau, PM4ADDAU_B, v2i32, v8i8>;
+  def : PatHorizontalMulAcc<riscv_pm4addasu, PM4ADDASU_B, v2i32, v8i8>;
 
   def : PatHorizontalMul<riscv_pm4add, PM4ADD_B, v2i32, v8i8>;
   def : PatHorizontalMul<riscv_pm2add, PM2ADD_H, v2i32, v4i16>;
@@ -3539,6 +3579,29 @@ let append Predicates = [IsRV64] in {
   def : PatHorizontalMulAcc<riscv_pm4addau, PM4ADDAU_H, i64, v4i16>;
   def : PatHorizontalMulAcc<riscv_pm4addasu, PM4ADDASU_H, i64, v4i16>;
 
+  // Direct ternary-accumulate forms of pm2adda/pm2suba/etc. at v2i32/v4i16
+  // width (the "_i16x4" intrinsics; pm2adda.h etc. compute two independent
+  // 32-bit-group results in parallel on RV64, matching this width exactly).
+  def : PatHorizontalMulAcc<riscv_pm2adda, PM2ADDA_H, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pm2adda_x, PM2ADDA_HX, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pm2addau, PM2ADDAU_H, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pmq2adda, PMQ2ADDA_H, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pmqr2adda, PMQR2ADDA_H, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pm2suba, PM2SUBA_H, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pm2suba_x, PM2SUBA_HX, v2i32, v4i16>;
+  def : PatHorizontalMulAcc<riscv_pm2addasu, PM2ADDASU_H, v2i32, v4i16>;
+
+  // Direct ternary-accumulate forms at i64/v2i32 width (the "_i32x2"
+  // intrinsics), pairing with the W-suffixed instructions.
+  def : PatHorizontalMulAcc<riscv_pm2adda, PM2ADDA_W, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pm2adda_x, PM2ADDA_WX, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pm2addau, PM2ADDAU_W, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pmq2adda, PMQ2ADDA_W, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pmqr2adda, PMQR2ADDA_W, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pm2suba, PM2SUBA_W, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pm2suba_x, PM2SUBA_WX, i64, v2i32>;
+  def : PatHorizontalMulAcc<riscv_pm2addasu, PM2ADDASU_W, i64, v2i32>;
+
   // 8/16/32-bit multiply low patterns
   // FIXME custom lower
   def : Pat<(v8i8 (mul GPR:$rs1, GPR:$rs2)),
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 45d3e90405f4c2..fc5024a5b5f674 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -9288,3 +9288,392 @@ define <2 x i32> @test_pslidedownx_v2i32(<2 x i32> %rd, 
<2 x i32> %rs1,
   %res = bitcast i64 %res.bits to <2 x i32>
   ret <2 x i32> %res
 }
+
+; Packed Multiplication with Horizontal Addition and Accumulate.
+define i32 @test_pm4adda_v4i8_i32(i32 %rd, <4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pm4adda_v4i8_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm4adda.b a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm4adda.i32.v4i8(i32 %rd, <4 x i8> %a, <4 x i8> %b)
+  ret i32 %r
+}
+
+define i32 @test_pm4addau_v4i8_i32(i32 %rd, <4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pm4addau_v4i8_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm4addau.b a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm4addau.i32.v4i8(i32 %rd, <4 x i8> %a, <4 x i8> 
%b)
+  ret i32 %r
+}
+
+define i32 @test_pm4addasu_v4i8_i32(i32 %rd, <4 x i8> %a, <4 x i8> %b) {
+; CHECK-LABEL: test_pm4addasu_v4i8_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm4addasu.b a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm4addasu.i32.v4i8(i32 %rd, <4 x i8> %a, <4 x i8> 
%b)
+  ret i32 %r
+}
+
+define i32 @test_pm2adda_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pm2adda_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm2adda.h a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm2adda.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x i16> 
%b)
+  ret i32 %r
+}
+
+define i32 @test_pm2adda_x_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pm2adda_x_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm2adda.hx a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm2adda.x.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_pm2addau_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pm2addau_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm2addau.h a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm2addau.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_pmq2adda_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pmq2adda_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmq2adda.h a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pmq2adda.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_pmqr2adda_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pmqr2adda_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmqr2adda.h a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pmqr2adda.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_pm2suba_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pm2suba_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm2suba.h a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm2suba.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x i16> 
%b)
+  ret i32 %r
+}
+
+define i32 @test_pm2suba_x_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pm2suba_x_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm2suba.hx a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm2suba.x.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
+  ret i32 %r
+}
+
+define i32 @test_pm2addasu_v2i16_i32(i32 %rd, <2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pm2addasu_v2i16_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pm2addasu.h a0, a1, a2
+; CHECK-NEXT:    ret
+  %r = call i32 @llvm.riscv.pm2addasu.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
+  ret i32 %r
+}
+
+define <2 x i32> @test_pm2adda_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pm2adda_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2adda.h a1, a3, a5
+; RV32-NEXT:    pm2adda.h a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2adda_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2adda.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pm2adda.v2i32.v4i16(<2 x i32> %rd, <4 x i16> 
%a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pm2adda_x_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pm2adda_x_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2adda.hx a1, a3, a5
+; RV32-NEXT:    pm2adda.hx a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2adda_x_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2adda.hx a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pm2adda.x.v2i32.v4i16(<2 x i32> %rd, <4 x 
i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pm2addau_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pm2addau_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2addau.h a1, a3, a5
+; RV32-NEXT:    pm2addau.h a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2addau_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2addau.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pm2addau.v2i32.v4i16(<2 x i32> %rd, <4 x 
i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmq2adda_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pmq2adda_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmq2adda.h a1, a3, a5
+; RV32-NEXT:    pmq2adda.h a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmq2adda_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmq2adda.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmq2adda.v2i32.v4i16(<2 x i32> %rd, <4 x 
i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pmqr2adda_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pmqr2adda_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmqr2adda.h a1, a3, a5
+; RV32-NEXT:    pmqr2adda.h a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmqr2adda_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmqr2adda.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pmqr2adda.v2i32.v4i16(<2 x i32> %rd, <4 x 
i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pm2suba_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pm2suba_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2suba.h a1, a3, a5
+; RV32-NEXT:    pm2suba.h a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2suba_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2suba.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pm2suba.v2i32.v4i16(<2 x i32> %rd, <4 x i16> 
%a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pm2suba_x_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pm2suba_x_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2suba.hx a1, a3, a5
+; RV32-NEXT:    pm2suba.hx a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2suba_x_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2suba.hx a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pm2suba.x.v2i32.v4i16(<2 x i32> %rd, <4 x 
i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @test_pm2addasu_v4i16_v2i32(<2 x i32> %rd, <4 x i16> %a, <4 x 
i16> %b) {
+; RV32-LABEL: test_pm2addasu_v4i16_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2addasu.h a1, a3, a5
+; RV32-NEXT:    pm2addasu.h a0, a2, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2addasu_v4i16_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2addasu.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call <2 x i32> @llvm.riscv.pm2addasu.v2i32.v4i16(<2 x i32> %rd, <4 x 
i16> %a, <4 x i16> %b)
+  ret <2 x i32> %r
+}
+
+define i64 @test_pm2adda_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pm2adda_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmacc a0, a2, a4
+; RV32-NEXT:    wmacc a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2adda_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2adda.w a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm2adda.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x i32> 
%b)
+  ret i64 %r
+}
+
+define i64 @test_pm2adda_x_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pm2adda_x_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmacc a0, a2, a5
+; RV32-NEXT:    wmacc a0, a3, a4
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2adda_x_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2adda.wx a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm2adda.x.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_pm2addau_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pm2addau_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmaccu a0, a2, a4
+; RV32-NEXT:    wmaccu a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2addau_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2addau.w a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm2addau.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_pmq2adda_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pmq2adda_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mqwacc a0, a2, a4
+; RV32-NEXT:    mqwacc a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmq2adda_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmq2adda.w a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pmq2adda.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_pmqr2adda_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pmqr2adda_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mqrwacc a0, a2, a4
+; RV32-NEXT:    mqrwacc a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmqr2adda_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmqr2adda.w a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pmqr2adda.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_pm2suba_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pm2suba_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmacc a0, a2, a4
+; RV32-NEXT:    wmul a2, a3, a5
+; RV32-NEXT:    subd a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2suba_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2suba.w a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm2suba.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x i32> 
%b)
+  ret i64 %r
+}
+
+define i64 @test_pm2suba_x_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pm2suba_x_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmacc a0, a2, a5
+; RV32-NEXT:    wmul a2, a3, a4
+; RV32-NEXT:    subd a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2suba_x_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2suba.wx a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm2suba.x.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_pm2addasu_v2i32_i64(i64 %rd, <2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pm2addasu_v2i32_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    wmaccsu a0, a2, a4
+; RV32-NEXT:    wmaccsu a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm2addasu_v2i32_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm2addasu.w a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm2addasu.i64.v2i32(i64 %rd, <2 x i32> %a, <2 x 
i32> %b)
+  ret i64 %r
+}
+
+define i64 @test_pm4adda_v4i16_i64(i64 %rd, <4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pm4adda_v4i16_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2wadda.h a0, a2, a4
+; RV32-NEXT:    pm2wadda.h a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm4adda_v4i16_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm4adda.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm4adda.i64.v4i16(i64 %rd, <4 x i16> %a, <4 x i16> 
%b)
+  ret i64 %r
+}
+
+define i64 @test_pm4addau_v4i16_i64(i64 %rd, <4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pm4addau_v4i16_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2waddau.h a0, a2, a4
+; RV32-NEXT:    pm2waddau.h a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm4addau_v4i16_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm4addau.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm4addau.i64.v4i16(i64 %rd, <4 x i16> %a, <4 x 
i16> %b)
+  ret i64 %r
+}
+
+define i64 @test_pm4addasu_v4i16_i64(i64 %rd, <4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pm4addasu_v4i16_i64:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pm2waddasu.h a0, a2, a4
+; RV32-NEXT:    pm2waddasu.h a0, a3, a5
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pm4addasu_v4i16_i64:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pm4addasu.h a0, a1, a2
+; RV64-NEXT:    ret
+  %r = call i64 @llvm.riscv.pm4addasu.i64.v4i16(i64 %rd, <4 x i16> %a, <4 x 
i16> %b)
+  ret i64 %r
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
+; CHECK: {{.*}}

>From 0a198305e333eff4ae9f5a7df72acd2fc5594e68 Mon Sep 17 00:00:00 2001
From: Dongyan Chen <[email protected]>
Date: Fri, 30 Oct 2026 05:31:29 +0000
Subject: [PATCH 2/2] [RISCV][P-ext] Address review: drop "new" from comment,
 clarify i32 reachability

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 7 +++++--
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td    | 6 +++---
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 329411a956deff..ea202a38bddb4c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -13875,7 +13875,6 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
   case Intrinsic::riscv_pm2suba:
   case Intrinsic::riscv_pm2suba_x:
   case Intrinsic::riscv_pm2addasu: {
-
     MVT VT = Op.getSimpleValueType();
     SDValue Rd = Op.getOperand(1);
     SDValue Rs1 = Op.getOperand(2);
@@ -13905,7 +13904,6 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
   case Intrinsic::riscv_pm4adda:
   case Intrinsic::riscv_pm4addau:
   case Intrinsic::riscv_pm4addasu: {
-
     MVT VT = Op.getSimpleValueType();
     SDValue Rd = Op.getOperand(1);
     SDValue Rs1 = Op.getOperand(2);
@@ -13914,6 +13912,11 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
                    : IntNo == Intrinsic::riscv_pm4addasu ? RISCVISD::PM4ADDASU
                                                          : RISCVISD::PM4ADDA;
 
+    // i32 (the "_i8x4" width) is reachable on both RV32 and RV64: it's the
+    // XLenVT on RV32, and on RV64 ISD::INTRINSIC_WO_CHAIN is registered
+    // Custom for i32 results (see the is64Bit() setOperationAction above),
+    // so this intrinsic's i32 result still reaches LowerOperation there too
+    // -- the generic legalizer appends the ABI-required sext.w afterward.
     if (VT == MVT::i32)
       return DAG.getNode(Opc, DL, MVT::i32, Rd, Rs1, Rs2);
     assert(Subtarget.is64Bit() && VT == MVT::i64 &&
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 860ab3d3fcad39..d7a35acef64567 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -2652,10 +2652,10 @@ let append Predicates = [IsRV32] in {
   def : PatHorizontalMulAdd<riscv_pm2sub_x, PM2SUBA_HX, i32, v2i16>;
   def : PatHorizontalMulAdd<riscv_pm2addsu, PM2ADDASU_H, i32, v2i16>;
 
-  // Direct ternary-accumulate forms of the above (used by the new
+  // Direct ternary-accumulate forms of the above, used by the
   // pm2adda/pm2suba/etc. public intrinsics at every width they're
-  // overloaded at; i32/v2i16 here, v2i32/v4i16 and i64/v2i32 further
-  // below in the RV64-only block).
+  // overloaded at: i32/v2i16 here, v2i32/v4i16 and i64/v2i32 further
+  // below in the RV64-only block.
   def : PatHorizontalMulAcc<riscv_pm2adda, PM2ADDA_H, i32, v2i16>;
   def : PatHorizontalMulAcc<riscv_pm2adda_x, PM2ADDA_HX, i32, v2i16>;
   def : PatHorizontalMulAcc<riscv_pm2addau, PM2ADDAU_H, i32, v2i16>;

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

Reply via email to