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 {
77 StringRef getPassName()
const override {
78 return "Fixup Statepoint Caller Saved";
81 bool runOnMachineFunction(MachineFunction &MF)
override;
86char FixupStatepointCallerSavedLegacy::ID = 0;
90 "Fixup Statepoint Caller Saved",
false,
false)
97 return TRI.getSpillSize(*RC);
118 int Idx = RI->findRegisterUseOperandIdx(
Reg, &
TRI,
false);
119 if (Idx >= 0 && (
unsigned)Idx <
StatepointOpers(&*RI).getNumDeoptArgsIdx()) {
130 for (
auto It = ++(RI.
getReverse()); It !=
E; ++It) {
131 if (It->readsRegister(
Reg, &
TRI) && !
Use)
133 if (It->modifiesRegister(
Reg, &
TRI)) {
142 auto DestSrc =
TII.isCopyInstr(*Def);
143 if (!DestSrc || DestSrc->Destination->getReg() !=
Reg)
146 Register SrcReg = DestSrc->Source->getReg();
157 IsKill = DestSrc->Source->isKill();
162 LLVM_DEBUG(
dbgs() <<
"spillRegisters: removing dead copy " << *Def);
163 Def->eraseFromParent();
175using RegSlotPair = std::pair<Register, int>;
178class RegReloadCache {
179 using ReloadSet = SmallSet<RegSlotPair, 8>;
180 DenseMap<const MachineBasicBlock *, ReloadSet> Reloads;
183 RegReloadCache() =
default;
187 bool tryRecordReload(
Register Reg,
int FI,
const MachineBasicBlock *
MBB) {
188 RegSlotPair RSP(
Reg, FI);
189 return Reloads[
MBB].insert(RSP).second;
198class FrameIndexesCache {
200 struct FrameIndexesPerSize {
202 SmallVector<int, 8> Slots;
206 MachineFrameInfo &MFI;
207 const TargetRegisterInfo &TRI;
212 DenseMap<unsigned, FrameIndexesPerSize> Cache;
216 SmallSet<int, 8> ReservedSlots;
221 DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>>
224 FrameIndexesPerSize &getCacheBucket(
unsigned Size) {
231 FrameIndexesCache(MachineFrameInfo &MFI,
const TargetRegisterInfo &TRI)
232 : MFI(MFI), TRI(TRI) {}
236 void reset(
const MachineBasicBlock *EHPad) {
237 for (
auto &It : Cache)
240 ReservedSlots.clear();
242 if (
auto It = GlobalIndices.find(EHPad); It != GlobalIndices.end())
247 int getFrameIndex(
Register Reg, MachineBasicBlock *EHPad) {
249 auto It = GlobalIndices.find(EHPad);
250 if (It != GlobalIndices.end()) {
251 auto &Vec = It->second;
253 Vec, [
Reg](RegSlotPair &RSP) {
return Reg == RSP.first; });
254 if (Idx != Vec.end()) {
255 int FI = Idx->second;
259 assert(ReservedSlots.count(FI) &&
"using unreserved slot");
265 FrameIndexesPerSize &
Line = getCacheBucket(
Size);
266 while (
Line.Index <
Line.Slots.size()) {
268 if (ReservedSlots.count(FI))
272 if (MFI.getObjectSize(FI) <
Size) {
273 MFI.setObjectSize(FI,
Size);
275 NumSpillSlotsExtended++;
280 NumSpillSlotsAllocated++;
281 Line.Slots.push_back(FI);
286 GlobalIndices[EHPad].push_back(std::make_pair(
Reg, FI));
298 void sortRegisters(SmallVectorImpl<Register> &Regs) {
308class StatepointState {
314 MachineBasicBlock *EHPad;
315 const TargetRegisterInfo &TRI;
316 const TargetInstrInfo &TII;
317 MachineFrameInfo &MFI;
319 const uint32_t *Mask;
321 FrameIndexesCache &CacheFI;
322 bool AllowGCPtrInCSR;
324 SmallVector<unsigned, 8> OpsToSpill;
330 DenseMap<Register, int> RegToSlotIdx;
333 StatepointState(MachineInstr &MI,
const uint32_t *Mask,
334 FrameIndexesCache &CacheFI,
bool AllowGCPtrInCSR)
335 : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
336 TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
337 Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) {
344 [](MachineInstr &
I) {
345 return I.getOpcode() == TargetOpcode::STATEPOINT;
351 auto IsEHPad = [](MachineBasicBlock *
B) {
return B->isEHPad(); };
360 MachineBasicBlock *getEHPad()
const {
return EHPad; }
364 return (Mask[
Reg.
id() / 32] >> (
Reg.
id() % 32)) & 1;
370 bool findRegistersToSpill() {
371 SmallSet<Register, 8> GCRegs;
374 for (
const auto &Def : MI.defs())
377 SmallSet<Register, 8> VisitedRegs;
378 for (
unsigned Idx = StatepointOpers(&MI).getVarIdx(),
379 EndIdx = MI.getNumOperands();
380 Idx < EndIdx; ++Idx) {
381 MachineOperand &MO = MI.getOperand(Idx);
387 if (isCalleeSaved(
Reg) && (AllowGCPtrInCSR || !GCRegs.
contains(
Reg)))
394 RegsToSpill.push_back(
Reg);
395 OpsToSpill.push_back(Idx);
397 CacheFI.sortRegisters(RegsToSpill);
398 return !RegsToSpill.empty();
403 void spillRegisters() {
405 int FI = CacheFI.getFrameIndex(
Reg, EHPad);
407 NumSpilledRegisters++;
408 RegToSlotIdx[
Reg] = FI;
420 TII.storeRegToStackSlot(*MI.getParent(), InsertBefore,
Reg, IsKill, FI,
426 MachineBasicBlock *
MBB) {
428 int FI = RegToSlotIdx[
Reg];
439 MachineInstr *Reload = It->getPrevNode();
442 assert(TII.isLoadFromStackSlot(*Reload, Dummy) ==
Reg);
449 void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) {
451 auto InsertPoint = std::next(NewStatepoint->
getIterator());
453 for (
auto Reg : RegsToReload) {
454 insertReloadBefore(
Reg, InsertPoint,
MBB);
456 << RegToSlotIdx[
Reg] <<
" after statepoint\n");
458 if (EHPad && RC.tryRecordReload(
Reg, RegToSlotIdx[
Reg], EHPad)) {
459 auto EHPadInsertPoint =
460 EHPad->SkipPHIsLabelsAndDebug(EHPad->begin(),
Reg);
461 insertReloadBefore(
Reg, EHPadInsertPoint, EHPad);
470 MachineInstr *rewriteStatepoint() {
471 MachineInstr *NewMI =
472 MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(),
true);
473 MachineInstrBuilder MIB(MF, NewMI);
475 unsigned NumOps = MI.getNumOperands();
478 SmallVector<unsigned, 8> NewIndices;
479 unsigned NumDefs = MI.getNumDefs();
480 for (
unsigned I = 0;
I < NumDefs; ++
I) {
481 MachineOperand &DefMO = MI.getOperand(
I);
487 if (MI.getOperand(MI.findTiedOperandIdx(
I)).isUndef()) {
488 if (AllowGCPtrInCSR) {
490 MIB.addReg(
Reg, RegState::Define);
494 if (!AllowGCPtrInCSR) {
496 RegsToReload.push_back(
Reg);
498 if (isCalleeSaved(
Reg)) {
500 MIB.addReg(
Reg, RegState::Define);
503 RegsToReload.push_back(
Reg);
509 OpsToSpill.push_back(MI.getNumOperands());
510 unsigned CurOpIdx = 0;
512 for (
unsigned I = NumDefs;
I < MI.getNumOperands(); ++
I) {
513 MachineOperand &MO = MI.getOperand(
I);
514 if (
I == OpsToSpill[CurOpIdx]) {
515 int FI = RegToSlotIdx[MO.
getReg()];
516 MIB.addImm(StackMaps::IndirectMemRefOp);
520 MIB.addFrameIndex(FI);
526 if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(
I, &OldDef)) {
529 MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1);
533 assert(CurOpIdx == (OpsToSpill.size() - 1) &&
"Not all operands processed");
536 for (
auto It : RegToSlotIdx) {
545 MFI.getObjectAlign(FrameIndex));
550 MI.getParent()->insert(MI, NewMI);
552 LLVM_DEBUG(
dbgs() <<
"rewritten statepoint to : " << *NewMI <<
"\n");
553 MI.eraseFromParent();
558class StatepointProcessor {
561 const TargetRegisterInfo &TRI;
562 FrameIndexesCache CacheFI;
563 RegReloadCache ReloadCache;
566 StatepointProcessor(MachineFunction &MF)
567 : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
568 CacheFI(MF.getFrameInfo(), TRI) {}
570 bool process(MachineInstr &
MI,
bool AllowGCPtrInCSR) {
571 StatepointOpers SO(&
MI);
572 uint64_t
Flags = SO.getFlags();
574 if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
577 <<
MI.getParent()->getName() <<
" : process statepoint "
579 CallingConv::ID CC = SO.getCallingConv();
580 const uint32_t *
Mask = TRI.getCallPreservedMask(MF, CC);
581 StatepointState
SS(
MI, Mask, CacheFI, AllowGCPtrInCSR);
582 CacheFI.reset(
SS.getEHPad());
584 if (!
SS.findRegistersToSpill())
588 auto *NewStatepoint =
SS.rewriteStatepoint();
589 SS.insertReloads(NewStatepoint, ReloadCache);
601 for (MachineBasicBlock &BB : MF)
602 for (MachineInstr &
I : BB)
603 if (
I.getOpcode() == TargetOpcode::STATEPOINT)
606 if (Statepoints.
empty())
610 StatepointProcessor SPP(MF);
611 unsigned NumStatepoints = 0;
613 for (MachineInstr *
I : Statepoints) {
617 AllowGCPtrInCSR =
false;
618 Changed |= SPP.process(*
I, AllowGCPtrInCSR);
623bool FixupStatepointCallerSavedLegacy::runOnMachineFunction(
624 MachineFunction &MF) {
628 return FixupStatepointCallerSavedImpl().run(MF);
635 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.
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.