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