-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RISCV] Move vmv.v.v peephole from SelectionDAG to RISCVVectorPeephole #100367
Changes from all commits
6208fcd
957d7f5
a621896
bcd80a7
8bb02da
f41e0f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,7 @@ class RISCVVectorPeephole : public MachineFunctionPass { | |
bool convertToWholeRegister(MachineInstr &MI) const; | ||
bool convertToUnmasked(MachineInstr &MI) const; | ||
bool convertVMergeToVMv(MachineInstr &MI) const; | ||
bool foldVMV_V_V(MachineInstr &MI); | ||
|
||
bool isAllOnesMask(const MachineInstr *MaskDef) const; | ||
std::optional<unsigned> getConstant(const MachineOperand &VL) const; | ||
|
@@ -324,6 +325,143 @@ bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &MI) const { | |
return true; | ||
} | ||
|
||
/// Given two VL operands, returns the one known to be the smallest or nullptr | ||
/// if unknown. | ||
static const MachineOperand *getKnownMinVL(const MachineOperand *LHS, | ||
const MachineOperand *RHS) { | ||
if (LHS->isReg() && RHS->isReg() && LHS->getReg().isVirtual() && | ||
LHS->getReg() == RHS->getReg()) | ||
return LHS; | ||
if (LHS->isImm() && LHS->getImm() == RISCV::VLMaxSentinel) | ||
return RHS; | ||
if (RHS->isImm() && RHS->getImm() == RISCV::VLMaxSentinel) | ||
return LHS; | ||
if (!LHS->isImm() || !RHS->isImm()) | ||
return nullptr; | ||
return LHS->getImm() <= RHS->getImm() ? LHS : RHS; | ||
} | ||
|
||
/// Check if it's safe to move From down to To, checking that no physical | ||
/// registers are clobbered. | ||
static bool isSafeToMove(const MachineInstr &From, const MachineInstr &To) { | ||
assert(From.getParent() == To.getParent() && !From.hasImplicitDef()); | ||
SmallVector<Register> PhysUses; | ||
for (const MachineOperand &MO : From.all_uses()) | ||
if (MO.getReg().isPhysical()) | ||
PhysUses.push_back(MO.getReg()); | ||
bool SawStore = false; | ||
for (auto II = From.getIterator(); II != To.getIterator(); II++) { | ||
for (Register PhysReg : PhysUses) | ||
if (II->definesRegister(PhysReg, nullptr)) | ||
return false; | ||
if (II->mayStore()) { | ||
SawStore = true; | ||
break; | ||
} | ||
} | ||
return From.isSafeToMove(SawStore); | ||
} | ||
|
||
static unsigned getSEWLMULRatio(const MachineInstr &MI) { | ||
RISCVII::VLMUL LMUL = RISCVII::getLMul(MI.getDesc().TSFlags); | ||
unsigned Log2SEW = MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm(); | ||
return RISCVVType::getSEWLMULRatio(1 << Log2SEW, LMUL); | ||
} | ||
|
||
/// If a PseudoVMV_V_V is the only user of its input, fold its passthru and VL | ||
/// into it. | ||
/// | ||
/// %x = PseudoVADD_V_V_M1 %passthru, %a, %b, %vl1, sew, policy | ||
/// %y = PseudoVMV_V_V_M1 %passthru, %x, %vl2, sew, policy | ||
/// | ||
/// -> | ||
/// | ||
/// %y = PseudoVADD_V_V_M1 %passthru, %a, %b, min(vl1, vl2), sew, policy | ||
bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &MI) { | ||
if (RISCV::getRVVMCOpcode(MI.getOpcode()) != RISCV::VMV_V_V) | ||
return false; | ||
|
||
MachineOperand &Passthru = MI.getOperand(1); | ||
|
||
if (!MRI->hasOneUse(MI.getOperand(2).getReg())) | ||
lukel97 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return false; | ||
|
||
MachineInstr *Src = MRI->getVRegDef(MI.getOperand(2).getReg()); | ||
if (!Src || Src->hasUnmodeledSideEffects() || | ||
Src->getParent() != MI.getParent() || Src->getNumDefs() != 1 || | ||
!RISCVII::isFirstDefTiedToFirstUse(Src->getDesc()) || | ||
!RISCVII::hasVLOp(Src->getDesc().TSFlags) || | ||
!RISCVII::hasVecPolicyOp(Src->getDesc().TSFlags)) | ||
return false; | ||
|
||
// Src needs to have the same VLMAX as MI | ||
if (getSEWLMULRatio(MI) != getSEWLMULRatio(*Src)) | ||
return false; | ||
|
||
// Src needs to have the same passthru as VMV_V_V | ||
MachineOperand &SrcPassthru = Src->getOperand(1); | ||
if (SrcPassthru.getReg() != RISCV::NoRegister && | ||
SrcPassthru.getReg() != Passthru.getReg()) | ||
return false; | ||
|
||
// Because Src and MI have the same passthru, we can use either AVL as long as | ||
// it's the smaller of the two. | ||
// | ||
// (src pt, ..., vl=5) x x x x x|. . . | ||
// (vmv.v.v pt, src, vl=3) x x x|. . . . . | ||
// -> | ||
// (src pt, ..., vl=3) x x x|. . . . . | ||
// | ||
// (src pt, ..., vl=3) x x x|. . . . . | ||
// (vmv.v.v pt, src, vl=6) x x x . . .|. . | ||
// -> | ||
// (src pt, ..., vl=3) x x x|. . . . . | ||
MachineOperand &SrcVL = Src->getOperand(RISCVII::getVLOpNum(Src->getDesc())); | ||
const MachineOperand *MinVL = getKnownMinVL(&MI.getOperand(3), &SrcVL); | ||
if (!MinVL) | ||
return false; | ||
|
||
bool VLChanged = !MinVL->isIdenticalTo(SrcVL); | ||
bool ActiveElementsAffectResult = RISCVII::activeElementsAffectResult( | ||
TII->get(RISCV::getRVVMCOpcode(Src->getOpcode())).TSFlags); | ||
|
||
if (VLChanged && (ActiveElementsAffectResult || Src->mayRaiseFPException())) | ||
return false; | ||
|
||
// If Src ends up using MI's passthru/VL, move it so it can access it. | ||
// TODO: We don't need to do this if they already dominate Src. | ||
if (!SrcVL.isIdenticalTo(*MinVL) || !SrcPassthru.isIdenticalTo(Passthru)) { | ||
if (!isSafeToMove(*Src, MI)) | ||
return false; | ||
Src->moveBefore(&MI); | ||
} | ||
|
||
if (SrcPassthru.getReg() != Passthru.getReg()) { | ||
SrcPassthru.setReg(Passthru.getReg()); | ||
// If Src is masked then its passthru needs to be in VRNoV0. | ||
if (Passthru.getReg() != RISCV::NoRegister) | ||
MRI->constrainRegClass(Passthru.getReg(), | ||
TII->getRegClass(Src->getDesc(), 1, TRI, | ||
*Src->getParent()->getParent())); | ||
} | ||
|
||
if (MinVL->isImm()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reading through this code, I'm left with a question. If the Src instruction uses a different SEW than the vmv.v.v, why is it legal to reduce the VL without accounting for the different size of the elements? I can't find that check in the DAG version of this code either. Am I forgetting something here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yikes good catch. Looks like we're miscompiling this in the DAG version too, and I don't think it's legal to fold in the mask either. Fix incoming There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fixed now in this PR, but by checking the VLMAXes are the same since we don't have access to the MVTs here. |
||
SrcVL.ChangeToImmediate(MinVL->getImm()); | ||
else if (MinVL->isReg()) | ||
SrcVL.ChangeToRegister(MinVL->getReg(), false); | ||
|
||
// Use a conservative tu,mu policy, RISCVInsertVSETVLI will relax it if | ||
// passthru is undef. | ||
Src->getOperand(RISCVII::getVecPolicyOpNum(Src->getDesc())) | ||
.setImm(RISCVII::TAIL_UNDISTURBED_MASK_UNDISTURBED); | ||
|
||
MRI->replaceRegWith(MI.getOperand(0).getReg(), Src->getOperand(0).getReg()); | ||
MI.eraseFromParent(); | ||
V0Defs.erase(&MI); | ||
|
||
return true; | ||
} | ||
|
||
bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) { | ||
if (skipFunction(MF.getFunction())) | ||
return false; | ||
|
@@ -358,11 +496,12 @@ bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) { | |
} | ||
|
||
for (MachineBasicBlock &MBB : MF) { | ||
for (MachineInstr &MI : MBB) { | ||
for (MachineInstr &MI : make_early_inc_range(MBB)) { | ||
Changed |= convertToVLMAX(MI); | ||
Changed |= convertToUnmasked(MI); | ||
Changed |= convertToWholeRegister(MI); | ||
Changed |= convertVMergeToVMv(MI); | ||
Changed |= foldVMV_V_V(MI); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a concern about the naming there. It is not consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I noticed this as well. I think the camel case in convertVMergeToVMv came from trying to please clang-tidy. But VMV_V_V is more accurate to the actual instruction name. Do we have a preference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard to decide... I don't have a preference, maybe just keep it, we already have a lof of exceptions in RISCVISelLowering now.