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 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 76 AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) { 77 initializeAArch64LowerHomogeneousPrologEpilogPass( 78 *PassRegistry::getPassRegistry()); 79 } 80 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 88 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 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 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. 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. 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. 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. 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 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. 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 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] 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. 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 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 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 611 ModulePass *llvm::createAArch64LowerHomogeneousPrologEpilogPass() { 612 return new AArch64LowerHomogeneousPrologEpilog(); 613 } 614