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;
102std::optional<unsigned>
108 if (!Def ||
Def->getOpcode() != RISCV::ADDI ||
109 Def->getOperand(1).getReg() != RISCV::X0)
111 return Def->getOperand(2).getImm();
115bool RISCVVectorPeephole::convertToVLMAX(MachineInstr &
MI)
const {
122 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
125 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
127 assert(8 * LMULFixed / SEW > 0);
132 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
146 uint64_t ScaleFixed = 8;
148 if (
Def->getOpcode() == RISCV::SLLI) {
149 assert(
Def->getOperand(2).getImm() < 64);
150 ScaleFixed <<=
Def->getOperand(2).getImm();
152 }
else if (
Def->getOpcode() == RISCV::SRLI) {
153 assert(
Def->getOperand(2).getImm() < 64);
154 ScaleFixed >>=
Def->getOperand(2).getImm();
158 if (!Def ||
Def->getOpcode() != RISCV::PseudoReadVLENB)
168 if (ScaleFixed != 8 * LMULFixed / SEW)
176bool RISCVVectorPeephole::isAllOnesMask(
const MachineInstr *MaskDef)
const {
184 case RISCV::PseudoVMSET_M_B1:
185 case RISCV::PseudoVMSET_M_B2:
186 case RISCV::PseudoVMSET_M_B4:
187 case RISCV::PseudoVMSET_M_B8:
188 case RISCV::PseudoVMSET_M_B16:
189 case RISCV::PseudoVMSET_M_B32:
190 case RISCV::PseudoVMSET_M_B64:
207bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &
MI)
const {
208#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
209 case RISCV::PseudoVLE##sew##_V_M##lmul: \
210 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
212 case RISCV::PseudoVSE##sew##_V_M##lmul: \
213 NewOpc = RISCV::VS##lmul##R_V; \
215#define CASE_WHOLE_REGISTER_LMUL(lmul) \
216 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
217 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
218 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
219 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
222 switch (
MI.getOpcode()) {
231 MachineOperand &VLOp =
MI.getOperand(RISCVII::getVLOpNum(
MI.getDesc()));
232 if (!VLOp.isImm() || VLOp.
getImm() != RISCV::VLMaxSentinel)
237 if (RISCVII::hasVecPolicyOp(
MI.getDesc().TSFlags))
238 MI.removeOperand(RISCVII::getVecPolicyOpNum(
MI.getDesc()));
239 MI.removeOperand(RISCVII::getSEWOpNum(
MI.getDesc()));
240 MI.removeOperand(RISCVII::getVLOpNum(
MI.getDesc()));
241 if (RISCVII::isFirstDefTiedToFirstUse(
MI.getDesc()))
249static
unsigned getVMV_V_VOpcodeForVMERGE_VVM(
const MachineInstr &
MI) {
250#define CASE_VMERGE_TO_VMV(lmul) \
251 case RISCV::PseudoVMERGE_VVM_##lmul: \
252 return RISCV::PseudoVMV_V_V_##lmul;
253 switch (
MI.getOpcode()) {
256 CASE_VMERGE_TO_VMV(MF8)
257 CASE_VMERGE_TO_VMV(MF4)
258 CASE_VMERGE_TO_VMV(MF2)
259 CASE_VMERGE_TO_VMV(M1)
260 CASE_VMERGE_TO_VMV(M2)
261 CASE_VMERGE_TO_VMV(M4)
262 CASE_VMERGE_TO_VMV(M8)
271bool RISCVVectorPeephole::convertAllOnesVMergeToVMv(MachineInstr &
MI)
const {
272 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
275 if (!isAllOnesMask(MRI->
getVRegDef(
MI.getOperand(4).getReg())))
278 MI.setDesc(
TII->get(NewOpc));
287 if (
MI.getOperand(1).getReg().isValid())
294Register RISCVVectorPeephole::lookThruCopies(
296 SmallVectorImpl<MachineInstr *> *
Copies)
const {
298 if (!
Def->isFullCopy())
301 if (!Src.isVirtual())
321bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &
MI) {
322 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(
MI);
325 MachineInstr *True = MRI->
getVRegDef(
MI.getOperand(3).getReg());
330 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->
getOpcode());
331 if (!TrueMaskedInfo || !hasSameEEW(
MI, *True))
334 Register TrueMaskReg = lookThruCopies(
337 Register MIMaskReg = lookThruCopies(
MI.getOperand(4).getReg());
338 if (!TrueMaskReg.
isVirtual() || TrueMaskReg != MIMaskReg)
346 const MachineOperand &TrueVL =
348 Register FalseReg =
MI.getOperand(2).getReg();
350 Register PassthruReg =
MI.getOperand(1).getReg();
351 if (FalseReg.
isValid() && FalseReg != PassthruReg)
355 uint64_t TruePolicy =
363 if (TruePassthruReg != FalseReg) {
365 if (TruePassthruReg.
isValid() ||
367 !ensureDominates(&
MI.getOperand(2), *True))
377 MachineOperand &PolicyOp =
382 MI.setDesc(
TII->get(NewOpc));
391 if (
MI.getOperand(1).getReg().isValid())
396bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &
MI)
const {
397 const RISCV::RISCVMaskedPseudoInfo *
I =
398 RISCV::getMaskedPseudoInfo(
MI.getOpcode());
403 MI.getOperand(
I->MaskOpIdx +
MI.getNumExplicitDefs()).getReg())))
408 const unsigned Opc =
I->UnmaskedPseudo;
409 const MCInstrDesc &MCID =
TII->get(
Opc);
410 [[maybe_unused]]
const bool HasPolicyOp =
413 const MCInstrDesc &MaskedMCID =
TII->get(
MI.getOpcode());
416 "Unmasked pseudo has policy but masked pseudo doesn't?");
417 assert(HasPolicyOp == HasPassthru &&
"Unexpected pseudo structure");
419 "Unmasked with passthru but masked with no passthru?");
430 unsigned MaskOpIdx =
I->MaskOpIdx +
MI.getNumExplicitDefs();
431 MI.removeOperand(MaskOpIdx);
439 unsigned PassthruOpIdx =
MI.getNumExplicitDefs();
441 if (
MI.getOperand(PassthruOpIdx).getReg())
444 MI.removeOperand(PassthruOpIdx);
453 assert(
A->getParent() ==
B->getParent());
455 auto MBBEnd =
MBB->end();
460 for (; &*
I !=
A && &*
I !=
B; ++
I)
470 MachineInstr &Use)
const {
471 MachineInstr *Dest = &
Use;
473 for (
const MachineOperand *MO : Defs) {
474 assert(MO->getParent()->getParent() ==
Use.getParent());
475 if (!MO->isReg() || !MO->getReg().isValid())
482 Dest =
Def->getNextNode();
487 Use.moveBefore(Dest);
493bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &
MI) {
496 if (
MI.getOperand(1).getReg().isValid())
501 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
502 if (Src && !Src->hasUnmodeledSideEffects() &&
506 const MachineOperand &MIVL =
MI.getOperand(3);
507 const MachineOperand &SrcVL =
510 MachineOperand &SrcPolicy =
521 MI.eraseFromParent();
535bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &
MI) {
539 MachineOperand &Passthru =
MI.getOperand(1);
544 MachineInstr *Src = MRI->
getVRegDef(
MI.getOperand(2).getReg());
545 if (!Src || Src->hasUnmodeledSideEffects() ||
546 Src->getParent() !=
MI.getParent() ||
552 if (!hasSameEEW(
MI, *Src))
555 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
558 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
563 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.
getReg(),
TRI);
566 unsigned OpIdx1 = OtherIdx;
567 unsigned OpIdx2 = Src->getNumExplicitDefs();
568 if (!
TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
570 NeedsCommute = {OpIdx1, OpIdx2};
581 if (!ensureDominates(&Passthru, *Src))
585 auto [OpIdx1, OpIdx2] = *NeedsCommute;
586 [[maybe_unused]]
bool Commuted =
587 TII->commuteInstruction(*Src,
false, OpIdx1, OpIdx2);
588 assert(Commuted &&
"Failed to commute Src?");
611 MRI->
replaceRegWith(
MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
612 MI.eraseFromParent();
635bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &
MI)
const {
640 SmallVector<MachineInstr *, 4> TrueCopies;
641 Register PassthruReg = lookThruCopies(
MI.getOperand(1).getReg());
642 const MachineOperand &FalseOp =
MI.getOperand(2);
644 Register TrueReg = lookThruCopies(
MI.getOperand(3).getReg(),
651 const MachineOperand &MaskOp =
MI.getOperand(4);
655 const RISCV::RISCVMaskedPseudoInfo *
Info =
656 RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
661 if (!hasSameEEW(
MI, True))
666 if (PassthruReg && !(PassthruReg.
isVirtual() && PassthruReg == FalseReg))
669 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
677 if (TruePassthru && !(TruePassthru.
isVirtual() && TruePassthru == FalseReg)) {
683 unsigned OpIdx1 = OtherIdx;
685 if (!
TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
687 NeedsCommute = {OpIdx1, OpIdx2};
695 const MachineOperand &VMergeVL =
697 const MachineOperand &TrueVL =
711 unsigned RVVTSFlags =
730 "Foldable unmasked pseudo should have a policy op already");
734 if (!ensureDominates({&MaskOp, &FalseOp, &MinVL}, True))
738 auto [OpIdx1, OpIdx2] = *NeedsCommute;
739 [[maybe_unused]]
bool Commuted =
740 TII->commuteInstruction(True,
false, OpIdx1, OpIdx2);
741 assert(Commuted &&
"Failed to commute True?");
742 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.
getOpcode());
763 if (!MO.isReg() || !MO.getReg().isVirtual())
770 MI.eraseFromParent();
774 for (MachineInstr *TrueCopy : TrueCopies)
775 TrueCopy->eraseFromParent();
780bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
795 for (MachineBasicBlock &
MBB : MF) {
803 Changed |= convertAllOnesVMergeToVMv(
MI);
804 Changed |= convertSameMaskVMergeToVMv(
MI);
805 if (foldUndefPassthruVMV_V_V(
MI)) {
817 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)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
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.
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 MachineBasicBlock::iterator &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...
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
NodeAddr< UseNode * > Use
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)
ArrayRef(const T &OneElt) -> ArrayRef< T >
FunctionPass * createRISCVVectorPeepholePass()