1f27f3738SPhilip Reames //===-- GCRootLowering.cpp - Garbage collection infrastructure ------------===//
2f27f3738SPhilip Reames //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f27f3738SPhilip Reames //
7f27f3738SPhilip Reames //===----------------------------------------------------------------------===//
8f27f3738SPhilip Reames //
9f27f3738SPhilip Reames // This file implements the lowering for the gc.root mechanism.
10f27f3738SPhilip Reames //
11f27f3738SPhilip Reames //===----------------------------------------------------------------------===//
12f27f3738SPhilip Reames 
132b453958SPhilip Reames #include "llvm/CodeGen/GCMetadata.h"
14f27f3738SPhilip Reames #include "llvm/CodeGen/MachineFrameInfo.h"
15f27f3738SPhilip Reames #include "llvm/CodeGen/MachineFunctionPass.h"
16f27f3738SPhilip Reames #include "llvm/CodeGen/MachineInstrBuilder.h"
17f27f3738SPhilip Reames #include "llvm/CodeGen/Passes.h"
183f833edcSDavid Blaikie #include "llvm/CodeGen/TargetFrameLowering.h"
193f833edcSDavid Blaikie #include "llvm/CodeGen/TargetInstrInfo.h"
20b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h"
21b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h"
22f27f3738SPhilip Reames #include "llvm/IR/Dominators.h"
23f27f3738SPhilip Reames #include "llvm/IR/IntrinsicInst.h"
24f27f3738SPhilip Reames #include "llvm/IR/Module.h"
2505da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
26*989f1c72Sserge-sans-paille #include "llvm/MC/MCContext.h"
27f27f3738SPhilip Reames 
28f27f3738SPhilip Reames using namespace llvm;
29f27f3738SPhilip Reames 
30f27f3738SPhilip Reames namespace {
31f27f3738SPhilip Reames 
32f27f3738SPhilip Reames /// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
33f27f3738SPhilip Reames /// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
34f27f3738SPhilip Reames /// directed by the GCStrategy. It also performs automatic root initialization
35f27f3738SPhilip Reames /// and custom intrinsic lowering.
36f27f3738SPhilip Reames class LowerIntrinsics : public FunctionPass {
3718945d6cSPhilip Reames   bool DoLowering(Function &F, GCStrategy &S);
38f27f3738SPhilip Reames 
39f27f3738SPhilip Reames public:
40f27f3738SPhilip Reames   static char ID;
41f27f3738SPhilip Reames 
42f27f3738SPhilip Reames   LowerIntrinsics();
43117296c0SMehdi Amini   StringRef getPassName() const override;
44f27f3738SPhilip Reames   void getAnalysisUsage(AnalysisUsage &AU) const override;
45f27f3738SPhilip Reames 
46f27f3738SPhilip Reames   bool doInitialization(Module &M) override;
47f27f3738SPhilip Reames   bool runOnFunction(Function &F) override;
48f27f3738SPhilip Reames };
49f27f3738SPhilip Reames 
50f27f3738SPhilip Reames /// GCMachineCodeAnalysis - This is a target-independent pass over the machine
51f27f3738SPhilip Reames /// function representation to identify safe points for the garbage collector
52f27f3738SPhilip Reames /// in the machine code. It inserts labels at safe points and populates a
53f27f3738SPhilip Reames /// GCMetadata record for each function.
54f27f3738SPhilip Reames class GCMachineCodeAnalysis : public MachineFunctionPass {
55f27f3738SPhilip Reames   GCFunctionInfo *FI;
56f27f3738SPhilip Reames   const TargetInstrInfo *TII;
57f27f3738SPhilip Reames 
58f27f3738SPhilip Reames   void FindSafePoints(MachineFunction &MF);
59cb0bab86SFangrui Song   void VisitCallPoint(MachineBasicBlock::iterator CI);
60b8714416SPhilip Reames   MCSymbol *InsertLabel(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
61bdc4956bSBenjamin Kramer                         const DebugLoc &DL) const;
62f27f3738SPhilip Reames 
63f27f3738SPhilip Reames   void FindStackOffsets(MachineFunction &MF);
64f27f3738SPhilip Reames 
65f27f3738SPhilip Reames public:
66f27f3738SPhilip Reames   static char ID;
67f27f3738SPhilip Reames 
68f27f3738SPhilip Reames   GCMachineCodeAnalysis();
69f27f3738SPhilip Reames   void getAnalysisUsage(AnalysisUsage &AU) const override;
70f27f3738SPhilip Reames 
71f27f3738SPhilip Reames   bool runOnMachineFunction(MachineFunction &MF) override;
72f27f3738SPhilip Reames };
73f00654e3SAlexander Kornienko }
74f27f3738SPhilip Reames 
75f27f3738SPhilip Reames // -----------------------------------------------------------------------------
76f27f3738SPhilip Reames 
77b8714416SPhilip Reames INITIALIZE_PASS_BEGIN(LowerIntrinsics, "gc-lowering", "GC Lowering", false,
78b8714416SPhilip Reames                       false)
INITIALIZE_PASS_DEPENDENCY(GCModuleInfo)79f27f3738SPhilip Reames INITIALIZE_PASS_DEPENDENCY(GCModuleInfo)
80f27f3738SPhilip Reames INITIALIZE_PASS_END(LowerIntrinsics, "gc-lowering", "GC Lowering", false, false)
81f27f3738SPhilip Reames 
82b8714416SPhilip Reames FunctionPass *llvm::createGCLoweringPass() { return new LowerIntrinsics(); }
83f27f3738SPhilip Reames 
84f27f3738SPhilip Reames char LowerIntrinsics::ID = 0;
850fdb25cdSStanislav Mekhanoshin char &llvm::GCLoweringID = LowerIntrinsics::ID;
86f27f3738SPhilip Reames 
LowerIntrinsics()87b8714416SPhilip Reames LowerIntrinsics::LowerIntrinsics() : FunctionPass(ID) {
88f27f3738SPhilip Reames   initializeLowerIntrinsicsPass(*PassRegistry::getPassRegistry());
89f27f3738SPhilip Reames }
90f27f3738SPhilip Reames 
getPassName() const91117296c0SMehdi Amini StringRef LowerIntrinsics::getPassName() const {
92f27f3738SPhilip Reames   return "Lower Garbage Collection Instructions";
93f27f3738SPhilip Reames }
94f27f3738SPhilip Reames 
getAnalysisUsage(AnalysisUsage & AU) const95f27f3738SPhilip Reames void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
96f27f3738SPhilip Reames   FunctionPass::getAnalysisUsage(AU);
97f27f3738SPhilip Reames   AU.addRequired<GCModuleInfo>();
98f27f3738SPhilip Reames   AU.addPreserved<DominatorTreeWrapperPass>();
99f27f3738SPhilip Reames }
100f27f3738SPhilip Reames 
101f27f3738SPhilip Reames /// doInitialization - If this module uses the GC intrinsics, find them now.
doInitialization(Module & M)102f27f3738SPhilip Reames bool LowerIntrinsics::doInitialization(Module &M) {
103f27f3738SPhilip Reames   GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
104f27f3738SPhilip Reames   assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
105905cf88dSKazu Hirata   for (Function &F : M)
106905cf88dSKazu Hirata     if (!F.isDeclaration() && F.hasGC())
107905cf88dSKazu Hirata       MI->getFunctionInfo(F); // Instantiate the GC strategy.
108f27f3738SPhilip Reames 
10923cf2e2fSPhilip Reames   return false;
110f27f3738SPhilip Reames }
111f27f3738SPhilip Reames 
11266c9fb0dSPhilip Reames /// CouldBecomeSafePoint - Predicate to conservatively determine whether the
11366c9fb0dSPhilip Reames /// instruction could introduce a safe point.
CouldBecomeSafePoint(Instruction * I)11466c9fb0dSPhilip Reames static bool CouldBecomeSafePoint(Instruction *I) {
11566c9fb0dSPhilip Reames   // The natural definition of instructions which could introduce safe points
11666c9fb0dSPhilip Reames   // are:
11766c9fb0dSPhilip Reames   //
11866c9fb0dSPhilip Reames   //   - call, invoke (AfterCall, BeforeCall)
11966c9fb0dSPhilip Reames   //   - phis (Loops)
12066c9fb0dSPhilip Reames   //   - invoke, ret, unwind (Exit)
12166c9fb0dSPhilip Reames   //
12266c9fb0dSPhilip Reames   // However, instructions as seemingly inoccuous as arithmetic can become
12366c9fb0dSPhilip Reames   // libcalls upon lowering (e.g., div i64 on a 32-bit platform), so instead
12466c9fb0dSPhilip Reames   // it is necessary to take a conservative approach.
12566c9fb0dSPhilip Reames 
12666c9fb0dSPhilip Reames   if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I) || isa<StoreInst>(I) ||
12766c9fb0dSPhilip Reames       isa<LoadInst>(I))
12866c9fb0dSPhilip Reames     return false;
12966c9fb0dSPhilip Reames 
13066c9fb0dSPhilip Reames   // llvm.gcroot is safe because it doesn't do anything at runtime.
13166c9fb0dSPhilip Reames   if (CallInst *CI = dyn_cast<CallInst>(I))
13266c9fb0dSPhilip Reames     if (Function *F = CI->getCalledFunction())
1339e1d3356SPete Cooper       if (Intrinsic::ID IID = F->getIntrinsicID())
13466c9fb0dSPhilip Reames         if (IID == Intrinsic::gcroot)
13566c9fb0dSPhilip Reames           return false;
13666c9fb0dSPhilip Reames 
13766c9fb0dSPhilip Reames   return true;
13866c9fb0dSPhilip Reames }
13966c9fb0dSPhilip Reames 
InsertRootInitializers(Function & F,ArrayRef<AllocaInst * > Roots)14015590217SPhilip Reames static bool InsertRootInitializers(Function &F, ArrayRef<AllocaInst *> Roots) {
141f27f3738SPhilip Reames   // Scroll past alloca instructions.
142f27f3738SPhilip Reames   BasicBlock::iterator IP = F.getEntryBlock().begin();
143b8714416SPhilip Reames   while (isa<AllocaInst>(IP))
144b8714416SPhilip Reames     ++IP;
145f27f3738SPhilip Reames 
146f27f3738SPhilip Reames   // Search for initializers in the initial BB.
147f27f3738SPhilip Reames   SmallPtrSet<AllocaInst *, 16> InitedRoots;
148d83547a1SDuncan P. N. Exon Smith   for (; !CouldBecomeSafePoint(&*IP); ++IP)
149f27f3738SPhilip Reames     if (StoreInst *SI = dyn_cast<StoreInst>(IP))
150f27f3738SPhilip Reames       if (AllocaInst *AI =
151f27f3738SPhilip Reames               dyn_cast<AllocaInst>(SI->getOperand(1)->stripPointerCasts()))
152f27f3738SPhilip Reames         InitedRoots.insert(AI);
153f27f3738SPhilip Reames 
154f27f3738SPhilip Reames   // Add root initializers.
155f27f3738SPhilip Reames   bool MadeChange = false;
156f27f3738SPhilip Reames 
15715590217SPhilip Reames   for (AllocaInst *Root : Roots)
15815590217SPhilip Reames     if (!InitedRoots.count(Root)) {
15911aa3707SEli Friedman       new StoreInst(
16015590217SPhilip Reames           ConstantPointerNull::get(cast<PointerType>(Root->getAllocatedType())),
16111aa3707SEli Friedman           Root, Root->getNextNode());
162f27f3738SPhilip Reames       MadeChange = true;
163f27f3738SPhilip Reames     }
164f27f3738SPhilip Reames 
165f27f3738SPhilip Reames   return MadeChange;
166f27f3738SPhilip Reames }
167f27f3738SPhilip Reames 
168f27f3738SPhilip Reames /// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
169f27f3738SPhilip Reames /// Leave gcroot intrinsics; the code generator needs to see those.
runOnFunction(Function & F)170f27f3738SPhilip Reames bool LowerIntrinsics::runOnFunction(Function &F) {
171f27f3738SPhilip Reames   // Quick exit for functions that do not use GC.
172f27f3738SPhilip Reames   if (!F.hasGC())
173f27f3738SPhilip Reames     return false;
174f27f3738SPhilip Reames 
175f27f3738SPhilip Reames   GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
176f27f3738SPhilip Reames   GCStrategy &S = FI.getStrategy();
177f27f3738SPhilip Reames 
17818945d6cSPhilip Reames   return DoLowering(F, S);
179f27f3738SPhilip Reames }
180f27f3738SPhilip Reames 
18118945d6cSPhilip Reames /// Lower barriers out of existance (if the associated GCStrategy hasn't
18218945d6cSPhilip Reames /// already done so...), and insert initializing stores to roots as a defensive
18318945d6cSPhilip Reames /// measure.  Given we're going to report all roots live at all safepoints, we
18418945d6cSPhilip Reames /// need to be able to ensure each root has been initialized by the point the
18518945d6cSPhilip Reames /// first safepoint is reached.  This really should have been done by the
18618945d6cSPhilip Reames /// frontend, but the old API made this non-obvious, so we do a potentially
18718945d6cSPhilip Reames /// redundant store just in case.
DoLowering(Function & F,GCStrategy & S)18818945d6cSPhilip Reames bool LowerIntrinsics::DoLowering(Function &F, GCStrategy &S) {
189f27f3738SPhilip Reames   SmallVector<AllocaInst *, 32> Roots;
190f27f3738SPhilip Reames 
191f27f3738SPhilip Reames   bool MadeChange = false;
19215590217SPhilip Reames   for (BasicBlock &BB : F)
1936bdb61c5SKazu Hirata     for (Instruction &I : llvm::make_early_inc_range(BB)) {
1946bdb61c5SKazu Hirata       IntrinsicInst *CI = dyn_cast<IntrinsicInst>(&I);
19515590217SPhilip Reames       if (!CI)
19615590217SPhilip Reames         continue;
19715590217SPhilip Reames 
198f27f3738SPhilip Reames       Function *F = CI->getCalledFunction();
199f27f3738SPhilip Reames       switch (F->getIntrinsicID()) {
20018945d6cSPhilip Reames       default: break;
20118945d6cSPhilip Reames       case Intrinsic::gcwrite: {
202f27f3738SPhilip Reames         // Replace a write barrier with a simple store.
20318945d6cSPhilip Reames         Value *St = new StoreInst(CI->getArgOperand(0),
20418945d6cSPhilip Reames                                   CI->getArgOperand(2), CI);
205f27f3738SPhilip Reames         CI->replaceAllUsesWith(St);
206f27f3738SPhilip Reames         CI->eraseFromParent();
20718945d6cSPhilip Reames         MadeChange = true;
208f27f3738SPhilip Reames         break;
20918945d6cSPhilip Reames       }
21018945d6cSPhilip Reames       case Intrinsic::gcread: {
211f27f3738SPhilip Reames         // Replace a read barrier with a simple load.
21214359ef1SJames Y Knight         Value *Ld = new LoadInst(CI->getType(), CI->getArgOperand(1), "", CI);
213f27f3738SPhilip Reames         Ld->takeName(CI);
214f27f3738SPhilip Reames         CI->replaceAllUsesWith(Ld);
215f27f3738SPhilip Reames         CI->eraseFromParent();
21618945d6cSPhilip Reames         MadeChange = true;
217f27f3738SPhilip Reames         break;
21818945d6cSPhilip Reames       }
21918945d6cSPhilip Reames       case Intrinsic::gcroot: {
220f27f3738SPhilip Reames         // Initialize the GC root, but do not delete the intrinsic. The
221f27f3738SPhilip Reames         // backend needs the intrinsic to flag the stack slot.
222b8714416SPhilip Reames         Roots.push_back(
223b8714416SPhilip Reames             cast<AllocaInst>(CI->getArgOperand(0)->stripPointerCasts()));
224f27f3738SPhilip Reames         break;
225f27f3738SPhilip Reames       }
22618945d6cSPhilip Reames       }
227f27f3738SPhilip Reames     }
228f27f3738SPhilip Reames 
229f27f3738SPhilip Reames   if (Roots.size())
23015590217SPhilip Reames     MadeChange |= InsertRootInitializers(F, Roots);
231f27f3738SPhilip Reames 
232f27f3738SPhilip Reames   return MadeChange;
233f27f3738SPhilip Reames }
234f27f3738SPhilip Reames 
235f27f3738SPhilip Reames // -----------------------------------------------------------------------------
236f27f3738SPhilip Reames 
237f27f3738SPhilip Reames char GCMachineCodeAnalysis::ID = 0;
238f27f3738SPhilip Reames char &llvm::GCMachineCodeAnalysisID = GCMachineCodeAnalysis::ID;
239f27f3738SPhilip Reames 
240f27f3738SPhilip Reames INITIALIZE_PASS(GCMachineCodeAnalysis, "gc-analysis",
241f27f3738SPhilip Reames                 "Analyze Machine Code For Garbage Collection", false, false)
242f27f3738SPhilip Reames 
GCMachineCodeAnalysis()243b8714416SPhilip Reames GCMachineCodeAnalysis::GCMachineCodeAnalysis() : MachineFunctionPass(ID) {}
244f27f3738SPhilip Reames 
getAnalysisUsage(AnalysisUsage & AU) const245f27f3738SPhilip Reames void GCMachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
246f27f3738SPhilip Reames   MachineFunctionPass::getAnalysisUsage(AU);
247f27f3738SPhilip Reames   AU.setPreservesAll();
248f27f3738SPhilip Reames   AU.addRequired<GCModuleInfo>();
249f27f3738SPhilip Reames }
250f27f3738SPhilip Reames 
InsertLabel(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,const DebugLoc & DL) const251f27f3738SPhilip Reames MCSymbol *GCMachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
252f27f3738SPhilip Reames                                              MachineBasicBlock::iterator MI,
253bdc4956bSBenjamin Kramer                                              const DebugLoc &DL) const {
2546f482000SJim Grosbach   MCSymbol *Label = MBB.getParent()->getContext().createTempSymbol();
255f27f3738SPhilip Reames   BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
256f27f3738SPhilip Reames   return Label;
257f27f3738SPhilip Reames }
258f27f3738SPhilip Reames 
VisitCallPoint(MachineBasicBlock::iterator CI)259f27f3738SPhilip Reames void GCMachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
260c75a0c3fSPhilip Reames   // Find the return address (next instruction), since that's what will be on
261c75a0c3fSPhilip Reames   // the stack when the call is suspended and we need to inspect the stack.
262f27f3738SPhilip Reames   MachineBasicBlock::iterator RAI = CI;
263f27f3738SPhilip Reames   ++RAI;
264f27f3738SPhilip Reames 
265f27f3738SPhilip Reames   MCSymbol *Label = InsertLabel(*CI->getParent(), RAI, CI->getDebugLoc());
266e44a55dcSPhilip Reames   FI->addSafePoint(Label, CI->getDebugLoc());
267f27f3738SPhilip Reames }
268f27f3738SPhilip Reames 
FindSafePoints(MachineFunction & MF)269f27f3738SPhilip Reames void GCMachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
27015590217SPhilip Reames   for (MachineBasicBlock &MBB : MF)
271ee0133dcSKazu Hirata     for (MachineInstr &MI : MBB)
272ee0133dcSKazu Hirata       if (MI.isCall()) {
2737de640a8SPhilip Reames         // Do not treat tail or sibling call sites as safe points.  This is
2747de640a8SPhilip Reames         // legal since any arguments passed to the callee which live in the
2757de640a8SPhilip Reames         // remnants of the callers frame will be owned and updated by the
2767de640a8SPhilip Reames         // callee if required.
277ee0133dcSKazu Hirata         if (MI.isTerminator())
2787de640a8SPhilip Reames           continue;
279ee0133dcSKazu Hirata         VisitCallPoint(&MI);
280f27f3738SPhilip Reames       }
2817de640a8SPhilip Reames }
282f27f3738SPhilip Reames 
FindStackOffsets(MachineFunction & MF)283f27f3738SPhilip Reames void GCMachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
2841df0c519SEric Christopher   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
285f27f3738SPhilip Reames   assert(TFI && "TargetRegisterInfo not available!");
286f27f3738SPhilip Reames 
287f27f3738SPhilip Reames   for (GCFunctionInfo::roots_iterator RI = FI->roots_begin();
288f27f3738SPhilip Reames        RI != FI->roots_end();) {
289f27f3738SPhilip Reames     // If the root references a dead object, no need to keep it.
290941a705bSMatthias Braun     if (MF.getFrameInfo().isDeadObjectIndex(RI->Num)) {
291f27f3738SPhilip Reames       RI = FI->removeStackRoot(RI);
292f27f3738SPhilip Reames     } else {
2932481f26aSMatt Arsenault       Register FrameReg; // FIXME: surely GCRoot ought to store the
2945567bafeSJames Y Knight                          // register that the offset is from?
295d57bba7cSSander de Smalen       auto FrameOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
296d57bba7cSSander de Smalen       assert(!FrameOffset.getScalable() &&
297d57bba7cSSander de Smalen              "Frame offsets with a scalable component are not supported");
298d57bba7cSSander de Smalen       RI->StackOffset = FrameOffset.getFixed();
299f27f3738SPhilip Reames       ++RI;
300f27f3738SPhilip Reames     }
301f27f3738SPhilip Reames   }
302f27f3738SPhilip Reames }
303f27f3738SPhilip Reames 
runOnMachineFunction(MachineFunction & MF)304f27f3738SPhilip Reames bool GCMachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
305f27f3738SPhilip Reames   // Quick exit for functions that do not use GC.
306f1caa283SMatthias Braun   if (!MF.getFunction().hasGC())
307f27f3738SPhilip Reames     return false;
308f27f3738SPhilip Reames 
309f1caa283SMatthias Braun   FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(MF.getFunction());
3101df0c519SEric Christopher   TII = MF.getSubtarget().getInstrInfo();
311f27f3738SPhilip Reames 
3122df7827cSPhilip Reames   // Find the size of the stack frame.  There may be no correct static frame
3132df7827cSPhilip Reames   // size, we use UINT64_MAX to represent this.
314941a705bSMatthias Braun   const MachineFrameInfo &MFI = MF.getFrameInfo();
3152df7827cSPhilip Reames   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
316a9968c0aSTomas Matheson   const bool DynamicFrameSize =
317a9968c0aSTomas Matheson       MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF);
318941a705bSMatthias Braun   FI->setFrameSize(DynamicFrameSize ? UINT64_MAX : MFI.getStackSize());
319f27f3738SPhilip Reames 
320f27f3738SPhilip Reames   // Find all safe points.
3212df7827cSPhilip Reames   if (FI->getStrategy().needsSafePoints())
322f27f3738SPhilip Reames     FindSafePoints(MF);
323f27f3738SPhilip Reames 
3242df7827cSPhilip Reames   // Find the concrete stack offsets for all roots (stack slots)
325f27f3738SPhilip Reames   FindStackOffsets(MF);
326f27f3738SPhilip Reames 
327f27f3738SPhilip Reames   return false;
328f27f3738SPhilip Reames }
329