Skip to content

Commit d1a4034

Browse files
committed
[RISCV] Select mask operands as virtual registers and eliminate vmv0
This is another attempt at #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 a3aa452 commit d1a4034

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

+1893
-1622
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)
@@ -3739,43 +3725,7 @@ bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) {
37393725
return false;
37403726
}
37413727

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

37993742
static bool isImplicitDef(SDValue V) {
@@ -3809,17 +3752,15 @@ static bool isImplicitDef(SDValue V) {
38093752
}
38103753

38113754
// Optimize masked RVV pseudo instructions with a known all-ones mask to their
3812-
// corresponding "unmasked" pseudo versions. The mask we're interested in will
3813-
// take the form of a V0 physical register operand, with a glued
3814-
// register-setting instruction.
3755+
// corresponding "unmasked" pseudo versions.
38153756
bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(MachineSDNode *N) {
38163757
const RISCV::RISCVMaskedPseudoInfo *I =
38173758
RISCV::getMaskedPseudoInfo(N->getMachineOpcode());
38183759
if (!I)
38193760
return false;
38203761

38213762
unsigned MaskOpIdx = I->MaskOpIdx;
3822-
if (!usesAllOnesMask(N, MaskOpIdx))
3763+
if (!usesAllOnesMask(N->getOperand(MaskOpIdx)))
38233764
return false;
38243765

38253766
// There are two classes of pseudos in the table - compares and
@@ -3843,18 +3784,13 @@ bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(MachineSDNode *N) {
38433784
// Skip the passthru operand at index 0 if the unmasked don't have one.
38443785
bool ShouldSkip = !HasPassthru && MaskedHasPassthru;
38453786
for (unsigned I = ShouldSkip, E = N->getNumOperands(); I != E; I++) {
3846-
// Skip the mask, and the Glue.
3787+
// Skip the mask
38473788
SDValue Op = N->getOperand(I);
3848-
if (I == MaskOpIdx || Op.getValueType() == MVT::Glue)
3789+
if (I == MaskOpIdx)
38493790
continue;
38503791
Ops.push_back(Op);
38513792
}
38523793

3853-
// Transitively apply any node glued to our new node.
3854-
const auto *Glued = N->getGluedNode();
3855-
if (auto *TGlued = Glued->getGluedNode())
3856-
Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1));
3857-
38583794
MachineSDNode *Result =
38593795
CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops);
38603796

@@ -3890,17 +3826,13 @@ static bool IsVMerge(SDNode *N) {
38903826
// The resulting policy is the effective policy the vmerge would have had,
38913827
// i.e. whether or not it's passthru operand was implicit-def.
38923828
bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
3893-
SDValue Passthru, False, True, VL, Mask, Glue;
3829+
SDValue Passthru, False, True, VL, Mask;
38943830
assert(IsVMerge(N));
38953831
Passthru = N->getOperand(0);
38963832
False = N->getOperand(1);
38973833
True = N->getOperand(2);
38983834
Mask = N->getOperand(3);
38993835
VL = N->getOperand(4);
3900-
// We always have a glue node for the mask at v0.
3901-
Glue = N->getOperand(N->getNumOperands() - 1);
3902-
assert(cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0);
3903-
assert(Glue.getValueType() == MVT::Glue);
39043836

39053837
// If the EEW of True is different from vmerge's SEW, then we can't fold.
39063838
if (True.getSimpleValueType() != N->getSimpleValueType(0))
@@ -3943,12 +3875,7 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
39433875
if (TII->get(TrueOpc).hasUnmodeledSideEffects())
39443876
return false;
39453877

3946-
// The last operand of a masked instruction may be glued.
3947-
bool HasGlueOp = True->getGluedNode() != nullptr;
3948-
3949-
// The chain operand may exist either before the glued operands or in the last
3950-
// position.
3951-
unsigned TrueChainOpIdx = True.getNumOperands() - HasGlueOp - 1;
3878+
unsigned TrueChainOpIdx = True.getNumOperands() - 1;
39523879
bool HasChainOp =
39533880
True.getOperand(TrueChainOpIdx).getValueType() == MVT::Other;
39543881

@@ -3960,15 +3887,14 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
39603887
LoopWorklist.push_back(False.getNode());
39613888
LoopWorklist.push_back(Mask.getNode());
39623889
LoopWorklist.push_back(VL.getNode());
3963-
LoopWorklist.push_back(Glue.getNode());
39643890
if (SDNode::hasPredecessorHelper(True.getNode(), Visited, LoopWorklist))
39653891
return false;
39663892
}
39673893

39683894
// The vector policy operand may be present for masked intrinsics
39693895
bool HasVecPolicyOp = RISCVII::hasVecPolicyOp(TrueTSFlags);
39703896
unsigned TrueVLIndex =
3971-
True.getNumOperands() - HasVecPolicyOp - HasChainOp - HasGlueOp - 2;
3897+
True.getNumOperands() - HasVecPolicyOp - HasChainOp - 2;
39723898
SDValue TrueVL = True.getOperand(TrueVLIndex);
39733899
SDValue SEW = True.getOperand(TrueVLIndex + 1);
39743900

@@ -4000,7 +3926,7 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
40003926
if (RISCVII::elementsDependOnVL(TrueBaseMCID.TSFlags) && (TrueVL != VL))
40013927
return false;
40023928
if (RISCVII::elementsDependOnMask(TrueBaseMCID.TSFlags) &&
4003-
(Mask && !usesAllOnesMask(Mask, Glue)))
3929+
(Mask && !usesAllOnesMask(Mask)))
40043930
return false;
40053931

40063932
// Make sure it doesn't raise any observable fp exceptions, since changing the
@@ -4057,9 +3983,6 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
40573983
if (HasChainOp)
40583984
Ops.push_back(True.getOperand(TrueChainOpIdx));
40593985

4060-
// Add the glue for the CopyToReg of mask->v0.
4061-
Ops.push_back(Glue);
4062-
40633986
MachineSDNode *Result =
40643987
CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops);
40653988
Result->setFlags(True->getFlags());

0 commit comments

Comments
 (0)