Skip to content

Commit 0bdb85a

Browse files
preamesIanWood1
authored andcommitted
[RISCV] Add codegen support for ri.vinsert.v.x and ri.vextract.x.v (llvm#136708)
These instructions are included in XRivosVisni. They perform a scalar insert into a vector (with a potentially non-zero index) and a scalar extract from a vector (with a potentially non-zero index) respectively. They're very analogous to vmv.s.x and vmv.x.s respectively. The instructions do have a couple restrictions: 1) Only constant indices are supported w/a uimm5 format. 2) There are no FP variants. One important property of these instructions is that their throughput and latency are expected to be LMUL independent.
1 parent d898d7e commit 0bdb85a

File tree

6 files changed

+922
-3
lines changed

6 files changed

+922
-3
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6963,7 +6963,7 @@ static bool hasPassthruOp(unsigned Opcode) {
69636963
Opcode <= RISCVISD::LAST_STRICTFP_OPCODE &&
69646964
"not a RISC-V target specific op");
69656965
static_assert(
6966-
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 133 &&
6966+
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 134 &&
69676967
RISCVISD::LAST_STRICTFP_OPCODE - RISCVISD::FIRST_STRICTFP_OPCODE == 21 &&
69686968
"adding target specific op should update this function");
69696969
if (Opcode >= RISCVISD::ADD_VL && Opcode <= RISCVISD::VFMAX_VL)
@@ -6987,7 +6987,7 @@ static bool hasMaskOp(unsigned Opcode) {
69876987
Opcode <= RISCVISD::LAST_STRICTFP_OPCODE &&
69886988
"not a RISC-V target specific op");
69896989
static_assert(
6990-
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 133 &&
6990+
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 134 &&
69916991
RISCVISD::LAST_STRICTFP_OPCODE - RISCVISD::FIRST_STRICTFP_OPCODE == 21 &&
69926992
"adding target specific op should update this function");
69936993
if (Opcode >= RISCVISD::TRUNCATE_VECTOR_VL && Opcode <= RISCVISD::SETCC_VL)
@@ -9595,6 +9595,13 @@ getSmallestVTForIndex(MVT VecVT, unsigned MaxIdx, SDLoc DL, SelectionDAG &DAG,
95959595
return SmallerVT;
95969596
}
95979597

9598+
static bool isValidVisniInsertExtractIndex(SDValue Idx) {
9599+
auto *IdxC = dyn_cast<ConstantSDNode>(Idx);
9600+
if (!IdxC || isNullConstant(Idx))
9601+
return false;
9602+
return isUInt<5>(IdxC->getZExtValue());
9603+
}
9604+
95989605
// Custom-legalize INSERT_VECTOR_ELT so that the value is inserted into the
95999606
// first position of a vector, and that vector is slid up to the insert index.
96009607
// By limiting the active vector length to index+1 and merging with the
@@ -9705,6 +9712,23 @@ SDValue RISCVTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
97059712
return Vec;
97069713
return convertFromScalableVector(VecVT, Vec, DAG, Subtarget);
97079714
}
9715+
9716+
// Use ri.vinsert.v.x if available.
9717+
if (Subtarget.hasVendorXRivosVisni() && VecVT.isInteger() &&
9718+
isValidVisniInsertExtractIndex(Idx)) {
9719+
// Tail policy applies to elements past VLMAX (by assumption Idx < VLMAX)
9720+
SDValue PolicyOp =
9721+
DAG.getTargetConstant(RISCVVType::TAIL_AGNOSTIC, DL, XLenVT);
9722+
Vec = DAG.getNode(RISCVISD::RI_VINSERT_VL, DL, ContainerVT, Vec, Val, Idx,
9723+
VL, PolicyOp);
9724+
if (AlignedIdx)
9725+
Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, OrigContainerVT, OrigVec,
9726+
Vec, AlignedIdx);
9727+
if (!VecVT.isFixedLengthVector())
9728+
return Vec;
9729+
return convertFromScalableVector(VecVT, Vec, DAG, Subtarget);
9730+
}
9731+
97089732
ValInVec = lowerScalarInsert(Val, VL, ContainerVT, DL, DAG, Subtarget);
97099733
} else {
97109734
// On RV32, i64-element vectors must be specially handled to place the
@@ -9904,6 +9928,14 @@ SDValue RISCVTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
99049928
}
99059929
}
99069930

9931+
// Use ri.vextract.x.v if available.
9932+
// TODO: Avoid index 0 and just use the vmv.x.s
9933+
if (Subtarget.hasVendorXRivosVisni() && EltVT.isInteger() &&
9934+
isValidVisniInsertExtractIndex(Idx)) {
9935+
SDValue Elt = DAG.getNode(RISCVISD::RI_VEXTRACT, DL, XLenVT, Vec, Idx);
9936+
return DAG.getNode(ISD::TRUNCATE, DL, EltVT, Elt);
9937+
}
9938+
99079939
// If after narrowing, the required slide is still greater than LMUL2,
99089940
// fallback to generic expansion and go through the stack. This is done
99099941
// for a subtle reason: extracting *all* elements out of a vector is
@@ -22321,12 +22353,14 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
2232122353
NODE_NAME_CASE(VZEXT_VL)
2232222354
NODE_NAME_CASE(VCPOP_VL)
2232322355
NODE_NAME_CASE(VFIRST_VL)
22356+
NODE_NAME_CASE(RI_VINSERT_VL)
2232422357
NODE_NAME_CASE(RI_VZIPEVEN_VL)
2232522358
NODE_NAME_CASE(RI_VZIPODD_VL)
2232622359
NODE_NAME_CASE(RI_VZIP2A_VL)
2232722360
NODE_NAME_CASE(RI_VZIP2B_VL)
2232822361
NODE_NAME_CASE(RI_VUNZIP2A_VL)
2232922362
NODE_NAME_CASE(RI_VUNZIP2B_VL)
22363+
NODE_NAME_CASE(RI_VEXTRACT)
2233022364
NODE_NAME_CASE(READ_CSR)
2233122365
NODE_NAME_CASE(WRITE_CSR)
2233222366
NODE_NAME_CASE(SWAP_CSR)

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@ enum NodeType : unsigned {
404404
// vfirst.m with additional mask and VL operands.
405405
VFIRST_VL,
406406

407+
// XRivosVisni
408+
// VINSERT matches the semantics of ri.vinsert.v.x. It carries a VL operand.
409+
RI_VINSERT_VL,
410+
407411
// XRivosVizip
408412
RI_VZIPEVEN_VL,
409413
RI_VZIPODD_VL,
@@ -414,6 +418,12 @@ enum NodeType : unsigned {
414418

415419
LAST_VL_VECTOR_OP = RI_VUNZIP2B_VL,
416420

421+
// XRivosVisni
422+
// VEXTRACT matches the semantics of ri.vextract.x.v. The result is always
423+
// XLenVT sign extended from the vector element size. VEXTRACT does *not*
424+
// have a VL operand.
425+
RI_VEXTRACT,
426+
417427
// Read VLENB CSR
418428
READ_VLENB,
419429
// Reads value of CSR.

llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ static bool isFloatScalarMoveOrScalarSplatInstr(const MachineInstr &MI) {
9494
}
9595
}
9696

97+
static bool isVExtractInstr(const MachineInstr &MI) {
98+
return RISCV::getRVVMCOpcode(MI.getOpcode()) == RISCV::RI_VEXTRACT;
99+
}
100+
97101
static bool isScalarExtractInstr(const MachineInstr &MI) {
98102
switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
99103
default:
@@ -538,6 +542,12 @@ DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
538542
Res.MaskPolicy = false;
539543
}
540544

545+
if (isVExtractInstr(MI)) {
546+
assert(!RISCVII::hasVLOp(TSFlags));
547+
// TODO: LMUL can be any larger value (without cost)
548+
Res.TailPolicy = false;
549+
}
550+
541551
return Res;
542552
}
543553

@@ -1085,7 +1095,7 @@ RISCVInsertVSETVLI::computeInfoForInstr(const MachineInstr &MI) const {
10851095
InstrInfo.setAVLRegDef(VNI, VLOp.getReg());
10861096
}
10871097
} else {
1088-
assert(isScalarExtractInstr(MI));
1098+
assert(isScalarExtractInstr(MI) || isVExtractInstr(MI));
10891099
// Pick a random value for state tracking purposes, will be ignored via
10901100
// the demanded fields mechanism
10911101
InstrInfo.setAVLImm(1);

llvm/lib/Target/RISCV/RISCVInstrInfoXRivos.td

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,57 @@ def RI_VEXTRACT : CustomRivosXVI<0b010111, OPMVV, (outs GPR:$rd),
128128
(ins VR:$vs2, uimm5:$imm),
129129
"ri.vextract.x.v", "$rd, $vs2, $imm">;
130130
}
131+
132+
133+
def ri_vextract : SDNode<"RISCVISD::RI_VEXTRACT",
134+
SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisVec<1>,
135+
SDTCisInt<2>,
136+
SDTCisInt<1>]>>;
137+
138+
def ri_vinsert_vl : SDNode<"RISCVISD::RI_VINSERT_VL",
139+
SDTypeProfile<1, 5, [SDTCisSameAs<0, 1>,
140+
SDTCisInt<0>,
141+
SDTCisVT<2, XLenVT>,
142+
SDTCisVT<3, XLenVT>,
143+
SDTCisVT<4, XLenVT>]>>;
144+
145+
let Predicates = [HasVendorXRivosVisni], mayLoad = 0, mayStore = 0,
146+
hasSideEffects = 0, HasSEWOp = 1 in
147+
foreach m = MxList in {
148+
defvar mx = m.MX;
149+
let VLMul = m.value in {
150+
let BaseInstr = RI_VEXTRACT in
151+
def PseudoRI_VEXTRACT_ # mx :
152+
Pseudo<(outs GPR:$rd), (ins m.vrclass:$rs2, uimm5:$idx, ixlenimm:$sew),
153+
[]>,
154+
RISCVVPseudo;
155+
156+
let HasVLOp = 1, BaseInstr = RI_VINSERT, HasVecPolicyOp = 1,
157+
Constraints = "$rd = $rs1" in
158+
def PseudoRI_VINSERT_ # mx :
159+
Pseudo<(outs m.vrclass:$rd),
160+
(ins m.vrclass:$rs1, GPR:$rs2, uimm5:$idx, AVL:$vl,
161+
ixlenimm:$sew, ixlenimm:$policy),
162+
[]>,
163+
RISCVVPseudo;
164+
}
165+
}
166+
167+
168+
169+
foreach vti = AllIntegerVectors in
170+
let Predicates = GetVTypePredicates<vti>.Predicates in {
171+
def : Pat<(XLenVT (ri_vextract (vti.Vector vti.RegClass:$vs2), uimm5:$imm)),
172+
(!cast<Instruction>("PseudoRI_VEXTRACT_" # vti.LMul.MX)
173+
$vs2, uimm5:$imm, vti.Log2SEW)>;
174+
175+
def : Pat<(vti.Vector (ri_vinsert_vl (vti.Vector vti.RegClass:$merge),
176+
vti.ScalarRegClass:$rs1,
177+
uimm5:$imm,
178+
VLOpFrag,
179+
(XLenVT timm:$policy))),
180+
(!cast<Instruction>("PseudoRI_VINSERT_" # vti.LMul.MX)
181+
$merge, vti.ScalarRegClass:$rs1, uimm5:$imm,
182+
GPR:$vl, vti.Log2SEW, (XLenVT timm:$policy))>;
183+
184+
}

0 commit comments

Comments
 (0)