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