LLVM: lib/CodeGen/FixupStatepointCallerSaved.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
33
34using namespace llvm;
35
36#define DEBUG_TYPE "fixup-statepoint-caller-saved"
37STATISTIC(NumSpilledRegisters, "Number of spilled register");
38STATISTIC(NumSpillSlotsAllocated, "Number of spill slots allocated");
39STATISTIC(NumSpillSlotsExtended, "Number of spill slots extended");
40
43 cl::desc("Allow spill in spill slot of greater size than register size"),
45
48 cl::desc("Allow passing GC Pointer arguments in callee saved registers"));
49
52 cl::desc("Enable simple copy propagation during register reloading"));
53
54
55
57 "fixup-max-csr-statepoints", cl::Hidden,
58 cl::desc("Max number of statepoints allowed to pass GC Ptrs in registers"));
59
60namespace {
61
62struct FixupStatepointCallerSavedImpl {
64};
65
67public:
68 static char ID;
69
70 FixupStatepointCallerSavedLegacy() : MachineFunctionPass(ID) {
73 }
74 void getAnalysisUsage(AnalysisUsage &AU) const override {
77 }
78
79 StringRef getPassName() const override {
80 return "Fixup Statepoint Caller Saved";
81 }
82
83 bool runOnMachineFunction(MachineFunction &MF) override;
84};
85
86}
87
88char FixupStatepointCallerSavedLegacy::ID = 0;
90
92 "Fixup Statepoint Caller Saved", false, false)
94 "Fixup Statepoint Caller Saved", false, false)
95
96
99 return TRI.getSpillSize(*RC);
100}
101
102
103
104
105
106
107
108
109
110
111
112
113
114
119
120 int Idx = RI->findRegisterUseOperandIdx(Reg, &TRI, false);
121 if (Idx >= 0 && (unsigned)Idx < StatepointOpers(&*RI).getNumDeoptArgsIdx()) {
122 IsKill = false;
123 return Reg;
124 }
125
127 return Reg;
128
132 for (auto It = ++(RI.getReverse()); It != E; ++It) {
133 if (It->readsRegister(Reg, &TRI) && )
134 Use = &*It;
135 if (It->modifiesRegister(Reg, &TRI)) {
136 Def = &*It;
137 break;
138 }
139 }
140
141 if (!Def)
142 return Reg;
143
144 auto DestSrc = TII.isCopyInstr(*Def);
145 if (!DestSrc || DestSrc->Destination->getReg() != Reg)
146 return Reg;
147
148 Register SrcReg = DestSrc->Source->getReg();
149
151 return Reg;
152
153 LLVM_DEBUG(dbgs() << "spillRegisters: perform copy propagation "
155 << "\n");
156
157
159 IsKill = DestSrc->Source->isKill();
160
161 if () {
162
163
164 LLVM_DEBUG(dbgs() << "spillRegisters: removing dead copy " << *Def);
165 Def->eraseFromParent();
166 } else if (IsKill) {
167
168
169 const_cast<MachineOperand *>(DestSrc->Source)->setIsKill(false);
170 }
171
172 return SrcReg;
173}
174
175namespace {
176
177using RegSlotPair = std::pair<Register, int>;
178
179
180class RegReloadCache {
181 using ReloadSet = SmallSet<RegSlotPair, 8>;
182 DenseMap<const MachineBasicBlock *, ReloadSet> Reloads;
183
184public:
185 RegReloadCache() = default;
186
187
188
189 bool tryRecordReload(Register Reg, int FI, const MachineBasicBlock *MBB) {
190 RegSlotPair RSP(Reg, FI);
191 return Reloads[MBB].insert(RSP).second;
192 }
193};
194
195
196
197
198
199
200class FrameIndexesCache {
201private:
202 struct FrameIndexesPerSize {
203
204 SmallVector<int, 8> Slots;
205
206 unsigned Index = 0;
207 };
208 MachineFrameInfo &MFI;
209 const TargetRegisterInfo &TRI;
210
211
212
213
214 DenseMap<unsigned, FrameIndexesPerSize> Cache;
215
216
217
218 SmallSet<int, 8> ReservedSlots;
219
220
221
222
223 DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>>
224 GlobalIndices;
225
226 FrameIndexesPerSize &getCacheBucket(unsigned Size) {
227
228
230 }
231
232public:
233 FrameIndexesCache(MachineFrameInfo &MFI, const TargetRegisterInfo &TRI)
234 : MFI(MFI), TRI(TRI) {}
235
236
237
238 void reset(const MachineBasicBlock *EHPad) {
239 for (auto &It : Cache)
240 It.second.Index = 0;
241
242 ReservedSlots.clear();
243 if (EHPad)
244 if (auto It = GlobalIndices.find(EHPad); It != GlobalIndices.end())
246 }
247
248
249 int getFrameIndex(Register Reg, MachineBasicBlock *EHPad) {
250
251 auto It = GlobalIndices.find(EHPad);
252 if (It != GlobalIndices.end()) {
253 auto &Vec = It->second;
255 Vec, [Reg](RegSlotPair &RSP) { return Reg == RSP.first; });
256 if (Idx != Vec.end()) {
257 int FI = Idx->second;
258 LLVM_DEBUG(dbgs() << "Found global FI " << FI << " for register "
261 assert(ReservedSlots.count(FI) && "using unreserved slot");
262 return FI;
263 }
264 }
265
267 FrameIndexesPerSize &Line = getCacheBucket(Size);
268 while (Line.Index < Line.Slots.size()) {
269 int FI = Line.Slots[Line.Index++];
270 if (ReservedSlots.count(FI))
271 continue;
272
273
274 if (MFI.getObjectSize(FI) < Size) {
275 MFI.setObjectSize(FI, Size);
276 MFI.setObjectAlignment(FI, Align(Size));
277 NumSpillSlotsExtended++;
278 }
279 return FI;
280 }
281 int FI = MFI.CreateSpillStackObject(Size, Align(Size));
282 NumSpillSlotsAllocated++;
283 Line.Slots.push_back(FI);
284 ++Line.Index;
285
286
287 if (EHPad) {
288 GlobalIndices[EHPad].push_back(std::make_pair(Reg, FI));
289 LLVM_DEBUG(dbgs() << "Reserved FI " << FI << " for spilling reg "
290 << printReg(Reg, &TRI) << " at landing pad "
292 }
293
294 return FI;
295 }
296
297
298
299
300 void sortRegisters(SmallVectorImpl &Regs) {
302 return;
305 });
306 }
307};
308
309
310class StatepointState {
311private:
312
313 MachineInstr &MI;
314 MachineFunction &MF;
315
316 MachineBasicBlock *EHPad;
317 const TargetRegisterInfo &TRI;
318 const TargetInstrInfo &TII;
319 MachineFrameInfo &MFI;
320
321 const uint32_t *Mask;
322
323 FrameIndexesCache &CacheFI;
324 bool AllowGCPtrInCSR;
325
326 SmallVector<unsigned, 8> OpsToSpill;
327
329
331
332 DenseMap<Register, int> RegToSlotIdx;
333
334public:
335 StatepointState(MachineInstr &MI, const uint32_t *Mask,
336 FrameIndexesCache &CacheFI, bool AllowGCPtrInCSR)
337 : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
338 TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
339 Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) {
340
341
342 EHPad = nullptr;
344
346 [](MachineInstr &I) {
347 return I.getOpcode() == TargetOpcode::STATEPOINT;
348 });
349
351 return;
352
353 auto IsEHPad = [](MachineBasicBlock *B) { return B->isEHPad(); };
354
356
359 EHPad = *It;
360 }
361
362 MachineBasicBlock *getEHPad() const { return EHPad; }
363
364
366 return (Mask[Reg.id() / 32] >> (Reg.id() % 32)) & 1;
367 }
368
369
370
371
372 bool findRegistersToSpill() {
373 SmallSet<Register, 8> GCRegs;
374
375
376 for (const auto &Def : MI.defs())
378
379 SmallSet<Register, 8> VisitedRegs;
380 for (unsigned Idx = StatepointOpers(&MI).getVarIdx(),
381 EndIdx = MI.getNumOperands();
382 Idx < EndIdx; ++Idx) {
383 MachineOperand &MO = MI.getOperand(Idx);
385 continue;
388
389 if (isCalleeSaved(Reg) && (AllowGCPtrInCSR || !GCRegs.contains(Reg)))
390 continue;
391
393 << Idx << "\n");
394
395 if (VisitedRegs.insert(Reg).second)
396 RegsToSpill.push_back(Reg);
397 OpsToSpill.push_back(Idx);
398 }
399 CacheFI.sortRegisters(RegsToSpill);
400 return !RegsToSpill.empty();
401 }
402
403
404
405 void spillRegisters() {
407 int FI = CacheFI.getFrameIndex(Reg, EHPad);
408
409 NumSpilledRegisters++;
410 RegToSlotIdx[Reg] = FI;
411
413 << "\n");
414
415
416 bool IsKill = true;
419 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
420
421 LLVM_DEBUG(dbgs() << "Insert spill before " << *InsertBefore);
422 TII.storeRegToStackSlot(*MI.getParent(), InsertBefore, Reg, IsKill, FI,
424 }
425 }
426
428 MachineBasicBlock *MBB) {
429 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
430 int FI = RegToSlotIdx[Reg];
432 TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, Register());
433 return;
434 }
435
436
437
439 --It;
440 TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, Register());
441 MachineInstr *Reload = It->getPrevNode();
442 int Dummy = 0;
443 (void)Dummy;
444 assert(TII.isLoadFromStackSlot(*Reload, Dummy) == Reg);
448 }
449
450
451 void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) {
452 MachineBasicBlock *MBB = NewStatepoint->getParent();
453 auto InsertPoint = std::next(NewStatepoint->getIterator());
454
455 for (auto Reg : RegsToReload) {
456 insertReloadBefore(Reg, InsertPoint, MBB);
458 << RegToSlotIdx[Reg] << " after statepoint\n");
459
460 if (EHPad && RC.tryRecordReload(Reg, RegToSlotIdx[Reg], EHPad)) {
461 auto EHPadInsertPoint =
462 EHPad->SkipPHIsLabelsAndDebug(EHPad->begin(), Reg);
463 insertReloadBefore(Reg, EHPadInsertPoint, EHPad);
466 }
467 }
468 }
469
470
471
472 MachineInstr *rewriteStatepoint() {
473 MachineInstr *NewMI =
474 MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(), true);
475 MachineInstrBuilder MIB(MF, NewMI);
476
477 unsigned NumOps = MI.getNumOperands();
478
479
480 SmallVector<unsigned, 8> NewIndices;
481 unsigned NumDefs = MI.getNumDefs();
482 for (unsigned I = 0; I < NumDefs; ++I) {
483 MachineOperand &DefMO = MI.getOperand(I);
484 assert(DefMO.isReg() && DefMO.isDef() && "Expected Reg Def operand");
486 assert(DefMO.isTied() && "Def is expected to be tied");
487
488
489 if (MI.getOperand(MI.findTiedOperandIdx(I)).isUndef()) {
490 if (AllowGCPtrInCSR) {
493 }
494 continue;
495 }
496 if (!AllowGCPtrInCSR) {
498 RegsToReload.push_back(Reg);
499 } else {
500 if (isCalleeSaved(Reg)) {
503 } else {
505 RegsToReload.push_back(Reg);
506 }
507 }
508 }
509
510
511 OpsToSpill.push_back(MI.getNumOperands());
512 unsigned CurOpIdx = 0;
513
514 for (unsigned I = NumDefs; I < MI.getNumOperands(); ++I) {
515 MachineOperand &MO = MI.getOperand(I);
516 if (I == OpsToSpill[CurOpIdx]) {
517 int FI = RegToSlotIdx[MO.getReg()];
518 MIB.addImm(StackMaps::IndirectMemRefOp);
520 assert(MO.isReg() && "Should be register");
522 MIB.addFrameIndex(FI);
523 MIB.addImm(0);
524 ++CurOpIdx;
525 } else {
526 MIB.add(MO);
527 unsigned OldDef;
528 if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(I, &OldDef)) {
529 assert(OldDef < NumDefs);
531 MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1);
532 }
533 }
534 }
535 assert(CurOpIdx == (OpsToSpill.size() - 1) && "Not all operands processed");
536
537 NewMI->setMemRefs(MF, MI.memoperands());
538 for (auto It : RegToSlotIdx) {
545 auto *MMO =
546 MF.getMachineMemOperand(PtrInfo, Flags, getRegisterSize(TRI, R),
547 MFI.getObjectAlign(FrameIndex));
549 }
550
551
552 MI.getParent()->insert(MI, NewMI);
553
554 LLVM_DEBUG(dbgs() << "rewritten statepoint to : " << *NewMI << "\n");
555 MI.eraseFromParent();
556 return NewMI;
557 }
558};
559
560class StatepointProcessor {
561private:
562 MachineFunction &MF;
563 const TargetRegisterInfo &TRI;
564 FrameIndexesCache CacheFI;
565 RegReloadCache ReloadCache;
566
567public:
568 StatepointProcessor(MachineFunction &MF)
569 : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
570 CacheFI(MF.getFrameInfo(), TRI) {}
571
572 bool process(MachineInstr &MI, bool AllowGCPtrInCSR) {
573 StatepointOpers SO(&MI);
574 uint64_t Flags = SO.getFlags();
575
576 if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
577 return false;
578 LLVM_DEBUG(dbgs() << "\nMBB " << MI.getParent()->getNumber() << " "
579 << MI.getParent()->getName() << " : process statepoint "
580 << MI);
581 CallingConv::ID CC = SO.getCallingConv();
582 const uint32_t *Mask = TRI.getCallPreservedMask(MF, CC);
583 StatepointState SS(MI, Mask, CacheFI, AllowGCPtrInCSR);
584 CacheFI.reset(SS.getEHPad());
585
586 if (.findRegistersToSpill())
587 return false;
588
589 SS.spillRegisters();
590 auto *NewStatepoint = SS.rewriteStatepoint();
591 SS.insertReloads(NewStatepoint, ReloadCache);
592 return true;
593 }
594};
595}
596
597bool FixupStatepointCallerSavedImpl::run(MachineFunction &MF) {
599 if (.hasGC())
600 return false;
601
603 for (MachineBasicBlock &BB : MF)
604 for (MachineInstr &I : BB)
605 if (I.getOpcode() == TargetOpcode::STATEPOINT)
607
608 if (Statepoints.empty())
609 return false;
610
612 StatepointProcessor SPP(MF);
613 unsigned NumStatepoints = 0;
615 for (MachineInstr *I : Statepoints) {
616 ++NumStatepoints;
619 AllowGCPtrInCSR = false;
620 Changed |= SPP.process(*I, AllowGCPtrInCSR);
621 }
623}
624
625bool FixupStatepointCallerSavedLegacy::runOnMachineFunction(
626 MachineFunction &MF) {
628 return false;
629
630 return FixupStatepointCallerSavedImpl().run(MF);
631}
632
633PreservedAnalyses
636
637 if (!FixupStatepointCallerSavedImpl().run(MF))
639
642 return PA;
643}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static Register performCopyPropagation(Register Reg, MachineBasicBlock::iterator &RI, bool &IsKill, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI)
Definition FixupStatepointCallerSaved.cpp:115
static cl::opt< bool > PassGCPtrInCSR("fixup-allow-gcptr-in-csr", cl::Hidden, cl::init(false), cl::desc("Allow passing GC Pointer arguments in callee saved registers"))
static cl::opt< unsigned > MaxStatepointsWithRegs("fixup-max-csr-statepoints", cl::Hidden, cl::desc("Max number of statepoints allowed to pass GC Ptrs in registers"))
Fixup Statepoint Caller static false unsigned getRegisterSize(const TargetRegisterInfo &TRI, Register Reg)
Definition FixupStatepointCallerSaved.cpp:97
static cl::opt< bool > FixupSCSExtendSlotSize("fixup-scs-extend-slot-size", cl::Hidden, cl::init(false), cl::desc("Allow spill in spill slot of greater size than register size"), cl::Hidden)
static cl::opt< bool > EnableCopyProp("fixup-scs-enable-copy-propagation", cl::Hidden, cl::init(true), cl::desc("Enable simple copy propagation during register reloading"))
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the SmallSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Definition FixupStatepointCallerSaved.cpp:634
MachineInstr * remove(MachineInstr *I)
Remove the unbundled instruction from the instruction list without deleting it.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Function & getFunction()
Return the LLVM function that this machine code represents.
reverse_iterator getReverse() const
Get a reverse iterator to the same node.
instr_iterator getInstrIterator() const
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void setMemRefs(MachineFunction &MF, ArrayRef< MachineMemOperand * > MemRefs)
Assign this MachineInstr's memory reference descriptor list.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
Flags
Flags values. These may be or'd together.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
constexpr unsigned id() const
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
bool contains(const T &V) const
Check if the SmallSet contains the given element.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
void push_back(const T &Elt)
MI-level Statepoint operands.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
A Use represents the edge between a Value definition and its users.
self_iterator getIterator()
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Define
Register definition.
initializer< Ty > init(const Ty &Val)
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI char & FixupStatepointCallerSavedID
The pass fixups statepoint machine instruction to replace usage of caller saved registers with stack ...
Definition FixupStatepointCallerSaved.cpp:89
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto make_second_range(ContainerTy &&c)
Given a container of pairs, return a range over the second elements.
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void initializeFixupStatepointCallerSavedLegacyPass(PassRegistry &)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.