40#define DEBUG_TYPE "riscv-vector-peephole"
44class RISCVVectorPeepholeImpl {
69 lookThruCopies(
Register Reg,
bool OneUseOnly =
false,
85 return "RISC-V Vector Peephole Optimization";
97char RISCVVectorPeepholeLegacy::ID = 0;
106 unsigned UserLog2SEW =
108 unsigned SrcLog2SEW =
112 return SrcLog2EEW == UserLog2SEW;
116std::optional<unsigned>
117RISCVVectorPeepholeImpl::getConstant(
const MachineOperand &VL)
const {
124 if (!Def ||
Def->getOpcode() != RISCV::ADDI || !
Def->getOperand(1).isReg() ||
125 Def->getOperand(1).getReg() != RISCV::X0)
127 return Def->getOperand(2).getImm();
131bool RISCVVectorPeepholeImpl::convertToVLMAX(MachineInstr &
MI)
const {
138 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
141 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
143 assert(8 * LMULFixed / SEW > 0);
148 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
164 if (
Def->getOpcode() == RISCV::SLLI) {
165 assert(
Def->getOperand(2).getImm() < 64);
166 ScaleFixed <<=
Def->getOperand(2).getImm();
168 }
else if (
Def->getOpcode() == RISCV::SRLI) {
169 assert(
Def->getOperand(2).getImm() < 64);
170 ScaleFixed >>=
Def->getOperand(2).getImm();
174 if (!Def ||
Def->getOpcode() != RISCV::PseudoReadVLENB)
184 if (ScaleFixed != 8 * LMULFixed / SEW)
192bool RISCVVectorPeepholeImpl::isAllOnesMask(
const MachineInstr *MaskDef)
const {
200 case RISCV::PseudoVMSET_M_B1:
201 case RISCV::PseudoVMSET_M_B2:
202 case RISCV::PseudoVMSET_M_B4:
203 case RISCV::PseudoVMSET_M_B8:
204 case RISCV::PseudoVMSET_M_B16:
205 case RISCV::PseudoVMSET_M_B32:
206 case RISCV::PseudoVMSET_M_B64:
223bool RISCVVectorPeepholeImpl::convertToWholeRegister(MachineInstr &
MI)
const {
224#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
225 case RISCV::PseudoVLE##sew##_V_M##lmul: \
226 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
228 case RISCV::PseudoVSE##sew##_V_M##lmul: \
229 NewOpc = RISCV::VS##lmul##R_V; \
231#define CASE_WHOLE_REGISTER_LMUL(lmul) \
232 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
233 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
234 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
235 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
238 switch (
MI.getOpcode()) {
247 MachineOperand &VLOp =
MI.getOperand(RISCVII::getVLOpNum(
MI.getDesc()));
248 if (!VLOp.isImm() || VLOp.
getImm() != RISCV::VLMaxSentinel)
253 if (RISCVII::hasVecPolicyOp(
MI.getDesc().TSFlags))
254 MI.removeOperand(RISCVII::getVecPolicyOpNum(
MI.getDesc()));
255 MI.removeOperand(RISCVII::getSEWOpNum(
MI.getDesc()));
256 MI.removeOperand(RISCVII::getVLOpNum(
MI.getDesc()));
257 if (RISCVII::isFirstDefTiedToFirstUse(
MI.getDesc()))
265static
unsigned getVMV_V_VOpcodeForVMERGE_VVM(
const MachineInstr &
MI) {
266#define CASE_VMERGE_TO_VMV(lmul) \
267 case RISCV::PseudoVMERGE_VVM_##lmul: \
268 return RISCV::PseudoVMV_V_V_##lmul;
269 switch (
MI.getOpcode()) {
272 CASE_VMERGE_TO_VMV(MF8)
273 CASE_VMERGE_TO_VMV(MF4)
274 CASE_VMERGE_TO_VMV(MF2)
275 CASE_VMERGE_TO_VMV(M1)
276 CASE_VMERGE_TO_VMV(M2)
277 CASE_VMERGE_TO_VMV(M4)
278 CASE_VMERGE_TO_VMV(M8)
287bool RISCVVectorPeepholeImpl::convertAllOnesVMergeToVMv(
288 MachineInstr &
MI)
const {
289 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
295 MI.setDesc(
TII->get(NewOpc));
304 if (
MI.getOperand(1).getReg().isValid())
311Register RISCVVectorPeepholeImpl::lookThruCopies(
313 SmallVectorImpl<MachineInstr *> *
Copies)
const {
315 if (!
Def->isFullCopy())
318 if (!Src.isVirtual())
338bool RISCVVectorPeepholeImpl::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
339 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
344 if (!
True ||
True->getParent() !=
MI.getParent())
347 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(
True->getOpcode());
348 if (!TrueMaskedInfo || !hasSameEEW(
MI, *
True))
351 Register TrueMaskReg = lookThruCopies(
352 True->getOperand(TrueMaskedInfo->MaskOpIdx +
True->getNumExplicitDefs())
354 Register MIMaskReg = lookThruCopies(
MI.getOperand(4).getReg());
355 if (!TrueMaskReg.
isVirtual() || TrueMaskReg != MIMaskReg)
363 const MachineOperand &TrueVL =
365 Register FalseReg =
MI.getOperand(2).getReg();
367 Register PassthruReg =
MI.getOperand(1).getReg();
368 if (FalseReg.
isValid() && FalseReg != PassthruReg)
379 Register TruePassthruReg =
True->getOperand(1).getReg();
380 if (TruePassthruReg != FalseReg) {
382 if (TruePassthruReg.
isValid() ||
384 !ensureDominates(&
MI.getOperand(2), *
True))
386 True->getOperand(1).setReg(
MI.getOperand(2).getReg());
389 TII->getRegClass(
True->getDesc(), 1));
394 MachineOperand &PolicyOp =
399 MI.setDesc(
TII->get(NewOpc));
408 if (
MI.getOperand(1).getReg().isValid())
413bool RISCVVectorPeepholeImpl::convertToUnmasked(MachineInstr &
MI)
const {
414 const RISCV::RISCVMaskedPseudoInfo *
I =
415 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
420 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
425 const unsigned Opc =
I->UnmaskedPseudo;
426 const MCInstrDesc &MCID =
TII->get(
Opc);
427 [[maybe_unused]]
const bool HasPolicyOp =
430 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
433 "Unmasked pseudo has policy but masked pseudo doesn't?");
434 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
436 "Unmasked with passthru but masked with no passthru?");
447 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
448 MI.removeOperand(MaskOpIdx);
456 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
458 if (
MI.getOperand(PassthruOpIdx).getReg())
461 MI.removeOperand(PassthruOpIdx);
470 assert(
A->getParent() ==
B->getParent());
474 auto MBBEnd =
MBB->end();
479 for (; &*
I !=
A && &*
I !=
B; ++
I)
488bool RISCVVectorPeepholeImpl::ensureDominates(
490 MachineInstr *Dest = &
Use;
492 for (
const MachineOperand *MO : Defs) {
493 assert(MO->getParent()->getParent() ==
Use.getParent());
494 if (!MO->isReg() || !MO->getReg().isValid())
502 Dest =
Def->getNextNode();
507 Use.moveBefore(Dest);
513bool RISCVVectorPeepholeImpl::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
516 if (
MI.getOperand(1).getReg().isValid())
522 if (Src && !Src->hasUnmodeledSideEffects() &&
526 const MachineOperand &MIVL =
MI.getOperand(3);
527 const MachineOperand &SrcVL =
530 MachineOperand &SrcPolicy =
540 MI.eraseFromParent();
554bool RISCVVectorPeepholeImpl::foldVMV_V_V(MachineInstr &
MI) {
558 MachineOperand &Passthru =
MI.getOperand(1);
564 if (!Src || Src->hasUnmodeledSideEffects() ||
565 Src->getParent() !=
MI.getParent() ||
571 if (!hasSameEEW(
MI, *Src))
574 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
577 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
582 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
585 unsigned OpIdx1 = OtherIdx;
586 unsigned OpIdx2 = Src->getNumExplicitDefs();
587 if (!
TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
589 NeedsCommute = {OpIdx1, OpIdx2};
600 if (!ensureDominates(&Passthru, *Src))
604 auto [OpIdx1, OpIdx2] = *NeedsCommute;
605 [[maybe_unused]]
bool Commuted =
606 TII->commuteInstruction(*Src,
false, OpIdx1, OpIdx2);
607 assert(Commuted &&
"Failed to commute Src?");
631 MI.eraseFromParent();
654bool RISCVVectorPeepholeImpl::foldVMergeToMask(MachineInstr &
MI)
const {
659 SmallVector<MachineInstr *, 4> TrueCopies;
660 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
661 const MachineOperand &FalseOp =
MI.getOperand(2);
663 Register TrueReg = lookThruCopies(
MI.getOperand(3).getReg(),
670 MachineInstr &
True = *TrueDef;
671 if (
True.getParent() !=
MI.getParent())
677 const RISCV::RISCVMaskedPseudoInfo *
Info =
678 RISCV::lookupMaskedIntrinsicByUnmasked(
True.getOpcode());
683 if (!hasSameEEW(
MI,
True))
688 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
691 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
698 lookThruCopies(
True.getOperand(
True.getNumExplicitDefs()).getReg());
699 if (TruePassthru && !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
702 int OtherIdx =
True.findRegisterUseOperandIdx(FalseReg,
TRI);
705 unsigned OpIdx1 = OtherIdx;
706 unsigned OpIdx2 =
True.getNumExplicitDefs();
707 if (!
TII->findCommutedOpIndices(
True, OpIdx1, OpIdx2))
709 NeedsCommute = {OpIdx1, OpIdx2};
714 if (
True.hasUnmodeledSideEffects() ||
True.mayRaiseFPException())
717 const MachineOperand &VMergeVL =
719 const MachineOperand &TrueVL =
727 else if (!TruePassthru && !
True.mayLoadOrStore())
734 unsigned RVVTSFlags =
TII->get(RVVOpc).TSFlags;
752 "Foldable unmasked pseudo should have a policy op already");
756 if (!ensureDominates({&MaskOp, &FalseOp, &MinVL},
True))
760 auto [OpIdx1, OpIdx2] = *NeedsCommute;
761 [[maybe_unused]]
bool Commuted =
762 TII->commuteInstruction(
True,
false, OpIdx1, OpIdx2);
763 assert(Commuted &&
"Failed to commute True?");
764 Info = RISCV::lookupMaskedIntrinsicByUnmasked(
True.getOpcode());
772 True.getNumExplicitDefs(),
776 True.getOperand(
True.getNumExplicitDefs()).setReg(FalseReg);
784 for (MachineOperand &MO :
True.explicit_operands()) {
785 if (!MO.isReg() || !MO.getReg().isVirtual())
788 MO.getReg(),
True.getRegClassConstraint(MO.getOperandNo(),
TII,
TRI));
790 MI.eraseFromParent();
794 for (MachineInstr *TrueCopy : TrueCopies)
795 TrueCopy->eraseFromParent();
816bool RISCVVectorPeepholeImpl::foldVMANDToMaskedCompare(MachineInstr &
MI)
const {
831 for (
unsigned CmpIdx : {1, 2}) {
832 unsigned MaskIdx = CmpIdx == 1 ? 2 : 1;
836 SmallVector<MachineInstr *, 4> CmpCopies;
837 Register CmpReg = lookThruCopies(
MI.getOperand(CmpIdx).getReg(),
842 if (
Cmp.getParent() !=
MI.getParent())
844 if (!RISCVInstrInfo::isRVVCompare(Cmp))
848 const RISCV::RISCVMaskedPseudoInfo *
Info =
849 RISCV::lookupMaskedIntrinsicByUnmasked(
Cmp.getOpcode());
854 if (!hasSameEEW(
MI, Cmp))
859 if (
Cmp.hasUnmodeledSideEffects() ||
Cmp.mayRaiseFPException())
866 const MachineOperand &CmpVL =
868 const MachineOperand &MIVL =
873 const MachineOperand &MaskOp =
MI.getOperand(MaskIdx);
876 unsigned MaskedOpc =
Info->MaskedPseudo;
877 const MCInstrDesc &MaskedDesc =
TII->get(MaskedOpc);
887 if (!
TII->getRegClass(MaskedDesc, 0)->contains(RISCV::V0))
891 if (!ensureDominates({&MaskOp, &MIVL},
Cmp))
900 TII->get(TargetOpcode::COPY), MaskV0Reg)
906 TII->get(TargetOpcode::COPY), PassthruReg)
916 BuildMI(*
MI.getParent(), Cmp, MIMetadata(Cmp), MaskedDesc, DestReg)
931 for (MachineOperand &MO :
Masked->explicit_operands()) {
932 if (!MO.isReg() || !MO.getReg().isVirtual())
935 Masked->getRegClassConstraint(MO.getOperandNo(),
TII,
TRI))
938 MI.eraseFromParent();
939 Cmp.eraseFromParent();
940 for (MachineInstr *CmpCopy : CmpCopies)
941 CmpCopy->eraseFromParent();
961 for (MachineBasicBlock &
MBB : MF) {
972 Changed |= convertAllOnesVMergeToVMv(
MI);
973 Changed |= convertSameMaskVMergeToVMv(
MI);
974 if (foldUndefPassthruVMV_V_V(
MI)) {
985bool RISCVVectorPeepholeLegacy::runOnMachineFunction(
MachineFunction &MF) {
988 return RISCVVectorPeepholeImpl().run(MF);
995 bool Changed = RISCVVectorPeepholeImpl().run(MF);
1006 return new RISCVVectorPeepholeLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static uint64_t getConstant(const Value *IndexValue)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
MachineRegisterInfo & MRI
static bool strictlyDominates(MachineBasicBlock::const_iterator A, MachineBasicBlock::const_iterator B)
Given A and B are in the same MBB, returns true if A comes before B.
#define CASE_WHOLE_REGISTER_LMUL(lmul)
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
An RAII based helper class to modify MachineFunctionProperties when running pass.
MachineInstrBundleIterator< const MachineInstr > const_iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI unsigned getOperandNo() const
Returns the index of this operand in the instruction that it belongs to.
void setImm(int64_t immVal)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI bool recomputeRegClass(Register Reg)
recomputeRegClass - Try to find a legal super-class of Reg's register class that still satisfies the ...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
const TargetRegisterInfo * getTargetRegisterInfo() const
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
static bool isSafeToMove(const MachineInstr &From, const MachineBasicBlock::iterator &To)
Return true if moving From down to To won't cause any physical register reads or writes to be clobber...
bool hasVInstructions() const
std::optional< unsigned > getRealVLen() const
const RISCVInstrInfo * getInstrInfo() const override
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Represent a constant reference to a string, i.e.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
static unsigned getVecPolicyOpNum(const MCInstrDesc &Desc)
static RISCVVType::VLMUL getLMul(uint64_t TSFlags)
static unsigned getVLOpNum(const MCInstrDesc &Desc)
static bool hasVLOp(uint64_t TSFlags)
static bool elementsDependOnMask(uint64_t TSFlags)
static bool hasVecPolicyOp(uint64_t TSFlags)
static unsigned getSEWOpNum(const MCInstrDesc &Desc)
static bool elementsDependOnVL(uint64_t TSFlags)
static bool hasSEWOp(uint64_t TSFlags)
static bool isFirstDefTiedToFirstUse(const MCInstrDesc &Desc)
@ TAIL_UNDISTURBED_MASK_UNDISTURBED
LLVM_ABI std::pair< unsigned, bool > decodeVLMUL(VLMUL VLMul)
static bool isValidSEW(unsigned SEW)
unsigned getRVVMCOpcode(unsigned RVVPseudoOpcode)
unsigned getDestLog2EEW(const MCInstrDesc &Desc, unsigned Log2SEW)
static constexpr int64_t VLMaxSentinel
bool isVLKnownLE(const MachineRegisterInfo &MRI, const MachineOperand &LHS, const MachineOperand &RHS)
Given two VL operands, do we know that LHS <= RHS?
NodeAddr< DefNode * > Def
NodeAddr< UseNode * > Use
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createRISCVVectorPeepholeLegacyPass()
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
ArrayRef(const T &OneElt) -> ArrayRef< T >
MCRegisterClass TargetRegisterClass