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().isValid())
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.
isValid() ||
452 !
MRI->hasOneUse(
MI.getOperand(3).getReg()) ||
453 !ensureDominates(
MI.getOperand(2), *True))
461 MI.setDesc(
TII->get(NewOpc));
469 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
470 if (
MI.getOperand(1).getReg().isValid())
471 MRI->recomputeRegClass(
MI.getOperand(1).getReg());
475bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
476 const RISCV::RISCVMaskedPseudoInfo *
I =
477 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
481 if (!isAllOnesMask(
MRI->getVRegDef(
482 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
487 const unsigned Opc =
I->UnmaskedPseudo;
488 const MCInstrDesc &MCID =
TII->get(
Opc);
489 [[maybe_unused]]
const bool HasPolicyOp =
492 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
495 "Unmasked pseudo has policy but masked pseudo doesn't?");
496 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
498 "Unmasked with passthru but masked with no passthru?");
509 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
510 MI.removeOperand(MaskOpIdx);
514 MRI->recomputeRegClass(
MI.getOperand(0).getReg());
518 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
520 if (
MI.getOperand(PassthruOpIdx).getReg())
521 MRI->recomputeRegClass(
MI.getOperand(PassthruOpIdx).getReg());
523 MI.removeOperand(PassthruOpIdx);
535 if (MO.getReg().isPhysical())
538 if (MO.getReg().isPhysical())
540 bool SawStore =
false;
543 if (
II->definesRegister(PhysReg,
nullptr))
546 if (
II->definesRegister(PhysReg,
nullptr) ||
547 II->readsRegister(PhysReg,
nullptr))
549 if (
II->mayStore()) {
560 assert(
A->getParent() ==
B->getParent());
562 auto MBBEnd =
MBB->end();
567 for (; &*
I !=
A && &*
I !=
B; ++
I)
576bool RISCVVectorPeephole::ensureDominates(
const MachineOperand &MO,
577 MachineInstr &Src)
const {
583 if (
Def->getParent() == Src.getParent() && !
dominates(Def, Src)) {
586 Src.moveBefore(
Def->getNextNode());
593bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
596 if (
MI.getOperand(1).getReg().isValid())
601 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
602 if (Src && !Src->hasUnmodeledSideEffects() &&
603 MRI->hasOneUse(
MI.getOperand(2).getReg()) &&
606 const MachineOperand &MIVL =
MI.getOperand(3);
607 const MachineOperand &SrcVL =
610 MachineOperand &SrcPolicy =
617 MRI->constrainRegClass(
MI.getOperand(2).getReg(),
618 MRI->getRegClass(
MI.getOperand(0).getReg()));
619 MRI->replaceRegWith(
MI.getOperand(0).getReg(),
MI.getOperand(2).getReg());
620 MRI->clearKillFlags(
MI.getOperand(2).getReg());
621 MI.eraseFromParent();
635bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
639 MachineOperand &Passthru =
MI.getOperand(1);
641 if (!
MRI->hasOneUse(
MI.getOperand(2).getReg()))
644 MachineInstr *Src =
MRI->getVRegDef(
MI.getOperand(2).getReg());
645 if (!Src || Src->hasUnmodeledSideEffects() ||
646 Src->getParent() !=
MI.getParent() ||
652 if (!hasSameEEW(
MI, *Src))
656 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
669 if (!ensureDominates(Passthru, *Src))
676 MRI->constrainRegClass(
690 MRI->constrainRegClass(Src->getOperand(0).getReg(),
691 MRI->getRegClass(
MI.getOperand(0).getReg()));
692 MRI->replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
693 MI.eraseFromParent();
716bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
720 Register PassthruReg =
MI.getOperand(1).getReg();
721 Register FalseReg =
MI.getOperand(2).getReg();
725 MachineInstr &True = *
MRI->getUniqueVRegDef(TrueReg);
728 const MachineOperand &MaskOp =
MI.getOperand(4);
732 const RISCV::RISCVMaskedPseudoInfo *
Info =
733 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
738 if (!hasSameEEW(
MI, True))
743 if (PassthruReg && !isKnownSameDefs(PassthruReg, FalseReg))
746 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
752 !isKnownSameDefs(TruePassthru, FalseReg)) {
758 unsigned OpIdx1 = OtherIdx;
760 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
762 NeedsCommute = {OpIdx1, OpIdx2};
770 const MachineOperand &VMergeVL =
772 const MachineOperand &TrueVL =
783 unsigned RVVTSFlags =
802 "Foldable unmasked pseudo should have a policy op already");
806 if (!ensureDominates(MaskOp, True))
810 auto [OpIdx1, OpIdx2] = *NeedsCommute;
811 [[maybe_unused]]
bool Commuted =
812 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
813 assert(Commuted &&
"Failed to commute True?");
814 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
837 MRI->constrainRegClass(
840 MI.eraseFromParent();
845bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
856 TRI =
MRI->getTargetRegisterInfo();
860 for (MachineBasicBlock &
MBB : MF) {
869 Changed |= convertAllOnesVMergeToVMv(
MI);
870 Changed |= convertSameMaskVMergeToVMv(
MI);
871 if (foldUndefPassthruVMV_V_V(
MI)) {
883 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.
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()