[llvm] [RISCV] Move vmv.v.v peephole from SelectionDAG to RISCVVectorPeephole (PR #100367)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 15 22:23:32 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);
----------------
lukel97 wrote:
I've updated it so we only perform the move if the passthru OR vl changed: The VL can get shrunk to MI's VL, in which case it could be a register defined after Src.
https://github.com/llvm/llvm-project/pull/100367
More information about the llvm-commits
mailing list