LLVM: lib/Target/AArch64/AArch64LowerHomogeneousPrologEpilog.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
27#include
28#include
29
30using namespace llvm;
31
32#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME \
33 "AArch64 homogeneous prolog/epilog lowering pass"
34
37 cl::desc("The minimum number of instructions that are outlined in a frame "
38 "helper (default = 2)"));
39
40namespace {
41
42class AArch64LowerHomogeneousPE {
43public:
45
47 : M(M), MMI(MMI) {}
48
49 bool run();
50 bool runOnMachineFunction(MachineFunction &Fn);
51
52private:
54 MachineModuleInfo *MMI;
55
56 bool runOnMBB(MachineBasicBlock &MBB);
59
60
61
62
65
66
67
70};
71
72class AArch64LowerHomogeneousPrologEpilog : public ModulePass {
73public:
74 static char ID;
75
76 AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {}
77 void getAnalysisUsage(AnalysisUsage &AU) const override {
78 AU.addRequired();
79 AU.addPreserved();
81 ModulePass::getAnalysisUsage(AU);
82 }
83 bool runOnModule(Module &M) override;
84
85 StringRef getPassName() const override {
87 }
88};
89
90}
91
92char AArch64LowerHomogeneousPrologEpilog::ID = 0;
93
95 "aarch64-lower-homogeneous-prolog-epilog",
97
98bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) {
99 if (skipModule(M))
100 return false;
101
103 &getAnalysis().getMMI();
104 return AArch64LowerHomogeneousPE(&M, MMI).run();
105}
106
107bool AArch64LowerHomogeneousPE::run() {
109 for (auto &F : *M) {
110 if (F.empty())
111 continue;
112
114 if (!MF)
115 continue;
116 Changed |= runOnMachineFunction(*MF);
117 }
118
120}
122
123
124
125
128 std::ostringstream RegStream;
129 switch (Type) {
131 RegStream << "OUTLINED_FUNCTION_PROLOG_";
132 break;
134 RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";
135 break;
137 RegStream << "OUTLINED_FUNCTION_EPILOG_";
138 break;
140 RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";
141 break;
142 }
143
144 for (auto Reg : Regs) {
145 if (Reg == AArch64::NoRegister)
146 continue;
148 }
149
150 return RegStream.str();
151}
152
153
154
159 Function *F = M->getFunction(Name);
160 assert(F == nullptr && "Function has been created before");
163 assert(F && "Function was null!");
164
165
168
169
170 F->addFnAttr(Attribute::NoInline);
171 F->addFnAttr(Attribute::MinSize);
172 F->addFnAttr(Attribute::Naked);
173
175
176 MF.getProperties().resetTracksLiveness().resetIsSSA().setNoVRegs();
178
179
182 Builder.CreateRetVoid();
183
184
187
188 return MF;
189}
190
191
192
196 int Offset, bool IsPreDec) {
197 assert(Reg1 != AArch64::NoRegister);
198 const bool IsPaired = Reg2 != AArch64::NoRegister;
199 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
200 assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));
201 unsigned Opc;
202 if (IsPreDec) {
203 if (IsFloat)
204 Opc = IsPaired ? AArch64::STPDpre : AArch64::STRDpre;
205 else
206 Opc = IsPaired ? AArch64::STPXpre : AArch64::STRXpre;
207 } else {
208 if (IsFloat)
209 Opc = IsPaired ? AArch64::STPDi : AArch64::STRDui;
210 else
211 Opc = IsPaired ? AArch64::STPXi : AArch64::STRXui;
212 }
213
214 TypeSize Scale(0U, false), Width(0U, false);
215 int64_t MinOffset, MaxOffset;
216 [[maybe_unused]] bool Success =
219 Offset *= (8 / (int)Scale);
220
222 if (IsPreDec)
223 MIB.addDef(AArch64::SP);
224 if (IsPaired)
230}
231
232
233
237 int Offset, bool IsPostDec) {
238 assert(Reg1 != AArch64::NoRegister);
239 const bool IsPaired = Reg2 != AArch64::NoRegister;
240 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
241 assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));
242 unsigned Opc;
243 if (IsPostDec) {
244 if (IsFloat)
245 Opc = IsPaired ? AArch64::LDPDpost : AArch64::LDRDpost;
246 else
247 Opc = IsPaired ? AArch64::LDPXpost : AArch64::LDRXpost;
248 } else {
249 if (IsFloat)
250 Opc = IsPaired ? AArch64::LDPDi : AArch64::LDRDui;
251 else
252 Opc = IsPaired ? AArch64::LDPXi : AArch64::LDRXui;
253 }
254
255 TypeSize Scale(0U, false), Width(0U, false);
256 int64_t MinOffset, MaxOffset;
257 [[maybe_unused]] bool Success =
260 Offset *= (8 / (int)Scale);
261
263 if (IsPostDec)
264 MIB.addDef(AArch64::SP);
265 if (IsPaired)
271}
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
306 unsigned FpOffset = 0) {
309 auto *F = M->getFunction(Name);
310 if (F)
311 return F;
312
317
319 switch (Type) {
322
323 auto LRIdx = std::distance(Regs.begin(), llvm::find(Regs, AArch64::LR));
324
325
326
327 if (LRIdx != Size - 2) {
328 assert(Regs[Size - 2] != AArch64::LR);
330 LRIdx - Size + 2, true);
331 }
332
333
334 for (int I = Size - 3; I >= 0; I -= 2) {
335
336 if (Regs[I - 1] == AArch64::LR)
337 continue;
339 false);
340 }
348
350 .addReg(AArch64::LR);
351 break;
352 }
356
358 .addDef(AArch64::X16)
359 .addReg(AArch64::XZR)
362
363 for (int I = 0; I < Size - 2; I += 2)
365 false);
366
368 true);
369
372 break;
373 }
374
375 return M->getFunction(Name);
376}
377
378
379
380
381
382
383
384
389 const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
390 auto RegCount = Regs.size();
391 assert(RegCount > 0 && (RegCount % 2 == 0));
392
393 int InstCount = RegCount / 2;
394
395
397 return false;
398
399 switch (Type) {
401
402 InstCount--;
403 break;
405
406 break;
407 }
409
410
411 for (auto NextMI = NextMBBI; NextMI != MBB.end(); NextMI++) {
412 if (NextMI->readsRegister(AArch64::W16, TRI))
413 return false;
414 }
415
417 if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))
418 return false;
419 }
420
421 break;
423
424 if (NextMBBI == MBB.end())
425 return false;
426 if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)
427 return false;
428 InstCount++;
429 break;
430 }
431 }
432
434}
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458bool AArch64LowerHomogeneousPE::lowerEpilog(
463
465 SmallVector<unsigned, 8> Regs;
466 bool HasUnpairedReg = false;
467 for (auto &MO : MI.operands())
468 if (MO.isReg()) {
469 if (!MO.getReg().isValid()) {
470
471
472 assert(!HasUnpairedReg);
473 HasUnpairedReg = true;
474 }
476 }
477 (void)HasUnpairedReg;
479 if (Size == 0)
480 return false;
481
483 assert(MI.getOpcode() == AArch64::HOM_Epilog);
484
485 auto Return = NextMBBI;
487
488 auto *EpilogTailHelper =
496 NextMBBI = std::next(Return);
497 Return->removeFromParent();
500
501 auto *EpilogHelper =
507 } else {
508
509 for (int I = 0; I < Size - 2; I += 2)
511
513 }
514
516 return true;
517}
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541bool AArch64LowerHomogeneousPE::lowerProlog(
546
548 SmallVector<unsigned, 8> Regs;
549 bool HasUnpairedReg = false;
550 int LRIdx = 0;
551 std::optional FpOffset;
552 for (auto &MO : MI.operands()) {
553 if (MO.isReg()) {
554 if (MO.getReg().isValid()) {
555 if (MO.getReg() == AArch64::LR)
556 LRIdx = Regs.size();
557 } else {
558
559
560 assert(!HasUnpairedReg);
561 HasUnpairedReg = true;
562 }
564 } else if (MO.isImm()) {
565 FpOffset = MO.getImm();
566 }
567 }
568 (void)HasUnpairedReg;
570 if (Size == 0)
571 return false;
572
574 assert(MI.getOpcode() == AArch64::HOM_Prolog);
575
576 if (FpOffset &&
578
579 emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);
590
591 emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);
592 auto *PrologHelper =
598 } else {
599
601 for (int I = Size - 3; I >= 0; I -= 2)
603 if (FpOffset) {
610 }
611 }
612
614 return true;
615}
616
617
618
619
620
621
622bool AArch64LowerHomogeneousPE::runOnMI(MachineBasicBlock &MBB,
626 unsigned Opcode = MI.getOpcode();
627 switch (Opcode) {
628 default:
629 break;
630 case AArch64::HOM_Prolog:
631 return lowerProlog(MBB, MBBI, NextMBBI);
632 case AArch64::HOM_Epilog:
633 return lowerEpilog(MBB, MBBI, NextMBBI);
634 }
635 return false;
636}
637
638bool AArch64LowerHomogeneousPE::runOnMBB(MachineBasicBlock &MBB) {
640
645 MBBI = NMBBI;
646 }
647
649}
650
651bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) {
652 TII = MF.getSubtarget().getInstrInfo();
653
655 for (auto &MBB : MF)
658}
659
661 return new AArch64LowerHomogeneousPrologEpilog();
662}
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.
Definition AArch64LowerHomogeneousPrologEpilog.cpp:303
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...
Definition AArch64LowerHomogeneousPrologEpilog.cpp:385
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.
Definition AArch64LowerHomogeneousPrologEpilog.cpp:234
#define AARCH64_LOWER_HOMOGENEOUS_PROLOG_EPILOG_NAME
Definition AArch64LowerHomogeneousPrologEpilog.cpp:32
static 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.
Definition AArch64LowerHomogeneousPrologEpilog.cpp:126
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.
Definition AArch64LowerHomogeneousPrologEpilog.cpp:193
FrameHelperType
Definition AArch64LowerHomogeneousPrologEpilog.cpp:121
@ EpilogTail
Definition AArch64LowerHomogeneousPrologEpilog.cpp:121
@ PrologFrame
Definition AArch64LowerHomogeneousPrologEpilog.cpp:121
static MachineFunction & createFrameHelperMachineFunction(Module *M, MachineModuleInfo *MMI, StringRef Name)
Create a Function for the unique frame helper with the given name.
Definition AArch64LowerHomogeneousPrologEpilog.cpp:155
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Module.h This file contains the declarations for the Module class.
Machine Check Debug Module
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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.
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 LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
@ ExternalLinkage
Externally visible function.
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
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 MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI MachineBasicBlock * removeFromParent()
This method unlinks 'this' from the containing function, and returns it, but does not delete it.
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)
CreateMachineInstr - Allocate a new MachineInstr.
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.
This class contains meta information specific to a module.
LLVM_ABI MachineFunction & getOrCreateMachineFunction(Function &F)
Returns the MachineFunction constructed for the IR function F.
LLVM_ABI MachineFunction * getMachineFunction(const Function &F) const
Returns the MachineFunction associated to IR function F if there is one, otherwise nullptr.
LLVM_ABI 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...
A Module instance is used to store all the information related to an LLVM module.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
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 TargetInstrInfo * getInstrInfo() const
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
@ 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.
unsigned getDefRegState(bool B)
ModulePass * createAArch64LowerHomogeneousPrologEpilogPass()
Definition AArch64LowerHomogeneousPrologEpilog.cpp:660
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.