Skip to content

Commit 8c4be01

Browse files
committed
[RISCV] Select mask operands as virtual registers and eliminate vmv0
This is another attempt at llvm#88496 to keep mask operands in SSA after instruction selection. Previously we selected the mask operands into vmv0, a singleton register class with exactly one register, V0. But the register allocator doesn't really support singleton register classes and we ran into errors like "ran out of registers during register allocation in function". This avoids this by introducing a pass just before register allocation that converts any use of vmv0 to a copy to $v0, i.e. what isel currently does today. That way the register allocator doesn't need to deal with the singleton register class, but get the benefits of having the mask registers in SSA throughout the backend: - This allows RISCVVLOptimizer to reduce the VLs of instructions that define mask registers - It enables CSE and code sinking in more places - It removes the need to peek through mask copies in RISCVISelDAGToDAG and keep track of V0 defs in RISCVVectorPeephole As a follow up, we can move the elimination pass to after phi elimination and outside of SSA, which would unblock the pre-RA scheduler around masked pseudos. This might also help the issue that RISCVVectorMaskDAGMutation tries to solve.
1 parent c475356 commit 8c4be01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1889
-1618
lines changed

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ add_llvm_target(RISCVCodeGen
6363
RISCVVectorMaskDAGMutation.cpp
6464
RISCVVectorPeephole.cpp
6565
RISCVVLOptimizer.cpp
66+
RISCVVMV0Elimination.cpp
6667
RISCVZacasABIFix.cpp
6768
GISel/RISCVCallLowering.cpp
6869
GISel/RISCVInstructionSelector.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ void initializeRISCVPreLegalizerCombinerPass(PassRegistry &);
107107

108108
FunctionPass *createRISCVVLOptimizerPass();
109109
void initializeRISCVVLOptimizerPass(PassRegistry &);
110+
111+
FunctionPass *createRISCVVMV0EliminationPass();
112+
void initializeRISCVVMV0EliminationPass(PassRegistry &);
110113
} // namespace llvm
111114

112115
#endif

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 15 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@ void RISCVDAGToDAGISel::addVectorLoadStoreOperands(
241241
bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands,
242242
bool IsLoad, MVT *IndexVT) {
243243
SDValue Chain = Node->getOperand(0);
244-
SDValue Glue;
245244

246245
Operands.push_back(Node->getOperand(CurOp++)); // Base pointer.
247246

@@ -252,11 +251,8 @@ void RISCVDAGToDAGISel::addVectorLoadStoreOperands(
252251
}
253252

254253
if (IsMasked) {
255-
// Mask needs to be copied to V0.
256254
SDValue Mask = Node->getOperand(CurOp++);
257-
Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue());
258-
Glue = Chain.getValue(1);
259-
Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType()));
255+
Operands.push_back(Mask);
260256
}
261257
SDValue VL;
262258
selectVLOp(Node->getOperand(CurOp++), VL);
@@ -278,8 +274,6 @@ void RISCVDAGToDAGISel::addVectorLoadStoreOperands(
278274
}
279275

280276
Operands.push_back(Chain); // Chain.
281-
if (Glue)
282-
Operands.push_back(Glue);
283277
}
284278

285279
void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, unsigned NF, bool IsMasked,
@@ -1831,19 +1825,13 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
18311825
return;
18321826
}
18331827

1834-
// Mask needs to be copied to V0.
1835-
SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
1836-
RISCV::V0, Mask, SDValue());
1837-
SDValue Glue = Chain.getValue(1);
1838-
SDValue V0 = CurDAG->getRegister(RISCV::V0, VT);
1839-
18401828
if (IsCmpConstant) {
18411829
SDValue Imm =
18421830
selectImm(CurDAG, SDLoc(Src2), XLenVT, CVal - 1, *Subtarget);
18431831

18441832
ReplaceNode(Node, CurDAG->getMachineNode(
18451833
VMSGTMaskOpcode, DL, VT,
1846-
{MaskedOff, Src1, Imm, V0, VL, SEW, Glue}));
1834+
{MaskedOff, Src1, Imm, Mask, VL, SEW}));
18471835
return;
18481836
}
18491837

@@ -1854,7 +1842,7 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
18541842
// the agnostic result can be either undisturbed or all 1.
18551843
SDValue Cmp = SDValue(
18561844
CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT,
1857-
{MaskedOff, Src1, Src2, V0, VL, SEW, Glue}),
1845+
{MaskedOff, Src1, Src2, Mask, VL, SEW}),
18581846
0);
18591847
// vmxor.mm vd, vd, v0 is used to update active value.
18601848
ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT,
@@ -3274,12 +3262,10 @@ static bool vectorPseudoHasAllNBitUsers(SDNode *User, unsigned UserOpNo,
32743262
return false;
32753263
assert(RISCVII::hasVLOp(TSFlags));
32763264

3277-
bool HasGlueOp = User->getGluedNode() != nullptr;
3278-
unsigned ChainOpIdx = User->getNumOperands() - HasGlueOp - 1;
3265+
unsigned ChainOpIdx = User->getNumOperands() - 1;
32793266
bool HasChainOp = User->getOperand(ChainOpIdx).getValueType() == MVT::Other;
32803267
bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TSFlags);
3281-
unsigned VLIdx =
3282-
User->getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2;
3268+
unsigned VLIdx = User->getNumOperands() - HasVecPolicyOp - HasChainOp - 2;
32833269
const unsigned Log2SEW = User->getConstantOperandVal(VLIdx + 1);
32843270

32853271
if (UserOpNo == VLIdx)
@@ -3746,43 +3732,7 @@ bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) {
37463732
return false;
37473733
}
37483734

3749-
// After ISel, a vector pseudo's mask will be copied to V0 via a CopyToReg
3750-
// that's glued to the pseudo. This tries to look up the value that was copied
3751-
// to V0.
3752-
static SDValue getMaskSetter(SDValue MaskOp, SDValue GlueOp) {
3753-
// Check that we're using V0 as a mask register.
3754-
if (!isa<RegisterSDNode>(MaskOp) ||
3755-
cast<RegisterSDNode>(MaskOp)->getReg() != RISCV::V0)
3756-
return SDValue();
3757-
3758-
// The glued user defines V0.
3759-
const auto *Glued = GlueOp.getNode();
3760-
3761-
if (!Glued || Glued->getOpcode() != ISD::CopyToReg)
3762-
return SDValue();
3763-
3764-
// Check that we're defining V0 as a mask register.
3765-
if (!isa<RegisterSDNode>(Glued->getOperand(1)) ||
3766-
cast<RegisterSDNode>(Glued->getOperand(1))->getReg() != RISCV::V0)
3767-
return SDValue();
3768-
3769-
SDValue MaskSetter = Glued->getOperand(2);
3770-
3771-
// Sometimes the VMSET is wrapped in a COPY_TO_REGCLASS, e.g. if the mask came
3772-
// from an extract_subvector or insert_subvector.
3773-
if (MaskSetter->isMachineOpcode() &&
3774-
MaskSetter->getMachineOpcode() == RISCV::COPY_TO_REGCLASS)
3775-
MaskSetter = MaskSetter->getOperand(0);
3776-
3777-
return MaskSetter;
3778-
}
3779-
3780-
static bool usesAllOnesMask(SDValue MaskOp, SDValue GlueOp) {
3781-
// Check the instruction defining V0; it needs to be a VMSET pseudo.
3782-
SDValue MaskSetter = getMaskSetter(MaskOp, GlueOp);
3783-
if (!MaskSetter)
3784-
return false;
3785-
3735+
static bool usesAllOnesMask(SDValue MaskOp) {
37863736
const auto IsVMSet = [](unsigned Opc) {
37873737
return Opc == RISCV::PseudoVMSET_M_B1 || Opc == RISCV::PseudoVMSET_M_B16 ||
37883738
Opc == RISCV::PseudoVMSET_M_B2 || Opc == RISCV::PseudoVMSET_M_B32 ||
@@ -3793,14 +3743,7 @@ static bool usesAllOnesMask(SDValue MaskOp, SDValue GlueOp) {
37933743
// TODO: Check that the VMSET is the expected bitwidth? The pseudo has
37943744
// undefined behaviour if it's the wrong bitwidth, so we could choose to
37953745
// assume that it's all-ones? Same applies to its VL.
3796-
return MaskSetter->isMachineOpcode() &&
3797-
IsVMSet(MaskSetter.getMachineOpcode());
3798-
}
3799-
3800-
// Return true if we can make sure mask of N is all-ones mask.
3801-
static bool usesAllOnesMask(SDNode *N, unsigned MaskOpIdx) {
3802-
return usesAllOnesMask(N->getOperand(MaskOpIdx),
3803-
N->getOperand(N->getNumOperands() - 1));
3746+
return MaskOp->isMachineOpcode() && IsVMSet(MaskOp.getMachineOpcode());
38043747
}
38053748

38063749
static bool isImplicitDef(SDValue V) {
@@ -3816,17 +3759,15 @@ static bool isImplicitDef(SDValue V) {
38163759
}
38173760

38183761
// Optimize masked RVV pseudo instructions with a known all-ones mask to their
3819-
// corresponding "unmasked" pseudo versions. The mask we're interested in will
3820-
// take the form of a V0 physical register operand, with a glued
3821-
// register-setting instruction.
3762+
// corresponding "unmasked" pseudo versions.
38223763
bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(MachineSDNode *N) {
38233764
const RISCV::RISCVMaskedPseudoInfo *I =
38243765
RISCV::getMaskedPseudoInfo(N->getMachineOpcode());
38253766
if (!I)
38263767
return false;
38273768

38283769
unsigned MaskOpIdx = I->MaskOpIdx;
3829-
if (!usesAllOnesMask(N, MaskOpIdx))
3770+
if (!usesAllOnesMask(N->getOperand(MaskOpIdx)))
38303771
return false;
38313772

38323773
// There are two classes of pseudos in the table - compares and
@@ -3850,18 +3791,13 @@ bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(MachineSDNode *N) {
38503791
// Skip the passthru operand at index 0 if the unmasked don't have one.
38513792
bool ShouldSkip = !HasPassthru && MaskedHasPassthru;
38523793
for (unsigned I = ShouldSkip, E = N->getNumOperands(); I != E; I++) {
3853-
// Skip the mask, and the Glue.
3794+
// Skip the mask
38543795
SDValue Op = N->getOperand(I);
3855-
if (I == MaskOpIdx || Op.getValueType() == MVT::Glue)
3796+
if (I == MaskOpIdx)
38563797
continue;
38573798
Ops.push_back(Op);
38583799
}
38593800

3860-
// Transitively apply any node glued to our new node.
3861-
const auto *Glued = N->getGluedNode();
3862-
if (auto *TGlued = Glued->getGluedNode())
3863-
Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1));
3864-
38653801
MachineSDNode *Result =
38663802
CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops);
38673803

@@ -3897,17 +3833,13 @@ static bool IsVMerge(SDNode *N) {
38973833
// The resulting policy is the effective policy the vmerge would have had,
38983834
// i.e. whether or not it's passthru operand was implicit-def.
38993835
bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
3900-
SDValue Passthru, False, True, VL, Mask, Glue;
3836+
SDValue Passthru, False, True, VL, Mask;
39013837
assert(IsVMerge(N));
39023838
Passthru = N->getOperand(0);
39033839
False = N->getOperand(1);
39043840
True = N->getOperand(2);
39053841
Mask = N->getOperand(3);
39063842
VL = N->getOperand(4);
3907-
// We always have a glue node for the mask at v0.
3908-
Glue = N->getOperand(N->getNumOperands() - 1);
3909-
assert(cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0);
3910-
assert(Glue.getValueType() == MVT::Glue);
39113843

39123844
// If the EEW of True is different from vmerge's SEW, then we can't fold.
39133845
if (True.getSimpleValueType() != N->getSimpleValueType(0))
@@ -3950,12 +3882,7 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
39503882
if (TII->get(TrueOpc).hasUnmodeledSideEffects())
39513883
return false;
39523884

3953-
// The last operand of a masked instruction may be glued.
3954-
bool HasGlueOp = True->getGluedNode() != nullptr;
3955-
3956-
// The chain operand may exist either before the glued operands or in the last
3957-
// position.
3958-
unsigned TrueChainOpIdx = True.getNumOperands() - HasGlueOp - 1;
3885+
unsigned TrueChainOpIdx = True.getNumOperands() - 1;
39593886
bool HasChainOp =
39603887
True.getOperand(TrueChainOpIdx).getValueType() == MVT::Other;
39613888

@@ -3967,15 +3894,14 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
39673894
LoopWorklist.push_back(False.getNode());
39683895
LoopWorklist.push_back(Mask.getNode());
39693896
LoopWorklist.push_back(VL.getNode());
3970-
LoopWorklist.push_back(Glue.getNode());
39713897
if (SDNode::hasPredecessorHelper(True.getNode(), Visited, LoopWorklist))
39723898
return false;
39733899
}
39743900

39753901
// The vector policy operand may be present for masked intrinsics
39763902
bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TrueTSFlags);
39773903
unsigned TrueVLIndex =
3978-
True.getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2;
3904+
True.getNumOperands() - HasVecPolicyOp - HasChainOp - 2;
39793905
SDValue TrueVL = True.getOperand(TrueVLIndex);
39803906
SDValue SEW = True.getOperand(TrueVLIndex + 1);
39813907

@@ -4007,7 +3933,7 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
40073933
if (RISCVII::elementsDependOnVL(TrueBaseMCID.TSFlags) && (TrueVL != VL))
40083934
return false;
40093935
if (RISCVII::elementsDependOnMask(TrueBaseMCID.TSFlags) &&
4010-
(Mask && !usesAllOnesMask(Mask, Glue)))
3936+
(Mask && !usesAllOnesMask(Mask)))
40113937
return false;
40123938

40133939
// Make sure it doesn't raise any observable fp exceptions, since changing the
@@ -4064,9 +3990,6 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
40643990
if (HasChainOp)
40653991
Ops.push_back(True.getOperand(TrueChainOpIdx));
40663992

4067-
// Add the glue for the CopyToReg of mask->v0.
4068-
Ops.push_back(Glue);
4069-
40703993
MachineSDNode *Result =
40713994
CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops);
40723995
Result->setFlags(True->getFlags());

0 commit comments

Comments
 (0)