SemiSpace is a very simple copying collector. When it starts up, it
allocates two blocks of memory for the heap. It uses a simple bump-pointer
@@ -302,7 +305,8 @@ Enhancements would be welcomed.
-
The ocaml collector is invoked with llc -gc=ocaml. It supports the
+
The ocaml backend is invoked with the gc "ocaml" function attribute.
+It supports the
Objective Caml language runtime by emitting
a type-accurate stack map in the form of an ocaml 3.10.0-compatible frametable.
The linkage requirements are satisfied automatically by the ocamlopt
@@ -317,7 +321,7 @@ may use load and store instead of llvm.gcread and
@@ -335,6 +339,27 @@ specified by the runtime.
+
+
The gc function attribute is used to specify the desired collector
+algorithm to the compiler. It is equivalent to specify the collector name
+programmatically using the setCollector method of
+Function.
+
+
Specifying the collector on a per-function basis allows LLVM to link together
+programs which use different garbage collection algorithms.
+
+
Identifying GC roots on the stack: llvm.gcroot
@@ -591,6 +616,10 @@ TODO
+
User code specifies which collector plugin to use with the gc
+function attribute or, equivalently, with the setCollector method of
+Function.
+
To implement a collector plugin, it is necessary to subclass
llvm::Collector, which can be accomplished in a few lines of
boilerplate code. LLVM's infrastructure provides access to several important
@@ -616,7 +645,7 @@ namespace {
};
CollectorRegistry::Add<MyCollector>
- X("mygc", "My custom garbage collector.");
+ X("mygc", "My bespoke garbage collector.");
}
Using the LLVM makefiles (like the
-
-
-Once the plugin is compiled, user code may be compiled using llc
--load=MyGC.so -gc=mygc (though MyGC.so may have some
-other platform-specific extension).
-
-
-To use a collector in a tool other than llc, simply assign a
-Collector to the llvm::TheCollector variable:
+Once the plugin is compiled, code using it may be compiled using llc
+-load=MyGC.so (though MyGC.so may have some other
+platform-specific extension):
TheCollector = new MyGC();
-
+>$ cat sample.ll
+define void @f() gc "mygc" {
+entry:
+ ret void
+}
+$ llvm-as < sample.ll | llc -load=MyGC.so
+
+It is also possible to statically link the collector plugin into tools, such
+as a language-specific compiler front-end.
@@ -956,15 +985,18 @@ interest.
CollectorMetadata &MD = ...;
-unsigned FrameSize = MD.getFrameSize();
-size_t RootCount = MD.roots_size();
-
-for (CollectorMetadata::roots_iterator RI = MD.roots_begin(),
- RE = MD.roots_end(); RI != RE; ++RI) {
- int RootNum = RI->Num;
- int RootStackOffset = RI->StackOffset;
- Constant *RootMetadata = RI->Metadata;
+>for (iterator I = begin(), E = end(); I != E; ++I) {
+ CollectorMetadata *MD = *I;
+ unsigned FrameSize = MD->getFrameSize();
+ size_t RootCount = MD->roots_size();
+
+ for (CollectorMetadata::roots_iterator RI = MD->roots_begin(),
+ RE = MD->roots_end();
+ RI != RE; ++RI) {
+ int RootNum = RI->Num;
+ int RootStackOffset = RI->StackOffset;
+ Constant *RootMetadata = RI->Metadata;
+ }
}
LLVM automatically computes a stack map. All a Collector needs to do
@@ -1021,10 +1053,8 @@ public:
CustomWriteBarriers = true;
}
-protected:
- virtual Pass *createCustomLoweringPass() const {
- return new MyGCLoweringFunctionPass();
- }
+ virtual bool initializeCustomLowering(Module &M);
+ virtual bool performCustomLowering(Function &F);
};
If any of these flags are set, then LLVM suppresses its default lowering for
@@ -1041,56 +1071,53 @@ pass specified by the collector.
If CustomReadBarriers or CustomWriteBarriers are specified,
-the custom lowering pass must eliminate the corresponding
-barriers.
+then
performCustomLowering must eliminate the
+corresponding barriers.
-
This template can be used as a starting point for a lowering pass:
+
performCustomLowering, must comply with the same restrictions as runOnFunction, and
+that initializeCustomLowering has the same semantics as doInitialization(Module
+&).
+
+
The following can be used as a template:
#include "llvm/Function.h"
-#include "llvm/Module.h"
+>#include "llvm/Module.h"
#include "llvm/Instructions.h"
-namespace {
- class VISIBILITY_HIDDEN MyGCLoweringFunctionPass : public FunctionPass {
- static char ID;
- public:
- MyGCLoweringFunctionPass() : FunctionPass(intptr_t(&ID)) {}
-
- const char *getPassName() const { return "Lower GC Intrinsics"; }
-
- bool runOnFunction(Function &F) {
- Module *M = F.getParent();
-
- Function *GCReadInt = M->getFunction("llvm.gcread"),
- *GCWriteInt = M->getFunction("llvm.gcwrite"),
- *GCRootInt = M->getFunction("llvm.gcroot");
-
- bool MadeChange = false;
-
- for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
- for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;)
- if (CallInst *CI = dyn_cast<CallInst>(II++))
- if (Function *F = CI->getCalledFunction())
- if (F == GCWriteInt) {
- // Handle llvm.gcwrite.
- CI->eraseFromParent();
- MadeChange = true;
- } else if (F == GCReadInt) {
- // Handle llvm.gcread.
- CI->eraseFromParent();
- MadeChange = true;
- } else if (F == GCRootInt) {
- // Handle llvm.gcroot.
- CI->eraseFromParent();
- MadeChange = true;
- }
-
- return MadeChange;
- }
- };
+bool MyCollector::initializeCustomLowering(Module &M) {
+ return false;
+}
- char MyGCLoweringFunctionPass::ID = 0;
+bool MyCollector::performCustomLowering(Function &F) {
+ const Module *M = F.getParent();
+
+ Function *GCReadInt = M->getFunction("llvm.gcread"),
+ *GCWriteInt = M->getFunction("llvm.gcwrite"),
+ *GCRootInt = M->getFunction("llvm.gcroot");
+
+ bool MadeChange = false;
+
+ for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
+ for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;)
+ if (CallInst *CI = dyn_cast<CallInst>(II++))
+ if (Function *F = CI->getCalledFunction())
+ if (F == GCWriteInt) {
+ // Handle llvm.gcwrite.
+ CI->eraseFromParent();
+ MadeChange = true;
+ } else if (F == GCReadInt) {
+ // Handle llvm.gcread.
+ CI->eraseFromParent();
+ MadeChange = true;
+ } else if (F == GCRootInt) {
+ // Handle llvm.gcroot.
+ CI->eraseFromParent();
+ MadeChange = true;
+ }
+
+ return MadeChange;
}
@@ -1130,15 +1157,18 @@ namespace {
It can then use the following routines to access safe points.
-
-CollectorMetadata &MD = ...;
-size_t PointCount = MD.size();
-
-for (CollectorMetadata::iterator PI = MD.begin(),
- PE = MD.end(); PI != PE; ++PI) {
- GC::PointKind PointKind = PI->Kind;
- unsigned PointNum = PI->Num;
-}
+
for (iterator I = begin(), E = end(); I != E; ++I) {
+ CollectorMetadata *MD = *I;
+ size_t PointCount = MD->size();
+
+ for (CollectorMetadata::iterator PI = MD->begin(),
+ PE = MD->end(); PI != PE; ++PI) {
+ GC::PointKind PointKind = PI->Kind;
+ unsigned PointNum = PI->Num;
+ }
+}
+
Almost every collector requires PostCall safe points, since these
correspond to the moments when the function is suspended during a call to a
@@ -1167,40 +1197,45 @@ safe point (because only the topmost function has been patched).
LLVM allows a collector to print arbitrary assembly code before and after
the rest of a module's assembly code. From the latter callback, the collector
-can print stack maps from CollectorModuleMetadata populated by the code
-generator.
+can print stack maps built by the code generator.
-
Note that LLVM does not currently support garbage collection code generation
-in the JIT, nor using the object writers.
+
Note that LLVM does not currently have analogous APIs to support code
+generation in the JIT, nor using the object writers.
class MyCollector : public Collector {
- virtual void beginAssembly(Module &M, std::ostream &OS, AsmPrinter &AP,
- const TargetAsmInfo &TAI) const;
+public:
+ virtual void beginAssembly(std::ostream &OS, AsmPrinter &AP,
+ const TargetAsmInfo &TAI);
- virtual void finishAssembly(Module &M, CollectorModuleMetadata &MMD,
- std::ostream &OS, AsmPrinter &AP,
- const TargetAsmInfo &TAI) const;
+ virtual void finishAssembly(std::ostream &OS, AsmPrinter &AP,
+ const TargetAsmInfo &TAI);
}
The collector should use AsmPrinter and TargetAsmInfo to
-print portable assembly code to the std::ostream. The collector may
-access the stack maps for the entire module using the methods of
-CollectorModuleMetadata. Here's a realistic example:
+print portable assembly code to the
std::ostream. The collector itself
+contains the stack map for the entire module, and may access the
+
CollectorMetadata using its own
begin() and
end()
+methods. Here's a realistic example:
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/Function.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetAsmInfo.h"
-void MyCollector::finishAssembly(Module &M,
- CollectorModuleMetadata &MMD,
- std::ostream &OS, AsmPrinter &AP,
- const TargetAsmInfo &TAI) const {
+void MyCollector::beginAssembly(std::ostream &OS, AsmPrinter &AP,
+ const TargetAsmInfo &TAI) {
+ // Nothing to do.
+}
+
+void MyCollector::finishAssembly(std::ostream &OS, AsmPrinter &AP,
+ const TargetAsmInfo &TAI) {
// Set up for emitting addresses.
const char *AddressDirective;
int AddressAlignLog;
- if (TAI.getAddressSize() == sizeof(int32_t)) {
+ if (AP.TM.getTargetData()->getPointerSize() == sizeof(int32_t)) {
AddressDirective = TAI.getData32bitsDirective();
AddressAlignLog = 2;
} else {
@@ -1212,8 +1247,7 @@ void MyCollector::finishAssembly(Module &M,
AP.SwitchToDataSection(TAI.getDataSection());
// For each function...
- for (CollectorModuleMetadata::iterator FI = MMD.begin(),
- FE = MMD.end(); FI != FE; ++FI) {
+ for (iterator FI = begin(), FE = end(); FI != FE; ++FI) {
CollectorMetadata &MD = **FI;
// Emit this data structure:
--
cgit v1.2.3