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();
51
52private:
55
59
60
61
62
65
66
67
70};
71
72class AArch64LowerHomogeneousPrologEpilog : public ModulePass {
73public:
74 static char ID;
75
76 AArch64LowerHomogeneousPrologEpilog() : ModulePass(ID) {
79 }
85 }
87
90 }
91};
92
93}
94
95char AArch64LowerHomogeneousPrologEpilog::ID = 0;
96
98 "aarch64-lower-homogeneous-prolog-epilog",
100
101bool AArch64LowerHomogeneousPrologEpilog::runOnModule(Module &M) {
102 if (skipModule(M))
103 return false;
104
106 &getAnalysis().getMMI();
107 return AArch64LowerHomogeneousPE(&M, MMI).run();
108}
109
110bool AArch64LowerHomogeneousPE::run() {
111 bool Changed = false;
112 for (auto &F : *M) {
113 if (F.empty())
114 continue;
115
117 if (!MF)
118 continue;
119 Changed |= runOnMachineFunction(*MF);
120 }
121
122 return Changed;
123}
125
126
127
128
131 std::ostringstream RegStream;
132 switch (Type) {
134 RegStream << "OUTLINED_FUNCTION_PROLOG_";
135 break;
137 RegStream << "OUTLINED_FUNCTION_PROLOG_FRAME" << FpOffset << "_";
138 break;
140 RegStream << "OUTLINED_FUNCTION_EPILOG_";
141 break;
143 RegStream << "OUTLINED_FUNCTION_EPILOG_TAIL_";
144 break;
145 }
146
147 for (auto Reg : Regs) {
148 if (Reg == AArch64::NoRegister)
149 continue;
151 }
152
153 return RegStream.str();
154}
155
156
157
163 assert(F == nullptr && "Function has been created before");
165 Function::ExternalLinkage, Name, M);
166 assert(F && "Function was null!");
167
168
170 F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
171
172
173 F->addFnAttr(Attribute::NoInline);
174 F->addFnAttr(Attribute::MinSize);
175 F->addFnAttr(Attribute::Naked);
176
178
179 MF.getProperties().reset(MachineFunctionProperties::Property::TracksLiveness);
180 MF.getProperties().reset(MachineFunctionProperties::Property::IsSSA);
181 MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
183
184
188
189
192
193 return MF;
194}
195
196
197
201 int Offset, bool IsPreDec) {
202 assert(Reg1 != AArch64::NoRegister);
203 const bool IsPaired = Reg2 != AArch64::NoRegister;
204 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
205 assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));
206 unsigned Opc;
207 if (IsPreDec) {
208 if (IsFloat)
209 Opc = IsPaired ? AArch64::STPDpre : AArch64::STRDpre;
210 else
211 Opc = IsPaired ? AArch64::STPXpre : AArch64::STRXpre;
212 } else {
213 if (IsFloat)
214 Opc = IsPaired ? AArch64::STPDi : AArch64::STRDui;
215 else
216 Opc = IsPaired ? AArch64::STPXi : AArch64::STRXui;
217 }
218
219 TypeSize Scale(0U, false), Width(0U, false);
220 int64_t MinOffset, MaxOffset;
221 [[maybe_unused]] bool Success =
224 Offset *= (8 / (int)Scale);
225
227 if (IsPreDec)
228 MIB.addDef(AArch64::SP);
229 if (IsPaired)
235}
236
237
238
242 int Offset, bool IsPostDec) {
243 assert(Reg1 != AArch64::NoRegister);
244 const bool IsPaired = Reg2 != AArch64::NoRegister;
245 bool IsFloat = AArch64::FPR64RegClass.contains(Reg1);
246 assert(!(IsFloat ^ AArch64::FPR64RegClass.contains(Reg2)));
247 unsigned Opc;
248 if (IsPostDec) {
249 if (IsFloat)
250 Opc = IsPaired ? AArch64::LDPDpost : AArch64::LDRDpost;
251 else
252 Opc = IsPaired ? AArch64::LDPXpost : AArch64::LDRXpost;
253 } else {
254 if (IsFloat)
255 Opc = IsPaired ? AArch64::LDPDi : AArch64::LDRDui;
256 else
257 Opc = IsPaired ? AArch64::LDPXi : AArch64::LDRXui;
258 }
259
260 TypeSize Scale(0U, false), Width(0U, false);
261 int64_t MinOffset, MaxOffset;
262 [[maybe_unused]] bool Success =
265 Offset *= (8 / (int)Scale);
266
268 if (IsPostDec)
269 MIB.addDef(AArch64::SP);
270 if (IsPaired)
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
303
304
305
306
307
311 unsigned FpOffset = 0) {
314 auto *F = M->getFunction(Name);
315 if (F)
316 return F;
317
322
324 switch (Type) {
327
328 auto LRIdx = std::distance(Regs.begin(), llvm::find(Regs, AArch64::LR));
329
330
331
332 if (LRIdx != Size - 2) {
333 assert(Regs[Size - 2] != AArch64::LR);
335 LRIdx - Size + 2, true);
336 }
337
338
339 for (int I = Size - 3; I >= 0; I -= 2) {
340
341 if (Regs[I - 1] == AArch64::LR)
342 continue;
344 false);
345 }
353
355 .addReg(AArch64::LR);
356 break;
357 }
361
363 .addDef(AArch64::X16)
364 .addReg(AArch64::XZR)
367
368 for (int I = 0; I < Size - 2; I += 2)
370 false);
371
373 true);
374
377 break;
378 }
379
380 return M->getFunction(Name);
381}
382
383
384
385
386
387
388
389
395 auto RegCount = Regs.size();
396 assert(RegCount > 0 && (RegCount % 2 == 0));
397
398 int InstCount = RegCount / 2;
399
400
402 return false;
403
404 switch (Type) {
406
407 InstCount--;
408 break;
410
411 break;
412 }
414
415
416 for (auto NextMI = NextMBBI; NextMI != MBB.end(); NextMI++) {
417 if (NextMI->readsRegister(AArch64::W16, TRI))
418 return false;
419 }
420
422 if (SuccMBB->isLiveIn(AArch64::W16) || SuccMBB->isLiveIn(AArch64::X16))
423 return false;
424 }
425
426 break;
428
429 if (NextMBBI == MBB.end())
430 return false;
431 if (NextMBBI->getOpcode() != AArch64::RET_ReallyLR)
432 return false;
433 InstCount++;
434 break;
435 }
436 }
437
439}
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463bool AArch64LowerHomogeneousPE::lowerEpilog(
468
471 bool HasUnpairedReg = false;
472 for (auto &MO : MI.operands())
473 if (MO.isReg()) {
474 if (!MO.getReg().isValid()) {
475
476
477 assert(!HasUnpairedReg);
478 HasUnpairedReg = true;
479 }
481 }
482 (void)HasUnpairedReg;
484 if (Size == 0)
485 return false;
486
488 assert(MI.getOpcode() == AArch64::HOM_Epilog);
489
490 auto Return = NextMBBI;
492
493 auto *EpilogTailHelper =
501 NextMBBI = std::next(Return);
502 Return->removeFromParent();
505
506 auto *EpilogHelper =
512 } else {
513
514 for (int I = 0; I < Size - 2; I += 2)
516
518 }
519
521 return true;
522}
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546bool AArch64LowerHomogeneousPE::lowerProlog(
551
554 bool HasUnpairedReg = false;
555 int LRIdx = 0;
556 std::optional FpOffset;
557 for (auto &MO : MI.operands()) {
558 if (MO.isReg()) {
559 if (MO.getReg().isValid()) {
560 if (MO.getReg() == AArch64::LR)
561 LRIdx = Regs.size();
562 } else {
563
564
565 assert(!HasUnpairedReg);
566 HasUnpairedReg = true;
567 }
569 } else if (MO.isImm()) {
570 FpOffset = MO.getImm();
571 }
572 }
573 (void)HasUnpairedReg;
575 if (Size == 0)
576 return false;
577
579 assert(MI.getOpcode() == AArch64::HOM_Prolog);
580
581 if (FpOffset &&
583
584 emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);
595
596 emitStore(MF, MBB, MBBI, *TII, AArch64::LR, AArch64::FP, -LRIdx - 2, true);
597 auto *PrologHelper =
603 } else {
604
606 for (int I = Size - 3; I >= 0; I -= 2)
608 if (FpOffset) {
615 }
616 }
617
619 return true;
620}
621
622
623
624
625
626
631 unsigned Opcode = MI.getOpcode();
632 switch (Opcode) {
633 default:
634 break;
635 case AArch64::HOM_Prolog:
636 return lowerProlog(MBB, MBBI, NextMBBI);
637 case AArch64::HOM_Epilog:
638 return lowerEpilog(MBB, MBBI, NextMBBI);
639 }
640 return false;
641}
642
645
647 while (MBBI != E) {
650 MBBI = NMBBI;
651 }
652
654}
655
656bool AArch64LowerHomogeneousPE::runOnMachineFunction(MachineFunction &MF) {
658
660 for (auto &MBB : MF)
663}
664
666 return new AArch64LowerHomogeneousPrologEpilog();
667}
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
Module.h This file contains the declarations for the Module class.
unsigned const TargetRegisterInfo * TRI
#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)
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ 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.