llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-x86 Author: 陈子昂 (Michael-Chen-NJU) <details> <summary>Changes</summary> Add Clang header intrinsics for the RISC-V P-extension packed widening add accumulate operations: - __riscv_pwadda_i16x4 - __riscv_pwadda_i32x2 - __riscv_pwaddau_u16x4 - __riscv_pwaddau_u32x2 The header wrappers use generic LLVM IR. RV32 selects the direct `pwadda.*` / `pwaddau.*` instructions. RV64 lowers the generic IR to the decomposition specified by the P-extension intrinsic spec, including `zip16p + pli.h + pm2adda.h/pm2addau.h` for the halfword forms. --- Patch is 20.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/221622.diff 6 Files Affected: - (modified) clang/lib/Headers/riscv_packed_simd.h (+13) - (modified) clang/test/CodeGen/RISCV/rvp-intrinsics.c (+122) - (modified) cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c (+39) - (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+82) - (modified) llvm/lib/Target/RISCV/RISCVInstrInfoP.td (+24) - (added) llvm/test/CodeGen/RISCV/rvp-widening-add-acc.ll (+86) ``````````diff diff --git a/clang/lib/Headers/riscv_packed_simd.h b/clang/lib/Headers/riscv_packed_simd.h index bb0e7624a50e9..757026443d485 100644 --- a/clang/lib/Headers/riscv_packed_simd.h +++ b/clang/lib/Headers/riscv_packed_simd.h @@ -148,6 +148,12 @@ typedef uint32_t uint32x2_t __attribute__((__vector_size__(8))); return __builtin_convertvector(__rs1, rty) \ op __builtin_convertvector(__rs2, rty); \ } +#define __packed_widen_binary_acc_op(name, rty, ty, op) \ + static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(rty __rd, ty __rs1, \ + ty __rs2) { \ + return __rd op __builtin_convertvector(__rs1, rty) \ + op __builtin_convertvector(__rs2, rty); \ + } #define __packed_widen_mul(name, rty, ty) \ static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1, \ ty __rs2) { \ @@ -620,6 +626,12 @@ __packed_widen_binary_op(pwsub_i32x2, int32x2_t, int16x2_t, -) __packed_widen_binary_op(pwsubu_u16x4, uint16x4_t, uint8x4_t, -) __packed_widen_binary_op(pwsubu_u32x2, uint32x2_t, uint16x2_t, -) +/* Packed Widening Addition Accumulate */ +__packed_widen_binary_acc_op(pwadda_i16x4, int16x4_t, int8x4_t, +) +__packed_widen_binary_acc_op(pwadda_i32x2, int32x2_t, int16x2_t, +) +__packed_widen_binary_acc_op(pwaddau_u16x4, uint16x4_t, uint8x4_t, +) +__packed_widen_binary_acc_op(pwaddau_u32x2, uint32x2_t, uint16x2_t, +) + /* Packed Widening Multiply (32-bit) */ __packed_widen_mul(pwmul_i16x4, int16x4_t, int8x4_t) __packed_widen_mul(pwmul_i32x2, int32x2_t, int16x2_t) @@ -1106,6 +1118,7 @@ __packed_reinterpret(u32x2_i32x2, int32x2_t, uint32x2_t) #undef __packed_unary_builtin #undef __packed_widen_convert #undef __packed_widen_binary_op +#undef __packed_widen_binary_acc_op #undef __packed_widen_mul #undef __packed_widen_mulsu #undef __packed_widen_high2 diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c b/clang/test/CodeGen/RISCV/rvp-intrinsics.c index 9453a07e89ce7..c3a2380466928 100644 --- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c +++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c @@ -8136,6 +8136,128 @@ uint32x2_t test_pwaddu_u32x2(uint16x2_t rs1, uint16x2_t rs2) { return __riscv_pwaddu_u32x2(rs1, rs2); } +// RV32-LABEL: define dso_local i64 @test_pwadda_i16x4( +// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV32-NEXT: [[ENTRY:.*:]] +// RV32-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16> +// RV32-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8> +// RV32-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8> +// RV32-NEXT: [[CONV_I:%.*]] = sext <4 x i8> [[TMP1]] to <4 x i16> +// RV32-NEXT: [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]] +// RV32-NEXT: [[CONV4_I:%.*]] = sext <4 x i8> [[TMP2]] to <4 x i16> +// RV32-NEXT: [[ADD5_I:%.*]] = add <4 x i16> [[ADD_I]], [[CONV4_I]] +// RV32-NEXT: [[TMP3:%.*]] = bitcast <4 x i16> [[ADD5_I]] to i64 +// RV32-NEXT: ret i64 [[TMP3]] +// +// RV64-LABEL: define dso_local i64 @test_pwadda_i16x4( +// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV64-NEXT: [[ENTRY:.*:]] +// RV64-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16> +// RV64-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8> +// RV64-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8> +// RV64-NEXT: [[CONV_I:%.*]] = sext <4 x i8> [[TMP1]] to <4 x i16> +// RV64-NEXT: [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]] +// RV64-NEXT: [[CONV4_I:%.*]] = sext <4 x i8> [[TMP2]] to <4 x i16> +// RV64-NEXT: [[ADD5_I:%.*]] = add <4 x i16> [[ADD_I]], [[CONV4_I]] +// RV64-NEXT: [[TMP3:%.*]] = bitcast <4 x i16> [[ADD5_I]] to i64 +// RV64-NEXT: ret i64 [[TMP3]] +// +int16x4_t test_pwadda_i16x4(int16x4_t rd, int8x4_t rs1, int8x4_t rs2) { + return __riscv_pwadda_i16x4(rd, rs1, rs2); +} + +// RV32-LABEL: define dso_local i64 @test_pwadda_i32x2( +// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV32-NEXT: [[ENTRY:.*:]] +// RV32-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32> +// RV32-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16> +// RV32-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16> +// RV32-NEXT: [[CONV_I:%.*]] = sext <2 x i16> [[TMP1]] to <2 x i32> +// RV32-NEXT: [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]] +// RV32-NEXT: [[CONV4_I:%.*]] = sext <2 x i16> [[TMP2]] to <2 x i32> +// RV32-NEXT: [[ADD5_I:%.*]] = add <2 x i32> [[ADD_I]], [[CONV4_I]] +// RV32-NEXT: [[TMP3:%.*]] = bitcast <2 x i32> [[ADD5_I]] to i64 +// RV32-NEXT: ret i64 [[TMP3]] +// +// RV64-LABEL: define dso_local i64 @test_pwadda_i32x2( +// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV64-NEXT: [[ENTRY:.*:]] +// RV64-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32> +// RV64-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16> +// RV64-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16> +// RV64-NEXT: [[CONV_I:%.*]] = sext <2 x i16> [[TMP1]] to <2 x i32> +// RV64-NEXT: [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]] +// RV64-NEXT: [[CONV4_I:%.*]] = sext <2 x i16> [[TMP2]] to <2 x i32> +// RV64-NEXT: [[ADD5_I:%.*]] = add <2 x i32> [[ADD_I]], [[CONV4_I]] +// RV64-NEXT: [[TMP3:%.*]] = bitcast <2 x i32> [[ADD5_I]] to i64 +// RV64-NEXT: ret i64 [[TMP3]] +// +int32x2_t test_pwadda_i32x2(int32x2_t rd, int16x2_t rs1, int16x2_t rs2) { + return __riscv_pwadda_i32x2(rd, rs1, rs2); +} + +// RV32-LABEL: define dso_local i64 @test_pwaddau_u16x4( +// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV32-NEXT: [[ENTRY:.*:]] +// RV32-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16> +// RV32-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8> +// RV32-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8> +// RV32-NEXT: [[CONV_I:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i16> +// RV32-NEXT: [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]] +// RV32-NEXT: [[CONV4_I:%.*]] = zext <4 x i8> [[TMP2]] to <4 x i16> +// RV32-NEXT: [[ADD5_I:%.*]] = add <4 x i16> [[ADD_I]], [[CONV4_I]] +// RV32-NEXT: [[TMP3:%.*]] = bitcast <4 x i16> [[ADD5_I]] to i64 +// RV32-NEXT: ret i64 [[TMP3]] +// +// RV64-LABEL: define dso_local i64 @test_pwaddau_u16x4( +// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV64-NEXT: [[ENTRY:.*:]] +// RV64-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16> +// RV64-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8> +// RV64-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8> +// RV64-NEXT: [[CONV_I:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i16> +// RV64-NEXT: [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]] +// RV64-NEXT: [[CONV4_I:%.*]] = zext <4 x i8> [[TMP2]] to <4 x i16> +// RV64-NEXT: [[ADD5_I:%.*]] = add <4 x i16> [[ADD_I]], [[CONV4_I]] +// RV64-NEXT: [[TMP3:%.*]] = bitcast <4 x i16> [[ADD5_I]] to i64 +// RV64-NEXT: ret i64 [[TMP3]] +// +uint16x4_t test_pwaddau_u16x4(uint16x4_t rd, uint8x4_t rs1, + uint8x4_t rs2) { + return __riscv_pwaddau_u16x4(rd, rs1, rs2); +} + +// RV32-LABEL: define dso_local i64 @test_pwaddau_u32x2( +// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV32-NEXT: [[ENTRY:.*:]] +// RV32-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32> +// RV32-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16> +// RV32-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16> +// RV32-NEXT: [[CONV_I:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32> +// RV32-NEXT: [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]] +// RV32-NEXT: [[CONV4_I:%.*]] = zext <2 x i16> [[TMP2]] to <2 x i32> +// RV32-NEXT: [[ADD5_I:%.*]] = add <2 x i32> [[ADD_I]], [[CONV4_I]] +// RV32-NEXT: [[TMP3:%.*]] = bitcast <2 x i32> [[ADD5_I]] to i64 +// RV32-NEXT: ret i64 [[TMP3]] +// +// RV64-LABEL: define dso_local i64 @test_pwaddau_u32x2( +// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { +// RV64-NEXT: [[ENTRY:.*:]] +// RV64-NEXT: [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32> +// RV64-NEXT: [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16> +// RV64-NEXT: [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16> +// RV64-NEXT: [[CONV_I:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32> +// RV64-NEXT: [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]] +// RV64-NEXT: [[CONV4_I:%.*]] = zext <2 x i16> [[TMP2]] to <2 x i32> +// RV64-NEXT: [[ADD5_I:%.*]] = add <2 x i32> [[ADD_I]], [[CONV4_I]] +// RV64-NEXT: [[TMP3:%.*]] = bitcast <2 x i32> [[ADD5_I]] to i64 +// RV64-NEXT: ret i64 [[TMP3]] +// +uint32x2_t test_pwaddau_u32x2(uint32x2_t rd, uint16x2_t rs1, + uint16x2_t rs2) { + return __riscv_pwaddau_u32x2(rd, rs1, rs2); +} + // RV32-LABEL: define dso_local i64 @test_pwsub_i16x4( // RV32-SAME: i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] { // RV32-NEXT: [[ENTRY:.*:]] 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 d76b2b0a4c7db..31a5efa9d8554 100644 --- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c +++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c @@ -2343,6 +2343,45 @@ uint32x2_t test_pwsubu_u32x2(uint16x2_t rs1, uint16x2_t rs2) { return __riscv_pwsubu_u32x2(rs1, rs2); } +// CHECK-LABEL: test_pwadda_i16x4: +// RV32: pwadda.b +// RV64: zip8p +// RV64: psext.h.b +// RV64: padd.h +// RV64: psrai.h +// RV64: padd.h +int16x4_t test_pwadda_i16x4(int16x4_t rd, int8x4_t rs1, int8x4_t rs2) { + return __riscv_pwadda_i16x4(rd, rs1, rs2); +} + +// CHECK-LABEL: test_pwadda_i32x2: +// RV32: pwadda.h +// RV64: zip16p +// RV64: pli.h +// RV64: pm2adda.h +int32x2_t test_pwadda_i32x2(int32x2_t rd, int16x2_t rs1, int16x2_t rs2) { + return __riscv_pwadda_i32x2(rd, rs1, rs2); +} + +// CHECK-LABEL: test_pwaddau_u16x4: +// RV32: pwaddau.b +// RV64: pwcvtu.wb +// RV64: padd.h +// RV64: pwcvtu.wb +// RV64: padd.h +uint16x4_t test_pwaddau_u16x4(uint16x4_t rd, uint8x4_t rs1, uint8x4_t rs2) { + return __riscv_pwaddau_u16x4(rd, rs1, rs2); +} + +// CHECK-LABEL: test_pwaddau_u32x2: +// RV32: pwaddau.h +// RV64: zip16p +// RV64: pli.h +// RV64: pm2addau.h +uint32x2_t test_pwaddau_u32x2(uint32x2_t rd, uint16x2_t rs1, uint16x2_t rs2) { + return __riscv_pwaddau_u32x2(rd, rs1, rs2); +} + // CHECK-LABEL: test_pwcvth_i16x4: // RV32: pwcvth.b // RV64: pwcvth.wb diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index b2f684952dd90..0175a1613e892 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -18439,6 +18439,86 @@ static SDValue combinePExtWideningAddSub(SDNode *N, SelectionDAG &DAG, return SDValue(); } +static SDValue combinePExtWideningAddAcc(SDNode *N, SelectionDAG &DAG, + const RISCVSubtarget &Subtarget) { + if (!Subtarget.hasStdExtP() || !Subtarget.is64Bit()) + return SDValue(); + + if (N->getOpcode() != ISD::ADD) + return SDValue(); + + MVT VT = N->getSimpleValueType(0); + if (VT != MVT::v4i16 && VT != MVT::v2i32) + return SDValue(); + + auto MatchExtend = [](SDValue V, unsigned ExtendOpcode, MVT SrcVT, + SDValue &Src) -> bool { + if (V.getOpcode() != ExtendOpcode || !V.hasOneUse() || + V.getOperand(0).getSimpleValueType() != SrcVT) + return false; + Src = V.getOperand(0); + return true; + }; + + auto Match = [&](SDValue V, SDValue &Acc, SDValue &A, SDValue &B, + bool &IsSExt) -> bool { + unsigned ExtendOpcode = V.getOpcode(); + if (ExtendOpcode != ISD::SIGN_EXTEND && ExtendOpcode != ISD::ZERO_EXTEND) + return false; + + MVT SrcVT = VT == MVT::v4i16 ? MVT::v4i8 : MVT::v2i16; + if (!MatchExtend(V, ExtendOpcode, SrcVT, B)) + return false; + + SDValue Add = V == N->getOperand(0) ? N->getOperand(1) : N->getOperand(0); + if (Add.getOpcode() != ISD::ADD || !Add.hasOneUse()) + return false; + + if (MatchExtend(Add.getOperand(0), ExtendOpcode, SrcVT, A)) + Acc = Add.getOperand(1); + else if (MatchExtend(Add.getOperand(1), ExtendOpcode, SrcVT, A)) + Acc = Add.getOperand(0); + else + return false; + + if (Acc.getValueType() != VT) + return false; + + IsSExt = ExtendOpcode == ISD::SIGN_EXTEND; + return true; + }; + + SDValue Acc, A, B; + bool IsSExt; + if (!Match(N->getOperand(0), Acc, A, B, IsSExt) && + !Match(N->getOperand(1), Acc, A, B, IsSExt)) + return SDValue(); + + if (VT == MVT::v4i16 && !IsSExt) + return SDValue(); + + SDLoc DL(N); + MVT LegalSrcVT = VT == MVT::v4i16 ? MVT::v8i8 : MVT::v4i16; + MVT SrcVT = VT == MVT::v4i16 ? MVT::v4i8 : MVT::v2i16; + A = DAG.getNode(ISD::CONCAT_VECTORS, DL, LegalSrcVT, A, DAG.getUNDEF(SrcVT)); + B = DAG.getNode(ISD::CONCAT_VECTORS, DL, LegalSrcVT, B, DAG.getUNDEF(SrcVT)); + + SDValue Zip = DAG.getNode(RISCVISD::PZIP, DL, LegalSrcVT, A, B); + if (VT == MVT::v4i16) { + SDValue ZipAsVT = DAG.getBitcast(VT, Zip); + SDValue Low = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, ZipAsVT, + DAG.getValueType(MVT::v4i8)); + SDValue High = DAG.getNode(RISCVISD::PSRA, DL, VT, ZipAsVT, + DAG.getConstant(8, DL, MVT::i64)); + return DAG.getNode(ISD::ADD, DL, VT, + DAG.getNode(ISD::ADD, DL, VT, Acc, Low), High); + } + + SDValue Ones = DAG.getConstant(1, DL, LegalSrcVT); + unsigned Opc = IsSExt ? RISCVISD::PM2ADDA_H : RISCVISD::PM2ADDAU_H; + return DAG.getNode(Opc, DL, VT, Acc, Zip, Ones); +} + static SDValue performADDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const RISCVSubtarget &Subtarget) { @@ -18457,6 +18537,8 @@ static SDValue performADDCombine(SDNode *N, return V; if (SDValue V = combineBinOpOfExtractToReduceTree(N, DAG, Subtarget)) return V; + if (SDValue V = combinePExtWideningAddAcc(N, DAG, Subtarget)) + return V; if (SDValue V = combinePExtWideningAddSub(N, DAG, Subtarget)) return V; if (SDValue V = combineBinOpOfZExt(N, DAG)) diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td index c7372ef3549b6..8304b172717a3 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td @@ -1915,6 +1915,12 @@ def riscv_pm2addu_h : RVSDNode<"PM2ADDU_H", SDT_RISCVPM2Halfword, [SDNPCommutative]>; def riscv_pm2sub_h : RVSDNode<"PM2SUB_H", SDT_RISCVPM2Halfword>; +def SDT_RISCVPM2HalfwordAcc + : SDTypeProfile<1, 3, [SDTCisVT<0, v2i32>, SDTCisSameAs<0, 1>, + SDTCisVT<2, v4i16>, SDTCisSameAs<2, 3>]>; +def riscv_pm2adda_h : RVSDNode<"PM2ADDA_H", SDT_RISCVPM2HalfwordAcc>; +def riscv_pm2addau_h : RVSDNode<"PM2ADDAU_H", SDT_RISCVPM2HalfwordAcc>; + def SDT_RISCVWideningShiftLeft : SDTypeProfile<2, 2, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, @@ -2509,6 +2515,18 @@ let append Predicates = [IsRV32] in { (PWADDU_B GPR:$rs1, GPR:$rs2)>; def : Pat<(v2i32 (add (zext (v2i16 GPR:$rs1)), (zext (v2i16 GPR:$rs2)))), (PWADDU_H GPR:$rs1, GPR:$rs2)>; + def : Pat<(v4i16 (add (add GPRPair:$rd, (sext (v4i8 GPR:$rs1))), + (sext (v4i8 GPR:$rs2)))), + (PWADDA_B GPRPair:$rd, GPR:$rs1, GPR:$rs2)>; + def : Pat<(v2i32 (add (add GPRPair:$rd, (sext (v2i16 GPR:$rs1))), + (sext (v2i16 GPR:$rs2)))), + (PWADDA_H GPRPair:$rd, GPR:$rs1, GPR:$rs2)>; + def : Pat<(v4i16 (add (add GPRPair:$rd, (zext (v4i8 GPR:$rs1))), + (zext (v4i8 GPR:$rs2)))), + (PWADDAU_B GPRPair:$rd, GPR:$rs1, GPR:$rs2)>; + def : Pat<(v2i32 (add (add GPRPair:$rd, (zext (v2i16 GPR:$rs1))), + (zext (v2i16 GPR:$rs2)))), + (PWADDAU_H GPRPair:$rd, GPR:$rs1, GPR:$rs2)>; def : Pat<(v4i16 (sub (sext (v4i8 GPR:$rs1)), (sext (v4i8 GPR:$rs2)))), (PWSUB_B GPR:$rs1, GPR:$rs2)>; def : Pat<(v2i32 (sub (sext (v2i16 GPR:$rs1)), (sext (v2i16 GPR:$rs2)))), @@ -3167,6 +3185,12 @@ let append Predicates = [IsRV64] in { (PM2ADDU_H GPR:$rs1, GPR:$rs2)>; def : Pat<(v2i32 (riscv_pm2sub_h (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))), (PM2SUB_H GPR:$rs1, GPR:$rs2)>; + def : Pat<(v2i32 (riscv_pm2adda_h (v2i32 GPR:$rd), (v4i16 GPR:$rs1), + (v4i16 GPR:$rs2))), + (PM2ADDA_H GPR:$rd, GPR:$rs1, GPR:$rs2)>; + def : Pat<(v2i32 (riscv_pm2addau_h (v2i32 GPR:$rd), (v4i16 GPR:$rs1), + (v4i16 GPR:$rs2))), + (PM2ADDAU_H GPR:$rd, GPR:$rs1, GPR:$rs2)>; // 32-bit logical shift left/right patterns def : PatGprImm<riscv_pshl, PSLLI_W, uimm5, v2i32>; diff --git a/llvm/test/CodeGen/RISCV/rvp-widening-add-acc.ll b/llvm/test/CodeGen/RISCV/rvp-widening-add-acc.ll new file mode 100644 index 0000000000000..637ce4d988be0 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvp-widening-add-acc.ll @@ -0,0 +1,86 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+experimental-p -verify-machineinstrs < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,RV32 +; RUN: llc -mtriple=riscv64 -mattr=+experimental-p -verify-machineinstrs < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,RV64 + +define <4 x i16> @test_pwadda_v4i8(<4 x i16> %rd, <4 x i8> %a, <4 x i8> %b) { +; RV32-LABEL: test_pwadda_v4i8: +; RV32: # %bb.0: +; RV32-NEXT: pwadda.b a0, a2, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pwadda_v4i8: +; RV64: # %bb.0: +; RV64-NEXT: zip8p a1, a1, a2 +; RV64-NEXT: psext.h.b a2, a1 +; RV64-NEXT: padd.h a0, a0, a2 +; RV64-NEXT: psrai.h a1, a1, 8 +; RV64-NEXT: padd.h a0, a0, a1 +; RV64-NEXT: ret + %ext.a = sext <4 x i8> %a to <4 x i16> + %ext.b = sext <4 x i8> %b to <4 x i16> + %sum.a = add <4 x i16> %rd, %ext.a + %sum.b = add <4 x i16> %sum.a, %ext.b + ret <4 x i16> %sum.b +} + +define <2 x i32> @test_pwadda_v2i16(<2 x i32> %rd, <2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_pwadda_v2i16: +; RV32: # %bb.0: +; RV32-NEXT: pwadda.h a0, a2, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pwadda_v2i16: +; RV64: # %bb.0: +; RV64-NEXT: zip16p a1, a1, a2 +; RV64-NEXT: pli.h a2, 1 +; RV64-NEXT: pm2adda.h a0, a1, a2 +; RV64-NEXT: ret + %ext.a = sext <2 x i16> %a to <2 x i32> + %ext.b = sext <2 x i16> %b to <2 x i32> + %sum.a = add <2 x i32> %rd, %ext.a + %sum.b = add <2 x i32> %sum.a, %ext.b + ret <2 x i32> %sum.b +} + +define <4 x i16> @test_pwaddau_v4i8(<4 x i16> %rd, <4 x i8> %a, <4 x i8> %b) { +; RV32-LABEL: test_pwaddau_v4i8: +; RV32: # %bb.0: +; RV32-NEXT: pwaddau.b a0, a2, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pwaddau_v4i8: +; RV64: # %bb.0: +; RV64-NEXT: pwcvtu.wb a1, a1 +; RV64-NEXT: pwcvtu.wb a2, a2 +; RV64-NEXT: padd.h a0, a0, a1 +; RV64-NEXT: padd.h a0, a0, a2 +; RV64-NEXT: ret + %ext.a = zext <4 x i8> %a to <4 x i16> + %ext.b = zext <4 x i8> %b to <4 x i16> + %sum.a = add <4 x i16> %rd, %ext.a + %sum.b = add <4 x i16> %sum.a, %ex... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/221622 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
