123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- //===- AArch64LowerHomogeneousPrologEpilog.cpp ----------------------------===//
- //
- // 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 file contains a pass that lowers homogeneous prolog/epilog instructions.
- //
- //===----------------------------------------------------------------------===//
- #include "AArch64InstrInfo.h"
- #include "AArch64Subtarget.h"
- #include "MCTargetDesc/AArch64InstPrinter.h"
- #include "Utils/AArch64BaseInfo.h"
- #include "llvm/CodeGen/MachineBasicBlock.h"
- #include "llvm/CodeGen/MachineFunction.h"
- #include "llvm/CodeGen/MachineFunctionPass.h"
- #include "llvm/CodeGen/MachineInstr.h"
- #include "llvm/CodeGen/MachineInstrBuilder.h"
- #include "llvm/CodeGen/MachineModuleInfo.h"
- #include "llvm/CodeGen/MachineOperand.h"
- #include "llvm/CodeGen/TargetSubtargetInfo.h"
- #include "llvm/IR/DebugLoc.h"
- #include "llvm/IR/IRBuilder.h"
- #include "llvm/Pass.h"
- #include "llvm/Support/raw_ostream.h"
- #include <optional>
- #include <sstream>
- using namespace llvm;
- #define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME \
- "AArch64 homogeneous prolog/epilog lowering pass"
- cl::opt<int> FrameHelperSizeThreshold(
- "frame-helper-size-threshold", cl::init(2), cl::Hidden,
- cl::desc("The minimum number of instructions that are outlined in a frame "
- "helper (default = 2)"));
- namespace {
- class AArch64LowerHomogeneousPE {
- public:
- const AArch64InstrInfo *TII;
- AArch64LowerHomogeneousPE(Module *M, MachineModuleInfo *MMI)
- : M(M), MMI(MMI) {}
- bool run();
- bool runOnMachineFunction(MachineFunction &Fn);
- private:
- Module *M;
- MachineModuleInfo *MMI;
- bool runOnMBB(MachineBasicBlock &MBB);
- bool runOnMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator &NextMBBI);
- /// Lower a HOM_Prolog pseudo instruction into a helper call
- /// or a sequence of homogeneous stores.
- /// When a a fp setup follows, it can be optimized.
- bool lowerProlog(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator &NextMBBI);
- /// Lower a HOM_Epilog pseudo instruction into a helper call
- /// or a sequence of homogeneous loads.
- /// When a return follow, it can be optimized.
- bool lowerEpilog(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator &NextMBBI);
- };
- class AArch64LowerHomogeneousPrologEpilog : public ModulePass {
- public:
- static char ID;
- AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {
- initializeAArch64LowerHomogeneousPrologEpilogPass(
- *PassRegistry::getPassRegistry());
- }
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<MachineModuleInfoWrapperPass>();
- AU.addPreserved<MachineModuleInfoWrapperPass>();
- AU.setPreservesAll();
- ModulePass::getAnalysisUsage(AU);
- }
- bool runOnModule(Module &M) override;
- StringRef getPassName() const override {
- return AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME;
- }
- };
- } // end anonymous namespace
- char AArch64LowerHomogeneousPrologEpilog::ID = 0;
- INITIALIZE_PASS(AArch64LowerHomogeneousPrologEpilog,
- "aarch64-lower-homogeneous-prolog-epilog",
- AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME, false, false)
- bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) {
- if (skipModule(M))
- return false;
- MachineModuleInfo *MMI =
- &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
- return AArch64LowerHomogeneousPE(&M, MMI).run();
- }
- bool AArch64LowerHomogeneousPE::run() {
- bool Changed = false;
- for (auto &F : *M) {
- if (F.empty())
- continue;
- MachineFunction *MF = MMI->getMachineFunction(F);
- if (!MF)
- continue;
- Changed |= runOnMachineFunction(*MF);
- }
- return Changed;
- }
- enum FrameHelperType { Prolog, PrologFrame, Epilog, EpilogTail };
- /// Return a frame helper name with the given CSRs and the helper type.
- /// For instance, a prolog helper that saves x19 and x20 is named as
- /// OUTLINED_FUNCTION_PROLOG_x19x20.
- static std::string getFrameHelperName(SmallVectorImpl<unsigned> &Regs,
- FrameHelperType Type, unsigned FpOffset) {
- std::ostringstream RegStream;
- switch (Type) {
- case FrameHelperType::Prolog:
- RegStream << "OUTLINED_FUNCTION_PROLOG_";
- break;
- case FrameHelperType::PrologFrame:
- RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";
- break;
- case FrameHelperType::Epilog:
- RegStream << "OUTLINED_FUNCTION_EPILOG_";
- break;
- case FrameHelperType::EpilogTail:
- RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";
- break;
- }
- for (auto Reg : Regs)
- RegStream << AArch64InstPrinter::getRegisterName(Reg);
- return RegStream.str();
- }
- /// Create a Function for the unique frame helper with the given name.
- /// Return a newly created MachineFunction with an empty MachineBasicBlock.
- static MachineFunction &createFrameHelperMachineFunction(Module *M,
- MachineModuleInfo *MMI,
- StringRef Name) {
- LLVMContext &C = M->getContext();
- Function *F = M->getFunction(Name);
- assert(F == nullptr && "Function has been created before");
- F = Function::Create(FunctionType::get(Type::getVoidTy(C), false),
- Function::ExternalLinkage, Name, M);
- assert(F && "Function was null!");
- // Use ODR linkage to avoid duplication.
- F->setLinkage(GlobalValue::LinkOnceODRLinkage);
- F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
- // Set no-opt/minsize, so we don't insert padding between outlined
- // functions.
- F->addFnAttr(Attribute::OptimizeNone);
- F->addFnAttr(Attribute::NoInline);
- F->addFnAttr(Attribute::MinSize);
- F->addFnAttr(Attribute::Naked);
- MachineFunction &MF = MMI->getOrCreateMachineFunction(*F);
- // Remove unnecessary register liveness and set NoVRegs.
- MF.getProperties().reset(MachineFunctionProperties::Property::TracksLiveness);
- MF.getProperties().reset(MachineFunctionProperties::Property::IsSSA);
- MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
- MF.getRegInfo().freezeReservedRegs(MF);
- // Create entry block.
- BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
- IRBuilder<> Builder(EntryBB);
- Builder.CreateRetVoid();
- // Insert the new block into the function.
- MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
- MF.insert(MF.begin(), MBB);
- return MF;
- }
- /// Emit a store-pair instruction for frame-setup.
- static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator Pos,
- const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2,
- int Offset, bool IsPreDec) {
- bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
- assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));
- unsigned Opc;
- if (IsPreDec)
- Opc = IsFloat ? AArch64::STPDpre : AArch64::STPXpre;
- else
- Opc = IsFloat ? AArch64::STPDi : AArch64::STPXi;
- MachineInstrBuilder MIB = BuildMI(MBB, Pos, DebugLoc(), TII.get(Opc));
- if (IsPreDec)
- MIB.addDef(AArch64::SP);
- MIB.addReg(Reg2)
- .addReg(Reg1)
- .addReg(AArch64::SP)
- .addImm(Offset)
- .setMIFlag(MachineInstr::FrameSetup);
- }
- /// Emit a load-pair instruction for frame-destroy.
- static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator Pos,
- const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2,
- int Offset, bool IsPostDec) {
- bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
- assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));
- unsigned Opc;
- if (IsPostDec)
- Opc = IsFloat ? AArch64::LDPDpost : AArch64::LDPXpost;
- else
- Opc = IsFloat ? AArch64::LDPDi : AArch64::LDPXi;
- MachineInstrBuilder MIB = BuildMI(MBB, Pos, DebugLoc(), TII.get(Opc));
- if (IsPostDec)
- MIB.addDef(AArch64::SP);
- MIB.addReg(Reg2, getDefRegState(true))
- .addReg(Reg1, getDefRegState(true))
- .addReg(AArch64::SP)
- .addImm(Offset)
- .setMIFlag(MachineInstr::FrameDestroy);
- }
- /// Return a unique function if a helper can be formed with the given Regs
- /// and frame type.
- /// 1) _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22:
- /// stp x22, x21, [sp, #-32]! ; x29/x30 has been stored at the caller
- /// stp x20, x19, [sp, #16]
- /// ret
- ///
- /// 2) _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22:
- /// stp x22, x21, [sp, #-32]! ; x29/x30 has been stored at the caller
- /// stp x20, x19, [sp, #16]
- /// add fp, sp, #32
- /// ret
- ///
- /// 3) _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22:
- /// mov x16, x30
- /// ldp x29, x30, [sp, #32]
- /// ldp x20, x19, [sp, #16]
- /// ldp x22, x21, [sp], #48
- /// ret x16
- ///
- /// 4) _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22:
- /// ldp x29, x30, [sp, #32]
- /// ldp x20, x19, [sp, #16]
- /// ldp x22, x21, [sp], #48
- /// ret
- /// @param M module
- /// @param MMI machine module info
- /// @param Regs callee save regs that the helper will handle
- /// @param Type frame helper type
- /// @return a helper function
- static Function *getOrCreateFrameHelper(Module *M, MachineModuleInfo *MMI,
- SmallVectorImpl<unsigned> &Regs,
- FrameHelperType Type,
- unsigned FpOffset = 0) {
- assert(Regs.size() >= 2);
- auto Name = getFrameHelperName(Regs, Type, FpOffset);
- auto *F = M->getFunction(Name);
- if (F)
- return F;
- auto &MF = createFrameHelperMachineFunction(M, MMI, Name);
- MachineBasicBlock &MBB = *MF.begin();
- const TargetSubtargetInfo &STI = MF.getSubtarget();
- const TargetInstrInfo &TII = *STI.getInstrInfo();
- int Size = (int)Regs.size();
- switch (Type) {
- case FrameHelperType::Prolog:
- case FrameHelperType::PrologFrame: {
- // Compute the remaining SP adjust beyond FP/LR.
- auto LRIdx = std::distance(Regs.begin(), llvm::find(Regs, AArch64::LR));
- // If the register stored to the lowest address is not LR, we must subtract
- // more from SP here.
- if (LRIdx != Size - 2) {
- assert(Regs[Size - 2] != AArch64::LR);
- emitStore(MF, MBB, MBB.end(), TII, Regs[Size - 2], Regs[Size - 1],
- LRIdx - Size + 2, true);
- }
- // Store CSRs in the reverse order.
- for (int I = Size - 3; I >= 0; I -= 2) {
- // FP/LR has been stored at call-site.
- if (Regs[I - 1] == AArch64::LR)
- continue;
- emitStore(MF, MBB, MBB.end(), TII, Regs[I - 1], Regs[I], Size - I - 1,
- false);
- }
- if (Type == FrameHelperType::PrologFrame)
- BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::ADDXri))
- .addDef(AArch64::FP)
- .addUse(AArch64::SP)
- .addImm(FpOffset)
- .addImm(0)
- .setMIFlag(MachineInstr::FrameSetup);
- BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::RET))
- .addReg(AArch64::LR);
- break;
- }
- case FrameHelperType::Epilog:
- case FrameHelperType::EpilogTail:
- if (Type == FrameHelperType::Epilog)
- // Stash LR to X16
- BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::ORRXrs))
- .addDef(AArch64::X16)
- .addReg(AArch64::XZR)
- .addUse(AArch64::LR)
- .addImm(0);
- for (int I = 0; I < Size - 2; I += 2)
- emitLoad(MF, MBB, MBB.end(), TII, Regs[I], Regs[I + 1], Size - I - 2,
- false);
- // Restore the last CSR with post-increment of SP.
- emitLoad(MF, MBB, MBB.end(), TII, Regs[Size - 2], Regs[Size - 1], Size,
- true);
- BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::RET))
- .addReg(Type == FrameHelperType::Epilog ? AArch64::X16 : AArch64::LR);
- break;
- }
- return M->getFunction(Name);
- }
- /// This function checks if a frame helper should be used for
- /// HOM_Prolog/HOM_Epilog pseudo instruction expansion.
- /// @param MBB machine basic block
- /// @param NextMBBI next instruction following HOM_Prolog/HOM_Epilog
- /// @param Regs callee save registers that are saved or restored.
- /// @param Type frame helper type
- /// @return True if a use of helper is qualified.
- static bool shouldUseFrameHelper(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator &NextMBBI,
- SmallVectorImpl<unsigned> &Regs,
- FrameHelperType Type) {
- const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
- auto RegCount = Regs.size();
- assert(RegCount > 0 && (RegCount % 2 == 0));
- // # of instructions that will be outlined.
- int InstCount = RegCount / 2;
- // Do not use a helper call when not saving LR.
- if (!llvm::is_contained(Regs, AArch64::LR))
- return false;
- switch (Type) {
- case FrameHelperType::Prolog:
- // Prolog helper cannot save FP/LR.
- InstCount--;
- break;
- case FrameHelperType::PrologFrame: {
- // Effecitvely no change in InstCount since FpAdjusment is included.
- break;
- }
- case FrameHelperType::Epilog:
- // Bail-out if X16 is live across the epilog helper because it is used in
- // the helper to handle X30.
- for (auto NextMI = NextMBBI; NextMI != MBB.end(); NextMI++) {
- if (NextMI->readsRegister(AArch64::W16, TRI))
- return false;
- }
- // Epilog may not be in the last block. Check the liveness in successors.
- for (const MachineBasicBlock *SuccMBB : MBB.successors()) {
- if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))
- return false;
- }
- // No change in InstCount for the regular epilog case.
- break;
- case FrameHelperType::EpilogTail: {
- // EpilogTail helper includes the caller's return.
- if (NextMBBI == MBB.end())
- return false;
- if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)
- return false;
- InstCount++;
- break;
- }
- }
- return InstCount >= FrameHelperSizeThreshold;
- }
- /// Lower a HOM_Epilog pseudo instruction into a helper call while
- /// creating the helper on demand. Or emit a sequence of loads in place when not
- /// using a helper call.
- ///
- /// 1. With a helper including ret
- /// HOM_Epilog x30, x29, x19, x20, x21, x22 ; MBBI
- /// ret ; NextMBBI
- /// =>
- /// b _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22
- /// ... ; NextMBBI
- ///
- /// 2. With a helper
- /// HOM_Epilog x30, x29, x19, x20, x21, x22
- /// =>
- /// bl _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22
- ///
- /// 3. Without a helper
- /// HOM_Epilog x30, x29, x19, x20, x21, x22
- /// =>
- /// ldp x29, x30, [sp, #32]
- /// ldp x20, x19, [sp, #16]
- /// ldp x22, x21, [sp], #48
- bool AArch64LowerHomogeneousPE::lowerEpilog(
- MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator &NextMBBI) {
- auto &MF = *MBB.getParent();
- MachineInstr &MI = *MBBI;
- DebugLoc DL = MI.getDebugLoc();
- SmallVector<unsigned, 8> Regs;
- for (auto &MO : MI.operands())
- if (MO.isReg())
- Regs.push_back(MO.getReg());
- int Size = (int)Regs.size();
- if (Size == 0)
- return false;
- // Registers are in pair.
- assert(Size % 2 == 0);
- assert(MI.getOpcode() == AArch64::HOM_Epilog);
- auto Return = NextMBBI;
- if (shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::EpilogTail)) {
- // When MBB ends with a return, emit a tail-call to the epilog helper
- auto *EpilogTailHelper =
- getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::EpilogTail);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::TCRETURNdi))
- .addGlobalAddress(EpilogTailHelper)
- .addImm(0)
- .setMIFlag(MachineInstr::FrameDestroy)
- .copyImplicitOps(MI)
- .copyImplicitOps(*Return);
- NextMBBI = std::next(Return);
- Return->removeFromParent();
- } else if (shouldUseFrameHelper(MBB, NextMBBI, Regs,
- FrameHelperType::Epilog)) {
- // The default epilog helper case.
- auto *EpilogHelper =
- getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Epilog);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
- .addGlobalAddress(EpilogHelper)
- .setMIFlag(MachineInstr::FrameDestroy)
- .copyImplicitOps(MI);
- } else {
- // Fall back to no-helper.
- for (int I = 0; I < Size - 2; I += 2)
- emitLoad(MF, MBB, MBBI, *TII, Regs[I], Regs[I + 1], Size - I - 2, false);
- // Restore the last CSR with post-increment of SP.
- emitLoad(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], Size, true);
- }
- MBBI->removeFromParent();
- return true;
- }
- /// Lower a HOM_Prolog pseudo instruction into a helper call while
- /// creating the helper on demand. Or emit a sequence of stores in place when
- /// not using a helper call.
- ///
- /// 1. With a helper including frame-setup
- /// HOM_Prolog x30, x29, x19, x20, x21, x22, 32
- /// =>
- /// stp x29, x30, [sp, #-16]!
- /// bl _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22
- ///
- /// 2. With a helper
- /// HOM_Prolog x30, x29, x19, x20, x21, x22
- /// =>
- /// stp x29, x30, [sp, #-16]!
- /// bl _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22
- ///
- /// 3. Without a helper
- /// HOM_Prolog x30, x29, x19, x20, x21, x22
- /// =>
- /// stp x22, x21, [sp, #-48]!
- /// stp x20, x19, [sp, #16]
- /// stp x29, x30, [sp, #32]
- bool AArch64LowerHomogeneousPE::lowerProlog(
- MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator &NextMBBI) {
- auto &MF = *MBB.getParent();
- MachineInstr &MI = *MBBI;
- DebugLoc DL = MI.getDebugLoc();
- SmallVector<unsigned, 8> Regs;
- int LRIdx = 0;
- std::optional<int> FpOffset;
- for (auto &MO : MI.operands()) {
- if (MO.isReg()) {
- if (MO.getReg() == AArch64::LR)
- LRIdx = Regs.size();
- Regs.push_back(MO.getReg());
- } else if (MO.isImm()) {
- FpOffset = MO.getImm();
- }
- }
- int Size = (int)Regs.size();
- if (Size == 0)
- return false;
- // Allow compact unwind case only for oww.
- assert(Size % 2 == 0);
- assert(MI.getOpcode() == AArch64::HOM_Prolog);
- if (FpOffset &&
- shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::PrologFrame)) {
- // FP/LR is stored at the top of stack before the prolog helper call.
- emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);
- auto *PrologFrameHelper = getOrCreateFrameHelper(
- M, MMI, Regs, FrameHelperType::PrologFrame, *FpOffset);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
- .addGlobalAddress(PrologFrameHelper)
- .setMIFlag(MachineInstr::FrameSetup)
- .copyImplicitOps(MI)
- .addReg(AArch64::FP, RegState::Implicit | RegState::Define)
- .addReg(AArch64::SP, RegState::Implicit);
- } else if (!FpOffset && shouldUseFrameHelper(MBB, NextMBBI, Regs,
- FrameHelperType::Prolog)) {
- // FP/LR is stored at the top of stack before the prolog helper call.
- emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);
- auto *PrologHelper =
- getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Prolog);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
- .addGlobalAddress(PrologHelper)
- .setMIFlag(MachineInstr::FrameSetup)
- .copyImplicitOps(MI);
- } else {
- // Fall back to no-helper.
- emitStore(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], -Size, true);
- for (int I = Size - 3; I >= 0; I -= 2)
- emitStore(MF, MBB, MBBI, *TII, Regs[I - 1], Regs[I], Size - I - 1, false);
- if (FpOffset) {
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri))
- .addDef(AArch64::FP)
- .addUse(AArch64::SP)
- .addImm(*FpOffset)
- .addImm(0)
- .setMIFlag(MachineInstr::FrameSetup);
- }
- }
- MBBI->removeFromParent();
- return true;
- }
- /// Process each machine instruction
- /// @param MBB machine basic block
- /// @param MBBI current instruction iterator
- /// @param NextMBBI next instruction iterator which can be updated
- /// @return True when IR is changed.
- bool AArch64LowerHomogeneousPE::runOnMI(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator &NextMBBI) {
- MachineInstr &MI = *MBBI;
- unsigned Opcode = MI.getOpcode();
- switch (Opcode) {
- default:
- break;
- case AArch64::HOM_Prolog:
- return lowerProlog(MBB, MBBI, NextMBBI);
- case AArch64::HOM_Epilog:
- return lowerEpilog(MBB, MBBI, NextMBBI);
- }
- return false;
- }
- bool AArch64LowerHomogeneousPE::runOnMBB(MachineBasicBlock &MBB) {
- bool Modified = false;
- MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
- while (MBBI != E) {
- MachineBasicBlock::iterator NMBBI = std::next(MBBI);
- Modified |= runOnMI(MBB, MBBI, NMBBI);
- MBBI = NMBBI;
- }
- return Modified;
- }
- bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) {
- TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
- bool Modified = false;
- for (auto &MBB : MF)
- Modified |= runOnMBB(MBB);
- return Modified;
- }
- ModulePass *llvm::createAArch64LowerHomogeneousPrologEpilogPass() {
- return new AArch64LowerHomogeneousPrologEpilog();
- }
|