https://github.com/topperc updated 
https://github.com/llvm/llvm-project/pull/225561

>From ca6adfc22355847165f70e75749855b43079befb Mon Sep 17 00:00:00 2001
From: "ZhiQiang.Fan" <[email protected]>
Date: Tue, 22 Sep 2026 15:13:14 +0800
Subject: [PATCH 1/2] [RISCV][P-ext] Add scalar multiply high intrinsics

---
 clang/include/clang/Basic/BuiltinsRISCV.td    |  8 ++
 clang/lib/CodeGen/TargetBuiltins/RISCV.cpp    | 32 +++++++
 clang/lib/Headers/riscv_packed_simd.h         | 14 +++
 clang/test/CodeGen/RISCV/rvp-intrinsics.c     | 96 +++++++++++++++++++
 .../riscv_packed_simd.c                       | 43 +++++++++
 llvm/include/llvm/IR/IntrinsicsRISCV.td       | 12 +++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   | 75 +++++++++++++++
 llvm/test/CodeGen/RISCV/rvp-simd-32.ll        | 85 ++++++++++++++++
 8 files changed, 365 insertions(+)

diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td 
b/clang/include/clang/Basic/BuiltinsRISCV.td
index ee840e45a65ba..a02c8ff47f1ff 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -247,6 +247,14 @@ 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>)">;
 
+// Scalar Multiply High
+def mulh_i32 : RISCVBuiltin<"int32_t(int32_t, int32_t)">;
+def mulhr_i32 : RISCVBuiltin<"int32_t(int32_t, int32_t)">;
+def mulhu_u32 : RISCVBuiltin<"uint32_t(uint32_t, uint32_t)">;
+def mulhru_u32 : RISCVBuiltin<"uint32_t(uint32_t, uint32_t)">;
+def mulhsu_i32 : RISCVBuiltin<"int32_t(int32_t, uint32_t)">;
+def mulhrsu_i32 : RISCVBuiltin<"int32_t(int32_t, uint32_t)">;
+
 // 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>)">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index f99a05ce673aa..edff5d6689550 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1531,6 +1531,38 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
     break;
   }
 
+  // Scalar Multiply High
+  case RISCV::BI__builtin_riscv_mulh_i32:
+  case RISCV::BI__builtin_riscv_mulhr_i32:
+  case RISCV::BI__builtin_riscv_mulhu_u32:
+  case RISCV::BI__builtin_riscv_mulhru_u32:
+  case RISCV::BI__builtin_riscv_mulhsu_i32:
+  case RISCV::BI__builtin_riscv_mulhrsu_i32: {
+    switch (BuiltinID) {
+    default:
+      llvm_unreachable("unexpected builtin ID");
+    case RISCV::BI__builtin_riscv_mulh_i32:
+      ID = Intrinsic::riscv_mulh_i32;
+      break;
+    case RISCV::BI__builtin_riscv_mulhr_i32:
+      ID = Intrinsic::riscv_mulhr_i32;
+      break;
+    case RISCV::BI__builtin_riscv_mulhu_u32:
+      ID = Intrinsic::riscv_mulhu_u32;
+      break;
+    case RISCV::BI__builtin_riscv_mulhru_u32:
+      ID = Intrinsic::riscv_mulhru_u32;
+      break;
+    case RISCV::BI__builtin_riscv_mulhsu_i32:
+      ID = Intrinsic::riscv_mulhsu_i32;
+      break;
+    case RISCV::BI__builtin_riscv_mulhrsu_i32:
+      ID = Intrinsic::riscv_mulhrsu_i32;
+      break;
+    }
+    break;
+  }
+
   // Packed Multiplication with Horizontal Addition
   case RISCV::BI__builtin_riscv_pm4add_i8x4:
   case RISCV::BI__builtin_riscv_pm4add_i8x8:
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index db6d0d37c2e8a..dacd9600d9bd2 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -400,6 +400,20 @@ __packed_pabs(abs_u32, int32_t, uint32_t)
 __packed_pabs(abs_u64, int64_t, uint64_t)
 #endif
 
+/* Scalar Multiply High */
+#define __packed_mulh_builtin(name, res_ty, ty1, ty2)                          
\
+  static __inline__ res_ty __DEFAULT_FN_ATTRS __riscv_##name(ty1 __rs1,        
\
+                                                             ty2 __rs2) {      
\
+    return __builtin_riscv_##name(__rs1, __rs2);                               
\
+  }
+__packed_mulh_builtin(mulh_i32, int32_t, int32_t, int32_t)
+__packed_mulh_builtin(mulhr_i32, int32_t, int32_t, int32_t)
+__packed_mulh_builtin(mulhu_u32, uint32_t, uint32_t, uint32_t)
+__packed_mulh_builtin(mulhru_u32, uint32_t, uint32_t, uint32_t)
+__packed_mulh_builtin(mulhsu_i32, int32_t, int32_t, uint32_t)
+__packed_mulh_builtin(mulhrsu_i32, int32_t, int32_t, uint32_t)
+#undef __packed_mulh_builtin
+
 /* Packed Splat (32-bit) */
 __packed_splat(pmv_s_u8x4, uint8x4_t, uint8_t, __packed_splat4)
 __packed_splat(pmv_s_i8x4, int8x4_t, int8_t, __packed_splat4)
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c 
b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index c6721dbeb5db8..fd4aff5f23e84 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -134,6 +134,102 @@ uint64_t test_abs_u64(int64_t a) {
 }
 #endif
 
+// RV32-LABEL: define dso_local i32 @test_mulh_i32(
+// RV32-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulh.i32(i32 [[A]], i32 
[[B]])
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_mulh_i32(
+// RV64-SAME: i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) 
#[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulh.i32(i32 [[A]], i32 
[[B]])
+// RV64-NEXT:    ret i32 [[TMP0]]
+//
+int32_t test_mulh_i32(int32_t a, int32_t b) {
+  return __riscv_mulh_i32(a, b);
+}
+
+// RV32-LABEL: define dso_local i32 @test_mulhr_i32(
+// RV32-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhr.i32(i32 [[A]], i32 
[[B]])
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_mulhr_i32(
+// RV64-SAME: i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) 
#[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhr.i32(i32 [[A]], i32 
[[B]])
+// RV64-NEXT:    ret i32 [[TMP0]]
+//
+int32_t test_mulhr_i32(int32_t a, int32_t b) {
+  return __riscv_mulhr_i32(a, b);
+}
+
+// RV32-LABEL: define dso_local i32 @test_mulhu_u32(
+// RV32-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhu.u32(i32 [[A]], i32 
[[B]])
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_mulhu_u32(
+// RV64-SAME: i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) 
#[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhu.u32(i32 [[A]], i32 
[[B]])
+// RV64-NEXT:    ret i32 [[TMP0]]
+//
+uint32_t test_mulhu_u32(uint32_t a, uint32_t b) {
+  return __riscv_mulhu_u32(a, b);
+}
+
+// RV32-LABEL: define dso_local i32 @test_mulhru_u32(
+// RV32-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhru.u32(i32 [[A]], i32 
[[B]])
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_mulhru_u32(
+// RV64-SAME: i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) 
#[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhru.u32(i32 [[A]], i32 
[[B]])
+// RV64-NEXT:    ret i32 [[TMP0]]
+//
+uint32_t test_mulhru_u32(uint32_t a, uint32_t b) {
+  return __riscv_mulhru_u32(a, b);
+}
+
+// RV32-LABEL: define dso_local i32 @test_mulhsu_i32(
+// RV32-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhsu.i32(i32 [[A]], i32 
[[B]])
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_mulhsu_i32(
+// RV64-SAME: i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) 
#[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhsu.i32(i32 [[A]], i32 
[[B]])
+// RV64-NEXT:    ret i32 [[TMP0]]
+//
+int32_t test_mulhsu_i32(int32_t a, uint32_t b) {
+  return __riscv_mulhsu_i32(a, b);
+}
+
+// RV32-LABEL: define dso_local i32 @test_mulhrsu_i32(
+// RV32-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhrsu.i32(i32 [[A]], 
i32 [[B]])
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local signext i32 @test_mulhrsu_i32(
+// RV64-SAME: i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) 
#[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.mulhrsu.i32(i32 [[A]], 
i32 [[B]])
+// RV64-NEXT:    ret i32 [[TMP0]]
+//
+int32_t test_mulhrsu_i32(int32_t a, uint32_t b) {
+  return __riscv_mulhrsu_i32(a, b);
+}
+
 /* Packed Splat (32-bit) */
 
 // RV32-LABEL: define dso_local i32 @test_pmv_s_u8x4(
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 14e64c3c3584b..5b9d03df5c72d 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2753,6 +2753,49 @@ int32x2_t test_pmerge_mvmn_i32x2(int32x2_t rs2, 
int32x2_t rs1, uint32x2_t rd) {
   return __riscv_pmerge_i32x2(rs1, rs2, rd);
 }
 
+// Scalar multiply high
+// CHECK-LABEL: test_mulh_i32:
+// RV32:        mulh
+// RV64:        pmulh.w
+int32_t test_mulh_i32(int32_t rs1, int32_t rs2) {
+  return __riscv_mulh_i32(rs1, rs2);
+}
+
+// CHECK-LABEL: test_mulhr_i32:
+// RV32:        mulhr
+// RV64:        pmulhr.w
+int32_t test_mulhr_i32(int32_t rs1, int32_t rs2) {
+  return __riscv_mulhr_i32(rs1, rs2);
+}
+
+// CHECK-LABEL: test_mulhu_u32:
+// RV32:        mulhu
+// RV64:        pmulhu.w
+uint32_t test_mulhu_u32(uint32_t rs1, uint32_t rs2) {
+  return __riscv_mulhu_u32(rs1, rs2);
+}
+
+// CHECK-LABEL: test_mulhru_u32:
+// RV32:        mulhru
+// RV64:        pmulhru.w
+uint32_t test_mulhru_u32(uint32_t rs1, uint32_t rs2) {
+  return __riscv_mulhru_u32(rs1, rs2);
+}
+
+// CHECK-LABEL: test_mulhsu_i32:
+// RV32:        mulhsu
+// RV64:        pmulhsu.w
+int32_t test_mulhsu_i32(int32_t rs1, uint32_t rs2) {
+  return __riscv_mulhsu_i32(rs1, rs2);
+}
+
+// CHECK-LABEL: test_mulhrsu_i32:
+// RV32:        mulhrsu
+// RV64:        pmulhrsu.w
+int32_t test_mulhrsu_i32(int32_t rs1, uint32_t rs2) {
+  return __riscv_mulhrsu_i32(rs1, rs2);
+}
+
 // CHECK-LABEL: test_pmulh_i16x2:
 // CHECK:       pmulh.h
 int16x2_t test_pmulh_i16x2(int16x2_t rs1, int16x2_t rs2) {
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 09399b0ea3f36..5ff4859ec5930 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2118,6 +2118,18 @@ class RVPBinaryIntrinsic
   def int_riscv_pmulhsu  : RVPBinaryIntrinsic;
   def int_riscv_pmulhrsu : RVPBinaryIntrinsic;
 
+  // Scalar Multiply High. On RV32 these map to the M-extension mulh
+  // instructions and the P-extension mulhr instructions.
+  class RVPScalarMulHighIntrinsic
+      : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty],
+                              [IntrNoMem, IntrSpeculatable]>;
+  def int_riscv_mulh_i32    : RVPScalarMulHighIntrinsic;
+  def int_riscv_mulhr_i32   : RVPScalarMulHighIntrinsic;
+  def int_riscv_mulhu_u32   : RVPScalarMulHighIntrinsic;
+  def int_riscv_mulhru_u32  : RVPScalarMulHighIntrinsic;
+  def int_riscv_mulhsu_i32  : RVPScalarMulHighIntrinsic;
+  def int_riscv_mulhrsu_i32 : RVPScalarMulHighIntrinsic;
+
   // Packed Multiply High Accumulate.
   def int_riscv_pmhacc    : RVPTernaryIntrinsic;
   def int_riscv_pmhracc   : RVPTernaryIntrinsic;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f17d9e90bfb73..d2835fd042d05 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -13177,6 +13177,39 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
 
     return DAG.getNode(Opc, DL, VT, Op.getOperand(1), Op.getOperand(2));
   }
+  case Intrinsic::riscv_mulh_i32:
+  case Intrinsic::riscv_mulhr_i32:
+  case Intrinsic::riscv_mulhu_u32:
+  case Intrinsic::riscv_mulhru_u32:
+  case Intrinsic::riscv_mulhsu_i32:
+  case Intrinsic::riscv_mulhrsu_i32: {
+    // RV32 maps the non-rounding forms onto the M extension and the rounding
+    // forms onto the scalar P instructions. RV64 goes via ReplaceNodeResults.
+    unsigned Opc;
+    switch (IntNo) {
+    default:
+      llvm_unreachable("unexpected multiply high intrinsic");
+    case Intrinsic::riscv_mulh_i32:
+      Opc = ISD::MULHS;
+      break;
+    case Intrinsic::riscv_mulhu_u32:
+      Opc = ISD::MULHU;
+      break;
+    case Intrinsic::riscv_mulhsu_i32:
+      Opc = RISCVISD::MULHSU;
+      break;
+    case Intrinsic::riscv_mulhr_i32:
+      Opc = RISCVISD::MULHR;
+      break;
+    case Intrinsic::riscv_mulhru_u32:
+      Opc = RISCVISD::MULHRU;
+      break;
+    case Intrinsic::riscv_mulhrsu_i32:
+      Opc = RISCVISD::MULHRSU;
+      break;
+    }
+    return DAG.getNode(Opc, DL, MVT::i32, Op.getOperand(1), Op.getOperand(2));
+  }
   case Intrinsic::riscv_pmhacc:
   case Intrinsic::riscv_pmhracc:
   case Intrinsic::riscv_pmhaccu:
@@ -17590,6 +17623,48 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
       Results.push_back(DAG.getExtractSubvector(DL, VT, Res, 0));
       return;
     }
+    case Intrinsic::riscv_mulh_i32:
+    case Intrinsic::riscv_mulhr_i32:
+    case Intrinsic::riscv_mulhu_u32:
+    case Intrinsic::riscv_mulhru_u32:
+    case Intrinsic::riscv_mulhsu_i32:
+    case Intrinsic::riscv_mulhrsu_i32: {
+      // RV64 has no scalar mulh instructions; reuse the packed pmulh.w
+      // family on the low words, whose element 0 is the scalar product.
+      MVT VT = N->getSimpleValueType(0);
+      if (!Subtarget.is64Bit() || VT != MVT::i32)
+        return;
+      unsigned Opc;
+      switch (IntNo) {
+      default:
+        llvm_unreachable("unexpected multiply high intrinsic");
+      case Intrinsic::riscv_mulh_i32:
+        Opc = ISD::MULHS;
+        break;
+      case Intrinsic::riscv_mulhu_u32:
+        Opc = ISD::MULHU;
+        break;
+      case Intrinsic::riscv_mulhsu_i32:
+        Opc = RISCVISD::MULHSU;
+        break;
+      case Intrinsic::riscv_mulhr_i32:
+        Opc = RISCVISD::MULHR;
+        break;
+      case Intrinsic::riscv_mulhru_u32:
+        Opc = RISCVISD::MULHRU;
+        break;
+      case Intrinsic::riscv_mulhrsu_i32:
+        Opc = RISCVISD::MULHRSU;
+        break;
+      }
+      SDValue Rd =
+          DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, N->getOperand(1));
+      SDValue Rs =
+          DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, N->getOperand(2));
+      SDValue Res = DAG.getNode(Opc, DL, MVT::v2i32, Rd, Rs);
+      Results.push_back(DAG.getExtractVectorElt(DL, MVT::i32, Res, 0));
+      return;
+    }
     case Intrinsic::riscv_pnclipp:
     case Intrinsic::riscv_pnclipup: {
       bool IsSigned = IntNo == Intrinsic::riscv_pnclipp;
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index e9e04eb6b5ebe..cb8c4dfacb524 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -3827,3 +3827,88 @@ define i32 @test_maccsu_h11_i32(i32 %rd, <2 x i16> %a, 
<2 x i16> %b) {
   %r = call i32 @llvm.riscv.maccsu.11.i32.v2i16(i32 %rd, <2 x i16> %a, <2 x 
i16> %b)
   ret i32 %r
 }
+
+; Scalar multiply high
+define i32 @test_mulh_i32(i32 %rs1, i32 %rs2) {
+; RV32-LABEL: test_mulh_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulh a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulh_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulh.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call i32 @llvm.riscv.mulh.i32(i32 %rs1, i32 %rs2)
+  ret i32 %res
+}
+
+define i32 @test_mulhr_i32(i32 %rs1, i32 %rs2) {
+; RV32-LABEL: test_mulhr_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhr a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulhr_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhr.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call i32 @llvm.riscv.mulhr.i32(i32 %rs1, i32 %rs2)
+  ret i32 %res
+}
+
+define i32 @test_mulhu_u32(i32 %rs1, i32 %rs2) {
+; RV32-LABEL: test_mulhu_u32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhu a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulhu_u32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhu.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call i32 @llvm.riscv.mulhu.u32(i32 %rs1, i32 %rs2)
+  ret i32 %res
+}
+
+define i32 @test_mulhru_u32(i32 %rs1, i32 %rs2) {
+; RV32-LABEL: test_mulhru_u32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhru a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulhru_u32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhru.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call i32 @llvm.riscv.mulhru.u32(i32 %rs1, i32 %rs2)
+  ret i32 %res
+}
+
+define i32 @test_mulhsu_i32(i32 %rs1, i32 %rs2) {
+; RV32-LABEL: test_mulhsu_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhsu a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulhsu_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhsu.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call i32 @llvm.riscv.mulhsu.i32(i32 %rs1, i32 %rs2)
+  ret i32 %res
+}
+
+define i32 @test_mulhrsu_i32(i32 %rs1, i32 %rs2) {
+; RV32-LABEL: test_mulhrsu_i32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mulhrsu a0, a0, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_mulhrsu_i32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pmulhrsu.w a0, a0, a1
+; RV64-NEXT:    ret
+  %res = call i32 @llvm.riscv.mulhrsu.i32(i32 %rs1, i32 %rs2)
+  ret i32 %res
+}

>From 685152eeec0c8de57334507daf139d1bec2d1dbd Mon Sep 17 00:00:00 2001
From: "ZhiQiang.Fan" <[email protected]>
Date: Wed, 23 Sep 2026 10:40:42 +0800
Subject: [PATCH 2/2] modify helper func

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 67 +++++++--------------
 1 file changed, 21 insertions(+), 46 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index d2835fd042d05..12f5f42900e25 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -12352,6 +12352,25 @@ static unsigned getRVPMulHighOpcode(unsigned IntNo) {
   }
 }
 
+static unsigned getRVScalarMulHighOpcode(unsigned IntNo) {
+  switch (IntNo) {
+  default:
+    llvm_unreachable("Unexpected RISC-V scalar multiply high intrinsic");
+  case Intrinsic::riscv_mulh_i32:
+    return ISD::MULHS;
+  case Intrinsic::riscv_mulhr_i32:
+    return RISCVISD::MULHR;
+  case Intrinsic::riscv_mulhu_u32:
+    return ISD::MULHU;
+  case Intrinsic::riscv_mulhru_u32:
+    return RISCVISD::MULHRU;
+  case Intrinsic::riscv_mulhsu_i32:
+    return RISCVISD::MULHSU;
+  case Intrinsic::riscv_mulhrsu_i32:
+    return RISCVISD::MULHRSU;
+  }
+}
+
 static unsigned getRVPMulHighAccumulateOpcode(unsigned IntNo) {
   switch (IntNo) {
   default:
@@ -13185,29 +13204,7 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
   case Intrinsic::riscv_mulhrsu_i32: {
     // RV32 maps the non-rounding forms onto the M extension and the rounding
     // forms onto the scalar P instructions. RV64 goes via ReplaceNodeResults.
-    unsigned Opc;
-    switch (IntNo) {
-    default:
-      llvm_unreachable("unexpected multiply high intrinsic");
-    case Intrinsic::riscv_mulh_i32:
-      Opc = ISD::MULHS;
-      break;
-    case Intrinsic::riscv_mulhu_u32:
-      Opc = ISD::MULHU;
-      break;
-    case Intrinsic::riscv_mulhsu_i32:
-      Opc = RISCVISD::MULHSU;
-      break;
-    case Intrinsic::riscv_mulhr_i32:
-      Opc = RISCVISD::MULHR;
-      break;
-    case Intrinsic::riscv_mulhru_u32:
-      Opc = RISCVISD::MULHRU;
-      break;
-    case Intrinsic::riscv_mulhrsu_i32:
-      Opc = RISCVISD::MULHRSU;
-      break;
-    }
+    unsigned Opc = getRVScalarMulHighOpcode(IntNo);
     return DAG.getNode(Opc, DL, MVT::i32, Op.getOperand(1), Op.getOperand(2));
   }
   case Intrinsic::riscv_pmhacc:
@@ -17634,29 +17631,7 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
       MVT VT = N->getSimpleValueType(0);
       if (!Subtarget.is64Bit() || VT != MVT::i32)
         return;
-      unsigned Opc;
-      switch (IntNo) {
-      default:
-        llvm_unreachable("unexpected multiply high intrinsic");
-      case Intrinsic::riscv_mulh_i32:
-        Opc = ISD::MULHS;
-        break;
-      case Intrinsic::riscv_mulhu_u32:
-        Opc = ISD::MULHU;
-        break;
-      case Intrinsic::riscv_mulhsu_i32:
-        Opc = RISCVISD::MULHSU;
-        break;
-      case Intrinsic::riscv_mulhr_i32:
-        Opc = RISCVISD::MULHR;
-        break;
-      case Intrinsic::riscv_mulhru_u32:
-        Opc = RISCVISD::MULHRU;
-        break;
-      case Intrinsic::riscv_mulhrsu_i32:
-        Opc = RISCVISD::MULHRSU;
-        break;
-      }
+      unsigned Opc = getRVScalarMulHighOpcode(IntNo);
       SDValue Rd =
           DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, N->getOperand(1));
       SDValue Rs =

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

Reply via email to