blob: 6d31097778ca9a643138003e3998c1475efbae4d [file] [log] [blame]
Serguei Katkov4275eb12020-04-09 18:40:53 +07001//===-- FixupStatepointCallerSaved.cpp - Fixup caller saved registers ----===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// Statepoint instruction in deopt parameters contains values which are
12/// meaningful to the runtime and should be able to be read at the moment the
13/// call returns. So we can say that we need to encode the fact that these
14/// values are "late read" by runtime. If we could express this notion for
15/// register allocator it would produce the right form for us.
16/// The need to fixup (i.e this pass) is specifically handling the fact that
17/// we cannot describe such a late read for the register allocator.
18/// Register allocator may put the value on a register clobbered by the call.
19/// This pass forces the spill of such registers and replaces corresponding
20/// statepoint operands to added spill slots.
21///
22//===----------------------------------------------------------------------===//
23
24#include "llvm/ADT/SmallSet.h"
25#include "llvm/ADT/Statistic.h"
26#include "llvm/CodeGen/MachineFrameInfo.h"
27#include "llvm/CodeGen/MachineFunctionPass.h"
28#include "llvm/CodeGen/MachineRegisterInfo.h"
29#include "llvm/CodeGen/Passes.h"
30#include "llvm/CodeGen/StackMaps.h"
31#include "llvm/CodeGen/TargetFrameLowering.h"
32#include "llvm/CodeGen/TargetInstrInfo.h"
33#include "llvm/IR/Statepoint.h"
34#include "llvm/InitializePasses.h"
35#include "llvm/Support/Debug.h"
36
37using namespace llvm;
38
39#define DEBUG_TYPE "fixup-statepoint-caller-saved"
40STATISTIC(NumSpilledRegisters, "Number of spilled register");
41STATISTIC(NumSpillSlotsAllocated, "Number of spill slots allocated");
42STATISTIC(NumSpillSlotsExtended, "Number of spill slots extended");
43
44static cl::opt<bool> FixupSCSExtendSlotSize(
45 "fixup-scs-extend-slot-size", cl::Hidden, cl::init(false),
46 cl::desc("Allow spill in spill slot of greater size than register size"),
47 cl::Hidden);
48
Denis Antrushin5f6bee72020-06-10 20:52:25 +070049static cl::opt<bool> PassGCPtrInCSR(
50 "fixup-allow-gcptr-in-csr", cl::Hidden, cl::init(false),
51 cl::desc("Allow passing GC Pointer arguments in callee saved registers"));
52
53static cl::opt<bool> EnableCopyProp(
54 "fixup-scs-enable-copy-propagation", cl::Hidden, cl::init(true),
55 cl::desc("Enable simple copy propagation during register reloading"));
56
57// This is purely debugging option.
58// It may be handy for investigating statepoint spilling issues.
59static cl::opt<unsigned> MaxStatepointsWithRegs(
60 "fixup-max-csr-statepoints", cl::Hidden,
61 cl::desc("Max number of statepoints allowed to pass GC Ptrs in registers"));
62
Serguei Katkov4275eb12020-04-09 18:40:53 +070063namespace {
64
65class FixupStatepointCallerSaved : public MachineFunctionPass {
66public:
67 static char ID;
68
69 FixupStatepointCallerSaved() : MachineFunctionPass(ID) {
70 initializeFixupStatepointCallerSavedPass(*PassRegistry::getPassRegistry());
71 }
72
73 void getAnalysisUsage(AnalysisUsage &AU) const override {
Craig Topperde92dc22020-05-13 10:29:04 -070074 AU.setPreservesCFG();
Serguei Katkov4275eb12020-04-09 18:40:53 +070075 MachineFunctionPass::getAnalysisUsage(AU);
76 }
77
78 StringRef getPassName() const override {
79 return "Fixup Statepoint Caller Saved";
80 }
81
82 bool runOnMachineFunction(MachineFunction &MF) override;
83};
Denis Antrushin5f6bee72020-06-10 20:52:25 +070084
Serguei Katkov4275eb12020-04-09 18:40:53 +070085} // End anonymous namespace.
86
87char FixupStatepointCallerSaved::ID = 0;
88char &llvm::FixupStatepointCallerSavedID = FixupStatepointCallerSaved::ID;
89
90INITIALIZE_PASS_BEGIN(FixupStatepointCallerSaved, DEBUG_TYPE,
91 "Fixup Statepoint Caller Saved", false, false)
92INITIALIZE_PASS_END(FixupStatepointCallerSaved, DEBUG_TYPE,
93 "Fixup Statepoint Caller Saved", false, false)
94
95// Utility function to get size of the register.
96static unsigned getRegisterSize(const TargetRegisterInfo &TRI, Register Reg) {
97 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
98 return TRI.getSpillSize(*RC);
99}
100
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700101// Advance iterator to the next stack map entry
102static MachineInstr::const_mop_iterator
103advanceToNextStackMapElt(MachineInstr::const_mop_iterator MOI) {
104 if (MOI->isImm()) {
105 switch (MOI->getImm()) {
106 default:
107 llvm_unreachable("Unrecognized operand type.");
108 case StackMaps::DirectMemRefOp:
109 MOI += 2; // <Reg>, <Imm>
110 break;
111 case StackMaps::IndirectMemRefOp:
112 MOI += 3; // <Size>, <Reg>, <Imm>
113 break;
114 case StackMaps::ConstantOp:
115 MOI += 1;
116 break;
117 }
118 }
119 return ++MOI;
120}
121
122// Return statepoint GC args as a set
123static SmallSet<Register, 8> collectGCRegs(MachineInstr &MI) {
124 StatepointOpers SO(&MI);
125 unsigned NumDeoptIdx = SO.getNumDeoptArgsIdx();
126 unsigned NumDeoptArgs = MI.getOperand(NumDeoptIdx).getImm();
127 MachineInstr::const_mop_iterator MOI(MI.operands_begin() + NumDeoptIdx + 1),
128 MOE(MI.operands_end());
129
130 // Skip deopt args
131 while (NumDeoptArgs--)
132 MOI = advanceToNextStackMapElt(MOI);
133
134 SmallSet<Register, 8> Result;
135 while (MOI != MOE) {
136 if (MOI->isReg() && !MOI->isImplicit())
137 Result.insert(MOI->getReg());
138 MOI = advanceToNextStackMapElt(MOI);
139 }
140 return Result;
141}
142
143// Try to eliminate redundant copy to register which we're going to
144// spill, i.e. try to change:
145// X = COPY Y
146// SPILL X
147// to
148// SPILL Y
149// If there are no uses of X between copy and STATEPOINT, that COPY
150// may be eliminated.
151// Reg - register we're about to spill
152// RI - On entry points to statepoint.
153// On successful copy propagation set to new spill point.
154// IsKill - set to true if COPY is Kill (there are no uses of Y)
155// Returns either found source copy register or original one.
156static Register performCopyPropagation(Register Reg,
157 MachineBasicBlock::iterator &RI,
158 bool &IsKill, const TargetInstrInfo &TII,
159 const TargetRegisterInfo &TRI) {
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700160 // First check if statepoint itself uses Reg in non-meta operands.
161 int Idx = RI->findRegisterUseOperandIdx(Reg, false, &TRI);
Denis Antrushin1c80a6c2020-08-14 22:08:54 +0700162 if (Idx >= 0 && (unsigned)Idx < StatepointOpers(&*RI).getNumDeoptArgsIdx()) {
163 IsKill = false;
164 return Reg;
165 }
166
167 if (!EnableCopyProp)
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700168 return Reg;
169
170 MachineBasicBlock *MBB = RI->getParent();
171 MachineBasicBlock::reverse_iterator E = MBB->rend();
172 MachineInstr *Def = nullptr, *Use = nullptr;
173 for (auto It = ++(RI.getReverse()); It != E; ++It) {
174 if (It->readsRegister(Reg, &TRI) && !Use)
175 Use = &*It;
176 if (It->modifiesRegister(Reg, &TRI)) {
177 Def = &*It;
178 break;
179 }
180 }
181
182 if (!Def)
183 return Reg;
184
185 auto DestSrc = TII.isCopyInstr(*Def);
186 if (!DestSrc || DestSrc->Destination->getReg() != Reg)
187 return Reg;
188
189 Register SrcReg = DestSrc->Source->getReg();
190
191 if (getRegisterSize(TRI, Reg) != getRegisterSize(TRI, SrcReg))
192 return Reg;
193
194 LLVM_DEBUG(dbgs() << "spillRegisters: perform copy propagation "
195 << printReg(Reg, &TRI) << " -> " << printReg(SrcReg, &TRI)
196 << "\n");
197
198 // Insert spill immediately after Def
199 RI = ++MachineBasicBlock::iterator(Def);
200 IsKill = DestSrc->Source->isKill();
201
202 // There are no uses of original register between COPY and STATEPOINT.
203 // There can't be any after STATEPOINT, so we can eliminate Def.
204 if (!Use) {
205 LLVM_DEBUG(dbgs() << "spillRegisters: removing dead copy " << *Def);
206 Def->eraseFromParent();
207 }
208 return SrcReg;
209}
210
Benjamin Kramer1d427642020-04-25 11:50:52 +0200211namespace {
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700212// Pair {Register, FrameIndex}
213using RegSlotPair = std::pair<Register, int>;
214
215// Keeps track of what reloads were inserted in MBB.
216class RegReloadCache {
217 using ReloadSet = SmallSet<RegSlotPair, 8>;
218 DenseMap<const MachineBasicBlock *, ReloadSet> Reloads;
219
220public:
221 RegReloadCache() = default;
222
223 // Record reload of Reg from FI in block MBB
224 void recordReload(Register Reg, int FI, const MachineBasicBlock *MBB) {
225 RegSlotPair RSP(Reg, FI);
226 auto Res = Reloads[MBB].insert(RSP);
Jordan Rupprechtfd9187f2020-08-14 08:35:58 -0700227 (void)Res;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700228 assert(Res.second && "reload already exists");
229 }
230
231 // Does basic block MBB contains reload of Reg from FI?
232 bool hasReload(Register Reg, int FI, const MachineBasicBlock *MBB) {
233 RegSlotPair RSP(Reg, FI);
234 return Reloads.count(MBB) && Reloads[MBB].count(RSP);
235 }
236};
237
Serguei Katkov4275eb12020-04-09 18:40:53 +0700238// Cache used frame indexes during statepoint re-write to re-use them in
239// processing next statepoint instruction.
240// Two strategies. One is to preserve the size of spill slot while another one
241// extends the size of spill slots to reduce the number of them, causing
242// the less total frame size. But unspill will have "implicit" any extend.
243class FrameIndexesCache {
244private:
245 struct FrameIndexesPerSize {
246 // List of used frame indexes during processing previous statepoints.
247 SmallVector<int, 8> Slots;
248 // Current index of un-used yet frame index.
249 unsigned Index = 0;
250 };
251 MachineFrameInfo &MFI;
252 const TargetRegisterInfo &TRI;
253 // Map size to list of frame indexes of this size. If the mode is
254 // FixupSCSExtendSlotSize then the key 0 is used to keep all frame indexes.
255 // If the size of required spill slot is greater than in a cache then the
256 // size will be increased.
257 DenseMap<unsigned, FrameIndexesPerSize> Cache;
258
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700259 // Keeps track of slots reserved for the shared landing pad processing.
260 // Initialized from GlobalIndices for the current EHPad.
261 SmallSet<int, 8> ReservedSlots;
262
263 // Landing pad can be destination of several statepoints. Every register
264 // defined by such statepoints must be spilled to the same stack slot.
265 // This map keeps that information.
266 DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>>
267 GlobalIndices;
268
269 FrameIndexesPerSize &getCacheBucket(unsigned Size) {
270 // In FixupSCSExtendSlotSize mode the bucket with 0 index is used
271 // for all sizes.
272 return Cache[FixupSCSExtendSlotSize ? 0 : Size];
273 }
274
Serguei Katkov4275eb12020-04-09 18:40:53 +0700275public:
276 FrameIndexesCache(MachineFrameInfo &MFI, const TargetRegisterInfo &TRI)
277 : MFI(MFI), TRI(TRI) {}
278 // Reset the current state of used frame indexes. After invocation of
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700279 // this function all frame indexes are available for allocation with
280 // the exception of slots reserved for landing pad processing (if any).
281 void reset(const MachineBasicBlock *EHPad) {
Serguei Katkov4275eb12020-04-09 18:40:53 +0700282 for (auto &It : Cache)
283 It.second.Index = 0;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700284
285 ReservedSlots.clear();
286 if (EHPad && GlobalIndices.count(EHPad))
287 for (auto &RSP : GlobalIndices[EHPad])
288 ReservedSlots.insert(RSP.second);
Serguei Katkov4275eb12020-04-09 18:40:53 +0700289 }
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700290
Serguei Katkov4275eb12020-04-09 18:40:53 +0700291 // Get frame index to spill the register.
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700292 int getFrameIndex(Register Reg, MachineBasicBlock *EHPad) {
293 // Check if slot for Reg is already reserved at EHPad.
294 auto It = GlobalIndices.find(EHPad);
295 if (It != GlobalIndices.end()) {
296 auto &Vec = It->second;
297 auto Idx = llvm::find_if(
298 Vec, [Reg](RegSlotPair &RSP) { return Reg == RSP.first; });
299 if (Idx != Vec.end()) {
300 int FI = Idx->second;
301 LLVM_DEBUG(dbgs() << "Found global FI " << FI << " for register "
302 << printReg(Reg, &TRI) << " at "
303 << printMBBReference(*EHPad) << "\n");
304 assert(ReservedSlots.count(FI) && "using unreserved slot");
305 return FI;
306 }
307 }
308
Serguei Katkov4275eb12020-04-09 18:40:53 +0700309 unsigned Size = getRegisterSize(TRI, Reg);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700310 FrameIndexesPerSize &Line = getCacheBucket(Size);
311 while (Line.Index < Line.Slots.size()) {
Serguei Katkov4275eb12020-04-09 18:40:53 +0700312 int FI = Line.Slots[Line.Index++];
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700313 if (ReservedSlots.count(FI))
314 continue;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700315 // If all sizes are kept together we probably need to extend the
316 // spill slot size.
317 if (MFI.getObjectSize(FI) < Size) {
318 MFI.setObjectSize(FI, Size);
319 MFI.setObjectAlignment(FI, Align(Size));
320 NumSpillSlotsExtended++;
321 }
322 return FI;
323 }
Guillaume Chatelet7f37d882020-07-01 08:49:28 +0000324 int FI = MFI.CreateSpillStackObject(Size, Align(Size));
Serguei Katkov4275eb12020-04-09 18:40:53 +0700325 NumSpillSlotsAllocated++;
326 Line.Slots.push_back(FI);
327 ++Line.Index;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700328
329 // Remember assignment {Reg, FI} for EHPad
330 if (EHPad) {
331 GlobalIndices[EHPad].push_back(std::make_pair(Reg, FI));
332 LLVM_DEBUG(dbgs() << "Reserved FI " << FI << " for spilling reg "
333 << printReg(Reg, &TRI) << " at landing pad "
334 << printMBBReference(*EHPad) << "\n");
335 }
336
Serguei Katkov4275eb12020-04-09 18:40:53 +0700337 return FI;
338 }
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700339
Serguei Katkov4275eb12020-04-09 18:40:53 +0700340 // Sort all registers to spill in descendent order. In the
341 // FixupSCSExtendSlotSize mode it will minimize the total frame size.
342 // In non FixupSCSExtendSlotSize mode we can skip this step.
343 void sortRegisters(SmallVectorImpl<Register> &Regs) {
344 if (!FixupSCSExtendSlotSize)
345 return;
346 llvm::sort(Regs.begin(), Regs.end(), [&](Register &A, Register &B) {
347 return getRegisterSize(TRI, A) > getRegisterSize(TRI, B);
348 });
349 }
350};
351
352// Describes the state of the current processing statepoint instruction.
353class StatepointState {
354private:
355 // statepoint instruction.
356 MachineInstr &MI;
357 MachineFunction &MF;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700358 // If non-null then statepoint is invoke, and this points to the landing pad.
359 MachineBasicBlock *EHPad;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700360 const TargetRegisterInfo &TRI;
361 const TargetInstrInfo &TII;
362 MachineFrameInfo &MFI;
363 // Mask with callee saved registers.
364 const uint32_t *Mask;
365 // Cache of frame indexes used on previous instruction processing.
366 FrameIndexesCache &CacheFI;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700367 bool AllowGCPtrInCSR;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700368 // Operands with physical registers requiring spilling.
369 SmallVector<unsigned, 8> OpsToSpill;
370 // Set of register to spill.
371 SmallVector<Register, 8> RegsToSpill;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700372 // Set of registers to reload after statepoint.
373 SmallVector<Register, 8> RegsToReload;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700374 // Map Register to Frame Slot index.
375 DenseMap<Register, int> RegToSlotIdx;
376
377public:
378 StatepointState(MachineInstr &MI, const uint32_t *Mask,
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700379 FrameIndexesCache &CacheFI, bool AllowGCPtrInCSR)
Serguei Katkov4275eb12020-04-09 18:40:53 +0700380 : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
381 TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700382 Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) {
383
384 // Find statepoint's landing pad, if any.
385 EHPad = nullptr;
386 MachineBasicBlock *MBB = MI.getParent();
387 // Invoke statepoint must be last one in block.
388 bool Last = std::none_of(++MI.getIterator(), MBB->end().getInstrIterator(),
389 [](MachineInstr &I) {
390 return I.getOpcode() == TargetOpcode::STATEPOINT;
391 });
392
393 if (!Last)
394 return;
395
396 auto IsEHPad = [](MachineBasicBlock *B) { return B->isEHPad(); };
397
398 assert(llvm::count_if(MBB->successors(), IsEHPad) < 2 && "multiple EHPads");
399
400 auto It = llvm::find_if(MBB->successors(), IsEHPad);
401 if (It != MBB->succ_end())
402 EHPad = *It;
403 }
404
405 MachineBasicBlock *getEHPad() const { return EHPad; }
406
Serguei Katkov4275eb12020-04-09 18:40:53 +0700407 // Return true if register is callee saved.
408 bool isCalleeSaved(Register Reg) { return (Mask[Reg / 32] >> Reg % 32) & 1; }
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700409
Serguei Katkov4275eb12020-04-09 18:40:53 +0700410 // Iterates over statepoint meta args to find caller saver registers.
411 // Also cache the size of found registers.
412 // Returns true if caller save registers found.
413 bool findRegistersToSpill() {
414 SmallSet<Register, 8> VisitedRegs;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700415 SmallSet<Register, 8> GCRegs = collectGCRegs(MI);
Serguei Katkov4275eb12020-04-09 18:40:53 +0700416 for (unsigned Idx = StatepointOpers(&MI).getVarIdx(),
417 EndIdx = MI.getNumOperands();
418 Idx < EndIdx; ++Idx) {
419 MachineOperand &MO = MI.getOperand(Idx);
420 if (!MO.isReg() || MO.isImplicit())
421 continue;
422 Register Reg = MO.getReg();
423 assert(Reg.isPhysical() && "Only physical regs are expected");
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700424
425 if (isCalleeSaved(Reg) && (AllowGCPtrInCSR || !is_contained(GCRegs, Reg)))
Serguei Katkov4275eb12020-04-09 18:40:53 +0700426 continue;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700427
428 LLVM_DEBUG(dbgs() << "Will spill " << printReg(Reg, &TRI) << " at index "
429 << Idx << "\n");
430
Serguei Katkov4275eb12020-04-09 18:40:53 +0700431 if (VisitedRegs.insert(Reg).second)
432 RegsToSpill.push_back(Reg);
433 OpsToSpill.push_back(Idx);
434 }
435 CacheFI.sortRegisters(RegsToSpill);
436 return !RegsToSpill.empty();
437 }
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700438
Serguei Katkov4275eb12020-04-09 18:40:53 +0700439 // Spill all caller saved registers right before statepoint instruction.
440 // Remember frame index where register is spilled.
441 void spillRegisters() {
442 for (Register Reg : RegsToSpill) {
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700443 int FI = CacheFI.getFrameIndex(Reg, EHPad);
Serguei Katkov4275eb12020-04-09 18:40:53 +0700444 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700445
Serguei Katkov4275eb12020-04-09 18:40:53 +0700446 NumSpilledRegisters++;
447 RegToSlotIdx[Reg] = FI;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700448
449 LLVM_DEBUG(dbgs() << "Spilling " << printReg(Reg, &TRI) << " to FI " << FI
450 << "\n");
451
452 // Perform trivial copy propagation
453 bool IsKill = true;
454 MachineBasicBlock::iterator InsertBefore(MI);
455 Reg = performCopyPropagation(Reg, InsertBefore, IsKill, TII, TRI);
456
457 LLVM_DEBUG(dbgs() << "Insert spill before " << *InsertBefore);
458 TII.storeRegToStackSlot(*MI.getParent(), InsertBefore, Reg, IsKill, FI,
459 RC, &TRI);
Serguei Katkov4275eb12020-04-09 18:40:53 +0700460 }
461 }
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700462
463 void insertReloadBefore(unsigned Reg, MachineBasicBlock::iterator It,
464 MachineBasicBlock *MBB) {
465 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
466 int FI = RegToSlotIdx[Reg];
467 if (It != MBB->end()) {
468 TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, &TRI);
469 return;
470 }
471
472 // To insert reload at the end of MBB, insert it before last instruction
473 // and then swap them.
474 assert(MBB->begin() != MBB->end() && "Empty block");
475 --It;
476 TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, &TRI);
477 MachineInstr *Reload = It->getPrevNode();
478 int Dummy = 0;
Jordan Rupprechtfd9187f2020-08-14 08:35:58 -0700479 (void)Dummy;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700480 assert(TII.isLoadFromStackSlot(*Reload, Dummy) == Reg);
481 assert(Dummy == FI);
482 MBB->remove(Reload);
483 MBB->insertAfter(It, Reload);
484 }
485
486 // Insert reloads of (relocated) registers spilled in statepoint.
487 void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) {
488 MachineBasicBlock *MBB = NewStatepoint->getParent();
489 auto InsertPoint = std::next(NewStatepoint->getIterator());
490
491 for (auto Reg : RegsToReload) {
492 insertReloadBefore(Reg, InsertPoint, MBB);
493 LLVM_DEBUG(dbgs() << "Reloading " << printReg(Reg, &TRI) << " from FI "
494 << RegToSlotIdx[Reg] << " after statepoint\n");
495
496 if (EHPad && !RC.hasReload(Reg, RegToSlotIdx[Reg], EHPad)) {
497 RC.recordReload(Reg, RegToSlotIdx[Reg], EHPad);
498 auto EHPadInsertPoint = EHPad->SkipPHIsLabelsAndDebug(EHPad->begin());
499 insertReloadBefore(Reg, EHPadInsertPoint, EHPad);
500 LLVM_DEBUG(dbgs() << "...also reload at EHPad "
501 << printMBBReference(*EHPad) << "\n");
502 }
503 }
504 }
505
Serguei Katkov4275eb12020-04-09 18:40:53 +0700506 // Re-write statepoint machine instruction to replace caller saved operands
507 // with indirect memory location (frame index).
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700508 MachineInstr *rewriteStatepoint() {
Serguei Katkov4275eb12020-04-09 18:40:53 +0700509 MachineInstr *NewMI =
510 MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(), true);
511 MachineInstrBuilder MIB(MF, NewMI);
512
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700513 unsigned NumOps = MI.getNumOperands();
514
515 // New indices for the remaining defs.
516 SmallVector<unsigned, 8> NewIndices;
517 unsigned NumDefs = MI.getNumDefs();
518 for (unsigned I = 0; I < NumDefs; ++I) {
519 MachineOperand &DefMO = MI.getOperand(I);
520 assert(DefMO.isReg() && DefMO.isDef() && "Expected Reg Def operand");
521 Register Reg = DefMO.getReg();
522 if (!AllowGCPtrInCSR) {
523 assert(is_contained(RegsToSpill, Reg));
524 RegsToReload.push_back(Reg);
525 } else {
526 if (isCalleeSaved(Reg)) {
527 NewIndices.push_back(NewMI->getNumOperands());
528 MIB.addReg(Reg, RegState::Define);
529 } else {
530 NewIndices.push_back(NumOps);
531 RegsToReload.push_back(Reg);
532 }
533 }
534 }
535
Serguei Katkov4275eb12020-04-09 18:40:53 +0700536 // Add End marker.
537 OpsToSpill.push_back(MI.getNumOperands());
538 unsigned CurOpIdx = 0;
539
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700540 for (unsigned I = NumDefs; I < MI.getNumOperands(); ++I) {
Serguei Katkov4275eb12020-04-09 18:40:53 +0700541 MachineOperand &MO = MI.getOperand(I);
542 if (I == OpsToSpill[CurOpIdx]) {
543 int FI = RegToSlotIdx[MO.getReg()];
544 MIB.addImm(StackMaps::IndirectMemRefOp);
545 MIB.addImm(getRegisterSize(TRI, MO.getReg()));
546 assert(MO.isReg() && "Should be register");
547 assert(MO.getReg().isPhysical() && "Should be physical register");
548 MIB.addFrameIndex(FI);
549 MIB.addImm(0);
550 ++CurOpIdx;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700551 } else {
Serguei Katkov4275eb12020-04-09 18:40:53 +0700552 MIB.add(MO);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700553 unsigned OldDef;
554 if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(I, &OldDef)) {
555 assert(OldDef < NumDefs);
556 assert(NewIndices[OldDef] < NumOps);
557 MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1);
558 }
559 }
Serguei Katkov4275eb12020-04-09 18:40:53 +0700560 }
561 assert(CurOpIdx == (OpsToSpill.size() - 1) && "Not all operands processed");
562 // Add mem operands.
563 NewMI->setMemRefs(MF, MI.memoperands());
564 for (auto It : RegToSlotIdx) {
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700565 Register R = It.first;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700566 int FrameIndex = It.second;
567 auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700568 MachineMemOperand::Flags Flags = MachineMemOperand::MOLoad;
569 if (is_contained(RegsToReload, R))
570 Flags |= MachineMemOperand::MOStore;
571 auto *MMO =
572 MF.getMachineMemOperand(PtrInfo, Flags, getRegisterSize(TRI, R),
573 MFI.getObjectAlign(FrameIndex));
Serguei Katkov4275eb12020-04-09 18:40:53 +0700574 NewMI->addMemOperand(MF, MMO);
575 }
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700576
Serguei Katkov4275eb12020-04-09 18:40:53 +0700577 // Insert new statepoint and erase old one.
578 MI.getParent()->insert(MI, NewMI);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700579
580 LLVM_DEBUG(dbgs() << "rewritten statepoint to : " << *NewMI << "\n");
Serguei Katkov4275eb12020-04-09 18:40:53 +0700581 MI.eraseFromParent();
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700582 return NewMI;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700583 }
584};
585
586class StatepointProcessor {
587private:
588 MachineFunction &MF;
589 const TargetRegisterInfo &TRI;
590 FrameIndexesCache CacheFI;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700591 RegReloadCache ReloadCache;
Serguei Katkov4275eb12020-04-09 18:40:53 +0700592
593public:
594 StatepointProcessor(MachineFunction &MF)
595 : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
596 CacheFI(MF.getFrameInfo(), TRI) {}
597
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700598 bool process(MachineInstr &MI, bool AllowGCPtrInCSR) {
Denis Antrushinedbb27c2020-04-14 18:30:51 +0300599 StatepointOpers SO(&MI);
600 uint64_t Flags = SO.getFlags();
Serguei Katkov4275eb12020-04-09 18:40:53 +0700601 // Do nothing for LiveIn, it supports all registers.
602 if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
603 return false;
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700604 LLVM_DEBUG(dbgs() << "\nMBB " << MI.getParent()->getNumber() << " "
605 << MI.getParent()->getName() << " : process statepoint "
606 << MI);
Denis Antrushinedbb27c2020-04-14 18:30:51 +0300607 CallingConv::ID CC = SO.getCallingConv();
Serguei Katkov4275eb12020-04-09 18:40:53 +0700608 const uint32_t *Mask = TRI.getCallPreservedMask(MF, CC);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700609 StatepointState SS(MI, Mask, CacheFI, AllowGCPtrInCSR);
610 CacheFI.reset(SS.getEHPad());
Serguei Katkov4275eb12020-04-09 18:40:53 +0700611
612 if (!SS.findRegistersToSpill())
613 return false;
614
615 SS.spillRegisters();
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700616 auto *NewStatepoint = SS.rewriteStatepoint();
617 SS.insertReloads(NewStatepoint, ReloadCache);
Serguei Katkov4275eb12020-04-09 18:40:53 +0700618 return true;
619 }
620};
Benjamin Kramer1d427642020-04-25 11:50:52 +0200621} // namespace
Serguei Katkov4275eb12020-04-09 18:40:53 +0700622
623bool FixupStatepointCallerSaved::runOnMachineFunction(MachineFunction &MF) {
624 if (skipFunction(MF.getFunction()))
625 return false;
626
627 const Function &F = MF.getFunction();
628 if (!F.hasGC())
629 return false;
630
631 SmallVector<MachineInstr *, 16> Statepoints;
632 for (MachineBasicBlock &BB : MF)
633 for (MachineInstr &I : BB)
634 if (I.getOpcode() == TargetOpcode::STATEPOINT)
635 Statepoints.push_back(&I);
636
637 if (Statepoints.empty())
638 return false;
639
640 bool Changed = false;
641 StatepointProcessor SPP(MF);
Denis Antrushin5f6bee72020-06-10 20:52:25 +0700642 unsigned NumStatepoints = 0;
643 bool AllowGCPtrInCSR = PassGCPtrInCSR;
644 for (MachineInstr *I : Statepoints) {
645 ++NumStatepoints;
646 if (MaxStatepointsWithRegs.getNumOccurrences() &&
647 NumStatepoints >= MaxStatepointsWithRegs)
648 AllowGCPtrInCSR = false;
649 Changed |= SPP.process(*I, AllowGCPtrInCSR);
650 }
Serguei Katkov4275eb12020-04-09 18:40:53 +0700651 return Changed;
652}