https://github.com/sihuan created https://github.com/llvm/llvm-project/pull/218875
Add SelectionDAG and intrinsic support for the RISC-V P multiply-parts operations, which widen one element out of every pair: `pmul.h.b00`, `pmul.w.h01`, `mul.h11`, `mul.w00` and their unsigned and signed-unsigned forms. The element width is implied by the overloaded types, so the intrinsic names only carry the element selection and the signedness: `llvm.riscv.pmul.00` covers both `pmul.h.b00` and `pmul.w.h00`, and `llvm.riscv.mul.00` covers `mul.h00` and `mul.w00`. The packed operands are `LLVMSubdivide2VectorType` of the result, so only the result type is mangled. Three shapes need legalizing rather than a pattern. On RV32 a 64-bit packed result lives in a GPR pair, so each half is computed with the 32-bit form of the same product, which for a `<2 x i32>` result is the scalar form. On RV64 there is no halfword multiply-parts instruction, so the `<2 x i16>` operands are widened to `<4 x i16>` and the wanted product is the first element of the packed result. On RV32 there is no word multiply-parts instruction, so the selected elements are extracted and multiplied into a GPR pair with `wmul`/`wmulu`/`wmulsu`. Also adds the Clang builtins and the `riscv_packed_simd.h` wrappers. >From 7f87baefe3592752044e4f9faed0ace7da3468c4 Mon Sep 17 00:00:00 2001 From: SiHuaN <[email protected]> Date: Thu, 13 Aug 2026 18:49:25 +0000 Subject: [PATCH] [RISCV][P-ext] Add packed multiply-parts intrinsics --- clang/include/clang/Basic/BuiltinsRISCV.td | 43 ++ clang/lib/CodeGen/TargetBuiltins/RISCV.cpp | 131 ++++++ clang/lib/Headers/riscv_packed_simd.h | 43 ++ .../riscv_packed_simd.c | 281 +++++++++++++ llvm/include/llvm/IR/IntrinsicsRISCV.td | 30 ++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 156 ++++++++ llvm/lib/Target/RISCV/RISCVInstrInfoP.td | 44 ++ llvm/test/CodeGen/RISCV/rvp-simd-32.ll | 202 ++++++++++ llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 378 ++++++++++++++++++ .../RISCV/rvp-simd-intrinsic-invalid.ll | 26 ++ 10 files changed, 1334 insertions(+) diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td b/clang/include/clang/Basic/BuiltinsRISCV.td index 89dbf736f4435..fd48c0d01a0f5 100644 --- a/clang/include/clang/Basic/BuiltinsRISCV.td +++ b/clang/include/clang/Basic/BuiltinsRISCV.td @@ -318,6 +318,49 @@ def pmulq_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4, def pmulqr_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>, _Vector<4, short>)">; def pmulq_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, int>)">; def pmulqr_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, int>)">; +// Packed Multiply Parts (32-bit) +def pmul_b00_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, _Vector<4, signed char>)">; +def pmul_b01_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, _Vector<4, signed char>)">; +def pmul_b11_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, _Vector<4, signed char>)">; +def pmulu_b00_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<4, unsigned char>, _Vector<4, unsigned char>)">; +def pmulu_b01_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<4, unsigned char>, _Vector<4, unsigned char>)">; +def pmulu_b11_u16x2 : RISCVBuiltin<"_Vector<2, unsigned short>(_Vector<4, unsigned char>, _Vector<4, unsigned char>)">; +def pmulsu_b00_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, _Vector<4, unsigned char>)">; +def pmulsu_b11_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<4, signed char>, _Vector<4, unsigned char>)">; +def mul_h00_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, short>)">; +def mul_h01_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, short>)">; +def mul_h11_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, short>)">; +def mulu_h00_u32 : RISCVBuiltin<"unsigned int(_Vector<2, unsigned short>, _Vector<2, unsigned short>)">; +def mulu_h01_u32 : RISCVBuiltin<"unsigned int(_Vector<2, unsigned short>, _Vector<2, unsigned short>)">; +def mulu_h11_u32 : RISCVBuiltin<"unsigned int(_Vector<2, unsigned short>, _Vector<2, unsigned short>)">; +def mulsu_h00_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, unsigned short>)">; +def mulsu_h11_i32 : RISCVBuiltin<"int(_Vector<2, short>, _Vector<2, unsigned short>)">; + +// Packed Multiply Parts (64-bit) +def pmul_b00_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, _Vector<8, signed char>)">; +def pmul_b01_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, _Vector<8, signed char>)">; +def pmul_b11_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, _Vector<8, signed char>)">; +def pmulu_b00_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<8, unsigned char>, _Vector<8, unsigned char>)">; +def pmulu_b01_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<8, unsigned char>, _Vector<8, unsigned char>)">; +def pmulu_b11_u16x4 : RISCVBuiltin<"_Vector<4, unsigned short>(_Vector<8, unsigned char>, _Vector<8, unsigned char>)">; +def pmulsu_b00_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, _Vector<8, unsigned char>)">; +def pmulsu_b11_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<8, signed char>, _Vector<8, unsigned char>)">; +def pmul_h00_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, _Vector<4, short>)">; +def pmul_h01_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, _Vector<4, short>)">; +def pmul_h11_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, _Vector<4, short>)">; +def pmulu_h00_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<4, unsigned short>, _Vector<4, unsigned short>)">; +def pmulu_h01_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<4, unsigned short>, _Vector<4, unsigned short>)">; +def pmulu_h11_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<4, unsigned short>, _Vector<4, unsigned short>)">; +def pmulsu_h00_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, _Vector<4, unsigned short>)">; +def pmulsu_h11_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<4, short>, _Vector<4, unsigned short>)">; +def mul_w00_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, int>)">; +def mul_w01_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, int>)">; +def mul_w11_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, int>)">; +def mulu_w00_u64 : RISCVBuiltin<"uint64_t(_Vector<2, unsigned int>, _Vector<2, unsigned int>)">; +def mulu_w01_u64 : RISCVBuiltin<"uint64_t(_Vector<2, unsigned int>, _Vector<2, unsigned int>)">; +def mulu_w11_u64 : RISCVBuiltin<"uint64_t(_Vector<2, unsigned int>, _Vector<2, unsigned int>)">; +def mulsu_w00_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, unsigned int>)">; +def mulsu_w11_i64 : RISCVBuiltin<"int64_t(_Vector<2, int>, _Vector<2, unsigned int>)">; // Packed Sign and Zero Extend (32-bit) def psext_b_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>)">; diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp index 88fedecbee504..1415a6446e733 100644 --- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp @@ -1625,6 +1625,137 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, IntrinsicTypes = {ResultType, Ops.back()->getType()}; break; } + // Packed Multiply Parts. + case RISCV::BI__builtin_riscv_pmul_b00_i16x2: + case RISCV::BI__builtin_riscv_pmul_b01_i16x2: + case RISCV::BI__builtin_riscv_pmul_b11_i16x2: + case RISCV::BI__builtin_riscv_pmulu_b00_u16x2: + case RISCV::BI__builtin_riscv_pmulu_b01_u16x2: + case RISCV::BI__builtin_riscv_pmulu_b11_u16x2: + case RISCV::BI__builtin_riscv_pmulsu_b00_i16x2: + case RISCV::BI__builtin_riscv_pmulsu_b11_i16x2: + case RISCV::BI__builtin_riscv_pmul_b00_i16x4: + case RISCV::BI__builtin_riscv_pmul_b01_i16x4: + case RISCV::BI__builtin_riscv_pmul_b11_i16x4: + case RISCV::BI__builtin_riscv_pmulu_b00_u16x4: + case RISCV::BI__builtin_riscv_pmulu_b01_u16x4: + case RISCV::BI__builtin_riscv_pmulu_b11_u16x4: + case RISCV::BI__builtin_riscv_pmulsu_b00_i16x4: + case RISCV::BI__builtin_riscv_pmulsu_b11_i16x4: + case RISCV::BI__builtin_riscv_pmul_h00_i32x2: + case RISCV::BI__builtin_riscv_pmul_h01_i32x2: + case RISCV::BI__builtin_riscv_pmul_h11_i32x2: + case RISCV::BI__builtin_riscv_pmulu_h00_u32x2: + case RISCV::BI__builtin_riscv_pmulu_h01_u32x2: + case RISCV::BI__builtin_riscv_pmulu_h11_u32x2: + case RISCV::BI__builtin_riscv_pmulsu_h00_i32x2: + case RISCV::BI__builtin_riscv_pmulsu_h11_i32x2: { + switch (BuiltinID) { + default: + llvm_unreachable("unexpected builtin ID"); + case RISCV::BI__builtin_riscv_pmul_b00_i16x2: + case RISCV::BI__builtin_riscv_pmul_b00_i16x4: + case RISCV::BI__builtin_riscv_pmul_h00_i32x2: + ID = Intrinsic::riscv_pmul_00; + break; + case RISCV::BI__builtin_riscv_pmul_b01_i16x2: + case RISCV::BI__builtin_riscv_pmul_b01_i16x4: + case RISCV::BI__builtin_riscv_pmul_h01_i32x2: + ID = Intrinsic::riscv_pmul_01; + break; + case RISCV::BI__builtin_riscv_pmul_b11_i16x2: + case RISCV::BI__builtin_riscv_pmul_b11_i16x4: + case RISCV::BI__builtin_riscv_pmul_h11_i32x2: + ID = Intrinsic::riscv_pmul_11; + break; + case RISCV::BI__builtin_riscv_pmulu_b00_u16x2: + case RISCV::BI__builtin_riscv_pmulu_b00_u16x4: + case RISCV::BI__builtin_riscv_pmulu_h00_u32x2: + ID = Intrinsic::riscv_pmulu_00; + break; + case RISCV::BI__builtin_riscv_pmulu_b01_u16x2: + case RISCV::BI__builtin_riscv_pmulu_b01_u16x4: + case RISCV::BI__builtin_riscv_pmulu_h01_u32x2: + ID = Intrinsic::riscv_pmulu_01; + break; + case RISCV::BI__builtin_riscv_pmulu_b11_u16x2: + case RISCV::BI__builtin_riscv_pmulu_b11_u16x4: + case RISCV::BI__builtin_riscv_pmulu_h11_u32x2: + ID = Intrinsic::riscv_pmulu_11; + break; + case RISCV::BI__builtin_riscv_pmulsu_b00_i16x2: + case RISCV::BI__builtin_riscv_pmulsu_b00_i16x4: + case RISCV::BI__builtin_riscv_pmulsu_h00_i32x2: + ID = Intrinsic::riscv_pmulsu_00; + break; + case RISCV::BI__builtin_riscv_pmulsu_b11_i16x2: + case RISCV::BI__builtin_riscv_pmulsu_b11_i16x4: + case RISCV::BI__builtin_riscv_pmulsu_h11_i32x2: + ID = Intrinsic::riscv_pmulsu_11; + break; + } + + IntrinsicTypes = {ResultType}; + break; + } + + // Scalar Multiply Parts. + case RISCV::BI__builtin_riscv_mul_h00_i32: + case RISCV::BI__builtin_riscv_mul_w00_i64: + case RISCV::BI__builtin_riscv_mul_h01_i32: + case RISCV::BI__builtin_riscv_mul_w01_i64: + case RISCV::BI__builtin_riscv_mul_h11_i32: + case RISCV::BI__builtin_riscv_mul_w11_i64: + case RISCV::BI__builtin_riscv_mulu_h00_u32: + case RISCV::BI__builtin_riscv_mulu_w00_u64: + case RISCV::BI__builtin_riscv_mulu_h01_u32: + case RISCV::BI__builtin_riscv_mulu_w01_u64: + case RISCV::BI__builtin_riscv_mulu_h11_u32: + case RISCV::BI__builtin_riscv_mulu_w11_u64: + case RISCV::BI__builtin_riscv_mulsu_h00_i32: + case RISCV::BI__builtin_riscv_mulsu_w00_i64: + case RISCV::BI__builtin_riscv_mulsu_h11_i32: + case RISCV::BI__builtin_riscv_mulsu_w11_i64: { + switch (BuiltinID) { + default: + llvm_unreachable("unexpected builtin ID"); + case RISCV::BI__builtin_riscv_mul_h00_i32: + case RISCV::BI__builtin_riscv_mul_w00_i64: + ID = Intrinsic::riscv_mul_00; + break; + case RISCV::BI__builtin_riscv_mul_h01_i32: + case RISCV::BI__builtin_riscv_mul_w01_i64: + ID = Intrinsic::riscv_mul_01; + break; + case RISCV::BI__builtin_riscv_mul_h11_i32: + case RISCV::BI__builtin_riscv_mul_w11_i64: + ID = Intrinsic::riscv_mul_11; + break; + case RISCV::BI__builtin_riscv_mulu_h00_u32: + case RISCV::BI__builtin_riscv_mulu_w00_u64: + ID = Intrinsic::riscv_mulu_00; + break; + case RISCV::BI__builtin_riscv_mulu_h01_u32: + case RISCV::BI__builtin_riscv_mulu_w01_u64: + ID = Intrinsic::riscv_mulu_01; + break; + case RISCV::BI__builtin_riscv_mulu_h11_u32: + case RISCV::BI__builtin_riscv_mulu_w11_u64: + ID = Intrinsic::riscv_mulu_11; + break; + case RISCV::BI__builtin_riscv_mulsu_h00_i32: + case RISCV::BI__builtin_riscv_mulsu_w00_i64: + ID = Intrinsic::riscv_mulsu_00; + break; + case RISCV::BI__builtin_riscv_mulsu_h11_i32: + case RISCV::BI__builtin_riscv_mulsu_w11_i64: + ID = Intrinsic::riscv_mulsu_11; + break; + } + + IntrinsicTypes = {ResultType, Ops[0]->getType()}; + break; + } // Zk builtins diff --git a/clang/lib/Headers/riscv_packed_simd.h b/clang/lib/Headers/riscv_packed_simd.h index 318900805043c..581ffb91f4b84 100644 --- a/clang/lib/Headers/riscv_packed_simd.h +++ b/clang/lib/Headers/riscv_packed_simd.h @@ -851,6 +851,49 @@ __packed_binary_builtin(pmulq_i16x4, int16x4_t, __builtin_riscv_pmulq_i16x4) __packed_binary_builtin(pmulqr_i16x4, int16x4_t, __builtin_riscv_pmulqr_i16x4) __packed_binary_builtin(pmulq_i32x2, int32x2_t, __builtin_riscv_pmulq_i32x2) __packed_binary_builtin(pmulqr_i32x2, int32x2_t, __builtin_riscv_pmulqr_i32x2) +/* Packed Multiply Parts (32-bit) */ +__packed_binary_builtin_mixed(pmul_b00_i16x2, int16x2_t, int8x4_t, int8x4_t, __builtin_riscv_pmul_b00_i16x2) +__packed_binary_builtin_mixed(pmul_b01_i16x2, int16x2_t, int8x4_t, int8x4_t, __builtin_riscv_pmul_b01_i16x2) +__packed_binary_builtin_mixed(pmul_b11_i16x2, int16x2_t, int8x4_t, int8x4_t, __builtin_riscv_pmul_b11_i16x2) +__packed_binary_builtin_mixed(pmulu_b00_u16x2, uint16x2_t, uint8x4_t, uint8x4_t, __builtin_riscv_pmulu_b00_u16x2) +__packed_binary_builtin_mixed(pmulu_b01_u16x2, uint16x2_t, uint8x4_t, uint8x4_t, __builtin_riscv_pmulu_b01_u16x2) +__packed_binary_builtin_mixed(pmulu_b11_u16x2, uint16x2_t, uint8x4_t, uint8x4_t, __builtin_riscv_pmulu_b11_u16x2) +__packed_binary_builtin_mixed(pmulsu_b00_i16x2, int16x2_t, int8x4_t, uint8x4_t, __builtin_riscv_pmulsu_b00_i16x2) +__packed_binary_builtin_mixed(pmulsu_b11_i16x2, int16x2_t, int8x4_t, uint8x4_t, __builtin_riscv_pmulsu_b11_i16x2) +__packed_binary_builtin_mixed(mul_h00_i32, int32_t, int16x2_t, int16x2_t, __builtin_riscv_mul_h00_i32) +__packed_binary_builtin_mixed(mul_h01_i32, int32_t, int16x2_t, int16x2_t, __builtin_riscv_mul_h01_i32) +__packed_binary_builtin_mixed(mul_h11_i32, int32_t, int16x2_t, int16x2_t, __builtin_riscv_mul_h11_i32) +__packed_binary_builtin_mixed(mulu_h00_u32, uint32_t, uint16x2_t, uint16x2_t, __builtin_riscv_mulu_h00_u32) +__packed_binary_builtin_mixed(mulu_h01_u32, uint32_t, uint16x2_t, uint16x2_t, __builtin_riscv_mulu_h01_u32) +__packed_binary_builtin_mixed(mulu_h11_u32, uint32_t, uint16x2_t, uint16x2_t, __builtin_riscv_mulu_h11_u32) +__packed_binary_builtin_mixed(mulsu_h00_i32, int32_t, int16x2_t, uint16x2_t, __builtin_riscv_mulsu_h00_i32) +__packed_binary_builtin_mixed(mulsu_h11_i32, int32_t, int16x2_t, uint16x2_t, __builtin_riscv_mulsu_h11_i32) + +/* Packed Multiply Parts (64-bit) */ +__packed_binary_builtin_mixed(pmul_b00_i16x4, int16x4_t, int8x8_t, int8x8_t, __builtin_riscv_pmul_b00_i16x4) +__packed_binary_builtin_mixed(pmul_b01_i16x4, int16x4_t, int8x8_t, int8x8_t, __builtin_riscv_pmul_b01_i16x4) +__packed_binary_builtin_mixed(pmul_b11_i16x4, int16x4_t, int8x8_t, int8x8_t, __builtin_riscv_pmul_b11_i16x4) +__packed_binary_builtin_mixed(pmulu_b00_u16x4, uint16x4_t, uint8x8_t, uint8x8_t, __builtin_riscv_pmulu_b00_u16x4) +__packed_binary_builtin_mixed(pmulu_b01_u16x4, uint16x4_t, uint8x8_t, uint8x8_t, __builtin_riscv_pmulu_b01_u16x4) +__packed_binary_builtin_mixed(pmulu_b11_u16x4, uint16x4_t, uint8x8_t, uint8x8_t, __builtin_riscv_pmulu_b11_u16x4) +__packed_binary_builtin_mixed(pmulsu_b00_i16x4, int16x4_t, int8x8_t, uint8x8_t, __builtin_riscv_pmulsu_b00_i16x4) +__packed_binary_builtin_mixed(pmulsu_b11_i16x4, int16x4_t, int8x8_t, uint8x8_t, __builtin_riscv_pmulsu_b11_i16x4) +__packed_binary_builtin_mixed(pmul_h00_i32x2, int32x2_t, int16x4_t, int16x4_t, __builtin_riscv_pmul_h00_i32x2) +__packed_binary_builtin_mixed(pmul_h01_i32x2, int32x2_t, int16x4_t, int16x4_t, __builtin_riscv_pmul_h01_i32x2) +__packed_binary_builtin_mixed(pmul_h11_i32x2, int32x2_t, int16x4_t, int16x4_t, __builtin_riscv_pmul_h11_i32x2) +__packed_binary_builtin_mixed(pmulu_h00_u32x2, uint32x2_t, uint16x4_t, uint16x4_t, __builtin_riscv_pmulu_h00_u32x2) +__packed_binary_builtin_mixed(pmulu_h01_u32x2, uint32x2_t, uint16x4_t, uint16x4_t, __builtin_riscv_pmulu_h01_u32x2) +__packed_binary_builtin_mixed(pmulu_h11_u32x2, uint32x2_t, uint16x4_t, uint16x4_t, __builtin_riscv_pmulu_h11_u32x2) +__packed_binary_builtin_mixed(pmulsu_h00_i32x2, int32x2_t, int16x4_t, uint16x4_t, __builtin_riscv_pmulsu_h00_i32x2) +__packed_binary_builtin_mixed(pmulsu_h11_i32x2, int32x2_t, int16x4_t, uint16x4_t, __builtin_riscv_pmulsu_h11_i32x2) +__packed_binary_builtin_mixed(mul_w00_i64, int64_t, int32x2_t, int32x2_t, __builtin_riscv_mul_w00_i64) +__packed_binary_builtin_mixed(mul_w01_i64, int64_t, int32x2_t, int32x2_t, __builtin_riscv_mul_w01_i64) +__packed_binary_builtin_mixed(mul_w11_i64, int64_t, int32x2_t, int32x2_t, __builtin_riscv_mul_w11_i64) +__packed_binary_builtin_mixed(mulu_w00_u64, uint64_t, uint32x2_t, uint32x2_t, __builtin_riscv_mulu_w00_u64) +__packed_binary_builtin_mixed(mulu_w01_u64, uint64_t, uint32x2_t, uint32x2_t, __builtin_riscv_mulu_w01_u64) +__packed_binary_builtin_mixed(mulu_w11_u64, uint64_t, uint32x2_t, uint32x2_t, __builtin_riscv_mulu_w11_u64) +__packed_binary_builtin_mixed(mulsu_w00_i64, int64_t, int32x2_t, uint32x2_t, __builtin_riscv_mulsu_w00_i64) +__packed_binary_builtin_mixed(mulsu_w11_i64, int64_t, int32x2_t, uint32x2_t, __builtin_riscv_mulsu_w11_i64) /* Packed Narrowing Clip Pair (32-bit) */ __packed_binary_builtin_cast(pnclipp_i8x4, int16x2_t, int8x4_t, __builtin_riscv_pnclipp_i8x4) 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 75dcb796b66cd..262194d3eb08f 100644 --- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c +++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c @@ -3406,3 +3406,284 @@ int32x2_t test_pnclipp_i32x2(int64_t a, int64_t b) { uint32x2_t test_pnclipup_u32x2(uint64_t a, uint64_t b) { return __riscv_pnclipup_u32x2(a, b); } + +// Packed Multiply Parts. +// CHECK-LABEL: test_pmul_b00_i16x2: +// RV32: pmul.h.b00 +// RV64: pmul.h.b00 +int16x2_t test_pmul_b00_i16x2(int8x4_t a, int8x4_t b) { + return __riscv_pmul_b00_i16x2(a, b); +} + +// CHECK-LABEL: test_pmul_b01_i16x2: +// RV32: pmul.h.b01 +// RV64: pmul.h.b01 +int16x2_t test_pmul_b01_i16x2(int8x4_t a, int8x4_t b) { + return __riscv_pmul_b01_i16x2(a, b); +} + +// CHECK-LABEL: test_pmul_b11_i16x2: +// RV32: pmul.h.b11 +// RV64: pmul.h.b11 +int16x2_t test_pmul_b11_i16x2(int8x4_t a, int8x4_t b) { + return __riscv_pmul_b11_i16x2(a, b); +} + +// CHECK-LABEL: test_pmulu_b00_u16x2: +// RV32: pmulu.h.b00 +// RV64: pmulu.h.b00 +uint16x2_t test_pmulu_b00_u16x2(uint8x4_t a, uint8x4_t b) { + return __riscv_pmulu_b00_u16x2(a, b); +} + +// CHECK-LABEL: test_pmulu_b01_u16x2: +// RV32: pmulu.h.b01 +// RV64: pmulu.h.b01 +uint16x2_t test_pmulu_b01_u16x2(uint8x4_t a, uint8x4_t b) { + return __riscv_pmulu_b01_u16x2(a, b); +} + +// CHECK-LABEL: test_pmulu_b11_u16x2: +// RV32: pmulu.h.b11 +// RV64: pmulu.h.b11 +uint16x2_t test_pmulu_b11_u16x2(uint8x4_t a, uint8x4_t b) { + return __riscv_pmulu_b11_u16x2(a, b); +} + +// CHECK-LABEL: test_pmulsu_b00_i16x2: +// RV32: pmulsu.h.b00 +// RV64: pmulsu.h.b00 +int16x2_t test_pmulsu_b00_i16x2(int8x4_t a, uint8x4_t b) { + return __riscv_pmulsu_b00_i16x2(a, b); +} + +// CHECK-LABEL: test_pmulsu_b11_i16x2: +// RV32: pmulsu.h.b11 +// RV64: pmulsu.h.b11 +int16x2_t test_pmulsu_b11_i16x2(int8x4_t a, uint8x4_t b) { + return __riscv_pmulsu_b11_i16x2(a, b); +} + +// CHECK-LABEL: test_mul_h00_i32: +// RV32: mul.h00 +// RV64: pmul.w.h00 +int32_t test_mul_h00_i32(int16x2_t a, int16x2_t b) { + return __riscv_mul_h00_i32(a, b); +} + +// CHECK-LABEL: test_mul_h01_i32: +// RV32: mul.h01 +// RV64: pmul.w.h01 +int32_t test_mul_h01_i32(int16x2_t a, int16x2_t b) { + return __riscv_mul_h01_i32(a, b); +} + +// CHECK-LABEL: test_mul_h11_i32: +// RV32: mul.h11 +// RV64: pmul.w.h11 +int32_t test_mul_h11_i32(int16x2_t a, int16x2_t b) { + return __riscv_mul_h11_i32(a, b); +} + +// CHECK-LABEL: test_mulu_h00_u32: +// RV32: mulu.h00 +// RV64: pmulu.w.h00 +uint32_t test_mulu_h00_u32(uint16x2_t a, uint16x2_t b) { + return __riscv_mulu_h00_u32(a, b); +} + +// CHECK-LABEL: test_mulu_h01_u32: +// RV32: mulu.h01 +// RV64: pmulu.w.h01 +uint32_t test_mulu_h01_u32(uint16x2_t a, uint16x2_t b) { + return __riscv_mulu_h01_u32(a, b); +} + +// CHECK-LABEL: test_mulu_h11_u32: +// RV32: mulu.h11 +// RV64: pmulu.w.h11 +uint32_t test_mulu_h11_u32(uint16x2_t a, uint16x2_t b) { + return __riscv_mulu_h11_u32(a, b); +} + +// CHECK-LABEL: test_mulsu_h00_i32: +// RV32: mulsu.h00 +// RV64: pmulsu.w.h00 +int32_t test_mulsu_h00_i32(int16x2_t a, uint16x2_t b) { + return __riscv_mulsu_h00_i32(a, b); +} + +// CHECK-LABEL: test_mulsu_h11_i32: +// RV32: mulsu.h11 +// RV64: pmulsu.w.h11 +int32_t test_mulsu_h11_i32(int16x2_t a, uint16x2_t b) { + return __riscv_mulsu_h11_i32(a, b); +} + +// CHECK-LABEL: test_pmul_b00_i16x4: +// RV32-COUNT-2: pmul.h.b00 +// RV64: pmul.h.b00 +int16x4_t test_pmul_b00_i16x4(int8x8_t a, int8x8_t b) { + return __riscv_pmul_b00_i16x4(a, b); +} + +// CHECK-LABEL: test_pmul_b01_i16x4: +// RV32-COUNT-2: pmul.h.b01 +// RV64: pmul.h.b01 +int16x4_t test_pmul_b01_i16x4(int8x8_t a, int8x8_t b) { + return __riscv_pmul_b01_i16x4(a, b); +} + +// CHECK-LABEL: test_pmul_b11_i16x4: +// RV32-COUNT-2: pmul.h.b11 +// RV64: pmul.h.b11 +int16x4_t test_pmul_b11_i16x4(int8x8_t a, int8x8_t b) { + return __riscv_pmul_b11_i16x4(a, b); +} + +// CHECK-LABEL: test_pmulu_b00_u16x4: +// RV32-COUNT-2: pmulu.h.b00 +// RV64: pmulu.h.b00 +uint16x4_t test_pmulu_b00_u16x4(uint8x8_t a, uint8x8_t b) { + return __riscv_pmulu_b00_u16x4(a, b); +} + +// CHECK-LABEL: test_pmulu_b01_u16x4: +// RV32-COUNT-2: pmulu.h.b01 +// RV64: pmulu.h.b01 +uint16x4_t test_pmulu_b01_u16x4(uint8x8_t a, uint8x8_t b) { + return __riscv_pmulu_b01_u16x4(a, b); +} + +// CHECK-LABEL: test_pmulu_b11_u16x4: +// RV32-COUNT-2: pmulu.h.b11 +// RV64: pmulu.h.b11 +uint16x4_t test_pmulu_b11_u16x4(uint8x8_t a, uint8x8_t b) { + return __riscv_pmulu_b11_u16x4(a, b); +} + +// CHECK-LABEL: test_pmulsu_b00_i16x4: +// RV32-COUNT-2: pmulsu.h.b00 +// RV64: pmulsu.h.b00 +int16x4_t test_pmulsu_b00_i16x4(int8x8_t a, uint8x8_t b) { + return __riscv_pmulsu_b00_i16x4(a, b); +} + +// CHECK-LABEL: test_pmulsu_b11_i16x4: +// RV32-COUNT-2: pmulsu.h.b11 +// RV64: pmulsu.h.b11 +int16x4_t test_pmulsu_b11_i16x4(int8x8_t a, uint8x8_t b) { + return __riscv_pmulsu_b11_i16x4(a, b); +} + +// CHECK-LABEL: test_pmul_h00_i32x2: +// RV32-COUNT-2: mul.h00 +// RV64: pmul.w.h00 +int32x2_t test_pmul_h00_i32x2(int16x4_t a, int16x4_t b) { + return __riscv_pmul_h00_i32x2(a, b); +} + +// CHECK-LABEL: test_pmul_h01_i32x2: +// RV32-COUNT-2: mul.h01 +// RV64: pmul.w.h01 +int32x2_t test_pmul_h01_i32x2(int16x4_t a, int16x4_t b) { + return __riscv_pmul_h01_i32x2(a, b); +} + +// CHECK-LABEL: test_pmul_h11_i32x2: +// RV32-COUNT-2: mul.h11 +// RV64: pmul.w.h11 +int32x2_t test_pmul_h11_i32x2(int16x4_t a, int16x4_t b) { + return __riscv_pmul_h11_i32x2(a, b); +} + +// CHECK-LABEL: test_pmulu_h00_u32x2: +// RV32-COUNT-2: mulu.h00 +// RV64: pmulu.w.h00 +uint32x2_t test_pmulu_h00_u32x2(uint16x4_t a, uint16x4_t b) { + return __riscv_pmulu_h00_u32x2(a, b); +} + +// CHECK-LABEL: test_pmulu_h01_u32x2: +// RV32-COUNT-2: mulu.h01 +// RV64: pmulu.w.h01 +uint32x2_t test_pmulu_h01_u32x2(uint16x4_t a, uint16x4_t b) { + return __riscv_pmulu_h01_u32x2(a, b); +} + +// CHECK-LABEL: test_pmulu_h11_u32x2: +// RV32-COUNT-2: mulu.h11 +// RV64: pmulu.w.h11 +uint32x2_t test_pmulu_h11_u32x2(uint16x4_t a, uint16x4_t b) { + return __riscv_pmulu_h11_u32x2(a, b); +} + +// CHECK-LABEL: test_pmulsu_h00_i32x2: +// RV32-COUNT-2: mulsu.h00 +// RV64: pmulsu.w.h00 +int32x2_t test_pmulsu_h00_i32x2(int16x4_t a, uint16x4_t b) { + return __riscv_pmulsu_h00_i32x2(a, b); +} + +// CHECK-LABEL: test_pmulsu_h11_i32x2: +// RV32-COUNT-2: mulsu.h11 +// RV64: pmulsu.w.h11 +int32x2_t test_pmulsu_h11_i32x2(int16x4_t a, uint16x4_t b) { + return __riscv_pmulsu_h11_i32x2(a, b); +} + +// CHECK-LABEL: test_mul_w00_i64: +// RV32: wmul{{[[:space:]]}} +// RV64: mul.w00 +int64_t test_mul_w00_i64(int32x2_t a, int32x2_t b) { + return __riscv_mul_w00_i64(a, b); +} + +// CHECK-LABEL: test_mul_w01_i64: +// RV32: wmul{{[[:space:]]}} +// RV64: mul.w01 +int64_t test_mul_w01_i64(int32x2_t a, int32x2_t b) { + return __riscv_mul_w01_i64(a, b); +} + +// CHECK-LABEL: test_mul_w11_i64: +// RV32: wmul{{[[:space:]]}} +// RV64: mul.w11 +int64_t test_mul_w11_i64(int32x2_t a, int32x2_t b) { + return __riscv_mul_w11_i64(a, b); +} + +// CHECK-LABEL: test_mulu_w00_u64: +// RV32: wmulu{{[[:space:]]}} +// RV64: mulu.w00 +uint64_t test_mulu_w00_u64(uint32x2_t a, uint32x2_t b) { + return __riscv_mulu_w00_u64(a, b); +} + +// CHECK-LABEL: test_mulu_w01_u64: +// RV32: wmulu{{[[:space:]]}} +// RV64: mulu.w01 +uint64_t test_mulu_w01_u64(uint32x2_t a, uint32x2_t b) { + return __riscv_mulu_w01_u64(a, b); +} + +// CHECK-LABEL: test_mulu_w11_u64: +// RV32: wmulu{{[[:space:]]}} +// RV64: mulu.w11 +uint64_t test_mulu_w11_u64(uint32x2_t a, uint32x2_t b) { + return __riscv_mulu_w11_u64(a, b); +} + +// CHECK-LABEL: test_mulsu_w00_i64: +// RV32: wmulsu{{[[:space:]]}} +// RV64: mulsu.w00 +int64_t test_mulsu_w00_i64(int32x2_t a, uint32x2_t b) { + return __riscv_mulsu_w00_i64(a, b); +} + +// CHECK-LABEL: test_mulsu_w11_i64: +// RV32: wmulsu{{[[:space:]]}} +// RV64: mulsu.w11 +int64_t test_mulsu_w11_i64(int32x2_t a, uint32x2_t b) { + return __riscv_mulsu_w11_i64(a, b); +} diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td index 8fa0ee78ca2a5..a8518ba4cdbc1 100644 --- a/llvm/include/llvm/IR/IntrinsicsRISCV.td +++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td @@ -2124,6 +2124,36 @@ class RVPBinaryIntrinsic def int_riscv_pmhraccu : RVPTernaryIntrinsic; def int_riscv_pmhaccsu : RVPTernaryIntrinsic; def int_riscv_pmhraccsu : RVPTernaryIntrinsic; + // Packed Multiply Parts. The packed forms multiply the selected element of + // every pair, so the operands are the result with each element split in two. + class RVPPackedMulPartsIntrinsic + : DefaultAttrsIntrinsic<[llvm_anyvector_ty], + [LLVMSubdivide2VectorType<0>, + LLVMSubdivide2VectorType<0>], + [IntrNoMem, IntrSpeculatable]>; + def int_riscv_pmul_00 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmul_01 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmul_11 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmulu_00 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmulu_01 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmulu_11 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmulsu_00 : RVPPackedMulPartsIntrinsic; + def int_riscv_pmulsu_11 : RVPPackedMulPartsIntrinsic; + + // The scalar forms select one element from each packed operand and keep that + // single product: <2 x i16> pairs with i32 and <2 x i32> with i64. + class RVPScalarMulPartsIntrinsic + : DefaultAttrsIntrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, LLVMMatchType<1>], + [IntrNoMem, IntrSpeculatable]>; + def int_riscv_mul_00 : RVPScalarMulPartsIntrinsic; + def int_riscv_mul_01 : RVPScalarMulPartsIntrinsic; + def int_riscv_mul_11 : RVPScalarMulPartsIntrinsic; + def int_riscv_mulu_00 : RVPScalarMulPartsIntrinsic; + def int_riscv_mulu_01 : RVPScalarMulPartsIntrinsic; + def int_riscv_mulu_11 : RVPScalarMulPartsIntrinsic; + def int_riscv_mulsu_00 : RVPScalarMulPartsIntrinsic; + def int_riscv_mulsu_11 : RVPScalarMulPartsIntrinsic; // Packed Absolute Difference Sum. def int_riscv_pabdsumu diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index b87e417356186..ec0d3d43bca9c 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -12273,6 +12273,67 @@ static unsigned getRVPMulHighAccumulateOpcode(unsigned IntNo) { } } +struct RVPMulPartsForms { + Intrinsic::ID Packed; + Intrinsic::ID Scalar; +}; + +static RVPMulPartsForms getRVPMulPartsForms(unsigned IntNo) { + switch (IntNo) { + default: + llvm_unreachable("Unexpected RISC-V multiply-parts intrinsic"); + case Intrinsic::riscv_pmul_00: + case Intrinsic::riscv_mul_00: + return {Intrinsic::riscv_pmul_00, Intrinsic::riscv_mul_00}; + case Intrinsic::riscv_pmul_01: + case Intrinsic::riscv_mul_01: + return {Intrinsic::riscv_pmul_01, Intrinsic::riscv_mul_01}; + case Intrinsic::riscv_pmul_11: + case Intrinsic::riscv_mul_11: + return {Intrinsic::riscv_pmul_11, Intrinsic::riscv_mul_11}; + case Intrinsic::riscv_pmulu_00: + case Intrinsic::riscv_mulu_00: + return {Intrinsic::riscv_pmulu_00, Intrinsic::riscv_mulu_00}; + case Intrinsic::riscv_pmulu_01: + case Intrinsic::riscv_mulu_01: + return {Intrinsic::riscv_pmulu_01, Intrinsic::riscv_mulu_01}; + case Intrinsic::riscv_pmulu_11: + case Intrinsic::riscv_mulu_11: + return {Intrinsic::riscv_pmulu_11, Intrinsic::riscv_mulu_11}; + case Intrinsic::riscv_pmulsu_00: + case Intrinsic::riscv_mulsu_00: + return {Intrinsic::riscv_pmulsu_00, Intrinsic::riscv_mulsu_00}; + case Intrinsic::riscv_pmulsu_11: + case Intrinsic::riscv_mulsu_11: + return {Intrinsic::riscv_pmulsu_11, Intrinsic::riscv_mulsu_11}; + } +} + +/// Return {opcode, rs1 lane, rs2 lane} for the word form of \p IntNo. +static std::tuple<unsigned, unsigned, unsigned> +getRVPWordMulPartsOpcodeAndLanes(unsigned IntNo) { + switch (IntNo) { + default: + llvm_unreachable("Unexpected RISC-V multiply-parts intrinsic"); + case Intrinsic::riscv_mul_00: + return {ISD::SMUL_LOHI, 0, 0}; + case Intrinsic::riscv_mul_01: + return {ISD::SMUL_LOHI, 0, 1}; + case Intrinsic::riscv_mul_11: + return {ISD::SMUL_LOHI, 1, 1}; + case Intrinsic::riscv_mulu_00: + return {ISD::UMUL_LOHI, 0, 0}; + case Intrinsic::riscv_mulu_01: + return {ISD::UMUL_LOHI, 0, 1}; + case Intrinsic::riscv_mulu_11: + return {ISD::UMUL_LOHI, 1, 1}; + case Intrinsic::riscv_mulsu_00: + return {RISCVISD::WMULSU, 0, 0}; + case Intrinsic::riscv_mulsu_11: + return {RISCVISD::WMULSU, 1, 1}; + } +} + SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const { unsigned IntNo = Op.getConstantOperandVal(0); @@ -12301,6 +12362,36 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, EVT PtrVT = getPointerTy(DAG.getDataLayout()); return DAG.getRegister(RISCV::X4, PtrVT); } + case Intrinsic::riscv_pmul_00: + case Intrinsic::riscv_pmul_01: + case Intrinsic::riscv_pmul_11: + case Intrinsic::riscv_pmulu_00: + case Intrinsic::riscv_pmulu_01: + case Intrinsic::riscv_pmulu_11: + case Intrinsic::riscv_pmulsu_00: + case Intrinsic::riscv_pmulsu_11: { + // On RV32 a 64-bit result lives in a GPR pair; compute each half with the + // 32-bit form of the same product. + MVT VT = Op.getSimpleValueType(); + if (!Subtarget.isPExtPackedDoubleType(VT)) + return SDValue(); + + bool IsSingleProduct = VT == MVT::v2i32; + MVT HalfVT = IsSingleProduct ? MVT::i32 : VT.getHalfNumVectorElementsVT(); + SDValue Id = IsSingleProduct + ? DAG.getTargetConstant(getRVPMulPartsForms(IntNo).Scalar, + DL, MVT::i32) + : Op.getOperand(0); + auto [Rs1Lo, Rs1Hi] = DAG.SplitVector(Op.getOperand(1), DL); + auto [Rs2Lo, Rs2Hi] = DAG.SplitVector(Op.getOperand(2), DL); + SDValue Lo = + DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, HalfVT, Id, Rs1Lo, Rs2Lo); + SDValue Hi = + DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, HalfVT, Id, Rs1Hi, Rs2Hi); + return DAG.getNode(IsSingleProduct ? ISD::BUILD_VECTOR + : ISD::CONCAT_VECTORS, + DL, VT, Lo, Hi); + } case Intrinsic::riscv_pas: case Intrinsic::riscv_psa: case Intrinsic::riscv_psas: @@ -16753,6 +16844,71 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, Results.push_back(DAG.getExtractSubvector(DL, VT, Res, 0)); return; } + case Intrinsic::riscv_pmul_00: + case Intrinsic::riscv_pmul_01: + case Intrinsic::riscv_pmul_11: + case Intrinsic::riscv_pmulu_00: + case Intrinsic::riscv_pmulu_01: + case Intrinsic::riscv_pmulu_11: + case Intrinsic::riscv_pmulsu_00: + case Intrinsic::riscv_pmulsu_11: { + MVT VT = N->getSimpleValueType(0); + if (!Subtarget.is64Bit() || VT != MVT::v2i16) + return; + + SDValue Undef = DAG.getUNDEF(MVT::v4i8); + SDValue Rs1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8, + N->getOperand(1), Undef); + SDValue Rs2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v8i8, + N->getOperand(2), Undef); + SDValue Res = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v4i16, + N->getOperand(0), Rs1, Rs2); + Results.push_back(DAG.getExtractSubvector(DL, VT, Res, 0)); + return; + } + case Intrinsic::riscv_mul_00: + case Intrinsic::riscv_mul_01: + case Intrinsic::riscv_mul_11: + case Intrinsic::riscv_mulu_00: + case Intrinsic::riscv_mulu_01: + case Intrinsic::riscv_mulu_11: + case Intrinsic::riscv_mulsu_00: + case Intrinsic::riscv_mulsu_11: { + // mul.hXX exists only on RV32 and mul.wXX only on RV64; the other XLEN + // has to build the product here. + MVT VT = N->getSimpleValueType(0); + MVT SrcVT = N->getOperand(1).getSimpleValueType(); + if (Subtarget.hasStdExtP() && Subtarget.is64Bit() && VT == MVT::i32 && + SrcVT == MVT::v2i16) { + // The halfword product is the first element of the packed one. + SDValue Undef = DAG.getUNDEF(SrcVT); + SDValue Rs1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16, + N->getOperand(1), Undef); + SDValue Rs2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16, + N->getOperand(2), Undef); + SDValue Id = DAG.getTargetConstant(getRVPMulPartsForms(IntNo).Packed, + DL, MVT::i32); + SDValue Res = + DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::v2i32, Id, Rs1, Rs2); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, + DAG.getBitcast(MVT::i64, Res))); + return; + } + if (Subtarget.hasStdExtP() && !Subtarget.is64Bit() && VT == MVT::i64 && + SrcVT == MVT::v2i32) { + auto [Opc, Rs1Lane, Rs2Lane] = getRVPWordMulPartsOpcodeAndLanes(IntNo); + SDValue Rs1 = + DAG.getExtractVectorElt(DL, MVT::i32, N->getOperand(1), Rs1Lane); + SDValue Rs2 = + DAG.getExtractVectorElt(DL, MVT::i32, N->getOperand(2), Rs2Lane); + SDValue Res = + DAG.getNode(Opc, DL, DAG.getVTList(MVT::i32, MVT::i32), Rs1, Rs2); + Results.push_back( + DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Res, Res.getValue(1))); + return; + } + reportFatalUsageError("unsupported llvm.riscv multiply-parts intrinsic"); + } case Intrinsic::riscv_paadd: case Intrinsic::riscv_paaddu: case Intrinsic::riscv_pasub: diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td index 0e3db705706b1..837d7f4347711 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td @@ -1785,6 +1785,10 @@ class PatAbdSum<SDPatternOperator OpNode, RVInst Inst, ValueType VecVT> class PatAbdSumAcc<SDPatternOperator OpNode, RVInst Inst, ValueType VecVT> : Pat<(XLenVT (OpNode (XLenVT GPR:$rd), (VecVT GPR:$rs1), (VecVT GPR:$rs2))), (Inst GPR:$rd, GPR:$rs1, GPR:$rs2)>; +class PatMulParts<SDPatternOperator OpNode, RVInst Inst, ValueType ResultVT, + ValueType SourceVT> + : Pat<(ResultVT (OpNode (SourceVT GPR:$rs1), (SourceVT GPR:$rs2))), + (Inst GPR:$rs1, GPR:$rs2)>; class PatGprGprGpr<SDPatternOperator OpNode, RVInst Inst, ValueType VT> : Pat<(VT (OpNode (VT GPR:$rd), (VT GPR:$rs1), (VT GPR:$rs2))), @@ -2267,7 +2271,27 @@ let Predicates = [HasStdExtP] in { def : Pat<(XLenVecI16VT (riscv_ppairoe_h GPR:$rs1, GPR:$rs2)), (PPAIROE_H GPR:$rs1, GPR:$rs2)>; + // Packed byte multiply-parts patterns. + def : PatMulParts<int_riscv_pmul_00, PMUL_H_B00, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmul_01, PMUL_H_B01, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmul_11, PMUL_H_B11, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmulu_00, PMULU_H_B00, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmulu_01, PMULU_H_B01, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmulu_11, PMULU_H_B11, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmulsu_00, PMULSU_H_B00, XLenVecI16VT, XLenVecI8VT>; + def : PatMulParts<int_riscv_pmulsu_11, PMULSU_H_B11, XLenVecI16VT, XLenVecI8VT>; + let append Predicates = [IsRV32] in { + // Scalar halfword multiply-parts patterns. + def : PatMulParts<int_riscv_mul_00, MUL_H00, i32, v2i16>; + def : PatMulParts<int_riscv_mul_01, MUL_H01, i32, v2i16>; + def : PatMulParts<int_riscv_mul_11, MUL_H11, i32, v2i16>; + def : PatMulParts<int_riscv_mulu_00, MULU_H00, i32, v2i16>; + def : PatMulParts<int_riscv_mulu_01, MULU_H01, i32, v2i16>; + def : PatMulParts<int_riscv_mulu_11, MULU_H11, i32, v2i16>; + def : PatMulParts<int_riscv_mulsu_00, MULSU_H00, i32, v2i16>; + def : PatMulParts<int_riscv_mulsu_11, MULSU_H11, i32, v2i16>; + def : PatGpr<bitreverse, REV_RV32>; def : Pat<(XLenVT (riscv_sati GPR:$rs1, timm:$imm)), @@ -2839,6 +2863,26 @@ let append Predicates = [IsRV64] in { def : PatGprGpr<riscv_asub, PASUB_W, v2i32>; def : PatGprGpr<riscv_asubu, PASUBU_W, v2i32>; + // Packed halfword multiply-parts patterns. + def : PatMulParts<int_riscv_pmul_00, PMUL_W_H00, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmul_01, PMUL_W_H01, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmul_11, PMUL_W_H11, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmulu_00, PMULU_W_H00, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmulu_01, PMULU_W_H01, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmulu_11, PMULU_W_H11, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmulsu_00, PMULSU_W_H00, v2i32, v4i16>; + def : PatMulParts<int_riscv_pmulsu_11, PMULSU_W_H11, v2i32, v4i16>; + + // Scalar word multiply-parts patterns. + def : PatMulParts<int_riscv_mul_00, MUL_W00, i64, v2i32>; + def : PatMulParts<int_riscv_mul_01, MUL_W01, i64, v2i32>; + def : PatMulParts<int_riscv_mul_11, MUL_W11, i64, v2i32>; + def : PatMulParts<int_riscv_mulu_00, MULU_W00, i64, v2i32>; + def : PatMulParts<int_riscv_mulu_01, MULU_W01, i64, v2i32>; + def : PatMulParts<int_riscv_mulu_11, MULU_W11, i64, v2i32>; + def : PatMulParts<int_riscv_mulsu_00, MULSU_W00, i64, v2i32>; + def : PatMulParts<int_riscv_mulsu_11, MULSU_W11, i64, v2i32>; + // 32-bit multiply high patterns def : PatGprGpr<mulhs, PMULH_W, v2i32>; def : PatGprGpr<mulhu, PMULHU_W, v2i32>; diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll index d38012912872d..45b8d3ae54de5 100644 --- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll +++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll @@ -3156,3 +3156,205 @@ define <2 x i16> @test_pnclipup_v2i16(i32 %a, i32 %b) { %r = call <2 x i16> @llvm.riscv.pnclipup.v2i16.i32(i32 %a, i32 %b) ret <2 x i16> %r } + +; Packed Multiply Parts. +declare <2 x i16> @llvm.riscv.pmul.00.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmul.01.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmul.11.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmulu.00.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmulu.01.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmulu.11.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmulsu.00.v2i16(<4 x i8>, <4 x i8>) +declare <2 x i16> @llvm.riscv.pmulsu.11.v2i16(<4 x i8>, <4 x i8>) +declare i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mul.01.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mul.11.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mulu.00.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mulu.01.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mulu.11.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mulsu.00.i32.v2i16(<2 x i16>, <2 x i16>) +declare i32 @llvm.riscv.mulsu.11.i32.v2i16(<2 x i16>, <2 x i16>) + +define <2 x i16> @test_pmul_b00_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmul_b00_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmul.h.b00 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmul.00.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmul_b01_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmul_b01_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmul.h.b01 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmul.01.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmul_b11_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmul_b11_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmul.h.b11 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmul.11.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmulu_b00_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmulu_b00_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmulu.h.b00 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmulu.00.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmulu_b01_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmulu_b01_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmulu.h.b01 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmulu.01.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmulu_b11_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmulu_b11_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmulu.h.b11 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmulu.11.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmulsu_b00_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmulsu_b00_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmulsu.h.b00 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmulsu.00.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define <2 x i16> @test_pmulsu_b11_v2i16(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: test_pmulsu_b11_v2i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pmulsu.h.b11 a0, a0, a1 +; CHECK-NEXT: ret + %r = call <2 x i16> @llvm.riscv.pmulsu.11.v2i16(<4 x i8> %a, <4 x i8> %b) + ret <2 x i16> %r +} + +define i32 @test_mul_h00_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mul_h00_i32: +; RV32: # %bb.0: +; RV32-NEXT: mul.h00 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mul_h00_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmul.w.h00 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mul_h01_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mul_h01_i32: +; RV32: # %bb.0: +; RV32-NEXT: mul.h01 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mul_h01_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmul.w.h01 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mul.01.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mul_h11_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mul_h11_i32: +; RV32: # %bb.0: +; RV32-NEXT: mul.h11 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mul_h11_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmul.w.h11 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mul.11.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mulu_h00_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mulu_h00_i32: +; RV32: # %bb.0: +; RV32-NEXT: mulu.h00 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulu_h00_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.w.h00 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mulu.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mulu_h01_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mulu_h01_i32: +; RV32: # %bb.0: +; RV32-NEXT: mulu.h01 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulu_h01_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.w.h01 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mulu.01.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mulu_h11_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mulu_h11_i32: +; RV32: # %bb.0: +; RV32-NEXT: mulu.h11 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulu_h11_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.w.h11 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mulu.11.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mulsu_h00_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mulsu_h00_i32: +; RV32: # %bb.0: +; RV32-NEXT: mulsu.h00 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulsu_h00_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulsu.w.h00 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mulsu.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} + +define i32 @test_mulsu_h11_i32(<2 x i16> %a, <2 x i16> %b) { +; RV32-LABEL: test_mulsu_h11_i32: +; RV32: # %bb.0: +; RV32-NEXT: mulsu.h11 a0, a0, a1 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulsu_h11_i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulsu.w.h11 a0, a0, a1 +; RV64-NEXT: ret + %r = call i32 @llvm.riscv.mulsu.11.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %r +} diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll index 96f16c3d52103..bbee8cb3a52da 100644 --- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll +++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll @@ -6936,3 +6936,381 @@ define i64 @test_pnclipup_v2i32(i64 %a, i64 %b) { %s = bitcast <2 x i32> %r to i64 ret i64 %s } + +; Packed Multiply Parts. +declare <4 x i16> @llvm.riscv.pmul.00.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmul.01.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmul.11.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmulu.00.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmulu.01.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmulu.11.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmulsu.00.v4i16(<8 x i8>, <8 x i8>) +declare <4 x i16> @llvm.riscv.pmulsu.11.v4i16(<8 x i8>, <8 x i8>) +declare <2 x i32> @llvm.riscv.pmul.00.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmul.01.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmul.11.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmulu.00.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmulu.01.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmulu.11.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmulsu.00.v2i32(<4 x i16>, <4 x i16>) +declare <2 x i32> @llvm.riscv.pmulsu.11.v2i32(<4 x i16>, <4 x i16>) +declare i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mul.01.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mul.11.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mulu.00.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mulu.01.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mulu.11.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mulsu.00.i64.v2i32(<2 x i32>, <2 x i32>) +declare i64 @llvm.riscv.mulsu.11.i64.v2i32(<2 x i32>, <2 x i32>) + +define <4 x i16> @test_pmul_b00_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmul_b00_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmul.h.b00 a1, a1, a3 +; RV32-NEXT: pmul.h.b00 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmul_b00_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmul.h.b00 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmul.00.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmul_b01_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmul_b01_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmul.h.b01 a1, a1, a3 +; RV32-NEXT: pmul.h.b01 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmul_b01_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmul.h.b01 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmul.01.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmul_b11_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmul_b11_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmul.h.b11 a1, a1, a3 +; RV32-NEXT: pmul.h.b11 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmul_b11_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmul.h.b11 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmul.11.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmulu_b00_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmulu_b00_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmulu.h.b00 a1, a1, a3 +; RV32-NEXT: pmulu.h.b00 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulu_b00_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.h.b00 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmulu.00.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmulu_b01_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmulu_b01_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmulu.h.b01 a1, a1, a3 +; RV32-NEXT: pmulu.h.b01 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulu_b01_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.h.b01 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmulu.01.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmulu_b11_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmulu_b11_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmulu.h.b11 a1, a1, a3 +; RV32-NEXT: pmulu.h.b11 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulu_b11_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.h.b11 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmulu.11.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmulsu_b00_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmulsu_b00_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmulsu.h.b00 a1, a1, a3 +; RV32-NEXT: pmulsu.h.b00 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulsu_b00_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmulsu.h.b00 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmulsu.00.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <4 x i16> @test_pmulsu_b11_v4i16(<8 x i8> %a, <8 x i8> %b) { +; RV32-LABEL: test_pmulsu_b11_v4i16: +; RV32: # %bb.0: +; RV32-NEXT: pmulsu.h.b11 a1, a1, a3 +; RV32-NEXT: pmulsu.h.b11 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulsu_b11_v4i16: +; RV64: # %bb.0: +; RV64-NEXT: pmulsu.h.b11 a0, a0, a1 +; RV64-NEXT: ret + %r = call <4 x i16> @llvm.riscv.pmulsu.11.v4i16(<8 x i8> %a, <8 x i8> %b) + ret <4 x i16> %r +} + +define <2 x i32> @test_pmul_h00_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmul_h00_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mul.h00 a1, a1, a3 +; RV32-NEXT: mul.h00 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmul_h00_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmul.w.h00 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmul.00.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmul_h01_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmul_h01_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mul.h01 a1, a1, a3 +; RV32-NEXT: mul.h01 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmul_h01_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmul.w.h01 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmul.01.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmul_h11_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmul_h11_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mul.h11 a1, a1, a3 +; RV32-NEXT: mul.h11 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmul_h11_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmul.w.h11 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmul.11.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmulu_h00_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmulu_h00_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mulu.h00 a1, a1, a3 +; RV32-NEXT: mulu.h00 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulu_h00_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.w.h00 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmulu.00.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmulu_h01_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmulu_h01_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mulu.h01 a1, a1, a3 +; RV32-NEXT: mulu.h01 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulu_h01_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.w.h01 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmulu.01.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmulu_h11_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmulu_h11_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mulu.h11 a1, a1, a3 +; RV32-NEXT: mulu.h11 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulu_h11_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulu.w.h11 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmulu.11.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmulsu_h00_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmulsu_h00_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mulsu.h00 a1, a1, a3 +; RV32-NEXT: mulsu.h00 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulsu_h00_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulsu.w.h00 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmulsu.00.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define <2 x i32> @test_pmulsu_h11_v2i32(<4 x i16> %a, <4 x i16> %b) { +; RV32-LABEL: test_pmulsu_h11_v2i32: +; RV32: # %bb.0: +; RV32-NEXT: mulsu.h11 a1, a1, a3 +; RV32-NEXT: mulsu.h11 a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_pmulsu_h11_v2i32: +; RV64: # %bb.0: +; RV64-NEXT: pmulsu.w.h11 a0, a0, a1 +; RV64-NEXT: ret + %r = call <2 x i32> @llvm.riscv.pmulsu.11.v2i32(<4 x i16> %a, <4 x i16> %b) + ret <2 x i32> %r +} + +define i64 @test_mul_w00_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mul_w00_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmul a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mul_w00_i64: +; RV64: # %bb.0: +; RV64-NEXT: mul.w00 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mul_w01_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mul_w01_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmul a0, a0, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mul_w01_i64: +; RV64: # %bb.0: +; RV64-NEXT: mul.w01 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mul.01.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mul_w11_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mul_w11_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmul a0, a1, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mul_w11_i64: +; RV64: # %bb.0: +; RV64-NEXT: mul.w11 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mul.11.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mulu_w00_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mulu_w00_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmulu a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulu_w00_i64: +; RV64: # %bb.0: +; RV64-NEXT: mulu.w00 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mulu.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mulu_w01_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mulu_w01_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmulu a0, a0, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulu_w01_i64: +; RV64: # %bb.0: +; RV64-NEXT: mulu.w01 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mulu.01.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mulu_w11_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mulu_w11_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmulu a0, a1, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulu_w11_i64: +; RV64: # %bb.0: +; RV64-NEXT: mulu.w11 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mulu.11.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mulsu_w00_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mulsu_w00_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmulsu a0, a0, a2 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulsu_w00_i64: +; RV64: # %bb.0: +; RV64-NEXT: mulsu.w00 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mulsu.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} + +define i64 @test_mulsu_w11_i64(<2 x i32> %a, <2 x i32> %b) { +; RV32-LABEL: test_mulsu_w11_i64: +; RV32: # %bb.0: +; RV32-NEXT: wmulsu a0, a1, a3 +; RV32-NEXT: ret +; +; RV64-LABEL: test_mulsu_w11_i64: +; RV64: # %bb.0: +; RV64-NEXT: mulsu.w11 a0, a0, a1 +; RV64-NEXT: ret + %r = call i64 @llvm.riscv.mulsu.11.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %r +} diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll b/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll index 28b1d7c53a6e7..20858559a4521 100644 --- a/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll +++ b/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll @@ -7,9 +7,16 @@ ; RUN: sed -n '/^; BEGIN-PZEXT$/,/^; END-PZEXT$/p' %s \ ; RUN: | not llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \ ; RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=PZEXT +; RUN: sed -n '/^; BEGIN-MUL-H$/,/^; END-MUL-H$/p' %s \ +; RUN: | not llc -mtriple=riscv64 -mattr=+m \ +; RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=MULPARTS +; RUN: sed -n '/^; BEGIN-MUL-W$/,/^; END-MUL-W$/p' %s \ +; RUN: | not llc -mtriple=riscv32 -mattr=+v,+m \ +; RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=MULPARTS ; PSEXT: LLVM ERROR: unsupported llvm.riscv.psext intrinsic ; PZEXT: LLVM ERROR: unsupported llvm.riscv.pzext intrinsic +; MULPARTS: LLVM ERROR: unsupported llvm.riscv multiply-parts intrinsic ; BEGIN-PSEXT-LEGAL define <4 x i16> @bad_psext_legal_type(<4 x i16> %a) { @@ -37,3 +44,22 @@ define <2 x i32> @bad_pzext(<2 x i32> %a) { declare <2 x i32> @llvm.riscv.pzext.b.v2i32(<2 x i32>) ; END-PZEXT + +; The multiply-parts intrinsics are only legalizable with the P extension. +; BEGIN-MUL-H +define i32 @bad_mul_h00_without_p(<2 x i16> %a, <2 x i16> %b) { + %res = call i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16> %a, <2 x i16> %b) + ret i32 %res +} + +declare i32 @llvm.riscv.mul.00.i32.v2i16(<2 x i16>, <2 x i16>) +; END-MUL-H + +; BEGIN-MUL-W +define i64 @bad_mul_w00_without_p(<2 x i32> %a, <2 x i32> %b) { + %res = call i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32> %a, <2 x i32> %b) + ret i64 %res +} + +declare i64 @llvm.riscv.mul.00.i64.v2i32(<2 x i32>, <2 x i32>) +; END-MUL-W _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
