35#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME \
36 "AArch64 homogeneous prolog/epilog lowering pass"
40 cl::desc(
"The minimum number of instructions that are outlined in a frame "
41 "helper (default = 2)"));
45class AArch64LowerHomogeneousPE {
75class AArch64LowerHomogeneousPrologEpilog :
public ModulePass {
98char AArch64LowerHomogeneousPrologEpilog::ID = 0;
101 "aarch64-lower-homogeneous-prolog-epilog",
104bool AArch64LowerHomogeneousPrologEpilog::runOnModule(
Module &M) {
109 &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
110 return AArch64LowerHomogeneousPE(&M, MMI).run();
113bool AArch64LowerHomogeneousPE::run() {
114 bool Changed =
false;
122 Changed |= runOnMachineFunction(*MF);
134 std::ostringstream RegStream;
137 RegStream <<
"OUTLINED_FUNCTION_PROLOG_";
140 RegStream <<
"OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset <<
"_";
143 RegStream <<
"OUTLINED_FUNCTION_EPILOG_";
146 RegStream <<
"OUTLINED_FUNCTION_EPILOG_TAIL_";
150 for (
auto Reg : Regs) {
151 if (Reg == AArch64::NoRegister)
156 return RegStream.str();
166 assert(
F ==
nullptr &&
"Function has been created before");
168 Function::ExternalLinkage,
Name, M);
169 assert(
F &&
"Function was null!");
173 F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
177 F->addFnAttr(Attribute::OptimizeNone);
178 F->addFnAttr(Attribute::NoInline);
179 F->addFnAttr(Attribute::MinSize);
180 F->addFnAttr(Attribute::Naked);
206 int Offset,
bool IsPreDec) {
207 assert(Reg1 != AArch64::NoRegister);
208 const bool IsPaired = Reg2 != AArch64::NoRegister;
209 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
214 Opc = IsPaired ? AArch64::STPDpre : AArch64::STRDpre;
216 Opc = IsPaired ? AArch64::STPXpre : AArch64::STRXpre;
219 Opc = IsPaired ? AArch64::STPDi : AArch64::STRDui;
221 Opc = IsPaired ? AArch64::STPXi : AArch64::STRXui;
224 TypeSize Scale(0U,
false), Width(0U,
false);
225 int64_t MinOffset, MaxOffset;
226 [[maybe_unused]]
bool Success =
229 Offset *= (8 / (int)Scale);
247 int Offset,
bool IsPostDec) {
248 assert(Reg1 != AArch64::NoRegister);
249 const bool IsPaired = Reg2 != AArch64::NoRegister;
250 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
255 Opc = IsPaired ? AArch64::LDPDpost : AArch64::LDRDpost;
257 Opc = IsPaired ? AArch64::LDPXpost : AArch64::LDRXpost;
260 Opc = IsPaired ? AArch64::LDPDi : AArch64::LDRDui;
262 Opc = IsPaired ? AArch64::LDPXi : AArch64::LDRXui;
265 TypeSize Scale(0U,
false), Width(0U,
false);
266 int64_t MinOffset, MaxOffset;
267 [[maybe_unused]]
bool Success =
270 Offset *= (8 / (int)Scale);
316 unsigned FpOffset = 0) {
319 auto *
F = M->getFunction(
Name);
333 auto LRIdx = std::distance(Regs.
begin(),
llvm::find(Regs, AArch64::LR));
337 if (LRIdx !=
Size - 2) {
340 LRIdx -
Size + 2,
true);
344 for (
int I =
Size - 3;
I >= 0;
I -= 2) {
346 if (Regs[
I - 1] == AArch64::LR)
373 for (
int I = 0;
I <
Size - 2;
I += 2)
385 return M->getFunction(
Name);
400 auto RegCount = Regs.
size();
401 assert(RegCount > 0 && (RegCount % 2 == 0));
403 int InstCount = RegCount / 2;
421 for (
auto NextMI = NextMBBI; NextMI !=
MBB.
end(); NextMI++) {
422 if (NextMI->readsRegister(AArch64::W16,
TRI))
427 if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))
434 if (NextMBBI ==
MBB.
end())
436 if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)
468bool AArch64LowerHomogeneousPE::lowerEpilog(
476 bool HasUnpairedReg =
false;
477 for (
auto &MO :
MI.operands())
479 if (!MO.getReg().isValid()) {
483 HasUnpairedReg =
true;
487 (void)HasUnpairedReg;
493 assert(
MI.getOpcode() == AArch64::HOM_Epilog);
498 auto *EpilogTailHelper =
506 NextMBBI = std::next(Return);
507 Return->removeFromParent();
519 for (
int I = 0;
I <
Size - 2;
I += 2)
551bool AArch64LowerHomogeneousPE::lowerProlog(
559 bool HasUnpairedReg =
false;
561 std::optional<int> FpOffset;
562 for (
auto &MO :
MI.operands()) {
564 if (MO.getReg().isValid()) {
565 if (MO.getReg() == AArch64::LR)
571 HasUnpairedReg =
true;
574 }
else if (MO.isImm()) {
575 FpOffset = MO.getImm();
578 (void)HasUnpairedReg;
584 assert(
MI.getOpcode() == AArch64::HOM_Prolog);
611 for (
int I =
Size - 3;
I >= 0;
I -= 2)
636 unsigned Opcode =
MI.getOpcode();
640 case AArch64::HOM_Prolog:
641 return lowerProlog(
MBB,
MBBI, NextMBBI);
642 case AArch64::HOM_Epilog:
643 return lowerEpilog(
MBB,
MBBI, NextMBBI);
661bool AArch64LowerHomogeneousPE::runOnMachineFunction(
MachineFunction &MF) {
671 return new AArch64LowerHomogeneousPrologEpilog();
static Function * getOrCreateFrameHelper(Module *M, MachineModuleInfo *MMI, SmallVectorImpl< unsigned > &Regs, FrameHelperType Type, unsigned FpOffset=0)
Return a unique function if a helper can be formed with the given Regs and frame type.
static bool shouldUseFrameHelper(MachineBasicBlock &MBB, MachineBasicBlock::iterator &NextMBBI, SmallVectorImpl< unsigned > &Regs, FrameHelperType Type)
This function checks if a frame helper should be used for HOM_Prolog/HOM_Epilog pseudo instruction ex...
static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)
Emit a load-pair instruction for frame-destroy.
#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)"))
static std::string getFrameHelperName(SmallVectorImpl< unsigned > &Regs, FrameHelperType Type, unsigned FpOffset)
Return a frame helper name with the given CSRs and the helper type.
static void emitStore(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPreDec)
Emit a store-pair instruction for frame-setup.
static MachineFunction & createFrameHelperMachineFunction(Module *M, MachineModuleInfo *MMI, StringRef Name)
Create a Function for the unique frame helper with the given name.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
const HexagonInstrInfo * TII
unsigned const TargetRegisterInfo * TRI
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
static const char * getRegisterName(MCRegister Reg, unsigned AltIdx=AArch64::NoRegAltName)
static bool getMemOpInfo(unsigned Opcode, TypeSize &Scale, TypeSize &Width, int64_t &MinOffset, int64_t &MaxOffset)
Returns true if opcode Opc is a memory operation.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This is an important class for using LLVM in a threaded context.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
MachineBasicBlock * removeFromParent()
This method unlinks 'this' from the containing function, and returns it, but does not delete it.
MachineFunctionProperties & set(Property P)
MachineFunctionProperties & reset(Property P)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineFunctionProperties & getProperties() const
Get the function properties.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & copyImplicitOps(const MachineInstr &OtherMI) const
Copy all the implicit operands from OtherMI onto this one.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
This class contains meta information specific to a module.
MachineFunction & getOrCreateMachineFunction(Function &F)
Returns the MachineFunction constructed for the IR function F.
void freezeReservedRegs()
freezeReservedRegs - Called by the register allocator to freeze the set of reserved registers before ...
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
TargetInstrInfo - Interface to description of machine instruction set.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
virtual const TargetInstrInfo * getInstrInfo() const
The instances of the Type class are immutable: once they are created, they are never changed.
static Type * getVoidTy(LLVMContext &C)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void initializeAArch64LowerHomogeneousPrologEpilogPass(PassRegistry &)
unsigned getDefRegState(bool B)
ModulePass * createAArch64LowerHomogeneousPrologEpilogPass()
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.