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) {
74 void getAnalysisUsage(AnalysisUsage &AU)
const override {
79 StringRef getPassName()
const override {
80 return "Fixup Statepoint Caller Saved";
83 bool runOnMachineFunction(MachineFunction &MF)
override;
88char FixupStatepointCallerSavedLegacy::ID = 0;
92 "Fixup Statepoint Caller Saved",
false,
false)
99 return TRI.getSpillSize(*RC);
120 int Idx = RI->findRegisterUseOperandIdx(
Reg, &
TRI,
false);
121 if (Idx >= 0 && (
unsigned)Idx <
StatepointOpers(&*RI).getNumDeoptArgsIdx()) {
132 for (
auto It = ++(RI.
getReverse()); It !=
E; ++It) {
133 if (It->readsRegister(
Reg, &
TRI) && !
Use)
135 if (It->modifiesRegister(
Reg, &
TRI)) {
144 auto DestSrc =
TII.isCopyInstr(*Def);
145 if (!DestSrc || DestSrc->Destination->getReg() !=
Reg)
148 Register SrcReg = DestSrc->Source->getReg();
159 IsKill = DestSrc->Source->isKill();
164 LLVM_DEBUG(
dbgs() <<
"spillRegisters: removing dead copy " << *Def);
165 Def->eraseFromParent();
177using RegSlotPair = std::pair<Register, int>;
180class RegReloadCache {
181 using ReloadSet = SmallSet<RegSlotPair, 8>;
182 DenseMap<const MachineBasicBlock *, ReloadSet> Reloads;
185 RegReloadCache() =
default;
189 bool tryRecordReload(
Register Reg,
int FI,
const MachineBasicBlock *
MBB) {
190 RegSlotPair RSP(
Reg, FI);
191 return Reloads[
MBB].insert(RSP).second;
200class FrameIndexesCache {
202 struct FrameIndexesPerSize {
204 SmallVector<int, 8> Slots;
208 MachineFrameInfo &MFI;
209 const TargetRegisterInfo &TRI;
214 DenseMap<unsigned, FrameIndexesPerSize> Cache;
218 SmallSet<int, 8> ReservedSlots;
223 DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>>
226 FrameIndexesPerSize &getCacheBucket(
unsigned Size) {
233 FrameIndexesCache(MachineFrameInfo &MFI,
const TargetRegisterInfo &TRI)
234 : MFI(MFI), TRI(TRI) {}
238 void reset(
const MachineBasicBlock *EHPad) {
239 for (
auto &It : Cache)
242 ReservedSlots.clear();
244 if (
auto It = GlobalIndices.find(EHPad); It != GlobalIndices.end())
249 int getFrameIndex(
Register Reg, MachineBasicBlock *EHPad) {
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;
261 assert(ReservedSlots.count(FI) &&
"using unreserved slot");
267 FrameIndexesPerSize &
Line = getCacheBucket(
Size);
268 while (
Line.Index <
Line.Slots.size()) {
270 if (ReservedSlots.count(FI))
274 if (MFI.getObjectSize(FI) <
Size) {
275 MFI.setObjectSize(FI,
Size);
277 NumSpillSlotsExtended++;
282 NumSpillSlotsAllocated++;
283 Line.Slots.push_back(FI);
288 GlobalIndices[EHPad].push_back(std::make_pair(
Reg, FI));
300 void sortRegisters(SmallVectorImpl<Register> &Regs) {
310class StatepointState {
316 MachineBasicBlock *EHPad;
317 const TargetRegisterInfo &TRI;
318 const TargetInstrInfo &TII;
319 MachineFrameInfo &MFI;
321 const uint32_t *Mask;
323 FrameIndexesCache &CacheFI;
324 bool AllowGCPtrInCSR;
326 SmallVector<unsigned, 8> OpsToSpill;
332 DenseMap<Register, int> RegToSlotIdx;
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) {
346 [](MachineInstr &
I) {
347 return I.getOpcode() == TargetOpcode::STATEPOINT;
353 auto IsEHPad = [](MachineBasicBlock *
B) {
return B->isEHPad(); };
362 MachineBasicBlock *getEHPad()
const {
return EHPad; }
366 return (Mask[
Reg.
id() / 32] >> (
Reg.
id() % 32)) & 1;
372 bool findRegistersToSpill() {
373 SmallSet<Register, 8> GCRegs;
376 for (
const auto &Def : MI.defs())
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);
389 if (isCalleeSaved(
Reg) && (AllowGCPtrInCSR || !GCRegs.
contains(
Reg)))
396 RegsToSpill.push_back(
Reg);
397 OpsToSpill.push_back(Idx);
399 CacheFI.sortRegisters(RegsToSpill);
400 return !RegsToSpill.empty();
405 void spillRegisters() {
407 int FI = CacheFI.getFrameIndex(
Reg, EHPad);
409 NumSpilledRegisters++;
410 RegToSlotIdx[
Reg] = FI;
419 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(
Reg);
422 TII.storeRegToStackSlot(*MI.getParent(), InsertBefore,
Reg, IsKill, FI,
428 MachineBasicBlock *
MBB) {
429 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(
Reg);
430 int FI = RegToSlotIdx[
Reg];
432 TII.loadRegFromStackSlot(*
MBB, It,
Reg, FI, RC, &TRI,
Register());
440 TII.loadRegFromStackSlot(*
MBB, It,
Reg, FI, RC, &TRI,
Register());
441 MachineInstr *Reload = It->getPrevNode();
444 assert(TII.isLoadFromStackSlot(*Reload, Dummy) ==
Reg);
451 void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) {
453 auto InsertPoint = std::next(NewStatepoint->
getIterator());
455 for (
auto Reg : RegsToReload) {
456 insertReloadBefore(
Reg, InsertPoint,
MBB);
458 << RegToSlotIdx[
Reg] <<
" after statepoint\n");
460 if (EHPad && RC.tryRecordReload(
Reg, RegToSlotIdx[
Reg], EHPad)) {
461 auto EHPadInsertPoint =
462 EHPad->SkipPHIsLabelsAndDebug(EHPad->begin(),
Reg);
463 insertReloadBefore(
Reg, EHPadInsertPoint, EHPad);
472 MachineInstr *rewriteStatepoint() {
473 MachineInstr *NewMI =
474 MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(),
true);
475 MachineInstrBuilder MIB(MF, NewMI);
477 unsigned NumOps = MI.getNumOperands();
480 SmallVector<unsigned, 8> NewIndices;
481 unsigned NumDefs = MI.getNumDefs();
482 for (
unsigned I = 0;
I < NumDefs; ++
I) {
483 MachineOperand &DefMO = MI.getOperand(
I);
489 if (MI.getOperand(MI.findTiedOperandIdx(
I)).isUndef()) {
490 if (AllowGCPtrInCSR) {
496 if (!AllowGCPtrInCSR) {
498 RegsToReload.push_back(
Reg);
500 if (isCalleeSaved(
Reg)) {
505 RegsToReload.push_back(
Reg);
511 OpsToSpill.push_back(MI.getNumOperands());
512 unsigned CurOpIdx = 0;
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);
522 MIB.addFrameIndex(FI);
528 if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(
I, &OldDef)) {
531 MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1);
535 assert(CurOpIdx == (OpsToSpill.size() - 1) &&
"Not all operands processed");
538 for (
auto It : RegToSlotIdx) {
547 MFI.getObjectAlign(FrameIndex));
552 MI.getParent()->insert(MI, NewMI);
554 LLVM_DEBUG(
dbgs() <<
"rewritten statepoint to : " << *NewMI <<
"\n");
555 MI.eraseFromParent();
560class StatepointProcessor {
563 const TargetRegisterInfo &TRI;
564 FrameIndexesCache CacheFI;
565 RegReloadCache ReloadCache;
568 StatepointProcessor(MachineFunction &MF)
569 : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
570 CacheFI(MF.getFrameInfo(), TRI) {}
572 bool process(MachineInstr &
MI,
bool AllowGCPtrInCSR) {
573 StatepointOpers SO(&
MI);
574 uint64_t
Flags = SO.getFlags();
576 if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
579 <<
MI.getParent()->getName() <<
" : process statepoint "
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());
586 if (!
SS.findRegistersToSpill())
590 auto *NewStatepoint =
SS.rewriteStatepoint();
591 SS.insertReloads(NewStatepoint, ReloadCache);
603 for (MachineBasicBlock &BB : MF)
604 for (MachineInstr &
I : BB)
605 if (
I.getOpcode() == TargetOpcode::STATEPOINT)
608 if (Statepoints.
empty())
612 StatepointProcessor SPP(MF);
613 unsigned NumStatepoints = 0;
615 for (MachineInstr *
I : Statepoints) {
619 AllowGCPtrInCSR =
false;
620 Changed |= SPP.process(*
I, AllowGCPtrInCSR);
625bool FixupStatepointCallerSavedLegacy::runOnMachineFunction(
626 MachineFunction &MF) {
630 return FixupStatepointCallerSavedImpl().run(MF);
637 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 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 ...
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.