Skip to content

Commit 84ff8d8

Browse files
committed
[RISCV] Add codegen support for ri.vinsert.v.x and ri.vextract.x.v
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 722d589 commit 84ff8d8

File tree

6 files changed

+936
-3
lines changed

6 files changed

+936
-3
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6935,7 +6935,7 @@ static bool hasPassthruOp(unsigned Opcode) {
69356935
Opcode <= RISCVISD::LAST_STRICTFP_OPCODE &&
69366936
"not a RISC-V target specific op");
69376937
static_assert(
6938-
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 132 &&
6938+
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 133 &&
69396939
RISCVISD::LAST_STRICTFP_OPCODE - RISCVISD::FIRST_STRICTFP_OPCODE == 21 &&
69406940
"adding target specific op should update this function");
69416941
if (Opcode >= RISCVISD::ADD_VL && Opcode <= RISCVISD::VFMAX_VL)
@@ -6959,7 +6959,7 @@ static bool hasMaskOp(unsigned Opcode) {
69596959
Opcode <= RISCVISD::LAST_STRICTFP_OPCODE &&
69606960
"not a RISC-V target specific op");
69616961
static_assert(
6962-
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 132 &&
6962+
RISCVISD::LAST_VL_VECTOR_OP - RISCVISD::FIRST_VL_VECTOR_OP == 133 &&
69636963
RISCVISD::LAST_STRICTFP_OPCODE - RISCVISD::FIRST_STRICTFP_OPCODE == 21 &&
69646964
"adding target specific op should update this function");
69656965
if (Opcode >= RISCVISD::TRUNCATE_VECTOR_VL && Opcode <= RISCVISD::SETCC_VL)
@@ -9567,6 +9567,13 @@ getSmallestVTForIndex(MVT VecVT, unsigned MaxIdx, SDLoc DL, SelectionDAG &DAG,
95679567
return SmallerVT;
95689568
}
95699569

9570+
static bool isValidInsertExtractIndex(SDValue Idx) {
9571+
auto *IdxC = dyn_cast<ConstantSDNode>(Idx);
9572+
if (!IdxC || isNullConstant(Idx))
9573+
return false;
9574+
return IdxC->getZExtValue() < 32;
9575+
}
9576+
95709577
// Custom-legalize INSERT_VECTOR_ELT so that the value is inserted into the
95719578
// first position of a vector, and that vector is slid up to the insert index.
95729579
// By limiting the active vector length to index+1 and merging with the
@@ -9677,6 +9684,26 @@ SDValue RISCVTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
96779684
return Vec;
96789685
return convertFromScalableVector(VecVT, Vec, DAG, Subtarget);
96799686
}
9687+
9688+
// Use ri.vinsert.v.x if available.
9689+
if (Subtarget.hasVendorXRivosVisni() && VecVT.isInteger() &&
9690+
isValidInsertExtractIndex(Idx)) {
9691+
unsigned Policy = RISCVVType::TAIL_UNDISTURBED_MASK_UNDISTURBED;
9692+
if (VecVT.isFixedLengthVector() && isa<ConstantSDNode>(Idx) &&
9693+
Idx->getAsZExtVal() + 1 == VecVT.getVectorNumElements())
9694+
Policy = RISCVVType::TAIL_AGNOSTIC;
9695+
SDValue PolicyOp =
9696+
DAG.getTargetConstant(Policy, DL, Subtarget.getXLenVT());
9697+
Vec = DAG.getNode(RISCVISD::RI_VINSERT_VL, DL, ContainerVT, Vec, Val, Idx,
9698+
VL, PolicyOp);
9699+
if (AlignedIdx)
9700+
Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, OrigContainerVT, OrigVec,
9701+
Vec, AlignedIdx);
9702+
if (!VecVT.isFixedLengthVector())
9703+
return Vec;
9704+
return convertFromScalableVector(VecVT, Vec, DAG, Subtarget);
9705+
}
9706+
96809707
ValInVec = lowerScalarInsert(Val, VL, ContainerVT, DL, DAG, Subtarget);
96819708
} else {
96829709
// On RV32, i64-element vectors must be specially handled to place the
@@ -9876,6 +9903,14 @@ SDValue RISCVTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
98769903
}
98779904
}
98789905

9906+
// Use ri.vextract.x.v if available.
9907+
// TODO: Avoid index 0 and just use the vmv.x.s
9908+
if (Subtarget.hasVendorXRivosVisni() && EltVT.isInteger() &&
9909+
isValidInsertExtractIndex(Idx)) {
9910+
SDValue Elt = DAG.getNode(RISCVISD::RI_VEXTRACT, DL, XLenVT, Vec, Idx);
9911+
return DAG.getNode(ISD::TRUNCATE, DL, EltVT, Elt);
9912+
}
9913+
98799914
// If after narrowing, the required slide is still greater than LMUL2,
98809915
// fallback to generic expansion and go through the stack. This is done
98819916
// for a subtle reason: extracting *all* elements out of a vector is
@@ -22253,11 +22288,13 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
2225322288
NODE_NAME_CASE(VZEXT_VL)
2225422289
NODE_NAME_CASE(VCPOP_VL)
2225522290
NODE_NAME_CASE(VFIRST_VL)
22291+
NODE_NAME_CASE(RI_VINSERT_VL)
2225622292
NODE_NAME_CASE(RI_VZIPEVEN_VL)
2225722293
NODE_NAME_CASE(RI_VZIPODD_VL)
2225822294
NODE_NAME_CASE(RI_VZIP2A_VL)
2225922295
NODE_NAME_CASE(RI_VUNZIP2A_VL)
2226022296
NODE_NAME_CASE(RI_VUNZIP2B_VL)
22297+
NODE_NAME_CASE(RI_VEXTRACT)
2226122298
NODE_NAME_CASE(READ_CSR)
2226222299
NODE_NAME_CASE(WRITE_CSR)
2226322300
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,
@@ -413,6 +417,12 @@ enum NodeType : unsigned {
413417

414418
LAST_VL_VECTOR_OP = RI_VUNZIP2B_VL,
415419

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

llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp

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

97+
static bool isVInsertInstr(const MachineInstr &MI) {
98+
return RISCV::getRVVMCOpcode(MI.getOpcode()) == RISCV::RI_VINSERT;
99+
}
100+
101+
static bool isVExtractInstr(const MachineInstr &MI) {
102+
return RISCV::getRVVMCOpcode(MI.getOpcode()) == RISCV::RI_VEXTRACT;
103+
}
104+
97105
static bool isScalarExtractInstr(const MachineInstr &MI) {
98106
switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
99107
default:
@@ -538,6 +546,18 @@ DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
538546
Res.MaskPolicy = false;
539547
}
540548

549+
if (isVExtractInstr(MI)) {
550+
assert(!RISCVII::hasVLOp(TSFlags));
551+
// TODO: LMUL can be any larger value (without cost)
552+
Res.TailPolicy = false;
553+
Res.MaskPolicy = false;
554+
}
555+
556+
if (isVInsertInstr(MI)) {
557+
// TODO: LMUL can be any larger value (without cost)
558+
Res.MaskPolicy = false;
559+
}
560+
541561
return Res;
542562
}
543563

@@ -1085,7 +1105,7 @@ RISCVInsertVSETVLI::computeInfoForInstr(const MachineInstr &MI) const {
10851105
InstrInfo.setAVLRegDef(VNI, VLOp.getReg());
10861106
}
10871107
} else {
1088-
assert(isScalarExtractInstr(MI));
1108+
assert(isScalarExtractInstr(MI) || isVExtractInstr(MI));
10891109
// Pick a random value for state tracking purposes, will be ignored via
10901110
// the demanded fields mechanism
10911111
InstrInfo.setAVLImm(1);

llvm/lib/Target/RISCV/RISCVInstrInfoXRivos.td

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

0 commit comments

Comments
 (0)