xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/FixupStatepointCallerSaved.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===-- FixupStatepointCallerSaved.cpp - Fixup caller saved registers  ----===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric //                     The LLVM Compiler Infrastructure
4*5ffd83dbSDimitry Andric //
5*5ffd83dbSDimitry Andric // This file is distributed under the University of Illinois Open Source
6*5ffd83dbSDimitry Andric // License. See LICENSE.TXT for details.
7*5ffd83dbSDimitry Andric //
8*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
9*5ffd83dbSDimitry Andric ///
10*5ffd83dbSDimitry Andric /// \file
11*5ffd83dbSDimitry Andric /// Statepoint instruction in deopt parameters contains values which are
12*5ffd83dbSDimitry Andric /// meaningful to the runtime and should be able to be read at the moment the
13*5ffd83dbSDimitry Andric /// call returns. So we can say that we need to encode the fact that these
14*5ffd83dbSDimitry Andric /// values are "late read" by runtime. If we could express this notion for
15*5ffd83dbSDimitry Andric /// register allocator it would produce the right form for us.
16*5ffd83dbSDimitry Andric /// The need to fixup (i.e this pass) is specifically handling the fact that
17*5ffd83dbSDimitry Andric /// we cannot describe such a late read for the register allocator.
18*5ffd83dbSDimitry Andric /// Register allocator may put the value on a register clobbered by the call.
19*5ffd83dbSDimitry Andric /// This pass forces the spill of such registers and replaces corresponding
20*5ffd83dbSDimitry Andric /// statepoint operands to added spill slots.
21*5ffd83dbSDimitry Andric ///
22*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
23*5ffd83dbSDimitry Andric 
24*5ffd83dbSDimitry Andric #include "llvm/ADT/SmallSet.h"
25*5ffd83dbSDimitry Andric #include "llvm/ADT/Statistic.h"
26*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
27*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
28*5ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
29*5ffd83dbSDimitry Andric #include "llvm/CodeGen/Passes.h"
30*5ffd83dbSDimitry Andric #include "llvm/CodeGen/StackMaps.h"
31*5ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
32*5ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
33*5ffd83dbSDimitry Andric #include "llvm/IR/Statepoint.h"
34*5ffd83dbSDimitry Andric #include "llvm/InitializePasses.h"
35*5ffd83dbSDimitry Andric #include "llvm/Support/Debug.h"
36*5ffd83dbSDimitry Andric 
37*5ffd83dbSDimitry Andric using namespace llvm;
38*5ffd83dbSDimitry Andric 
39*5ffd83dbSDimitry Andric #define DEBUG_TYPE "fixup-statepoint-caller-saved"
40*5ffd83dbSDimitry Andric STATISTIC(NumSpilledRegisters, "Number of spilled register");
41*5ffd83dbSDimitry Andric STATISTIC(NumSpillSlotsAllocated, "Number of spill slots allocated");
42*5ffd83dbSDimitry Andric STATISTIC(NumSpillSlotsExtended, "Number of spill slots extended");
43*5ffd83dbSDimitry Andric 
44*5ffd83dbSDimitry Andric static cl::opt<bool> FixupSCSExtendSlotSize(
45*5ffd83dbSDimitry Andric     "fixup-scs-extend-slot-size", cl::Hidden, cl::init(false),
46*5ffd83dbSDimitry Andric     cl::desc("Allow spill in spill slot of greater size than register size"),
47*5ffd83dbSDimitry Andric     cl::Hidden);
48*5ffd83dbSDimitry Andric 
49*5ffd83dbSDimitry Andric namespace {
50*5ffd83dbSDimitry Andric 
51*5ffd83dbSDimitry Andric class FixupStatepointCallerSaved : public MachineFunctionPass {
52*5ffd83dbSDimitry Andric public:
53*5ffd83dbSDimitry Andric   static char ID;
54*5ffd83dbSDimitry Andric 
55*5ffd83dbSDimitry Andric   FixupStatepointCallerSaved() : MachineFunctionPass(ID) {
56*5ffd83dbSDimitry Andric     initializeFixupStatepointCallerSavedPass(*PassRegistry::getPassRegistry());
57*5ffd83dbSDimitry Andric   }
58*5ffd83dbSDimitry Andric 
59*5ffd83dbSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
60*5ffd83dbSDimitry Andric     AU.setPreservesCFG();
61*5ffd83dbSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
62*5ffd83dbSDimitry Andric   }
63*5ffd83dbSDimitry Andric 
64*5ffd83dbSDimitry Andric   StringRef getPassName() const override {
65*5ffd83dbSDimitry Andric     return "Fixup Statepoint Caller Saved";
66*5ffd83dbSDimitry Andric   }
67*5ffd83dbSDimitry Andric 
68*5ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
69*5ffd83dbSDimitry Andric };
70*5ffd83dbSDimitry Andric } // End anonymous namespace.
71*5ffd83dbSDimitry Andric 
72*5ffd83dbSDimitry Andric char FixupStatepointCallerSaved::ID = 0;
73*5ffd83dbSDimitry Andric char &llvm::FixupStatepointCallerSavedID = FixupStatepointCallerSaved::ID;
74*5ffd83dbSDimitry Andric 
75*5ffd83dbSDimitry Andric INITIALIZE_PASS_BEGIN(FixupStatepointCallerSaved, DEBUG_TYPE,
76*5ffd83dbSDimitry Andric                       "Fixup Statepoint Caller Saved", false, false)
77*5ffd83dbSDimitry Andric INITIALIZE_PASS_END(FixupStatepointCallerSaved, DEBUG_TYPE,
78*5ffd83dbSDimitry Andric                     "Fixup Statepoint Caller Saved", false, false)
79*5ffd83dbSDimitry Andric 
80*5ffd83dbSDimitry Andric // Utility function to get size of the register.
81*5ffd83dbSDimitry Andric static unsigned getRegisterSize(const TargetRegisterInfo &TRI, Register Reg) {
82*5ffd83dbSDimitry Andric   const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
83*5ffd83dbSDimitry Andric   return TRI.getSpillSize(*RC);
84*5ffd83dbSDimitry Andric }
85*5ffd83dbSDimitry Andric 
86*5ffd83dbSDimitry Andric namespace {
87*5ffd83dbSDimitry Andric // Cache used frame indexes during statepoint re-write to re-use them in
88*5ffd83dbSDimitry Andric // processing next statepoint instruction.
89*5ffd83dbSDimitry Andric // Two strategies. One is to preserve the size of spill slot while another one
90*5ffd83dbSDimitry Andric // extends the size of spill slots to reduce the number of them, causing
91*5ffd83dbSDimitry Andric // the less total frame size. But unspill will have "implicit" any extend.
92*5ffd83dbSDimitry Andric class FrameIndexesCache {
93*5ffd83dbSDimitry Andric private:
94*5ffd83dbSDimitry Andric   struct FrameIndexesPerSize {
95*5ffd83dbSDimitry Andric     // List of used frame indexes during processing previous statepoints.
96*5ffd83dbSDimitry Andric     SmallVector<int, 8> Slots;
97*5ffd83dbSDimitry Andric     // Current index of un-used yet frame index.
98*5ffd83dbSDimitry Andric     unsigned Index = 0;
99*5ffd83dbSDimitry Andric   };
100*5ffd83dbSDimitry Andric   MachineFrameInfo &MFI;
101*5ffd83dbSDimitry Andric   const TargetRegisterInfo &TRI;
102*5ffd83dbSDimitry Andric   // Map size to list of frame indexes of this size. If the mode is
103*5ffd83dbSDimitry Andric   // FixupSCSExtendSlotSize then the key 0 is used to keep all frame indexes.
104*5ffd83dbSDimitry Andric   // If the size of required spill slot is greater than in a cache then the
105*5ffd83dbSDimitry Andric   // size will be increased.
106*5ffd83dbSDimitry Andric   DenseMap<unsigned, FrameIndexesPerSize> Cache;
107*5ffd83dbSDimitry Andric 
108*5ffd83dbSDimitry Andric public:
109*5ffd83dbSDimitry Andric   FrameIndexesCache(MachineFrameInfo &MFI, const TargetRegisterInfo &TRI)
110*5ffd83dbSDimitry Andric       : MFI(MFI), TRI(TRI) {}
111*5ffd83dbSDimitry Andric   // Reset the current state of used frame indexes. After invocation of
112*5ffd83dbSDimitry Andric   // this function all frame indexes are available for allocation.
113*5ffd83dbSDimitry Andric   void reset() {
114*5ffd83dbSDimitry Andric     for (auto &It : Cache)
115*5ffd83dbSDimitry Andric       It.second.Index = 0;
116*5ffd83dbSDimitry Andric   }
117*5ffd83dbSDimitry Andric   // Get frame index to spill the register.
118*5ffd83dbSDimitry Andric   int getFrameIndex(Register Reg) {
119*5ffd83dbSDimitry Andric     unsigned Size = getRegisterSize(TRI, Reg);
120*5ffd83dbSDimitry Andric     // In FixupSCSExtendSlotSize mode the bucket with 0 index is used
121*5ffd83dbSDimitry Andric     // for all sizes.
122*5ffd83dbSDimitry Andric     unsigned Bucket = FixupSCSExtendSlotSize ? 0 : Size;
123*5ffd83dbSDimitry Andric     FrameIndexesPerSize &Line = Cache[Bucket];
124*5ffd83dbSDimitry Andric     if (Line.Index < Line.Slots.size()) {
125*5ffd83dbSDimitry Andric       int FI = Line.Slots[Line.Index++];
126*5ffd83dbSDimitry Andric       // If all sizes are kept together we probably need to extend the
127*5ffd83dbSDimitry Andric       // spill slot size.
128*5ffd83dbSDimitry Andric       if (MFI.getObjectSize(FI) < Size) {
129*5ffd83dbSDimitry Andric         MFI.setObjectSize(FI, Size);
130*5ffd83dbSDimitry Andric         MFI.setObjectAlignment(FI, Align(Size));
131*5ffd83dbSDimitry Andric         NumSpillSlotsExtended++;
132*5ffd83dbSDimitry Andric       }
133*5ffd83dbSDimitry Andric       return FI;
134*5ffd83dbSDimitry Andric     }
135*5ffd83dbSDimitry Andric     int FI = MFI.CreateSpillStackObject(Size, Align(Size));
136*5ffd83dbSDimitry Andric     NumSpillSlotsAllocated++;
137*5ffd83dbSDimitry Andric     Line.Slots.push_back(FI);
138*5ffd83dbSDimitry Andric     ++Line.Index;
139*5ffd83dbSDimitry Andric     return FI;
140*5ffd83dbSDimitry Andric   }
141*5ffd83dbSDimitry Andric   // Sort all registers to spill in descendent order. In the
142*5ffd83dbSDimitry Andric   // FixupSCSExtendSlotSize mode it will minimize the total frame size.
143*5ffd83dbSDimitry Andric   // In non FixupSCSExtendSlotSize mode we can skip this step.
144*5ffd83dbSDimitry Andric   void sortRegisters(SmallVectorImpl<Register> &Regs) {
145*5ffd83dbSDimitry Andric     if (!FixupSCSExtendSlotSize)
146*5ffd83dbSDimitry Andric       return;
147*5ffd83dbSDimitry Andric     llvm::sort(Regs.begin(), Regs.end(), [&](Register &A, Register &B) {
148*5ffd83dbSDimitry Andric       return getRegisterSize(TRI, A) > getRegisterSize(TRI, B);
149*5ffd83dbSDimitry Andric     });
150*5ffd83dbSDimitry Andric   }
151*5ffd83dbSDimitry Andric };
152*5ffd83dbSDimitry Andric 
153*5ffd83dbSDimitry Andric // Describes the state of the current processing statepoint instruction.
154*5ffd83dbSDimitry Andric class StatepointState {
155*5ffd83dbSDimitry Andric private:
156*5ffd83dbSDimitry Andric   // statepoint instruction.
157*5ffd83dbSDimitry Andric   MachineInstr &MI;
158*5ffd83dbSDimitry Andric   MachineFunction &MF;
159*5ffd83dbSDimitry Andric   const TargetRegisterInfo &TRI;
160*5ffd83dbSDimitry Andric   const TargetInstrInfo &TII;
161*5ffd83dbSDimitry Andric   MachineFrameInfo &MFI;
162*5ffd83dbSDimitry Andric   // Mask with callee saved registers.
163*5ffd83dbSDimitry Andric   const uint32_t *Mask;
164*5ffd83dbSDimitry Andric   // Cache of frame indexes used on previous instruction processing.
165*5ffd83dbSDimitry Andric   FrameIndexesCache &CacheFI;
166*5ffd83dbSDimitry Andric   // Operands with physical registers requiring spilling.
167*5ffd83dbSDimitry Andric   SmallVector<unsigned, 8> OpsToSpill;
168*5ffd83dbSDimitry Andric   // Set of register to spill.
169*5ffd83dbSDimitry Andric   SmallVector<Register, 8> RegsToSpill;
170*5ffd83dbSDimitry Andric   // Map Register to Frame Slot index.
171*5ffd83dbSDimitry Andric   DenseMap<Register, int> RegToSlotIdx;
172*5ffd83dbSDimitry Andric 
173*5ffd83dbSDimitry Andric public:
174*5ffd83dbSDimitry Andric   StatepointState(MachineInstr &MI, const uint32_t *Mask,
175*5ffd83dbSDimitry Andric                   FrameIndexesCache &CacheFI)
176*5ffd83dbSDimitry Andric       : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
177*5ffd83dbSDimitry Andric         TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
178*5ffd83dbSDimitry Andric         Mask(Mask), CacheFI(CacheFI) {}
179*5ffd83dbSDimitry Andric   // Return true if register is callee saved.
180*5ffd83dbSDimitry Andric   bool isCalleeSaved(Register Reg) { return (Mask[Reg / 32] >> Reg % 32) & 1; }
181*5ffd83dbSDimitry Andric   // Iterates over statepoint meta args to find caller saver registers.
182*5ffd83dbSDimitry Andric   // Also cache the size of found registers.
183*5ffd83dbSDimitry Andric   // Returns true if caller save registers found.
184*5ffd83dbSDimitry Andric   bool findRegistersToSpill() {
185*5ffd83dbSDimitry Andric     SmallSet<Register, 8> VisitedRegs;
186*5ffd83dbSDimitry Andric     for (unsigned Idx = StatepointOpers(&MI).getVarIdx(),
187*5ffd83dbSDimitry Andric                   EndIdx = MI.getNumOperands();
188*5ffd83dbSDimitry Andric          Idx < EndIdx; ++Idx) {
189*5ffd83dbSDimitry Andric       MachineOperand &MO = MI.getOperand(Idx);
190*5ffd83dbSDimitry Andric       if (!MO.isReg() || MO.isImplicit())
191*5ffd83dbSDimitry Andric         continue;
192*5ffd83dbSDimitry Andric       Register Reg = MO.getReg();
193*5ffd83dbSDimitry Andric       assert(Reg.isPhysical() && "Only physical regs are expected");
194*5ffd83dbSDimitry Andric       if (isCalleeSaved(Reg))
195*5ffd83dbSDimitry Andric         continue;
196*5ffd83dbSDimitry Andric       if (VisitedRegs.insert(Reg).second)
197*5ffd83dbSDimitry Andric         RegsToSpill.push_back(Reg);
198*5ffd83dbSDimitry Andric       OpsToSpill.push_back(Idx);
199*5ffd83dbSDimitry Andric     }
200*5ffd83dbSDimitry Andric     CacheFI.sortRegisters(RegsToSpill);
201*5ffd83dbSDimitry Andric     return !RegsToSpill.empty();
202*5ffd83dbSDimitry Andric   }
203*5ffd83dbSDimitry Andric   // Spill all caller saved registers right before statepoint instruction.
204*5ffd83dbSDimitry Andric   // Remember frame index where register is spilled.
205*5ffd83dbSDimitry Andric   void spillRegisters() {
206*5ffd83dbSDimitry Andric     for (Register Reg : RegsToSpill) {
207*5ffd83dbSDimitry Andric       int FI = CacheFI.getFrameIndex(Reg);
208*5ffd83dbSDimitry Andric       const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
209*5ffd83dbSDimitry Andric       TII.storeRegToStackSlot(*MI.getParent(), MI, Reg, true /*is_Kill*/, FI,
210*5ffd83dbSDimitry Andric                               RC, &TRI);
211*5ffd83dbSDimitry Andric       NumSpilledRegisters++;
212*5ffd83dbSDimitry Andric       RegToSlotIdx[Reg] = FI;
213*5ffd83dbSDimitry Andric     }
214*5ffd83dbSDimitry Andric   }
215*5ffd83dbSDimitry Andric   // Re-write statepoint machine instruction to replace caller saved operands
216*5ffd83dbSDimitry Andric   // with indirect memory location (frame index).
217*5ffd83dbSDimitry Andric   void rewriteStatepoint() {
218*5ffd83dbSDimitry Andric     MachineInstr *NewMI =
219*5ffd83dbSDimitry Andric         MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(), true);
220*5ffd83dbSDimitry Andric     MachineInstrBuilder MIB(MF, NewMI);
221*5ffd83dbSDimitry Andric 
222*5ffd83dbSDimitry Andric     // Add End marker.
223*5ffd83dbSDimitry Andric     OpsToSpill.push_back(MI.getNumOperands());
224*5ffd83dbSDimitry Andric     unsigned CurOpIdx = 0;
225*5ffd83dbSDimitry Andric 
226*5ffd83dbSDimitry Andric     for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
227*5ffd83dbSDimitry Andric       MachineOperand &MO = MI.getOperand(I);
228*5ffd83dbSDimitry Andric       if (I == OpsToSpill[CurOpIdx]) {
229*5ffd83dbSDimitry Andric         int FI = RegToSlotIdx[MO.getReg()];
230*5ffd83dbSDimitry Andric         MIB.addImm(StackMaps::IndirectMemRefOp);
231*5ffd83dbSDimitry Andric         MIB.addImm(getRegisterSize(TRI, MO.getReg()));
232*5ffd83dbSDimitry Andric         assert(MO.isReg() && "Should be register");
233*5ffd83dbSDimitry Andric         assert(MO.getReg().isPhysical() && "Should be physical register");
234*5ffd83dbSDimitry Andric         MIB.addFrameIndex(FI);
235*5ffd83dbSDimitry Andric         MIB.addImm(0);
236*5ffd83dbSDimitry Andric         ++CurOpIdx;
237*5ffd83dbSDimitry Andric       } else
238*5ffd83dbSDimitry Andric         MIB.add(MO);
239*5ffd83dbSDimitry Andric     }
240*5ffd83dbSDimitry Andric     assert(CurOpIdx == (OpsToSpill.size() - 1) && "Not all operands processed");
241*5ffd83dbSDimitry Andric     // Add mem operands.
242*5ffd83dbSDimitry Andric     NewMI->setMemRefs(MF, MI.memoperands());
243*5ffd83dbSDimitry Andric     for (auto It : RegToSlotIdx) {
244*5ffd83dbSDimitry Andric       int FrameIndex = It.second;
245*5ffd83dbSDimitry Andric       auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
246*5ffd83dbSDimitry Andric       auto *MMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
247*5ffd83dbSDimitry Andric                                           getRegisterSize(TRI, It.first),
248*5ffd83dbSDimitry Andric                                           MFI.getObjectAlign(FrameIndex));
249*5ffd83dbSDimitry Andric       NewMI->addMemOperand(MF, MMO);
250*5ffd83dbSDimitry Andric     }
251*5ffd83dbSDimitry Andric     // Insert new statepoint and erase old one.
252*5ffd83dbSDimitry Andric     MI.getParent()->insert(MI, NewMI);
253*5ffd83dbSDimitry Andric     MI.eraseFromParent();
254*5ffd83dbSDimitry Andric   }
255*5ffd83dbSDimitry Andric };
256*5ffd83dbSDimitry Andric 
257*5ffd83dbSDimitry Andric class StatepointProcessor {
258*5ffd83dbSDimitry Andric private:
259*5ffd83dbSDimitry Andric   MachineFunction &MF;
260*5ffd83dbSDimitry Andric   const TargetRegisterInfo &TRI;
261*5ffd83dbSDimitry Andric   FrameIndexesCache CacheFI;
262*5ffd83dbSDimitry Andric 
263*5ffd83dbSDimitry Andric public:
264*5ffd83dbSDimitry Andric   StatepointProcessor(MachineFunction &MF)
265*5ffd83dbSDimitry Andric       : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
266*5ffd83dbSDimitry Andric         CacheFI(MF.getFrameInfo(), TRI) {}
267*5ffd83dbSDimitry Andric 
268*5ffd83dbSDimitry Andric   bool process(MachineInstr &MI) {
269*5ffd83dbSDimitry Andric     StatepointOpers SO(&MI);
270*5ffd83dbSDimitry Andric     uint64_t Flags = SO.getFlags();
271*5ffd83dbSDimitry Andric     // Do nothing for LiveIn, it supports all registers.
272*5ffd83dbSDimitry Andric     if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
273*5ffd83dbSDimitry Andric       return false;
274*5ffd83dbSDimitry Andric     CallingConv::ID CC = SO.getCallingConv();
275*5ffd83dbSDimitry Andric     const uint32_t *Mask = TRI.getCallPreservedMask(MF, CC);
276*5ffd83dbSDimitry Andric     CacheFI.reset();
277*5ffd83dbSDimitry Andric     StatepointState SS(MI, Mask, CacheFI);
278*5ffd83dbSDimitry Andric 
279*5ffd83dbSDimitry Andric     if (!SS.findRegistersToSpill())
280*5ffd83dbSDimitry Andric       return false;
281*5ffd83dbSDimitry Andric 
282*5ffd83dbSDimitry Andric     SS.spillRegisters();
283*5ffd83dbSDimitry Andric     SS.rewriteStatepoint();
284*5ffd83dbSDimitry Andric     return true;
285*5ffd83dbSDimitry Andric   }
286*5ffd83dbSDimitry Andric };
287*5ffd83dbSDimitry Andric } // namespace
288*5ffd83dbSDimitry Andric 
289*5ffd83dbSDimitry Andric bool FixupStatepointCallerSaved::runOnMachineFunction(MachineFunction &MF) {
290*5ffd83dbSDimitry Andric   if (skipFunction(MF.getFunction()))
291*5ffd83dbSDimitry Andric     return false;
292*5ffd83dbSDimitry Andric 
293*5ffd83dbSDimitry Andric   const Function &F = MF.getFunction();
294*5ffd83dbSDimitry Andric   if (!F.hasGC())
295*5ffd83dbSDimitry Andric     return false;
296*5ffd83dbSDimitry Andric 
297*5ffd83dbSDimitry Andric   SmallVector<MachineInstr *, 16> Statepoints;
298*5ffd83dbSDimitry Andric   for (MachineBasicBlock &BB : MF)
299*5ffd83dbSDimitry Andric     for (MachineInstr &I : BB)
300*5ffd83dbSDimitry Andric       if (I.getOpcode() == TargetOpcode::STATEPOINT)
301*5ffd83dbSDimitry Andric         Statepoints.push_back(&I);
302*5ffd83dbSDimitry Andric 
303*5ffd83dbSDimitry Andric   if (Statepoints.empty())
304*5ffd83dbSDimitry Andric     return false;
305*5ffd83dbSDimitry Andric 
306*5ffd83dbSDimitry Andric   bool Changed = false;
307*5ffd83dbSDimitry Andric   StatepointProcessor SPP(MF);
308*5ffd83dbSDimitry Andric   for (MachineInstr *I : Statepoints)
309*5ffd83dbSDimitry Andric     Changed |= SPP.process(*I);
310*5ffd83dbSDimitry Andric   return Changed;
311*5ffd83dbSDimitry Andric }
312