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