Skip to content

Commit f8ee58a

Browse files
authored
[RISCV] Initial codegen support for the XRivosVizip extension (#131933)
This implements initial code generation support for a subset of the xrivosvizip extension. Specifically, this adds support for vzipeven, vzipodd, and vzip2a, but not vzip2b, vunzip2a, or vunzip2b. The others will follow in separate patches. One review note: The zipeven/zipodd matchers were recently rewritten to better match upstream style, so careful review there would be appreciated. The matchers don't yet support type coercion to wider types. This will be done in a future patch.
1 parent 2f5c836 commit f8ee58a

File tree

5 files changed

+575
-6
lines changed

5 files changed

+575
-6
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4563,8 +4563,10 @@ static SDValue getSingleShuffleSrc(MVT VT, SDValue V1, SDValue V2) {
45634563
/// way through the source.
45644564
static bool isInterleaveShuffle(ArrayRef<int> Mask, MVT VT, int &EvenSrc,
45654565
int &OddSrc, const RISCVSubtarget &Subtarget) {
4566-
// We need to be able to widen elements to the next larger integer type.
4567-
if (VT.getScalarSizeInBits() >= Subtarget.getELen())
4566+
// We need to be able to widen elements to the next larger integer type or
4567+
// use the zip2a instruction at e64.
4568+
if (VT.getScalarSizeInBits() >= Subtarget.getELen() &&
4569+
!Subtarget.hasVendorXRivosVizip())
45684570
return false;
45694571

45704572
int Size = Mask.size();
@@ -4621,6 +4623,48 @@ static bool isElementRotate(const std::array<std::pair<int, int>, 2> &SrcInfo,
46214623
SrcInfo[1].second - SrcInfo[0].second == (int)NumElts;
46224624
}
46234625

4626+
static bool isAlternating(const std::array<std::pair<int, int>, 2> &SrcInfo,
4627+
ArrayRef<int> Mask, bool RequiredPolarity) {
4628+
int NumElts = Mask.size();
4629+
for (unsigned i = 0; i != NumElts; ++i) {
4630+
int M = Mask[i];
4631+
if (M < 0)
4632+
continue;
4633+
int Src = M >= NumElts;
4634+
int Diff = (int)i - (M % NumElts);
4635+
bool C = Src == SrcInfo[1].first && Diff == SrcInfo[1].second;
4636+
assert(C != (Src == SrcInfo[0].first && Diff == SrcInfo[0].second) &&
4637+
"Must match exactly one of the two slides");
4638+
if (RequiredPolarity != (C == i % 2))
4639+
return false;
4640+
}
4641+
return true;
4642+
}
4643+
4644+
/// Given a shuffle which can be represented as a pair of two slides,
4645+
/// see if it is a zipeven idiom. Zipeven is:
4646+
/// vs2: a0 a1 a2 a3
4647+
/// vs1: b0 b1 b2 b3
4648+
/// vd: a0 b0 a2 b2
4649+
static bool isZipEven(const std::array<std::pair<int, int>, 2> &SrcInfo,
4650+
ArrayRef<int> Mask) {
4651+
return SrcInfo[0].second == 0 && SrcInfo[1].second == 1 &&
4652+
isAlternating(SrcInfo, Mask, true);
4653+
}
4654+
4655+
/// Given a shuffle which can be represented as a pair of two slides,
4656+
/// see if it is a zipodd idiom. Zipodd is:
4657+
/// vs2: a0 a1 a2 a3
4658+
/// vs1: b0 b1 b2 b3
4659+
/// vd: a1 b1 a3 b3
4660+
/// Note that the operand order is swapped due to the way we canonicalize
4661+
/// the slides, so SrCInfo[0] is vs1, and SrcInfo[1] is vs2.
4662+
static bool isZipOdd(const std::array<std::pair<int, int>, 2> &SrcInfo,
4663+
ArrayRef<int> Mask) {
4664+
return SrcInfo[0].second == 0 && SrcInfo[1].second == -1 &&
4665+
isAlternating(SrcInfo, Mask, false);
4666+
}
4667+
46244668
// Lower a deinterleave shuffle to SRL and TRUNC. Factor must be
46254669
// 2, 4, 8 and the integer type Factor-times larger than VT's
46264670
// element type must be a legal element type.
@@ -4880,6 +4924,34 @@ static bool isSpreadMask(ArrayRef<int> Mask, unsigned Factor, unsigned &Index) {
48804924
return true;
48814925
}
48824926

4927+
static SDValue lowerVZIP(unsigned Opc, SDValue Op0, SDValue Op1,
4928+
const SDLoc &DL, SelectionDAG &DAG,
4929+
const RISCVSubtarget &Subtarget) {
4930+
assert(RISCVISD::RI_VZIPEVEN_VL == Opc || RISCVISD::RI_VZIPODD_VL == Opc ||
4931+
RISCVISD::RI_VZIP2A_VL == Opc);
4932+
assert(Op0.getSimpleValueType() == Op1.getSimpleValueType());
4933+
4934+
MVT VT = Op0.getSimpleValueType();
4935+
MVT IntVT = VT.changeVectorElementTypeToInteger();
4936+
Op0 = DAG.getBitcast(IntVT, Op0);
4937+
Op1 = DAG.getBitcast(IntVT, Op1);
4938+
4939+
MVT ContainerVT = IntVT;
4940+
if (VT.isFixedLengthVector()) {
4941+
ContainerVT = getContainerForFixedLengthVector(DAG, IntVT, Subtarget);
4942+
Op0 = convertToScalableVector(ContainerVT, Op0, DAG, Subtarget);
4943+
Op1 = convertToScalableVector(ContainerVT, Op1, DAG, Subtarget);
4944+
}
4945+
4946+
auto [Mask, VL] = getDefaultVLOps(IntVT, ContainerVT, DL, DAG, Subtarget);
4947+
SDValue Passthru = DAG.getUNDEF(ContainerVT);
4948+
SDValue Res = DAG.getNode(Opc, DL, ContainerVT, Op0, Op1, Passthru, Mask, VL);
4949+
if (IntVT.isFixedLengthVector())
4950+
Res = convertFromScalableVector(IntVT, Res, DAG, Subtarget);
4951+
Res = DAG.getBitcast(VT, Res);
4952+
return Res;
4953+
}
4954+
48834955
// Given a vector a, b, c, d return a vector Factor times longer
48844956
// with Factor-1 undef's between elements. Ex:
48854957
// a, undef, b, undef, c, undef, d, undef (Factor=2, Index=0)
@@ -5619,6 +5691,15 @@ static SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG,
56195691
DAG.getVectorIdxConstant(OddSrc % Size, DL));
56205692
}
56215693

5694+
// Prefer vzip2a if available.
5695+
// TODO: Extend to matching zip2b if EvenSrc and OddSrc allow.
5696+
if (Subtarget.hasVendorXRivosVizip()) {
5697+
EvenV = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT),
5698+
EvenV, DAG.getVectorIdxConstant(0, DL));
5699+
OddV = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), OddV,
5700+
DAG.getVectorIdxConstant(0, DL));
5701+
return lowerVZIP(RISCVISD::RI_VZIP2A_VL, EvenV, OddV, DL, DAG, Subtarget);
5702+
}
56225703
return getWideningInterleave(EvenV, OddV, DL, DAG, Subtarget);
56235704
}
56245705

@@ -5670,6 +5751,18 @@ static SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG,
56705751
return convertFromScalableVector(VT, Res, DAG, Subtarget);
56715752
}
56725753

5754+
if (Subtarget.hasVendorXRivosVizip() && isZipEven(SrcInfo, Mask)) {
5755+
SDValue Src1 = SrcInfo[0].first == 0 ? V1 : V2;
5756+
SDValue Src2 = SrcInfo[1].first == 0 ? V1 : V2;
5757+
return lowerVZIP(RISCVISD::RI_VZIPEVEN_VL, Src1, Src2, DL, DAG,
5758+
Subtarget);
5759+
}
5760+
if (Subtarget.hasVendorXRivosVizip() && isZipOdd(SrcInfo, Mask)) {
5761+
SDValue Src1 = SrcInfo[1].first == 0 ? V1 : V2;
5762+
SDValue Src2 = SrcInfo[0].first == 0 ? V1 : V2;
5763+
return lowerVZIP(RISCVISD::RI_VZIPODD_VL, Src1, Src2, DL, DAG, Subtarget);
5764+
}
5765+
56735766
// Build the mask. Note that vslideup unconditionally preserves elements
56745767
// below the slide amount in the destination, and thus those elements are
56755768
// undefined in the mask. If the mask ends up all true (or undef), it
@@ -6733,7 +6826,7 @@ static bool hasPassthruOp(unsigned Opcode) {
67336826
Opcode <= RISCVISD::LAST_STRICTFP_OPCODE &&
67346827
"not a RISC-V target specific op");
67356828
static_assert(
6736-
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 127 &&
6829+
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 130 &&
67376830
RISCVISD::LAST_STRICTFP_OPCODE - RISCVISD::FIRST_STRICTFP_OPCODE == 21 &&
67386831
"adding target specific op should update this function");
67396832
if (Opcode >= RISCVISD::ADD_VL && Opcode <= RISCVISD::VFMAX_VL)
@@ -6757,12 +6850,13 @@ static bool hasMaskOp(unsigned Opcode) {
67576850
Opcode <= RISCVISD::LAST_STRICTFP_OPCODE &&
67586851
"not a RISC-V target specific op");
67596852
static_assert(
6760-
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 127 &&
6853+
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 130 &&
67616854
RISCVISD::LAST_STRICTFP_OPCODE - RISCVISD::FIRST_STRICTFP_OPCODE == 21 &&
67626855
"adding target specific op should update this function");
67636856
if (Opcode >= RISCVISD::TRUNCATE_VECTOR_VL && Opcode <= RISCVISD::SETCC_VL)
67646857
return true;
6765-
if (Opcode >= RISCVISD::VRGATHER_VX_VL && Opcode <= RISCVISD::VFIRST_VL)
6858+
if (Opcode >= RISCVISD::VRGATHER_VX_VL &&
6859+
Opcode <= RISCVISD::LAST_VL_VECTOR_OP)
67666860
return true;
67676861
if (Opcode >= RISCVISD::STRICT_FADD_VL &&
67686862
Opcode <= RISCVISD::STRICT_VFROUND_NOEXCEPT_VL)
@@ -21807,6 +21901,9 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
2180721901
NODE_NAME_CASE(VZEXT_VL)
2180821902
NODE_NAME_CASE(VCPOP_VL)
2180921903
NODE_NAME_CASE(VFIRST_VL)
21904+
NODE_NAME_CASE(RI_VZIPEVEN_VL)
21905+
NODE_NAME_CASE(RI_VZIPODD_VL)
21906+
NODE_NAME_CASE(RI_VZIP2A_VL)
2181021907
NODE_NAME_CASE(READ_CSR)
2181121908
NODE_NAME_CASE(WRITE_CSR)
2181221909
NODE_NAME_CASE(SWAP_CSR)

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,12 @@ enum NodeType : unsigned {
403403
// vfirst.m with additional mask and VL operands.
404404
VFIRST_VL,
405405

406-
LAST_VL_VECTOR_OP = VFIRST_VL,
406+
// XRivosVizip
407+
RI_VZIPEVEN_VL,
408+
RI_VZIPODD_VL,
409+
RI_VZIP2A_VL,
410+
411+
LAST_VL_VECTOR_OP = RI_VZIP2A_VL,
407412

408413
// Read VLENB CSR
409414
READ_VLENB,

llvm/lib/Target/RISCV/RISCVInstrInfoXRivos.td

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,38 @@ defm RI_VUNZIP2A_V : VALU_IV_V<"ri.vunzip2a", 0b001000>;
6767
defm RI_VUNZIP2B_V : VALU_IV_V<"ri.vunzip2b", 0b011000>;
6868
}
6969

70+
// These are modeled after the int binop VL nodes
71+
def ri_vzipeven_vl : SDNode<"RISCVISD::RI_VZIPEVEN_VL", SDT_RISCVIntBinOp_VL>;
72+
def ri_vzipodd_vl : SDNode<"RISCVISD::RI_VZIPODD_VL", SDT_RISCVIntBinOp_VL>;
73+
def ri_vzip2a_vl : SDNode<"RISCVISD::RI_VZIP2A_VL", SDT_RISCVIntBinOp_VL>;
74+
75+
multiclass RIVPseudoVALU_VV {
76+
foreach m = MxList in
77+
defm "" : VPseudoBinaryV_VV<m, Commutable=0>;
78+
}
79+
80+
let Predicates = [HasVendorXRivosVizip],
81+
Constraints = "@earlyclobber $rd, $rd = $passthru" in {
82+
defm PseudoRI_VZIPEVEN : RIVPseudoVALU_VV;
83+
defm PseudoRI_VZIPODD : RIVPseudoVALU_VV;
84+
defm PseudoRI_VZIP2A : RIVPseudoVALU_VV;
85+
}
86+
87+
multiclass RIVPatBinaryVL_VV<SDPatternOperator vop, string instruction_name,
88+
list<VTypeInfo> vtilist = AllIntegerVectors,
89+
bit isSEWAware = false> {
90+
foreach vti = vtilist in
91+
let Predicates = GetVTypePredicates<vti>.Predicates in
92+
def : VPatBinaryVL_V<vop, instruction_name, "VV",
93+
vti.Vector, vti.Vector, vti.Vector, vti.Mask,
94+
vti.Log2SEW, vti.LMul, vti.RegClass, vti.RegClass,
95+
vti.RegClass, isSEWAware>;
96+
}
97+
98+
defm : RIVPatBinaryVL_VV<ri_vzipeven_vl, "PseudoRI_VZIPEVEN">;
99+
defm : RIVPatBinaryVL_VV<ri_vzipodd_vl, "PseudoRI_VZIPODD">;
100+
defm : RIVPatBinaryVL_VV<ri_vzip2a_vl, "PseudoRI_VZIP2A">;
101+
70102
//===----------------------------------------------------------------------===//
71103
// XRivosVisni
72104
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)