xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64LowerHomogeneousPrologEpilog.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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