https://github.com/sihuan created https://github.com/llvm/llvm-project/pull/234560
Add the scalar "Q-format" Multiply with Widening Accumulate intrinsics from the P-extension intrinsic spec: https://github.com/riscv/riscv-p-spec/blob/master/P-ext-intrinsics.adoc#q-format-multiply-with-widening-accumulate - `__riscv_mqwacc_i64` - `__riscv_mqrwacc_i64` >From 16bd73dbd8062ad06fc1fd6f15e57f3d0fe39d36 Mon Sep 17 00:00:00 2001 From: SiHuaN <[email protected]> Date: Wed, 21 Oct 2026 05:25:51 +0000 Subject: [PATCH] [RISCV][P-ext] Add scalar mqwacc/mqrwacc intrinsics Add __riscv_mqwacc_i64 and __riscv_mqrwacc_i64. RV32 selects mqwacc/mqrwacc directly. RV64 has no mqwacc and uses mqacc.w00/mqracc.w00 on the low words. --- clang/include/clang/Basic/BuiltinsRISCV.td | 4 +++ clang/lib/CodeGen/TargetBuiltins/RISCV.cpp | 8 +++++ clang/lib/Headers/riscv_packed_simd.h | 4 +++ clang/test/CodeGen/RISCV/rvp-intrinsics.c | 34 +++++++++++++++++++ .../riscv_packed_simd.c | 15 ++++++++ llvm/include/llvm/IR/IntrinsicsRISCV.td | 8 +++++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 27 +++++++++++++++ llvm/test/CodeGen/RISCV/rvp-scalar.ll | 28 +++++++++++++++ 8 files changed, 128 insertions(+) diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td b/clang/include/clang/Basic/BuiltinsRISCV.td index 4454b14bc7519..361e6a65b54ff 100644 --- a/clang/include/clang/Basic/BuiltinsRISCV.td +++ b/clang/include/clang/Basic/BuiltinsRISCV.td @@ -299,6 +299,10 @@ def mhraccsu_i32 : RISCVBuiltin<"int32_t(int32_t, int32_t, uint32_t)">; def mulq_i32 : RISCVBuiltin<"int32_t(int32_t, int32_t)">; def mulqr_i32 : RISCVBuiltin<"int32_t(int32_t, int32_t)">; +// Scalar "Q-format" Multiply with Widening Accumulate +def mqwacc_i64 : RISCVBuiltin<"int64_t(int64_t, int32_t, int32_t)">; +def mqrwacc_i64 : RISCVBuiltin<"int64_t(int64_t, int32_t, int32_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 5a9b0e0b4a191..733e7de47a8f9 100644 --- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp @@ -1760,6 +1760,14 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, ID = Intrinsic::riscv_mulqr_i32; break; + // Scalar "Q-format" Multiply with Widening Accumulate + case RISCV::BI__builtin_riscv_mqwacc_i64: + ID = Intrinsic::riscv_mqwacc_i64; + break; + case RISCV::BI__builtin_riscv_mqrwacc_i64: + ID = Intrinsic::riscv_mqrwacc_i64; + break; + // Packed "Q-format" Multiply with Widening Accumulate case RISCV::BI__builtin_riscv_pmqwacc_i32x2: case RISCV::BI__builtin_riscv_pmqrwacc_i32x2: { diff --git a/clang/lib/Headers/riscv_packed_simd.h b/clang/lib/Headers/riscv_packed_simd.h index ef5708689331c..1f09b046c159b 100644 --- a/clang/lib/Headers/riscv_packed_simd.h +++ b/clang/lib/Headers/riscv_packed_simd.h @@ -498,6 +498,10 @@ __packed_ternary_builtin_mixed(mhraccsu_i32, int32_t, int32_t, uint32_t, __built __packed_binary_builtin(mulq_i32, int32_t, __builtin_riscv_mulq_i32) __packed_binary_builtin(mulqr_i32, int32_t, __builtin_riscv_mulqr_i32) +/* Scalar "Q-format" Multiply with Widening Accumulate */ +__packed_ternary_builtin_mixed(mqwacc_i64, int64_t, int32_t, int32_t, __builtin_riscv_mqwacc_i64) +__packed_ternary_builtin_mixed(mqrwacc_i64, int64_t, int32_t, int32_t, __builtin_riscv_mqrwacc_i64) + /* 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 74500ed9d79be..be3680406a41e 100644 --- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c +++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c @@ -584,6 +584,40 @@ int32_t test_mulqr_i32(int32_t a, int32_t b) { return __riscv_mulqr_i32(a, b); } +/* Scalar "Q-format" Multiply with Widening Accumulate */ + +// RV32-LABEL: define dso_local i64 @test_mqwacc_i64( +// RV32-SAME: i64 noundef [[RD:%.*]], i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] { +// RV32-NEXT: [[ENTRY:.*:]] +// RV32-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.mqwacc.i64(i64 [[RD]], i32 [[A]], i32 [[B]]) +// RV32-NEXT: ret i64 [[TMP0]] +// +// RV64-LABEL: define dso_local i64 @test_mqwacc_i64( +// RV64-SAME: i64 noundef [[RD:%.*]], i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) #[[ATTR0]] { +// RV64-NEXT: [[ENTRY:.*:]] +// RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.mqwacc.i64(i64 [[RD]], i32 [[A]], i32 [[B]]) +// RV64-NEXT: ret i64 [[TMP0]] +// +int64_t test_mqwacc_i64(int64_t rd, int32_t a, int32_t b) { + return __riscv_mqwacc_i64(rd, a, b); +} + +// RV32-LABEL: define dso_local i64 @test_mqrwacc_i64( +// RV32-SAME: i64 noundef [[RD:%.*]], i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] { +// RV32-NEXT: [[ENTRY:.*:]] +// RV32-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.mqrwacc.i64(i64 [[RD]], i32 [[A]], i32 [[B]]) +// RV32-NEXT: ret i64 [[TMP0]] +// +// RV64-LABEL: define dso_local i64 @test_mqrwacc_i64( +// RV64-SAME: i64 noundef [[RD:%.*]], i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]]) #[[ATTR0]] { +// RV64-NEXT: [[ENTRY:.*:]] +// RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.mqrwacc.i64(i64 [[RD]], i32 [[A]], i32 [[B]]) +// RV64-NEXT: ret i64 [[TMP0]] +// +int64_t test_mqrwacc_i64(int64_t rd, int32_t a, int32_t b) { + return __riscv_mqrwacc_i64(rd, a, b); +} + /* Packed Splat (32-bit) */ // CHECK-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 875d2de46a0b3..ceb1588f9e19c 100644 --- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c +++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c @@ -3200,6 +3200,21 @@ int32_t test_mulqr_i32(int32_t rs1, int32_t rs2) { return __riscv_mulqr_i32(rs1, rs2); } +// Scalar "Q-format" multiply with widening accumulate +// CHECK-LABEL: test_mqwacc_i64: +// RV32: mqwacc{{[[:space:]]}} +// RV64: mqacc.w00 +int64_t test_mqwacc_i64(int64_t rd, int32_t rs1, int32_t rs2) { + return __riscv_mqwacc_i64(rd, rs1, rs2); +} + +// CHECK-LABEL: test_mqrwacc_i64: +// RV32: mqrwacc{{[[:space:]]}} +// RV64: mqracc.w00 +int64_t test_mqrwacc_i64(int64_t rd, int32_t rs1, int32_t rs2) { + return __riscv_mqrwacc_i64(rd, 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 171c2afe6d8aa..528d2cbe6261a 100644 --- a/llvm/include/llvm/IR/IntrinsicsRISCV.td +++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td @@ -2211,6 +2211,14 @@ class RVPBinaryIntrinsic def int_riscv_mulq_i32 : RVPScalarBinaryIntrinsic; def int_riscv_mulqr_i32 : RVPScalarBinaryIntrinsic; + // Scalar "Q-format" Multiply with Widening Accumulate. + class RVPScalarQFormatWideningAccIntrinsic + : DefaultAttrsIntrinsic<[llvm_i64_ty], + [llvm_i64_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrSpeculatable]>; + def int_riscv_mqwacc_i64 : RVPScalarQFormatWideningAccIntrinsic; + def int_riscv_mqrwacc_i64 : RVPScalarQFormatWideningAccIntrinsic; + // 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 5aaa11a9b0474..86077a47286d1 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -13450,6 +13450,18 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, unsigned Opc = getRVScalarQFormatMulOpcode(IntNo); return DAG.getNode(Opc, DL, MVT::i32, Op.getOperand(1), Op.getOperand(2)); } + case Intrinsic::riscv_mqwacc_i64: + case Intrinsic::riscv_mqrwacc_i64: { + // RV32 goes via ReplaceNodeResults. RV64 uses mqacc.w00 on the low words. + unsigned Opc = IntNo == Intrinsic::riscv_mqwacc_i64 + ? RISCVISD::MQACC_HALVES_00 + : RISCVISD::MQRACC_HALVES_00; + SDValue Rs1 = + DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, Op.getOperand(2)); + SDValue Rs2 = + DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i32, Op.getOperand(3)); + return DAG.getNode(Opc, DL, MVT::i64, Op.getOperand(1), Rs1, Rs2); + } case Intrinsic::riscv_pmhacc: case Intrinsic::riscv_pmhracc: case Intrinsic::riscv_pmhaccu: @@ -18255,6 +18267,21 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, Results.push_back(DAG.getExtractVectorElt(DL, MVT::i32, Res, 0)); return; } + case Intrinsic::riscv_mqwacc_i64: + case Intrinsic::riscv_mqrwacc_i64: { + if (Subtarget.is64Bit()) + return; + unsigned Opc = IntNo == Intrinsic::riscv_mqwacc_i64 ? RISCVISD::MQWACC + : RISCVISD::MQRWACC; + auto [RdLo, RdHi] = + DAG.SplitScalar(N->getOperand(1), DL, MVT::i32, MVT::i32); + SDValue Acc = + DAG.getNode(Opc, DL, DAG.getVTList(MVT::i32, MVT::i32), + {RdLo, RdHi, N->getOperand(2), N->getOperand(3)}); + Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, + Acc.getValue(0), Acc.getValue(1))); + return; + } case Intrinsic::riscv_pnclipp: case Intrinsic::riscv_pnclipup: { bool IsSigned = IntNo == Intrinsic::riscv_pnclipp; diff --git a/llvm/test/CodeGen/RISCV/rvp-scalar.ll b/llvm/test/CodeGen/RISCV/rvp-scalar.ll index 6fab93896d7dc..9000b119865a9 100644 --- a/llvm/test/CodeGen/RISCV/rvp-scalar.ll +++ b/llvm/test/CodeGen/RISCV/rvp-scalar.ll @@ -3824,3 +3824,31 @@ define i32 @test_mulqr_i32(i32 %a, i32 %b) { %res = call i32 @llvm.riscv.mulqr.i32(i32 %a, i32 %b) ret i32 %res } + +define i64 @test_mqwacc_i64(i64 %rd, i32 %a, i32 %b) { +; RV32-LABEL: test_mqwacc_i64: +; RV32: # %bb.0: +; RV32-NEXT: mqwacc a0, a2, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mqwacc_i64: +; RV64: # %bb.0: +; RV64-NEXT: mqacc.w00 a0, a1, a2 +; RV64-NEXT: ret + %res = call i64 @llvm.riscv.mqwacc.i64(i64 %rd, i32 %a, i32 %b) + ret i64 %res +} + +define i64 @test_mqrwacc_i64(i64 %rd, i32 %a, i32 %b) { +; RV32-LABEL: test_mqrwacc_i64: +; RV32: # %bb.0: +; RV32-NEXT: mqrwacc a0, a2, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mqrwacc_i64: +; RV64: # %bb.0: +; RV64-NEXT: mqracc.w00 a0, a1, a2 +; RV64-NEXT: ret + %res = call i64 @llvm.riscv.mqrwacc.i64(i64 %rd, i32 %a, i32 %b) + ret i64 %res +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
