Skip to content

Commit 95398d4

Browse files
committed
[RISCV] Move vmv.v.v peephole from SelectionDAG to RISCVVectorPeephole
This is split off from #71764, and moves only the vmv.v.v part of performCombineVMergeAndVOps to work on MachineInstrs. In retrospect trying to handle PseudoVMV_V_V and PseudoVMERGE_VVM in the same function makes the code quite hard to read, so this just does it in a separate peephole. This turns out to be simpler since for PseudoVMV_V_V we don't need to convert the Src instruction to a masked variant, and we don't need to create a fake all ones mask.
1 parent 05e9506 commit 95398d4

File tree

2 files changed

+154
-71
lines changed

2 files changed

+154
-71
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 14 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3651,32 +3651,6 @@ static bool IsVMerge(SDNode *N) {
36513651
return RISCV::getRVVMCOpcode(N->getMachineOpcode()) == RISCV::VMERGE_VVM;
36523652
}
36533653

3654-
static bool IsVMv(SDNode *N) {
3655-
return RISCV::getRVVMCOpcode(N->getMachineOpcode()) == RISCV::VMV_V_V;
3656-
}
3657-
3658-
static unsigned GetVMSetForLMul(RISCVII::VLMUL LMUL) {
3659-
switch (LMUL) {
3660-
case RISCVII::LMUL_F8:
3661-
return RISCV::PseudoVMSET_M_B1;
3662-
case RISCVII::LMUL_F4:
3663-
return RISCV::PseudoVMSET_M_B2;
3664-
case RISCVII::LMUL_F2:
3665-
return RISCV::PseudoVMSET_M_B4;
3666-
case RISCVII::LMUL_1:
3667-
return RISCV::PseudoVMSET_M_B8;
3668-
case RISCVII::LMUL_2:
3669-
return RISCV::PseudoVMSET_M_B16;
3670-
case RISCVII::LMUL_4:
3671-
return RISCV::PseudoVMSET_M_B32;
3672-
case RISCVII::LMUL_8:
3673-
return RISCV::PseudoVMSET_M_B64;
3674-
case RISCVII::LMUL_RESERVED:
3675-
llvm_unreachable("Unexpected LMUL");
3676-
}
3677-
llvm_unreachable("Unknown VLMUL enum");
3678-
}
3679-
36803654
// Try to fold away VMERGE_VVM instructions into their true operands:
36813655
//
36823656
// %true = PseudoVADD_VV ...
@@ -3691,35 +3665,22 @@ static unsigned GetVMSetForLMul(RISCVII::VLMUL LMUL) {
36913665
// If %true is masked, then we can use its mask instead of vmerge's if vmerge's
36923666
// mask is all ones.
36933667
//
3694-
// We can also fold a VMV_V_V into its true operand, since it is equivalent to a
3695-
// VMERGE_VVM with an all ones mask.
3696-
//
36973668
// The resulting VL is the minimum of the two VLs.
36983669
//
36993670
// The resulting policy is the effective policy the vmerge would have had,
37003671
// i.e. whether or not it's merge operand was implicit-def.
37013672
bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
37023673
SDValue Merge, False, True, VL, Mask, Glue;
3703-
// A vmv.v.v is equivalent to a vmerge with an all-ones mask.
3704-
if (IsVMv(N)) {
3705-
Merge = N->getOperand(0);
3706-
False = N->getOperand(0);
3707-
True = N->getOperand(1);
3708-
VL = N->getOperand(2);
3709-
// A vmv.v.v won't have a Mask or Glue, instead we'll construct an all-ones
3710-
// mask later below.
3711-
} else {
3712-
assert(IsVMerge(N));
3713-
Merge = N->getOperand(0);
3714-
False = N->getOperand(1);
3715-
True = N->getOperand(2);
3716-
Mask = N->getOperand(3);
3717-
VL = N->getOperand(4);
3718-
// We always have a glue node for the mask at v0.
3719-
Glue = N->getOperand(N->getNumOperands() - 1);
3720-
}
3721-
assert(!Mask || cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0);
3722-
assert(!Glue || Glue.getValueType() == MVT::Glue);
3674+
assert(IsVMerge(N));
3675+
Merge = N->getOperand(0);
3676+
False = N->getOperand(1);
3677+
True = N->getOperand(2);
3678+
Mask = N->getOperand(3);
3679+
VL = N->getOperand(4);
3680+
// We always have a glue node for the mask at v0.
3681+
Glue = N->getOperand(N->getNumOperands() - 1);
3682+
assert(cast<RegisterSDNode>(Mask)->getReg() == RISCV::V0);
3683+
assert(Glue.getValueType() == MVT::Glue);
37233684

37243685
// We require that either merge and false are the same, or that merge
37253686
// is undefined.
@@ -3763,7 +3724,7 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
37633724

37643725
// If True is masked then the vmerge must have either the same mask or an all
37653726
// 1s mask, since we're going to keep the mask from True.
3766-
if (IsMasked && Mask) {
3727+
if (IsMasked) {
37673728
// FIXME: Support mask agnostic True instruction which would have an
37683729
// undef merge operand.
37693730
SDValue TrueMask =
@@ -3793,11 +3754,9 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
37933754
SmallVector<const SDNode *, 4> LoopWorklist;
37943755
SmallPtrSet<const SDNode *, 16> Visited;
37953756
LoopWorklist.push_back(False.getNode());
3796-
if (Mask)
3797-
LoopWorklist.push_back(Mask.getNode());
3757+
LoopWorklist.push_back(Mask.getNode());
37983758
LoopWorklist.push_back(VL.getNode());
3799-
if (Glue)
3800-
LoopWorklist.push_back(Glue.getNode());
3759+
LoopWorklist.push_back(Glue.getNode());
38013760
if (SDNode::hasPredecessorHelper(True.getNode(), Visited, LoopWorklist))
38023761
return false;
38033762
}
@@ -3857,21 +3816,6 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
38573816
Glue = True->getOperand(True->getNumOperands() - 1);
38583817
assert(Glue.getValueType() == MVT::Glue);
38593818
}
3860-
// If we end up using the vmerge mask the vmerge is actually a vmv.v.v, create
3861-
// an all-ones mask to use.
3862-
else if (IsVMv(N)) {
3863-
unsigned TSFlags = TII->get(N->getMachineOpcode()).TSFlags;
3864-
unsigned VMSetOpc = GetVMSetForLMul(RISCVII::getLMul(TSFlags));
3865-
ElementCount EC = N->getValueType(0).getVectorElementCount();
3866-
MVT MaskVT = MVT::getVectorVT(MVT::i1, EC);
3867-
3868-
SDValue AllOnesMask =
3869-
SDValue(CurDAG->getMachineNode(VMSetOpc, DL, MaskVT, VL, SEW), 0);
3870-
SDValue MaskCopy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
3871-
RISCV::V0, AllOnesMask, SDValue());
3872-
Mask = CurDAG->getRegister(RISCV::V0, MaskVT);
3873-
Glue = MaskCopy.getValue(1);
3874-
}
38753819

38763820
unsigned MaskedOpc = Info->MaskedPseudo;
38773821
#ifndef NDEBUG
@@ -3950,7 +3894,7 @@ bool RISCVDAGToDAGISel::doPeepholeMergeVVMFold() {
39503894
if (N->use_empty() || !N->isMachineOpcode())
39513895
continue;
39523896

3953-
if (IsVMerge(N) || IsVMv(N))
3897+
if (IsVMerge(N))
39543898
MadeChange |= performCombineVMergeAndVOps(N);
39553899
}
39563900
return MadeChange;

llvm/lib/Target/RISCV/RISCVVectorPeephole.cpp

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class RISCVVectorPeephole : public MachineFunctionPass {
6262
bool convertToWholeRegister(MachineInstr &MI) const;
6363
bool convertToUnmasked(MachineInstr &MI) const;
6464
bool convertVMergeToVMv(MachineInstr &MI) const;
65+
bool foldVMV_V_V(MachineInstr &MI);
6566

6667
bool isAllOnesMask(const MachineInstr *MaskDef) const;
6768

@@ -297,6 +298,143 @@ bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &MI) const {
297298
return true;
298299
}
299300

301+
/// Given two VL operands, returns the one known to be the smallest or nullptr
302+
/// if unknown.
303+
static const MachineOperand *getKnownMinVL(const MachineOperand *LHS,
304+
const MachineOperand *RHS) {
305+
if (LHS->isReg() && RHS->isReg() && LHS->getReg().isVirtual() &&
306+
LHS->getReg() == RHS->getReg())
307+
return LHS;
308+
if (LHS->isImm() && LHS->getImm() == RISCV::VLMaxSentinel)
309+
return RHS;
310+
if (RHS->isImm() && RHS->getImm() == RISCV::VLMaxSentinel)
311+
return LHS;
312+
if (!LHS->isImm() || !RHS->isImm())
313+
return nullptr;
314+
return LHS->getImm() <= RHS->getImm() ? LHS : RHS;
315+
}
316+
317+
/// Check if it's safe to move From down to To, checking that no physical
318+
/// registers are clobbered.
319+
static bool isSafeToMove(const MachineInstr &From, const MachineInstr &To) {
320+
assert(From.getParent() == To.getParent() && !From.hasImplicitDef());
321+
SmallVector<Register> PhysUses;
322+
for (const MachineOperand &MO : From.all_uses())
323+
if (MO.getReg().isPhysical())
324+
PhysUses.push_back(MO.getReg());
325+
bool SawStore = false;
326+
for (auto II = From.getIterator(); II != To.getIterator(); II++) {
327+
for (Register PhysReg : PhysUses)
328+
if (II->definesRegister(PhysReg, nullptr))
329+
return false;
330+
if (II->mayStore()) {
331+
SawStore = true;
332+
break;
333+
}
334+
}
335+
return From.isSafeToMove(nullptr, SawStore);
336+
}
337+
338+
static const RISCV::RISCVMaskedPseudoInfo *
339+
lookupMaskedPseudoInfo(const MachineInstr &MI) {
340+
const RISCV::RISCVMaskedPseudoInfo *Info =
341+
RISCV::lookupMaskedIntrinsicByUnmasked(MI.getOpcode());
342+
if (!Info)
343+
Info = RISCV::getMaskedPseudoInfo(MI.getOpcode());
344+
return Info;
345+
}
346+
347+
/// If a PseudoVMV_V_V is the only user of it's input, fold its passthru and VL
348+
/// into it.
349+
///
350+
/// %x = PseudoVADD_V_V_M1 %passthru, %a, %b, %vl, sew, policy
351+
/// %y = PseudoVMV_V_V_M1 %passthru, %x, %vl, sew, policy
352+
///
353+
/// ->
354+
///
355+
/// %y = PseudoVADD_V_V_M1 %passthru, %a, %b, %vl, sew, policy
356+
bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &MI) {
357+
if (RISCV::getRVVMCOpcode(MI.getOpcode()) != RISCV::VMV_V_V)
358+
return false;
359+
360+
MachineOperand &Passthru = MI.getOperand(1);
361+
MachineInstr *Src = MRI->getVRegDef(MI.getOperand(2).getReg());
362+
363+
if (!MRI->hasOneUse(MI.getOperand(2).getReg()))
364+
return false;
365+
366+
if (!Src || Src->hasUnmodeledSideEffects() ||
367+
Src->getParent() != MI.getParent())
368+
return false;
369+
370+
// Src needs to be a pseudo that's opted into this transform.
371+
const RISCV::RISCVMaskedPseudoInfo *Info = lookupMaskedPseudoInfo(*Src);
372+
if (!Info)
373+
return false;
374+
375+
assert(Src->getNumDefs() == 1 &&
376+
RISCVII::isFirstDefTiedToFirstUse(Src->getDesc()) &&
377+
RISCVII::hasVLOp(Src->getDesc().TSFlags) &&
378+
RISCVII::hasVecPolicyOp(Src->getDesc().TSFlags));
379+
380+
// Src needs to have the same passthru as VMV_V_V
381+
if (Src->getOperand(1).getReg() != RISCV::NoRegister &&
382+
Src->getOperand(1).getReg() != Passthru.getReg())
383+
return false;
384+
385+
// Because Src and MI have the same passthru, we can use either AVL as long as
386+
// it's the smaller of the two.
387+
//
388+
// (src pt, ..., vl=5) x x x x x|. . .
389+
// (vmv.v.v pt, src, vl=3) x x x|. . . . .
390+
// ->
391+
// (src pt, ..., vl=3) x x x|. . . . .
392+
//
393+
// (src pt, ..., vl=3) x x x|. . . . .
394+
// (vmv.v.v pt, src, vl=6) x x x . . .|. .
395+
// ->
396+
// (src pt, ..., vl=3) x x x|. . . . .
397+
MachineOperand &SrcVL = Src->getOperand(RISCVII::getVLOpNum(Src->getDesc()));
398+
const MachineOperand *MinVL = getKnownMinVL(&MI.getOperand(3), &SrcVL);
399+
if (!MinVL)
400+
return false;
401+
402+
bool VLChanged = !MinVL->isIdenticalTo(SrcVL);
403+
bool RaisesFPExceptions = MI.getDesc().mayRaiseFPException() &&
404+
!MI.getFlag(MachineInstr::MIFlag::NoFPExcept);
405+
if (VLChanged && (Info->ActiveElementsAffectResult || RaisesFPExceptions))
406+
return false;
407+
408+
if (!isSafeToMove(*Src, MI))
409+
return false;
410+
411+
// Move Src down to MI, then replace all uses of MI with it.
412+
Src->moveBefore(&MI);
413+
414+
Src->getOperand(1).setReg(Passthru.getReg());
415+
// If Src is masked then its passthru needs to be in VRNoV0.
416+
if (Passthru.getReg() != RISCV::NoRegister)
417+
MRI->constrainRegClass(Passthru.getReg(),
418+
TII->getRegClass(Src->getDesc(), 1, TRI,
419+
*Src->getParent()->getParent()));
420+
421+
if (MinVL->isImm())
422+
SrcVL.ChangeToImmediate(MinVL->getImm());
423+
else if (MinVL->isReg())
424+
SrcVL.ChangeToRegister(MinVL->getReg(), false);
425+
426+
// Use a conservative tu,mu policy, RISCVInsertVSETVLI will relax it if
427+
// passthru is undef.
428+
Src->getOperand(RISCVII::getVecPolicyOpNum(Src->getDesc()))
429+
.setImm(RISCVII::TAIL_UNDISTURBED_MASK_UNDISTURBED);
430+
431+
MRI->replaceRegWith(MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
432+
MI.eraseFromParent();
433+
V0Defs.erase(&MI);
434+
435+
return true;
436+
}
437+
300438
bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
301439
if (skipFunction(MF.getFunction()))
302440
return false;
@@ -331,11 +469,12 @@ bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
331469
}
332470

333471
for (MachineBasicBlock &MBB : MF) {
334-
for (MachineInstr &MI : MBB) {
472+
for (MachineInstr &MI : make_early_inc_range(MBB)) {
335473
Changed |= convertToVLMAX(MI);
336474
Changed |= convertToUnmasked(MI);
337475
Changed |= convertToWholeRegister(MI);
338476
Changed |= convertVMergeToVMv(MI);
477+
Changed |= foldVMV_V_V(MI);
339478
}
340479
}
341480

0 commit comments

Comments
 (0)