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