[llvm] [RISCV] Move vmv.v.v peephole from SelectionDAG to RISCVVectorPeephole (PR #100367)
Philip Reames via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 15 08:06:17 PDT 2024
================
@@ -297,6 +298,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(nullptr, SawStore);
+}
+
+static const RISCV::RISCVMaskedPseudoInfo *
+lookupMaskedPseudoInfo(const MachineInstr &MI) {
+ const RISCV::RISCVMaskedPseudoInfo *Info =
+ RISCV::lookupMaskedIntrinsicByUnmasked(MI.getOpcode());
+ if (!Info)
+ Info = RISCV::getMaskedPseudoInfo(MI.getOpcode());
+ return Info;
+}
+
+/// If a PseudoVMV_V_V is the only user of it's input, fold its passthru and VL
+/// into it.
+///
+/// %x = PseudoVADD_V_V_M1 %passthru, %a, %b, %vl, sew, policy
+/// %y = PseudoVMV_V_V_M1 %passthru, %x, %vl, sew, policy
+///
+/// ->
+///
+/// %y = PseudoVADD_V_V_M1 %passthru, %a, %b, %vl, 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);
+ MachineInstr *Src = MRI->getVRegDef(MI.getOperand(2).getReg());
+
+ if (!MRI->hasOneUse(MI.getOperand(2).getReg()))
+ return false;
+
+ if (!Src || Src->hasUnmodeledSideEffects() ||
+ Src->getParent() != MI.getParent())
+ return false;
+
+ // Src needs to be a pseudo that's opted into this transform.
+ const RISCV::RISCVMaskedPseudoInfo *Info = lookupMaskedPseudoInfo(*Src);
+ if (!Info)
+ return false;
+
+ assert(Src->getNumDefs() == 1 &&
+ RISCVII::isFirstDefTiedToFirstUse(Src->getDesc()) &&
+ RISCVII::hasVLOp(Src->getDesc().TSFlags) &&
+ RISCVII::hasVecPolicyOp(Src->getDesc().TSFlags));
+
+ // Src needs to have the same passthru as VMV_V_V
+ if (Src->getOperand(1).getReg() != RISCV::NoRegister &&
+ Src->getOperand(1).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 RaisesFPExceptions = MI.getDesc().mayRaiseFPException() &&
+ !MI.getFlag(MachineInstr::MIFlag::NoFPExcept);
+ if (VLChanged && (Info->ActiveElementsAffectResult || RaisesFPExceptions))
+ return false;
+
+ if (!isSafeToMove(*Src, MI))
+ return false;
+
+ // Move Src down to MI, then replace all uses of MI with it.
+ Src->moveBefore(&MI);
----------------
preames wrote:
This movement only needs to happen in the case where the Passthru is changing. Can you move both the movement and the safety check to inside the if block just below? It would make the code a bit easier to follow.
Worth noting here is that we only need to move the Src if-and-only-if MI's psssthru is defined between the instructions. It may be illegal to move Src in some cases that the passthru is defined *before* src. You don't need to change that in this review, it's purely a potential missed optimization. Maybe leave a TODO though.
https://github.com/llvm/llvm-project/pull/100367
More information about the llvm-commits
mailing list