Go to the documentation of this file.
48 #define DEBUG_TYPE "aarch64-mi-peephole-opt"
64 using OpcodePair = std::pair<unsigned, unsigned>;
66 using SplitAndOpcFunc =
67 std::function<std::optional<OpcodePair>(
T,
unsigned,
T &,
T &)>;
88 SplitAndOpcFunc<T> SplitAndOpc, BuildMIFunc BuildInstr);
94 bool visitADDSUB(
unsigned PosOpc,
unsigned NegOpc,
MachineInstr &
MI);
96 bool visitADDSSUBS(OpcodePair PosOpcs, OpcodePair NegOpcs,
MachineInstr &
MI);
105 return "AArch64 MI Peephole Optimization pass";
120 "AArch64 MI Peephole Optimization",
false,
false)
122 template <typename
T>
124 T UImm =
static_cast<T>(
Imm);
131 if (
Insn.size() == 1)
160 template <
typename T>
161 bool AArch64MIPeepholeOpt::visitAND(
173 return splitTwoPartImm<T>(
176 T &Imm1) -> std::optional<OpcodePair> {
177 if (splitBitmaskImm(
Imm,
RegSize, Imm0, Imm1))
178 return std::make_pair(Opc, Opc);
200 if (
MI.getOperand(3).getImm() != 0)
203 if (
MI.getOperand(1).getReg() != AArch64::WZR)
220 if (SrcMI->
getOpcode() == TargetOpcode::COPY &&
227 if (RC != &AArch64::FPR32RegClass &&
228 ((RC != &AArch64::FPR64RegClass && RC != &AArch64::FPR128RegClass) ||
235 TII->get(TargetOpcode::COPY), CpySrc)
243 else if (SrcMI->
getOpcode() <= TargetOpcode::GENERIC_OP_END)
251 MI.eraseFromParent();
264 if (!
MI.isRegTiedToDefOperand(1))
283 if ((SrcMI->
getOpcode() <= TargetOpcode::GENERIC_OP_END) ||
284 !AArch64::GPR64allRegClass.hasSubClassEq(RC))
290 TII->get(TargetOpcode::SUBREG_TO_REG), DstReg)
292 .
add(
MI.getOperand(2))
293 .
add(
MI.getOperand(3));
296 MI.eraseFromParent();
301 template <
typename T>
305 if ((
Imm & 0xfff000) == 0 || (
Imm & 0xfff) == 0 ||
306 (
Imm & ~
static_cast<T>(0xffffff)) != 0)
312 if (
Insn.size() == 1)
316 Imm0 = (
Imm >> 12) & 0xfff;
321 template <
typename T>
322 bool AArch64MIPeepholeOpt::visitADDSUB(
337 return splitTwoPartImm<T>(
340 T &Imm1) -> std::optional<OpcodePair> {
342 return std::make_pair(PosOpc, PosOpc);
344 return std::make_pair(NegOpc, NegOpc);
363 template <
typename T>
364 bool AArch64MIPeepholeOpt::visitADDSSUBS(
368 return splitTwoPartImm<T>(
372 T &Imm1) -> std::optional<OpcodePair> {
384 if (!NZCVUsed || NZCVUsed->C || NZCVUsed->V)
421 SubregToRegMI =
nullptr;
422 if (MovMI->
getOpcode() == TargetOpcode::SUBREG_TO_REG) {
423 SubregToRegMI = MovMI;
429 if (MovMI->
getOpcode() != AArch64::MOVi32imm &&
430 MovMI->
getOpcode() != AArch64::MOVi64imm)
444 template <
typename T>
445 bool AArch64MIPeepholeOpt::splitTwoPartImm(
447 SplitAndOpcFunc<T> SplitAndOpc, BuildMIFunc BuildInstr) {
450 "Invalid RegSize for legal immediate peephole optimization");
454 if (!checkMovImmInstr(
MI, MovMI, SubregToRegMI))
466 if (
auto R = SplitAndOpc(
Imm,
RegSize, Imm0, Imm1))
479 TII->getRegClass(
TII->get(Opcode.first), 0,
TRI, *MF);
481 TII->getRegClass(
TII->get(Opcode.first), 1,
TRI, *MF);
483 (Opcode.first == Opcode.second)
485 :
TII->getRegClass(
TII->get(Opcode.second), 0,
TRI, *MF);
487 (Opcode.first == Opcode.second)
488 ? FirstInstrOperandRC
489 :
TII->getRegClass(
TII->get(Opcode.second), 1,
TRI, *MF);
504 if (DstReg != NewDstReg)
508 BuildInstr(
MI, Opcode, Imm0, Imm1, SrcReg, NewTmpReg, NewDstReg);
512 if (DstReg != NewDstReg) {
514 MI.getOperand(0).setReg(DstReg);
518 MI.eraseFromParent();
533 MLI = &getAnalysis<MachineLoopInfo>();
538 bool Changed =
false;
542 switch (
MI.getOpcode()) {
545 case AArch64::INSERT_SUBREG:
546 Changed = visitINSERT(
MI);
548 case AArch64::ANDWrr:
549 Changed = visitAND<uint32_t>(AArch64::ANDWri,
MI);
551 case AArch64::ANDXrr:
552 Changed = visitAND<uint64_t>(AArch64::ANDXri,
MI);
554 case AArch64::ORRWrs:
555 Changed = visitORR(
MI);
557 case AArch64::ADDWrr:
558 Changed = visitADDSUB<uint32_t>(AArch64::ADDWri, AArch64::SUBWri,
MI);
560 case AArch64::SUBWrr:
561 Changed = visitADDSUB<uint32_t>(AArch64::SUBWri, AArch64::ADDWri,
MI);
563 case AArch64::ADDXrr:
564 Changed = visitADDSUB<uint64_t>(AArch64::ADDXri, AArch64::SUBXri,
MI);
566 case AArch64::SUBXrr:
567 Changed = visitADDSUB<uint64_t>(AArch64::SUBXri, AArch64::ADDXri,
MI);
569 case AArch64::ADDSWrr:
570 Changed = visitADDSSUBS<uint32_t>({AArch64::ADDWri, AArch64::ADDSWri},
571 {AArch64::SUBWri, AArch64::SUBSWri},
574 case AArch64::SUBSWrr:
575 Changed = visitADDSSUBS<uint32_t>({AArch64::SUBWri, AArch64::SUBSWri},
576 {AArch64::ADDWri, AArch64::ADDSWri},
579 case AArch64::ADDSXrr:
580 Changed = visitADDSSUBS<uint64_t>({AArch64::ADDXri, AArch64::ADDSXri},
581 {AArch64::SUBXri, AArch64::SUBSXri},
584 case AArch64::SUBSXrr:
585 Changed = visitADDSSUBS<uint64_t>({AArch64::SUBXri, AArch64::SUBSXri},
586 {AArch64::ADDXri, AArch64::ADDSXri},
597 return new AArch64MIPeepholeOpt();
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
This is an optimization pass for GlobalISel generic memory operations.
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const MachineInstrBuilder & add(const MachineOperand &MO) const
virtual const TargetInstrInfo * getInstrInfo() const
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
unsigned const TargetRegisterInfo * TRI
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
std::optional< UsedNZCV > examineCFlagsUse(MachineInstr &MI, MachineInstr &CmpInstr, const TargetRegisterInfo &TRI, SmallVectorImpl< MachineInstr * > *CCUseInstrs=nullptr)
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
const MachineOperand & getOperand(unsigned i) const
Represent the analysis usage information of a pass.
const HexagonInstrInfo * TII
static bool splitAddSubImm(T Imm, unsigned RegSize, T &Imm0, T &Imm1)
INITIALIZE_PASS(AArch64MIPeepholeOpt, "aarch64-mi-peephole-opt", "AArch64 MI Peephole Optimization", false, false) template< typename T > static bool splitBitmaskImm(T Imm
unsigned countTrailingZeros(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
Representation of each machine instruction.
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...
FunctionPass * createAArch64MIPeepholeOptPass()
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
print Print MemDeps of function
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Register getReg() const
getReg - Returns the register number.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
void setPreservesCFG()
This function should be called by the pass, iff they do not:
StringRef - Represent a constant reference to a string, i.e.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
const MachineBasicBlock * getParent() const
unsigned const MachineRegisterInfo * MRI
Wrapper class representing virtual and physical registers.
unsigned getSubReg() const
void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
void initializeAArch64MIPeepholeOptPass(PassRegistry &)
SmallVector< AArch64_IMM::ImmInsnModel, 4 > Insn
Function & getFunction()
Return the LLVM function that this machine code represents.
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
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...
FunctionPass class - This class is used to implement most global optimizations.
AnalysisUsage & addRequired()
bool isLoopInvariant(MachineInstr &I) const
Returns true if the instruction is loop invariant.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.