37#define DEBUG_TYPE "fixup-statepoint-caller-saved"
38STATISTIC(NumSpilledRegisters,
"Number of spilled register");
39STATISTIC(NumSpillSlotsAllocated,
"Number of spill slots allocated");
40STATISTIC(NumSpillSlotsExtended,
"Number of spill slots extended");
44 cl::desc(
"Allow spill in spill slot of greater size than register size"),
49 cl::desc(
"Allow passing GC Pointer arguments in callee saved registers"));
53 cl::desc(
"Enable simple copy propagation during register reloading"));
59 cl::desc(
"Max number of statepoints allowed to pass GC Ptrs in registers"));
63struct FixupStatepointCallerSavedImpl {
71 FixupStatepointCallerSavedLegacy() : MachineFunctionPass(ID) {}
72 void getAnalysisUsage(AnalysisUsage &AU)
const override {
78 StringRef getPassName()
const override {
79 return "Fixup Statepoint Caller Saved";
82 bool runOnMachineFunction(MachineFunction &MF)
override;
87char FixupStatepointCallerSavedLegacy::ID = 0;
91 "Fixup Statepoint Caller Saved",
false,
false)
98 return TRI.getSpillSize(*RC);
119 int Idx = RI->findRegisterUseOperandIdx(
Reg, &
TRI,
false);
120 if (Idx >= 0 && (
unsigned)Idx <
StatepointOpers(&*RI).getNumDeoptArgsIdx()) {
131 for (
auto It = ++(RI.
getReverse()); It !=
E; ++It) {
132 if (It->readsRegister(
Reg, &
TRI) && !
Use)
134 if (It->modifiesRegister(
Reg, &
TRI)) {
143 auto DestSrc =
TII.isCopyInstr(*Def);
144 if (!DestSrc || DestSrc->Destination->getReg() !=
Reg)
147 Register SrcReg = DestSrc->Source->getReg();
158 IsKill = DestSrc->Source->isKill();
163 LLVM_DEBUG(
dbgs() <<
"spillRegisters: removing dead copy " << *Def);
164 Def->eraseFromParent();
176using RegSlotPair = std::pair<Register, int>;
179class RegReloadCache {
180 using ReloadSet = SmallSet<RegSlotPair, 8>;
181 DenseMap<const MachineBasicBlock *, ReloadSet> Reloads;
184 RegReloadCache() =
default;
188 bool tryRecordReload(
Register Reg,
int FI,
const MachineBasicBlock *
MBB) {
189 RegSlotPair RSP(
Reg, FI);
190 return Reloads[
MBB].insert(RSP).second;
199class FrameIndexesCache {
201 struct FrameIndexesPerSize {
203 SmallVector<int, 8> Slots;
207 MachineFrameInfo &MFI;
208 const TargetRegisterInfo &TRI;
213 DenseMap<unsigned, FrameIndexesPerSize> Cache;
217 SmallSet<int, 8> ReservedSlots;
222 DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>>
225 FrameIndexesPerSize &getCacheBucket(
unsigned Size) {
232 FrameIndexesCache(MachineFrameInfo &MFI,
const TargetRegisterInfo &TRI)
233 : MFI(MFI), TRI(TRI) {}
237 void reset(
const MachineBasicBlock *EHPad) {
238 for (
auto &It : Cache)
241 ReservedSlots.clear();
243 if (
auto It = GlobalIndices.find(EHPad); It != GlobalIndices.end())
248 int getFrameIndex(
Register Reg, MachineBasicBlock *EHPad) {
250 auto It = GlobalIndices.find(EHPad);
251 if (It != GlobalIndices.end()) {
252 auto &Vec = It->second;
254 Vec, [
Reg](RegSlotPair &RSP) {
return Reg == RSP.first; });
255 if (Idx != Vec.end()) {
256 int FI = Idx->second;
260 assert(ReservedSlots.count(FI) &&
"using unreserved slot");
266 FrameIndexesPerSize &
Line = getCacheBucket(
Size);
267 while (
Line.Index <
Line.Slots.size()) {
269 if (ReservedSlots.count(FI))
273 if (MFI.getObjectSize(FI) <
Size) {
274 MFI.setObjectSize(FI,
Size);
276 NumSpillSlotsExtended++;
281 NumSpillSlotsAllocated++;
282 Line.Slots.push_back(FI);
287 GlobalIndices[EHPad].push_back(std::make_pair(
Reg, FI));
299 void sortRegisters(SmallVectorImpl<Register> &Regs) {
309class StatepointState {
315 MachineBasicBlock *EHPad;
316 const TargetRegisterInfo &TRI;
317 const TargetInstrInfo &TII;
318 MachineFrameInfo &MFI;
320 const uint32_t *Mask;
322 FrameIndexesCache &CacheFI;
323 bool AllowGCPtrInCSR;
325 SmallVector<unsigned, 8> OpsToSpill;
331 DenseMap<Register, int> RegToSlotIdx;
334 StatepointState(MachineInstr &MI,
const uint32_t *Mask,
335 FrameIndexesCache &CacheFI,
bool AllowGCPtrInCSR)
336 : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
337 TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
338 Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) {
345 [](MachineInstr &
I) {
346 return I.getOpcode() == TargetOpcode::STATEPOINT;
352 auto IsEHPad = [](MachineBasicBlock *
B) {
return B->isEHPad(); };
361 MachineBasicBlock *getEHPad()
const {
return EHPad; }
365 return (Mask[
Reg.
id() / 32] >> (
Reg.
id() % 32)) & 1;
371 bool findRegistersToSpill() {
372 SmallSet<Register, 8> GCRegs;
375 for (
const auto &Def : MI.defs())
378 SmallSet<Register, 8> VisitedRegs;
379 for (
unsigned Idx = StatepointOpers(&MI).getVarIdx(),
380 EndIdx = MI.getNumOperands();
381 Idx < EndIdx; ++Idx) {
382 MachineOperand &MO = MI.getOperand(Idx);
388 if (isCalleeSaved(
Reg) && (AllowGCPtrInCSR || !GCRegs.
contains(
Reg)))
395 RegsToSpill.push_back(
Reg);
396 OpsToSpill.push_back(Idx);
398 CacheFI.sortRegisters(RegsToSpill);
399 return !RegsToSpill.empty();
404 void spillRegisters() {
406 int FI = CacheFI.getFrameIndex(
Reg, EHPad);
408 NumSpilledRegisters++;
409 RegToSlotIdx[
Reg] = FI;
421 TII.storeRegToStackSlot(*MI.getParent(), InsertBefore,
Reg, IsKill, FI,
427 MachineBasicBlock *
MBB) {
429 int FI = RegToSlotIdx[
Reg];
440 MachineInstr *Reload = It->getPrevNode();
443 assert(TII.isLoadFromStackSlot(*Reload, Dummy) ==
Reg);
450 void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) {
452 auto InsertPoint = std::next(NewStatepoint->
getIterator());
454 for (
auto Reg : RegsToReload) {
455 insertReloadBefore(
Reg, InsertPoint,
MBB);
457 << RegToSlotIdx[
Reg] <<
" after statepoint\n");
459 if (EHPad && RC.tryRecordReload(
Reg, RegToSlotIdx[
Reg], EHPad)) {
460 auto EHPadInsertPoint =
461 EHPad->SkipPHIsLabelsAndDebug(EHPad->begin(),
Reg);
462 insertReloadBefore(
Reg, EHPadInsertPoint, EHPad);
471 MachineInstr *rewriteStatepoint() {
472 MachineInstr *NewMI =
473 MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(),
true);
474 MachineInstrBuilder MIB(MF, NewMI);
476 unsigned NumOps = MI.getNumOperands();
479 SmallVector<unsigned, 8> NewIndices;
480 unsigned NumDefs = MI.getNumDefs();
481 for (
unsigned I = 0;
I < NumDefs; ++
I) {
482 MachineOperand &DefMO = MI.getOperand(
I);
488 if (MI.getOperand(MI.findTiedOperandIdx(
I)).isUndef()) {
489 if (AllowGCPtrInCSR) {
491 MIB.addReg(
Reg, RegState::Define);
495 if (!AllowGCPtrInCSR) {
497 RegsToReload.push_back(
Reg);
499 if (isCalleeSaved(
Reg)) {
501 MIB.addReg(
Reg, RegState::Define);
504 RegsToReload.push_back(
Reg);
510 OpsToSpill.push_back(MI.getNumOperands());
511 unsigned CurOpIdx = 0;
513 for (
unsigned I = NumDefs;
I < MI.getNumOperands(); ++
I) {
514 MachineOperand &MO = MI.getOperand(
I);
515 if (
I == OpsToSpill[CurOpIdx]) {
516 int FI = RegToSlotIdx[MO.
getReg()];
517 MIB.addImm(StackMaps::IndirectMemRefOp);
521 MIB.addFrameIndex(FI);
527 if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(
I, &OldDef)) {
530 MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1);
534 assert(CurOpIdx == (OpsToSpill.size() - 1) &&
"Not all operands processed");
537 for (
auto It : RegToSlotIdx) {
546 MFI.getObjectAlign(FrameIndex));
551 MI.getParent()->insert(MI, NewMI);
553 LLVM_DEBUG(
dbgs() <<
"rewritten statepoint to : " << *NewMI <<
"\n");
554 MI.eraseFromParent();
559class StatepointProcessor {
562 const TargetRegisterInfo &TRI;
563 FrameIndexesCache CacheFI;
564 RegReloadCache ReloadCache;
567 StatepointProcessor(MachineFunction &MF)
568 : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
569 CacheFI(MF.getFrameInfo(), TRI) {}
571 bool process(MachineInstr &
MI,
bool AllowGCPtrInCSR) {
572 StatepointOpers SO(&
MI);
573 uint64_t
Flags = SO.getFlags();
575 if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
578 <<
MI.getParent()->getName() <<
" : process statepoint "
580 CallingConv::ID CC = SO.getCallingConv();
581 const uint32_t *
Mask = TRI.getCallPreservedMask(MF, CC);
582 StatepointState
SS(
MI, Mask, CacheFI, AllowGCPtrInCSR);
583 CacheFI.reset(
SS.getEHPad());
585 if (!
SS.findRegistersToSpill())
589 auto *NewStatepoint =
SS.rewriteStatepoint();
590 SS.insertReloads(NewStatepoint, ReloadCache);
602 for (MachineBasicBlock &BB : MF)
603 for (MachineInstr &
I : BB)
604 if (
I.getOpcode() == TargetOpcode::STATEPOINT)
607 if (Statepoints.
empty())
611 StatepointProcessor SPP(MF);
612 unsigned NumStatepoints = 0;
614 for (MachineInstr *
I : Statepoints) {
618 AllowGCPtrInCSR =
false;
619 Changed |= SPP.process(*
I, AllowGCPtrInCSR);
624bool FixupStatepointCallerSavedLegacy::runOnMachineFunction(
625 MachineFunction &MF) {
629 return FixupStatepointCallerSavedImpl().run(MF);
636 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)
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
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.
LLVM_ABI 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.
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.
MCRegisterClass TargetRegisterClass
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.