39#define DEBUG_TYPE "riscv-vector-peephole"
58 return "RISC-V Vector Peephole Optimization";
81char RISCVVectorPeephole::ID = 0;
90 unsigned UserLog2SEW =
96 return SrcLog2EEW == UserLog2SEW;
116 SmallVector<unsigned, 2> SrcIndices = {0};
128 case RISCV::VMERGE_VVM:
129 SrcIndices.
assign({2, 3});
131 case RISCV::VREDSUM_VS:
132 case RISCV::VREDMAXU_VS:
133 case RISCV::VREDMAX_VS:
134 case RISCV::VREDMINU_VS:
135 case RISCV::VREDMIN_VS:
136 case RISCV::VREDAND_VS:
137 case RISCV::VREDOR_VS:
138 case RISCV::VREDXOR_VS:
139 case RISCV::VWREDSUM_VS:
140 case RISCV::VWREDSUMU_VS:
141 case RISCV::VFREDUSUM_VS:
142 case RISCV::VFREDOSUM_VS:
143 case RISCV::VFREDMAX_VS:
144 case RISCV::VFREDMIN_VS:
145 case RISCV::VFWREDUSUM_VS:
146 case RISCV::VFWREDOSUM_VS:
156 for (
unsigned SrcIdx : SrcIndices) {
157 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
159 if (!
MRI->hasOneUse(SrcReg))
162 MachineInstr *Src =
MRI->getVRegDef(SrcReg);
163 if (!Src || Src->hasUnmodeledSideEffects() ||
164 Src->getParent() !=
MI.getParent() || Src->getNumDefs() != 1 ||
170 if (!hasSameEEW(
MI, *Src))
175 if (ElementsDependOnVL || Src->mayRaiseFPException())
178 MachineOperand &SrcVL =
183 if (!ensureDominates(VL, *Src))
200std::optional<unsigned>
201RISCVVectorPeephole::getConstant(
const MachineOperand &VL)
const {
206 if (!Def ||
Def->getOpcode() != RISCV::ADDI ||
207 Def->getOperand(1).getReg() != RISCV::X0)
209 return Def->getOperand(2).getImm();
213bool RISCVVectorPeephole::convertToVLMAX(MachineInstr &
MI)
const {
220 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
223 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
225 assert(8 * LMULFixed / SEW > 0);
230 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
244 uint64_t ScaleFixed = 8;
246 if (
Def->getOpcode() == RISCV::SLLI) {
247 assert(
Def->getOperand(2).getImm() < 64);
248 ScaleFixed <<=
Def->getOperand(2).getImm();
249 Def =
MRI->getVRegDef(
Def->getOperand(1).getReg());
250 }
else if (
Def->getOpcode() == RISCV::SRLI) {
251 assert(
Def->getOperand(2).getImm() < 64);
252 ScaleFixed >>=
Def->getOperand(2).getImm();
253 Def =
MRI->getVRegDef(
Def->getOperand(1).getReg());
256 if (!Def ||
Def->getOpcode() != RISCV::PseudoReadVLENB)
266 if (ScaleFixed != 8 * LMULFixed / SEW)
274bool RISCVVectorPeephole::isAllOnesMask(
const MachineInstr *MaskDef)
const {
282 case RISCV::PseudoVMSET_M_B1:
283 case RISCV::PseudoVMSET_M_B2:
284 case RISCV::PseudoVMSET_M_B4:
285 case RISCV::PseudoVMSET_M_B8:
286 case RISCV::PseudoVMSET_M_B16:
287 case RISCV::PseudoVMSET_M_B32:
288 case RISCV::PseudoVMSET_M_B64:
305bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &
MI)
const {
306#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
307 case RISCV::PseudoVLE##sew##_V_M##lmul: \
308 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
310 case RISCV::PseudoVSE##sew##_V_M##lmul: \
311 NewOpc = RISCV::VS##lmul##R_V; \
313#define CASE_WHOLE_REGISTER_LMUL(lmul) \
314 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
315 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
316 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
317 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
320 switch (
MI.getOpcode()) {
329 MachineOperand &VLOp =
MI.getOperand(RISCVII::getVLOpNum(
MI.getDesc()));
330 if (!VLOp.isImm() || VLOp.
getImm() != RISCV::VLMaxSentinel)
335 if (RISCVII::hasVecPolicyOp(
MI.getDesc().TSFlags))
336 MI.removeOperand(RISCVII::getVecPolicyOpNum(
MI.getDesc()));
337 MI.removeOperand(RISCVII::getSEWOpNum(
MI.getDesc()));
338 MI.removeOperand(RISCVII::getVLOpNum(
MI.getDesc()));
339 if (RISCVII::isFirstDefTiedToFirstUse(
MI.getDesc()))
347static
unsigned getVMV_V_VOpcodeForVMERGE_VVM(
const MachineInstr &
MI) {
348#define CASE_VMERGE_TO_VMV(lmul) \
349 case RISCV::PseudoVMERGE_VVM_##lmul: \
350 return RISCV::PseudoVMV_V_V_##lmul;
351 switch (
MI.getOpcode()) {
354 CASE_VMERGE_TO_VMV(MF8)
355 CASE_VMERGE_TO_VMV(MF4)
356 CASE_VMERGE_TO_VMV(MF2)
357 CASE_VMERGE_TO_VMV(M1)
358 CASE_VMERGE_TO_VMV(M2)
359 CASE_VMERGE_TO_VMV(M4)
360 CASE_VMERGE_TO_VMV(M8)
369bool RISCVVectorPeephole::convertAllOnesVMergeToVMv(MachineInstr &
MI)
const {
370 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
373 if (!isAllOnesMask(
MRI->getVRegDef(
MI.getOperand(4).getReg())))
376 MI.setDesc(
TII->get(NewOpc));
384 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
385 if (
MI.getOperand(1).getReg() != RISCV::NoRegister)
386 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
391 if (
A.isPhysical() ||
B.isPhysical())
394 auto LookThruVirtRegCopies = [
this](
Register Reg) {
395 while (MachineInstr *Def =
MRI->getUniqueVRegDef(
Reg)) {
396 if (!
Def->isFullCopy())
399 if (!Src.isVirtual())
406 return LookThruVirtRegCopies(
A) == LookThruVirtRegCopies(
B);
418bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
419 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
422 MachineInstr *True =
MRI->getVRegDef(
MI.getOperand(3).getReg());
427 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->
getOpcode());
428 if (!TrueMaskedInfo || !hasSameEEW(
MI, *True))
431 const MachineOperand &TrueMask =
433 const MachineOperand &MIMask =
MI.getOperand(4);
434 if (!isKnownSameDefs(TrueMask.
getReg(), MIMask.
getReg()))
441 const MachineOperand &TrueVL =
448 Register FalseReg =
MI.getOperand(2).getReg();
449 if (TruePassthruReg != FalseReg) {
451 if (TruePassthruReg != RISCV::NoRegister ||
452 !
MRI->hasOneUse(
MI.getOperand(3).getReg()) ||
453 !ensureDominates(
MI.getOperand(2), *True))
462 MI.setDesc(
TII->get(NewOpc));
470 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
471 if (
MI.getOperand(1).getReg() != RISCV::NoRegister)
472 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
476bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
477 const RISCV::RISCVMaskedPseudoInfo *
I =
478 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
482 if (!isAllOnesMask(
MRI->getVRegDef(
483 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
488 const unsigned Opc =
I->UnmaskedPseudo;
489 const MCInstrDesc &MCID =
TII->get(
Opc);
490 [[maybe_unused]]
const bool HasPolicyOp =
493 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
496 "Unmasked pseudo has policy but masked pseudo doesn't?");
497 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
499 "Unmasked with passthru but masked with no passthru?");
510 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
511 MI.removeOperand(MaskOpIdx);
515 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
519 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
521 if (
MI.getOperand(PassthruOpIdx).getReg() != RISCV::NoRegister)
522 MRI->recomputeRegClass(
MI.getOperand(PassthruOpIdx).getReg());
524 MI.removeOperand(PassthruOpIdx);
536 if (MO.getReg().isPhysical())
539 if (MO.getReg().isPhysical())
541 bool SawStore =
false;
544 if (
II->definesRegister(PhysReg,
nullptr))
547 if (
II->definesRegister(PhysReg,
nullptr) ||
548 II->readsRegister(PhysReg,
nullptr))
550 if (
II->mayStore()) {
561 assert(
A->getParent() ==
B->getParent());
563 auto MBBEnd =
MBB->end();
568 for (; &*
I !=
A && &*
I !=
B; ++
I)
577bool RISCVVectorPeephole::ensureDominates(
const MachineOperand &MO,
578 MachineInstr &Src)
const {
580 if (!MO.
isReg() || MO.
getReg() == RISCV::NoRegister)
584 if (
Def->getParent() == Src.getParent() && !
dominates(Def, Src)) {
587 Src.moveBefore(
Def->getNextNode());
594bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
597 if (
MI.getOperand(1).getReg() != RISCV::NoRegister)
602 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
603 if (Src && !Src->hasUnmodeledSideEffects() &&
604 MRI->hasOneUse(
MI.getOperand(2).getReg()) &&
607 const MachineOperand &MIVL =
MI.getOperand(3);
608 const MachineOperand &SrcVL =
611 MachineOperand &SrcPolicy =
618 MRI->constrainRegClass(
MI.getOperand(2).getReg(),
619 MRI->getRegClass(
MI.getOperand(0).getReg()));
620 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
MI.getOperand(2).getReg());
621 MRI->clearKillFlags(
MI.getOperand(2).getReg());
622 MI.eraseFromParent();
636bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
640 MachineOperand &Passthru =
MI.getOperand(1);
642 if (!
MRI->hasOneUse(
MI.getOperand(2).getReg()))
645 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
646 if (!Src || Src->hasUnmodeledSideEffects() ||
647 Src->getParent() !=
MI.getParent() ||
653 if (!hasSameEEW(
MI, *Src))
657 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
658 if (SrcPassthru.
getReg() != RISCV::NoRegister &&
670 if (!ensureDominates(Passthru, *Src))
676 if (Passthru.
getReg() != RISCV::NoRegister)
677 MRI->constrainRegClass(Passthru.
getReg(),
678 TII->getRegClass(Src->getDesc(),
680 *Src->getParent()->getParent()));
692 MRI->constrainRegClass(Src->getOperand(0).getReg(),
693 MRI->getRegClass(
MI.getOperand(0).getReg()));
694 MRI->replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
695 MI.eraseFromParent();
718bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
722 Register PassthruReg =
MI.getOperand(1).getReg();
723 Register FalseReg =
MI.getOperand(2).getReg();
727 MachineInstr &True = *
MRI->getUniqueVRegDef(TrueReg);
730 const MachineOperand &MaskOp =
MI.getOperand(4);
734 const RISCV::RISCVMaskedPseudoInfo *
Info =
735 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
740 if (!hasSameEEW(
MI, True))
745 if (PassthruReg && !isKnownSameDefs(PassthruReg, FalseReg))
748 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
754 !isKnownSameDefs(TruePassthru, FalseReg)) {
760 unsigned OpIdx1 = OtherIdx;
762 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
764 NeedsCommute = {OpIdx1, OpIdx2};
772 const MachineOperand &VMergeVL =
774 const MachineOperand &TrueVL =
785 unsigned RVVTSFlags =
804 "Foldable unmasked pseudo should have a policy op already");
808 if (!ensureDominates(MaskOp, True))
812 auto [OpIdx1, OpIdx2] = *NeedsCommute;
813 [[maybe_unused]]
bool Commuted =
814 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
815 assert(Commuted &&
"Failed to commute True?");
816 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
839 MRI->constrainRegClass(
842 MI.eraseFromParent();
847bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
858 TRI =
MRI->getTargetRegisterInfo();
862 for (MachineBasicBlock &
MBB : MF) {
871 Changed |= convertAllOnesVMergeToVMv(
MI);
872 Changed |= convertSameMaskVMergeToVMv(
MI);
873 if (foldUndefPassthruVMV_V_V(
MI)) {
885 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
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
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 isVirtual() const
Return true if the specified register number is in the virtual register namespace.
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()