brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.5 KiB · 03dd1cd Raw
663 lines · cpp
1//===- AArch64LowerHomogeneousPrologEpilog.cpp ----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains a pass that lowers homogeneous prolog/epilog instructions.10//11//===----------------------------------------------------------------------===//12 13#include "AArch64InstrInfo.h"14#include "AArch64Subtarget.h"15#include "MCTargetDesc/AArch64InstPrinter.h"16#include "llvm/CodeGen/MachineBasicBlock.h"17#include "llvm/CodeGen/MachineFunction.h"18#include "llvm/CodeGen/MachineInstr.h"19#include "llvm/CodeGen/MachineInstrBuilder.h"20#include "llvm/CodeGen/MachineModuleInfo.h"21#include "llvm/CodeGen/MachineOperand.h"22#include "llvm/CodeGen/TargetSubtargetInfo.h"23#include "llvm/IR/DebugLoc.h"24#include "llvm/IR/IRBuilder.h"25#include "llvm/IR/Module.h"26#include "llvm/Pass.h"27#include <optional>28#include <sstream>29 30using namespace llvm;31 32#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME                           \33  "AArch64 homogeneous prolog/epilog lowering pass"34 35static cl::opt<int> FrameHelperSizeThreshold(36    "frame-helper-size-threshold", cl::init(2), cl::Hidden,37    cl::desc("The minimum number of instructions that are outlined in a frame "38             "helper (default = 2)"));39 40namespace {41 42class AArch64LowerHomogeneousPE {43public:44  const AArch64InstrInfo *TII;45 46  AArch64LowerHomogeneousPE(Module *M, MachineModuleInfo *MMI)47      : M(M), MMI(MMI) {}48 49  bool run();50  bool runOnMachineFunction(MachineFunction &Fn);51 52private:53  Module *M;54  MachineModuleInfo *MMI;55 56  bool runOnMBB(MachineBasicBlock &MBB);57  bool runOnMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,58               MachineBasicBlock::iterator &NextMBBI);59 60  /// Lower a HOM_Prolog pseudo instruction into a helper call61  /// or a sequence of homogeneous stores.62  /// When a fp setup follows, it can be optimized.63  bool lowerProlog(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,64                   MachineBasicBlock::iterator &NextMBBI);65  /// Lower a HOM_Epilog pseudo instruction into a helper call66  /// or a sequence of homogeneous loads.67  /// When a return follow, it can be optimized.68  bool lowerEpilog(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,69                   MachineBasicBlock::iterator &NextMBBI);70};71 72class AArch64LowerHomogeneousPrologEpilog : public ModulePass {73public:74  static char ID;75 76  AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {}77  void getAnalysisUsage(AnalysisUsage &AU) const override {78    AU.addRequired<MachineModuleInfoWrapperPass>();79    AU.addPreserved<MachineModuleInfoWrapperPass>();80    AU.setPreservesAll();81    ModulePass::getAnalysisUsage(AU);82  }83  bool runOnModule(Module &M) override;84 85  StringRef getPassName() const override {86    return AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME;87  }88};89 90} // end anonymous namespace91 92char AArch64LowerHomogeneousPrologEpilog::ID = 0;93 94INITIALIZE_PASS(AArch64LowerHomogeneousPrologEpilog,95                "aarch64-lower-homogeneous-prolog-epilog",96                AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME, false, false)97 98bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) {99  if (skipModule(M))100    return false;101 102  MachineModuleInfo *MMI =103      &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();104  return AArch64LowerHomogeneousPE(&M, MMI).run();105}106 107bool AArch64LowerHomogeneousPE::run() {108  bool Changed = false;109  for (auto &F : *M) {110    if (F.empty())111      continue;112 113    MachineFunction *MF = MMI->getMachineFunction(F);114    if (!MF)115      continue;116    Changed |= runOnMachineFunction(*MF);117  }118 119  return Changed;120}121enum FrameHelperType { Prolog, PrologFrame, Epilog, EpilogTail };122 123/// Return a frame helper name with the given CSRs and the helper type.124/// For instance, a prolog helper that saves x19 and x20 is named as125/// OUTLINED_FUNCTION_PROLOG_x19x20.126static std::string getFrameHelperName(SmallVectorImpl<unsigned> &Regs,127                                      FrameHelperType Type, unsigned FpOffset) {128  std::ostringstream RegStream;129  switch (Type) {130  case FrameHelperType::Prolog:131    RegStream << "OUTLINED_FUNCTION_PROLOG_";132    break;133  case FrameHelperType::PrologFrame:134    RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";135    break;136  case FrameHelperType::Epilog:137    RegStream << "OUTLINED_FUNCTION_EPILOG_";138    break;139  case FrameHelperType::EpilogTail:140    RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";141    break;142  }143 144  for (auto Reg : Regs) {145    if (Reg == AArch64::NoRegister)146      continue;147    RegStream << AArch64InstPrinter::getRegisterName(Reg);148  }149 150  return RegStream.str();151}152 153/// Create a Function for the unique frame helper with the given name.154/// Return a newly created MachineFunction with an empty MachineBasicBlock.155static MachineFunction &createFrameHelperMachineFunction(Module *M,156                                                         MachineModuleInfo *MMI,157                                                         StringRef Name) {158  LLVMContext &C = M->getContext();159  Function *F = M->getFunction(Name);160  assert(F == nullptr && "Function has been created before");161  F = Function::Create(FunctionType::get(Type::getVoidTy(C), false),162                       Function::ExternalLinkage, Name, M);163  assert(F && "Function was null!");164 165  // Use ODR linkage to avoid duplication.166  F->setLinkage(GlobalValue::LinkOnceODRLinkage);167  F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);168 169  // Set minsize, so we don't insert padding between outlined functions.170  F->addFnAttr(Attribute::NoInline);171  F->addFnAttr(Attribute::MinSize);172  F->addFnAttr(Attribute::Naked);173 174  MachineFunction &MF = MMI->getOrCreateMachineFunction(*F);175  // Remove unnecessary register liveness and set NoVRegs.176  MF.getProperties().resetTracksLiveness().resetIsSSA().setNoVRegs();177  MF.getRegInfo().freezeReservedRegs();178 179  // Create entry block.180  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);181  IRBuilder<> Builder(EntryBB);182  Builder.CreateRetVoid();183 184  // Insert the new block into the function.185  MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();186  MF.insert(MF.begin(), MBB);187 188  return MF;189}190 191/// Emit a store-pair instruction for frame-setup.192/// If Reg2 is AArch64::NoRegister, emit STR instead.193static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB,194                      MachineBasicBlock::iterator Pos,195                      const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2,196                      int Offset, bool IsPreDec) {197  assert(Reg1 != AArch64::NoRegister);198  const bool IsPaired = Reg2 != AArch64::NoRegister;199  bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);200  assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));201  unsigned Opc;202  if (IsPreDec) {203    if (IsFloat)204      Opc = IsPaired ? AArch64::STPDpre : AArch64::STRDpre;205    else206      Opc = IsPaired ? AArch64::STPXpre : AArch64::STRXpre;207  } else {208    if (IsFloat)209      Opc = IsPaired ? AArch64::STPDi : AArch64::STRDui;210    else211      Opc = IsPaired ? AArch64::STPXi : AArch64::STRXui;212  }213  // The implicit scale for Offset is 8.214  TypeSize Scale(0U, false), Width(0U, false);215  int64_t MinOffset, MaxOffset;216  [[maybe_unused]] bool Success =217      AArch64InstrInfo::getMemOpInfo(Opc, Scale, Width, MinOffset, MaxOffset);218  assert(Success && "Invalid Opcode");219  Offset *= (8 / (int)Scale);220 221  MachineInstrBuilder MIB = BuildMI(MBB, Pos, DebugLoc(), TII.get(Opc));222  if (IsPreDec)223    MIB.addDef(AArch64::SP);224  if (IsPaired)225    MIB.addReg(Reg2);226  MIB.addReg(Reg1)227      .addReg(AArch64::SP)228      .addImm(Offset)229      .setMIFlag(MachineInstr::FrameSetup);230}231 232/// Emit a load-pair instruction for frame-destroy.233/// If Reg2 is AArch64::NoRegister, emit LDR instead.234static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB,235                     MachineBasicBlock::iterator Pos,236                     const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2,237                     int Offset, bool IsPostDec) {238  assert(Reg1 != AArch64::NoRegister);239  const bool IsPaired = Reg2 != AArch64::NoRegister;240  bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);241  assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));242  unsigned Opc;243  if (IsPostDec) {244    if (IsFloat)245      Opc = IsPaired ? AArch64::LDPDpost : AArch64::LDRDpost;246    else247      Opc = IsPaired ? AArch64::LDPXpost : AArch64::LDRXpost;248  } else {249    if (IsFloat)250      Opc = IsPaired ? AArch64::LDPDi : AArch64::LDRDui;251    else252      Opc = IsPaired ? AArch64::LDPXi : AArch64::LDRXui;253  }254  // The implicit scale for Offset is 8.255  TypeSize Scale(0U, false), Width(0U, false);256  int64_t MinOffset, MaxOffset;257  [[maybe_unused]] bool Success =258      AArch64InstrInfo::getMemOpInfo(Opc, Scale, Width, MinOffset, MaxOffset);259  assert(Success && "Invalid Opcode");260  Offset *= (8 / (int)Scale);261 262  MachineInstrBuilder MIB = BuildMI(MBB, Pos, DebugLoc(), TII.get(Opc));263  if (IsPostDec)264    MIB.addDef(AArch64::SP);265  if (IsPaired)266    MIB.addReg(Reg2, getDefRegState(true));267  MIB.addReg(Reg1, getDefRegState(true))268      .addReg(AArch64::SP)269      .addImm(Offset)270      .setMIFlag(MachineInstr::FrameDestroy);271}272 273/// Return a unique function if a helper can be formed with the given Regs274/// and frame type.275/// 1) _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22:276///    stp x22, x21, [sp, #-32]!    ; x29/x30 has been stored at the caller277///    stp x20, x19, [sp, #16]278///    ret279///280/// 2) _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22:281///    stp x22, x21, [sp, #-32]!    ; x29/x30 has been stored at the caller282///    stp x20, x19, [sp, #16]283///    add fp, sp, #32284///    ret285///286/// 3) _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22:287///    mov x16, x30288///    ldp x29, x30, [sp, #32]289///    ldp x20, x19, [sp, #16]290///    ldp x22, x21, [sp], #48291///    ret x16292///293/// 4) _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22:294///    ldp x29, x30, [sp, #32]295///    ldp x20, x19, [sp, #16]296///    ldp x22, x21, [sp], #48297///    ret298/// @param M module299/// @param MMI machine module info300/// @param Regs callee save regs that the helper will handle301/// @param Type frame helper type302/// @return a helper function303static Function *getOrCreateFrameHelper(Module *M, MachineModuleInfo *MMI,304                                        SmallVectorImpl<unsigned> &Regs,305                                        FrameHelperType Type,306                                        unsigned FpOffset = 0) {307  assert(Regs.size() >= 2);308  auto Name = getFrameHelperName(Regs, Type, FpOffset);309  auto *F = M->getFunction(Name);310  if (F)311    return F;312 313  auto &MF = createFrameHelperMachineFunction(M, MMI, Name);314  MachineBasicBlock &MBB = *MF.begin();315  const TargetSubtargetInfo &STI = MF.getSubtarget();316  const TargetInstrInfo &TII = *STI.getInstrInfo();317 318  int Size = (int)Regs.size();319  switch (Type) {320  case FrameHelperType::Prolog:321  case FrameHelperType::PrologFrame: {322    // Compute the remaining SP adjust beyond FP/LR.323    auto LRIdx = std::distance(Regs.begin(), llvm::find(Regs, AArch64::LR));324 325    // If the register stored to the lowest address is not LR, we must subtract326    // more from SP here.327    if (LRIdx != Size - 2) {328      assert(Regs[Size - 2] != AArch64::LR);329      emitStore(MF, MBB, MBB.end(), TII, Regs[Size - 2], Regs[Size - 1],330                LRIdx - Size + 2, true);331    }332 333    // Store CSRs in the reverse order.334    for (int I = Size - 3; I >= 0; I -= 2) {335      // FP/LR has been stored at call-site.336      if (Regs[I - 1] == AArch64::LR)337        continue;338      emitStore(MF, MBB, MBB.end(), TII, Regs[I - 1], Regs[I], Size - I - 1,339                false);340    }341    if (Type == FrameHelperType::PrologFrame)342      BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::ADDXri))343          .addDef(AArch64::FP)344          .addUse(AArch64::SP)345          .addImm(FpOffset)346          .addImm(0)347          .setMIFlag(MachineInstr::FrameSetup);348 349    BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::RET))350        .addReg(AArch64::LR);351    break;352  }353  case FrameHelperType::Epilog:354  case FrameHelperType::EpilogTail:355    if (Type == FrameHelperType::Epilog)356      // Stash LR to X16357      BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::ORRXrs))358          .addDef(AArch64::X16)359          .addReg(AArch64::XZR)360          .addUse(AArch64::LR)361          .addImm(0);362 363    for (int I = 0; I < Size - 2; I += 2)364      emitLoad(MF, MBB, MBB.end(), TII, Regs[I], Regs[I + 1], Size - I - 2,365               false);366    // Restore the last CSR with post-increment of SP.367    emitLoad(MF, MBB, MBB.end(), TII, Regs[Size - 2], Regs[Size - 1], Size,368             true);369 370    BuildMI(MBB, MBB.end(), DebugLoc(), TII.get(AArch64::RET))371        .addReg(Type == FrameHelperType::Epilog ? AArch64::X16 : AArch64::LR);372    break;373  }374 375  return M->getFunction(Name);376}377 378/// This function checks if a frame helper should be used for379/// HOM_Prolog/HOM_Epilog pseudo instruction expansion.380/// @param MBB machine basic block381/// @param NextMBBI  next instruction following HOM_Prolog/HOM_Epilog382/// @param Regs callee save registers that are saved or restored.383/// @param Type frame helper type384/// @return True if a use of helper is qualified.385static bool shouldUseFrameHelper(MachineBasicBlock &MBB,386                                 MachineBasicBlock::iterator &NextMBBI,387                                 SmallVectorImpl<unsigned> &Regs,388                                 FrameHelperType Type) {389  const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();390  auto RegCount = Regs.size();391  assert(RegCount > 0 && (RegCount % 2 == 0));392  // # of instructions that will be outlined.393  int InstCount = RegCount / 2;394 395  // Do not use a helper call when not saving LR.396  if (!llvm::is_contained(Regs, AArch64::LR))397    return false;398 399  switch (Type) {400  case FrameHelperType::Prolog:401    // Prolog helper cannot save FP/LR.402    InstCount--;403    break;404  case FrameHelperType::PrologFrame: {405    // Effectively no change in InstCount since FpAdjustment is included.406    break;407  }408  case FrameHelperType::Epilog:409    // Bail-out if X16 is live across the epilog helper because it is used in410    // the helper to handle X30.411    for (auto NextMI = NextMBBI; NextMI != MBB.end(); NextMI++) {412      if (NextMI->readsRegister(AArch64::W16, TRI))413        return false;414    }415    // Epilog may not be in the last block. Check the liveness in successors.416    for (const MachineBasicBlock *SuccMBB : MBB.successors()) {417      if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))418        return false;419    }420    // No change in InstCount for the regular epilog case.421    break;422  case FrameHelperType::EpilogTail: {423    // EpilogTail helper includes the caller's return.424    if (NextMBBI == MBB.end())425      return false;426    if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)427      return false;428    InstCount++;429    break;430  }431  }432 433  return InstCount >= FrameHelperSizeThreshold;434}435 436/// Lower a HOM_Epilog pseudo instruction into a helper call while437/// creating the helper on demand. Or emit a sequence of loads in place when not438/// using a helper call.439///440/// 1. With a helper including ret441///    HOM_Epilog x30, x29, x19, x20, x21, x22              ; MBBI442///    ret                                                  ; NextMBBI443///    =>444///    b _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22445///    ...                                                  ; NextMBBI446///447/// 2. With a helper448///    HOM_Epilog x30, x29, x19, x20, x21, x22449///    =>450///    bl _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22451///452/// 3. Without a helper453///    HOM_Epilog x30, x29, x19, x20, x21, x22454///    =>455///    ldp x29, x30, [sp, #32]456///    ldp x20, x19, [sp, #16]457///    ldp x22, x21, [sp], #48458bool AArch64LowerHomogeneousPE::lowerEpilog(459    MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,460    MachineBasicBlock::iterator &NextMBBI) {461  auto &MF = *MBB.getParent();462  MachineInstr &MI = *MBBI;463 464  DebugLoc DL = MI.getDebugLoc();465  SmallVector<unsigned, 8> Regs;466  bool HasUnpairedReg = false;467  for (auto &MO : MI.operands())468    if (MO.isReg()) {469      if (!MO.getReg().isValid()) {470        // For now we are only expecting unpaired GP registers which should471        // occur exactly once.472        assert(!HasUnpairedReg);473        HasUnpairedReg = true;474      }475      Regs.push_back(MO.getReg());476    }477  (void)HasUnpairedReg;478  int Size = (int)Regs.size();479  if (Size == 0)480    return false;481  // Registers are in pair.482  assert(Size % 2 == 0);483  assert(MI.getOpcode() == AArch64::HOM_Epilog);484 485  auto Return = NextMBBI;486  if (shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::EpilogTail)) {487    // When MBB ends with a return, emit a tail-call to the epilog helper488    auto *EpilogTailHelper =489        getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::EpilogTail);490    BuildMI(MBB, MBBI, DL, TII->get(AArch64::TCRETURNdi))491        .addGlobalAddress(EpilogTailHelper)492        .addImm(0)493        .setMIFlag(MachineInstr::FrameDestroy)494        .copyImplicitOps(MI)495        .copyImplicitOps(*Return);496    NextMBBI = std::next(Return);497    Return->removeFromParent();498  } else if (shouldUseFrameHelper(MBB, NextMBBI, Regs,499                                  FrameHelperType::Epilog)) {500    // The default epilog helper case.501    auto *EpilogHelper =502        getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Epilog);503    BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))504        .addGlobalAddress(EpilogHelper)505        .setMIFlag(MachineInstr::FrameDestroy)506        .copyImplicitOps(MI);507  } else {508    // Fall back to no-helper.509    for (int I = 0; I < Size - 2; I += 2)510      emitLoad(MF, MBB, MBBI, *TII, Regs[I], Regs[I + 1], Size - I - 2, false);511    // Restore the last CSR with post-increment of SP.512    emitLoad(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], Size, true);513  }514 515  MBBI->removeFromParent();516  return true;517}518 519/// Lower a HOM_Prolog pseudo instruction into a helper call while520/// creating the helper on demand. Or emit a sequence of stores in place when521/// not using a helper call.522///523/// 1. With a helper including frame-setup524///    HOM_Prolog x30, x29, x19, x20, x21, x22, 32525///    =>526///    stp x29, x30, [sp, #-16]!527///    bl _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22528///529/// 2. With a helper530///    HOM_Prolog x30, x29, x19, x20, x21, x22531///    =>532///    stp x29, x30, [sp, #-16]!533///    bl _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22534///535/// 3. Without a helper536///    HOM_Prolog x30, x29, x19, x20, x21, x22537///    =>538///    stp	x22, x21, [sp, #-48]!539///    stp	x20, x19, [sp, #16]540///    stp	x29, x30, [sp, #32]541bool AArch64LowerHomogeneousPE::lowerProlog(542    MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,543    MachineBasicBlock::iterator &NextMBBI) {544  auto &MF = *MBB.getParent();545  MachineInstr &MI = *MBBI;546 547  DebugLoc DL = MI.getDebugLoc();548  SmallVector<unsigned, 8> Regs;549  bool HasUnpairedReg = false;550  int LRIdx = 0;551  std::optional<int> FpOffset;552  for (auto &MO : MI.operands()) {553    if (MO.isReg()) {554      if (MO.getReg().isValid()) {555        if (MO.getReg() == AArch64::LR)556          LRIdx = Regs.size();557      } else {558        // For now we are only expecting unpaired GP registers which should559        // occur exactly once.560        assert(!HasUnpairedReg);561        HasUnpairedReg = true;562      }563      Regs.push_back(MO.getReg());564    } else if (MO.isImm()) {565      FpOffset = MO.getImm();566    }567  }568  (void)HasUnpairedReg;569  int Size = (int)Regs.size();570  if (Size == 0)571    return false;572  // Allow compact unwind case only for oww.573  assert(Size % 2 == 0);574  assert(MI.getOpcode() == AArch64::HOM_Prolog);575 576  if (FpOffset &&577      shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::PrologFrame)) {578    // FP/LR is stored at the top of stack before the prolog helper call.579    emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);580    auto *PrologFrameHelper = getOrCreateFrameHelper(581        M, MMI, Regs, FrameHelperType::PrologFrame, *FpOffset);582    BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))583        .addGlobalAddress(PrologFrameHelper)584        .setMIFlag(MachineInstr::FrameSetup)585        .copyImplicitOps(MI)586        .addReg(AArch64::FP, RegState::Implicit | RegState::Define)587        .addReg(AArch64::SP, RegState::Implicit);588  } else if (!FpOffset && shouldUseFrameHelper(MBB, NextMBBI, Regs,589                                               FrameHelperType::Prolog)) {590    // FP/LR is stored at the top of stack before the prolog helper call.591    emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);592    auto *PrologHelper =593        getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Prolog);594    BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))595        .addGlobalAddress(PrologHelper)596        .setMIFlag(MachineInstr::FrameSetup)597        .copyImplicitOps(MI);598  } else {599    // Fall back to no-helper.600    emitStore(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], -Size, true);601    for (int I = Size - 3; I >= 0; I -= 2)602      emitStore(MF, MBB, MBBI, *TII, Regs[I - 1], Regs[I], Size - I - 1, false);603    if (FpOffset) {604      BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri))605          .addDef(AArch64::FP)606          .addUse(AArch64::SP)607          .addImm(*FpOffset)608          .addImm(0)609          .setMIFlag(MachineInstr::FrameSetup);610    }611  }612 613  MBBI->removeFromParent();614  return true;615}616 617/// Process each machine instruction618/// @param MBB machine basic block619/// @param MBBI current instruction iterator620/// @param NextMBBI next instruction iterator which can be updated621/// @return True when IR is changed.622bool AArch64LowerHomogeneousPE::runOnMI(MachineBasicBlock &MBB,623                                        MachineBasicBlock::iterator MBBI,624                                        MachineBasicBlock::iterator &NextMBBI) {625  MachineInstr &MI = *MBBI;626  unsigned Opcode = MI.getOpcode();627  switch (Opcode) {628  default:629    break;630  case AArch64::HOM_Prolog:631    return lowerProlog(MBB, MBBI, NextMBBI);632  case AArch64::HOM_Epilog:633    return lowerEpilog(MBB, MBBI, NextMBBI);634  }635  return false;636}637 638bool AArch64LowerHomogeneousPE::runOnMBB(MachineBasicBlock &MBB) {639  bool Modified = false;640 641  MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();642  while (MBBI != E) {643    MachineBasicBlock::iterator NMBBI = std::next(MBBI);644    Modified |= runOnMI(MBB, MBBI, NMBBI);645    MBBI = NMBBI;646  }647 648  return Modified;649}650 651bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) {652  TII = MF.getSubtarget<AArch64Subtarget>().getInstrInfo();653 654  bool Modified = false;655  for (auto &MBB : MF)656    Modified |= runOnMBB(MBB);657  return Modified;658}659 660ModulePass *llvm::createAArch64LowerHomogeneousPrologEpilogPass() {661  return new AArch64LowerHomogeneousPrologEpilog();662}663