LLVM 23.0.0git
GCRootLowering.cpp
Go to the documentation of this file.
1//===-- GCRootLowering.cpp - Garbage collection infrastructure ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the lowering for the gc.root mechanism.
10//
11//===----------------------------------------------------------------------===//
12
17#include "llvm/CodeGen/Passes.h"
22#include "llvm/IR/Dominators.h"
24#include "llvm/IR/Module.h"
26#include "llvm/MC/MCContext.h"
27
28using namespace llvm;
29
30/// Lower barriers out of existence (if the associated GCStrategy hasn't
31/// already done so...), and insert initializing stores to roots as a defensive
32/// measure. Given we're going to report all roots live at all safepoints, we
33/// need to be able to ensure each root has been initialized by the point the
34/// first safepoint is reached. This really should have been done by the
35/// frontend, but the old API made this non-obvious, so we do a potentially
36/// redundant store just in case.
37static bool DoLowering(Function &F, GCStrategy &S);
38
39namespace {
40
41/// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
42/// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
43/// directed by the GCStrategy. It also performs automatic root initialization
44/// and custom intrinsic lowering.
45class LowerIntrinsics : public FunctionPass {
46public:
47 static char ID;
48
49 LowerIntrinsics();
50 StringRef getPassName() const override;
51 void getAnalysisUsage(AnalysisUsage &AU) const override;
52
53 bool doInitialization(Module &M) override;
54 bool runOnFunction(Function &F) override;
55};
56
57/// GCMachineCodeAnalysis - This is a target-independent pass over the machine
58/// function representation to identify safe points for the garbage collector
59/// in the machine code. It inserts labels at safe points and populates a
60/// GCMetadata record for each function.
61class GCMachineCodeAnalysis : public MachineFunctionPass {
62 GCFunctionInfo *FI = nullptr;
63 const TargetInstrInfo *TII = nullptr;
64
65 void FindSafePoints(MachineFunction &MF);
66 void VisitCallPoint(MachineBasicBlock::iterator CI);
67 MCSymbol *InsertLabel(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
68 const DebugLoc &DL) const;
69
70 void FindStackOffsets(MachineFunction &MF);
71
72public:
73 static char ID;
74
75 GCMachineCodeAnalysis();
76 void getAnalysisUsage(AnalysisUsage &AU) const override;
77
78 bool runOnMachineFunction(MachineFunction &MF) override;
79};
80}
81
84 if (!F.hasGC())
86
87 auto &Info = FAM.getResult<GCFunctionAnalysis>(F);
88
89 bool Changed = DoLowering(F, Info.getStrategy());
90
91 if (!Changed)
95 return PA;
96}
97
98// -----------------------------------------------------------------------------
99
100INITIALIZE_PASS_BEGIN(LowerIntrinsics, "gc-lowering", "GC Lowering", false,
101 false)
103INITIALIZE_PASS_END(LowerIntrinsics, "gc-lowering", "GC Lowering", false, false)
104
105FunctionPass *llvm::createGCLoweringPass() { return new LowerIntrinsics(); }
106
107char LowerIntrinsics::ID = 0;
108char &llvm::GCLoweringID = LowerIntrinsics::ID;
109
110LowerIntrinsics::LowerIntrinsics() : FunctionPass(ID) {}
111
112StringRef LowerIntrinsics::getPassName() const {
113 return "Lower Garbage Collection Instructions";
114}
115
116void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
117 FunctionPass::getAnalysisUsage(AU);
118 AU.addRequired<GCModuleInfo>();
119 AU.addPreserved<DominatorTreeWrapperPass>();
120}
121
122/// doInitialization - If this module uses the GC intrinsics, find them now.
123bool LowerIntrinsics::doInitialization(Module &M) {
124 GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
125 assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
126 for (Function &F : M)
127 if (!F.isDeclaration() && F.hasGC())
128 MI->getFunctionInfo(F); // Instantiate the GC strategy.
129
130 return false;
131}
132
133/// CouldBecomeSafePoint - Predicate to conservatively determine whether the
134/// instruction could introduce a safe point.
136 // The natural definition of instructions which could introduce safe points
137 // are:
138 //
139 // - call, invoke (AfterCall, BeforeCall)
140 // - phis (Loops)
141 // - invoke, ret, unwind (Exit)
142 //
143 // However, instructions as seemingly inoccuous as arithmetic can become
144 // libcalls upon lowering (e.g., div i64 on a 32-bit platform), so instead
145 // it is necessary to take a conservative approach.
146
149 return false;
150
151 // llvm.gcroot is safe because it doesn't do anything at runtime.
152 if (CallInst *CI = dyn_cast<CallInst>(I))
153 if (Function *F = CI->getCalledFunction())
154 if (Intrinsic::ID IID = F->getIntrinsicID())
155 if (IID == Intrinsic::gcroot)
156 return false;
157
158 return true;
159}
160
162 // Scroll past alloca instructions.
163 BasicBlock::iterator IP = F.getEntryBlock().begin();
164 while (isa<AllocaInst>(IP))
165 ++IP;
166
167 // Search for initializers in the initial BB.
169 for (; !CouldBecomeSafePoint(&*IP); ++IP)
171 if (AllocaInst *AI =
172 dyn_cast<AllocaInst>(SI->getOperand(1)->stripPointerCasts()))
173 InitedRoots.insert(AI);
174
175 // Add root initializers.
176 bool MadeChange = false;
177
178 for (AllocaInst *Root : Roots)
179 if (!InitedRoots.count(Root)) {
180 new StoreInst(
181 ConstantPointerNull::get(cast<PointerType>(Root->getAllocatedType())),
182 Root, std::next(Root->getIterator()));
183 MadeChange = true;
184 }
185
186 return MadeChange;
187}
188
189/// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
190/// Leave gcroot intrinsics; the code generator needs to see those.
191bool LowerIntrinsics::runOnFunction(Function &F) {
192 // Quick exit for functions that do not use GC.
193 if (!F.hasGC())
194 return false;
195
196 GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
197 GCStrategy &S = FI.getStrategy();
198
199 return DoLowering(F, S);
200}
201
204
205 bool MadeChange = false;
206 for (BasicBlock &BB : F)
209 if (!CI)
210 continue;
211
213 switch (F->getIntrinsicID()) {
214 default: break;
215 case Intrinsic::gcwrite: {
216 // Replace a write barrier with a simple store.
217 Value *St = new StoreInst(CI->getArgOperand(0), CI->getArgOperand(2),
218 CI->getIterator());
219 CI->replaceAllUsesWith(St);
220 CI->eraseFromParent();
221 MadeChange = true;
222 break;
223 }
224 case Intrinsic::gcread: {
225 // Replace a read barrier with a simple load.
226 Value *Ld = new LoadInst(CI->getType(), CI->getArgOperand(1), "",
227 CI->getIterator());
228 Ld->takeName(CI);
229 CI->replaceAllUsesWith(Ld);
230 CI->eraseFromParent();
231 MadeChange = true;
232 break;
233 }
234 case Intrinsic::gcroot: {
235 // Initialize the GC root, but do not delete the intrinsic. The
236 // backend needs the intrinsic to flag the stack slot.
237 Roots.push_back(
239 break;
240 }
241 }
242 }
243
244 if (Roots.size())
245 MadeChange |= InsertRootInitializers(F, Roots);
246
247 return MadeChange;
248}
249
250// -----------------------------------------------------------------------------
251
252char GCMachineCodeAnalysis::ID = 0;
253char &llvm::GCMachineCodeAnalysisID = GCMachineCodeAnalysis::ID;
254
255INITIALIZE_PASS(GCMachineCodeAnalysis, "gc-analysis",
256 "Analyze Machine Code For Garbage Collection", false, false)
257
258GCMachineCodeAnalysis::GCMachineCodeAnalysis() : MachineFunctionPass(ID) {}
259
260void GCMachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
262 AU.setPreservesAll();
263 AU.addRequired<GCModuleInfo>();
264}
265
266MCSymbol *GCMachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
268 const DebugLoc &DL) const {
270 BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
271 return Label;
272}
273
274void GCMachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
275 // Find the return address (next instruction), since that's what will be on
276 // the stack when the call is suspended and we need to inspect the stack.
278 ++RAI;
279
280 MCSymbol *Label = InsertLabel(*CI->getParent(), RAI, CI->getDebugLoc());
281 FI->addSafePoint(Label, CI->getDebugLoc());
282}
283
284void GCMachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
285 for (MachineBasicBlock &MBB : MF)
286 for (MachineInstr &MI : MBB)
287 if (MI.isCall()) {
288 // Do not treat tail or sibling call sites as safe points. This is
289 // legal since any arguments passed to the callee which live in the
290 // remnants of the callers frame will be owned and updated by the
291 // callee if required.
292 if (MI.isTerminator())
293 continue;
294 VisitCallPoint(&MI);
295 }
296}
297
298void GCMachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
299 const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
300 assert(TFI && "TargetRegisterInfo not available!");
301
303 RI != FI->roots_end();) {
304 // If the root references a dead object, no need to keep it.
305 if (MF.getFrameInfo().isDeadObjectIndex(RI->Num)) {
306 RI = FI->removeStackRoot(RI);
307 } else {
308 Register FrameReg; // FIXME: surely GCRoot ought to store the
309 // register that the offset is from?
310 auto FrameOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
311 assert(!FrameOffset.getScalable() &&
312 "Frame offsets with a scalable component are not supported");
313 RI->StackOffset = FrameOffset.getFixed();
314 ++RI;
315 }
316 }
317}
318
319bool GCMachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
320 // Quick exit for functions that do not use GC.
321 if (!MF.getFunction().hasGC())
322 return false;
323
324 FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(MF.getFunction());
326
327 // Find the size of the stack frame. There may be no correct static frame
328 // size, we use UINT64_MAX to represent this.
329 const MachineFrameInfo &MFI = MF.getFrameInfo();
330 const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
331 const bool DynamicFrameSize =
332 MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF);
333 FI->setFrameSize(DynamicFrameSize ? UINT64_MAX : MFI.getStackSize());
334
335 // Find all safe points.
336 if (FI->getStrategy().needsSafePoints())
337 FindSafePoints(MF);
338
339 // Find the concrete stack offsets for all roots (stack slots)
340 FindStackOffsets(MF);
341
342 return false;
343}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool runOnFunction(Function &F, bool PostInlining)
static bool InsertRootInitializers(Function &F, ArrayRef< AllocaInst * > Roots)
static bool CouldBecomeSafePoint(Instruction *I)
CouldBecomeSafePoint - Predicate to conservatively determine whether the instruction could introduce ...
static bool DoLowering(Function &F, GCStrategy &S)
Lower barriers out of existence (if the associated GCStrategy hasn't already done so....
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
Promote Memory to Register
Definition Mem2Reg.cpp:110
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
an instruction to allocate memory on the stack
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM Basic Block Representation.
Definition BasicBlock.h:62
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Value * getArgOperand(unsigned i) const
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Analysis pass which computes a DominatorTree.
Definition Dominators.h:283
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool hasGC() const
hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm to use during code generatio...
Definition Function.h:344
An analysis pass which caches information about the Function.
Definition GCMetadata.h:214
void setFrameSize(uint64_t S)
Definition GCMetadata.h:138
void addSafePoint(MCSymbol *Label, const DebugLoc &DL)
addSafePoint - Notes the existence of a safe point.
Definition GCMetadata.h:132
std::vector< GCRoot >::iterator roots_iterator
Definition GCMetadata.h:83
roots_iterator removeStackRoot(roots_iterator position)
removeStackRoot - Removes a root.
Definition GCMetadata.h:125
GCStrategy & getStrategy()
getStrategy - Return the GC strategy for the function.
Definition GCMetadata.h:115
roots_iterator roots_end()
Definition GCMetadata.h:147
roots_iterator roots_begin()
roots_begin/roots_end - Iterators for all roots in the function.
Definition GCMetadata.h:146
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
An analysis pass which caches information about the entire Module.
Definition GCMetadata.h:237
GCStrategy describes a garbage collector algorithm's code generation requirements,...
Definition GCStrategy.h:64
bool needsSafePoints() const
True if safe points need to be inferred on call sites.
Definition GCStrategy.h:129
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A wrapper class for inspecting calls to intrinsic functions.
An instruction for reading from memory.
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
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.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MCContext & getContext() const
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
virtual StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const
getFrameIndexReference - This method should return the base register and offset used to reference a f...
bool hasStackRealignment(const MachineFunction &MF) const
True if stack realignment is required and still possible.
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:708
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:403
self_iterator getIterator()
Definition ilist_node.h:123
Changed
#define UINT64_MAX
Definition DataTypes.h:77
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
LLVM_ABI char & GCMachineCodeAnalysisID
GCMachineCodeAnalysis - Target-independent pass to mark safe points in machine code.
LLVM_ABI char & GCLoweringID
GCLowering Pass - Used by gc.root to perform its default lowering operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:632
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI FunctionPass * createGCLoweringPass()
GCLowering Pass - Used by gc.root to perform its default lowering operations.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.