123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- //===- AArch64MIPeepholeOpt.cpp - AArch64 MI peephole optimization pass ---===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This pass performs below peephole optimizations on MIR level.
- //
- // 1. MOVi32imm + ANDWrr ==> ANDWri + ANDWri
- // MOVi64imm + ANDXrr ==> ANDXri + ANDXri
- //
- // 2. MOVi32imm + ADDWrr ==> ADDWRi + ADDWRi
- // MOVi64imm + ADDXrr ==> ANDXri + ANDXri
- //
- // 3. MOVi32imm + SUBWrr ==> SUBWRi + SUBWRi
- // MOVi64imm + SUBXrr ==> SUBXri + SUBXri
- //
- // The mov pseudo instruction could be expanded to multiple mov instructions
- // later. In this case, we could try to split the constant operand of mov
- // instruction into two immediates which can be directly encoded into
- // *Wri/*Xri instructions. It makes two AND/ADD/SUB instructions instead of
- // multiple `mov` + `and/add/sub` instructions.
- //
- // 4. Remove redundant ORRWrs which is generated by zero-extend.
- //
- // %3:gpr32 = ORRWrs $wzr, %2, 0
- // %4:gpr64 = SUBREG_TO_REG 0, %3, %subreg.sub_32
- //
- // If AArch64's 32-bit form of instruction defines the source operand of
- // ORRWrs, we can remove the ORRWrs because the upper 32 bits of the source
- // operand are set to zero.
- //
- // 5. %reg = INSERT_SUBREG %reg(tied-def 0), %subreg, subidx
- // ==> %reg:subidx = SUBREG_TO_REG 0, %subreg, subidx
- //
- //===----------------------------------------------------------------------===//
- #include "AArch64ExpandImm.h"
- #include "AArch64InstrInfo.h"
- #include "MCTargetDesc/AArch64AddressingModes.h"
- #include "llvm/CodeGen/MachineDominators.h"
- #include "llvm/CodeGen/MachineLoopInfo.h"
- using namespace llvm;
- #define DEBUG_TYPE "aarch64-mi-peephole-opt"
- namespace {
- struct AArch64MIPeepholeOpt : public MachineFunctionPass {
- static char ID;
- AArch64MIPeepholeOpt() : MachineFunctionPass(ID) {
- initializeAArch64MIPeepholeOptPass(*PassRegistry::getPassRegistry());
- }
- const AArch64InstrInfo *TII;
- const AArch64RegisterInfo *TRI;
- MachineLoopInfo *MLI;
- MachineRegisterInfo *MRI;
- using OpcodePair = std::pair<unsigned, unsigned>;
- template <typename T>
- using SplitAndOpcFunc =
- std::function<std::optional<OpcodePair>(T, unsigned, T &, T &)>;
- using BuildMIFunc =
- std::function<void(MachineInstr &, OpcodePair, unsigned, unsigned,
- Register, Register, Register)>;
- /// For instructions where an immediate operand could be split into two
- /// separate immediate instructions, use the splitTwoPartImm two handle the
- /// optimization.
- ///
- /// To implement, the following function types must be passed to
- /// splitTwoPartImm. A SplitAndOpcFunc must be implemented that determines if
- /// splitting the immediate is valid and returns the associated new opcode. A
- /// BuildMIFunc must be implemented to build the two immediate instructions.
- ///
- /// Example Pattern (where IMM would require 2+ MOV instructions):
- /// %dst = <Instr>rr %src IMM [...]
- /// becomes:
- /// %tmp = <Instr>ri %src (encode half IMM) [...]
- /// %dst = <Instr>ri %tmp (encode half IMM) [...]
- template <typename T>
- bool splitTwoPartImm(MachineInstr &MI,
- SplitAndOpcFunc<T> SplitAndOpc, BuildMIFunc BuildInstr);
- bool checkMovImmInstr(MachineInstr &MI, MachineInstr *&MovMI,
- MachineInstr *&SubregToRegMI);
- template <typename T>
- bool visitADDSUB(unsigned PosOpc, unsigned NegOpc, MachineInstr &MI);
- template <typename T>
- bool visitADDSSUBS(OpcodePair PosOpcs, OpcodePair NegOpcs, MachineInstr &MI);
- template <typename T>
- bool visitAND(unsigned Opc, MachineInstr &MI);
- bool visitORR(MachineInstr &MI);
- bool visitINSERT(MachineInstr &MI);
- bool runOnMachineFunction(MachineFunction &MF) override;
- StringRef getPassName() const override {
- return "AArch64 MI Peephole Optimization pass";
- }
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesCFG();
- AU.addRequired<MachineLoopInfo>();
- MachineFunctionPass::getAnalysisUsage(AU);
- }
- };
- char AArch64MIPeepholeOpt::ID = 0;
- } // end anonymous namespace
- INITIALIZE_PASS(AArch64MIPeepholeOpt, "aarch64-mi-peephole-opt",
- "AArch64 MI Peephole Optimization", false, false)
- template <typename T>
- static bool splitBitmaskImm(T Imm, unsigned RegSize, T &Imm1Enc, T &Imm2Enc) {
- T UImm = static_cast<T>(Imm);
- if (AArch64_AM::isLogicalImmediate(UImm, RegSize))
- return false;
- // If this immediate can be handled by one instruction, do not split it.
- SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
- AArch64_IMM::expandMOVImm(UImm, RegSize, Insn);
- if (Insn.size() == 1)
- return false;
- // The bitmask immediate consists of consecutive ones. Let's say there is
- // constant 0b00000000001000000000010000000000 which does not consist of
- // consecutive ones. We can split it in to two bitmask immediate like
- // 0b00000000001111111111110000000000 and 0b11111111111000000000011111111111.
- // If we do AND with these two bitmask immediate, we can see original one.
- unsigned LowestBitSet = countTrailingZeros(UImm);
- unsigned HighestBitSet = Log2_64(UImm);
- // Create a mask which is filled with one from the position of lowest bit set
- // to the position of highest bit set.
- T NewImm1 = (static_cast<T>(2) << HighestBitSet) -
- (static_cast<T>(1) << LowestBitSet);
- // Create a mask which is filled with one outside the position of lowest bit
- // set and the position of highest bit set.
- T NewImm2 = UImm | ~NewImm1;
- // If the split value is not valid bitmask immediate, do not split this
- // constant.
- if (!AArch64_AM::isLogicalImmediate(NewImm2, RegSize))
- return false;
- Imm1Enc = AArch64_AM::encodeLogicalImmediate(NewImm1, RegSize);
- Imm2Enc = AArch64_AM::encodeLogicalImmediate(NewImm2, RegSize);
- return true;
- }
- template <typename T>
- bool AArch64MIPeepholeOpt::visitAND(
- unsigned Opc, MachineInstr &MI) {
- // Try below transformation.
- //
- // MOVi32imm + ANDWrr ==> ANDWri + ANDWri
- // MOVi64imm + ANDXrr ==> ANDXri + ANDXri
- //
- // The mov pseudo instruction could be expanded to multiple mov instructions
- // later. Let's try to split the constant operand of mov instruction into two
- // bitmask immediates. It makes only two AND instructions intead of multiple
- // mov + and instructions.
- return splitTwoPartImm<T>(
- MI,
- [Opc](T Imm, unsigned RegSize, T &Imm0,
- T &Imm1) -> std::optional<OpcodePair> {
- if (splitBitmaskImm(Imm, RegSize, Imm0, Imm1))
- return std::make_pair(Opc, Opc);
- return std::nullopt;
- },
- [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
- unsigned Imm1, Register SrcReg, Register NewTmpReg,
- Register NewDstReg) {
- DebugLoc DL = MI.getDebugLoc();
- MachineBasicBlock *MBB = MI.getParent();
- BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
- .addReg(SrcReg)
- .addImm(Imm0);
- BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
- .addReg(NewTmpReg)
- .addImm(Imm1);
- });
- }
- bool AArch64MIPeepholeOpt::visitORR(MachineInstr &MI) {
- // Check this ORR comes from below zero-extend pattern.
- //
- // def : Pat<(i64 (zext GPR32:$src)),
- // (SUBREG_TO_REG (i32 0), (ORRWrs WZR, GPR32:$src, 0), sub_32)>;
- if (MI.getOperand(3).getImm() != 0)
- return false;
- if (MI.getOperand(1).getReg() != AArch64::WZR)
- return false;
- MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
- if (!SrcMI)
- return false;
- // From https://developer.arm.com/documentation/dui0801/b/BABBGCAC
- //
- // When you use the 32-bit form of an instruction, the upper 32 bits of the
- // source registers are ignored and the upper 32 bits of the destination
- // register are set to zero.
- //
- // If AArch64's 32-bit form of instruction defines the source operand of
- // zero-extend, we do not need the zero-extend. Let's check the MI's opcode is
- // real AArch64 instruction and if it is not, do not process the opcode
- // conservatively.
- if (SrcMI->getOpcode() == TargetOpcode::COPY &&
- SrcMI->getOperand(1).getReg().isVirtual()) {
- const TargetRegisterClass *RC =
- MRI->getRegClass(SrcMI->getOperand(1).getReg());
- // A COPY from an FPR will become a FMOVSWr, so do so now so that we know
- // that the upper bits are zero.
- if (RC != &AArch64::FPR32RegClass &&
- ((RC != &AArch64::FPR64RegClass && RC != &AArch64::FPR128RegClass) ||
- SrcMI->getOperand(1).getSubReg() != AArch64::ssub))
- return false;
- Register CpySrc = SrcMI->getOperand(1).getReg();
- if (SrcMI->getOperand(1).getSubReg() == AArch64::ssub) {
- CpySrc = MRI->createVirtualRegister(&AArch64::FPR32RegClass);
- BuildMI(*SrcMI->getParent(), SrcMI, SrcMI->getDebugLoc(),
- TII->get(TargetOpcode::COPY), CpySrc)
- .add(SrcMI->getOperand(1));
- }
- BuildMI(*SrcMI->getParent(), SrcMI, SrcMI->getDebugLoc(),
- TII->get(AArch64::FMOVSWr), SrcMI->getOperand(0).getReg())
- .addReg(CpySrc);
- SrcMI->eraseFromParent();
- }
- else if (SrcMI->getOpcode() <= TargetOpcode::GENERIC_OP_END)
- return false;
- Register DefReg = MI.getOperand(0).getReg();
- Register SrcReg = MI.getOperand(2).getReg();
- MRI->replaceRegWith(DefReg, SrcReg);
- MRI->clearKillFlags(SrcReg);
- LLVM_DEBUG(dbgs() << "Removed: " << MI << "\n");
- MI.eraseFromParent();
- return true;
- }
- bool AArch64MIPeepholeOpt::visitINSERT(MachineInstr &MI) {
- // Check this INSERT_SUBREG comes from below zero-extend pattern.
- //
- // From %reg = INSERT_SUBREG %reg(tied-def 0), %subreg, subidx
- // To %reg:subidx = SUBREG_TO_REG 0, %subreg, subidx
- //
- // We're assuming the first operand to INSERT_SUBREG is irrelevant because a
- // COPY would destroy the upper part of the register anyway
- if (!MI.isRegTiedToDefOperand(1))
- return false;
- Register DstReg = MI.getOperand(0).getReg();
- const TargetRegisterClass *RC = MRI->getRegClass(DstReg);
- MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
- if (!SrcMI)
- return false;
- // From https://developer.arm.com/documentation/dui0801/b/BABBGCAC
- //
- // When you use the 32-bit form of an instruction, the upper 32 bits of the
- // source registers are ignored and the upper 32 bits of the destination
- // register are set to zero.
- //
- // If AArch64's 32-bit form of instruction defines the source operand of
- // zero-extend, we do not need the zero-extend. Let's check the MI's opcode is
- // real AArch64 instruction and if it is not, do not process the opcode
- // conservatively.
- if ((SrcMI->getOpcode() <= TargetOpcode::GENERIC_OP_END) ||
- !AArch64::GPR64allRegClass.hasSubClassEq(RC))
- return false;
- // Build a SUBREG_TO_REG instruction
- MachineInstr *SubregMI =
- BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
- TII->get(TargetOpcode::SUBREG_TO_REG), DstReg)
- .addImm(0)
- .add(MI.getOperand(2))
- .add(MI.getOperand(3));
- LLVM_DEBUG(dbgs() << MI << " replace by:\n: " << *SubregMI << "\n");
- (void)SubregMI;
- MI.eraseFromParent();
- return true;
- }
- template <typename T>
- static bool splitAddSubImm(T Imm, unsigned RegSize, T &Imm0, T &Imm1) {
- // The immediate must be in the form of ((imm0 << 12) + imm1), in which both
- // imm0 and imm1 are non-zero 12-bit unsigned int.
- if ((Imm & 0xfff000) == 0 || (Imm & 0xfff) == 0 ||
- (Imm & ~static_cast<T>(0xffffff)) != 0)
- return false;
- // The immediate can not be composed via a single instruction.
- SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
- AArch64_IMM::expandMOVImm(Imm, RegSize, Insn);
- if (Insn.size() == 1)
- return false;
- // Split Imm into (Imm0 << 12) + Imm1;
- Imm0 = (Imm >> 12) & 0xfff;
- Imm1 = Imm & 0xfff;
- return true;
- }
- template <typename T>
- bool AArch64MIPeepholeOpt::visitADDSUB(
- unsigned PosOpc, unsigned NegOpc, MachineInstr &MI) {
- // Try below transformation.
- //
- // MOVi32imm + ADDWrr ==> ADDWri + ADDWri
- // MOVi64imm + ADDXrr ==> ADDXri + ADDXri
- //
- // MOVi32imm + SUBWrr ==> SUBWri + SUBWri
- // MOVi64imm + SUBXrr ==> SUBXri + SUBXri
- //
- // The mov pseudo instruction could be expanded to multiple mov instructions
- // later. Let's try to split the constant operand of mov instruction into two
- // legal add/sub immediates. It makes only two ADD/SUB instructions intead of
- // multiple `mov` + `and/sub` instructions.
- return splitTwoPartImm<T>(
- MI,
- [PosOpc, NegOpc](T Imm, unsigned RegSize, T &Imm0,
- T &Imm1) -> std::optional<OpcodePair> {
- if (splitAddSubImm(Imm, RegSize, Imm0, Imm1))
- return std::make_pair(PosOpc, PosOpc);
- if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1))
- return std::make_pair(NegOpc, NegOpc);
- return std::nullopt;
- },
- [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
- unsigned Imm1, Register SrcReg, Register NewTmpReg,
- Register NewDstReg) {
- DebugLoc DL = MI.getDebugLoc();
- MachineBasicBlock *MBB = MI.getParent();
- BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
- .addReg(SrcReg)
- .addImm(Imm0)
- .addImm(12);
- BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
- .addReg(NewTmpReg)
- .addImm(Imm1)
- .addImm(0);
- });
- }
- template <typename T>
- bool AArch64MIPeepholeOpt::visitADDSSUBS(
- OpcodePair PosOpcs, OpcodePair NegOpcs, MachineInstr &MI) {
- // Try the same transformation as ADDSUB but with additional requirement
- // that the condition code usages are only for Equal and Not Equal
- return splitTwoPartImm<T>(
- MI,
- [PosOpcs, NegOpcs, &MI, &TRI = TRI,
- &MRI = MRI](T Imm, unsigned RegSize, T &Imm0,
- T &Imm1) -> std::optional<OpcodePair> {
- OpcodePair OP;
- if (splitAddSubImm(Imm, RegSize, Imm0, Imm1))
- OP = PosOpcs;
- else if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1))
- OP = NegOpcs;
- else
- return std::nullopt;
- // Check conditional uses last since it is expensive for scanning
- // proceeding instructions
- MachineInstr &SrcMI = *MRI->getUniqueVRegDef(MI.getOperand(1).getReg());
- std::optional<UsedNZCV> NZCVUsed = examineCFlagsUse(SrcMI, MI, *TRI);
- if (!NZCVUsed || NZCVUsed->C || NZCVUsed->V)
- return std::nullopt;
- return OP;
- },
- [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
- unsigned Imm1, Register SrcReg, Register NewTmpReg,
- Register NewDstReg) {
- DebugLoc DL = MI.getDebugLoc();
- MachineBasicBlock *MBB = MI.getParent();
- BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
- .addReg(SrcReg)
- .addImm(Imm0)
- .addImm(12);
- BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
- .addReg(NewTmpReg)
- .addImm(Imm1)
- .addImm(0);
- });
- }
- // Checks if the corresponding MOV immediate instruction is applicable for
- // this peephole optimization.
- bool AArch64MIPeepholeOpt::checkMovImmInstr(MachineInstr &MI,
- MachineInstr *&MovMI,
- MachineInstr *&SubregToRegMI) {
- // Check whether current MBB is in loop and the AND is loop invariant.
- MachineBasicBlock *MBB = MI.getParent();
- MachineLoop *L = MLI->getLoopFor(MBB);
- if (L && !L->isLoopInvariant(MI))
- return false;
- // Check whether current MI's operand is MOV with immediate.
- MovMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
- if (!MovMI)
- return false;
- // If it is SUBREG_TO_REG, check its operand.
- SubregToRegMI = nullptr;
- if (MovMI->getOpcode() == TargetOpcode::SUBREG_TO_REG) {
- SubregToRegMI = MovMI;
- MovMI = MRI->getUniqueVRegDef(MovMI->getOperand(2).getReg());
- if (!MovMI)
- return false;
- }
- if (MovMI->getOpcode() != AArch64::MOVi32imm &&
- MovMI->getOpcode() != AArch64::MOVi64imm)
- return false;
- // If the MOV has multiple uses, do not split the immediate because it causes
- // more instructions.
- if (!MRI->hasOneUse(MovMI->getOperand(0).getReg()))
- return false;
- if (SubregToRegMI && !MRI->hasOneUse(SubregToRegMI->getOperand(0).getReg()))
- return false;
- // It is OK to perform this peephole optimization.
- return true;
- }
- template <typename T>
- bool AArch64MIPeepholeOpt::splitTwoPartImm(
- MachineInstr &MI,
- SplitAndOpcFunc<T> SplitAndOpc, BuildMIFunc BuildInstr) {
- unsigned RegSize = sizeof(T) * 8;
- assert((RegSize == 32 || RegSize == 64) &&
- "Invalid RegSize for legal immediate peephole optimization");
- // Perform several essential checks against current MI.
- MachineInstr *MovMI, *SubregToRegMI;
- if (!checkMovImmInstr(MI, MovMI, SubregToRegMI))
- return false;
- // Split the immediate to Imm0 and Imm1, and calculate the Opcode.
- T Imm = static_cast<T>(MovMI->getOperand(1).getImm()), Imm0, Imm1;
- // For the 32 bit form of instruction, the upper 32 bits of the destination
- // register are set to zero. If there is SUBREG_TO_REG, set the upper 32 bits
- // of Imm to zero. This is essential if the Immediate value was a negative
- // number since it was sign extended when we assign to the 64-bit Imm.
- if (SubregToRegMI)
- Imm &= 0xFFFFFFFF;
- OpcodePair Opcode;
- if (auto R = SplitAndOpc(Imm, RegSize, Imm0, Imm1))
- Opcode = *R;
- else
- return false;
- // Create new MIs using the first and second opcodes. Opcodes might differ for
- // flag setting operations that should only set flags on second instruction.
- // NewTmpReg = Opcode.first SrcReg Imm0
- // NewDstReg = Opcode.second NewTmpReg Imm1
- // Determine register classes for destinations and register operands
- MachineFunction *MF = MI.getMF();
- const TargetRegisterClass *FirstInstrDstRC =
- TII->getRegClass(TII->get(Opcode.first), 0, TRI, *MF);
- const TargetRegisterClass *FirstInstrOperandRC =
- TII->getRegClass(TII->get(Opcode.first), 1, TRI, *MF);
- const TargetRegisterClass *SecondInstrDstRC =
- (Opcode.first == Opcode.second)
- ? FirstInstrDstRC
- : TII->getRegClass(TII->get(Opcode.second), 0, TRI, *MF);
- const TargetRegisterClass *SecondInstrOperandRC =
- (Opcode.first == Opcode.second)
- ? FirstInstrOperandRC
- : TII->getRegClass(TII->get(Opcode.second), 1, TRI, *MF);
- // Get old registers destinations and new register destinations
- Register DstReg = MI.getOperand(0).getReg();
- Register SrcReg = MI.getOperand(1).getReg();
- Register NewTmpReg = MRI->createVirtualRegister(FirstInstrDstRC);
- // In the situation that DstReg is not Virtual (likely WZR or XZR), we want to
- // reuse that same destination register.
- Register NewDstReg = DstReg.isVirtual()
- ? MRI->createVirtualRegister(SecondInstrDstRC)
- : DstReg;
- // Constrain registers based on their new uses
- MRI->constrainRegClass(SrcReg, FirstInstrOperandRC);
- MRI->constrainRegClass(NewTmpReg, SecondInstrOperandRC);
- if (DstReg != NewDstReg)
- MRI->constrainRegClass(NewDstReg, MRI->getRegClass(DstReg));
- // Call the delegating operation to build the instruction
- BuildInstr(MI, Opcode, Imm0, Imm1, SrcReg, NewTmpReg, NewDstReg);
- // replaceRegWith changes MI's definition register. Keep it for SSA form until
- // deleting MI. Only if we made a new destination register.
- if (DstReg != NewDstReg) {
- MRI->replaceRegWith(DstReg, NewDstReg);
- MI.getOperand(0).setReg(DstReg);
- }
- // Record the MIs need to be removed.
- MI.eraseFromParent();
- if (SubregToRegMI)
- SubregToRegMI->eraseFromParent();
- MovMI->eraseFromParent();
- return true;
- }
- bool AArch64MIPeepholeOpt::runOnMachineFunction(MachineFunction &MF) {
- if (skipFunction(MF.getFunction()))
- return false;
- TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
- TRI = static_cast<const AArch64RegisterInfo *>(
- MF.getSubtarget().getRegisterInfo());
- MLI = &getAnalysis<MachineLoopInfo>();
- MRI = &MF.getRegInfo();
- assert(MRI->isSSA() && "Expected to be run on SSA form!");
- bool Changed = false;
- for (MachineBasicBlock &MBB : MF) {
- for (MachineInstr &MI : make_early_inc_range(MBB)) {
- switch (MI.getOpcode()) {
- default:
- break;
- case AArch64::INSERT_SUBREG:
- Changed = visitINSERT(MI);
- break;
- case AArch64::ANDWrr:
- Changed = visitAND<uint32_t>(AArch64::ANDWri, MI);
- break;
- case AArch64::ANDXrr:
- Changed = visitAND<uint64_t>(AArch64::ANDXri, MI);
- break;
- case AArch64::ORRWrs:
- Changed = visitORR(MI);
- break;
- case AArch64::ADDWrr:
- Changed = visitADDSUB<uint32_t>(AArch64::ADDWri, AArch64::SUBWri, MI);
- break;
- case AArch64::SUBWrr:
- Changed = visitADDSUB<uint32_t>(AArch64::SUBWri, AArch64::ADDWri, MI);
- break;
- case AArch64::ADDXrr:
- Changed = visitADDSUB<uint64_t>(AArch64::ADDXri, AArch64::SUBXri, MI);
- break;
- case AArch64::SUBXrr:
- Changed = visitADDSUB<uint64_t>(AArch64::SUBXri, AArch64::ADDXri, MI);
- break;
- case AArch64::ADDSWrr:
- Changed = visitADDSSUBS<uint32_t>({AArch64::ADDWri, AArch64::ADDSWri},
- {AArch64::SUBWri, AArch64::SUBSWri},
- MI);
- break;
- case AArch64::SUBSWrr:
- Changed = visitADDSSUBS<uint32_t>({AArch64::SUBWri, AArch64::SUBSWri},
- {AArch64::ADDWri, AArch64::ADDSWri},
- MI);
- break;
- case AArch64::ADDSXrr:
- Changed = visitADDSSUBS<uint64_t>({AArch64::ADDXri, AArch64::ADDSXri},
- {AArch64::SUBXri, AArch64::SUBSXri},
- MI);
- break;
- case AArch64::SUBSXrr:
- Changed = visitADDSSUBS<uint64_t>({AArch64::SUBXri, AArch64::SUBSXri},
- {AArch64::ADDXri, AArch64::ADDSXri},
- MI);
- break;
- }
- }
- }
- return Changed;
- }
- FunctionPass *llvm::createAArch64MIPeepholeOptPass() {
- return new AArch64MIPeepholeOpt();
- }
|