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");
43 cl::desc(
"Allow spill in spill slot of greater size than register size"),
48 cl::desc(
"Allow passing GC Pointer arguments in callee saved registers"));
52 cl::desc(
"Enable simple copy propagation during register reloading"));
58 cl::desc(
"Max number of statepoints allowed to pass GC Ptrs in registers"));
62struct FixupStatepointCallerSavedImpl {
70 FixupStatepointCallerSavedLegacy() : MachineFunctionPass(ID) {}
71 void getAnalysisUsage(AnalysisUsage &AU)
const override {
76 StringRef getPassName()
const override {
77 return "Fixup Statepoint Caller Saved";
80 bool runOnMachineFunction(MachineFunction &MF)
override;
85char FixupStatepointCallerSavedLegacy::ID = 0;
89 "Fixup Statepoint Caller Saved",
false,
false)
96 return TRI.getSpillSize(*RC);
117 int Idx = RI->findRegisterUseOperandIdx(
Reg, &
TRI,
false);
118 if (Idx >= 0 && (
unsigned)Idx <
StatepointOpers(&*RI).getNumDeoptArgsIdx()) {
129 for (
auto It = ++(RI.
getReverse()); It !=
E; ++It) {
130 if (It->readsRegister(
Reg, &
TRI) && !
Use)
132 if (It->modifiesRegister(
Reg, &
TRI)) {
141 auto DestSrc =
TII.isCopyInstr(*Def);
142 if (!DestSrc || DestSrc->Destination->getReg() !=
Reg)
145 Register SrcReg = DestSrc->Source->getReg();
156 IsKill = DestSrc->Source->isKill();
161 LLVM_DEBUG(
dbgs() <<
"spillRegisters: removing dead copy " << *Def);
162 Def->eraseFromParent();
174using RegSlotPair = std::pair<Register, int>;
177class RegReloadCache {
178 using ReloadSet = SmallSet<RegSlotPair, 8>;
179 DenseMap<const MachineBasicBlock *, ReloadSet> Reloads;
182 RegReloadCache() =
default;
186 bool tryRecordReload(
Register Reg,
int FI,
const MachineBasicBlock *
MBB) {
187 RegSlotPair RSP(
Reg, FI);
188 return Reloads[
MBB].insert(RSP).second;
197class FrameIndexesCache {
199 struct FrameIndexesPerSize {
201 SmallVector<int, 8> Slots;
205 MachineFrameInfo &MFI;
206 const TargetRegisterInfo &TRI;
211 DenseMap<unsigned, FrameIndexesPerSize> Cache;
215 SmallSet<int, 8> ReservedSlots;
220 DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>>
223 FrameIndexesPerSize &getCacheBucket(
unsigned Size) {
230 FrameIndexesCache(MachineFrameInfo &MFI,
const TargetRegisterInfo &TRI)
231 : MFI(MFI), TRI(TRI) {}
235 void reset(
const MachineBasicBlock *EHPad) {
236 for (
auto &It : Cache)
239 ReservedSlots.clear();
241 if (
auto It = GlobalIndices.find(EHPad); It != GlobalIndices.end())
246 int getFrameIndex(
Register Reg, MachineBasicBlock *EHPad) {
248 auto It = GlobalIndices.find(EHPad);
249 if (It != GlobalIndices.end()) {
250 auto &Vec = It->second;
252 Vec, [
Reg](RegSlotPair &RSP) {
return Reg == RSP.first; });
253 if (Idx != Vec.end()) {
254 int FI = Idx->second;
258 assert(ReservedSlots.count(FI) &&
"using unreserved slot");
264 FrameIndexesPerSize &
Line = getCacheBucket(
Size);
265 while (
Line.Index <
Line.Slots.size()) {
267 if (ReservedSlots.count(FI))
271 if (MFI.getObjectSize(FI) <
Size) {
272 MFI.setObjectSize(FI,
Size);
274 NumSpillSlotsExtended++;
279 NumSpillSlotsAllocated++;
280 Line.Slots.push_back(FI);
285 GlobalIndices[EHPad].push_back(std::make_pair(
Reg, FI));
297 void sortRegisters(SmallVectorImpl<Register> &Regs) {
307class StatepointState {
313 MachineBasicBlock *EHPad;
314 const TargetRegisterInfo &TRI;
315 const TargetInstrInfo &TII;
316 MachineFrameInfo &MFI;
318 const uint32_t *Mask;
320 FrameIndexesCache &CacheFI;
321 bool AllowGCPtrInCSR;
323 SmallVector<unsigned, 8> OpsToSpill;
329 DenseMap<Register, int> RegToSlotIdx;
332 StatepointState(MachineInstr &MI,
const uint32_t *Mask,
333 FrameIndexesCache &CacheFI,
bool AllowGCPtrInCSR)
334 : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
335 TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
336 Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) {
343 [](MachineInstr &
I) {
344 return I.getOpcode() == TargetOpcode::STATEPOINT;
350 auto IsEHPad = [](MachineBasicBlock *
B) {
return B->isEHPad(); };
359 MachineBasicBlock *getEHPad()
const {
return EHPad; }
363 return (Mask[
Reg.
id() / 32] >> (
Reg.
id() % 32)) & 1;
369 bool findRegistersToSpill() {
370 SmallSet<Register, 8> GCRegs;
373 for (
const auto &Def : MI.defs())
376 SmallSet<Register, 8> VisitedRegs;
377 for (
unsigned Idx = StatepointOpers(&MI).getVarIdx(),
378 EndIdx = MI.getNumOperands();
379 Idx < EndIdx; ++Idx) {
380 MachineOperand &MO = MI.getOperand(Idx);
386 if (isCalleeSaved(
Reg) && (AllowGCPtrInCSR || !GCRegs.
contains(
Reg)))
393 RegsToSpill.push_back(
Reg);
394 OpsToSpill.push_back(Idx);
396 CacheFI.sortRegisters(RegsToSpill);
397 return !RegsToSpill.empty();
402 void spillRegisters() {
404 int FI = CacheFI.getFrameIndex(
Reg, EHPad);
406 NumSpilledRegisters++;
407 RegToSlotIdx[
Reg] = FI;
416 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(
Reg);
419 TII.storeRegToStackSlot(*MI.getParent(), InsertBefore,
Reg, IsKill, FI,
425 MachineBasicBlock *
MBB) {
426 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(
Reg);
427 int FI = RegToSlotIdx[
Reg];
438 MachineInstr *Reload = It->getPrevNode();
441 assert(TII.isLoadFromStackSlot(*Reload, Dummy) ==
Reg);
448 void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) {
450 auto InsertPoint = std::next(NewStatepoint->
getIterator());
452 for (
auto Reg : RegsToReload) {
453 insertReloadBefore(
Reg, InsertPoint,
MBB);
455 << RegToSlotIdx[
Reg] <<
" after statepoint\n");
457 if (EHPad && RC.tryRecordReload(
Reg, RegToSlotIdx[
Reg], EHPad)) {
458 auto EHPadInsertPoint =
459 EHPad->SkipPHIsLabelsAndDebug(EHPad->begin(),
Reg);
460 insertReloadBefore(
Reg, EHPadInsertPoint, EHPad);
469 MachineInstr *rewriteStatepoint() {
470 MachineInstr *NewMI =
471 MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(),
true);
472 MachineInstrBuilder MIB(MF, NewMI);
474 unsigned NumOps = MI.getNumOperands();
477 SmallVector<unsigned, 8> NewIndices;
478 unsigned NumDefs = MI.getNumDefs();
479 for (
unsigned I = 0;
I < NumDefs; ++
I) {
480 MachineOperand &DefMO = MI.getOperand(
I);
486 if (MI.getOperand(MI.findTiedOperandIdx(
I)).isUndef()) {
487 if (AllowGCPtrInCSR) {
493 if (!AllowGCPtrInCSR) {
495 RegsToReload.push_back(
Reg);
497 if (isCalleeSaved(
Reg)) {
502 RegsToReload.push_back(
Reg);
508 OpsToSpill.push_back(MI.getNumOperands());
509 unsigned CurOpIdx = 0;
511 for (
unsigned I = NumDefs;
I < MI.getNumOperands(); ++
I) {
512 MachineOperand &MO = MI.getOperand(
I);
513 if (
I == OpsToSpill[CurOpIdx]) {
514 int FI = RegToSlotIdx[MO.
getReg()];
515 MIB.addImm(StackMaps::IndirectMemRefOp);
519 MIB.addFrameIndex(FI);
525 if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(
I, &OldDef)) {
528 MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1);
532 assert(CurOpIdx == (OpsToSpill.size() - 1) &&
"Not all operands processed");
535 for (
auto It : RegToSlotIdx) {
544 MFI.getObjectAlign(FrameIndex));
549 MI.getParent()->insert(MI, NewMI);
551 LLVM_DEBUG(
dbgs() <<
"rewritten statepoint to : " << *NewMI <<
"\n");
552 MI.eraseFromParent();
557class StatepointProcessor {
560 const TargetRegisterInfo &TRI;
561 FrameIndexesCache CacheFI;
562 RegReloadCache ReloadCache;
565 StatepointProcessor(MachineFunction &MF)
566 : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
567 CacheFI(MF.getFrameInfo(), TRI) {}
569 bool process(MachineInstr &
MI,
bool AllowGCPtrInCSR) {
570 StatepointOpers SO(&
MI);
571 uint64_t
Flags = SO.getFlags();
573 if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
576 <<
MI.getParent()->getName() <<
" : process statepoint "
578 CallingConv::ID CC = SO.getCallingConv();
579 const uint32_t *
Mask = TRI.getCallPreservedMask(MF, CC);
580 StatepointState
SS(
MI, Mask, CacheFI, AllowGCPtrInCSR);
581 CacheFI.reset(
SS.getEHPad());
583 if (!
SS.findRegistersToSpill())
587 auto *NewStatepoint =
SS.rewriteStatepoint();
588 SS.insertReloads(NewStatepoint, ReloadCache);
600 for (MachineBasicBlock &BB : MF)
601 for (MachineInstr &
I : BB)
602 if (
I.getOpcode() == TargetOpcode::STATEPOINT)
605 if (Statepoints.
empty())
609 StatepointProcessor SPP(MF);
610 unsigned NumStatepoints = 0;
612 for (MachineInstr *
I : Statepoints) {
616 AllowGCPtrInCSR =
false;
617 Changed |= SPP.process(*
I, AllowGCPtrInCSR);
622bool FixupStatepointCallerSavedLegacy::runOnMachineFunction(
623 MachineFunction &MF) {
627 return FixupStatepointCallerSavedImpl().run(MF);
634 if (!FixupStatepointCallerSavedImpl().
run(MF))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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)
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)
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 HexagonInstrInfo * TII
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)
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 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 ...
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.
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.