mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-29 10:32:47 +00:00
CollectorMetadata and Collector are rejiggered to get along with
per-function collector model. Collector is now the factory for CollectorMetadata, so the latter may be subclassed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44827 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
519452282b
commit
ad93c4f936
@ -36,8 +36,10 @@
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="#intrinsics">Collection intrinsics</a>
|
||||
<li><a href="#core">Core support</a>
|
||||
<ul>
|
||||
<li><a href="#gcattr">Specifying GC code generation:
|
||||
<tt>gc "..."</tt></a></li>
|
||||
<li><a href="#gcroot">Identifying GC roots on the stack:
|
||||
<tt>llvm.gcroot</tt></a></li>
|
||||
<li><a href="#barriers">Reading and writing references in the heap</a>
|
||||
@ -198,11 +200,12 @@ garbage collector implementations in two manners:</p>
|
||||
|
||||
<ul>
|
||||
<li>Emitting compatible code, including initialization in the main
|
||||
program.</li>
|
||||
program if necessary.</li>
|
||||
<li>Loading a compiler plugin if the collector is not statically linked with
|
||||
your compiler. For <tt>llc</tt>, use the <tt>-load</tt> option.</li>
|
||||
<li>Selecting the collection algorithm with <tt>llc -gc=</tt> or by setting
|
||||
<tt>llvm::TheCollector</tt>.</li>
|
||||
<li>Selecting the collection algorithm by applying the <tt>gc "..."</tt>
|
||||
attribute to your garbage collected functions, or equivalently with
|
||||
the <tt>setCollector</tt> method.</li>
|
||||
<li>Linking your final executable with the garbage collector runtime.</li>
|
||||
</ul>
|
||||
|
||||
@ -211,7 +214,7 @@ garbage collector implementations in two manners:</p>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Collector</th>
|
||||
<th><tt>llc</tt> arguments</th>
|
||||
<th><tt>gc</tt> attribute</th>
|
||||
<th>Linkage</th>
|
||||
<th><tt>gcroot</tt></th>
|
||||
<th><tt>gcread</tt></th>
|
||||
@ -219,7 +222,7 @@ garbage collector implementations in two manners:</p>
|
||||
</tr>
|
||||
<tr valign="baseline">
|
||||
<td><a href="#semispace">SemiSpace</a></td>
|
||||
<td><tt>-gc=shadow-stack</tt></td>
|
||||
<td><tt>gc "shadow-stack"</tt></td>
|
||||
<td>TODO FIXME</td>
|
||||
<td>required</td>
|
||||
<td>optional</td>
|
||||
@ -227,7 +230,7 @@ garbage collector implementations in two manners:</p>
|
||||
</tr>
|
||||
<tr valign="baseline">
|
||||
<td><a href="#ocaml">Ocaml</a></td>
|
||||
<td><tt>-gc=ocaml</tt></td>
|
||||
<td><tt>gc "ocaml"</tt></td>
|
||||
<td><i>provided by ocamlopt</i></td>
|
||||
<td>required</td>
|
||||
<td>optional</td>
|
||||
@ -252,11 +255,12 @@ collectors may require user programs to utilize.</p>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>The ShadowStack collector is invoked with <tt>llc -gc=shadow-stack</tt>.
|
||||
<p>The ShadowStack backend is invoked with the <tt>gc "shadow-stack"</tt>
|
||||
function attribute.
|
||||
Unlike many collectors which rely on a cooperative code generator to generate
|
||||
stack maps, this algorithm carefully maintains a linked list of stack root
|
||||
descriptors [<a href="#henderson02">Henderson2002</a>]. This so-called "shadow
|
||||
stack," mirrors the machine stack. Maintaining this data structure is slower
|
||||
stack" mirrors the machine stack. Maintaining this data structure is slower
|
||||
than using stack maps, but has a significant portability advantage because it
|
||||
requires no special support from the target code generator.</p>
|
||||
|
||||
@ -264,7 +268,7 @@ requires no special support from the target code generator.</p>
|
||||
program may use <tt>load</tt> and <tt>store</tt> instead of <tt>llvm.gcread</tt>
|
||||
and <tt>llvm.gcwrite</tt>.</p>
|
||||
|
||||
<p>The ShadowStack collector is a compiler plugin only. It must be paired with a
|
||||
<p>ShadowStack is a code generator plugin only. It must be paired with a
|
||||
compatible runtime.</p>
|
||||
|
||||
</div>
|
||||
@ -277,8 +281,7 @@ compatible runtime.</p>
|
||||
<div class="doc_text">
|
||||
|
||||
<p>The SemiSpace runtime implements with the <a href="runtime">suggested
|
||||
runtime interface</a> and is compatible the ShadowStack collector's code
|
||||
generation.</p>
|
||||
runtime interface</a> and is compatible the ShadowStack backend.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>The ocaml collector is invoked with <tt>llc -gc=ocaml</tt>. It supports the
|
||||
<p>The ocaml backend is invoked with the <tt>gc "ocaml"</tt> function attribute.
|
||||
It supports the
|
||||
<a href="http://caml.inria.fr/">Objective Caml</a> 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 <tt>ocamlopt</tt>
|
||||
@ -317,7 +321,7 @@ may use <tt>load</tt> and <tt>store</tt> instead of <tt>llvm.gcread</tt> and
|
||||
|
||||
<!-- *********************************************************************** -->
|
||||
<div class="doc_section">
|
||||
<a name="intrinsics">Collection intrinsics</a>
|
||||
<a name="core">Core support</a>
|
||||
</div>
|
||||
<!-- *********************************************************************** -->
|
||||
|
||||
@ -335,6 +339,27 @@ specified by the runtime.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="gcattr">Specifying GC code generation: <tt>gc "..."</tt></a>
|
||||
</div>
|
||||
|
||||
<div class="doc_code"><tt>
|
||||
define <i>ty</i> @<i>name</i>(...) <u>gc "<i>collector</i>"</u> { ...
|
||||
</tt></div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>The <tt>gc</tt> function attribute is used to specify the desired collector
|
||||
algorithm to the compiler. It is equivalent to specify the collector name
|
||||
programmatically using the <tt>setCollector</tt> method of
|
||||
<tt>Function</tt>.</p>
|
||||
|
||||
<p>Specifying the collector on a per-function basis allows LLVM to link together
|
||||
programs which use different garbage collection algorithms.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="gcroot">Identifying GC roots on the stack: <tt>llvm.gcroot</tt></a>
|
||||
@ -591,6 +616,10 @@ TODO
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>User code specifies which collector plugin to use with the <tt>gc</tt>
|
||||
function attribute or, equivalently, with the <tt>setCollector</tt> method of
|
||||
<tt>Function</tt>.</p>
|
||||
|
||||
<p>To implement a collector plugin, it is necessary to subclass
|
||||
<tt>llvm::Collector</tt>, 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.");
|
||||
}</pre></blockquote>
|
||||
|
||||
<p>Using the LLVM makefiles (like the <a
|
||||
@ -632,20 +661,20 @@ LOADABLE_MODULE = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common</pre></blockquote>
|
||||
|
||||
<blockquote><pre
|
||||
></pre></blockquote>
|
||||
|
||||
<p>Once the plugin is compiled, user code may be compiled using <tt>llc
|
||||
-load=<var>MyGC.so</var> -gc=mygc</tt> (though <var>MyGC.so</var> may have some
|
||||
other platform-specific extension).</p>
|
||||
|
||||
<!-- BEGIN FIXME: Gross -->
|
||||
<p>To use a collector in a tool other than <tt>llc</tt>, simply assign a
|
||||
<tt>Collector</tt> to the <tt>llvm::TheCollector</tt> variable:</p>
|
||||
<p>Once the plugin is compiled, code using it may be compiled using <tt>llc
|
||||
-load=<var>MyGC.so</var></tt> (though <var>MyGC.so</var> may have some other
|
||||
platform-specific extension):</p>
|
||||
|
||||
<blockquote><pre
|
||||
>TheCollector = new MyGC();</pre></blockquote>
|
||||
<!-- /FIXME GROSS -->
|
||||
>$ cat sample.ll
|
||||
define void @f() gc "mygc" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
$ llvm-as < sample.ll | llc -load=MyGC.so</pre></blockquote>
|
||||
|
||||
<p>It is also possible to statically link the collector plugin into tools, such
|
||||
as a language-specific compiler front-end.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@ -956,15 +985,18 @@ interest.</p>
|
||||
<div class="doc_text">
|
||||
|
||||
<blockquote><pre
|
||||
>CollectorMetadata &MD = ...;
|
||||
unsigned FrameSize = MD.getFrameSize();
|
||||
size_t RootCount = MD.roots_size();
|
||||
>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;
|
||||
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;
|
||||
}
|
||||
}</pre></blockquote>
|
||||
|
||||
<p>LLVM automatically computes a stack map. All a <tt>Collector</tt> 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);
|
||||
};</pre></blockquote>
|
||||
|
||||
<p>If any of these flags are set, then LLVM suppresses its default lowering for
|
||||
@ -1041,56 +1071,53 @@ pass specified by the collector.</p>
|
||||
</ul>
|
||||
|
||||
<p>If <tt>CustomReadBarriers</tt> or <tt>CustomWriteBarriers</tt> are specified,
|
||||
the custom lowering pass <strong>must</strong> eliminate the corresponding
|
||||
barriers.</p>
|
||||
then <tt>performCustomLowering</tt> <strong>must</strong> eliminate the
|
||||
corresponding barriers.</p>
|
||||
|
||||
<p>This template can be used as a starting point for a lowering pass:</p>
|
||||
<p><tt>performCustomLowering</tt>, must comply with the same restrictions as <a
|
||||
href="WritingAnLLVMPass.html#runOnFunction"><tt>runOnFunction</tt></a>, and
|
||||
that <tt>initializeCustomLowering</tt> has the same semantics as <a
|
||||
href="WritingAnLLVMPass.html#doInitialization_mod"><tt>doInitialization(Module
|
||||
&)</tt></a>.</p>
|
||||
|
||||
<p>The following can be used as a template:</p>
|
||||
|
||||
<blockquote><pre
|
||||
>#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;
|
||||
}</pre></blockquote>
|
||||
|
||||
</div>
|
||||
@ -1130,15 +1157,18 @@ namespace {
|
||||
|
||||
<p>It can then use the following routines to access safe points.</p>
|
||||
|
||||
<blockquote><pre>
|
||||
CollectorMetadata &MD = ...;
|
||||
size_t PointCount = MD.size();
|
||||
<blockquote><pre
|
||||
>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;
|
||||
}</pre></blockquote>
|
||||
for (CollectorMetadata::iterator PI = MD->begin(),
|
||||
PE = MD->end(); PI != PE; ++PI) {
|
||||
GC::PointKind PointKind = PI->Kind;
|
||||
unsigned PointNum = PI->Num;
|
||||
}
|
||||
}
|
||||
</pre></blockquote>
|
||||
|
||||
<p>Almost every collector requires <tt>PostCall</tt> 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).</p>
|
||||
|
||||
<p>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 <tt>CollectorModuleMetadata</tt> populated by the code
|
||||
generator.</p>
|
||||
can print stack maps built by the code generator.</p>
|
||||
|
||||
<p>Note that LLVM does not currently support garbage collection code generation
|
||||
in the JIT, nor using the object writers.</p>
|
||||
<p>Note that LLVM does not currently have analogous APIs to support code
|
||||
generation in the JIT, nor using the object writers.</p>
|
||||
|
||||
<blockquote><pre
|
||||
>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);
|
||||
}</pre></blockquote>
|
||||
|
||||
<p>The collector should use <tt>AsmPrinter</tt> and <tt>TargetAsmInfo</tt> to
|
||||
print portable assembly code to the <tt>std::ostream</tt>. The collector may
|
||||
access the stack maps for the entire module using the methods of
|
||||
<tt>CollectorModuleMetadata</tt>. Here's a realistic example:</p>
|
||||
print portable assembly code to the <tt>std::ostream</tt>. The collector itself
|
||||
contains the stack map for the entire module, and may access the
|
||||
<tt>CollectorMetadata</tt> using its own <tt>begin()</tt> and <tt>end()</tt>
|
||||
methods. Here's a realistic example:</p>
|
||||
|
||||
<blockquote><pre
|
||||
>#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:
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// GCInfo records sufficient information about a machine function to enable
|
||||
// Collector records sufficient information about a machine function to enable
|
||||
// accurate garbage collectors. Specifically:
|
||||
//
|
||||
// - Safe points
|
||||
@ -25,8 +25,8 @@
|
||||
// This generic information should used by ABI-specific passes to emit support
|
||||
// tables for the runtime garbage collector.
|
||||
//
|
||||
// GCSafePointPass identifies the GC safe points in the machine code. (Roots are
|
||||
// identified in SelectionDAGISel.)
|
||||
// MachineCodeAnalysis identifies the GC safe points in the machine code. (Roots
|
||||
// are identified in SelectionDAGISel.)
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -35,19 +35,25 @@
|
||||
|
||||
#include "llvm/CodeGen/CollectorMetadata.h"
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class FunctionPassManager;
|
||||
class PassManager;
|
||||
class TargetAsmInfo;
|
||||
|
||||
|
||||
/// Collector describes a garbage collector's code generation requirements,
|
||||
/// and provides overridable hooks for those needs which cannot be abstractly
|
||||
/// described.
|
||||
class Collector {
|
||||
public:
|
||||
typedef std::vector<CollectorMetadata*> list_type;
|
||||
typedef list_type::iterator iterator;
|
||||
|
||||
private:
|
||||
friend class CollectorModuleMetadata;
|
||||
const Module *M;
|
||||
std::string Name;
|
||||
|
||||
list_type Functions;
|
||||
|
||||
protected:
|
||||
unsigned NeededSafePoints; //< Bitmask of required safe points.
|
||||
bool CustomReadBarriers; //< Default is to insert loads.
|
||||
@ -55,16 +61,20 @@ namespace llvm {
|
||||
bool CustomRoots; //< Default is to pass through to backend.
|
||||
bool InitRoots; //< If set, roots are nulled during lowering.
|
||||
|
||||
/// If any of the actions are set to Custom, this is expected to be
|
||||
/// overriden to create a transform to lower those actions to LLVM IR.
|
||||
virtual Pass *createCustomLoweringPass() const;
|
||||
|
||||
public:
|
||||
Collector();
|
||||
|
||||
virtual ~Collector();
|
||||
|
||||
|
||||
/// getName - The name of the collector, for debugging.
|
||||
///
|
||||
const std::string &getName() const { return Name; }
|
||||
|
||||
/// getModule - The module upon which the collector is operating.
|
||||
///
|
||||
const Module &getModule() const { return *M; }
|
||||
|
||||
/// True if this collector requires safe points of any kind. By default,
|
||||
/// none are recorded.
|
||||
bool needsSafePoints() const { return NeededSafePoints != 0; }
|
||||
@ -94,40 +104,30 @@ namespace llvm {
|
||||
bool initializeRoots() const { return InitRoots; }
|
||||
|
||||
|
||||
/// Adds LLVM IR transforms to handle collection intrinsics. By default,
|
||||
/// read- and write barriers are replaced with direct memory accesses, and
|
||||
/// roots are passed on to the code generator.
|
||||
void addLoweringPasses(FunctionPassManager &PM) const;
|
||||
|
||||
/// Same as addLoweringPasses(FunctionPassManager &), except uses a
|
||||
/// PassManager for compatibility with unusual backends (such as MSIL or
|
||||
/// CBackend).
|
||||
void addLoweringPasses(PassManager &PM) const;
|
||||
|
||||
/// Adds target-independent MachineFunction pass to mark safe points. This
|
||||
/// is added very late during code generation, just prior to output, and
|
||||
/// importantly after all CFG transformations (like branch folding).
|
||||
void addGenericMachineCodePass(FunctionPassManager &PM,
|
||||
const TargetMachine &TM, bool Fast) const;
|
||||
|
||||
/// beginAssembly/finishAssembly - Emit module metadata as assembly code.
|
||||
virtual void beginAssembly(Module &M, std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) const;
|
||||
virtual void finishAssembly(Module &M, CollectorModuleMetadata &CMM,
|
||||
std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) const;
|
||||
|
||||
private:
|
||||
bool NeedsDefaultLoweringPass() const;
|
||||
bool NeedsCustomLoweringPass() const;
|
||||
virtual void beginAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
virtual void finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
/// begin/end - Iterators for function metadata.
|
||||
///
|
||||
iterator begin() { return Functions.begin(); }
|
||||
iterator end() { return Functions.end(); }
|
||||
|
||||
/// insertFunctionMetadata - Creates metadata for a function.
|
||||
///
|
||||
CollectorMetadata *insertFunctionMetadata(const Function &F);
|
||||
|
||||
/// initializeCustomLowering/performCustomLowering - If any of the actions
|
||||
/// are set to custom, performCustomLowering must be overriden to create a
|
||||
/// transform to lower those actions to LLVM IR. initializeCustomLowering
|
||||
/// is optional to override. These are the only Collector methods through
|
||||
/// which the LLVM IR can be modified.
|
||||
virtual bool initializeCustomLowering(Module &F);
|
||||
virtual bool performCustomLowering(Function &F);
|
||||
};
|
||||
|
||||
|
||||
/// If set, the code generator should generate garbage collection as specified
|
||||
/// by the collector properties.
|
||||
extern const Collector *TheCollector; // FIXME: Find a better home!
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// This file declares the CollectorMetadata and CollectorModuleMetadata classes,
|
||||
// which are used as a communication channel from the target code generator
|
||||
// to the target garbage collector. This interface allows code generators and
|
||||
// to the target garbage collectors. This interface allows code generators and
|
||||
// garbage collectors to be developed independently.
|
||||
//
|
||||
// The CollectorMetadata class records the data necessary to build a type
|
||||
@ -37,19 +37,14 @@
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class Collector;
|
||||
class Constant;
|
||||
|
||||
|
||||
/// Creates a pass to print collector metadata.
|
||||
///
|
||||
Pass *createCollectorMetadataPrinter(std::ostream &OS);
|
||||
|
||||
/// Creates a pass to destroy collector metadata.
|
||||
///
|
||||
Pass *createCollectorMetadataDeleter();
|
||||
class TargetAsmInfo;
|
||||
|
||||
|
||||
namespace GC {
|
||||
@ -77,7 +72,7 @@ namespace llvm {
|
||||
struct GCRoot {
|
||||
int Num; //< Usually a frame index.
|
||||
int StackOffset; //< Offset from the stack pointer.
|
||||
Constant *Metadata; //< From the call to llvm.gcroot.
|
||||
Constant *Metadata; //< Metadata straight from the call to llvm.gcroot.
|
||||
|
||||
GCRoot(int N, Constant *MD) : Num(N), StackOffset(-1), Metadata(MD) {}
|
||||
};
|
||||
@ -93,6 +88,7 @@ namespace llvm {
|
||||
|
||||
private:
|
||||
const Function &F;
|
||||
Collector &C;
|
||||
uint64_t FrameSize;
|
||||
std::vector<GCRoot> Roots;
|
||||
std::vector<GCPoint> SafePoints;
|
||||
@ -107,14 +103,18 @@ namespace llvm {
|
||||
// The bit vector is the more compact representation where >3.2% of roots
|
||||
// are live per safe point (1.5% on 64-bit hosts).
|
||||
|
||||
friend class CollectorModuleMetadata;
|
||||
CollectorMetadata(const Function &F);
|
||||
|
||||
public:
|
||||
CollectorMetadata(const Function &F, Collector &C);
|
||||
~CollectorMetadata();
|
||||
|
||||
/// getFunction - Return the function to which this metadata applies.
|
||||
///
|
||||
const Function &getFunction() const { return F; }
|
||||
|
||||
/// getCollector - Return the collector for the function.
|
||||
///
|
||||
Collector &getCollector() { return C; }
|
||||
|
||||
/// addStackRoot - Registers a root that lives on the stack. Num is the
|
||||
/// stack object ID for the alloca (if the code generator is using
|
||||
/// MachineFrameInfo).
|
||||
@ -157,37 +157,36 @@ namespace llvm {
|
||||
/// CollectorModuleMetadata - Garbage collection metadata for a whole module.
|
||||
///
|
||||
class CollectorModuleMetadata : public ImmutablePass {
|
||||
typedef std::vector<CollectorMetadata*> list_type;
|
||||
typedef DenseMap<const Function*,CollectorMetadata*> map_type;
|
||||
typedef StringMap<Collector*> collector_map_type;
|
||||
typedef std::vector<Collector*> list_type;
|
||||
typedef DenseMap<const Function*,CollectorMetadata*> function_map_type;
|
||||
|
||||
Module *Mod;
|
||||
list_type Functions;
|
||||
map_type Map;
|
||||
collector_map_type NameMap;
|
||||
list_type Collectors;
|
||||
function_map_type Map;
|
||||
|
||||
Collector *getOrCreateCollector(const Module *M, const std::string &Name);
|
||||
|
||||
public:
|
||||
typedef list_type::iterator iterator;
|
||||
typedef list_type::const_iterator iterator;
|
||||
|
||||
static char ID;
|
||||
|
||||
CollectorModuleMetadata();
|
||||
~CollectorModuleMetadata();
|
||||
|
||||
/// clear - Used to delete module metadata. Collector invokes this as
|
||||
/// necessary.
|
||||
/// clear - Used to delete module metadata. The metadata deleter pass calls
|
||||
/// this.
|
||||
void clear();
|
||||
|
||||
/// begin/end - Iterators for function metadata.
|
||||
/// begin/end - Iterators for collectors.
|
||||
///
|
||||
iterator begin() { return Functions.begin(); }
|
||||
iterator end() { return Functions.end(); }
|
||||
iterator begin() const { return Collectors.begin(); }
|
||||
iterator end() const { return Collectors.end(); }
|
||||
|
||||
/// insert - Creates metadata for a function.
|
||||
/// get - Look up function metadata.
|
||||
///
|
||||
CollectorMetadata& insert(const Function *F);
|
||||
|
||||
/// get - Looks up existing function metadata.
|
||||
///
|
||||
CollectorMetadata* get(const Function *F) const;
|
||||
CollectorMetadata &get(const Function &F);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,9 @@ namespace llvm {
|
||||
///
|
||||
typedef Registry<Collector> CollectorRegistry;
|
||||
|
||||
/// FIXME: Collector instances are not useful on their own. These no longer
|
||||
/// serve any purpose except to link in the plugins.
|
||||
|
||||
/// Creates an ocaml-compatible garbage collector.
|
||||
Collector *createOcamlCollector();
|
||||
|
||||
|
@ -135,6 +135,24 @@ namespace llvm {
|
||||
/// for the Sparc.
|
||||
FunctionPass *getRegisterAllocator(TargetMachine &T);
|
||||
|
||||
/// IntrinsicLowering Pass - Performs target-independent LLVM IR
|
||||
/// transformations for highly portable collectors.
|
||||
FunctionPass *createGCLoweringPass();
|
||||
|
||||
/// MachineCodeAnalysis Pass - Target-independent pass to mark safe points in
|
||||
/// machine code. Must be added very late during code generation, just prior
|
||||
/// to output, and importantly after all CFG transformations (such as branch
|
||||
/// folding).
|
||||
FunctionPass *createGCMachineCodeAnalysisPass();
|
||||
|
||||
/// Deleter Pass - Releases collector metadata.
|
||||
///
|
||||
FunctionPass *createCollectorMetadataDeleter();
|
||||
|
||||
/// Creates a pass to print collector metadata.
|
||||
///
|
||||
FunctionPass *createCollectorMetadataPrinter(std::ostream &OS);
|
||||
|
||||
/// createMachineLICMPass - This pass performs LICM on machine instructions.
|
||||
///
|
||||
FunctionPass *createMachineLICMPass();
|
||||
|
@ -13,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/Collector.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
@ -29,38 +30,40 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
/// This pass rewrites calls to the llvm.gcread or llvm.gcwrite intrinsics,
|
||||
/// replacing them with simple loads and stores as directed by the Collector.
|
||||
/// This is useful for most garbage collectors.
|
||||
/// LowerIntrinsics - This pass rewrites calls to the llvm.gcread or
|
||||
/// llvm.gcwrite intrinsics, replacing them with simple loads and stores as
|
||||
/// directed by the Collector. It also performs automatic root initialization
|
||||
/// and custom intrinsic lowering.
|
||||
class VISIBILITY_HIDDEN LowerIntrinsics : public FunctionPass {
|
||||
const Collector &Coll;
|
||||
|
||||
/// GCRootInt, GCReadInt, GCWriteInt - The function prototypes for the
|
||||
/// llvm.gc* intrinsics.
|
||||
Function *GCRootInt, *GCReadInt, *GCWriteInt;
|
||||
|
||||
static bool NeedsDefaultLoweringPass(const Collector &C);
|
||||
static bool NeedsCustomLoweringPass(const Collector &C);
|
||||
static bool CouldBecomeSafePoint(Instruction *I);
|
||||
static void InsertRootInitializers(Function &F,
|
||||
bool PerformDefaultLowering(Function &F, Collector &Coll);
|
||||
static bool InsertRootInitializers(Function &F,
|
||||
AllocaInst **Roots, unsigned Count);
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LowerIntrinsics(const Collector &GC);
|
||||
LowerIntrinsics();
|
||||
const char *getPassName() const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
bool doInitialization(Module &M);
|
||||
bool runOnFunction(Function &F);
|
||||
};
|
||||
|
||||
|
||||
/// 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 the GCInfo class.
|
||||
/// MachineCodeAnalysis - 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
|
||||
/// CollectorMetadata record for each function.
|
||||
class VISIBILITY_HIDDEN MachineCodeAnalysis : public MachineFunctionPass {
|
||||
const Collector &Coll;
|
||||
const TargetMachine &Targ;
|
||||
|
||||
const TargetMachine *TM;
|
||||
CollectorMetadata *MD;
|
||||
MachineModuleInfo *MMI;
|
||||
const TargetInstrInfo *TII;
|
||||
@ -76,7 +79,7 @@ namespace {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
MachineCodeAnalysis(const Collector &C, const TargetMachine &T);
|
||||
MachineCodeAnalysis();
|
||||
const char *getPassName() const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
@ -87,8 +90,6 @@ namespace {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const Collector *llvm::TheCollector = 0;
|
||||
|
||||
Collector::Collector() :
|
||||
NeededSafePoints(0),
|
||||
CustomReadBarriers(false),
|
||||
@ -97,85 +98,85 @@ Collector::Collector() :
|
||||
InitRoots(true)
|
||||
{}
|
||||
|
||||
Collector::~Collector() {}
|
||||
|
||||
void Collector::addLoweringPasses(FunctionPassManager &PM) const {
|
||||
if (NeedsDefaultLoweringPass())
|
||||
PM.add(new LowerIntrinsics(*this));
|
||||
|
||||
if (NeedsCustomLoweringPass())
|
||||
PM.add(createCustomLoweringPass());
|
||||
Collector::~Collector() {
|
||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
delete *I;
|
||||
|
||||
Functions.clear();
|
||||
}
|
||||
|
||||
void Collector::addLoweringPasses(PassManager &PM) const {
|
||||
if (NeedsDefaultLoweringPass())
|
||||
PM.add(new LowerIntrinsics(*this));
|
||||
|
||||
if (NeedsCustomLoweringPass())
|
||||
PM.add(createCustomLoweringPass());
|
||||
}
|
||||
|
||||
void Collector::addGenericMachineCodePass(FunctionPassManager &PM,
|
||||
const TargetMachine &TM,
|
||||
bool Fast) const {
|
||||
if (needsSafePoints())
|
||||
PM.add(new MachineCodeAnalysis(*this, TM));
|
||||
}
|
||||
|
||||
bool Collector::NeedsDefaultLoweringPass() const {
|
||||
// Default lowering is necessary only if read or write barriers have a default
|
||||
// action. The default for roots is no action.
|
||||
return !customWriteBarrier()
|
||||
|| !customReadBarrier()
|
||||
|| initializeRoots();
|
||||
}
|
||||
|
||||
bool Collector::NeedsCustomLoweringPass() const {
|
||||
// Custom lowering is only necessary if enabled for some action.
|
||||
return customWriteBarrier()
|
||||
|| customReadBarrier()
|
||||
|| customRoots();
|
||||
}
|
||||
|
||||
Pass *Collector::createCustomLoweringPass() const {
|
||||
cerr << "Collector must override createCustomLoweringPass.\n";
|
||||
|
||||
bool Collector::initializeCustomLowering(Module &M) { return false; }
|
||||
|
||||
bool Collector::performCustomLowering(Function &F) {
|
||||
cerr << "gc " << getName() << " must override performCustomLowering.\n";
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Collector::beginAssembly(Module &M, std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) const {
|
||||
void Collector::beginAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) {
|
||||
// Default is no action.
|
||||
}
|
||||
|
||||
void Collector::finishAssembly(Module &M, CollectorModuleMetadata &CMM,
|
||||
std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) const {
|
||||
void Collector::finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) {
|
||||
// Default is no action.
|
||||
}
|
||||
|
||||
CollectorMetadata *Collector::insertFunctionMetadata(const Function &F) {
|
||||
CollectorMetadata *CM = new CollectorMetadata(F, *this);
|
||||
Functions.push_back(CM);
|
||||
return CM;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
FunctionPass *llvm::createGCLoweringPass() {
|
||||
return new LowerIntrinsics();
|
||||
}
|
||||
|
||||
char LowerIntrinsics::ID = 0;
|
||||
|
||||
LowerIntrinsics::LowerIntrinsics(const Collector &C)
|
||||
: FunctionPass((intptr_t)&ID), Coll(C),
|
||||
LowerIntrinsics::LowerIntrinsics()
|
||||
: FunctionPass((intptr_t)&ID),
|
||||
GCRootInt(0), GCReadInt(0), GCWriteInt(0) {}
|
||||
|
||||
const char *LowerIntrinsics::getPassName() const {
|
||||
return "Lower Garbage Collection Instructions";
|
||||
}
|
||||
|
||||
/// doInitialization - If this module uses the GC intrinsics, find them now. If
|
||||
/// not, this pass does not do anything.
|
||||
void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
FunctionPass::getAnalysisUsage(AU);
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
}
|
||||
|
||||
/// doInitialization - If this module uses the GC intrinsics, find them now.
|
||||
bool LowerIntrinsics::doInitialization(Module &M) {
|
||||
GCReadInt = M.getFunction("llvm.gcread");
|
||||
GCWriteInt = M.getFunction("llvm.gcwrite");
|
||||
GCRootInt = M.getFunction("llvm.gcroot");
|
||||
return false;
|
||||
|
||||
// FIXME: This is rather antisocial in the context of a JIT since it performs
|
||||
// work against the entire module. But this cannot be done at
|
||||
// runFunction time (initializeCustomLowering likely needs to change
|
||||
// the module).
|
||||
CollectorModuleMetadata *CMM = getAnalysisToUpdate<CollectorModuleMetadata>();
|
||||
assert(CMM && "LowerIntrinsics didn't require CollectorModuleMetadata!?");
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (I->hasCollector())
|
||||
CMM->get(*I); // Instantiate the Collector.
|
||||
|
||||
bool MadeChange = false;
|
||||
for (CollectorModuleMetadata::iterator I = CMM->begin(),
|
||||
E = CMM->end(); I != E; ++I)
|
||||
if (NeedsCustomLoweringPass(**I))
|
||||
if ((*I)->initializeCustomLowering(M))
|
||||
MadeChange = true;
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
void LowerIntrinsics::InsertRootInitializers(Function &F, AllocaInst **Roots,
|
||||
bool LowerIntrinsics::InsertRootInitializers(Function &F, AllocaInst **Roots,
|
||||
unsigned Count) {
|
||||
// Scroll past alloca instructions.
|
||||
BasicBlock::iterator IP = F.getEntryBlock().begin();
|
||||
@ -190,11 +191,32 @@ void LowerIntrinsics::InsertRootInitializers(Function &F, AllocaInst **Roots,
|
||||
InitedRoots.insert(AI);
|
||||
|
||||
// Add root initializers.
|
||||
bool MadeChange = false;
|
||||
|
||||
for (AllocaInst **I = Roots, **E = Roots + Count; I != E; ++I)
|
||||
if (!InitedRoots.count(*I))
|
||||
if (!InitedRoots.count(*I)) {
|
||||
new StoreInst(ConstantPointerNull::get(cast<PointerType>(
|
||||
cast<PointerType>((*I)->getType())->getElementType())),
|
||||
*I, IP);
|
||||
MadeChange = true;
|
||||
}
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
bool LowerIntrinsics::NeedsDefaultLoweringPass(const Collector &C) {
|
||||
// Default lowering is necessary only if read or write barriers have a default
|
||||
// action. The default for roots is no action.
|
||||
return !C.customWriteBarrier()
|
||||
|| !C.customReadBarrier()
|
||||
|| C.initializeRoots();
|
||||
}
|
||||
|
||||
bool LowerIntrinsics::NeedsCustomLoweringPass(const Collector &C) {
|
||||
// Custom lowering is only necessary if enabled for some action.
|
||||
return C.customWriteBarrier()
|
||||
|| C.customReadBarrier()
|
||||
|| C.customRoots();
|
||||
}
|
||||
|
||||
/// CouldBecomeSafePoint - Predicate to conservatively determine whether the
|
||||
@ -228,9 +250,24 @@ bool LowerIntrinsics::CouldBecomeSafePoint(Instruction *I) {
|
||||
/// 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 programs that do not declare the intrinsics.
|
||||
if (!GCReadInt && !GCWriteInt && !GCRootInt) return false;
|
||||
// Quick exit for functions that do not use GC.
|
||||
if (!F.hasCollector()) return false;
|
||||
|
||||
CollectorMetadata &MD = getAnalysis<CollectorModuleMetadata>().get(F);
|
||||
Collector &Coll = MD.getCollector();
|
||||
|
||||
bool MadeChange = false;
|
||||
|
||||
if (NeedsDefaultLoweringPass(Coll))
|
||||
MadeChange |= PerformDefaultLowering(F, Coll);
|
||||
|
||||
if (NeedsCustomLoweringPass(Coll))
|
||||
MadeChange |= Coll.performCustomLowering(F);
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
bool LowerIntrinsics::PerformDefaultLowering(Function &F, Collector &Coll) {
|
||||
bool LowerWr = !Coll.customWriteBarrier();
|
||||
bool LowerRd = !Coll.customReadBarrier();
|
||||
bool InitRoots = Coll.initializeRoots();
|
||||
@ -268,17 +305,21 @@ bool LowerIntrinsics::runOnFunction(Function &F) {
|
||||
}
|
||||
|
||||
if (Roots.size())
|
||||
InsertRootInitializers(F, Roots.begin(), Roots.size());
|
||||
MadeChange |= InsertRootInitializers(F, Roots.begin(), Roots.size());
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
FunctionPass *llvm::createGCMachineCodeAnalysisPass() {
|
||||
return new MachineCodeAnalysis();
|
||||
}
|
||||
|
||||
char MachineCodeAnalysis::ID = 0;
|
||||
|
||||
MachineCodeAnalysis::MachineCodeAnalysis(const Collector &C, const TargetMachine &T)
|
||||
: MachineFunctionPass(intptr_t(&ID)), Coll(C), Targ(T) {}
|
||||
MachineCodeAnalysis::MachineCodeAnalysis()
|
||||
: MachineFunctionPass(intptr_t(&ID)) {}
|
||||
|
||||
const char *MachineCodeAnalysis::getPassName() const {
|
||||
return "Analyze Machine Code For Garbage Collection";
|
||||
@ -304,10 +345,10 @@ void MachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
|
||||
MachineBasicBlock::iterator RAI = CI;
|
||||
++RAI;
|
||||
|
||||
if (Coll.needsSafePoint(GC::PreCall))
|
||||
if (MD->getCollector().needsSafePoint(GC::PreCall))
|
||||
MD->addSafePoint(GC::PreCall, InsertLabel(*CI->getParent(), CI));
|
||||
|
||||
if (Coll.needsSafePoint(GC::PostCall))
|
||||
if (MD->getCollector().needsSafePoint(GC::PostCall))
|
||||
MD->addSafePoint(GC::PostCall, InsertLabel(*CI->getParent(), RAI));
|
||||
}
|
||||
|
||||
@ -323,7 +364,7 @@ void MachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
|
||||
void MachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
|
||||
uint64_t StackSize = MFI->getStackSize();
|
||||
uint64_t OffsetAdjustment = MFI->getOffsetAdjustment();
|
||||
uint64_t OffsetOfLocalArea = Targ.getFrameInfo()->getOffsetOfLocalArea();
|
||||
uint64_t OffsetOfLocalArea = TM->getFrameInfo()->getOffsetOfLocalArea();
|
||||
|
||||
for (CollectorMetadata::roots_iterator RI = MD->roots_begin(),
|
||||
RE = MD->roots_end(); RI != RE; ++RI)
|
||||
@ -332,12 +373,16 @@ void MachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
|
||||
}
|
||||
|
||||
bool MachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
|
||||
if (!Coll.needsSafePoints())
|
||||
// Quick exit for functions that do not use GC.
|
||||
if (!MF.getFunction()->hasCollector()) return false;
|
||||
|
||||
MD = &getAnalysis<CollectorModuleMetadata>().get(*MF.getFunction());
|
||||
if (!MD->getCollector().needsSafePoints())
|
||||
return false;
|
||||
|
||||
MD = getAnalysis<CollectorModuleMetadata>().get(MF.getFunction());
|
||||
TM = &MF.getTarget();
|
||||
MMI = &getAnalysis<MachineModuleInfo>();
|
||||
TII = MF.getTarget().getInstrInfo();
|
||||
TII = TM->getInstrInfo();
|
||||
MFI = MF.getFrameInfo();
|
||||
|
||||
// Find the size of the stack frame.
|
||||
|
@ -13,8 +13,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/CollectorMetadata.h"
|
||||
#include "llvm/CodeGen/Collector.h"
|
||||
#include "llvm/CodeGen/Collectors.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
@ -22,7 +25,7 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN Printer : public MachineFunctionPass {
|
||||
class VISIBILITY_HIDDEN Printer : public FunctionPass {
|
||||
static char ID;
|
||||
std::ostream &OS;
|
||||
|
||||
@ -32,10 +35,10 @@ namespace {
|
||||
const char *getPassName() const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF);
|
||||
bool runOnFunction(Function &F);
|
||||
};
|
||||
|
||||
class VISIBILITY_HIDDEN Deleter : public MachineFunctionPass {
|
||||
class VISIBILITY_HIDDEN Deleter : public FunctionPass {
|
||||
static char ID;
|
||||
|
||||
public:
|
||||
@ -44,7 +47,7 @@ namespace {
|
||||
const char *getPassName() const;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF);
|
||||
bool runOnFunction(Function &F);
|
||||
bool doFinalization(Module &M);
|
||||
};
|
||||
|
||||
@ -55,8 +58,8 @@ namespace {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
CollectorMetadata::CollectorMetadata(const Function &F)
|
||||
: F(F), FrameSize(~0LL) {}
|
||||
CollectorMetadata::CollectorMetadata(const Function &F, Collector &C)
|
||||
: F(F), C(C), FrameSize(~0LL) {}
|
||||
|
||||
CollectorMetadata::~CollectorMetadata() {}
|
||||
|
||||
@ -71,46 +74,71 @@ CollectorModuleMetadata::~CollectorModuleMetadata() {
|
||||
clear();
|
||||
}
|
||||
|
||||
CollectorMetadata& CollectorModuleMetadata::insert(const Function *F) {
|
||||
assert(Map.find(F) == Map.end() && "Function GC metadata already exists!");
|
||||
CollectorMetadata *FMD = new CollectorMetadata(*F);
|
||||
Functions.push_back(FMD);
|
||||
Map[F] = FMD;
|
||||
return *FMD;
|
||||
Collector *CollectorModuleMetadata::
|
||||
getOrCreateCollector(const Module *M, const std::string &Name) {
|
||||
const char *Start = Name.c_str();
|
||||
|
||||
collector_map_type::iterator NMI = NameMap.find(Start, Start + Name.size());
|
||||
if (NMI != NameMap.end())
|
||||
return NMI->getValue();
|
||||
|
||||
for (CollectorRegistry::iterator I = CollectorRegistry::begin(),
|
||||
E = CollectorRegistry::end(); I != E; ++I) {
|
||||
if (strcmp(Start, I->getName()) == 0) {
|
||||
Collector *C = I->instantiate();
|
||||
C->M = M;
|
||||
C->Name = Name;
|
||||
NameMap.GetOrCreateValue(Start, Start + Name.size()).setValue(C);
|
||||
Collectors.push_back(C);
|
||||
return C;
|
||||
}
|
||||
}
|
||||
|
||||
cerr << "unsupported collector: " << Name << "\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
CollectorMetadata* CollectorModuleMetadata::get(const Function *F) const {
|
||||
map_type::iterator I = Map.find(F);
|
||||
if (I == Map.end())
|
||||
return 0;
|
||||
return I->second;
|
||||
CollectorMetadata &CollectorModuleMetadata::get(const Function &F) {
|
||||
assert(F.hasCollector());
|
||||
function_map_type::iterator I = Map.find(&F);
|
||||
if (I != Map.end())
|
||||
return *I->second;
|
||||
|
||||
Collector *C = getOrCreateCollector(F.getParent(), F.getCollector());
|
||||
CollectorMetadata *MD = C->insertFunctionMetadata(F);
|
||||
Map[&F] = MD;
|
||||
return *MD;
|
||||
}
|
||||
|
||||
void CollectorModuleMetadata::clear() {
|
||||
Map.clear();
|
||||
|
||||
// TODO: StringMap should provide a clear method.
|
||||
while (!NameMap.empty())
|
||||
NameMap.erase(NameMap.begin());
|
||||
|
||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
delete *I;
|
||||
|
||||
Functions.clear();
|
||||
Map.clear();
|
||||
Collectors.clear();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
char Printer::ID = 0;
|
||||
|
||||
Pass *llvm::createCollectorMetadataPrinter(std::ostream &OS) {
|
||||
FunctionPass *llvm::createCollectorMetadataPrinter(std::ostream &OS) {
|
||||
return new Printer(OS);
|
||||
}
|
||||
|
||||
Printer::Printer(std::ostream &OS)
|
||||
: MachineFunctionPass(intptr_t(&ID)), OS(OS) {}
|
||||
: FunctionPass(intptr_t(&ID)), OS(OS) {}
|
||||
|
||||
const char *Printer::getPassName() const {
|
||||
return "Print Garbage Collector Information";
|
||||
}
|
||||
|
||||
void Printer::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
FunctionPass::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
}
|
||||
@ -125,9 +153,9 @@ static const char *DescKind(GC::PointKind Kind) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Printer::runOnMachineFunction(MachineFunction &MF) {
|
||||
if (CollectorMetadata *FD =
|
||||
getAnalysis<CollectorModuleMetadata>().get(MF.getFunction())) {
|
||||
bool Printer::runOnFunction(Function &F) {
|
||||
if (F.hasCollector()) {
|
||||
CollectorMetadata *FD = &getAnalysis<CollectorModuleMetadata>().get(F);
|
||||
|
||||
OS << "GC roots for " << FD->getFunction().getNameStart() << ":\n";
|
||||
for (CollectorMetadata::roots_iterator RI = FD->roots_begin(),
|
||||
@ -160,11 +188,11 @@ bool Printer::runOnMachineFunction(MachineFunction &MF) {
|
||||
|
||||
char Deleter::ID = 0;
|
||||
|
||||
Pass *llvm::createCollectorMetadataDeleter() {
|
||||
FunctionPass *llvm::createCollectorMetadataDeleter() {
|
||||
return new Deleter();
|
||||
}
|
||||
|
||||
Deleter::Deleter() : MachineFunctionPass(intptr_t(&ID)) {}
|
||||
Deleter::Deleter() : FunctionPass(intptr_t(&ID)) {}
|
||||
|
||||
const char *Deleter::getPassName() const {
|
||||
return "Delete Garbage Collector Information";
|
||||
@ -175,11 +203,13 @@ void Deleter::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
}
|
||||
|
||||
bool Deleter::runOnMachineFunction(MachineFunction &MF) {
|
||||
bool Deleter::runOnFunction(Function &MF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Deleter::doFinalization(Module &M) {
|
||||
getAnalysis<CollectorModuleMetadata>().clear();
|
||||
CollectorModuleMetadata *CMM = getAnalysisToUpdate<CollectorModuleMetadata>();
|
||||
assert(CMM && "Deleter didn't require CollectorModuleMetadata?!");
|
||||
CMM->clear();
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user