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(Constant::getNullValue(Root->getAllocatedType()), Root,
181 std::next(Root->getIterator()));
182 MadeChange = true;
183 }
184
185 return MadeChange;
186}
187
188/// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
189/// Leave gcroot intrinsics; the code generator needs to see those.
190bool LowerIntrinsics::runOnFunction(Function &F) {
191 // Quick exit for functions that do not use GC.
192 if (!F.hasGC())
193 return false;
194
195 GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
196 GCStrategy &S = FI.getStrategy();
197
198 return DoLowering(F, S);
199}
200
203
204 bool MadeChange = false;
205 for (BasicBlock &BB : F)
208 if (!CI)
209 continue;
210
212 switch (F->getIntrinsicID()) {
213 default: break;
214 case Intrinsic::gcwrite: {
215 // Replace a write barrier with a simple store.
216 Value *St = new StoreInst(CI->getArgOperand(0), CI->getArgOperand(2),
217 CI->getIterator());
218 CI->replaceAllUsesWith(St);
219 CI->eraseFromParent();
220 MadeChange = true;
221 break;
222 }
223 case Intrinsic::gcread: {
224 // Replace a read barrier with a simple load.
225 Value *Ld = new LoadInst(CI->getType(), CI->getArgOperand(1), "",
226 CI->getIterator());
227 Ld->takeName(CI);
228 CI->replaceAllUsesWith(Ld);
229 CI->eraseFromParent();
230 MadeChange = true;
231 break;
232 }
233 case Intrinsic::gcroot: {
234 // Initialize the GC root, but do not delete the intrinsic. The
235 // backend needs the intrinsic to flag the stack slot.
236 Roots.push_back(
238 break;
239 }
240 }
241 }
242
243 if (Roots.size())
244 MadeChange |= InsertRootInitializers(F, Roots);
245
246 return MadeChange;
247}
248
249// -----------------------------------------------------------------------------
250
251char GCMachineCodeAnalysis::ID = 0;
252char &llvm::GCMachineCodeAnalysisID = GCMachineCodeAnalysis::ID;
253
254INITIALIZE_PASS(GCMachineCodeAnalysis, "gc-analysis",
255 "Analyze Machine Code For Garbage Collection", false, false)
256
257GCMachineCodeAnalysis::GCMachineCodeAnalysis() : MachineFunctionPass(ID) {}
258
259void GCMachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
261 AU.setPreservesAll();
262 AU.addRequired<GCModuleInfo>();
263}
264
265MCSymbol *GCMachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
267 const DebugLoc &DL) const {
269 BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
270 return Label;
271}
272
273void GCMachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
274 // Find the return address (next instruction), since that's what will be on
275 // the stack when the call is suspended and we need to inspect the stack.
277 ++RAI;
278
279 MCSymbol *Label = InsertLabel(*CI->getParent(), RAI, CI->getDebugLoc());
280 FI->addSafePoint(Label, CI->getDebugLoc());
281}
282
283void GCMachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
284 for (MachineBasicBlock &MBB : MF)
285 for (MachineInstr &MI : MBB)
286 if (MI.isCall()) {
287 // Do not treat tail or sibling call sites as safe points. This is
288 // legal since any arguments passed to the callee which live in the
289 // remnants of the callers frame will be owned and updated by the
290 // callee if required.
291 if (MI.isTerminator())
292 continue;
293 VisitCallPoint(&MI);
294 }
295}
296
297void GCMachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
298 const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
299 assert(TFI && "TargetRegisterInfo not available!");
300
302 RI != FI->roots_end();) {
303 // If the root references a dead object, no need to keep it.
304 if (MF.getFrameInfo().isDeadObjectIndex(RI->Num)) {
305 RI = FI->removeStackRoot(RI);
306 } else {
307 Register FrameReg; // FIXME: surely GCRoot ought to store the
308 // register that the offset is from?
309 auto FrameOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
310 assert(!FrameOffset.getScalable() &&
311 "Frame offsets with a scalable component are not supported");
312 RI->StackOffset = FrameOffset.getFixed();
313 ++RI;
314 }
315 }
316}
317
318bool GCMachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
319 // Quick exit for functions that do not use GC.
320 if (!MF.getFunction().hasGC())
321 return false;
322
323 FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(MF.getFunction());
325
326 // Find the size of the stack frame. There may be no correct static frame
327 // size, we use UINT64_MAX to represent this.
328 const MachineFrameInfo &MFI = MF.getFrameInfo();
329 const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
330 const bool DynamicFrameSize =
331 MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF);
332 FI->setFrameSize(DynamicFrameSize ? UINT64_MAX : MFI.getStackSize());
333
334 // Find all safe points.
335 if (FI->getStrategy().needsSafePoints())
336 FindSafePoints(MF);
337
338 // Find the concrete stack offsets for all roots (stack slots)
339 FindStackOffsets(MF);
340
341 return false;
342}
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.
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 Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Analysis pass which computes a DominatorTree.
Definition Dominators.h:274
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:346
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.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
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:255
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:552
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:712
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:399
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.
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:633
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.