//===- AArch64LowerHomogeneousPrologEpilog.cpp ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains a pass that lowers homogeneous prolog/epilog instructions. // //===----------------------------------------------------------------------===// #include "AArch64InstrInfo.h" #include "AArch64Subtarget.h" #include "MCTargetDesc/AArch64InstPrinter.h" #include "Utils/AArch64BaseInfo.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" #include <optional> #include <sstream> usingnamespacellvm; #define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME … cl::opt<int> FrameHelperSizeThreshold( "frame-helper-size-threshold", cl::init(2), cl::Hidden, cl::desc("The minimum number of instructions that are outlined in a frame " "helper (default = 2)")); namespace { class AArch64LowerHomogeneousPE { … }; class AArch64LowerHomogeneousPrologEpilog : public ModulePass { … }; } // end anonymous namespace char AArch64LowerHomogeneousPrologEpilog::ID = …; INITIALIZE_PASS(…) bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) { … } bool AArch64LowerHomogeneousPE::run() { … } enum FrameHelperType { … }; /// Return a frame helper name with the given CSRs and the helper type. /// For instance, a prolog helper that saves x19 and x20 is named as /// OUTLINED_FUNCTION_PROLOG_x19x20. static std::string getFrameHelperName(SmallVectorImpl<unsigned> &Regs, FrameHelperType Type, unsigned FpOffset) { … } /// Create a Function for the unique frame helper with the given name. /// Return a newly created MachineFunction with an empty MachineBasicBlock. static MachineFunction &createFrameHelperMachineFunction(Module *M, MachineModuleInfo *MMI, StringRef Name) { … } /// Emit a store-pair instruction for frame-setup. /// If Reg2 is AArch64::NoRegister, emit STR instead. static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPreDec) { … } /// Emit a load-pair instruction for frame-destroy. /// If Reg2 is AArch64::NoRegister, emit LDR instead. static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec) { … } /// Return a unique function if a helper can be formed with the given Regs /// and frame type. /// 1) _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22: /// stp x22, x21, [sp, #-32]! ; x29/x30 has been stored at the caller /// stp x20, x19, [sp, #16] /// ret /// /// 2) _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22: /// stp x22, x21, [sp, #-32]! ; x29/x30 has been stored at the caller /// stp x20, x19, [sp, #16] /// add fp, sp, #32 /// ret /// /// 3) _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22: /// mov x16, x30 /// ldp x29, x30, [sp, #32] /// ldp x20, x19, [sp, #16] /// ldp x22, x21, [sp], #48 /// ret x16 /// /// 4) _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22: /// ldp x29, x30, [sp, #32] /// ldp x20, x19, [sp, #16] /// ldp x22, x21, [sp], #48 /// ret /// @param M module /// @param MMI machine module info /// @param Regs callee save regs that the helper will handle /// @param Type frame helper type /// @return a helper function static Function *getOrCreateFrameHelper(Module *M, MachineModuleInfo *MMI, SmallVectorImpl<unsigned> &Regs, FrameHelperType Type, unsigned FpOffset = 0) { … } /// This function checks if a frame helper should be used for /// HOM_Prolog/HOM_Epilog pseudo instruction expansion. /// @param MBB machine basic block /// @param NextMBBI next instruction following HOM_Prolog/HOM_Epilog /// @param Regs callee save registers that are saved or restored. /// @param Type frame helper type /// @return True if a use of helper is qualified. static bool shouldUseFrameHelper(MachineBasicBlock &MBB, MachineBasicBlock::iterator &NextMBBI, SmallVectorImpl<unsigned> &Regs, FrameHelperType Type) { … } /// Lower a HOM_Epilog pseudo instruction into a helper call while /// creating the helper on demand. Or emit a sequence of loads in place when not /// using a helper call. /// /// 1. With a helper including ret /// HOM_Epilog x30, x29, x19, x20, x21, x22 ; MBBI /// ret ; NextMBBI /// => /// b _OUTLINED_FUNCTION_EPILOG_TAIL_x30x29x19x20x21x22 /// ... ; NextMBBI /// /// 2. With a helper /// HOM_Epilog x30, x29, x19, x20, x21, x22 /// => /// bl _OUTLINED_FUNCTION_EPILOG_x30x29x19x20x21x22 /// /// 3. Without a helper /// HOM_Epilog x30, x29, x19, x20, x21, x22 /// => /// ldp x29, x30, [sp, #32] /// ldp x20, x19, [sp, #16] /// ldp x22, x21, [sp], #48 bool AArch64LowerHomogeneousPE::lowerEpilog( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { … } /// Lower a HOM_Prolog pseudo instruction into a helper call while /// creating the helper on demand. Or emit a sequence of stores in place when /// not using a helper call. /// /// 1. With a helper including frame-setup /// HOM_Prolog x30, x29, x19, x20, x21, x22, 32 /// => /// stp x29, x30, [sp, #-16]! /// bl _OUTLINED_FUNCTION_PROLOG_FRAME32_x30x29x19x20x21x22 /// /// 2. With a helper /// HOM_Prolog x30, x29, x19, x20, x21, x22 /// => /// stp x29, x30, [sp, #-16]! /// bl _OUTLINED_FUNCTION_PROLOG_x30x29x19x20x21x22 /// /// 3. Without a helper /// HOM_Prolog x30, x29, x19, x20, x21, x22 /// => /// stp x22, x21, [sp, #-48]! /// stp x20, x19, [sp, #16] /// stp x29, x30, [sp, #32] bool AArch64LowerHomogeneousPE::lowerProlog( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { … } /// Process each machine instruction /// @param MBB machine basic block /// @param MBBI current instruction iterator /// @param NextMBBI next instruction iterator which can be updated /// @return True when IR is changed. bool AArch64LowerHomogeneousPE::runOnMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI) { … } bool AArch64LowerHomogeneousPE::runOnMBB(MachineBasicBlock &MBB) { … } bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) { … } ModulePass *llvm::createAArch64LowerHomogeneousPrologEpilogPass() { … }