2015-01-16 03:29:42 +08:00
|
|
|
//===-- GCRootLowering.cpp - Garbage collection infrastructure ------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-01-16 03:29:42 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the lowering for the gc.root mechanism.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-01-17 04:07:33 +08:00
|
|
|
#include "llvm/CodeGen/GCMetadata.h"
|
2015-01-16 03:29:42 +08:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/Passes.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
2015-01-16 03:29:42 +08:00
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
#include "llvm/InitializePasses.h"
|
2022-03-08 07:25:52 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2015-01-16 03:39:17 +08:00
|
|
|
/// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
|
|
|
|
/// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
|
|
|
|
/// directed by the GCStrategy. It also performs automatic root initialization
|
|
|
|
/// and custom intrinsic lowering.
|
|
|
|
class LowerIntrinsics : public FunctionPass {
|
2018-11-12 05:13:09 +08:00
|
|
|
bool DoLowering(Function &F, GCStrategy &S);
|
2015-01-16 03:39:17 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
|
|
|
|
LowerIntrinsics();
|
2016-10-01 10:56:57 +08:00
|
|
|
StringRef getPassName() const override;
|
2015-01-16 03:39:17 +08:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
|
|
|
|
|
|
|
bool doInitialization(Module &M) override;
|
|
|
|
bool runOnFunction(Function &F) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// GCMachineCodeAnalysis - This is a target-independent pass over the machine
|
|
|
|
/// function representation to identify safe points for the garbage collector
|
|
|
|
/// in the machine code. It inserts labels at safe points and populates a
|
|
|
|
/// GCMetadata record for each function.
|
|
|
|
class GCMachineCodeAnalysis : public MachineFunctionPass {
|
|
|
|
GCFunctionInfo *FI;
|
|
|
|
const TargetInstrInfo *TII;
|
|
|
|
|
|
|
|
void FindSafePoints(MachineFunction &MF);
|
2018-07-17 02:51:40 +08:00
|
|
|
void VisitCallPoint(MachineBasicBlock::iterator CI);
|
2015-01-16 03:39:17 +08:00
|
|
|
MCSymbol *InsertLabel(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
2016-06-12 23:39:02 +08:00
|
|
|
const DebugLoc &DL) const;
|
2015-01-16 03:39:17 +08:00
|
|
|
|
|
|
|
void FindStackOffsets(MachineFunction &MF);
|
|
|
|
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
|
|
|
|
GCMachineCodeAnalysis();
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
|
|
|
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
};
|
2015-06-23 17:49:53 +08:00
|
|
|
}
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
2015-01-16 03:39:17 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(LowerIntrinsics, "gc-lowering", "GC Lowering", false,
|
|
|
|
false)
|
2015-01-16 03:29:42 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(GCModuleInfo)
|
|
|
|
INITIALIZE_PASS_END(LowerIntrinsics, "gc-lowering", "GC Lowering", false, false)
|
|
|
|
|
2015-01-16 03:39:17 +08:00
|
|
|
FunctionPass *llvm::createGCLoweringPass() { return new LowerIntrinsics(); }
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
char LowerIntrinsics::ID = 0;
|
2021-07-08 05:25:24 +08:00
|
|
|
char &llvm::GCLoweringID = LowerIntrinsics::ID;
|
2015-01-16 03:29:42 +08:00
|
|
|
|
2015-01-16 03:39:17 +08:00
|
|
|
LowerIntrinsics::LowerIntrinsics() : FunctionPass(ID) {
|
|
|
|
initializeLowerIntrinsicsPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2015-01-16 03:29:42 +08:00
|
|
|
|
2016-10-01 10:56:57 +08:00
|
|
|
StringRef LowerIntrinsics::getPassName() const {
|
2015-01-16 03:29:42 +08:00
|
|
|
return "Lower Garbage Collection Instructions";
|
|
|
|
}
|
|
|
|
|
|
|
|
void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
FunctionPass::getAnalysisUsage(AU);
|
|
|
|
AU.addRequired<GCModuleInfo>();
|
|
|
|
AU.addPreserved<DominatorTreeWrapperPass>();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// doInitialization - If this module uses the GC intrinsics, find them now.
|
|
|
|
bool LowerIntrinsics::doInitialization(Module &M) {
|
|
|
|
GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
|
|
|
|
assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
|
2021-02-13 15:44:33 +08:00
|
|
|
for (Function &F : M)
|
|
|
|
if (!F.isDeclaration() && F.hasGC())
|
|
|
|
MI->getFunctionInfo(F); // Instantiate the GC strategy.
|
2015-01-16 03:29:42 +08:00
|
|
|
|
2015-01-29 03:28:03 +08:00
|
|
|
return false;
|
2015-01-16 03:29:42 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 03:49:25 +08:00
|
|
|
/// CouldBecomeSafePoint - Predicate to conservatively determine whether the
|
|
|
|
/// instruction could introduce a safe point.
|
|
|
|
static bool CouldBecomeSafePoint(Instruction *I) {
|
|
|
|
// The natural definition of instructions which could introduce safe points
|
|
|
|
// are:
|
|
|
|
//
|
|
|
|
// - call, invoke (AfterCall, BeforeCall)
|
|
|
|
// - phis (Loops)
|
|
|
|
// - invoke, ret, unwind (Exit)
|
|
|
|
//
|
|
|
|
// However, instructions as seemingly inoccuous as arithmetic can become
|
|
|
|
// libcalls upon lowering (e.g., div i64 on a 32-bit platform), so instead
|
|
|
|
// it is necessary to take a conservative approach.
|
|
|
|
|
|
|
|
if (isa<AllocaInst>(I) || isa<GetElementPtrInst>(I) || isa<StoreInst>(I) ||
|
|
|
|
isa<LoadInst>(I))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// llvm.gcroot is safe because it doesn't do anything at runtime.
|
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(I))
|
|
|
|
if (Function *F = CI->getCalledFunction())
|
2015-05-21 01:16:39 +08:00
|
|
|
if (Intrinsic::ID IID = F->getIntrinsicID())
|
2015-01-16 03:49:25 +08:00
|
|
|
if (IID == Intrinsic::gcroot)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-12 10:26:26 +08:00
|
|
|
static bool InsertRootInitializers(Function &F, ArrayRef<AllocaInst *> Roots) {
|
2015-01-16 03:29:42 +08:00
|
|
|
// Scroll past alloca instructions.
|
|
|
|
BasicBlock::iterator IP = F.getEntryBlock().begin();
|
2015-01-16 03:39:17 +08:00
|
|
|
while (isa<AllocaInst>(IP))
|
|
|
|
++IP;
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
// Search for initializers in the initial BB.
|
2015-01-16 03:39:17 +08:00
|
|
|
SmallPtrSet<AllocaInst *, 16> InitedRoots;
|
2015-10-10 02:44:40 +08:00
|
|
|
for (; !CouldBecomeSafePoint(&*IP); ++IP)
|
2015-01-16 03:29:42 +08:00
|
|
|
if (StoreInst *SI = dyn_cast<StoreInst>(IP))
|
|
|
|
if (AllocaInst *AI =
|
2015-01-16 03:39:17 +08:00
|
|
|
dyn_cast<AllocaInst>(SI->getOperand(1)->stripPointerCasts()))
|
2015-01-16 03:29:42 +08:00
|
|
|
InitedRoots.insert(AI);
|
|
|
|
|
|
|
|
// Add root initializers.
|
|
|
|
bool MadeChange = false;
|
|
|
|
|
2018-11-12 10:26:26 +08:00
|
|
|
for (AllocaInst *Root : Roots)
|
|
|
|
if (!InitedRoots.count(Root)) {
|
2020-05-15 05:48:10 +08:00
|
|
|
new StoreInst(
|
2018-11-12 10:26:26 +08:00
|
|
|
ConstantPointerNull::get(cast<PointerType>(Root->getAllocatedType())),
|
2020-05-15 05:48:10 +08:00
|
|
|
Root, Root->getNextNode());
|
2015-01-16 03:29:42 +08:00
|
|
|
MadeChange = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MadeChange;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// runOnFunction - Replace gcread/gcwrite intrinsics with loads and stores.
|
|
|
|
/// Leave gcroot intrinsics; the code generator needs to see those.
|
|
|
|
bool LowerIntrinsics::runOnFunction(Function &F) {
|
|
|
|
// Quick exit for functions that do not use GC.
|
|
|
|
if (!F.hasGC())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
|
|
|
|
GCStrategy &S = FI.getStrategy();
|
|
|
|
|
2018-11-12 05:13:09 +08:00
|
|
|
return DoLowering(F, S);
|
2015-01-16 03:29:42 +08:00
|
|
|
}
|
|
|
|
|
2018-11-12 05:13:09 +08:00
|
|
|
/// Lower barriers out of existance (if the associated GCStrategy hasn't
|
|
|
|
/// already done so...), and insert initializing stores to roots as a defensive
|
|
|
|
/// measure. Given we're going to report all roots live at all safepoints, we
|
|
|
|
/// need to be able to ensure each root has been initialized by the point the
|
|
|
|
/// first safepoint is reached. This really should have been done by the
|
|
|
|
/// frontend, but the old API made this non-obvious, so we do a potentially
|
2020-02-18 10:48:38 +08:00
|
|
|
/// redundant store just in case.
|
2018-11-12 05:13:09 +08:00
|
|
|
bool LowerIntrinsics::DoLowering(Function &F, GCStrategy &S) {
|
2015-01-16 03:39:17 +08:00
|
|
|
SmallVector<AllocaInst *, 32> Roots;
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
bool MadeChange = false;
|
2020-02-18 10:48:38 +08:00
|
|
|
for (BasicBlock &BB : F)
|
2021-11-02 13:38:48 +08:00
|
|
|
for (Instruction &I : llvm::make_early_inc_range(BB)) {
|
|
|
|
IntrinsicInst *CI = dyn_cast<IntrinsicInst>(&I);
|
2018-11-12 10:26:26 +08:00
|
|
|
if (!CI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Function *F = CI->getCalledFunction();
|
|
|
|
switch (F->getIntrinsicID()) {
|
|
|
|
default: break;
|
|
|
|
case Intrinsic::gcwrite: {
|
|
|
|
// Replace a write barrier with a simple store.
|
|
|
|
Value *St = new StoreInst(CI->getArgOperand(0),
|
|
|
|
CI->getArgOperand(2), CI);
|
|
|
|
CI->replaceAllUsesWith(St);
|
|
|
|
CI->eraseFromParent();
|
|
|
|
MadeChange = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Intrinsic::gcread: {
|
|
|
|
// Replace a read barrier with a simple load.
|
2019-02-02 04:44:24 +08:00
|
|
|
Value *Ld = new LoadInst(CI->getType(), CI->getArgOperand(1), "", CI);
|
2018-11-12 10:26:26 +08:00
|
|
|
Ld->takeName(CI);
|
|
|
|
CI->replaceAllUsesWith(Ld);
|
|
|
|
CI->eraseFromParent();
|
|
|
|
MadeChange = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Intrinsic::gcroot: {
|
|
|
|
// Initialize the GC root, but do not delete the intrinsic. The
|
|
|
|
// backend needs the intrinsic to flag the stack slot.
|
|
|
|
Roots.push_back(
|
|
|
|
cast<AllocaInst>(CI->getArgOperand(0)->stripPointerCasts()));
|
|
|
|
break;
|
|
|
|
}
|
2015-01-16 03:29:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Roots.size())
|
2018-11-12 10:26:26 +08:00
|
|
|
MadeChange |= InsertRootInitializers(F, Roots);
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
return MadeChange;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
char GCMachineCodeAnalysis::ID = 0;
|
|
|
|
char &llvm::GCMachineCodeAnalysisID = GCMachineCodeAnalysis::ID;
|
|
|
|
|
|
|
|
INITIALIZE_PASS(GCMachineCodeAnalysis, "gc-analysis",
|
|
|
|
"Analyze Machine Code For Garbage Collection", false, false)
|
|
|
|
|
2015-01-16 03:39:17 +08:00
|
|
|
GCMachineCodeAnalysis::GCMachineCodeAnalysis() : MachineFunctionPass(ID) {}
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
void GCMachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
|
|
AU.setPreservesAll();
|
|
|
|
AU.addRequired<GCModuleInfo>();
|
|
|
|
}
|
|
|
|
|
|
|
|
MCSymbol *GCMachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator MI,
|
2016-06-12 23:39:02 +08:00
|
|
|
const DebugLoc &DL) const {
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Label = MBB.getParent()->getContext().createTempSymbol();
|
2015-01-16 03:29:42 +08:00
|
|
|
BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
|
|
|
|
return Label;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GCMachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
|
2018-11-13 04:15:34 +08:00
|
|
|
// Find the return address (next instruction), since that's what will be on
|
|
|
|
// the stack when the call is suspended and we need to inspect the stack.
|
2015-01-16 03:29:42 +08:00
|
|
|
MachineBasicBlock::iterator RAI = CI;
|
|
|
|
++RAI;
|
|
|
|
|
2018-11-13 06:03:53 +08:00
|
|
|
MCSymbol *Label = InsertLabel(*CI->getParent(), RAI, CI->getDebugLoc());
|
|
|
|
FI->addSafePoint(Label, CI->getDebugLoc());
|
2015-01-16 03:29:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GCMachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
|
2018-11-12 10:26:26 +08:00
|
|
|
for (MachineBasicBlock &MBB : MF)
|
2021-11-17 01:01:56 +08:00
|
|
|
for (MachineInstr &MI : MBB)
|
|
|
|
if (MI.isCall()) {
|
2015-01-17 03:33:28 +08:00
|
|
|
// Do not treat tail or sibling call sites as safe points. This is
|
|
|
|
// legal since any arguments passed to the callee which live in the
|
|
|
|
// remnants of the callers frame will be owned and updated by the
|
|
|
|
// callee if required.
|
2021-11-17 01:01:56 +08:00
|
|
|
if (MI.isTerminator())
|
2015-01-17 03:33:28 +08:00
|
|
|
continue;
|
2021-11-17 01:01:56 +08:00
|
|
|
VisitCallPoint(&MI);
|
2015-01-17 03:33:28 +08:00
|
|
|
}
|
2015-01-16 03:29:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GCMachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
|
2015-02-21 02:44:15 +08:00
|
|
|
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
|
2015-01-16 03:29:42 +08:00
|
|
|
assert(TFI && "TargetRegisterInfo not available!");
|
|
|
|
|
|
|
|
for (GCFunctionInfo::roots_iterator RI = FI->roots_begin();
|
|
|
|
RI != FI->roots_end();) {
|
|
|
|
// If the root references a dead object, no need to keep it.
|
2016-07-29 02:40:00 +08:00
|
|
|
if (MF.getFrameInfo().isDeadObjectIndex(RI->Num)) {
|
2015-01-16 03:29:42 +08:00
|
|
|
RI = FI->removeStackRoot(RI);
|
|
|
|
} else {
|
2020-04-08 04:33:58 +08:00
|
|
|
Register FrameReg; // FIXME: surely GCRoot ought to store the
|
2015-08-15 10:32:35 +08:00
|
|
|
// register that the offset is from?
|
2020-11-04 16:56:54 +08:00
|
|
|
auto FrameOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
|
|
|
|
assert(!FrameOffset.getScalable() &&
|
|
|
|
"Frame offsets with a scalable component are not supported");
|
|
|
|
RI->StackOffset = FrameOffset.getFixed();
|
2015-01-16 03:29:42 +08:00
|
|
|
++RI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GCMachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
|
|
|
|
// Quick exit for functions that do not use GC.
|
2017-12-16 06:22:58 +08:00
|
|
|
if (!MF.getFunction().hasGC())
|
2015-01-16 03:29:42 +08:00
|
|
|
return false;
|
|
|
|
|
2017-12-16 06:22:58 +08:00
|
|
|
FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(MF.getFunction());
|
2015-02-21 02:44:15 +08:00
|
|
|
TII = MF.getSubtarget().getInstrInfo();
|
2015-01-16 03:29:42 +08:00
|
|
|
|
2015-04-02 13:00:40 +08:00
|
|
|
// Find the size of the stack frame. There may be no correct static frame
|
|
|
|
// size, we use UINT64_MAX to represent this.
|
2016-07-29 02:40:00 +08:00
|
|
|
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
2015-04-02 13:00:40 +08:00
|
|
|
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
|
2021-03-15 21:01:34 +08:00
|
|
|
const bool DynamicFrameSize =
|
|
|
|
MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF);
|
2016-07-29 02:40:00 +08:00
|
|
|
FI->setFrameSize(DynamicFrameSize ? UINT64_MAX : MFI.getStackSize());
|
2015-01-16 03:29:42 +08:00
|
|
|
|
|
|
|
// Find all safe points.
|
2015-04-02 13:00:40 +08:00
|
|
|
if (FI->getStrategy().needsSafePoints())
|
|
|
|
FindSafePoints(MF);
|
2015-01-16 03:29:42 +08:00
|
|
|
|
2015-04-02 13:00:40 +08:00
|
|
|
// Find the concrete stack offsets for all roots (stack slots)
|
2015-01-16 03:29:42 +08:00
|
|
|
FindStackOffsets(MF);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|