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
