[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:
Yeting Kuo 2022-12-09 16:20:04 +08:00
parent f02e378275
commit 47b9da72e0
12 changed files with 7165 additions and 1 deletions

View File

@ -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

View File

@ -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.

View File

@ -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>,

View File

@ -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)

View File

@ -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);

View File

@ -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:

View File

@ -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 {

View File

@ -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.

View File

@ -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},

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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"