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)
344 const MachineOperand &TrueVL =
351 Register FalseReg =
MI.getOperand(2).getReg();
352 if (TruePassthruReg != FalseReg) {
354 if (TruePassthruReg.
isValid() ||
356 !ensureDominates(
MI.getOperand(2), *True))
364 MI.setDesc(
TII->get(NewOpc));
373 if (
MI.getOperand(1).getReg().isValid())
378bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
379 const RISCV::RISCVMaskedPseudoInfo *
I =
380 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
385 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
390 const unsigned Opc =
I->UnmaskedPseudo;
391 const MCInstrDesc &MCID =
TII->get(
Opc);
392 [[maybe_unused]]
const bool HasPolicyOp =
395 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
398 "Unmasked pseudo has policy but masked pseudo doesn't?");
399 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
401 "Unmasked with passthru but masked with no passthru?");
412 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
413 MI.removeOperand(MaskOpIdx);
421 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
423 if (
MI.getOperand(PassthruOpIdx).getReg())
426 MI.removeOperand(PassthruOpIdx);
435 assert(
A->getParent() ==
B->getParent());
437 auto MBBEnd =
MBB->end();
442 for (; &*
I !=
A && &*
I !=
B; ++
I)
451bool RISCVVectorPeephole::ensureDominates(
const MachineOperand &MO,
452 MachineInstr &Src)
const {
458 if (
Def->getParent() == Src.getParent() && !
dominates(Def, Src)) {
461 Src.moveBefore(
Def->getNextNode());
468bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
471 if (
MI.getOperand(1).getReg().isValid())
476 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
477 if (Src && !Src->hasUnmodeledSideEffects() &&
481 const MachineOperand &MIVL =
MI.getOperand(3);
482 const MachineOperand &SrcVL =
485 MachineOperand &SrcPolicy =
496 MI.eraseFromParent();
510bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
514 MachineOperand &Passthru =
MI.getOperand(1);
519 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
520 if (!Src || Src->hasUnmodeledSideEffects() ||
521 Src->getParent() !=
MI.getParent() ||
527 if (!hasSameEEW(
MI, *Src))
530 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
533 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
538 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
541 unsigned OpIdx1 = OtherIdx;
542 unsigned OpIdx2 = Src->getNumExplicitDefs();
543 if (!
TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
545 NeedsCommute = {OpIdx1, OpIdx2};
556 if (!ensureDominates(Passthru, *Src))
560 auto [OpIdx1, OpIdx2] = *NeedsCommute;
561 [[maybe_unused]]
bool Commuted =
562 TII->commuteInstruction(*Src,
false, OpIdx1, OpIdx2);
563 assert(Commuted &&
"Failed to commute Src?");
586 MRI->
replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
587 MI.eraseFromParent();
610bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
615 SmallVector<MachineInstr *, 4> TrueCopies;
616 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
617 const MachineOperand &FalseOp =
MI.getOperand(2);
619 Register TrueReg = lookThruCopies(
MI.getOperand(3).getReg(),
626 const MachineOperand &MaskOp =
MI.getOperand(4);
630 const RISCV::RISCVMaskedPseudoInfo *
Info =
631 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
636 if (!hasSameEEW(
MI, True))
641 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
644 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
652 if (TruePassthru && !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
658 unsigned OpIdx1 = OtherIdx;
660 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
662 NeedsCommute = {OpIdx1, OpIdx2};
670 const MachineOperand &VMergeVL =
672 const MachineOperand &TrueVL =
686 unsigned RVVTSFlags =
705 "Foldable unmasked pseudo should have a policy op already");
710 const MachineOperand *DomOp = &MaskOp;
715 if (!ensureDominates(*DomOp, True))
719 auto [OpIdx1, OpIdx2] = *NeedsCommute;
720 [[maybe_unused]]
bool Commuted =
721 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
722 assert(Commuted &&
"Failed to commute True?");
723 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
751 MI.eraseFromParent();
755 for (MachineInstr *TrueCopy : TrueCopies)
756 TrueCopy->eraseFromParent();
761bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
776 for (MachineBasicBlock &
MBB : MF) {
784 Changed |= convertAllOnesVMergeToVMv(
MI);
785 Changed |= convertSameMaskVMergeToVMv(
MI);
786 if (foldUndefPassthruVMV_V_V(
MI)) {
798 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()