39#define DEBUG_TYPE "riscv-vector-peephole"
58 return "RISC-V Vector Peephole Optimization";
77 lookThruCopies(
Register Reg,
bool OneUseOnly =
false,
83char RISCVVectorPeephole::ID = 0;
92 unsigned UserLog2SEW =
98 return SrcLog2EEW == UserLog2SEW;
118 SmallVector<unsigned, 2> SrcIndices = {0};
130 case RISCV::VMERGE_VVM:
131 SrcIndices.
assign({2, 3});
133 case RISCV::VREDSUM_VS:
134 case RISCV::VREDMAXU_VS:
135 case RISCV::VREDMAX_VS:
136 case RISCV::VREDMINU_VS:
137 case RISCV::VREDMIN_VS:
138 case RISCV::VREDAND_VS:
139 case RISCV::VREDOR_VS:
140 case RISCV::VREDXOR_VS:
141 case RISCV::VWREDSUM_VS:
142 case RISCV::VWREDSUMU_VS:
143 case RISCV::VFREDUSUM_VS:
144 case RISCV::VFREDOSUM_VS:
145 case RISCV::VFREDMAX_VS:
146 case RISCV::VFREDMIN_VS:
147 case RISCV::VFWREDUSUM_VS:
148 case RISCV::VFWREDOSUM_VS:
158 for (
unsigned SrcIdx : SrcIndices) {
159 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
161 if (!
MRI->hasOneUse(SrcReg))
164 MachineInstr *Src =
MRI->getVRegDef(SrcReg);
165 if (!Src || Src->hasUnmodeledSideEffects() ||
166 Src->getParent() !=
MI.getParent() || Src->getNumDefs() != 1 ||
172 if (!hasSameEEW(
MI, *Src))
177 if (ElementsDependOnVL || Src->mayRaiseFPException())
180 MachineOperand &SrcVL =
185 if (!ensureDominates(VL, *Src))
202std::optional<unsigned>
203RISCVVectorPeephole::getConstant(
const MachineOperand &VL)
const {
208 if (!Def ||
Def->getOpcode() != RISCV::ADDI ||
209 Def->getOperand(1).getReg() != RISCV::X0)
211 return Def->getOperand(2).getImm();
215bool RISCVVectorPeephole::convertToVLMAX(MachineInstr &
MI)
const {
222 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
225 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
227 assert(8 * LMULFixed / SEW > 0);
232 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
246 uint64_t ScaleFixed = 8;
248 if (
Def->getOpcode() == RISCV::SLLI) {
249 assert(
Def->getOperand(2).getImm() < 64);
250 ScaleFixed <<=
Def->getOperand(2).getImm();
251 Def =
MRI->getVRegDef(
Def->getOperand(1).getReg());
252 }
else if (
Def->getOpcode() == RISCV::SRLI) {
253 assert(
Def->getOperand(2).getImm() < 64);
254 ScaleFixed >>=
Def->getOperand(2).getImm();
255 Def =
MRI->getVRegDef(
Def->getOperand(1).getReg());
258 if (!Def ||
Def->getOpcode() != RISCV::PseudoReadVLENB)
268 if (ScaleFixed != 8 * LMULFixed / SEW)
276bool RISCVVectorPeephole::isAllOnesMask(
const MachineInstr *MaskDef)
const {
284 case RISCV::PseudoVMSET_M_B1:
285 case RISCV::PseudoVMSET_M_B2:
286 case RISCV::PseudoVMSET_M_B4:
287 case RISCV::PseudoVMSET_M_B8:
288 case RISCV::PseudoVMSET_M_B16:
289 case RISCV::PseudoVMSET_M_B32:
290 case RISCV::PseudoVMSET_M_B64:
307bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &
MI)
const {
308#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
309 case RISCV::PseudoVLE##sew##_V_M##lmul: \
310 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
312 case RISCV::PseudoVSE##sew##_V_M##lmul: \
313 NewOpc = RISCV::VS##lmul##R_V; \
315#define CASE_WHOLE_REGISTER_LMUL(lmul) \
316 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
317 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
318 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
319 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
322 switch (
MI.getOpcode()) {
331 MachineOperand &VLOp =
MI.getOperand(RISCVII::getVLOpNum(
MI.getDesc()));
332 if (!VLOp.isImm() || VLOp.
getImm() != RISCV::VLMaxSentinel)
337 if (RISCVII::hasVecPolicyOp(
MI.getDesc().TSFlags))
338 MI.removeOperand(RISCVII::getVecPolicyOpNum(
MI.getDesc()));
339 MI.removeOperand(RISCVII::getSEWOpNum(
MI.getDesc()));
340 MI.removeOperand(RISCVII::getVLOpNum(
MI.getDesc()));
341 if (RISCVII::isFirstDefTiedToFirstUse(
MI.getDesc()))
349static
unsigned getVMV_V_VOpcodeForVMERGE_VVM(
const MachineInstr &
MI) {
350#define CASE_VMERGE_TO_VMV(lmul) \
351 case RISCV::PseudoVMERGE_VVM_##lmul: \
352 return RISCV::PseudoVMV_V_V_##lmul;
353 switch (
MI.getOpcode()) {
356 CASE_VMERGE_TO_VMV(MF8)
357 CASE_VMERGE_TO_VMV(MF4)
358 CASE_VMERGE_TO_VMV(MF2)
359 CASE_VMERGE_TO_VMV(M1)
360 CASE_VMERGE_TO_VMV(M2)
361 CASE_VMERGE_TO_VMV(M4)
362 CASE_VMERGE_TO_VMV(M8)
371bool RISCVVectorPeephole::convertAllOnesVMergeToVMv(MachineInstr &
MI)
const {
372 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
375 if (!isAllOnesMask(
MRI->getVRegDef(
MI.getOperand(4).getReg())))
378 MI.setDesc(
TII->get(NewOpc));
386 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
387 if (
MI.getOperand(1).getReg().isValid())
388 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
394Register RISCVVectorPeephole::lookThruCopies(
396 SmallVectorImpl<MachineInstr *> *
Copies)
const {
397 while (MachineInstr *Def =
MRI->getUniqueVRegDef(
Reg)) {
398 if (!
Def->isFullCopy())
401 if (!Src.isVirtual())
403 if (OneUseOnly && !
MRI->hasOneNonDBGUse(
Reg))
421bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
422 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
425 MachineInstr *True =
MRI->getVRegDef(
MI.getOperand(3).getReg());
430 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->
getOpcode());
431 if (!TrueMaskedInfo || !hasSameEEW(
MI, *True))
434 Register TrueMaskReg = lookThruCopies(
437 Register MIMaskReg = lookThruCopies(
MI.getOperand(4).getReg());
438 if (!TrueMaskReg.
isVirtual() || TrueMaskReg != MIMaskReg)
445 const MachineOperand &TrueVL =
452 Register FalseReg =
MI.getOperand(2).getReg();
453 if (TruePassthruReg != FalseReg) {
455 if (TruePassthruReg.
isValid() ||
456 !
MRI->hasOneUse(
MI.getOperand(3).getReg()) ||
457 !ensureDominates(
MI.getOperand(2), *True))
465 MI.setDesc(
TII->get(NewOpc));
473 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
474 if (
MI.getOperand(1).getReg().isValid())
475 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
479bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
480 const RISCV::RISCVMaskedPseudoInfo *
I =
481 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
485 if (!isAllOnesMask(
MRI->getVRegDef(
486 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
491 const unsigned Opc =
I->UnmaskedPseudo;
492 const MCInstrDesc &MCID =
TII->get(
Opc);
493 [[maybe_unused]]
const bool HasPolicyOp =
496 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
499 "Unmasked pseudo has policy but masked pseudo doesn't?");
500 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
502 "Unmasked with passthru but masked with no passthru?");
513 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
514 MI.removeOperand(MaskOpIdx);
518 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
522 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
524 if (
MI.getOperand(PassthruOpIdx).getReg())
525 MRI->recomputeRegClass(
MI.getOperand(PassthruOpIdx).getReg());
527 MI.removeOperand(PassthruOpIdx);
539 if (MO.getReg().isPhysical())
542 if (MO.getReg().isPhysical())
544 bool SawStore =
false;
547 if (
II->definesRegister(PhysReg,
nullptr))
550 if (
II->definesRegister(PhysReg,
nullptr) ||
551 II->readsRegister(PhysReg,
nullptr))
553 if (
II->mayStore()) {
564 assert(
A->getParent() ==
B->getParent());
566 auto MBBEnd =
MBB->end();
571 for (; &*
I !=
A && &*
I !=
B; ++
I)
580bool RISCVVectorPeephole::ensureDominates(
const MachineOperand &MO,
581 MachineInstr &Src)
const {
587 if (
Def->getParent() == Src.getParent() && !
dominates(Def, Src)) {
590 Src.moveBefore(
Def->getNextNode());
597bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
600 if (
MI.getOperand(1).getReg().isValid())
605 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
606 if (Src && !Src->hasUnmodeledSideEffects() &&
607 MRI->hasOneUse(
MI.getOperand(2).getReg()) &&
610 const MachineOperand &MIVL =
MI.getOperand(3);
611 const MachineOperand &SrcVL =
614 MachineOperand &SrcPolicy =
621 MRI->constrainRegClass(
MI.getOperand(2).getReg(),
622 MRI->getRegClass(
MI.getOperand(0).getReg()));
623 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
MI.getOperand(2).getReg());
624 MRI->clearKillFlags(
MI.getOperand(2).getReg());
625 MI.eraseFromParent();
639bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
643 MachineOperand &Passthru =
MI.getOperand(1);
645 if (!
MRI->hasOneUse(
MI.getOperand(2).getReg()))
648 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
649 if (!Src || Src->hasUnmodeledSideEffects() ||
650 Src->getParent() !=
MI.getParent() ||
656 if (!hasSameEEW(
MI, *Src))
659 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
662 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
667 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
670 unsigned OpIdx1 = OtherIdx;
671 unsigned OpIdx2 = Src->getNumExplicitDefs();
672 if (!
TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
674 NeedsCommute = {OpIdx1, OpIdx2};
685 if (!ensureDominates(Passthru, *Src))
689 auto [OpIdx1, OpIdx2] = *NeedsCommute;
690 [[maybe_unused]]
bool Commuted =
691 TII->commuteInstruction(*Src,
false, OpIdx1, OpIdx2);
692 assert(Commuted &&
"Failed to commute Src?");
699 MRI->constrainRegClass(
713 MRI->constrainRegClass(Src->getOperand(0).getReg(),
714 MRI->getRegClass(
MI.getOperand(0).getReg()));
715 MRI->replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
716 MI.eraseFromParent();
739bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
744 SmallVector<MachineInstr *, 4> TrueCopies;
745 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
746 Register FalseReg = lookThruCopies(
MI.getOperand(2).getReg());
747 Register TrueReg = lookThruCopies(
MI.getOperand(3).getReg(),
751 MachineInstr &True = *
MRI->getUniqueVRegDef(TrueReg);
754 const MachineOperand &MaskOp =
MI.getOperand(4);
758 const RISCV::RISCVMaskedPseudoInfo *
Info =
759 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
764 if (!hasSameEEW(
MI, True))
769 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
772 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
779 !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
785 unsigned OpIdx1 = OtherIdx;
787 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
789 NeedsCommute = {OpIdx1, OpIdx2};
797 const MachineOperand &VMergeVL =
799 const MachineOperand &TrueVL =
810 unsigned RVVTSFlags =
829 "Foldable unmasked pseudo should have a policy op already");
834 if (!ensureDominates(MaskOp, True))
838 auto [OpIdx1, OpIdx2] = *NeedsCommute;
839 [[maybe_unused]]
bool Commuted =
840 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
841 assert(Commuted &&
"Failed to commute True?");
842 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
865 MRI->constrainRegClass(
869 MRI->clearKillFlags(FalseReg);
870 MI.eraseFromParent();
874 for (MachineInstr *TrueCopy : TrueCopies)
875 TrueCopy->eraseFromParent();
880bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
891 TRI =
MRI->getTargetRegisterInfo();
895 for (MachineBasicBlock &
MBB : MF) {
904 Changed |= convertAllOnesVMergeToVMv(
MI);
905 Changed |= convertSameMaskVMergeToVMv(
MI);
906 if (foldUndefPassthruVMV_V_V(
MI)) {
918 return new RISCVVectorPeephole();
unsigned const MachineRegisterInfo * MRI
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")
Analysis containing CSE Info
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
#define CASE_WHOLE_REGISTER_LMUL(lmul)
static bool isSafeToMove(const MachineInstr &From, const MachineInstr &To)
Check if it's safe to move From down to To, checking that no physical registers are clobbered.
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.
const MachineBasicBlock * getParent() const
filtered_mop_range all_defs()
Returns an iterator range over all operands that are (explicit or implicit) register defs.
LLVM_ABI bool isSafeToMove(bool &SawStore) const
Return true if it is safe to move this instruction.
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.
filtered_mop_range all_uses()
Returns an iterator range over all operands that are (explicit or implicit) register uses.
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.
LLVM_ABI void ChangeToRegister(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isDebug=false)
ChangeToRegister - Replace this operand with a new register 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,...
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...
void assign(size_type NumElts, ValueParamT Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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
self_iterator getIterator()
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()