40#define DEBUG_TYPE "riscv-vector-peephole"
59 return "RISC-V Vector Peephole Optimization";
84 lookThruCopies(
Register Reg,
bool OneUseOnly =
false,
90char RISCVVectorPeephole::ID = 0;
99 unsigned UserLog2SEW =
101 unsigned SrcLog2SEW =
105 return SrcLog2EEW == UserLog2SEW;
109std::optional<unsigned>
115 if (!Def ||
Def->getOpcode() != RISCV::ADDI || !
Def->getOperand(1).isReg() ||
116 Def->getOperand(1).getReg() != RISCV::X0)
118 return Def->getOperand(2).getImm();
122bool RISCVVectorPeephole::convertToVLMAX(MachineInstr &
MI)
const {
129 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
132 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
134 assert(8 * LMULFixed / SEW > 0);
139 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
153 uint64_t ScaleFixed = 8;
155 if (
Def->getOpcode() == RISCV::SLLI) {
156 assert(
Def->getOperand(2).getImm() < 64);
157 ScaleFixed <<=
Def->getOperand(2).getImm();
159 }
else if (
Def->getOpcode() == RISCV::SRLI) {
160 assert(
Def->getOperand(2).getImm() < 64);
161 ScaleFixed >>=
Def->getOperand(2).getImm();
165 if (!Def ||
Def->getOpcode() != RISCV::PseudoReadVLENB)
175 if (ScaleFixed != 8 * LMULFixed / SEW)
183bool RISCVVectorPeephole::isAllOnesMask(
const MachineInstr *MaskDef)
const {
191 case RISCV::PseudoVMSET_M_B1:
192 case RISCV::PseudoVMSET_M_B2:
193 case RISCV::PseudoVMSET_M_B4:
194 case RISCV::PseudoVMSET_M_B8:
195 case RISCV::PseudoVMSET_M_B16:
196 case RISCV::PseudoVMSET_M_B32:
197 case RISCV::PseudoVMSET_M_B64:
214bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &
MI)
const {
215#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
216 case RISCV::PseudoVLE##sew##_V_M##lmul: \
217 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
219 case RISCV::PseudoVSE##sew##_V_M##lmul: \
220 NewOpc = RISCV::VS##lmul##R_V; \
222#define CASE_WHOLE_REGISTER_LMUL(lmul) \
223 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
224 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
225 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
226 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
229 switch (
MI.getOpcode()) {
238 MachineOperand &VLOp =
MI.getOperand(RISCVII::getVLOpNum(
MI.getDesc()));
239 if (!VLOp.isImm() || VLOp.
getImm() != RISCV::VLMaxSentinel)
244 if (RISCVII::hasVecPolicyOp(
MI.getDesc().TSFlags))
245 MI.removeOperand(RISCVII::getVecPolicyOpNum(
MI.getDesc()));
246 MI.removeOperand(RISCVII::getSEWOpNum(
MI.getDesc()));
247 MI.removeOperand(RISCVII::getVLOpNum(
MI.getDesc()));
248 if (RISCVII::isFirstDefTiedToFirstUse(
MI.getDesc()))
256static
unsigned getVMV_V_VOpcodeForVMERGE_VVM(
const MachineInstr &
MI) {
257#define CASE_VMERGE_TO_VMV(lmul) \
258 case RISCV::PseudoVMERGE_VVM_##lmul: \
259 return RISCV::PseudoVMV_V_V_##lmul;
260 switch (
MI.getOpcode()) {
263 CASE_VMERGE_TO_VMV(MF8)
264 CASE_VMERGE_TO_VMV(MF4)
265 CASE_VMERGE_TO_VMV(MF2)
266 CASE_VMERGE_TO_VMV(M1)
267 CASE_VMERGE_TO_VMV(M2)
268 CASE_VMERGE_TO_VMV(M4)
269 CASE_VMERGE_TO_VMV(M8)
278bool RISCVVectorPeephole::convertAllOnesVMergeToVMv(MachineInstr &
MI)
const {
279 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
282 if (!isAllOnesMask(MRI->
getVRegDef(
MI.getOperand(4).getReg())))
285 MI.setDesc(
TII->get(NewOpc));
294 if (
MI.getOperand(1).getReg().isValid())
301Register RISCVVectorPeephole::lookThruCopies(
303 SmallVectorImpl<MachineInstr *> *
Copies)
const {
305 if (!
Def->isFullCopy())
308 if (!Src.isVirtual())
328bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
329 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
332 MachineInstr *True = MRI->
getVRegDef(
MI.getOperand(3).getReg());
337 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->
getOpcode());
338 if (!TrueMaskedInfo || !hasSameEEW(
MI, *True))
341 Register TrueMaskReg = lookThruCopies(
344 Register MIMaskReg = lookThruCopies(
MI.getOperand(4).getReg());
345 if (!TrueMaskReg.
isVirtual() || TrueMaskReg != MIMaskReg)
353 const MachineOperand &TrueVL =
355 Register FalseReg =
MI.getOperand(2).getReg();
357 Register PassthruReg =
MI.getOperand(1).getReg();
358 if (FalseReg.
isValid() && FalseReg != PassthruReg)
362 uint64_t TruePolicy =
370 if (TruePassthruReg != FalseReg) {
372 if (TruePassthruReg.
isValid() ||
374 !ensureDominates(&
MI.getOperand(2), *True))
384 MachineOperand &PolicyOp =
389 MI.setDesc(
TII->get(NewOpc));
398 if (
MI.getOperand(1).getReg().isValid())
403bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
404 const RISCV::RISCVMaskedPseudoInfo *
I =
405 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
410 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
415 const unsigned Opc =
I->UnmaskedPseudo;
416 const MCInstrDesc &MCID =
TII->get(
Opc);
417 [[maybe_unused]]
const bool HasPolicyOp =
420 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
423 "Unmasked pseudo has policy but masked pseudo doesn't?");
424 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
426 "Unmasked with passthru but masked with no passthru?");
437 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
438 MI.removeOperand(MaskOpIdx);
446 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
448 if (
MI.getOperand(PassthruOpIdx).getReg())
451 MI.removeOperand(PassthruOpIdx);
460 assert(
A->getParent() ==
B->getParent());
464 auto MBBEnd =
MBB->end();
469 for (; &*
I !=
A && &*
I !=
B; ++
I)
479 MachineInstr &Use)
const {
480 MachineInstr *Dest = &
Use;
482 for (
const MachineOperand *MO : Defs) {
483 assert(MO->getParent()->getParent() ==
Use.getParent());
484 if (!MO->isReg() || !MO->getReg().isValid())
492 Dest =
Def->getNextNode();
497 Use.moveBefore(Dest);
503bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
506 if (
MI.getOperand(1).getReg().isValid())
511 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
512 if (Src && !Src->hasUnmodeledSideEffects() &&
516 const MachineOperand &MIVL =
MI.getOperand(3);
517 const MachineOperand &SrcVL =
520 MachineOperand &SrcPolicy =
531 MI.eraseFromParent();
545bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
549 MachineOperand &Passthru =
MI.getOperand(1);
554 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
555 if (!Src || Src->hasUnmodeledSideEffects() ||
556 Src->getParent() !=
MI.getParent() ||
562 if (!hasSameEEW(
MI, *Src))
565 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
568 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
573 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
576 unsigned OpIdx1 = OtherIdx;
577 unsigned OpIdx2 = Src->getNumExplicitDefs();
578 if (!
TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
580 NeedsCommute = {OpIdx1, OpIdx2};
591 if (!ensureDominates(&Passthru, *Src))
595 auto [OpIdx1, OpIdx2] = *NeedsCommute;
596 [[maybe_unused]]
bool Commuted =
597 TII->commuteInstruction(*Src,
false, OpIdx1, OpIdx2);
598 assert(Commuted &&
"Failed to commute Src?");
621 MRI->
replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
622 MI.eraseFromParent();
645bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
650 SmallVector<MachineInstr *, 4> TrueCopies;
651 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
652 const MachineOperand &FalseOp =
MI.getOperand(2);
654 Register TrueReg = lookThruCopies(
MI.getOperand(3).getReg(),
661 const MachineOperand &MaskOp =
MI.getOperand(4);
665 const RISCV::RISCVMaskedPseudoInfo *
Info =
666 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
671 if (!hasSameEEW(
MI, True))
676 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
679 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
687 if (TruePassthru && !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
693 unsigned OpIdx1 = OtherIdx;
695 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
697 NeedsCommute = {OpIdx1, OpIdx2};
705 const MachineOperand &VMergeVL =
707 const MachineOperand &TrueVL =
721 unsigned RVVTSFlags =
740 "Foldable unmasked pseudo should have a policy op already");
744 if (!ensureDominates({&MaskOp, &FalseOp, &MinVL}, True))
748 auto [OpIdx1, OpIdx2] = *NeedsCommute;
749 [[maybe_unused]]
bool Commuted =
750 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
751 assert(Commuted &&
"Failed to commute True?");
752 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
773 if (!MO.isReg() || !MO.getReg().isVirtual())
780 MI.eraseFromParent();
784 for (MachineInstr *TrueCopy : TrueCopies)
785 TrueCopy->eraseFromParent();
790bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
805 for (MachineBasicBlock &
MBB : MF) {
813 Changed |= convertAllOnesVMergeToVMv(
MI);
814 Changed |= convertSameMaskVMergeToVMv(
MI);
815 if (foldUndefPassthruVMV_V_V(
MI)) {
827 return new RISCVVectorPeephole();
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)
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),...
FunctionPass class - This class is used to implement most global optimizations.
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.
Representation of each machine instruction.
mop_iterator operands_begin()
bool mayRaiseFPException() const
Return true if this instruction could possibly raise a floating-point exception.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
LLVM_ABI int findRegisterUseOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false) const
Returns the operand index that is a use of the specific register or -1 if it is not found.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
LLVM_ABI bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore,...
LLVM_ABI void insert(mop_iterator InsertBefore, ArrayRef< MachineOperand > Ops)
Inserts Ops BEFORE It. Can untie/retie tied operands.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
mop_range explicit_operands()
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI const TargetRegisterClass * getRegClassConstraint(unsigned OpIdx, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI) const
Compute the static register class constraint for operand OpIdx.
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 void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
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 MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
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
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)
bool isVLKnownLE(const MachineOperand &LHS, const MachineOperand &RHS)
Given two VL operands, do we know that LHS <= RHS?
unsigned getRVVMCOpcode(unsigned RVVPseudoOpcode)
unsigned getDestLog2EEW(const MCInstrDesc &Desc, unsigned Log2SEW)
static constexpr int64_t VLMaxSentinel
NodeAddr< DefNode * > Def
NodeAddr< UseNode * > Use
This is an optimization pass for GlobalISel generic memory operations.
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...
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 >
FunctionPass * createRISCVVectorPeepholePass()