39#define DEBUG_TYPE "riscv-vector-peephole"
58 return "RISC-V Vector Peephole Optimization";
76 lookThruCopies(
Register Reg,
bool OneUseOnly =
false,
82char RISCVVectorPeephole::ID = 0;
91 unsigned UserLog2SEW =
97 return SrcLog2EEW == UserLog2SEW;
101std::optional<unsigned>
107 if (!Def ||
Def->getOpcode() != RISCV::ADDI ||
108 Def->getOperand(1).getReg() != RISCV::X0)
110 return Def->getOperand(2).getImm();
114bool RISCVVectorPeephole::convertToVLMAX(MachineInstr &
MI)
const {
121 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
124 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
126 assert(8 * LMULFixed / SEW > 0);
131 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
145 uint64_t ScaleFixed = 8;
147 if (
Def->getOpcode() == RISCV::SLLI) {
148 assert(
Def->getOperand(2).getImm() < 64);
149 ScaleFixed <<=
Def->getOperand(2).getImm();
151 }
else if (
Def->getOpcode() == RISCV::SRLI) {
152 assert(
Def->getOperand(2).getImm() < 64);
153 ScaleFixed >>=
Def->getOperand(2).getImm();
157 if (!Def ||
Def->getOpcode() != RISCV::PseudoReadVLENB)
167 if (ScaleFixed != 8 * LMULFixed / SEW)
175bool RISCVVectorPeephole::isAllOnesMask(
const MachineInstr *MaskDef)
const {
183 case RISCV::PseudoVMSET_M_B1:
184 case RISCV::PseudoVMSET_M_B2:
185 case RISCV::PseudoVMSET_M_B4:
186 case RISCV::PseudoVMSET_M_B8:
187 case RISCV::PseudoVMSET_M_B16:
188 case RISCV::PseudoVMSET_M_B32:
189 case RISCV::PseudoVMSET_M_B64:
206bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &
MI)
const {
207#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
208 case RISCV::PseudoVLE##sew##_V_M##lmul: \
209 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
211 case RISCV::PseudoVSE##sew##_V_M##lmul: \
212 NewOpc = RISCV::VS##lmul##R_V; \
214#define CASE_WHOLE_REGISTER_LMUL(lmul) \
215 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
216 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
217 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
218 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
221 switch (
MI.getOpcode()) {
230 MachineOperand &VLOp =
MI.getOperand(RISCVII::getVLOpNum(
MI.getDesc()));
231 if (!VLOp.isImm() || VLOp.
getImm() != RISCV::VLMaxSentinel)
236 if (RISCVII::hasVecPolicyOp(
MI.getDesc().TSFlags))
237 MI.removeOperand(RISCVII::getVecPolicyOpNum(
MI.getDesc()));
238 MI.removeOperand(RISCVII::getSEWOpNum(
MI.getDesc()));
239 MI.removeOperand(RISCVII::getVLOpNum(
MI.getDesc()));
240 if (RISCVII::isFirstDefTiedToFirstUse(
MI.getDesc()))
248static
unsigned getVMV_V_VOpcodeForVMERGE_VVM(
const MachineInstr &
MI) {
249#define CASE_VMERGE_TO_VMV(lmul) \
250 case RISCV::PseudoVMERGE_VVM_##lmul: \
251 return RISCV::PseudoVMV_V_V_##lmul;
252 switch (
MI.getOpcode()) {
255 CASE_VMERGE_TO_VMV(MF8)
256 CASE_VMERGE_TO_VMV(MF4)
257 CASE_VMERGE_TO_VMV(MF2)
258 CASE_VMERGE_TO_VMV(M1)
259 CASE_VMERGE_TO_VMV(M2)
260 CASE_VMERGE_TO_VMV(M4)
261 CASE_VMERGE_TO_VMV(M8)
270bool RISCVVectorPeephole::convertAllOnesVMergeToVMv(MachineInstr &
MI)
const {
271 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
274 if (!isAllOnesMask(MRI->
getVRegDef(
MI.getOperand(4).getReg())))
277 MI.setDesc(
TII->get(NewOpc));
286 if (
MI.getOperand(1).getReg().isValid())
293Register RISCVVectorPeephole::lookThruCopies(
295 SmallVectorImpl<MachineInstr *> *
Copies)
const {
297 if (!
Def->isFullCopy())
300 if (!Src.isVirtual())
320bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
321 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
324 MachineInstr *True = MRI->
getVRegDef(
MI.getOperand(3).getReg());
329 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->
getOpcode());
330 if (!TrueMaskedInfo || !hasSameEEW(
MI, *True))
333 Register TrueMaskReg = lookThruCopies(
336 Register MIMaskReg = lookThruCopies(
MI.getOperand(4).getReg());
337 if (!TrueMaskReg.
isVirtual() || TrueMaskReg != MIMaskReg)
345 const MachineOperand &TrueVL =
347 Register FalseReg =
MI.getOperand(2).getReg();
349 Register PassthruReg =
MI.getOperand(1).getReg();
350 if (FalseReg.
isValid() && FalseReg != PassthruReg)
354 uint64_t TruePolicy =
362 if (TruePassthruReg != FalseReg) {
364 if (TruePassthruReg.
isValid() ||
366 !ensureDominates(
MI.getOperand(2), *True))
374 MI.setDesc(
TII->get(NewOpc));
383 if (
MI.getOperand(1).getReg().isValid())
388bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
389 const RISCV::RISCVMaskedPseudoInfo *
I =
390 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
395 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
400 const unsigned Opc =
I->UnmaskedPseudo;
401 const MCInstrDesc &MCID =
TII->get(
Opc);
402 [[maybe_unused]]
const bool HasPolicyOp =
405 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
408 "Unmasked pseudo has policy but masked pseudo doesn't?");
409 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
411 "Unmasked with passthru but masked with no passthru?");
422 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
423 MI.removeOperand(MaskOpIdx);
431 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
433 if (
MI.getOperand(PassthruOpIdx).getReg())
436 MI.removeOperand(PassthruOpIdx);
445 assert(
A->getParent() ==
B->getParent());
447 auto MBBEnd =
MBB->end();
452 for (; &*
I !=
A && &*
I !=
B; ++
I)
461bool RISCVVectorPeephole::ensureDominates(
const MachineOperand &MO,
462 MachineInstr &Src)
const {
468 if (
Def->getParent() == Src.getParent() && !
dominates(Def, Src)) {
471 Src.moveBefore(
Def->getNextNode());
478bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
481 if (
MI.getOperand(1).getReg().isValid())
486 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
487 if (Src && !Src->hasUnmodeledSideEffects() &&
491 const MachineOperand &MIVL =
MI.getOperand(3);
492 const MachineOperand &SrcVL =
495 MachineOperand &SrcPolicy =
506 MI.eraseFromParent();
520bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
524 MachineOperand &Passthru =
MI.getOperand(1);
529 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
530 if (!Src || Src->hasUnmodeledSideEffects() ||
531 Src->getParent() !=
MI.getParent() ||
537 if (!hasSameEEW(
MI, *Src))
540 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
543 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
548 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
551 unsigned OpIdx1 = OtherIdx;
552 unsigned OpIdx2 = Src->getNumExplicitDefs();
553 if (!
TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
555 NeedsCommute = {OpIdx1, OpIdx2};
566 if (!ensureDominates(Passthru, *Src))
570 auto [OpIdx1, OpIdx2] = *NeedsCommute;
571 [[maybe_unused]]
bool Commuted =
572 TII->commuteInstruction(*Src,
false, OpIdx1, OpIdx2);
573 assert(Commuted &&
"Failed to commute Src?");
596 MRI->
replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
597 MI.eraseFromParent();
620bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
625 SmallVector<MachineInstr *, 4> TrueCopies;
626 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
627 const MachineOperand &FalseOp =
MI.getOperand(2);
629 Register TrueReg = lookThruCopies(
MI.getOperand(3).getReg(),
636 const MachineOperand &MaskOp =
MI.getOperand(4);
640 const RISCV::RISCVMaskedPseudoInfo *
Info =
641 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
646 if (!hasSameEEW(
MI, True))
651 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
654 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
662 if (TruePassthru && !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
668 unsigned OpIdx1 = OtherIdx;
670 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
672 NeedsCommute = {OpIdx1, OpIdx2};
680 const MachineOperand &VMergeVL =
682 const MachineOperand &TrueVL =
696 unsigned RVVTSFlags =
715 "Foldable unmasked pseudo should have a policy op already");
720 const MachineOperand *DomOp = &MaskOp;
725 if (!ensureDominates(*DomOp, True))
729 auto [OpIdx1, OpIdx2] = *NeedsCommute;
730 [[maybe_unused]]
bool Commuted =
731 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
732 assert(Commuted &&
"Failed to commute True?");
733 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
761 MI.eraseFromParent();
765 for (MachineInstr *TrueCopy : TrueCopies)
766 TrueCopy->eraseFromParent();
771bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
786 for (MachineBasicBlock &
MBB : MF) {
794 Changed |= convertAllOnesVMergeToVMv(
MI);
795 Changed |= convertSameMaskVMergeToVMv(
MI);
796 if (foldUndefPassthruVMV_V_V(
MI)) {
808 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)
#define CASE_WHOLE_REGISTER_LMUL(lmul)
static bool dominates(InstrPosIndexes &PosIndexes, const MachineInstr &A, const MachineInstr &B)
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...
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.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
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 MachineInstr &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...
StringRef - 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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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
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)
FunctionPass * createRISCVVectorPeepholePass()