Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64LowerHomogeneousPrologEpilog.cpp
35266 views
//===- AArch64LowerHomogeneousPrologEpilog.cpp ----------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains a pass that lowers homogeneous prolog/epilog instructions.9//10//===----------------------------------------------------------------------===//1112#include "AArch64InstrInfo.h"13#include "AArch64Subtarget.h"14#include "MCTargetDesc/AArch64InstPrinter.h"15#include "Utils/AArch64BaseInfo.h"16#include "llvm/CodeGen/MachineBasicBlock.h"17#include "llvm/CodeGen/MachineFunction.h"18#include "llvm/CodeGen/MachineFunctionPass.h"19#include "llvm/CodeGen/MachineInstr.h"20#include "llvm/CodeGen/MachineInstrBuilder.h"21#include "llvm/CodeGen/MachineModuleInfo.h"22#include "llvm/CodeGen/MachineOperand.h"23#include "llvm/CodeGen/TargetSubtargetInfo.h"24#include "llvm/IR/DebugLoc.h"25#include "llvm/IR/IRBuilder.h"26#include "llvm/IR/Module.h"27#include "llvm/Pass.h"28#include "llvm/Support/raw_ostream.h"29#include <optional>30#include <sstream>3132using namespace llvm;3334#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME \35"AArch64 homogeneous prolog/epilog lowering pass"3637cl::opt<int> FrameHelperSizeThreshold(38"frame-helper-size-threshold", cl::init(2), cl::Hidden,39cl::desc("The minimum number of instructions that are outlined in a frame "40"helper (default = 2)"));4142namespace {4344class AArch64LowerHomogeneousPE {45public:46const AArch64InstrInfo *TII;4748AArch64LowerHomogeneousPE(Module *M, MachineModuleInfo *MMI)49: M(M), MMI(MMI) {}5051bool run();52bool runOnMachineFunction(MachineFunction &Fn);5354private:55Module *M;56MachineModuleInfo *MMI;5758bool runOnMBB(MachineBasicBlock &MBB);59bool runOnMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,60MachineBasicBlock::iterator &NextMBBI);6162/// Lower a HOM_Prolog pseudo instruction into a helper call63/// or a sequence of homogeneous stores.64/// When a fp setup follows, it can be optimized.65bool lowerProlog(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,66MachineBasicBlock::iterator &NextMBBI);67/// Lower a HOM_Epilog pseudo instruction into a helper call68/// or a sequence of homogeneous loads.69/// When a return follow, it can be optimized.70bool lowerEpilog(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,71MachineBasicBlock::iterator &NextMBBI);72};7374class AArch64LowerHomogeneousPrologEpilog : public ModulePass {75public:76static char ID;7778AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {79initializeAArch64LowerHomogeneousPrologEpilogPass(80*PassRegistry::getPassRegistry());81}82void getAnalysisUsage(AnalysisUsage &AU) const override {83AU.addRequired<MachineModuleInfoWrapperPass>();84AU.addPreserved<MachineModuleInfoWrapperPass>();85AU.setPreservesAll();86ModulePass::getAnalysisUsage(AU);87}88bool runOnModule(Module &M) override;8990StringRef getPassName() const override {91return AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME;92}93};9495} // end anonymous namespace9697char AArch64LowerHomogeneousPrologEpilog::ID = 0;9899INITIALIZE_PASS(AArch64LowerHomogeneousPrologEpilog,100"aarch64-lower-homogeneous-prolog-epilog",101AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME, false, false)102103bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) {104if (skipModule(M))105return false;106107MachineModuleInfo *MMI =108&getAnalysis<MachineModuleInfoWrapperPass>().getMMI();109return AArch64LowerHomogeneousPE(&M, MMI).run();110}111112bool AArch64LowerHomogeneousPE::run() {113bool Changed = false;114for (auto &F : *M) {115if (F.empty())116continue;117118MachineFunction *MF = MMI->getMachineFunction(F);119if (!MF)120continue;121Changed |= runOnMachineFunction(*MF);122}123124return Changed;125}126enum FrameHelperType { Prolog, PrologFrame, Epilog, EpilogTail };127128/// Return a frame helper name with the given CSRs and the helper type.129/// For instance, a prolog helper that saves x19 and x20 is named as130/// OUTLINED_FUNCTION_PROLOG_x19x20.131static std::string getFrameHelperName(SmallVectorImpl<unsigned> &Regs,132FrameHelperType Type, unsigned FpOffset) {133std::ostringstream RegStream;134switch (Type) {135case FrameHelperType::Prolog:136RegStream << "OUTLINED_FUNCTION_PROLOG_";137break;138case FrameHelperType::PrologFrame:139RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";140break;141case FrameHelperType::Epilog:142RegStream << "OUTLINED_FUNCTION_EPILOG_";143break;144case FrameHelperType::EpilogTail:145RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";146break;147}148149for (auto Reg : Regs) {150if (Reg == AArch64::NoRegister)151continue;152RegStream << AArch64InstPrinter::getRegisterName(Reg);153}154155return RegStream.str();156}157158/// Create a Function for the unique frame helper with the given name.159/// Return a newly created MachineFunction with an empty MachineBasicBlock.160static MachineFunction &createFrameHelperMachineFunction(Module *M,161MachineModuleInfo *MMI,162StringRef Name) {163LLVMContext &C = M->getContext();164Function *F = M->getFunction(Name);165assert(F == nullptr && "Function has been created before");166F = Function::Create(FunctionType::get(Type::getVoidTy(C), false),167Function::ExternalLinkage, Name, M);168assert(F && "Function was null!");169170// Use ODR linkage to avoid duplication.171F->setLinkage(GlobalValue::LinkOnceODRLinkage);172F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);173174// Set no-opt/minsize, so we don't insert padding between outlined175// functions.176F->addFnAttr(Attribute::OptimizeNone);177F->addFnAttr(Attribute::NoInline);178F->addFnAttr(Attribute::MinSize);179F->addFnAttr(Attribute::Naked);180181MachineFunction &MF = MMI->getOrCreateMachineFunction(*F);182// Remove unnecessary register liveness and set NoVRegs.183MF.getProperties().reset(MachineFunctionProperties::Property::TracksLiveness);184MF.getProperties().reset(MachineFunctionProperties::Property::IsSSA);185MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);186MF.getRegInfo().freezeReservedRegs();187188// Create entry block.189BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);190IRBuilder<> Builder(EntryBB);191Builder.CreateRetVoid();192193// Insert the new block into the function.194MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();195MF.insert(MF.begin(), MBB);196197return MF;198}199200/// Emit a store-pair instruction for frame-setup.201/// If Reg2 is AArch64::NoRegister, emit STR instead.202static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB,203MachineBasicBlock::iterator Pos,204const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2,205int Offset, bool IsPreDec) {206assert(Reg1 != AArch64::NoRegister);207const bool IsPaired = Reg2 != AArch64::NoRegister;208bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);209assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));210unsigned Opc;211if (IsPreDec) {212if (IsFloat)213Opc = IsPaired ? AArch64::STPDpre : AArch64::STRDpre;214else215Opc = IsPaired ? AArch64::STPXpre : AArch64::STRXpre;216} else {217if (IsFloat)218Opc = IsPaired ? AArch64::STPDi : AArch64::STRDui;219else220Opc = IsPaired ? AArch64::STPXi : AArch64::STRXui;221}222// The implicit scale for Offset is 8.223TypeSize Scale(0U, false), Width(0U, false);224int64_t MinOffset, MaxOffset;225[[maybe_unused]] bool Success =226AArch64InstrInfo::getMemOpInfo(Opc, Scale, Width, MinOffset, MaxOffset);227assert(Success && "Invalid Opcode");228Offset *= (8 / (int)Scale);229230MachineInstrBuilder MIB = BuildMI(MBB, Pos, DebugLoc(), TII.get(Opc));231if (IsPreDec)232MIB.addDef(AArch64::SP);233if (IsPaired)234MIB.addReg(Reg2);235MIB.addReg(Reg1)236.addReg(AArch64::SP)237.addImm(Offset)238.setMIFlag(MachineInstr::FrameSetup);239}240241/// Emit a load-pair instruction for frame-destroy.242/// If Reg2 is AArch64::NoRegister, emit LDR instead.243static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB,244MachineBasicBlock::iterator Pos,245const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2,246int Offset, bool IsPostDec) {247assert(Reg1 != AArch64::NoRegister);248const bool IsPaired = Reg2 != AArch64::NoRegister;249bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);250assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));251unsigned Opc;252if (IsPostDec) {253if (IsFloat)254Opc = IsPaired ? AArch64::LDPDpost : AArch64::LDRDpost;255else256Opc = IsPaired ? AArch64::LDPXpost : AArch64::LDRXpost;257} else {258if (IsFloat)259Opc = IsPaired ? AArch64::LDPDi : AArch64::LDRDui;260else261Opc = IsPaired ? AArch64::LDPXi : AArch64::LDRXui;262}263// The implicit scale for Offset is 8.264TypeSize Scale(0U, false), Width(0U, false);265int64_t MinOffset, MaxOffset;266[[maybe_unused]] bool Success =267AArch64InstrInfo::getMemOpInfo(Opc, Scale, Width, MinOffset, MaxOffset);268assert(Success && "Invalid Opcode");269Offset *= (8 / (int)Scale);270271MachineInstrBuilder MIB = BuildMI(MBB, Pos, DebugLoc(), TII.get(Opc));272if (IsPostDec)273MIB.addDef(AArch64::SP);274if (IsPaired)275MIB.addReg(Reg2, getDefRegState(true));276MIB.addReg(Reg1, getDefRegState(true))277.addReg(AArch64::SP)278.addImm(Offset)279.setMIFlag(MachineInstr::FrameDestroy);280}281282/// Return a unique function if a helper can be formed with the given Regs283/// and frame type.284/// 1) _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22:285/// stp x22, x21, [sp, #-32]! ; x29/x30 has been stored at the caller286/// stp x20, x19, [sp, #16]287/// ret288///289/// 2) _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22:290/// stp x22, x21, [sp, #-32]! ; x29/x30 has been stored at the caller291/// stp x20, x19, [sp, #16]292/// add fp, sp, #32293/// ret294///295/// 3) _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22:296/// mov x16, x30297/// ldp x29, x30, [sp, #32]298/// ldp x20, x19, [sp, #16]299/// ldp x22, x21, [sp], #48300/// ret x16301///302/// 4) _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22:303/// ldp x29, x30, [sp, #32]304/// ldp x20, x19, [sp, #16]305/// ldp x22, x21, [sp], #48306/// ret307/// @param M module308/// @param MMI machine module info309/// @param Regs callee save regs that the helper will handle310/// @param Type frame helper type311/// @return a helper function312static Function *getOrCreateFrameHelper(Module *M, MachineModuleInfo *MMI,313SmallVectorImpl<unsigned> &Regs,314FrameHelperType Type,315unsigned FpOffset = 0) {316assert(Regs.size() >= 2);317auto Name = getFrameHelperName(Regs, Type, FpOffset);318auto *F = M->getFunction(Name);319if (F)320return F;321322auto &MF = createFrameHelperMachineFunction(M, MMI, Name);323MachineBasicBlock &MBB = *MF.begin();324const TargetSubtargetInfo &STI = MF.getSubtarget();325const TargetInstrInfo &TII = *STI.getInstrInfo();326327int Size = (int)Regs.size();328switch (Type) {329case FrameHelperType::Prolog:330case FrameHelperType::PrologFrame: {331// Compute the remaining SP adjust beyond FP/LR.332auto LRIdx = std::distance(Regs.begin(), llvm::find(Regs, AArch64::LR));333334// If the register stored to the lowest address is not LR, we must subtract335// more from SP here.336if (LRIdx != Size - 2) {337assert(Regs[Size - 2] != AArch64::LR);338emitStore(MF, MBB, MBB.end(), TII, Regs[Size - 2], Regs[Size - 1],339LRIdx - Size + 2, true);340}341342// Store CSRs in the reverse order.343for (int I = Size - 3; I >= 0; I -= 2) {344// FP/LR has been stored at call-site.345if (Regs[I - 1] == AArch64::LR)346continue;347emitStore(MF, MBB, MBB.end(), TII, Regs[I - 1], Regs[I], Size - I - 1,348false);349}350if (Type == FrameHelperType::PrologFrame)351BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::ADDXri))352.addDef(AArch64::FP)353.addUse(AArch64::SP)354.addImm(FpOffset)355.addImm(0)356.setMIFlag(MachineInstr::FrameSetup);357358BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::RET))359.addReg(AArch64::LR);360break;361}362case FrameHelperType::Epilog:363case FrameHelperType::EpilogTail:364if (Type == FrameHelperType::Epilog)365// Stash LR to X16366BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::ORRXrs))367.addDef(AArch64::X16)368.addReg(AArch64::XZR)369.addUse(AArch64::LR)370.addImm(0);371372for (int I = 0; I < Size - 2; I += 2)373emitLoad(MF, MBB, MBB.end(), TII, Regs[I], Regs[I + 1], Size - I - 2,374false);375// Restore the last CSR with post-increment of SP.376emitLoad(MF, MBB, MBB.end(), TII, Regs[Size - 2], Regs[Size - 1], Size,377true);378379BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::RET))380.addReg(Type == FrameHelperType::Epilog ? AArch64::X16 : AArch64::LR);381break;382}383384return M->getFunction(Name);385}386387/// This function checks if a frame helper should be used for388/// HOM_Prolog/HOM_Epilog pseudo instruction expansion.389/// @param MBB machine basic block390/// @param NextMBBI next instruction following HOM_Prolog/HOM_Epilog391/// @param Regs callee save registers that are saved or restored.392/// @param Type frame helper type393/// @return True if a use of helper is qualified.394static bool shouldUseFrameHelper(MachineBasicBlock &MBB,395MachineBasicBlock::iterator &NextMBBI,396SmallVectorImpl<unsigned> &Regs,397FrameHelperType Type) {398const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();399auto RegCount = Regs.size();400assert(RegCount > 0 && (RegCount % 2 == 0));401// # of instructions that will be outlined.402int InstCount = RegCount / 2;403404// Do not use a helper call when not saving LR.405if (!llvm::is_contained(Regs, AArch64::LR))406return false;407408switch (Type) {409case FrameHelperType::Prolog:410// Prolog helper cannot save FP/LR.411InstCount--;412break;413case FrameHelperType::PrologFrame: {414// Effecitvely no change in InstCount since FpAdjusment is included.415break;416}417case FrameHelperType::Epilog:418// Bail-out if X16 is live across the epilog helper because it is used in419// the helper to handle X30.420for (auto NextMI = NextMBBI; NextMI != MBB.end(); NextMI++) {421if (NextMI->readsRegister(AArch64::W16, TRI))422return false;423}424// Epilog may not be in the last block. Check the liveness in successors.425for (const MachineBasicBlock *SuccMBB : MBB.successors()) {426if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))427return false;428}429// No change in InstCount for the regular epilog case.430break;431case FrameHelperType::EpilogTail: {432// EpilogTail helper includes the caller's return.433if (NextMBBI == MBB.end())434return false;435if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)436return false;437InstCount++;438break;439}440}441442return InstCount >= FrameHelperSizeThreshold;443}444445/// Lower a HOM_Epilog pseudo instruction into a helper call while446/// creating the helper on demand. Or emit a sequence of loads in place when not447/// using a helper call.448///449/// 1. With a helper including ret450/// HOM_Epilog x30, x29, x19, x20, x21, x22 ; MBBI451/// ret ; NextMBBI452/// =>453/// b _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22454/// ... ; NextMBBI455///456/// 2. With a helper457/// HOM_Epilog x30, x29, x19, x20, x21, x22458/// =>459/// bl _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22460///461/// 3. Without a helper462/// HOM_Epilog x30, x29, x19, x20, x21, x22463/// =>464/// ldp x29, x30, [sp, #32]465/// ldp x20, x19, [sp, #16]466/// ldp x22, x21, [sp], #48467bool AArch64LowerHomogeneousPE::lowerEpilog(468MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,469MachineBasicBlock::iterator &NextMBBI) {470auto &MF = *MBB.getParent();471MachineInstr &MI = *MBBI;472473DebugLoc DL = MI.getDebugLoc();474SmallVector<unsigned, 8> Regs;475bool HasUnpairedReg = false;476for (auto &MO : MI.operands())477if (MO.isReg()) {478if (!MO.getReg().isValid()) {479// For now we are only expecting unpaired GP registers which should480// occur exactly once.481assert(!HasUnpairedReg);482HasUnpairedReg = true;483}484Regs.push_back(MO.getReg());485}486(void)HasUnpairedReg;487int Size = (int)Regs.size();488if (Size == 0)489return false;490// Registers are in pair.491assert(Size % 2 == 0);492assert(MI.getOpcode() == AArch64::HOM_Epilog);493494auto Return = NextMBBI;495if (shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::EpilogTail)) {496// When MBB ends with a return, emit a tail-call to the epilog helper497auto *EpilogTailHelper =498getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::EpilogTail);499BuildMI(MBB, MBBI, DL, TII->get(AArch64::TCRETURNdi))500.addGlobalAddress(EpilogTailHelper)501.addImm(0)502.setMIFlag(MachineInstr::FrameDestroy)503.copyImplicitOps(MI)504.copyImplicitOps(*Return);505NextMBBI = std::next(Return);506Return->removeFromParent();507} else if (shouldUseFrameHelper(MBB, NextMBBI, Regs,508FrameHelperType::Epilog)) {509// The default epilog helper case.510auto *EpilogHelper =511getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Epilog);512BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))513.addGlobalAddress(EpilogHelper)514.setMIFlag(MachineInstr::FrameDestroy)515.copyImplicitOps(MI);516} else {517// Fall back to no-helper.518for (int I = 0; I < Size - 2; I += 2)519emitLoad(MF, MBB, MBBI, *TII, Regs[I], Regs[I + 1], Size - I - 2, false);520// Restore the last CSR with post-increment of SP.521emitLoad(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], Size, true);522}523524MBBI->removeFromParent();525return true;526}527528/// Lower a HOM_Prolog pseudo instruction into a helper call while529/// creating the helper on demand. Or emit a sequence of stores in place when530/// not using a helper call.531///532/// 1. With a helper including frame-setup533/// HOM_Prolog x30, x29, x19, x20, x21, x22, 32534/// =>535/// stp x29, x30, [sp, #-16]!536/// bl _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22537///538/// 2. With a helper539/// HOM_Prolog x30, x29, x19, x20, x21, x22540/// =>541/// stp x29, x30, [sp, #-16]!542/// bl _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22543///544/// 3. Without a helper545/// HOM_Prolog x30, x29, x19, x20, x21, x22546/// =>547/// stp x22, x21, [sp, #-48]!548/// stp x20, x19, [sp, #16]549/// stp x29, x30, [sp, #32]550bool AArch64LowerHomogeneousPE::lowerProlog(551MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,552MachineBasicBlock::iterator &NextMBBI) {553auto &MF = *MBB.getParent();554MachineInstr &MI = *MBBI;555556DebugLoc DL = MI.getDebugLoc();557SmallVector<unsigned, 8> Regs;558bool HasUnpairedReg = false;559int LRIdx = 0;560std::optional<int> FpOffset;561for (auto &MO : MI.operands()) {562if (MO.isReg()) {563if (MO.getReg().isValid()) {564if (MO.getReg() == AArch64::LR)565LRIdx = Regs.size();566} else {567// For now we are only expecting unpaired GP registers which should568// occur exactly once.569assert(!HasUnpairedReg);570HasUnpairedReg = true;571}572Regs.push_back(MO.getReg());573} else if (MO.isImm()) {574FpOffset = MO.getImm();575}576}577(void)HasUnpairedReg;578int Size = (int)Regs.size();579if (Size == 0)580return false;581// Allow compact unwind case only for oww.582assert(Size % 2 == 0);583assert(MI.getOpcode() == AArch64::HOM_Prolog);584585if (FpOffset &&586shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::PrologFrame)) {587// FP/LR is stored at the top of stack before the prolog helper call.588emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);589auto *PrologFrameHelper = getOrCreateFrameHelper(590M, MMI, Regs, FrameHelperType::PrologFrame, *FpOffset);591BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))592.addGlobalAddress(PrologFrameHelper)593.setMIFlag(MachineInstr::FrameSetup)594.copyImplicitOps(MI)595.addReg(AArch64::FP, RegState::Implicit | RegState::Define)596.addReg(AArch64::SP, RegState::Implicit);597} else if (!FpOffset && shouldUseFrameHelper(MBB, NextMBBI, Regs,598FrameHelperType::Prolog)) {599// FP/LR is stored at the top of stack before the prolog helper call.600emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);601auto *PrologHelper =602getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Prolog);603BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))604.addGlobalAddress(PrologHelper)605.setMIFlag(MachineInstr::FrameSetup)606.copyImplicitOps(MI);607} else {608// Fall back to no-helper.609emitStore(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], -Size, true);610for (int I = Size - 3; I >= 0; I -= 2)611emitStore(MF, MBB, MBBI, *TII, Regs[I - 1], Regs[I], Size - I - 1, false);612if (FpOffset) {613BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri))614.addDef(AArch64::FP)615.addUse(AArch64::SP)616.addImm(*FpOffset)617.addImm(0)618.setMIFlag(MachineInstr::FrameSetup);619}620}621622MBBI->removeFromParent();623return true;624}625626/// Process each machine instruction627/// @param MBB machine basic block628/// @param MBBI current instruction iterator629/// @param NextMBBI next instruction iterator which can be updated630/// @return True when IR is changed.631bool AArch64LowerHomogeneousPE::runOnMI(MachineBasicBlock &MBB,632MachineBasicBlock::iterator MBBI,633MachineBasicBlock::iterator &NextMBBI) {634MachineInstr &MI = *MBBI;635unsigned Opcode = MI.getOpcode();636switch (Opcode) {637default:638break;639case AArch64::HOM_Prolog:640return lowerProlog(MBB, MBBI, NextMBBI);641case AArch64::HOM_Epilog:642return lowerEpilog(MBB, MBBI, NextMBBI);643}644return false;645}646647bool AArch64LowerHomogeneousPE::runOnMBB(MachineBasicBlock &MBB) {648bool Modified = false;649650MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();651while (MBBI != E) {652MachineBasicBlock::iterator NMBBI = std::next(MBBI);653Modified |= runOnMI(MBB, MBBI, NMBBI);654MBBI = NMBBI;655}656657return Modified;658}659660bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) {661TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());662663bool Modified = false;664for (auto &MBB : MF)665Modified |= runOnMBB(MBB);666return Modified;667}668669ModulePass *llvm::createAArch64LowerHomogeneousPrologEpilogPass() {670return new AArch64LowerHomogeneousPrologEpilog();671}672673674