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