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())))
384 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
385 if (
MI.getOperand(1).getReg().isValid())
386 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
393 bool OneUseOnly)
const {
394 while (MachineInstr *Def =
MRI->getUniqueVRegDef(
Reg)) {
395 if (!
Def->isFullCopy())
398 if (!Src.isVirtual())
400 if (OneUseOnly && !
MRI->hasOneNonDBGUse(
Reg))
416bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
417 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
420 MachineInstr *True =
MRI->getVRegDef(
MI.getOperand(3).getReg());
425 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->
getOpcode());
426 if (!TrueMaskedInfo || !hasSameEEW(
MI, *True))
429 Register TrueMaskReg = lookThruCopies(
432 Register MIMaskReg = lookThruCopies(
MI.getOperand(4).getReg());
433 if (!TrueMaskReg.
isVirtual() || TrueMaskReg != MIMaskReg)
440 const MachineOperand &TrueVL =
447 Register FalseReg =
MI.getOperand(2).getReg();
448 if (TruePassthruReg != FalseReg) {
450 if (TruePassthruReg.
isValid() ||
451 !
MRI->hasOneUse(
MI.getOperand(3).getReg()) ||
452 !ensureDominates(
MI.getOperand(2), *True))
468 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
469 if (
MI.getOperand(1).getReg().isValid())
470 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
474bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
475 const RISCV::RISCVMaskedPseudoInfo *
I =
476 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
480 if (!isAllOnesMask(
MRI->getVRegDef(
481 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
486 const unsigned Opc =
I->UnmaskedPseudo;
488 [[maybe_unused]]
const bool HasPolicyOp =
491 const MCInstrDesc &MaskedMCID =
TII->
get(
MI.getOpcode());
494 "Unmasked pseudo has policy but masked pseudo doesn't?");
495 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
497 "Unmasked with passthru but masked with no passthru?");
508 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
509 MI.removeOperand(MaskOpIdx);
513 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
517 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
519 if (
MI.getOperand(PassthruOpIdx).getReg())
520 MRI->recomputeRegClass(
MI.getOperand(PassthruOpIdx).getReg());
522 MI.removeOperand(PassthruOpIdx);
534 if (MO.getReg().isPhysical())
537 if (MO.getReg().isPhysical())
539 bool SawStore =
false;
542 if (
II->definesRegister(PhysReg,
nullptr))
545 if (
II->definesRegister(PhysReg,
nullptr) ||
546 II->readsRegister(PhysReg,
nullptr))
548 if (
II->mayStore()) {
559 assert(
A->getParent() ==
B->getParent());
561 auto MBBEnd =
MBB->end();
566 for (; &*
I !=
A && &*
I !=
B; ++
I)
575bool RISCVVectorPeephole::ensureDominates(
const MachineOperand &MO,
576 MachineInstr &Src)
const {
582 if (
Def->getParent() == Src.getParent() && !
dominates(Def, Src)) {
585 Src.moveBefore(
Def->getNextNode());
592bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
595 if (
MI.getOperand(1).getReg().isValid())
600 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
601 if (Src && !Src->hasUnmodeledSideEffects() &&
602 MRI->hasOneUse(
MI.getOperand(2).getReg()) &&
605 const MachineOperand &MIVL =
MI.getOperand(3);
606 const MachineOperand &SrcVL =
609 MachineOperand &SrcPolicy =
616 MRI->constrainRegClass(
MI.getOperand(2).getReg(),
617 MRI->getRegClass(
MI.getOperand(0).getReg()));
618 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
MI.getOperand(2).getReg());
619 MRI->clearKillFlags(
MI.getOperand(2).getReg());
620 MI.eraseFromParent();
634bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
638 MachineOperand &Passthru =
MI.getOperand(1);
640 if (!
MRI->hasOneUse(
MI.getOperand(2).getReg()))
643 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
644 if (!Src || Src->hasUnmodeledSideEffects() ||
645 Src->getParent() !=
MI.getParent() ||
651 if (!hasSameEEW(
MI, *Src))
654 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
657 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
662 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
665 unsigned OpIdx1 = OtherIdx;
666 unsigned OpIdx2 = Src->getNumExplicitDefs();
669 NeedsCommute = {OpIdx1, OpIdx2};
680 if (!ensureDominates(Passthru, *Src))
684 auto [OpIdx1, OpIdx2] = *NeedsCommute;
685 [[maybe_unused]]
bool Commuted =
687 assert(Commuted &&
"Failed to commute Src?");
694 MRI->constrainRegClass(
708 MRI->constrainRegClass(Src->getOperand(0).getReg(),
709 MRI->getRegClass(
MI.getOperand(0).getReg()));
710 MRI->replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
711 MI.eraseFromParent();
734bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
738 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
739 Register FalseReg = lookThruCopies(
MI.getOperand(2).getReg());
741 lookThruCopies(
MI.getOperand(3).getReg(),
true);
744 MachineInstr &True = *
MRI->getUniqueVRegDef(TrueReg);
747 const MachineOperand &MaskOp =
MI.getOperand(4);
751 const RISCV::RISCVMaskedPseudoInfo *
Info =
752 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
757 if (!hasSameEEW(
MI, True))
762 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
765 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
772 !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
778 unsigned OpIdx1 = OtherIdx;
782 NeedsCommute = {OpIdx1, OpIdx2};
790 const MachineOperand &VMergeVL =
792 const MachineOperand &TrueVL =
803 unsigned RVVTSFlags =
822 "Foldable unmasked pseudo should have a policy op already");
826 if (!ensureDominates(MaskOp, True))
830 auto [OpIdx1, OpIdx2] = *NeedsCommute;
831 [[maybe_unused]]
bool Commuted =
833 assert(Commuted &&
"Failed to commute True?");
834 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
857 MRI->constrainRegClass(
861 MRI->clearKillFlags(FalseReg);
862 MI.eraseFromParent();
867bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
878 TRI =
MRI->getTargetRegisterInfo();
882 for (MachineBasicBlock &
MBB : MF) {
891 Changed |= convertAllOnesVMergeToVMv(
MI);
892 Changed |= convertSameMaskVMergeToVMv(
MI);
893 if (foldUndefPassthruVMV_V_V(
MI)) {
905 return new RISCVVectorPeephole();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
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
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.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
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.
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.
virtual const TargetRegisterClass * getRegClass(const MCInstrDesc &MCID, unsigned OpNum) const
Given a machine instruction descriptor, returns the register class constraint for OpNum,...
virtual bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const
Returns true iff the routine could find two commutable operands in the given machine instruction.
MachineInstr * commuteInstruction(MachineInstr &MI, bool NewMI=false, unsigned OpIdx1=CommuteAnyOperandIndex, unsigned OpIdx2=CommuteAnyOperandIndex) const
This method commutes the operands of the given machine instruction MI.
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()