109467b48Spatrick //===-- GCRootLowering.cpp - Garbage collection infrastructure ------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file implements the lowering for the gc.root mechanism.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick
1309467b48Spatrick #include "llvm/CodeGen/GCMetadata.h"
1409467b48Spatrick #include "llvm/CodeGen/MachineFrameInfo.h"
1509467b48Spatrick #include "llvm/CodeGen/MachineFunctionPass.h"
1609467b48Spatrick #include "llvm/CodeGen/MachineInstrBuilder.h"
1709467b48Spatrick #include "llvm/CodeGen/Passes.h"
1809467b48Spatrick #include "llvm/CodeGen/TargetFrameLowering.h"
1909467b48Spatrick #include "llvm/CodeGen/TargetInstrInfo.h"
2009467b48Spatrick #include "llvm/CodeGen/TargetRegisterInfo.h"
2109467b48Spatrick #include "llvm/CodeGen/TargetSubtargetInfo.h"
2209467b48Spatrick #include "llvm/IR/Dominators.h"
2309467b48Spatrick #include "llvm/IR/IntrinsicInst.h"
2409467b48Spatrick #include "llvm/IR/Module.h"
2509467b48Spatrick #include "llvm/InitializePasses.h"
26*d415bd75Srobert #include "llvm/MC/MCContext.h"
2709467b48Spatrick
2809467b48Spatrick using namespace llvm;
2909467b48Spatrick
3009467b48Spatrick namespace {
3109467b48Spatrick
3209467b48Spatrick /// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
3309467b48Spatrick /// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
3409467b48Spatrick /// directed by the GCStrategy. It also performs automatic root initialization
3509467b48Spatrick /// and custom intrinsic lowering.
3609467b48Spatrick class LowerIntrinsics : public FunctionPass {
3709467b48Spatrick bool DoLowering(Function &F, GCStrategy &S);
3809467b48Spatrick
3909467b48Spatrick public:
4009467b48Spatrick static char ID;
4109467b48Spatrick
4209467b48Spatrick LowerIntrinsics();
4309467b48Spatrick StringRef getPassName() const override;
4409467b48Spatrick void getAnalysisUsage(AnalysisUsage &AU) const override;
4509467b48Spatrick
4609467b48Spatrick bool doInitialization(Module &M) override;
4709467b48Spatrick bool runOnFunction(Function &F) override;
4809467b48Spatrick };
4909467b48Spatrick
5009467b48Spatrick /// GCMachineCodeAnalysis - This is a target-independent pass over the machine
5109467b48Spatrick /// function representation to identify safe points for the garbage collector
5209467b48Spatrick /// in the machine code. It inserts labels at safe points and populates a
5309467b48Spatrick /// GCMetadata record for each function.
5409467b48Spatrick class GCMachineCodeAnalysis : public MachineFunctionPass {
5509467b48Spatrick GCFunctionInfo *FI;
5609467b48Spatrick const TargetInstrInfo *TII;
5709467b48Spatrick
5809467b48Spatrick void FindSafePoints(MachineFunction &MF);
5909467b48Spatrick void VisitCallPoint(MachineBasicBlock::iterator CI);
6009467b48Spatrick MCSymbol *InsertLabel(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
6109467b48Spatrick const DebugLoc &DL) const;
6209467b48Spatrick
6309467b48Spatrick void FindStackOffsets(MachineFunction &MF);
6409467b48Spatrick
6509467b48Spatrick public:
6609467b48Spatrick static char ID;
6709467b48Spatrick
6809467b48Spatrick GCMachineCodeAnalysis();
6909467b48Spatrick void getAnalysisUsage(AnalysisUsage &AU) const override;
7009467b48Spatrick
7109467b48Spatrick bool runOnMachineFunction(MachineFunction &MF) override;
7209467b48Spatrick };
7309467b48Spatrick }
7409467b48Spatrick
7509467b48Spatrick // -----------------------------------------------------------------------------
7609467b48Spatrick
7709467b48Spatrick INITIALIZE_PASS_BEGIN(LowerIntrinsics, "gc-lowering", "GC Lowering", false,
7809467b48Spatrick false)
INITIALIZE_PASS_DEPENDENCY(GCModuleInfo)7909467b48Spatrick INITIALIZE_PASS_DEPENDENCY(GCModuleInfo)
8009467b48Spatrick INITIALIZE_PASS_END(LowerIntrinsics, "gc-lowering", "GC Lowering", false, false)
8109467b48Spatrick
8209467b48Spatrick FunctionPass *llvm::createGCLoweringPass() { return new LowerIntrinsics(); }
8309467b48Spatrick
8409467b48Spatrick char LowerIntrinsics::ID = 0;
8573471bf0Spatrick char &llvm::GCLoweringID = LowerIntrinsics::ID;
8609467b48Spatrick
LowerIntrinsics()8709467b48Spatrick LowerIntrinsics::LowerIntrinsics() : FunctionPass(ID) {
8809467b48Spatrick initializeLowerIntrinsicsPass(*PassRegistry::getPassRegistry());
8909467b48Spatrick }
9009467b48Spatrick
getPassName() const9109467b48Spatrick StringRef LowerIntrinsics::getPassName() const {
9209467b48Spatrick return "Lower Garbage Collection Instructions";
9309467b48Spatrick }
9409467b48Spatrick
getAnalysisUsage(AnalysisUsage & AU) const9509467b48Spatrick void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
9609467b48Spatrick FunctionPass::getAnalysisUsage(AU);
9709467b48Spatrick AU.addRequired<GCModuleInfo>();
9809467b48Spatrick AU.addPreserved<DominatorTreeWrapperPass>();
9909467b48Spatrick }
10009467b48Spatrick
10109467b48Spatrick /// doInitialization - If this module uses the GC intrinsics, find them now.
doInitialization(Module & M)10209467b48Spatrick bool LowerIntrinsics::doInitialization(Module &M) {
10309467b48Spatrick GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
10409467b48Spatrick assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
10573471bf0Spatrick for (Function &F : M)
10673471bf0Spatrick if (!F.isDeclaration() && F.hasGC())
10773471bf0Spatrick MI->getFunctionInfo(F); // Instantiate the GC strategy.
10809467b48Spatrick
10909467b48Spatrick return false;
11009467b48Spatrick }
11109467b48Spatrick
11209467b48Spatrick /// CouldBecomeSafePoint - Predicate to conservatively determine whether the
11309467b48Spatrick /// instruction could introduce a safe point.
CouldBecomeSafePoint(Instruction * I)11409467b48Spatrick static bool CouldBecomeSafePoint(Instruction *I) {
11509467b48Spatrick // The natural definition of instructions which could introduce safe points
11609467b48Spatrick // are:
11709467b48Spatrick //
11809467b48Spatrick // - call, invoke (AfterCall, BeforeCall)
11909467b48Spatrick // - phis (Loops)
12009467b48Spatrick // - invoke, ret, unwind (Exit)
12109467b48Spatrick //
12209467b48Spatrick // However, instructions as seemingly inoccuous as arithmetic can become
12309467b48Spatrick // libcalls upon lowering (e.g., div i64 on a 32-bit platform), so instead
12409467b48Spatrick // it is necessary to take a conservative approach.
12509467b48Spatrick
12609467b48Spatrick if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I) || isa<StoreInst>(I) ||
12709467b48Spatrick isa<LoadInst>(I))
12809467b48Spatrick return false;
12909467b48Spatrick
13009467b48Spatrick // llvm.gcroot is safe because it doesn't do anything at runtime.
13109467b48Spatrick if (CallInst *CI = dyn_cast<CallInst>(I))
13209467b48Spatrick if (Function *F = CI->getCalledFunction())
13309467b48Spatrick if (Intrinsic::ID IID = F->getIntrinsicID())
13409467b48Spatrick if (IID == Intrinsic::gcroot)
13509467b48Spatrick return false;
13609467b48Spatrick
13709467b48Spatrick return true;
13809467b48Spatrick }
13909467b48Spatrick
InsertRootInitializers(Function & F,ArrayRef<AllocaInst * > Roots)14009467b48Spatrick static bool InsertRootInitializers(Function &F, ArrayRef<AllocaInst *> Roots) {
14109467b48Spatrick // Scroll past alloca instructions.
14209467b48Spatrick BasicBlock::iterator IP = F.getEntryBlock().begin();
14309467b48Spatrick while (isa<AllocaInst>(IP))
14409467b48Spatrick ++IP;
14509467b48Spatrick
14609467b48Spatrick // Search for initializers in the initial BB.
14709467b48Spatrick SmallPtrSet<AllocaInst *, 16> InitedRoots;
14809467b48Spatrick for (; !CouldBecomeSafePoint(&*IP); ++IP)
14909467b48Spatrick if (StoreInst *SI = dyn_cast<StoreInst>(IP))
15009467b48Spatrick if (AllocaInst *AI =
15109467b48Spatrick dyn_cast<AllocaInst>(SI->getOperand(1)->stripPointerCasts()))
15209467b48Spatrick InitedRoots.insert(AI);
15309467b48Spatrick
15409467b48Spatrick // Add root initializers.
15509467b48Spatrick bool MadeChange = false;
15609467b48Spatrick
15709467b48Spatrick for (AllocaInst *Root : Roots)
15809467b48Spatrick if (!InitedRoots.count(Root)) {
159097a140dSpatrick new StoreInst(
16009467b48Spatrick ConstantPointerNull::get(cast<PointerType>(Root->getAllocatedType())),
161097a140dSpatrick Root, Root->getNextNode());
16209467b48Spatrick MadeChange = true;
16309467b48Spatrick }
16409467b48Spatrick
16509467b48Spatrick return MadeChange;
16609467b48Spatrick }
16709467b48Spatrick
16809467b48Spatrick /// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
16909467b48Spatrick /// Leave gcroot intrinsics; the code generator needs to see those.
runOnFunction(Function & F)17009467b48Spatrick bool LowerIntrinsics::runOnFunction(Function &F) {
17109467b48Spatrick // Quick exit for functions that do not use GC.
17209467b48Spatrick if (!F.hasGC())
17309467b48Spatrick return false;
17409467b48Spatrick
17509467b48Spatrick GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
17609467b48Spatrick GCStrategy &S = FI.getStrategy();
17709467b48Spatrick
17809467b48Spatrick return DoLowering(F, S);
17909467b48Spatrick }
18009467b48Spatrick
18109467b48Spatrick /// Lower barriers out of existance (if the associated GCStrategy hasn't
18209467b48Spatrick /// already done so...), and insert initializing stores to roots as a defensive
18309467b48Spatrick /// measure. Given we're going to report all roots live at all safepoints, we
18409467b48Spatrick /// need to be able to ensure each root has been initialized by the point the
18509467b48Spatrick /// first safepoint is reached. This really should have been done by the
18609467b48Spatrick /// frontend, but the old API made this non-obvious, so we do a potentially
18709467b48Spatrick /// redundant store just in case.
DoLowering(Function & F,GCStrategy & S)18809467b48Spatrick bool LowerIntrinsics::DoLowering(Function &F, GCStrategy &S) {
18909467b48Spatrick SmallVector<AllocaInst *, 32> Roots;
19009467b48Spatrick
19109467b48Spatrick bool MadeChange = false;
19209467b48Spatrick for (BasicBlock &BB : F)
193*d415bd75Srobert for (Instruction &I : llvm::make_early_inc_range(BB)) {
194*d415bd75Srobert IntrinsicInst *CI = dyn_cast<IntrinsicInst>(&I);
19509467b48Spatrick if (!CI)
19609467b48Spatrick continue;
19709467b48Spatrick
19809467b48Spatrick Function *F = CI->getCalledFunction();
19909467b48Spatrick switch (F->getIntrinsicID()) {
20009467b48Spatrick default: break;
20109467b48Spatrick case Intrinsic::gcwrite: {
20209467b48Spatrick // Replace a write barrier with a simple store.
20309467b48Spatrick Value *St = new StoreInst(CI->getArgOperand(0),
20409467b48Spatrick CI->getArgOperand(2), CI);
20509467b48Spatrick CI->replaceAllUsesWith(St);
20609467b48Spatrick CI->eraseFromParent();
20709467b48Spatrick MadeChange = true;
20809467b48Spatrick break;
20909467b48Spatrick }
21009467b48Spatrick case Intrinsic::gcread: {
21109467b48Spatrick // Replace a read barrier with a simple load.
21209467b48Spatrick Value *Ld = new LoadInst(CI->getType(), CI->getArgOperand(1), "", CI);
21309467b48Spatrick Ld->takeName(CI);
21409467b48Spatrick CI->replaceAllUsesWith(Ld);
21509467b48Spatrick CI->eraseFromParent();
21609467b48Spatrick MadeChange = true;
21709467b48Spatrick break;
21809467b48Spatrick }
21909467b48Spatrick case Intrinsic::gcroot: {
22009467b48Spatrick // Initialize the GC root, but do not delete the intrinsic. The
22109467b48Spatrick // backend needs the intrinsic to flag the stack slot.
22209467b48Spatrick Roots.push_back(
22309467b48Spatrick cast<AllocaInst>(CI->getArgOperand(0)->stripPointerCasts()));
22409467b48Spatrick break;
22509467b48Spatrick }
22609467b48Spatrick }
22709467b48Spatrick }
22809467b48Spatrick
22909467b48Spatrick if (Roots.size())
23009467b48Spatrick MadeChange |= InsertRootInitializers(F, Roots);
23109467b48Spatrick
23209467b48Spatrick return MadeChange;
23309467b48Spatrick }
23409467b48Spatrick
23509467b48Spatrick // -----------------------------------------------------------------------------
23609467b48Spatrick
23709467b48Spatrick char GCMachineCodeAnalysis::ID = 0;
23809467b48Spatrick char &llvm::GCMachineCodeAnalysisID = GCMachineCodeAnalysis::ID;
23909467b48Spatrick
24009467b48Spatrick INITIALIZE_PASS(GCMachineCodeAnalysis, "gc-analysis",
24109467b48Spatrick "Analyze Machine Code For Garbage Collection", false, false)
24209467b48Spatrick
GCMachineCodeAnalysis()24309467b48Spatrick GCMachineCodeAnalysis::GCMachineCodeAnalysis() : MachineFunctionPass(ID) {}
24409467b48Spatrick
getAnalysisUsage(AnalysisUsage & AU) const24509467b48Spatrick void GCMachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
24609467b48Spatrick MachineFunctionPass::getAnalysisUsage(AU);
24709467b48Spatrick AU.setPreservesAll();
24809467b48Spatrick AU.addRequired<GCModuleInfo>();
24909467b48Spatrick }
25009467b48Spatrick
InsertLabel(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,const DebugLoc & DL) const25109467b48Spatrick MCSymbol *GCMachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
25209467b48Spatrick MachineBasicBlock::iterator MI,
25309467b48Spatrick const DebugLoc &DL) const {
25409467b48Spatrick MCSymbol *Label = MBB.getParent()->getContext().createTempSymbol();
25509467b48Spatrick BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
25609467b48Spatrick return Label;
25709467b48Spatrick }
25809467b48Spatrick
VisitCallPoint(MachineBasicBlock::iterator CI)25909467b48Spatrick void GCMachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
26009467b48Spatrick // Find the return address (next instruction), since that's what will be on
26109467b48Spatrick // the stack when the call is suspended and we need to inspect the stack.
26209467b48Spatrick MachineBasicBlock::iterator RAI = CI;
26309467b48Spatrick ++RAI;
26409467b48Spatrick
26509467b48Spatrick MCSymbol *Label = InsertLabel(*CI->getParent(), RAI, CI->getDebugLoc());
26609467b48Spatrick FI->addSafePoint(Label, CI->getDebugLoc());
26709467b48Spatrick }
26809467b48Spatrick
FindSafePoints(MachineFunction & MF)26909467b48Spatrick void GCMachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
27009467b48Spatrick for (MachineBasicBlock &MBB : MF)
271*d415bd75Srobert for (MachineInstr &MI : MBB)
272*d415bd75Srobert if (MI.isCall()) {
27309467b48Spatrick // Do not treat tail or sibling call sites as safe points. This is
27409467b48Spatrick // legal since any arguments passed to the callee which live in the
27509467b48Spatrick // remnants of the callers frame will be owned and updated by the
27609467b48Spatrick // callee if required.
277*d415bd75Srobert if (MI.isTerminator())
27809467b48Spatrick continue;
279*d415bd75Srobert VisitCallPoint(&MI);
28009467b48Spatrick }
28109467b48Spatrick }
28209467b48Spatrick
FindStackOffsets(MachineFunction & MF)28309467b48Spatrick void GCMachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
28409467b48Spatrick const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
28509467b48Spatrick assert(TFI && "TargetRegisterInfo not available!");
28609467b48Spatrick
28709467b48Spatrick for (GCFunctionInfo::roots_iterator RI = FI->roots_begin();
28809467b48Spatrick RI != FI->roots_end();) {
28909467b48Spatrick // If the root references a dead object, no need to keep it.
29009467b48Spatrick if (MF.getFrameInfo().isDeadObjectIndex(RI->Num)) {
29109467b48Spatrick RI = FI->removeStackRoot(RI);
29209467b48Spatrick } else {
293097a140dSpatrick Register FrameReg; // FIXME: surely GCRoot ought to store the
29409467b48Spatrick // register that the offset is from?
29573471bf0Spatrick auto FrameOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
29673471bf0Spatrick assert(!FrameOffset.getScalable() &&
29773471bf0Spatrick "Frame offsets with a scalable component are not supported");
29873471bf0Spatrick RI->StackOffset = FrameOffset.getFixed();
29909467b48Spatrick ++RI;
30009467b48Spatrick }
30109467b48Spatrick }
30209467b48Spatrick }
30309467b48Spatrick
runOnMachineFunction(MachineFunction & MF)30409467b48Spatrick bool GCMachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
30509467b48Spatrick // Quick exit for functions that do not use GC.
30609467b48Spatrick if (!MF.getFunction().hasGC())
30709467b48Spatrick return false;
30809467b48Spatrick
30909467b48Spatrick FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(MF.getFunction());
31009467b48Spatrick TII = MF.getSubtarget().getInstrInfo();
31109467b48Spatrick
31209467b48Spatrick // Find the size of the stack frame. There may be no correct static frame
31309467b48Spatrick // size, we use UINT64_MAX to represent this.
31409467b48Spatrick const MachineFrameInfo &MFI = MF.getFrameInfo();
31509467b48Spatrick const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
31673471bf0Spatrick const bool DynamicFrameSize =
31773471bf0Spatrick MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF);
31809467b48Spatrick FI->setFrameSize(DynamicFrameSize ? UINT64_MAX : MFI.getStackSize());
31909467b48Spatrick
32009467b48Spatrick // Find all safe points.
32109467b48Spatrick if (FI->getStrategy().needsSafePoints())
32209467b48Spatrick FindSafePoints(MF);
32309467b48Spatrick
32409467b48Spatrick // Find the concrete stack offsets for all roots (stack slots)
32509467b48Spatrick FindStackOffsets(MF);
32609467b48Spatrick
32709467b48Spatrick return false;
32809467b48Spatrick }
329