[clang] [llvm] [RISCV][P-ext] Add scalar mqwacc/mqrwacc intrinsics (PR #234560)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 22 02:59:12 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: SiHuaN (sihuan)
<details>
<summary>Changes</summary>
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`
---
Full diff: https://github.com/llvm/llvm-project/pull/234560.diff
8 Files Affected:
- (modified) clang/include/clang/Basic/BuiltinsRISCV.td (+4)
- (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+8)
- (modified) clang/lib/Headers/riscv_packed_simd.h (+4)
- (modified) clang/test/CodeGen/RISCV/rvp-intrinsics.c (+34)
- (modified) cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c (+15)
- (modified) llvm/include/llvm/IR/IntrinsicsRISCV.td (+8)
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+27)
- (modified) llvm/test/CodeGen/RISCV/rvp-scalar.ll (+28)
``````````diff
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
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/234560
More information about the cfe-commits
mailing list