[VP][RISCV] Add vp.bitreverse and RISC-V support.
The patch also added function expandVPBITREVERSE to expand ISD::VP_BITREVERSE nodes. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D139697
This commit is contained in:
parent
f02e378275
commit
47b9da72e0
@ -15216,6 +15216,8 @@ Bit Manipulation Intrinsics
|
||||
LLVM provides intrinsics for a few important bit manipulation
|
||||
operations. These allow efficient code generation for some algorithms.
|
||||
|
||||
.. _int_bitreverse:
|
||||
|
||||
'``llvm.bitreverse.*``' Intrinsics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -22066,6 +22068,53 @@ Examples:
|
||||
%t = call <4 x float> @llvm.trunc.v4f32(<4 x float> %a)
|
||||
%also.r = select <4 x i1> %mask, <4 x float> %t, <4 x float> poison
|
||||
|
||||
.. _int_vp_bitreverse:
|
||||
|
||||
'``llvm.vp.bitreverse.*``' Intrinsics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
This is an overloaded intrinsic.
|
||||
|
||||
::
|
||||
|
||||
declare <16 x i32> @llvm.vp.bitreverse.v16i32 (<16 x i32> <op>, <16 x i1> <mask>, i32 <vector_length>)
|
||||
declare <vscale x 4 x i32> @llvm.vp.bitreverse.nxv4i32 (<vscale x 4 x i32> <op>, <vscale x 4 x i1> <mask>, i32 <vector_length>)
|
||||
declare <256 x i64> @llvm.vp.bitreverse.v256i64 (<256 x i64> <op>, <256 x i1> <mask>, i32 <vector_length>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
Predicated bitreverse of a vector of integers.
|
||||
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first operand and the result have the same vector of integer type. The
|
||||
second operand is the vector mask and has the same number of elements as the
|
||||
result vector type. The third operand is the explicit vector length of the
|
||||
operation.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
The '``llvm.vp.bitreverse``' intrinsic performs bitreverse (:ref:`bitreverse <int_bitreverse>`) of the first operand on each
|
||||
enabled lane. The result on disabled lanes is a :ref:`poison value <poisonvalues>`.
|
||||
|
||||
Examples:
|
||||
"""""""""
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
%r = call <4 x i32> @llvm.vp.bitreverse.v4i32(<4 x i32> %a, <4 x i1> %mask, i32 %evl)
|
||||
;; For all lanes below %evl, %r is lane-wise equivalent to %also.r
|
||||
|
||||
%t = call <4 x i32> @llvm.bitreverse.v4i32(<4 x i32> %a)
|
||||
%also.r = select <4 x i1> %mask, <4 x i32> %t, <4 x i32> poison
|
||||
|
||||
|
||||
.. _int_vp_bswap:
|
||||
|
||||
'``llvm.vp.bswap.*``' Intrinsics
|
||||
|
||||
@ -4959,6 +4959,11 @@ public:
|
||||
/// \returns The expansion result or SDValue() if it fails.
|
||||
SDValue expandBITREVERSE(SDNode *N, SelectionDAG &DAG) const;
|
||||
|
||||
/// Expand VP_BITREVERSE nodes. Expands VP_BITREVERSE nodes with
|
||||
/// i8/i16/i32/i64 scalar types. \param N Node to expand \returns The
|
||||
/// expansion result or SDValue() if it fails.
|
||||
SDValue expandVPBITREVERSE(SDNode *N, SelectionDAG &DAG) const;
|
||||
|
||||
/// Turn load of vector type into a load of the individual elements.
|
||||
/// \param LD load to expand
|
||||
/// \returns BUILD_VECTOR and TokenFactor nodes.
|
||||
|
||||
@ -1562,6 +1562,10 @@ let IntrProperties = [IntrNoMem, IntrNoSync, IntrWillReturn] in {
|
||||
[ LLVMMatchType<0>,
|
||||
LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>,
|
||||
llvm_i32_ty]>;
|
||||
def int_vp_bitreverse : DefaultAttrsIntrinsic<[ llvm_anyvector_ty ],
|
||||
[ LLVMMatchType<0>,
|
||||
LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>,
|
||||
llvm_i32_ty]>;
|
||||
def int_vp_fshl : DefaultAttrsIntrinsic<[ llvm_anyvector_ty ],
|
||||
[ LLVMMatchType<0>,
|
||||
LLVMMatchType<0>,
|
||||
|
||||
@ -220,6 +220,10 @@ END_REGISTER_VP(vp_umax, VP_UMAX)
|
||||
BEGIN_REGISTER_VP(vp_bswap, 1, 2, VP_BSWAP, -1)
|
||||
END_REGISTER_VP(vp_bswap, VP_BSWAP)
|
||||
|
||||
// llvm.vp.bitreverse(x,mask,vlen)
|
||||
BEGIN_REGISTER_VP(vp_bitreverse, 1, 2, VP_BITREVERSE, -1)
|
||||
END_REGISTER_VP(vp_bitreverse, VP_BITREVERSE)
|
||||
|
||||
// llvm.vp.fshl(x,y,z,mask,vlen)
|
||||
BEGIN_REGISTER_VP(vp_fshl, 3, 4, VP_FSHL, -1)
|
||||
END_REGISTER_VP(vp_fshl, VP_FSHL)
|
||||
|
||||
@ -788,6 +788,12 @@ void VectorLegalizer::Expand(SDNode *Node, SmallVectorImpl<SDValue> &Results) {
|
||||
case ISD::BITREVERSE:
|
||||
ExpandBITREVERSE(Node, Results);
|
||||
return;
|
||||
case ISD::VP_BITREVERSE:
|
||||
if (SDValue Expanded = TLI.expandVPBITREVERSE(Node, DAG)) {
|
||||
Results.push_back(Expanded);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ISD::CTPOP:
|
||||
if (SDValue Expanded = TLI.expandCTPOP(Node, DAG)) {
|
||||
Results.push_back(Expanded);
|
||||
|
||||
@ -1012,6 +1012,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
|
||||
|
||||
case ISD::ABS:
|
||||
case ISD::BITREVERSE:
|
||||
case ISD::VP_BITREVERSE:
|
||||
case ISD::BSWAP:
|
||||
case ISD::VP_BSWAP:
|
||||
case ISD::CTLZ:
|
||||
@ -4091,6 +4092,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
|
||||
|
||||
case ISD::ABS:
|
||||
case ISD::BITREVERSE:
|
||||
case ISD::VP_BITREVERSE:
|
||||
case ISD::BSWAP:
|
||||
case ISD::VP_BSWAP:
|
||||
case ISD::CTLZ:
|
||||
|
||||
@ -8630,6 +8630,68 @@ SDValue TargetLowering::expandBITREVERSE(SDNode *N, SelectionDAG &DAG) const {
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
SDValue TargetLowering::expandVPBITREVERSE(SDNode *N, SelectionDAG &DAG) const {
|
||||
assert(N->getOpcode() == ISD::VP_BITREVERSE);
|
||||
|
||||
SDLoc dl(N);
|
||||
EVT VT = N->getValueType(0);
|
||||
SDValue Op = N->getOperand(0);
|
||||
SDValue Mask = N->getOperand(1);
|
||||
SDValue EVL = N->getOperand(2);
|
||||
EVT SHVT = getShiftAmountTy(VT, DAG.getDataLayout());
|
||||
unsigned Sz = VT.getScalarSizeInBits();
|
||||
|
||||
SDValue Tmp, Tmp2, Tmp3;
|
||||
|
||||
// If we can, perform BSWAP first and then the mask+swap the i4, then i2
|
||||
// and finally the i1 pairs.
|
||||
// TODO: We can easily support i4/i2 legal types if any target ever does.
|
||||
if (Sz >= 8 && isPowerOf2_32(Sz)) {
|
||||
// Create the masks - repeating the pattern every byte.
|
||||
APInt Mask4 = APInt::getSplat(Sz, APInt(8, 0x0F));
|
||||
APInt Mask2 = APInt::getSplat(Sz, APInt(8, 0x33));
|
||||
APInt Mask1 = APInt::getSplat(Sz, APInt(8, 0x55));
|
||||
|
||||
// BSWAP if the type is wider than a single byte.
|
||||
Tmp = (Sz > 8 ? DAG.getNode(ISD::VP_BSWAP, dl, VT, Op, Mask, EVL) : Op);
|
||||
|
||||
// swap i4: ((V >> 4) & 0x0F) | ((V & 0x0F) << 4)
|
||||
Tmp2 = DAG.getNode(ISD::VP_LSHR, dl, VT, Tmp, DAG.getConstant(4, dl, SHVT),
|
||||
Mask, EVL);
|
||||
Tmp2 = DAG.getNode(ISD::VP_AND, dl, VT, Tmp2,
|
||||
DAG.getConstant(Mask4, dl, VT), Mask, EVL);
|
||||
Tmp3 = DAG.getNode(ISD::VP_AND, dl, VT, Tmp, DAG.getConstant(Mask4, dl, VT),
|
||||
Mask, EVL);
|
||||
Tmp3 = DAG.getNode(ISD::VP_SHL, dl, VT, Tmp3, DAG.getConstant(4, dl, SHVT),
|
||||
Mask, EVL);
|
||||
Tmp = DAG.getNode(ISD::VP_OR, dl, VT, Tmp2, Tmp3, Mask, EVL);
|
||||
|
||||
// swap i2: ((V >> 2) & 0x33) | ((V & 0x33) << 2)
|
||||
Tmp2 = DAG.getNode(ISD::VP_LSHR, dl, VT, Tmp, DAG.getConstant(2, dl, SHVT),
|
||||
Mask, EVL);
|
||||
Tmp2 = DAG.getNode(ISD::VP_AND, dl, VT, Tmp2,
|
||||
DAG.getConstant(Mask2, dl, VT), Mask, EVL);
|
||||
Tmp3 = DAG.getNode(ISD::VP_AND, dl, VT, Tmp, DAG.getConstant(Mask2, dl, VT),
|
||||
Mask, EVL);
|
||||
Tmp3 = DAG.getNode(ISD::VP_SHL, dl, VT, Tmp3, DAG.getConstant(2, dl, SHVT),
|
||||
Mask, EVL);
|
||||
Tmp = DAG.getNode(ISD::VP_OR, dl, VT, Tmp2, Tmp3, Mask, EVL);
|
||||
|
||||
// swap i1: ((V >> 1) & 0x55) | ((V & 0x55) << 1)
|
||||
Tmp2 = DAG.getNode(ISD::VP_LSHR, dl, VT, Tmp, DAG.getConstant(1, dl, SHVT),
|
||||
Mask, EVL);
|
||||
Tmp2 = DAG.getNode(ISD::VP_AND, dl, VT, Tmp2,
|
||||
DAG.getConstant(Mask1, dl, VT), Mask, EVL);
|
||||
Tmp3 = DAG.getNode(ISD::VP_AND, dl, VT, Tmp, DAG.getConstant(Mask1, dl, VT),
|
||||
Mask, EVL);
|
||||
Tmp3 = DAG.getNode(ISD::VP_SHL, dl, VT, Tmp3, DAG.getConstant(1, dl, SHVT),
|
||||
Mask, EVL);
|
||||
Tmp = DAG.getNode(ISD::VP_OR, dl, VT, Tmp2, Tmp3, Mask, EVL);
|
||||
return Tmp;
|
||||
}
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
std::pair<SDValue, SDValue>
|
||||
TargetLowering::scalarizeVectorLoad(LoadSDNode *LD,
|
||||
SelectionDAG &DAG) const {
|
||||
|
||||
@ -613,7 +613,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
|
||||
setOperationAction({ISD::CTTZ, ISD::CTLZ, ISD::CTPOP}, VT, Expand);
|
||||
|
||||
setOperationAction(ISD::BSWAP, VT, Expand);
|
||||
setOperationAction(ISD::VP_BSWAP, VT, Expand);
|
||||
setOperationAction({ISD::VP_BSWAP, ISD::VP_BITREVERSE}, VT, Expand);
|
||||
setOperationAction({ISD::VP_FSHL, ISD::VP_FSHR}, VT, Expand);
|
||||
|
||||
// Custom-lower extensions and truncations from/to mask types.
|
||||
|
||||
@ -641,6 +641,41 @@ static const CostTblEntry VectorIntrinsicCostTable[]{
|
||||
{Intrinsic::bitreverse, MVT::nxv2i64, 52},
|
||||
{Intrinsic::bitreverse, MVT::nxv4i64, 52},
|
||||
{Intrinsic::bitreverse, MVT::nxv8i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::v2i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::v4i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::v8i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::v16i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv1i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv2i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv4i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv8i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv16i8, 17},
|
||||
{Intrinsic::vp_bitreverse, MVT::v2i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::v4i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::v8i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::v16i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv1i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv2i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv4i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv8i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv16i16, 24},
|
||||
{Intrinsic::vp_bitreverse, MVT::v2i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::v4i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::v8i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::v16i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv1i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv2i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv4i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv8i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv16i32, 33},
|
||||
{Intrinsic::vp_bitreverse, MVT::v2i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::v4i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::v8i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::v16i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv1i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv2i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv4i64, 52},
|
||||
{Intrinsic::vp_bitreverse, MVT::nxv8i64, 52},
|
||||
{Intrinsic::ctpop, MVT::v2i8, 12},
|
||||
{Intrinsic::ctpop, MVT::v4i8, 12},
|
||||
{Intrinsic::ctpop, MVT::v8i8, 12},
|
||||
|
||||
3798
llvm/test/CodeGen/RISCV/rvv/bitreverse-vp.ll
Normal file
3798
llvm/test/CodeGen/RISCV/rvv/bitreverse-vp.ll
Normal file
File diff suppressed because it is too large
Load Diff
3197
llvm/test/CodeGen/RISCV/rvv/fixed-vectors-bitreverse-vp.ll
Normal file
3197
llvm/test/CodeGen/RISCV/rvv/fixed-vectors-bitreverse-vp.ll
Normal file
File diff suppressed because it is too large
Load Diff
@ -146,6 +146,8 @@ protected:
|
||||
Str << " declare <8 x i1> @llvm.vp.icmp.v8i16"
|
||||
<< "(<8 x i16>, <8 x i16>, metadata, <8 x i1>, i32) ";
|
||||
|
||||
Str << " declare <8 x i16> @llvm.vp.bitreverse.v8i16"
|
||||
<< "(<8 x i16>, <8 x i1>, i32) ";
|
||||
Str << " declare <8 x i16> @llvm.vp.bswap.v8i16"
|
||||
<< "(<8 x i16>, <8 x i1>, i32) ";
|
||||
Str << " declare <8 x i16> @llvm.vp.fshl.v8i16"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user