xref: /openbsd-src/gnu/llvm/llvm/lib/CodeGen/GCRootLowering.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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