https://github.com/XChy created https://github.com/llvm/llvm-project/pull/211223

None

>From cc4efb7f7329d04520d239aeb67ea56240975ab5 Mon Sep 17 00:00:00 2001
From: XChy <[email protected]>
Date: Sat, 18 Jul 2026 02:31:50 +0800
Subject: [PATCH] [RISCV][P-ext] Support Packed Multiply High

---
 clang/include/clang/Basic/BuiltinsRISCV.td    |  22 +++
 clang/lib/CodeGen/TargetBuiltins/RISCV.cpp    |  49 +++++
 clang/lib/Headers/riscv_packed_simd.h         |  29 +++
 .../riscv_packed_simd.c                       | 120 ++++++++++++
 llvm/include/llvm/IR/IntrinsicsRISCV.td       |   8 +
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  67 ++++++-
 llvm/test/CodeGen/RISCV/rvp-simd-32.ll        |  55 ++++++
 llvm/test/CodeGen/RISCV/rvp-simd-64.ll        | 181 ++++++++++++++++++
 8 files changed, 529 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td 
b/clang/include/clang/Basic/BuiltinsRISCV.td
index 3814958d81f8b..4e1eb7bc5621b 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -247,6 +247,28 @@ def pmerge_i16x4 : RISCVBuiltin<"_Vector<4, 
short>(_Vector<4, short>, _Vector<4,
 def pmerge_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned 
int>, _Vector<2, unsigned int>, _Vector<2, unsigned int>)">;
 def pmerge_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>, _Vector<2, unsigned int>)">;
 
+// Packed Multiply High (32-bit)
+def pmulh_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, 
_Vector<2, short>)">;
+def pmulhr_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, 
_Vector<2, short>)">;
+def pmulhu_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<2, 
unsigned short>, _Vector<2, unsigned short>)">;
+def pmulhru_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<2, 
unsigned short>, _Vector<2, unsigned short>)">;
+def pmulhsu_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, 
_Vector<2, unsigned short>)">;
+def pmulhrsu_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>, 
_Vector<2, unsigned short>)">;
+
+// Packed Multiply High (64-bit)
+def pmulh_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, 
_Vector<4, short>)">;
+def pmulh_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>)">;
+def pmulhr_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, 
_Vector<4, short>)">;
+def pmulhr_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>)">;
+def pmulhu_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<4, 
unsigned short>, _Vector<4, unsigned short>)">;
+def pmulhu_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned 
int>, _Vector<2, unsigned int>)">;
+def pmulhru_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<4, 
unsigned short>, _Vector<4, unsigned short>)">;
+def pmulhru_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned 
int>, _Vector<2, unsigned int>)">;
+def pmulhsu_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, 
_Vector<4, unsigned short>)">;
+def pmulhsu_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
unsigned int>)">;
+def pmulhrsu_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, 
_Vector<4, unsigned short>)">;
+def pmulhrsu_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
unsigned int>)">;
+
 // Packed Absolute Difference Sum (32-bit)
 def pabdsumu_u8x4_u32 : RISCVBuiltin<"unsigned int(_Vector<4, unsigned char>, 
_Vector<4, unsigned char>)">;
 def pabdsumau_u8x4_u32 : RISCVBuiltin<"unsigned int(unsigned int, _Vector<4, 
unsigned char>, _Vector<4, unsigned char>)">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index a3b1db1732af9..782c1ee1903d2 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1259,6 +1259,25 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
   case RISCV::BI__builtin_riscv_pmerge_i16x4:
   case RISCV::BI__builtin_riscv_pmerge_u32x2:
   case RISCV::BI__builtin_riscv_pmerge_i32x2:
+  // Packed Multiply High
+  case RISCV::BI__builtin_riscv_pmulh_i16x2:
+  case RISCV::BI__builtin_riscv_pmulh_i16x4:
+  case RISCV::BI__builtin_riscv_pmulh_i32x2:
+  case RISCV::BI__builtin_riscv_pmulhr_i16x2:
+  case RISCV::BI__builtin_riscv_pmulhr_i16x4:
+  case RISCV::BI__builtin_riscv_pmulhr_i32x2:
+  case RISCV::BI__builtin_riscv_pmulhu_u16x2:
+  case RISCV::BI__builtin_riscv_pmulhu_u16x4:
+  case RISCV::BI__builtin_riscv_pmulhu_u32x2:
+  case RISCV::BI__builtin_riscv_pmulhru_u16x2:
+  case RISCV::BI__builtin_riscv_pmulhru_u16x4:
+  case RISCV::BI__builtin_riscv_pmulhru_u32x2:
+  case RISCV::BI__builtin_riscv_pmulhsu_i16x2:
+  case RISCV::BI__builtin_riscv_pmulhsu_i16x4:
+  case RISCV::BI__builtin_riscv_pmulhsu_i32x2:
+  case RISCV::BI__builtin_riscv_pmulhrsu_i16x2:
+  case RISCV::BI__builtin_riscv_pmulhrsu_i16x4:
+  case RISCV::BI__builtin_riscv_pmulhrsu_i32x2:
   // Packed Saturating Absolute Value
   case RISCV::BI__builtin_riscv_psabs_i8x4:
   case RISCV::BI__builtin_riscv_psabs_i16x2:
@@ -1349,6 +1368,36 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
     case RISCV::BI__builtin_riscv_pmerge_i32x2:
       ID = Intrinsic::riscv_pmerge;
       break;
+    case RISCV::BI__builtin_riscv_pmulh_i16x2:
+    case RISCV::BI__builtin_riscv_pmulh_i16x4:
+    case RISCV::BI__builtin_riscv_pmulh_i32x2:
+      ID = Intrinsic::riscv_pmulh;
+      break;
+    case RISCV::BI__builtin_riscv_pmulhr_i16x2:
+    case RISCV::BI__builtin_riscv_pmulhr_i16x4:
+    case RISCV::BI__builtin_riscv_pmulhr_i32x2:
+      ID = Intrinsic::riscv_pmulhr;
+      break;
+    case RISCV::BI__builtin_riscv_pmulhu_u16x2:
+    case RISCV::BI__builtin_riscv_pmulhu_u16x4:
+    case RISCV::BI__builtin_riscv_pmulhu_u32x2:
+      ID = Intrinsic::riscv_pmulhu;
+      break;
+    case RISCV::BI__builtin_riscv_pmulhru_u16x2:
+    case RISCV::BI__builtin_riscv_pmulhru_u16x4:
+    case RISCV::BI__builtin_riscv_pmulhru_u32x2:
+      ID = Intrinsic::riscv_pmulhru;
+      break;
+    case RISCV::BI__builtin_riscv_pmulhsu_i16x2:
+    case RISCV::BI__builtin_riscv_pmulhsu_i16x4:
+    case RISCV::BI__builtin_riscv_pmulhsu_i32x2:
+      ID = Intrinsic::riscv_pmulhsu;
+      break;
+    case RISCV::BI__builtin_riscv_pmulhrsu_i16x2:
+    case RISCV::BI__builtin_riscv_pmulhrsu_i16x4:
+    case RISCV::BI__builtin_riscv_pmulhrsu_i32x2:
+      ID = Intrinsic::riscv_pmulhrsu;
+      break;
     case RISCV::BI__builtin_riscv_psabs_i8x4:
     case RISCV::BI__builtin_riscv_psabs_i16x2:
     case RISCV::BI__builtin_riscv_psabs_i8x8:
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index 7d40f046eba80..7ca98aaa21553 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -71,6 +71,12 @@ typedef uint32_t uint32x2_t 
__attribute__((__vector_size__(8)));
     return builtin(__rs1, __rs2);                                              
\
   }
 
+#define __packed_binary_builtin_mixed(name, rty, ty1, ty2, builtin)            
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty1 __rs1,           
\
+                                                          ty2 __rs2) {         
\
+    return builtin(__rs1, __rs2);                                              
\
+  }
+
 #define __packed_sh1add(name, ty)                                              
\
   static __inline__ ty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1, ty __rs2) { 
\
     return (__rs1 << 1) + __rs2;                                               
\
@@ -672,6 +678,28 @@ __packed_merge_builtin(pmerge_i16x4, int16x4_t, 
uint16x4_t, __builtin_riscv_pmer
 __packed_merge_builtin(pmerge_u32x2, uint32x2_t, uint32x2_t, 
__builtin_riscv_pmerge_u32x2)
 __packed_merge_builtin(pmerge_i32x2, int32x2_t, uint32x2_t, 
__builtin_riscv_pmerge_i32x2)
 
+/* Packed Multiply High (32-bit) */
+__packed_binary_builtin(pmulh_i16x2, int16x2_t, __builtin_riscv_pmulh_i16x2)
+__packed_binary_builtin(pmulhr_i16x2, int16x2_t, __builtin_riscv_pmulhr_i16x2)
+__packed_binary_builtin(pmulhu_u16x2, uint16x2_t, __builtin_riscv_pmulhu_u16x2)
+__packed_binary_builtin(pmulhru_u16x2, uint16x2_t, 
__builtin_riscv_pmulhru_u16x2)
+__packed_binary_builtin_mixed(pmulhsu_i16x2, int16x2_t, int16x2_t, uint16x2_t, 
__builtin_riscv_pmulhsu_i16x2)
+__packed_binary_builtin_mixed(pmulhrsu_i16x2, int16x2_t, int16x2_t, 
uint16x2_t, __builtin_riscv_pmulhrsu_i16x2)
+
+/* Packed Multiply High (64-bit) */
+__packed_binary_builtin(pmulh_i16x4, int16x4_t, __builtin_riscv_pmulh_i16x4)
+__packed_binary_builtin(pmulh_i32x2, int32x2_t, __builtin_riscv_pmulh_i32x2)
+__packed_binary_builtin(pmulhr_i16x4, int16x4_t, __builtin_riscv_pmulhr_i16x4)
+__packed_binary_builtin(pmulhr_i32x2, int32x2_t, __builtin_riscv_pmulhr_i32x2)
+__packed_binary_builtin(pmulhu_u16x4, uint16x4_t, __builtin_riscv_pmulhu_u16x4)
+__packed_binary_builtin(pmulhu_u32x2, uint32x2_t, __builtin_riscv_pmulhu_u32x2)
+__packed_binary_builtin(pmulhru_u16x4, uint16x4_t, 
__builtin_riscv_pmulhru_u16x4)
+__packed_binary_builtin(pmulhru_u32x2, uint32x2_t, 
__builtin_riscv_pmulhru_u32x2)
+__packed_binary_builtin_mixed(pmulhsu_i16x4, int16x4_t, int16x4_t, uint16x4_t, 
__builtin_riscv_pmulhsu_i16x4)
+__packed_binary_builtin_mixed(pmulhsu_i32x2, int32x2_t, int32x2_t, uint32x2_t, 
__builtin_riscv_pmulhsu_i32x2)
+__packed_binary_builtin_mixed(pmulhrsu_i16x4, int16x4_t, int16x4_t, 
uint16x4_t, __builtin_riscv_pmulhrsu_i16x4)
+__packed_binary_builtin_mixed(pmulhrsu_i32x2, int32x2_t, int32x2_t, 
uint32x2_t, __builtin_riscv_pmulhrsu_i32x2)
+
 /* Packed Absolute Difference Sum (32-bit) */
 __packed_abdsum(pabdsumu_u8x4_u32, uint32_t, uint8x4_t, 
__builtin_riscv_pabdsumu_u8x4_u32)
 __packed_abdsum_acc(pabdsumau_u8x4_u32, uint32_t, uint8x4_t, 
__builtin_riscv_pabdsumau_u8x4_u32)
@@ -794,6 +822,7 @@ __packed_reinterpret(u32x2_i32x2, int32x2_t, uint32x2_t)
 #undef __packed_binary_op
 #undef __packed_unary_op
 #undef __packed_binary_builtin
+#undef __packed_binary_builtin_mixed
 #undef __packed_sh1add
 #undef __packed_sh1sadd
 #undef __packed_cmp
diff --git a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c 
b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
index 2af196cdaadc0..fe3f56a0a6a3a 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2382,6 +2382,126 @@ int32x2_t test_pmerge_mvmn_i32x2(int32x2_t rs2, 
int32x2_t rs1, uint32x2_t rd) {
   return __riscv_pmerge_i32x2(rs1, rs2, rd);
 }
 
+// CHECK-LABEL: test_pmulh_i16x2:
+// CHECK:       pmulh.h
+int16x2_t test_pmulh_i16x2(int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pmulh_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhr_i16x2:
+// CHECK:       pmulhr.h
+int16x2_t test_pmulhr_i16x2(int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pmulhr_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhu_u16x2:
+// CHECK:       pmulhu.h
+uint16x2_t test_pmulhu_u16x2(uint16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pmulhu_u16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhru_u16x2:
+// CHECK:       pmulhru.h
+uint16x2_t test_pmulhru_u16x2(uint16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pmulhru_u16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhsu_i16x2:
+// CHECK:       pmulhsu.h
+int16x2_t test_pmulhsu_i16x2(int16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pmulhsu_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhrsu_i16x2:
+// CHECK:       pmulhrsu.h
+int16x2_t test_pmulhrsu_i16x2(int16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pmulhrsu_i16x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulh_i16x4:
+// RV32-COUNT-2: pmulh.h
+// RV64:         pmulh.h
+int16x4_t test_pmulh_i16x4(int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pmulh_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhr_i16x4:
+// RV32-COUNT-2: pmulhr.h
+// RV64:         pmulhr.h
+int16x4_t test_pmulhr_i16x4(int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pmulhr_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhu_u16x4:
+// RV32-COUNT-2: pmulhu.h
+// RV64:         pmulhu.h
+uint16x4_t test_pmulhu_u16x4(uint16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pmulhu_u16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhru_u16x4:
+// RV32-COUNT-2: pmulhru.h
+// RV64:         pmulhru.h
+uint16x4_t test_pmulhru_u16x4(uint16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pmulhru_u16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhsu_i16x4:
+// RV32-COUNT-2: pmulhsu.h
+// RV64:         pmulhsu.h
+int16x4_t test_pmulhsu_i16x4(int16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pmulhsu_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhrsu_i16x4:
+// RV32-COUNT-2: pmulhrsu.h
+// RV64:         pmulhrsu.h
+int16x4_t test_pmulhrsu_i16x4(int16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pmulhrsu_i16x4(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulh_i32x2:
+// RV32-COUNT-2: mulh
+// RV64:         pmulh.w
+int32x2_t test_pmulh_i32x2(int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pmulh_i32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhr_i32x2:
+// RV32-COUNT-2: mulhr
+// RV64:         pmulhr.w
+int32x2_t test_pmulhr_i32x2(int32x2_t rs1, int32x2_t rs2) {
+  return __riscv_pmulhr_i32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhu_u32x2:
+// RV32-COUNT-2: mulhu
+// RV64:         pmulhu.w
+uint32x2_t test_pmulhu_u32x2(uint32x2_t rs1, uint32x2_t rs2) {
+  return __riscv_pmulhu_u32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhru_u32x2:
+// RV32-COUNT-2: mulhru
+// RV64:         pmulhru.w
+uint32x2_t test_pmulhru_u32x2(uint32x2_t rs1, uint32x2_t rs2) {
+  return __riscv_pmulhru_u32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhsu_i32x2:
+// RV32-COUNT-2: mulhsu
+// RV64:         pmulhsu.w
+int32x2_t test_pmulhsu_i32x2(int32x2_t rs1, uint32x2_t rs2) {
+  return __riscv_pmulhsu_i32x2(rs1, rs2);
+}
+
+// CHECK-LABEL: test_pmulhrsu_i32x2:
+// RV32-COUNT-2: mulhrsu
+// RV64:         pmulhrsu.w
+int32x2_t test_pmulhrsu_i32x2(int32x2_t rs1, uint32x2_t rs2) {
+  return __riscv_pmulhrsu_i32x2(rs1, rs2);
+}
+
 // CHECK-LABEL: test_prev_i8x4:
 // CHECK:       rev8
 int8x4_t test_prev_i8x4(int8x4_t a) { return __riscv_prev_i8x4(a); }
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index fca28455f2117..972942f565c83 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2095,6 +2095,14 @@ class RVPBinaryIntrinsic
                             [IntrNoMem, IntrSpeculatable]>;
   def int_riscv_pmerge : RVPTernaryIntrinsic;
 
+  // Packed Multiply High.
+  def int_riscv_pmulh    : RVPBinaryIntrinsic;
+  def int_riscv_pmulhr   : RVPBinaryIntrinsic;
+  def int_riscv_pmulhu   : RVPBinaryIntrinsic;
+  def int_riscv_pmulhru  : RVPBinaryIntrinsic;
+  def int_riscv_pmulhsu  : RVPBinaryIntrinsic;
+  def int_riscv_pmulhrsu : RVPBinaryIntrinsic;
+
   // Packed Absolute Difference Sum.
   def int_riscv_pabdsumu
       : DefaultAttrsIntrinsic<[llvm_anyint_ty],
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0e33e140aaa72..521a9be84596f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -11974,6 +11974,25 @@ static unsigned getRVPShiftOpcode(Intrinsic::ID IntNo) 
{
   }
 }
 
+static unsigned getRVPMulHighOpcode(unsigned IntNo) {
+  switch (IntNo) {
+  default:
+    llvm_unreachable("Unexpected RISC-V packed multiply high intrinsic");
+  case Intrinsic::riscv_pmulh:
+    return ISD::MULHS;
+  case Intrinsic::riscv_pmulhr:
+    return RISCVISD::MULHR;
+  case Intrinsic::riscv_pmulhu:
+    return ISD::MULHU;
+  case Intrinsic::riscv_pmulhru:
+    return RISCVISD::MULHRU;
+  case Intrinsic::riscv_pmulhsu:
+    return RISCVISD::MULHSU;
+  case Intrinsic::riscv_pmulhrsu:
+    return RISCVISD::MULHRSU;
+  }
+}
+
 SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
                                                      SelectionDAG &DAG) const {
   unsigned IntNo = Op.getConstantOperandVal(0);
@@ -12175,6 +12194,44 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
     return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32, AbdsumauId, Lo,
                        Rs1Hi, Rs2Hi);
   }
+  case Intrinsic::riscv_pmulh:
+  case Intrinsic::riscv_pmulhr:
+  case Intrinsic::riscv_pmulhu:
+  case Intrinsic::riscv_pmulhru:
+  case Intrinsic::riscv_pmulhsu:
+  case Intrinsic::riscv_pmulhrsu: {
+    EVT VT = Op.getValueType();
+    unsigned Opc = getRVPMulHighOpcode(IntNo);
+
+    // RV32 has no single instruction for 64-bit packed multiply high. Split
+    // v4i16 into two v2i16 packed operations, and split v2i32 into scalar i32
+    // operations so isel can use MULH*.
+    if (!Subtarget.is64Bit() && VT == MVT::v4i16) {
+      auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Op.getOperand(1), DL);
+      auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Op.getOperand(2), DL);
+      SDValue Id = Op.getOperand(0);
+      SDValue Lo = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i16, Id,
+                               Rs1Lo, Rs2Lo);
+      SDValue Hi = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i16, Id,
+                               Rs1Hi, Rs2Hi);
+      return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
+    }
+
+    if (!Subtarget.is64Bit() && VT == MVT::v2i32) {
+      auto Extract = [&](SDValue V, unsigned Idx) {
+        return DAG.getExtractVectorElt(DL, MVT::i32, V, Idx);
+      };
+      SDValue Rs1 = Op.getOperand(1);
+      SDValue Rs2 = Op.getOperand(2);
+      SDValue Lo = DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 0),
+                               Extract(Rs2, 0));
+      SDValue Hi = DAG.getNode(Opc, DL, MVT::i32, Extract(Rs1, 1),
+                               Extract(Rs2, 1));
+      return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Lo, Hi);
+    }
+
+    return DAG.getNode(Opc, DL, VT, Op.getOperand(1), Op.getOperand(2));
+  }
   case Intrinsic::riscv_pmerge: {
     EVT VT = Op.getValueType();
     auto buildMerge = [&](SDValue Rs1, SDValue Rs2, SDValue Mask,
@@ -16204,6 +16261,12 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
     case Intrinsic::riscv_paas:
     case Intrinsic::riscv_pasa:
     case Intrinsic::riscv_pmerge:
+    case Intrinsic::riscv_pmulh:
+    case Intrinsic::riscv_pmulhr:
+    case Intrinsic::riscv_pmulhu:
+    case Intrinsic::riscv_pmulhru:
+    case Intrinsic::riscv_pmulhsu:
+    case Intrinsic::riscv_pmulhrsu:
     case Intrinsic::riscv_psabs: {
       EVT VT = N->getValueType(0);
       if (!Subtarget.is64Bit() || (VT != MVT::v4i8 && VT != MVT::v2i16))
@@ -16233,8 +16296,8 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
         Opc = RISCVISD::PSABS;
         break;
       default:
-        // pas/psa/psas/pssa/paas/pasa and pmerge: re-emit at the widened type
-        // rather than lowering to a generic node.
+        // pas/psa/psas/pssa/paas/pasa, pmerge, and pmulh*: re-emit at the
+        // widened type rather than lowering to a generic node.
         Opc = ISD::INTRINSIC_WO_CHAIN;
         break;
       }
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index a490494f7a464..cfdc0141b0e1d 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -2681,6 +2681,61 @@ define <2 x i16> @test_pmerge_mvmn_i16x2(<2 x i16> %rs2, 
<2 x i16> %rs1, <2 x i1
   ret <2 x i16> %res
 }
 
+; Packed multiply high
+define <2 x i16> @test_pmulh_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulh_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulh.h a0, a0, a1
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.pmulh.v2i16(<2 x i16> %rs1, <2 x i16> %rs2)
+  ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhr_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhr_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulhr.h a0, a0, a1
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.pmulhr.v2i16(<2 x i16> %rs1, <2 x i16> 
%rs2)
+  ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhu_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhu_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulhu.h a0, a0, a1
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.pmulhu.v2i16(<2 x i16> %rs1, <2 x i16> 
%rs2)
+  ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhru_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhru_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulhru.h a0, a0, a1
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.pmulhru.v2i16(<2 x i16> %rs1, <2 x i16> 
%rs2)
+  ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhsu_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhsu_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulhsu.h a0, a0, a1
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.pmulhsu.v2i16(<2 x i16> %rs1, <2 x i16> 
%rs2)
+  ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pmulhrsu_v2i16(<2 x i16> %rs1, <2 x i16> %rs2) {
+; CHECK-LABEL: test_pmulhrsu_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pmulhrsu.h a0, a0, a1
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.pmulhrsu.v2i16(<2 x i16> %rs1, <2 x i16> 
%rs2)
+  ret <2 x i16> %res
+}
+
 ; Packed absolute difference sum
 define i32 @test_pabdsumu_u8x4_u32(<4 x i8> %a, <4 x i8> %b) {
 ; RV32-LABEL: test_pabdsumu_u8x4_u32:
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index f49d66019458d..2eeabe8fcee10 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -5892,6 +5892,187 @@ define <2 x i32> @test_pmerge_mvmn_i32x2(<2 x i32> 
%rs2, <2 x i32> %rs1, <2 x i3
   ret <2 x i32> %res
 }
 
+; Packed multiply high
+define <4 x i16> @test_pmulh_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulh_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulh.h a1, a1, a3
+; RV32-NEXT:    pmulh.h a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulh_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulh.h a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.pmulh.v4i16(<4 x i16> %rs1, <4 x i16> %rs2)
+  ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhr_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhr_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulhr.h a1, a1, a3
+; RV32-NEXT:    pmulhr.h a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhr_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhr.h a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.pmulhr.v4i16(<4 x i16> %rs1, <4 x i16> 
%rs2)
+  ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhu_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhu_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulhu.h a1, a1, a3
+; RV32-NEXT:    pmulhu.h a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhu_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhu.h a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.pmulhu.v4i16(<4 x i16> %rs1, <4 x i16> 
%rs2)
+  ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhru_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhru_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulhru.h a1, a1, a3
+; RV32-NEXT:    pmulhru.h a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhru_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhru.h a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.pmulhru.v4i16(<4 x i16> %rs1, <4 x i16> 
%rs2)
+  ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhsu_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhsu_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulhsu.h a1, a1, a3
+; RV32-NEXT:    pmulhsu.h a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhsu_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhsu.h a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.pmulhsu.v4i16(<4 x i16> %rs1, <4 x i16> 
%rs2)
+  ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pmulhrsu_v4i16(<4 x i16> %rs1, <4 x i16> %rs2) {
+; RV32-LABEL: test_pmulhrsu_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pmulhrsu.h a1, a1, a3
+; RV32-NEXT:    pmulhrsu.h a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhrsu_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhrsu.h a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.pmulhrsu.v4i16(<4 x i16> %rs1, <4 x i16> 
%rs2)
+  ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pmulh_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulh_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulh a1, a1, a3
+; RV32-NEXT:    mulh a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulh_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulh.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <2 x i32> @llvm.riscv.pmulh.v2i32(<2 x i32> %rs1, <2 x i32> %rs2)
+  ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhr_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhr_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhr a1, a1, a3
+; RV32-NEXT:    mulhr a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhr_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhr.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <2 x i32> @llvm.riscv.pmulhr.v2i32(<2 x i32> %rs1, <2 x i32> 
%rs2)
+  ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhu_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhu_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhu a1, a1, a3
+; RV32-NEXT:    mulhu a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhu_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhu.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <2 x i32> @llvm.riscv.pmulhu.v2i32(<2 x i32> %rs1, <2 x i32> 
%rs2)
+  ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhru_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhru_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhru a1, a1, a3
+; RV32-NEXT:    mulhru a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhru_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhru.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <2 x i32> @llvm.riscv.pmulhru.v2i32(<2 x i32> %rs1, <2 x i32> 
%rs2)
+  ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhsu_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhsu_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhsu a1, a1, a3
+; RV32-NEXT:    mulhsu a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhsu_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhsu.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <2 x i32> @llvm.riscv.pmulhsu.v2i32(<2 x i32> %rs1, <2 x i32> 
%rs2)
+  ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pmulhrsu_v2i32(<2 x i32> %rs1, <2 x i32> %rs2) {
+; RV32-LABEL: test_pmulhrsu_v2i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhrsu a1, a1, a3
+; RV32-NEXT:    mulhrsu a0, a0, a2
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pmulhrsu_v2i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhrsu.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call <2 x i32> @llvm.riscv.pmulhrsu.v2i32(<2 x i32> %rs1, <2 x i32> 
%rs2)
+  ret <2 x i32> %res
+}
+
 ; Packed absolute difference sum
 define i32 @test_pabdsumu_u8x8_u32(<8 x i8> %a, <8 x i8> %b) {
 ; RV32-LABEL: test_pabdsumu_u8x8_u32:

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

Reply via email to