mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
Rename some GC classes so that their roll will hopefully be clearer.
In particular, Collector was confusing to implementors. Several thought that this compile-time class was the place to implement their runtime GC heap. Of course, it doesn't even exist at runtime. Specifically, the renames are: Collector -> GCStrategy CollectorMetadata -> GCFunctionInfo CollectorModuleMetadata -> GCModuleInfo CollectorRegistry -> GCRegistry Function::getCollector -> getGC (setGC, hasGC, clearGC) Several accessors and nested types have also been renamed to be consistent. These changes should be obvious. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@54899 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
94fb5f2a70
commit
5eca075b74
@ -366,8 +366,8 @@ external is_intrinsic : llvalue -> bool = "llvm_is_intrinsic"
|
||||
external function_call_conv : llvalue -> int = "llvm_function_call_conv"
|
||||
external set_function_call_conv : int -> llvalue -> unit
|
||||
= "llvm_set_function_call_conv"
|
||||
external collector : llvalue -> string option = "llvm_collector"
|
||||
external set_collector : string option -> llvalue -> unit = "llvm_set_collector"
|
||||
external gc : llvalue -> string option = "llvm_gc"
|
||||
external set_gc : string option -> llvalue -> unit = "llvm_set_gc"
|
||||
external function_begin : llmodule -> (llmodule, llvalue) llpos
|
||||
= "llvm_function_begin"
|
||||
external function_succ : llvalue -> (llmodule, llvalue) llpos
|
||||
|
@ -921,14 +921,14 @@ external function_call_conv : llvalue -> int = "llvm_function_call_conv"
|
||||
external set_function_call_conv : int -> llvalue -> unit
|
||||
= "llvm_set_function_call_conv"
|
||||
|
||||
(** [collector f] returns [Some name] if the function [f] has a garbage
|
||||
(** [gc f] returns [Some name] if the function [f] has a garbage
|
||||
collection algorithm specified and [None] otherwise.
|
||||
See the method [llvm::Function::getCollector]. *)
|
||||
external collector : llvalue -> string option = "llvm_collector"
|
||||
See the method [llvm::Function::getGC]. *)
|
||||
external gc : llvalue -> string option = "llvm_gc"
|
||||
|
||||
(** [set_collector gc f] sets the collection algorithm for the function [f] to
|
||||
[gc]. See the method [llvm::Function::setCollector]. *)
|
||||
external set_collector : string option -> llvalue -> unit = "llvm_set_collector"
|
||||
(** [set_gc gc f] sets the collection algorithm for the function [f] to
|
||||
[gc]. See the method [llvm::Function::setGC]. *)
|
||||
external set_gc : string option -> llvalue -> unit = "llvm_set_gc"
|
||||
|
||||
|
||||
(** {7 Operations on params} *)
|
||||
|
@ -643,13 +643,13 @@ CAMLprim value llvm_set_function_call_conv(value Id, LLVMValueRef Fn) {
|
||||
}
|
||||
|
||||
/* llvalue -> string option */
|
||||
CAMLprim value llvm_collector(LLVMValueRef Fn) {
|
||||
const char *Collector;
|
||||
CAMLprim value llvm_gc(LLVMValueRef Fn) {
|
||||
const char *GC;
|
||||
CAMLparam0();
|
||||
CAMLlocal2(Name, Option);
|
||||
|
||||
if ((Collector = LLVMGetCollector(Fn))) {
|
||||
Name = copy_string(Collector);
|
||||
if ((GC = LLVMGetGC(Fn))) {
|
||||
Name = copy_string(GC);
|
||||
|
||||
Option = alloc(1, 0);
|
||||
Field(Option, 0) = Name;
|
||||
@ -660,8 +660,8 @@ CAMLprim value llvm_collector(LLVMValueRef Fn) {
|
||||
}
|
||||
|
||||
/* string option -> llvalue -> unit */
|
||||
CAMLprim value llvm_set_collector(value GC, LLVMValueRef Fn) {
|
||||
LLVMSetCollector(Fn, GC == Val_int(0)? 0 : String_val(Field(GC, 0)));
|
||||
CAMLprim value llvm_set_gc(value GC, LLVMValueRef Fn) {
|
||||
LLVMSetGC(Fn, GC == Val_int(0)? 0 : String_val(Field(GC, 0)));
|
||||
return Val_unit;
|
||||
}
|
||||
|
||||
|
@ -411,8 +411,8 @@ void LLVMDeleteFunction(LLVMValueRef Fn);
|
||||
unsigned LLVMGetIntrinsicID(LLVMValueRef Fn);
|
||||
unsigned LLVMGetFunctionCallConv(LLVMValueRef Fn);
|
||||
void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC);
|
||||
const char *LLVMGetCollector(LLVMValueRef Fn);
|
||||
void LLVMSetCollector(LLVMValueRef Fn, const char *Coll);
|
||||
const char *LLVMGetGC(LLVMValueRef Fn);
|
||||
void LLVMSetGC(LLVMValueRef Fn, const char *Name);
|
||||
|
||||
/* Operations on parameters */
|
||||
unsigned LLVMCountParams(LLVMValueRef Fn);
|
||||
|
@ -60,7 +60,7 @@ namespace bitc {
|
||||
/// MODULE_CODE_PURGEVALS: [numvals]
|
||||
MODULE_CODE_PURGEVALS = 10,
|
||||
|
||||
MODULE_CODE_COLLECTORNAME = 11 // COLLECTORNAME: [strchr x N]
|
||||
MODULE_CODE_GCNAME = 11 // GCNAME: [strchr x N]
|
||||
};
|
||||
|
||||
/// PARAMATTR blocks have code for defining a parameter attribute set.
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <set>
|
||||
|
||||
namespace llvm {
|
||||
class Collector;
|
||||
class GCStrategy;
|
||||
class Constant;
|
||||
class ConstantArray;
|
||||
class GCMetadataPrinter;
|
||||
@ -53,7 +53,7 @@ namespace llvm {
|
||||
MachineModuleInfo *MMI;
|
||||
|
||||
// GCMetadataPrinters - The garbage collection metadata printer table.
|
||||
typedef DenseMap<Collector*,GCMetadataPrinter*> gcp_map_type;
|
||||
typedef DenseMap<GCStrategy*,GCMetadataPrinter*> gcp_map_type;
|
||||
typedef gcp_map_type::iterator gcp_iterator;
|
||||
gcp_map_type GCMetadataPrinters;
|
||||
|
||||
@ -366,7 +366,7 @@ namespace llvm {
|
||||
void EmitXXStructorList(Constant *List);
|
||||
void EmitConstantPool(unsigned Alignment, const char *Section,
|
||||
std::vector<std::pair<MachineConstantPoolEntry,unsigned> > &CP);
|
||||
GCMetadataPrinter *GetOrCreateGCPrinter(Collector *C);
|
||||
GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy *C);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,167 +0,0 @@
|
||||
//===-- llvm/CodeGen/Collector.h - Garbage collection -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Collector records sufficient information about a machine function to enable
|
||||
// accurate garbage collectors. Specifically:
|
||||
//
|
||||
// - Safe points
|
||||
// Garbage collection is only possible at certain points in code. Code
|
||||
// generators should record points:
|
||||
//
|
||||
// - At and after any call to a subroutine
|
||||
// - Before returning from the current function
|
||||
// - Before backwards branches (loops)
|
||||
//
|
||||
// - Roots
|
||||
// When a reference to a GC-allocated object exists on the stack, it must be
|
||||
// stored in an alloca registered with llvm.gcoot.
|
||||
//
|
||||
// This generic information should used by ABI-specific passes to emit support
|
||||
// tables for the runtime garbage collector.
|
||||
//
|
||||
// MachineCodeAnalysis identifies the GC safe points in the machine code. (Roots
|
||||
// are identified in SelectionDAGISel.)
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_COLLECTOR_H
|
||||
#define LLVM_CODEGEN_COLLECTOR_H
|
||||
|
||||
#include "llvm/CodeGen/CollectorMetadata.h"
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// 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.
|
||||
bool CustomWriteBarriers; //< Default is to insert stores.
|
||||
bool CustomRoots; //< Default is to pass through to backend.
|
||||
bool InitRoots; //< If set, roots are nulled during lowering.
|
||||
bool UsesMetadata; //< If set, backend must emit metadata tables.
|
||||
|
||||
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; }
|
||||
|
||||
/// True if the collector requires the given kind of safe point. By default,
|
||||
/// none are recorded.
|
||||
bool needsSafePoint(GC::PointKind Kind) const {
|
||||
return (NeededSafePoints & 1 << Kind) != 0;
|
||||
}
|
||||
|
||||
/// By default, write barriers are replaced with simple store instructions.
|
||||
/// If true, then addPassesToCustomLowerIntrinsics must instead process
|
||||
/// them.
|
||||
bool customWriteBarrier() const { return CustomWriteBarriers; }
|
||||
|
||||
/// By default, read barriers are replaced with simple load instructions.
|
||||
/// If true, then addPassesToCustomLowerIntrinsics must instead process
|
||||
/// them.
|
||||
bool customReadBarrier() const { return CustomReadBarriers; }
|
||||
|
||||
/// By default, roots are left for the code generator. If Custom, then
|
||||
/// addPassesToCustomLowerIntrinsics must add passes to delete them.
|
||||
bool customRoots() const { return CustomRoots; }
|
||||
|
||||
/// If set, gcroot intrinsics should initialize their allocas to null. This
|
||||
/// is necessary for most collectors.
|
||||
bool initializeRoots() const { return InitRoots; }
|
||||
|
||||
/// If set, appropriate metadata tables must be emitted by the back-end
|
||||
/// (assembler, JIT, or otherwise).
|
||||
bool usesMetadata() const { return UsesMetadata; }
|
||||
|
||||
/// 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);
|
||||
};
|
||||
|
||||
// GCMetadataPrinter - Emits GC metadata as assembly code.
|
||||
class GCMetadataPrinter {
|
||||
public:
|
||||
typedef Collector::list_type list_type;
|
||||
typedef Collector::iterator iterator;
|
||||
|
||||
private:
|
||||
Collector *Coll;
|
||||
|
||||
friend class AsmPrinter;
|
||||
|
||||
protected:
|
||||
// May only be subclassed.
|
||||
GCMetadataPrinter();
|
||||
|
||||
// Do not implement.
|
||||
GCMetadataPrinter(const GCMetadataPrinter &);
|
||||
GCMetadataPrinter &operator=(const GCMetadataPrinter &);
|
||||
|
||||
public:
|
||||
Collector &getCollector() { return *Coll; }
|
||||
const Module &getModule() const { return Coll->getModule(); }
|
||||
|
||||
iterator begin() { return Coll->begin(); }
|
||||
iterator end() { return Coll->end(); }
|
||||
|
||||
/// beginAssembly/finishAssembly - Emit module metadata as assembly code.
|
||||
virtual void beginAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
virtual void finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
virtual ~GCMetadataPrinter();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===-- CollectorMetadata.h - Garbage collector metadata ------------------===//
|
||||
//===-- GCMetadata.h - Garbage collector metadata -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,33 +7,31 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the CollectorMetadata and CollectorModuleMetadata classes,
|
||||
// which are used as a communication channel from the target code generator
|
||||
// to the target garbage collectors. This interface allows code generators and
|
||||
// garbage collectors to be developed independently.
|
||||
// This file declares the GCFunctionInfo and GCModuleInfo classes, which are
|
||||
// used as a communication channel from the target code generator 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
|
||||
// accurate stack map. Roots are specified in the LLVM IR using the llvm.gcroot
|
||||
// intrinsic, which the code generator understands. The code generator records
|
||||
// the stack offset for each GC root. Safe points are generated by the code
|
||||
// generator according to the collector's declared needs (generally at function
|
||||
// calls).
|
||||
// The GCFunctionInfo class logs the data necessary to build a type accurate
|
||||
// stack map. The code generator outputs:
|
||||
//
|
||||
// - Safe points as specified by the GCStrategy's NeededSafePoints.
|
||||
// - Stack offsets for GC roots, as specified by calls to llvm.gcroot
|
||||
//
|
||||
// Safe points and roots are sufficient to build type-accurate stack maps. As a
|
||||
// refinement, liveness analysis calculates the set of live roots at each safe
|
||||
// point. Liveness analysis is not presently performed, so all roots are assumed
|
||||
// live.
|
||||
// As a refinement, liveness analysis calculates the set of live roots at each
|
||||
// safe point. Liveness analysis is not presently performed by the code
|
||||
// generator, so all roots are assumed live.
|
||||
//
|
||||
// CollectorModuleMetadata simply collects CollectorMetadata structures for each
|
||||
// Function as it is compiled. This is necessary for collectors which must emit
|
||||
// a stack map for the entire compilation unit. CollectorMetadata outlives the
|
||||
// MachineFunction from which it is derived, so must not refer to any code
|
||||
// generator data structures.
|
||||
// GCModuleInfo simply collects GCFunctionInfo instances for each Function as
|
||||
// they are compiled. This accretion is necessary for collectors which must emit
|
||||
// a stack map for the compilation unit as a whole. Therefore, GCFunctionInfo
|
||||
// outlives the MachineFunction from which it is derived and must not refer to
|
||||
// any code generator data structures.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_COLLECTORMETADATA_H
|
||||
#define LLVM_CODEGEN_COLLECTORMETADATA_H
|
||||
#ifndef LLVM_CODEGEN_GCMETADATA_H
|
||||
#define LLVM_CODEGEN_GCMETADATA_H
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
@ -42,7 +40,7 @@
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class Collector;
|
||||
class GCStrategy;
|
||||
class Constant;
|
||||
class TargetAsmInfo;
|
||||
|
||||
@ -78,9 +76,9 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
/// CollectorMetadata - Garbage collection metadata for a function.
|
||||
/// GCFunctionInfo - Garbage collection metadata for a single function.
|
||||
///
|
||||
class CollectorMetadata {
|
||||
class GCFunctionInfo {
|
||||
public:
|
||||
typedef std::vector<GCPoint>::iterator iterator;
|
||||
typedef std::vector<GCRoot>::iterator roots_iterator;
|
||||
@ -88,7 +86,7 @@ namespace llvm {
|
||||
|
||||
private:
|
||||
const Function &F;
|
||||
Collector &C;
|
||||
GCStrategy &S;
|
||||
uint64_t FrameSize;
|
||||
std::vector<GCRoot> Roots;
|
||||
std::vector<GCPoint> SafePoints;
|
||||
@ -104,20 +102,20 @@ namespace llvm {
|
||||
// are live per safe point (1.5% on 64-bit hosts).
|
||||
|
||||
public:
|
||||
CollectorMetadata(const Function &F, Collector &C);
|
||||
~CollectorMetadata();
|
||||
GCFunctionInfo(const Function &F, GCStrategy &S);
|
||||
~GCFunctionInfo();
|
||||
|
||||
/// getFunction - Return the function to which this metadata applies.
|
||||
///
|
||||
const Function &getFunction() const { return F; }
|
||||
|
||||
/// getCollector - Return the collector for the function.
|
||||
/// getStrategy - Return the GC strategy for the function.
|
||||
///
|
||||
Collector &getCollector() { return C; }
|
||||
GCStrategy &getStrategy() { return S; }
|
||||
|
||||
/// 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).
|
||||
/// stack object ID for the alloca (if the code generator is
|
||||
// using MachineFrameInfo).
|
||||
void addStackRoot(int Num, Constant *Metadata) {
|
||||
Roots.push_back(GCRoot(Num, Metadata));
|
||||
}
|
||||
@ -154,39 +152,39 @@ namespace llvm {
|
||||
};
|
||||
|
||||
|
||||
/// CollectorModuleMetadata - Garbage collection metadata for a whole module.
|
||||
/// GCModuleInfo - Garbage collection metadata for a whole module.
|
||||
///
|
||||
class CollectorModuleMetadata : public ImmutablePass {
|
||||
typedef StringMap<Collector*> collector_map_type;
|
||||
typedef std::vector<Collector*> list_type;
|
||||
typedef DenseMap<const Function*,CollectorMetadata*> function_map_type;
|
||||
class GCModuleInfo : public ImmutablePass {
|
||||
typedef StringMap<GCStrategy*> strategy_map_type;
|
||||
typedef std::vector<GCStrategy*> list_type;
|
||||
typedef DenseMap<const Function*,GCFunctionInfo*> finfo_map_type;
|
||||
|
||||
collector_map_type NameMap;
|
||||
list_type Collectors;
|
||||
function_map_type Map;
|
||||
strategy_map_type StrategyMap;
|
||||
list_type StrategyList;
|
||||
finfo_map_type FInfoMap;
|
||||
|
||||
Collector *getOrCreateCollector(const Module *M, const std::string &Name);
|
||||
GCStrategy *getOrCreateStrategy(const Module *M, const std::string &Name);
|
||||
|
||||
public:
|
||||
typedef list_type::const_iterator iterator;
|
||||
|
||||
static char ID;
|
||||
|
||||
CollectorModuleMetadata();
|
||||
~CollectorModuleMetadata();
|
||||
GCModuleInfo();
|
||||
~GCModuleInfo();
|
||||
|
||||
/// clear - Used to delete module metadata. The metadata deleter pass calls
|
||||
/// this.
|
||||
/// clear - Resets the pass. The metadata deleter pass calls this.
|
||||
///
|
||||
void clear();
|
||||
|
||||
/// begin/end - Iterators for collectors.
|
||||
/// begin/end - Iterators for used strategies.
|
||||
///
|
||||
iterator begin() const { return Collectors.begin(); }
|
||||
iterator end() const { return Collectors.end(); }
|
||||
iterator begin() const { return StrategyList.begin(); }
|
||||
iterator end() const { return StrategyList.end(); }
|
||||
|
||||
/// get - Look up function metadata.
|
||||
///
|
||||
CollectorMetadata &get(const Function &F);
|
||||
GCFunctionInfo &getFunctionInfo(const Function &F);
|
||||
};
|
||||
|
||||
}
|
||||
|
77
include/llvm/CodeGen/GCMetadataPrinter.h
Normal file
77
include/llvm/CodeGen/GCMetadataPrinter.h
Normal file
@ -0,0 +1,77 @@
|
||||
//===-- llvm/CodeGen/GCMetadataPrinter.h - Prints asm GC tables -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The abstract base class GCMetadataPrinter supports writing GC metadata tables
|
||||
// as assembly code. This is a separate class from GCStrategy in order to allow
|
||||
// users of the LLVM JIT to avoid linking with the AsmWriter.
|
||||
//
|
||||
// Subclasses of GCMetadataPrinter must be registered using the
|
||||
// GCMetadataPrinterRegistry. This is separate from the GCStrategy itself
|
||||
// because these subclasses are logically plugins for the AsmWriter.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GCMETADATAPRINTER_H
|
||||
#define LLVM_CODEGEN_GCMETADATAPRINTER_H
|
||||
|
||||
#include "llvm/CodeGen/GCMetadata.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/Support/Registry.h"
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GCMetadataPrinter;
|
||||
|
||||
/// GCMetadataPrinterRegistry - The GC assembly printer registry uses all the
|
||||
/// defaults from Registry.
|
||||
typedef Registry<GCMetadataPrinter> GCMetadataPrinterRegistry;
|
||||
|
||||
/// GCMetadataPrinter - Emits GC metadata as assembly code.
|
||||
///
|
||||
class GCMetadataPrinter {
|
||||
public:
|
||||
typedef GCStrategy::list_type list_type;
|
||||
typedef GCStrategy::iterator iterator;
|
||||
|
||||
private:
|
||||
GCStrategy *S;
|
||||
|
||||
friend class AsmPrinter;
|
||||
|
||||
protected:
|
||||
// May only be subclassed.
|
||||
GCMetadataPrinter();
|
||||
|
||||
// Do not implement.
|
||||
GCMetadataPrinter(const GCMetadataPrinter &);
|
||||
GCMetadataPrinter &operator=(const GCMetadataPrinter &);
|
||||
|
||||
public:
|
||||
GCStrategy &getStrategy() { return *S; }
|
||||
const Module &getModule() const { return S->getModule(); }
|
||||
|
||||
/// begin/end - Iterate over the collected function metadata.
|
||||
iterator begin() { return S->begin(); }
|
||||
iterator end() { return S->end(); }
|
||||
|
||||
/// beginAssembly/finishAssembly - Emit module metadata as assembly code.
|
||||
virtual void beginAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
virtual void finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
virtual ~GCMetadataPrinter();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/Collector.h - Garbage collection -----------*- C++ -*-===//
|
||||
//===-- llvm/CodeGen/GCStrategy.h - Garbage collection ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,12 +7,18 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Collector records sufficient information about a machine function to enable
|
||||
// accurate garbage collectors. Specifically:
|
||||
// GCStrategy coordinates code generation algorithms and implements some itself
|
||||
// in order to generate code compatible with a target code generator as
|
||||
// specified in a function's 'gc' attribute. Algorithms are enabled by setting
|
||||
// flags in a subclass's constructor, and some virtual methods can be
|
||||
// overridden.
|
||||
//
|
||||
// When requested, the GCStrategy will be populated with data about each
|
||||
// function which uses it. Specifically:
|
||||
//
|
||||
// - Safe points
|
||||
// Garbage collection is only possible at certain points in code. Code
|
||||
// generators should record points:
|
||||
// Garbage collection is generally only possible at certain points in code.
|
||||
// GCStrategy can request that the collector insert such points:
|
||||
//
|
||||
// - At and after any call to a subroutine
|
||||
// - Before returning from the current function
|
||||
@ -22,33 +28,37 @@
|
||||
// When a reference to a GC-allocated object exists on the stack, it must be
|
||||
// stored in an alloca registered with llvm.gcoot.
|
||||
//
|
||||
// This generic information should used by ABI-specific passes to emit support
|
||||
// tables for the runtime garbage collector.
|
||||
//
|
||||
// MachineCodeAnalysis identifies the GC safe points in the machine code. (Roots
|
||||
// are identified in SelectionDAGISel.)
|
||||
// This information can used to emit the metadata tables which are required by
|
||||
// the target garbage collector runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_COLLECTOR_H
|
||||
#define LLVM_CODEGEN_COLLECTOR_H
|
||||
#ifndef LLVM_CODEGEN_GCSTRATEGY_H
|
||||
#define LLVM_CODEGEN_GCSTRATEGY_H
|
||||
|
||||
#include "llvm/CodeGen/GCMetadata.h"
|
||||
#include "llvm/Support/Registry.h"
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Collector describes a garbage collector's code generation requirements,
|
||||
/// and provides overridable hooks for those needs which cannot be abstractly
|
||||
/// described.
|
||||
class Collector {
|
||||
class GCStrategy;
|
||||
|
||||
/// The GC strategy registry uses all the defaults from Registry.
|
||||
///
|
||||
typedef Registry<GCStrategy> GCRegistry;
|
||||
|
||||
/// GCStrategy describes a garbage collector algorithm's code generation
|
||||
/// requirements, and provides overridable hooks for those needs which cannot
|
||||
/// be abstractly described.
|
||||
class GCStrategy {
|
||||
public:
|
||||
typedef std::vector<CollectorMetadata*> list_type;
|
||||
typedef std::vector<GCFunctionInfo*> list_type;
|
||||
typedef list_type::iterator iterator;
|
||||
|
||||
private:
|
||||
friend class CollectorModuleMetadata;
|
||||
friend class GCModuleInfo;
|
||||
const Module *M;
|
||||
std::string Name;
|
||||
|
||||
@ -63,49 +73,51 @@ namespace llvm {
|
||||
bool UsesMetadata; //< If set, backend must emit metadata tables.
|
||||
|
||||
public:
|
||||
Collector();
|
||||
GCStrategy();
|
||||
|
||||
virtual ~Collector();
|
||||
virtual ~GCStrategy();
|
||||
|
||||
|
||||
/// getName - The name of the collector, for debugging.
|
||||
/// getName - The name of the GC strategy, for debugging.
|
||||
///
|
||||
const std::string &getName() const { return Name; }
|
||||
|
||||
/// getModule - The module upon which the collector is operating.
|
||||
/// getModule - The module within which the GC strategy is operating.
|
||||
///
|
||||
const Module &getModule() const { return *M; }
|
||||
|
||||
/// True if this collector requires safe points of any kind. By default,
|
||||
/// none are recorded.
|
||||
/// needsSafePoitns - True if safe points of any kind are required. By
|
||||
// default, none are recorded.
|
||||
bool needsSafePoints() const { return NeededSafePoints != 0; }
|
||||
|
||||
/// True if the collector requires the given kind of safe point. By default,
|
||||
/// none are recorded.
|
||||
/// needsSafePoint(Kind) - True if the given kind of safe point is
|
||||
// required. By default, none are recorded.
|
||||
bool needsSafePoint(GC::PointKind Kind) const {
|
||||
return (NeededSafePoints & 1 << Kind) != 0;
|
||||
}
|
||||
|
||||
/// By default, write barriers are replaced with simple store instructions.
|
||||
/// If true, then addPassesToCustomLowerIntrinsics must instead process
|
||||
/// them.
|
||||
/// customWriteBarrier - By default, write barriers are replaced with simple
|
||||
/// store instructions. If true, then
|
||||
/// performCustomLowering must instead lower them.
|
||||
bool customWriteBarrier() const { return CustomWriteBarriers; }
|
||||
|
||||
/// By default, read barriers are replaced with simple load instructions.
|
||||
/// If true, then addPassesToCustomLowerIntrinsics must instead process
|
||||
/// them.
|
||||
/// customReadBarrier - By default, read barriers are replaced with simple
|
||||
/// load instructions. If true, then
|
||||
/// performCustomLowering must instead lower them.
|
||||
bool customReadBarrier() const { return CustomReadBarriers; }
|
||||
|
||||
/// By default, roots are left for the code generator. If Custom, then
|
||||
/// addPassesToCustomLowerIntrinsics must add passes to delete them.
|
||||
/// customRoots - By default, roots are left for the code generator so it
|
||||
/// can generate a stack map. If true, then
|
||||
// performCustomLowering must delete them.
|
||||
bool customRoots() const { return CustomRoots; }
|
||||
|
||||
/// If set, gcroot intrinsics should initialize their allocas to null. This
|
||||
/// is necessary for most collectors.
|
||||
/// initializeRoots - If set, gcroot intrinsics should initialize their
|
||||
// allocas to null before the first use. This is
|
||||
// necessary for most GCs and is enabled by default.
|
||||
bool initializeRoots() const { return InitRoots; }
|
||||
|
||||
/// If set, appropriate metadata tables must be emitted by the back-end
|
||||
/// (assembler, JIT, or otherwise).
|
||||
/// usesMetadata - If set, appropriate metadata tables must be emitted by
|
||||
/// the back-end (assembler, JIT, or otherwise).
|
||||
bool usesMetadata() const { return UsesMetadata; }
|
||||
|
||||
/// begin/end - Iterators for function metadata.
|
||||
@ -115,53 +127,17 @@ namespace llvm {
|
||||
|
||||
/// insertFunctionMetadata - Creates metadata for a function.
|
||||
///
|
||||
CollectorMetadata *insertFunctionMetadata(const Function &F);
|
||||
GCFunctionInfo *insertFunctionInfo(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
|
||||
/// are set to custom, performCustomLowering must be overriden to transform
|
||||
/// the corresponding actions to LLVM IR. initializeCustomLowering is
|
||||
/// optional to override. These are the only GCStrategy methods through
|
||||
/// which the LLVM IR can be modified.
|
||||
virtual bool initializeCustomLowering(Module &F);
|
||||
virtual bool performCustomLowering(Function &F);
|
||||
};
|
||||
|
||||
// GCMetadataPrinter - Emits GC metadata as assembly code.
|
||||
class GCMetadataPrinter {
|
||||
public:
|
||||
typedef Collector::list_type list_type;
|
||||
typedef Collector::iterator iterator;
|
||||
|
||||
private:
|
||||
Collector *Coll;
|
||||
|
||||
friend class AsmPrinter;
|
||||
|
||||
protected:
|
||||
// May only be subclassed.
|
||||
GCMetadataPrinter();
|
||||
|
||||
// Do not implement.
|
||||
GCMetadataPrinter(const GCMetadataPrinter &);
|
||||
GCMetadataPrinter &operator=(const GCMetadataPrinter &);
|
||||
|
||||
public:
|
||||
Collector &getCollector() { return *Coll; }
|
||||
const Module &getModule() const { return Coll->getModule(); }
|
||||
|
||||
iterator begin() { return Coll->begin(); }
|
||||
iterator end() { return Coll->end(); }
|
||||
|
||||
/// beginAssembly/finishAssembly - Emit module metadata as assembly code.
|
||||
virtual void beginAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
virtual void finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI);
|
||||
|
||||
virtual ~GCMetadataPrinter();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- Collectors.h - Garbage collector registry -------------------------===//
|
||||
//===-- GCs.h - Garbage collector linkage hacks ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,41 +7,29 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the CollectorRegistry class, which is used to discover
|
||||
// pluggable garbage collectors.
|
||||
// This file contains hack functions to force linking in the GC components.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GCS_H
|
||||
#define LLVM_CODEGEN_GCS_H
|
||||
|
||||
#include "llvm/Support/Registry.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Collector;
|
||||
class GCStrategy;
|
||||
class GCMetadataPrinter;
|
||||
|
||||
/// The collector registry uses all the defaults from Registry.
|
||||
///
|
||||
typedef Registry<Collector> CollectorRegistry;
|
||||
|
||||
/// The GC assembly printer registry uses all the defaults from Registry.
|
||||
///
|
||||
typedef Registry<GCMetadataPrinter> GCMetadataPrinterRegistry;
|
||||
|
||||
/// 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();
|
||||
void linkOcamlGC();
|
||||
|
||||
/// Creates an ocaml-compatible metadata printer.
|
||||
GCMetadataPrinter *createOcamlMetadataPrinter();
|
||||
void linkOcamlGCPrinter();
|
||||
|
||||
/// Creates a shadow stack garbage collector. This collector requires no code
|
||||
/// generator support.
|
||||
Collector *createShadowStackCollector();
|
||||
void linkShadowStackGC();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -20,14 +20,14 @@
|
||||
namespace {
|
||||
struct ForceAsmWriterLinking {
|
||||
ForceAsmWriterLinking() {
|
||||
// We must reference the passes in such a way that compilers will not
|
||||
// We must reference the plug-ins in such a way that compilers will not
|
||||
// delete it all as dead code, even with whole program optimization,
|
||||
// yet is effectively a NO-OP. As the compiler isn't smart enough
|
||||
// to know that getenv() never returns -1, this will do the job.
|
||||
if (std::getenv("bar") != (char*) -1)
|
||||
return;
|
||||
|
||||
(void) llvm::createOcamlMetadataPrinter();
|
||||
llvm::linkOcamlGCPrinter();
|
||||
|
||||
}
|
||||
} ForceAsmWriterLinking; // Force link by creating a global definition.
|
||||
|
@ -36,8 +36,8 @@ namespace {
|
||||
|
||||
(void) llvm::createSimpleRegisterCoalescer();
|
||||
|
||||
(void) llvm::createOcamlCollector();
|
||||
(void) llvm::createShadowStackCollector();
|
||||
llvm::linkOcamlGC();
|
||||
llvm::linkShadowStackGC();
|
||||
|
||||
(void) llvm::createBURRListDAGScheduler(NULL, NULL, NULL, false);
|
||||
(void) llvm::createTDRRListDAGScheduler(NULL, NULL, NULL, false);
|
||||
|
@ -152,7 +152,7 @@ namespace llvm {
|
||||
FunctionPass *getRegisterAllocator(TargetMachine &T);
|
||||
|
||||
/// IntrinsicLowering Pass - Performs target-independent LLVM IR
|
||||
/// transformations for highly portable collectors.
|
||||
/// transformations for highly portable strategies.
|
||||
FunctionPass *createGCLoweringPass();
|
||||
|
||||
/// MachineCodeAnalysis Pass - Target-independent pass to mark safe points in
|
||||
@ -161,13 +161,13 @@ namespace llvm {
|
||||
/// folding).
|
||||
FunctionPass *createGCMachineCodeAnalysisPass();
|
||||
|
||||
/// Deleter Pass - Releases collector metadata.
|
||||
/// Deleter Pass - Releases GC metadata.
|
||||
///
|
||||
FunctionPass *createCollectorMetadataDeleter();
|
||||
FunctionPass *createGCInfoDeleter();
|
||||
|
||||
/// Creates a pass to print collector metadata.
|
||||
/// Creates a pass to print GC metadata.
|
||||
///
|
||||
FunctionPass *createCollectorMetadataPrinter(std::ostream &OS);
|
||||
FunctionPass *createGCInfoPrinter(std::ostream &OS);
|
||||
|
||||
/// createMachineLICMPass - This pass performs LICM on machine instructions.
|
||||
///
|
||||
|
@ -29,7 +29,7 @@ namespace llvm {
|
||||
class TargetLowering;
|
||||
class FunctionLoweringInfo;
|
||||
class HazardRecognizer;
|
||||
class CollectorMetadata;
|
||||
class GCFunctionInfo;
|
||||
class ScheduleDAG;
|
||||
|
||||
/// SelectionDAGISel - This is the common base class used for SelectionDAG-based
|
||||
@ -41,13 +41,13 @@ public:
|
||||
SelectionDAG *CurDAG;
|
||||
MachineBasicBlock *BB;
|
||||
AliasAnalysis *AA;
|
||||
CollectorMetadata *GCI;
|
||||
GCFunctionInfo *GFI;
|
||||
bool Fast;
|
||||
std::vector<SDNode*> TopOrder;
|
||||
static char ID;
|
||||
|
||||
explicit SelectionDAGISel(TargetLowering &tli, bool fast = false) :
|
||||
FunctionPass((intptr_t)&ID), TLI(tli), GCI(0), Fast(fast), DAGSize(0) {}
|
||||
FunctionPass((intptr_t)&ID), TLI(tli), GFI(), Fast(fast), DAGSize(0) {}
|
||||
|
||||
TargetLowering &getTargetLowering() { return TLI; }
|
||||
|
||||
|
@ -148,12 +148,12 @@ public:
|
||||
///
|
||||
void setParamAttrs(const PAListPtr &attrs) { ParamAttrs = attrs; }
|
||||
|
||||
/// hasCollector/getCollector/setCollector/clearCollector - The name of the
|
||||
/// garbage collection algorithm to use during code generation.
|
||||
bool hasCollector() const;
|
||||
const char *getCollector() const;
|
||||
void setCollector(const char *Str);
|
||||
void clearCollector();
|
||||
/// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm
|
||||
/// to use during code generation.
|
||||
bool hasGC() const;
|
||||
const char *getGC() const;
|
||||
void setGC(const char *Str);
|
||||
void clearGC();
|
||||
|
||||
/// @brief Determine whether the function has the given attribute.
|
||||
bool paramHasAttr(unsigned i, ParameterAttributes attr) const {
|
||||
|
@ -2393,7 +2393,7 @@ FunctionHeaderH : OptCallingConv ResultTypes GlobalName '(' ArgList ')'
|
||||
delete $8;
|
||||
}
|
||||
if ($10) {
|
||||
Fn->setCollector($10->c_str());
|
||||
Fn->setGC($10->c_str());
|
||||
delete $10;
|
||||
}
|
||||
|
||||
|
@ -892,7 +892,7 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
|
||||
|
||||
SmallVector<uint64_t, 64> Record;
|
||||
std::vector<std::string> SectionTable;
|
||||
std::vector<std::string> CollectorTable;
|
||||
std::vector<std::string> GCTable;
|
||||
|
||||
// Read all the records for this module.
|
||||
while (!Stream.AtEndOfStream()) {
|
||||
@ -1019,11 +1019,11 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
|
||||
SectionTable.push_back(S);
|
||||
break;
|
||||
}
|
||||
case bitc::MODULE_CODE_COLLECTORNAME: { // SECTIONNAME: [strchr x N]
|
||||
case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N]
|
||||
std::string S;
|
||||
if (ConvertToString(Record, 0, S))
|
||||
return Error("Invalid MODULE_CODE_COLLECTORNAME record");
|
||||
CollectorTable.push_back(S);
|
||||
return Error("Invalid MODULE_CODE_GCNAME record");
|
||||
GCTable.push_back(S);
|
||||
break;
|
||||
}
|
||||
// GLOBALVAR: [pointer type, isconst, initid,
|
||||
@ -1070,7 +1070,7 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
|
||||
break;
|
||||
}
|
||||
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
|
||||
// alignment, section, visibility, collector]
|
||||
// alignment, section, visibility, gc]
|
||||
case bitc::MODULE_CODE_FUNCTION: {
|
||||
if (Record.size() < 8)
|
||||
return Error("Invalid MODULE_CODE_FUNCTION record");
|
||||
@ -1098,9 +1098,9 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
|
||||
}
|
||||
Func->setVisibility(GetDecodedVisibility(Record[7]));
|
||||
if (Record.size() > 8 && Record[8]) {
|
||||
if (Record[8]-1 > CollectorTable.size())
|
||||
return Error("Invalid collector ID");
|
||||
Func->setCollector(CollectorTable[Record[8]-1].c_str());
|
||||
if (Record[8]-1 > GCTable.size())
|
||||
return Error("Invalid GC ID");
|
||||
Func->setGC(GCTable[Record[8]-1].c_str());
|
||||
}
|
||||
|
||||
ValueList.push_back(Func);
|
||||
|
@ -303,10 +303,10 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
WriteStringRecord(bitc::MODULE_CODE_ASM, M->getModuleInlineAsm(),
|
||||
0/*TODO*/, Stream);
|
||||
|
||||
// Emit information about sections and collectors, computing how many there
|
||||
// are. Also compute the maximum alignment value.
|
||||
// Emit information about sections and GC, computing how many there are. Also
|
||||
// compute the maximum alignment value.
|
||||
std::map<std::string, unsigned> SectionMap;
|
||||
std::map<std::string, unsigned> CollectorMap;
|
||||
std::map<std::string, unsigned> GCMap;
|
||||
unsigned MaxAlignment = 0;
|
||||
unsigned MaxGlobalType = 0;
|
||||
for (Module::const_global_iterator GV = M->global_begin(),E = M->global_end();
|
||||
@ -333,13 +333,13 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
Entry = SectionMap.size();
|
||||
}
|
||||
}
|
||||
if (F->hasCollector()) {
|
||||
// Same for collector names.
|
||||
unsigned &Entry = CollectorMap[F->getCollector()];
|
||||
if (F->hasGC()) {
|
||||
// Same for GC names.
|
||||
unsigned &Entry = GCMap[F->getGC()];
|
||||
if (!Entry) {
|
||||
WriteStringRecord(bitc::MODULE_CODE_COLLECTORNAME, F->getCollector(),
|
||||
WriteStringRecord(bitc::MODULE_CODE_GCNAME, F->getGC(),
|
||||
0/*TODO*/, Stream);
|
||||
Entry = CollectorMap.size();
|
||||
Entry = GCMap.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -401,7 +401,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
// Emit the function proto information.
|
||||
for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
|
||||
// FUNCTION: [type, callingconv, isproto, paramattr,
|
||||
// linkage, alignment, section, visibility, collector]
|
||||
// linkage, alignment, section, visibility, gc]
|
||||
Vals.push_back(VE.getTypeID(F->getType()));
|
||||
Vals.push_back(F->getCallingConv());
|
||||
Vals.push_back(F->isDeclaration());
|
||||
@ -410,7 +410,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
|
||||
Vals.push_back(Log2_32(F->getAlignment())+1);
|
||||
Vals.push_back(F->hasSection() ? SectionMap[F->getSection()] : 0);
|
||||
Vals.push_back(getEncodedVisibility(F));
|
||||
Vals.push_back(F->hasCollector() ? CollectorMap[F->getCollector()] : 0);
|
||||
Vals.push_back(F->hasGC() ? GCMap[F->getGC()] : 0);
|
||||
|
||||
unsigned AbbrevToUse = 0;
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
|
||||
|
@ -16,9 +16,7 @@
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/CodeGen/GCMetadata.h"
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
@ -110,18 +108,17 @@ void AsmPrinter::SwitchToDataSection(const char *NewSection,
|
||||
|
||||
void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
AU.addRequired<GCModuleInfo>();
|
||||
}
|
||||
|
||||
bool AsmPrinter::doInitialization(Module &M) {
|
||||
Mang = new Mangler(M, TAI->getGlobalPrefix());
|
||||
|
||||
CollectorModuleMetadata *CMM = getAnalysisToUpdate<CollectorModuleMetadata>();
|
||||
assert(CMM && "AsmPrinter didn't require CollectorModuleMetadata?");
|
||||
for (CollectorModuleMetadata::iterator I = CMM->begin(),
|
||||
E = CMM->end(); I != E; ++I)
|
||||
if (GCMetadataPrinter *GCP = GetOrCreateGCPrinter(*I))
|
||||
GCP->beginAssembly(O, *this, *TAI);
|
||||
GCModuleInfo *MI = getAnalysisToUpdate<GCModuleInfo>();
|
||||
assert(MI && "AsmPrinter didn't require GCModuleInfo?");
|
||||
for (GCModuleInfo::iterator I = MI->begin(), E = MI->end(); I != E; ++I)
|
||||
if (GCMetadataPrinter *MP = GetOrCreateGCPrinter(*I))
|
||||
MP->beginAssembly(O, *this, *TAI);
|
||||
|
||||
if (!M.getModuleInlineAsm().empty())
|
||||
O << TAI->getCommentString() << " Start of file scope inline assembly\n"
|
||||
@ -192,12 +189,11 @@ bool AsmPrinter::doFinalization(Module &M) {
|
||||
}
|
||||
}
|
||||
|
||||
CollectorModuleMetadata *CMM = getAnalysisToUpdate<CollectorModuleMetadata>();
|
||||
assert(CMM && "AsmPrinter didn't require CollectorModuleMetadata?");
|
||||
for (CollectorModuleMetadata::iterator I = CMM->end(),
|
||||
E = CMM->begin(); I != E; )
|
||||
if (GCMetadataPrinter *GCP = GetOrCreateGCPrinter(*--I))
|
||||
GCP->finishAssembly(O, *this, *TAI);
|
||||
GCModuleInfo *MI = getAnalysisToUpdate<GCModuleInfo>();
|
||||
assert(MI && "AsmPrinter didn't require GCModuleInfo?");
|
||||
for (GCModuleInfo::iterator I = MI->end(), E = MI->begin(); I != E; )
|
||||
if (GCMetadataPrinter *MP = GetOrCreateGCPrinter(*--I))
|
||||
MP->finishAssembly(O, *this, *TAI);
|
||||
|
||||
// If we don't have any trampolines, then we don't require stack memory
|
||||
// to be executable. Some targets have a directive to declare this.
|
||||
@ -1466,26 +1462,26 @@ void AsmPrinter::printVisibility(const std::string& Name,
|
||||
}
|
||||
}
|
||||
|
||||
GCMetadataPrinter *AsmPrinter::GetOrCreateGCPrinter(Collector *C) {
|
||||
if (!C->usesMetadata())
|
||||
GCMetadataPrinter *AsmPrinter::GetOrCreateGCPrinter(GCStrategy *S) {
|
||||
if (!S->usesMetadata())
|
||||
return 0;
|
||||
|
||||
gcp_iterator GCPI = GCMetadataPrinters.find(C);
|
||||
gcp_iterator GCPI = GCMetadataPrinters.find(S);
|
||||
if (GCPI != GCMetadataPrinters.end())
|
||||
return GCPI->second;
|
||||
|
||||
const char *Name = C->getName().c_str();
|
||||
const char *Name = S->getName().c_str();
|
||||
|
||||
for (GCMetadataPrinterRegistry::iterator
|
||||
I = GCMetadataPrinterRegistry::begin(),
|
||||
E = GCMetadataPrinterRegistry::end(); I != E; ++I)
|
||||
if (strcmp(Name, I->getName()) == 0) {
|
||||
GCMetadataPrinter *GCP = I->instantiate();
|
||||
GCP->Coll = C;
|
||||
GCMetadataPrinters.insert(std::make_pair(C, GCP));
|
||||
return GCP;
|
||||
GCMetadataPrinter *GMP = I->instantiate();
|
||||
GMP->S = S;
|
||||
GCMetadataPrinters.insert(std::make_pair(S, GMP));
|
||||
return GMP;
|
||||
}
|
||||
|
||||
cerr << "no GCMetadataPrinter registered for collector: " << Name << "\n";
|
||||
cerr << "no GCMetadataPrinter registered for GC: " << Name << "\n";
|
||||
abort();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- OcamlCollector.cpp - Ocaml frametable emitter ---------------------===//
|
||||
//===-- OcamlGCPrinter.cpp - Ocaml frametable emitter ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,13 +7,13 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements lowering for the llvm.gc* intrinsics compatible with
|
||||
// Objective Caml 3.10.0, which uses a liveness-accurate static stack map.
|
||||
// This file implements printing the assembly code for an Ocaml frametable.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
@ -38,9 +38,7 @@ namespace {
|
||||
static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
|
||||
Y("ocaml", "ocaml 3.10-compatible collector");
|
||||
|
||||
GCMetadataPrinter *llvm::createOcamlMetadataPrinter() {
|
||||
return new OcamlGCMetadataPrinter();
|
||||
}
|
||||
void llvm::linkOcamlGCPrinter() { }
|
||||
|
||||
static void EmitCamlGlobal(const Module &M, std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI, const char *Id) {
|
||||
@ -85,7 +83,7 @@ void OcamlGCMetadataPrinter::beginAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
///
|
||||
/// Note that this precludes programs from stack frames larger than 64K
|
||||
/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
|
||||
/// either condition is detected in a function which uses the collector.
|
||||
/// either condition is detected in a function which uses the GC.
|
||||
///
|
||||
void OcamlGCMetadataPrinter::finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
const TargetAsmInfo &TAI) {
|
||||
@ -111,33 +109,32 @@ void OcamlGCMetadataPrinter::finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
AP.SwitchToDataSection(TAI.getDataSection());
|
||||
EmitCamlGlobal(getModule(), OS, AP, TAI, "frametable");
|
||||
|
||||
for (iterator FI = begin(), FE = end(); FI != FE; ++FI) {
|
||||
CollectorMetadata &MD = **FI;
|
||||
for (iterator I = begin(), IE = end(); I != IE; ++I) {
|
||||
GCFunctionInfo &FI = **I;
|
||||
|
||||
uint64_t FrameSize = FI.getFrameSize();
|
||||
if (FrameSize >= 1<<16) {
|
||||
cerr << "Function '" << FI.getFunction().getNameStart()
|
||||
<< "' is too large for the ocaml GC! "
|
||||
<< "Frame size " << FrameSize << " >= 65536.\n";
|
||||
cerr << "(" << uintptr_t(&FI) << ")\n";
|
||||
abort(); // Very rude!
|
||||
}
|
||||
|
||||
OS << "\t" << TAI.getCommentString() << " live roots for "
|
||||
<< MD.getFunction().getNameStart() << "\n";
|
||||
<< FI.getFunction().getNameStart() << "\n";
|
||||
|
||||
for (CollectorMetadata::iterator PI = MD.begin(),
|
||||
PE = MD.end(); PI != PE; ++PI) {
|
||||
|
||||
uint64_t FrameSize = MD.getFrameSize();
|
||||
if (FrameSize >= 1<<16) {
|
||||
cerr << "Function '" << MD.getFunction().getNameStart()
|
||||
<< "' is too large for the ocaml collector! "
|
||||
<< "Frame size " << FrameSize << " >= 65536.\n";
|
||||
abort(); // Very rude!
|
||||
}
|
||||
|
||||
size_t LiveCount = MD.live_size(PI);
|
||||
for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
|
||||
size_t LiveCount = FI.live_size(J);
|
||||
if (LiveCount >= 1<<16) {
|
||||
cerr << "Function '" << MD.getFunction().getNameStart()
|
||||
<< "' is too large for the ocaml collector! "
|
||||
cerr << "Function '" << FI.getFunction().getNameStart()
|
||||
<< "' is too large for the ocaml GC! "
|
||||
<< "Live root count " << LiveCount << " >= 65536.\n";
|
||||
abort(); // Very rude!
|
||||
}
|
||||
|
||||
OS << AddressDirective
|
||||
<< TAI.getPrivateGlobalPrefix() << "label" << PI->Num;
|
||||
<< TAI.getPrivateGlobalPrefix() << "label" << J->Num;
|
||||
AP.EOL("call return address");
|
||||
|
||||
AP.EmitInt16(FrameSize);
|
||||
@ -146,14 +143,13 @@ void OcamlGCMetadataPrinter::finishAssembly(std::ostream &OS, AsmPrinter &AP,
|
||||
AP.EmitInt16(LiveCount);
|
||||
AP.EOL("live root count");
|
||||
|
||||
for (CollectorMetadata::live_iterator LI = MD.live_begin(PI),
|
||||
LE = MD.live_end(PI);
|
||||
LI != LE; ++LI) {
|
||||
assert(LI->StackOffset < 1<<16 &&
|
||||
for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
|
||||
KE = FI.live_end(J); K != KE; ++K) {
|
||||
assert(K->StackOffset < 1<<16 &&
|
||||
"GC root stack offset is outside of fixed stack frame and out "
|
||||
"of range for Ocaml collector!");
|
||||
"of range for ocaml GC!");
|
||||
|
||||
OS << "\t.word\t" << LI->StackOffset;
|
||||
OS << "\t.word\t" << K->StackOffset;
|
||||
AP.EOL("stack offset");
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- CollectorMetadata.cpp - Garbage collector metadata ----------------===//
|
||||
//===-- GCMetadata.cpp - Garbage collector metadata -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,14 +7,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the CollectorMetadata and CollectorModuleMetadata
|
||||
// classes.
|
||||
// This file implements the GCFunctionInfo class and GCModuleInfo pass.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCMetadata.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
@ -53,79 +51,80 @@ namespace {
|
||||
|
||||
}
|
||||
|
||||
static RegisterPass<CollectorModuleMetadata>
|
||||
static RegisterPass<GCModuleInfo>
|
||||
X("collector-metadata", "Create Garbage Collector Module Metadata");
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
CollectorMetadata::CollectorMetadata(const Function &F, Collector &C)
|
||||
: F(F), C(C), FrameSize(~0LL) {}
|
||||
GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S)
|
||||
: F(F), S(S), FrameSize(~0LL) {}
|
||||
|
||||
CollectorMetadata::~CollectorMetadata() {}
|
||||
GCFunctionInfo::~GCFunctionInfo() {}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
char CollectorModuleMetadata::ID = 0;
|
||||
char GCModuleInfo::ID = 0;
|
||||
|
||||
CollectorModuleMetadata::CollectorModuleMetadata()
|
||||
GCModuleInfo::GCModuleInfo()
|
||||
: ImmutablePass((intptr_t)&ID) {}
|
||||
|
||||
CollectorModuleMetadata::~CollectorModuleMetadata() {
|
||||
GCModuleInfo::~GCModuleInfo() {
|
||||
clear();
|
||||
}
|
||||
|
||||
Collector *CollectorModuleMetadata::
|
||||
getOrCreateCollector(const Module *M, const std::string &Name) {
|
||||
GCStrategy *GCModuleInfo::getOrCreateStrategy(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())
|
||||
strategy_map_type::iterator NMI =
|
||||
StrategyMap.find(Start, Start + Name.size());
|
||||
if (NMI != StrategyMap.end())
|
||||
return NMI->getValue();
|
||||
|
||||
for (CollectorRegistry::iterator I = CollectorRegistry::begin(),
|
||||
E = CollectorRegistry::end(); I != E; ++I) {
|
||||
for (GCRegistry::iterator I = GCRegistry::begin(),
|
||||
E = GCRegistry::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;
|
||||
GCStrategy *S = I->instantiate();
|
||||
S->M = M;
|
||||
S->Name = Name;
|
||||
StrategyMap.GetOrCreateValue(Start, Start + Name.size()).setValue(S);
|
||||
StrategyList.push_back(S);
|
||||
return S;
|
||||
}
|
||||
}
|
||||
|
||||
cerr << "unsupported collector: " << Name << "\n";
|
||||
cerr << "unsupported GC: " << Name << "\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
CollectorMetadata &CollectorModuleMetadata::get(const Function &F) {
|
||||
GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) {
|
||||
assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!");
|
||||
assert(F.hasCollector());
|
||||
assert(F.hasGC());
|
||||
|
||||
function_map_type::iterator I = Map.find(&F);
|
||||
if (I != Map.end())
|
||||
finfo_map_type::iterator I = FInfoMap.find(&F);
|
||||
if (I != FInfoMap.end())
|
||||
return *I->second;
|
||||
|
||||
Collector *C = getOrCreateCollector(F.getParent(), F.getCollector());
|
||||
CollectorMetadata *MD = C->insertFunctionMetadata(F);
|
||||
Map[&F] = MD;
|
||||
return *MD;
|
||||
|
||||
GCStrategy *S = getOrCreateStrategy(F.getParent(), F.getGC());
|
||||
GCFunctionInfo *GFI = S->insertFunctionInfo(F);
|
||||
FInfoMap[&F] = GFI;
|
||||
return *GFI;
|
||||
}
|
||||
|
||||
void CollectorModuleMetadata::clear() {
|
||||
Map.clear();
|
||||
NameMap.clear();
|
||||
void GCModuleInfo::clear() {
|
||||
FInfoMap.clear();
|
||||
StrategyMap.clear();
|
||||
|
||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
delete *I;
|
||||
Collectors.clear();
|
||||
StrategyList.clear();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
char Printer::ID = 0;
|
||||
|
||||
FunctionPass *llvm::createCollectorMetadataPrinter(std::ostream &OS) {
|
||||
FunctionPass *llvm::createGCInfoPrinter(std::ostream &OS) {
|
||||
return new Printer(OS);
|
||||
}
|
||||
|
||||
@ -139,7 +138,7 @@ const char *Printer::getPassName() const {
|
||||
void Printer::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
FunctionPass::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
AU.addRequired<GCModuleInfo>();
|
||||
}
|
||||
|
||||
static const char *DescKind(GC::PointKind Kind) {
|
||||
@ -153,23 +152,22 @@ static const char *DescKind(GC::PointKind Kind) {
|
||||
}
|
||||
|
||||
bool Printer::runOnFunction(Function &F) {
|
||||
if (F.hasCollector()) {
|
||||
CollectorMetadata *FD = &getAnalysis<CollectorModuleMetadata>().get(F);
|
||||
if (!F.hasGC()) {
|
||||
GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F);
|
||||
|
||||
OS << "GC roots for " << FD->getFunction().getNameStart() << ":\n";
|
||||
for (CollectorMetadata::roots_iterator RI = FD->roots_begin(),
|
||||
RE = FD->roots_end();
|
||||
RI != RE; ++RI)
|
||||
for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(),
|
||||
RE = FD->roots_end(); RI != RE; ++RI)
|
||||
OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n";
|
||||
|
||||
OS << "GC safe points for " << FD->getFunction().getNameStart() << ":\n";
|
||||
for (CollectorMetadata::iterator PI = FD->begin(),
|
||||
PE = FD->end(); PI != PE; ++PI) {
|
||||
for (GCFunctionInfo::iterator PI = FD->begin(),
|
||||
PE = FD->end(); PI != PE; ++PI) {
|
||||
|
||||
OS << "\tlabel " << PI->Num << ": " << DescKind(PI->Kind) << ", live = {";
|
||||
|
||||
for (CollectorMetadata::live_iterator RI = FD->live_begin(PI),
|
||||
RE = FD->live_end(PI);;) {
|
||||
for (GCFunctionInfo::live_iterator RI = FD->live_begin(PI),
|
||||
RE = FD->live_end(PI);;) {
|
||||
OS << " " << RI->Num;
|
||||
if (++RI == RE)
|
||||
break;
|
||||
@ -187,7 +185,7 @@ bool Printer::runOnFunction(Function &F) {
|
||||
|
||||
char Deleter::ID = 0;
|
||||
|
||||
FunctionPass *llvm::createCollectorMetadataDeleter() {
|
||||
FunctionPass *llvm::createGCInfoDeleter() {
|
||||
return new Deleter();
|
||||
}
|
||||
|
||||
@ -199,7 +197,7 @@ const char *Deleter::getPassName() const {
|
||||
|
||||
void Deleter::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
AU.addRequired<GCModuleInfo>();
|
||||
}
|
||||
|
||||
bool Deleter::runOnFunction(Function &MF) {
|
||||
@ -207,8 +205,8 @@ bool Deleter::runOnFunction(Function &MF) {
|
||||
}
|
||||
|
||||
bool Deleter::doFinalization(Module &M) {
|
||||
CollectorModuleMetadata *CMM = getAnalysisToUpdate<CollectorModuleMetadata>();
|
||||
assert(CMM && "Deleter didn't require CollectorModuleMetadata?!");
|
||||
CMM->clear();
|
||||
GCModuleInfo *GMI = getAnalysisToUpdate<GCModuleInfo>();
|
||||
assert(GMI && "Deleter didn't require GCModuleInfo?!");
|
||||
GMI->clear();
|
||||
return false;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- Collector.cpp - Garbage collection infrastructure -----------------===//
|
||||
//===-- GCMetadataPrinter.cpp - Garbage collection infrastructure ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,15 +7,25 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements target- and collector-independent garbage collection
|
||||
// infrastructure.
|
||||
// This file implements the abstract base class GCMetadataPrinter.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template<> GCMetadataPrinterRegistry::node *GCMetadataPrinterRegistry::Head = 0;
|
||||
template<> GCMetadataPrinterRegistry::node *GCMetadataPrinterRegistry::Tail = 0;
|
||||
template<> GCMetadataPrinterRegistry::listener *
|
||||
GCMetadataPrinterRegistry::ListenerHead = 0;
|
||||
template<> GCMetadataPrinterRegistry::listener *
|
||||
GCMetadataPrinterRegistry::ListenerTail = 0;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
GCMetadataPrinter::GCMetadataPrinter() { }
|
||||
|
||||
GCMetadataPrinter::~GCMetadataPrinter() { }
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- Collector.cpp - Garbage collection infrastructure -----------------===//
|
||||
//===-- GCStrategy.cpp - Garbage collection infrastructure -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -10,6 +10,9 @@
|
||||
// This file implements target- and collector-independent garbage collection
|
||||
// infrastructure.
|
||||
//
|
||||
// MachineCodeAnalysis identifies the GC safe points in the machine code. Roots
|
||||
// are identified in SelectionDAGISel.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
@ -31,13 +34,13 @@ namespace {
|
||||
|
||||
/// 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
|
||||
/// directed by the GCStrategy. It also performs automatic root initialization
|
||||
/// and custom intrinsic lowering.
|
||||
class VISIBILITY_HIDDEN LowerIntrinsics : public FunctionPass {
|
||||
static bool NeedsDefaultLoweringPass(const Collector &C);
|
||||
static bool NeedsCustomLoweringPass(const Collector &C);
|
||||
static bool NeedsDefaultLoweringPass(const GCStrategy &C);
|
||||
static bool NeedsCustomLoweringPass(const GCStrategy &C);
|
||||
static bool CouldBecomeSafePoint(Instruction *I);
|
||||
bool PerformDefaultLowering(Function &F, Collector &Coll);
|
||||
bool PerformDefaultLowering(Function &F, GCStrategy &Coll);
|
||||
static bool InsertRootInitializers(Function &F,
|
||||
AllocaInst **Roots, unsigned Count);
|
||||
|
||||
@ -56,10 +59,10 @@ namespace {
|
||||
/// 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.
|
||||
/// GCMetadata record for each function.
|
||||
class VISIBILITY_HIDDEN MachineCodeAnalysis : public MachineFunctionPass {
|
||||
const TargetMachine *TM;
|
||||
CollectorMetadata *MD;
|
||||
GCFunctionInfo *FI;
|
||||
MachineModuleInfo *MMI;
|
||||
const TargetInstrInfo *TII;
|
||||
MachineFrameInfo *MFI;
|
||||
@ -85,7 +88,14 @@ namespace {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Collector::Collector() :
|
||||
template<> GCRegistry::node *GCRegistry::Head = 0;
|
||||
template<> GCRegistry::node *GCRegistry::Tail = 0;
|
||||
template<> GCRegistry::listener *GCRegistry::ListenerHead = 0;
|
||||
template<> GCRegistry::listener *GCRegistry::ListenerTail = 0;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
GCStrategy::GCStrategy() :
|
||||
NeededSafePoints(0),
|
||||
CustomReadBarriers(false),
|
||||
CustomWriteBarriers(false),
|
||||
@ -94,26 +104,26 @@ Collector::Collector() :
|
||||
UsesMetadata(false)
|
||||
{}
|
||||
|
||||
Collector::~Collector() {
|
||||
GCStrategy::~GCStrategy() {
|
||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||
delete *I;
|
||||
|
||||
Functions.clear();
|
||||
}
|
||||
|
||||
bool Collector::initializeCustomLowering(Module &M) { return false; }
|
||||
bool GCStrategy::initializeCustomLowering(Module &M) { return false; }
|
||||
|
||||
bool Collector::performCustomLowering(Function &F) {
|
||||
bool GCStrategy::performCustomLowering(Function &F) {
|
||||
cerr << "gc " << getName() << " must override performCustomLowering.\n";
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CollectorMetadata *Collector::insertFunctionMetadata(const Function &F) {
|
||||
CollectorMetadata *CM = new CollectorMetadata(F, *this);
|
||||
Functions.push_back(CM);
|
||||
return CM;
|
||||
}
|
||||
|
||||
GCFunctionInfo *GCStrategy::insertFunctionInfo(const Function &F) {
|
||||
GCFunctionInfo *FI = new GCFunctionInfo(F, *this);
|
||||
Functions.push_back(FI);
|
||||
return FI;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@ -132,7 +142,7 @@ const char *LowerIntrinsics::getPassName() const {
|
||||
|
||||
void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
FunctionPass::getAnalysisUsage(AU);
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
AU.addRequired<GCModuleInfo>();
|
||||
}
|
||||
|
||||
/// doInitialization - If this module uses the GC intrinsics, find them now.
|
||||
@ -141,15 +151,14 @@ bool LowerIntrinsics::doInitialization(Module &M) {
|
||||
// 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!?");
|
||||
GCModuleInfo *MI = getAnalysisToUpdate<GCModuleInfo>();
|
||||
assert(MI && "LowerIntrinsics didn't require GCModuleInfo!?");
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isDeclaration() && I->hasCollector())
|
||||
CMM->get(*I); // Instantiate the Collector.
|
||||
if (!I->isDeclaration() && I->hasGC())
|
||||
MI->getFunctionInfo(*I); // Instantiate the GC strategy.
|
||||
|
||||
bool MadeChange = false;
|
||||
for (CollectorModuleMetadata::iterator I = CMM->begin(),
|
||||
E = CMM->end(); I != E; ++I)
|
||||
for (GCModuleInfo::iterator I = MI->begin(), E = MI->end(); I != E; ++I)
|
||||
if (NeedsCustomLoweringPass(**I))
|
||||
if ((*I)->initializeCustomLowering(M))
|
||||
MadeChange = true;
|
||||
@ -185,7 +194,7 @@ bool LowerIntrinsics::InsertRootInitializers(Function &F, AllocaInst **Roots,
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
bool LowerIntrinsics::NeedsDefaultLoweringPass(const Collector &C) {
|
||||
bool LowerIntrinsics::NeedsDefaultLoweringPass(const GCStrategy &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()
|
||||
@ -193,7 +202,7 @@ bool LowerIntrinsics::NeedsDefaultLoweringPass(const Collector &C) {
|
||||
|| C.initializeRoots();
|
||||
}
|
||||
|
||||
bool LowerIntrinsics::NeedsCustomLoweringPass(const Collector &C) {
|
||||
bool LowerIntrinsics::NeedsCustomLoweringPass(const GCStrategy &C) {
|
||||
// Custom lowering is only necessary if enabled for some action.
|
||||
return C.customWriteBarrier()
|
||||
|| C.customReadBarrier()
|
||||
@ -232,26 +241,27 @@ bool LowerIntrinsics::CouldBecomeSafePoint(Instruction *I) {
|
||||
/// 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.hasCollector()) return false;
|
||||
if (!F.hasGC())
|
||||
return false;
|
||||
|
||||
CollectorMetadata &MD = getAnalysis<CollectorModuleMetadata>().get(F);
|
||||
Collector &Coll = MD.getCollector();
|
||||
GCFunctionInfo &FI = getAnalysis<GCModuleInfo>().getFunctionInfo(F);
|
||||
GCStrategy &S = FI.getStrategy();
|
||||
|
||||
bool MadeChange = false;
|
||||
|
||||
if (NeedsDefaultLoweringPass(Coll))
|
||||
MadeChange |= PerformDefaultLowering(F, Coll);
|
||||
if (NeedsDefaultLoweringPass(S))
|
||||
MadeChange |= PerformDefaultLowering(F, S);
|
||||
|
||||
if (NeedsCustomLoweringPass(Coll))
|
||||
MadeChange |= Coll.performCustomLowering(F);
|
||||
if (NeedsCustomLoweringPass(S))
|
||||
MadeChange |= S.performCustomLowering(F);
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
bool LowerIntrinsics::PerformDefaultLowering(Function &F, Collector &Coll) {
|
||||
bool LowerWr = !Coll.customWriteBarrier();
|
||||
bool LowerRd = !Coll.customReadBarrier();
|
||||
bool InitRoots = Coll.initializeRoots();
|
||||
bool LowerIntrinsics::PerformDefaultLowering(Function &F, GCStrategy &S) {
|
||||
bool LowerWr = !S.customWriteBarrier();
|
||||
bool LowerRd = !S.customReadBarrier();
|
||||
bool InitRoots = S.initializeRoots();
|
||||
|
||||
SmallVector<AllocaInst*,32> Roots;
|
||||
|
||||
@ -320,7 +330,7 @@ void MachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<MachineModuleInfo>();
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
AU.addRequired<GCModuleInfo>();
|
||||
}
|
||||
|
||||
unsigned MachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB,
|
||||
@ -336,11 +346,11 @@ void MachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) {
|
||||
MachineBasicBlock::iterator RAI = CI;
|
||||
++RAI;
|
||||
|
||||
if (MD->getCollector().needsSafePoint(GC::PreCall))
|
||||
MD->addSafePoint(GC::PreCall, InsertLabel(*CI->getParent(), CI));
|
||||
if (FI->getStrategy().needsSafePoint(GC::PreCall))
|
||||
FI->addSafePoint(GC::PreCall, InsertLabel(*CI->getParent(), CI));
|
||||
|
||||
if (MD->getCollector().needsSafePoint(GC::PostCall))
|
||||
MD->addSafePoint(GC::PostCall, InsertLabel(*CI->getParent(), RAI));
|
||||
if (FI->getStrategy().needsSafePoint(GC::PostCall))
|
||||
FI->addSafePoint(GC::PostCall, InsertLabel(*CI->getParent(), RAI));
|
||||
}
|
||||
|
||||
void MachineCodeAnalysis::FindSafePoints(MachineFunction &MF) {
|
||||
@ -357,18 +367,19 @@ void MachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
|
||||
uint64_t OffsetAdjustment = MFI->getOffsetAdjustment();
|
||||
uint64_t OffsetOfLocalArea = TM->getFrameInfo()->getOffsetOfLocalArea();
|
||||
|
||||
for (CollectorMetadata::roots_iterator RI = MD->roots_begin(),
|
||||
RE = MD->roots_end(); RI != RE; ++RI)
|
||||
for (GCFunctionInfo::roots_iterator RI = FI->roots_begin(),
|
||||
RE = FI->roots_end(); RI != RE; ++RI)
|
||||
RI->StackOffset = MFI->getObjectOffset(RI->Num) + StackSize
|
||||
- OffsetOfLocalArea + OffsetAdjustment;
|
||||
}
|
||||
|
||||
bool MachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
|
||||
// Quick exit for functions that do not use GC.
|
||||
if (!MF.getFunction()->hasCollector()) return false;
|
||||
if (!MF.getFunction()->hasGC())
|
||||
return false;
|
||||
|
||||
MD = &getAnalysis<CollectorModuleMetadata>().get(*MF.getFunction());
|
||||
if (!MD->getCollector().needsSafePoints())
|
||||
FI = &getAnalysis<GCModuleInfo>().getFunctionInfo(*MF.getFunction());
|
||||
if (!FI->getStrategy().needsSafePoints())
|
||||
return false;
|
||||
|
||||
TM = &MF.getTarget();
|
||||
@ -377,7 +388,7 @@ bool MachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) {
|
||||
MFI = MF.getFrameInfo();
|
||||
|
||||
// Find the size of the stack frame.
|
||||
MD->setFrameSize(MFI->getStackSize());
|
||||
FI->setFrameSize(MFI->getStackSize());
|
||||
|
||||
// Find all safe points.
|
||||
FindSafePoints(MF);
|
||||
|
@ -1,28 +0,0 @@
|
||||
//===-- Collectors.cpp - Garbage collector registry -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the static data members of the CollectorRegistry class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
template<> CollectorRegistry::node *CollectorRegistry::Head = 0;
|
||||
template<> CollectorRegistry::node *CollectorRegistry::Tail = 0;
|
||||
template<> CollectorRegistry::listener *CollectorRegistry::ListenerHead = 0;
|
||||
template<> CollectorRegistry::listener *CollectorRegistry::ListenerTail = 0;
|
||||
|
||||
template<> GCMetadataPrinterRegistry::node *GCMetadataPrinterRegistry::Head = 0;
|
||||
template<> GCMetadataPrinterRegistry::node *GCMetadataPrinterRegistry::Tail = 0;
|
||||
template<> GCMetadataPrinterRegistry::listener *
|
||||
GCMetadataPrinterRegistry::ListenerHead = 0;
|
||||
template<> GCMetadataPrinterRegistry::listener *
|
||||
GCMetadataPrinterRegistry::ListenerTail = 0;
|
@ -133,7 +133,7 @@ LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
|
||||
PM.add(createMachineFunctionPrinterPass(cerr));
|
||||
|
||||
if (PrintGCInfo)
|
||||
PM.add(createCollectorMetadataPrinter(*cerr));
|
||||
PM.add(createGCInfoPrinter(*cerr));
|
||||
|
||||
// Fold redundant debug labels.
|
||||
PM.add(createDebugLabelFoldingPass());
|
||||
@ -173,7 +173,7 @@ bool LLVMTargetMachine::addPassesToEmitFileFinish(PassManagerBase &PM,
|
||||
if (MCE)
|
||||
addSimpleCodeEmitter(PM, Fast, PrintEmittedAsm, *MCE);
|
||||
|
||||
PM.add(createCollectorMetadataDeleter());
|
||||
PM.add(createGCInfoDeleter());
|
||||
|
||||
// Delete machine code for this function
|
||||
PM.add(createMachineCodeDeleter());
|
||||
@ -274,14 +274,14 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM,
|
||||
PM.add(createMachineFunctionPrinterPass(cerr));
|
||||
|
||||
if (PrintGCInfo)
|
||||
PM.add(createCollectorMetadataPrinter(*cerr));
|
||||
PM.add(createGCInfoPrinter(*cerr));
|
||||
|
||||
if (addPreEmitPass(PM, Fast) && PrintMachineCode)
|
||||
PM.add(createMachineFunctionPrinterPass(cerr));
|
||||
|
||||
addCodeEmitter(PM, Fast, PrintEmittedAsm, MCE);
|
||||
|
||||
PM.add(createCollectorMetadataDeleter());
|
||||
PM.add(createGCInfoDeleter());
|
||||
|
||||
// Delete machine code for this function
|
||||
PM.add(createMachineCodeDeleter());
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- OcamlCollector.cpp - Ocaml frametable emitter ---------------------===//
|
||||
//===-- OcamlGC.cpp - Ocaml frametable GC strategy ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -9,38 +9,29 @@
|
||||
//
|
||||
// This file implements lowering for the llvm.gc* intrinsics compatible with
|
||||
// Objective Caml 3.10.0, which uses a liveness-accurate static stack map.
|
||||
//
|
||||
// The frametable emitter is in OcamlGCPrinter.cpp.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Target/TargetAsmInfo.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN OcamlCollector : public Collector {
|
||||
class VISIBILITY_HIDDEN OcamlGC : public GCStrategy {
|
||||
public:
|
||||
OcamlCollector();
|
||||
OcamlGC();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static CollectorRegistry::Add<OcamlCollector>
|
||||
X("ocaml", "ocaml 3.10-compatible collector");
|
||||
static GCRegistry::Add<OcamlGC>
|
||||
X("ocaml", "ocaml 3.10-compatible GC");
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void llvm::linkOcamlGC() { }
|
||||
|
||||
Collector *llvm::createOcamlCollector() {
|
||||
return new OcamlCollector();
|
||||
}
|
||||
|
||||
OcamlCollector::OcamlCollector() {
|
||||
OcamlGC::OcamlGC() {
|
||||
NeededSafePoints = 1 << GC::PostCall;
|
||||
UsesMetadata = true;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/ParameterAttributes.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/CodeGen/GCMetadata.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
@ -601,15 +602,15 @@ public:
|
||||
///
|
||||
FunctionLoweringInfo &FuncInfo;
|
||||
|
||||
/// GCI - Garbage collection metadata for the function.
|
||||
CollectorMetadata *GCI;
|
||||
/// GFI - Garbage collection metadata for the function.
|
||||
GCFunctionInfo *GFI;
|
||||
|
||||
SelectionDAGLowering(SelectionDAG &dag, TargetLowering &tli,
|
||||
AliasAnalysis &aa,
|
||||
FunctionLoweringInfo &funcinfo,
|
||||
CollectorMetadata *gci)
|
||||
GCFunctionInfo *gfi)
|
||||
: TLI(tli), DAG(dag), TD(DAG.getTarget().getTargetData()), AA(aa),
|
||||
FuncInfo(funcinfo), GCI(gci) {
|
||||
FuncInfo(funcinfo), GFI(gfi) {
|
||||
}
|
||||
|
||||
/// getRoot - Return the current virtual root of the Selection DAG,
|
||||
@ -3485,18 +3486,18 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
|
||||
}
|
||||
|
||||
case Intrinsic::gcroot:
|
||||
if (GCI) {
|
||||
if (GFI) {
|
||||
Value *Alloca = I.getOperand(1);
|
||||
Constant *TypeMap = cast<Constant>(I.getOperand(2));
|
||||
|
||||
FrameIndexSDNode *FI = cast<FrameIndexSDNode>(getValue(Alloca).Val);
|
||||
GCI->addStackRoot(FI->getIndex(), TypeMap);
|
||||
GFI->addStackRoot(FI->getIndex(), TypeMap);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case Intrinsic::gcread:
|
||||
case Intrinsic::gcwrite:
|
||||
assert(0 && "Collector failed to lower gcread/gcwrite intrinsics!");
|
||||
assert(0 && "GC failed to lower gcread/gcwrite intrinsics!");
|
||||
return 0;
|
||||
|
||||
case Intrinsic::flt_rounds: {
|
||||
@ -4878,7 +4879,7 @@ unsigned SelectionDAGISel::MakeReg(MVT VT) {
|
||||
|
||||
void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addRequired<CollectorModuleMetadata>();
|
||||
AU.addRequired<GCModuleInfo>();
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
@ -4887,10 +4888,10 @@ bool SelectionDAGISel::runOnFunction(Function &Fn) {
|
||||
AA = &getAnalysis<AliasAnalysis>();
|
||||
|
||||
MachineFunction &MF = MachineFunction::construct(&Fn, TLI.getTargetMachine());
|
||||
if (MF.getFunction()->hasCollector())
|
||||
GCI = &getAnalysis<CollectorModuleMetadata>().get(*MF.getFunction());
|
||||
if (MF.getFunction()->hasGC())
|
||||
GFI = &getAnalysis<GCModuleInfo>().getFunctionInfo(*MF.getFunction());
|
||||
else
|
||||
GCI = 0;
|
||||
GFI = 0;
|
||||
RegInfo = &MF.getRegInfo();
|
||||
DOUT << "\n\n\n=== " << Fn.getName() << "\n";
|
||||
|
||||
@ -5089,7 +5090,7 @@ static void CheckDAGForTailCallsAndFixThem(SelectionDAG &DAG,
|
||||
void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
|
||||
std::vector<std::pair<MachineInstr*, unsigned> > &PHINodesToUpdate,
|
||||
FunctionLoweringInfo &FuncInfo) {
|
||||
SelectionDAGLowering SDL(DAG, TLI, *AA, FuncInfo, GCI);
|
||||
SelectionDAGLowering SDL(DAG, TLI, *AA, FuncInfo, GFI);
|
||||
|
||||
// Lower any arguments needed in this block if this is the entry block.
|
||||
if (LLVMBB == &LLVMBB->getParent()->getEntryBlock())
|
||||
@ -5504,7 +5505,7 @@ SelectionDAGISel::FinishBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
|
||||
getAnalysisToUpdate<MachineModuleInfo>(),
|
||||
NodeAllocator);
|
||||
CurDAG = &HSDAG;
|
||||
SelectionDAGLowering HSDL(HSDAG, TLI, *AA, FuncInfo, GCI);
|
||||
SelectionDAGLowering HSDL(HSDAG, TLI, *AA, FuncInfo, GFI);
|
||||
// Set the current basic block to the mbb we wish to insert the code into
|
||||
BB = BitTestCases[i].Parent;
|
||||
HSDL.setCurrentBasicBlock(BB);
|
||||
@ -5519,7 +5520,7 @@ SelectionDAGISel::FinishBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
|
||||
getAnalysisToUpdate<MachineModuleInfo>(),
|
||||
NodeAllocator);
|
||||
CurDAG = &BSDAG;
|
||||
SelectionDAGLowering BSDL(BSDAG, TLI, *AA, FuncInfo, GCI);
|
||||
SelectionDAGLowering BSDL(BSDAG, TLI, *AA, FuncInfo, GFI);
|
||||
// Set the current basic block to the mbb we wish to insert the code into
|
||||
BB = BitTestCases[i].Cases[j].ThisBB;
|
||||
BSDL.setCurrentBasicBlock(BB);
|
||||
@ -5578,7 +5579,7 @@ SelectionDAGISel::FinishBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
|
||||
getAnalysisToUpdate<MachineModuleInfo>(),
|
||||
NodeAllocator);
|
||||
CurDAG = &HSDAG;
|
||||
SelectionDAGLowering HSDL(HSDAG, TLI, *AA, FuncInfo, GCI);
|
||||
SelectionDAGLowering HSDL(HSDAG, TLI, *AA, FuncInfo, GFI);
|
||||
// Set the current basic block to the mbb we wish to insert the code into
|
||||
BB = JTCases[i].first.HeaderBB;
|
||||
HSDL.setCurrentBasicBlock(BB);
|
||||
@ -5592,7 +5593,7 @@ SelectionDAGISel::FinishBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
|
||||
getAnalysisToUpdate<MachineModuleInfo>(),
|
||||
NodeAllocator);
|
||||
CurDAG = &JSDAG;
|
||||
SelectionDAGLowering JSDL(JSDAG, TLI, *AA, FuncInfo, GCI);
|
||||
SelectionDAGLowering JSDL(JSDAG, TLI, *AA, FuncInfo, GFI);
|
||||
// Set the current basic block to the mbb we wish to insert the code into
|
||||
BB = JTCases[i].second.MBB;
|
||||
JSDL.setCurrentBasicBlock(BB);
|
||||
@ -5642,7 +5643,7 @@ SelectionDAGISel::FinishBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
|
||||
getAnalysisToUpdate<MachineModuleInfo>(),
|
||||
NodeAllocator);
|
||||
CurDAG = &SDAG;
|
||||
SelectionDAGLowering SDL(SDAG, TLI, *AA, FuncInfo, GCI);
|
||||
SelectionDAGLowering SDL(SDAG, TLI, *AA, FuncInfo, GFI);
|
||||
|
||||
// Set the current basic block to the mbb we wish to insert the code into
|
||||
BB = SwitchCases[i].ThisBB;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- ShadowStackCollector.cpp - GC support for uncooperative targets ---===//
|
||||
//===-- ShadowStackGC.cpp - GC support for uncooperative targets ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -9,7 +9,7 @@
|
||||
//
|
||||
// This file implements lowering for the llvm.gc* intrinsics for targets that do
|
||||
// not natively support them (which includes the C backend). Note that the code
|
||||
// generated is not quite as efficient as collectors which generate stack maps
|
||||
// generated is not quite as efficient as algorithms which generate stack maps
|
||||
// to identify roots.
|
||||
//
|
||||
// This pass implements the code transformation described in this paper:
|
||||
@ -17,7 +17,7 @@
|
||||
// Fergus Henderson, ISMM, 2002
|
||||
//
|
||||
// In runtime/GC/SemiSpace.cpp is a prototype runtime which is compatible with
|
||||
// this collector.
|
||||
// ShadowStackGC.
|
||||
//
|
||||
// In order to support this particular transformation, all stack roots are
|
||||
// coallocated in the stack. This allows a fully target-independent stack map
|
||||
@ -37,7 +37,7 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN ShadowStackCollector : public Collector {
|
||||
class VISIBILITY_HIDDEN ShadowStackGC : public GCStrategy {
|
||||
/// RootChain - This is the global linked-list that contains the chain of GC
|
||||
/// roots.
|
||||
GlobalVariable *Head;
|
||||
@ -51,7 +51,7 @@ namespace {
|
||||
std::vector<std::pair<CallInst*,AllocaInst*> > Roots;
|
||||
|
||||
public:
|
||||
ShadowStackCollector();
|
||||
ShadowStackGC();
|
||||
|
||||
bool initializeCustomLowering(Module &M);
|
||||
bool performCustomLowering(Function &F);
|
||||
@ -69,9 +69,8 @@ namespace {
|
||||
|
||||
}
|
||||
|
||||
static CollectorRegistry::Add<ShadowStackCollector>
|
||||
Y("shadow-stack",
|
||||
"Very portable collector for uncooperative code generators");
|
||||
static GCRegistry::Add<ShadowStackGC>
|
||||
X("shadow-stack", "Very portable GC for uncooperative code generators");
|
||||
|
||||
namespace {
|
||||
/// EscapeEnumerator - This is a little algorithm to find all escape points
|
||||
@ -173,21 +172,18 @@ namespace {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Collector *llvm::createShadowStackCollector() {
|
||||
return new ShadowStackCollector();
|
||||
}
|
||||
void llvm::linkShadowStackGC() { }
|
||||
|
||||
ShadowStackCollector::ShadowStackCollector() : Head(0), StackEntryTy(0) {
|
||||
ShadowStackGC::ShadowStackGC() : Head(0), StackEntryTy(0) {
|
||||
InitRoots = true;
|
||||
CustomRoots = true;
|
||||
}
|
||||
|
||||
Constant *ShadowStackCollector::GetFrameMap(Function &F) {
|
||||
Constant *ShadowStackGC::GetFrameMap(Function &F) {
|
||||
// doInitialization creates the abstract type of this value.
|
||||
|
||||
Type *VoidPtr = PointerType::getUnqual(Type::Int8Ty);
|
||||
@ -242,7 +238,7 @@ Constant *ShadowStackCollector::GetFrameMap(Function &F) {
|
||||
return ConstantExpr::getGetElementPtr(GV, GEPIndices, 2);
|
||||
}
|
||||
|
||||
const Type* ShadowStackCollector::GetConcreteStackEntryType(Function &F) {
|
||||
const Type* ShadowStackGC::GetConcreteStackEntryType(Function &F) {
|
||||
// doInitialization creates the generic version of this type.
|
||||
std::vector<const Type*> EltTys;
|
||||
EltTys.push_back(StackEntryTy);
|
||||
@ -259,7 +255,7 @@ const Type* ShadowStackCollector::GetConcreteStackEntryType(Function &F) {
|
||||
|
||||
/// doInitialization - If this module uses the GC intrinsics, find them now. If
|
||||
/// not, exit fast.
|
||||
bool ShadowStackCollector::initializeCustomLowering(Module &M) {
|
||||
bool ShadowStackGC::initializeCustomLowering(Module &M) {
|
||||
// struct FrameMap {
|
||||
// int32_t NumRoots; // Number of roots in stack frame.
|
||||
// int32_t NumMeta; // Number of metadata descriptors. May be < NumRoots.
|
||||
@ -307,13 +303,13 @@ bool ShadowStackCollector::initializeCustomLowering(Module &M) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShadowStackCollector::IsNullValue(Value *V) {
|
||||
bool ShadowStackGC::IsNullValue(Value *V) {
|
||||
if (Constant *C = dyn_cast<Constant>(V))
|
||||
return C->isNullValue();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShadowStackCollector::CollectRoots(Function &F) {
|
||||
void ShadowStackGC::CollectRoots(Function &F) {
|
||||
// FIXME: Account for original alignment. Could fragment the root array.
|
||||
// Approach 1: Null initialize empty slots at runtime. Yuck.
|
||||
// Approach 2: Emit a map of the array instead of just a count.
|
||||
@ -341,8 +337,8 @@ void ShadowStackCollector::CollectRoots(Function &F) {
|
||||
}
|
||||
|
||||
GetElementPtrInst *
|
||||
ShadowStackCollector::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
||||
int Idx, int Idx2, const char *Name) {
|
||||
ShadowStackGC::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
||||
int Idx, int Idx2, const char *Name) {
|
||||
Value *Indices[] = { ConstantInt::get(Type::Int32Ty, 0),
|
||||
ConstantInt::get(Type::Int32Ty, Idx),
|
||||
ConstantInt::get(Type::Int32Ty, Idx2) };
|
||||
@ -354,8 +350,8 @@ ShadowStackCollector::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
||||
}
|
||||
|
||||
GetElementPtrInst *
|
||||
ShadowStackCollector::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
||||
int Idx, const char *Name) {
|
||||
ShadowStackGC::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
||||
int Idx, const char *Name) {
|
||||
Value *Indices[] = { ConstantInt::get(Type::Int32Ty, 0),
|
||||
ConstantInt::get(Type::Int32Ty, Idx) };
|
||||
Value *Val = B.CreateGEP(BasePtr, Indices, Indices + 2, Name);
|
||||
@ -366,7 +362,7 @@ ShadowStackCollector::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
||||
}
|
||||
|
||||
/// runOnFunction - Insert code to maintain the shadow stack.
|
||||
bool ShadowStackCollector::performCustomLowering(Function &F) {
|
||||
bool ShadowStackGC::performCustomLowering(Function &F) {
|
||||
// Find calls to llvm.gcroot.
|
||||
CollectRoots(F);
|
||||
|
||||
@ -405,9 +401,10 @@ bool ShadowStackCollector::performCustomLowering(Function &F) {
|
||||
OriginalAlloca->replaceAllUsesWith(SlotPtr);
|
||||
}
|
||||
|
||||
// Move past the original stores inserted by Collector::InitRoots. This isn't
|
||||
// really necessary (the collector would never see the intermediate state),
|
||||
// but it's nicer not to push the half-initialized entry onto the stack.
|
||||
// Move past the original stores inserted by GCStrategy::InitRoots. This isn't
|
||||
// really necessary (the collector would never see the intermediate state at
|
||||
// runtime), but it's nicer not to push the half-initialized entry onto the
|
||||
// shadow stack.
|
||||
while (isa<StoreInst>(IP)) ++IP;
|
||||
AtEntry.SetInsertPoint(IP->getParent(), IP);
|
||||
|
||||
|
@ -3386,6 +3386,6 @@ bool CTargetMachine::addPassesToEmitWholeFile(PassManager &PM,
|
||||
PM.add(createCFGSimplificationPass()); // clean up after lower invoke.
|
||||
PM.add(new CBackendNameAllUsedStructsAndMergeFunctions());
|
||||
PM.add(new CWriter(o));
|
||||
PM.add(createCollectorMetadataDeleter());
|
||||
PM.add(createGCInfoDeleter());
|
||||
return false;
|
||||
}
|
||||
|
@ -1603,9 +1603,9 @@ namespace {
|
||||
Out << ");";
|
||||
nl(Out);
|
||||
}
|
||||
if (F->hasCollector()) {
|
||||
if (F->hasGC()) {
|
||||
printCppName(F);
|
||||
Out << "->setCollector(\"" << F->getCollector() << "\");";
|
||||
Out << "->setGC(\"" << F->getGC() << "\");";
|
||||
nl(Out);
|
||||
}
|
||||
if (is_inline) {
|
||||
|
@ -1660,6 +1660,6 @@ bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, std::ostream &o,
|
||||
PM.add(createCFGSimplificationPass());
|
||||
PM.add(new MSILModule(Writer->UsedTypes,Writer->TD));
|
||||
PM.add(Writer);
|
||||
PM.add(createCollectorMetadataDeleter());
|
||||
PM.add(createGCInfoDeleter());
|
||||
return false;
|
||||
}
|
||||
|
@ -208,10 +208,10 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG, const TargetData *TD) {
|
||||
// 1. If the caller has no GC, then the callee's GC must be propagated to the
|
||||
// caller.
|
||||
// 2. If the caller has a differing GC, it is invalid to inline.
|
||||
if (CalledFunc->hasCollector()) {
|
||||
if (!Caller->hasCollector())
|
||||
Caller->setCollector(CalledFunc->getCollector());
|
||||
else if (CalledFunc->getCollector() != Caller->getCollector())
|
||||
if (CalledFunc->hasGC()) {
|
||||
if (!Caller->hasGC())
|
||||
Caller->setGC(CalledFunc->getGC());
|
||||
else if (CalledFunc->getGC() != Caller->getGC())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1184,8 +1184,8 @@ void AssemblyWriter::printFunction(const Function *F) {
|
||||
Out << " section \"" << F->getSection() << '"';
|
||||
if (F->getAlignment())
|
||||
Out << " align " << F->getAlignment();
|
||||
if (F->hasCollector())
|
||||
Out << " gc \"" << F->getCollector() << '"';
|
||||
if (F->hasGC())
|
||||
Out << " gc \"" << F->getGC() << '"';
|
||||
|
||||
if (F->isDeclaration()) {
|
||||
Out << "\n";
|
||||
|
@ -719,17 +719,17 @@ void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC) {
|
||||
return unwrap<Function>(Fn)->setCallingConv(CC);
|
||||
}
|
||||
|
||||
const char *LLVMGetCollector(LLVMValueRef Fn) {
|
||||
const char *LLVMGetGC(LLVMValueRef Fn) {
|
||||
Function *F = unwrap<Function>(Fn);
|
||||
return F->hasCollector()? F->getCollector() : 0;
|
||||
return F->hasGC()? F->getGC() : 0;
|
||||
}
|
||||
|
||||
void LLVMSetCollector(LLVMValueRef Fn, const char *Coll) {
|
||||
void LLVMSetGC(LLVMValueRef Fn, const char *GC) {
|
||||
Function *F = unwrap<Function>(Fn);
|
||||
if (Coll)
|
||||
F->setCollector(Coll);
|
||||
if (GC)
|
||||
F->setGC(GC);
|
||||
else
|
||||
F->clearCollector();
|
||||
F->clearGC();
|
||||
}
|
||||
|
||||
/*--.. Operations on parameters ............................................--*/
|
||||
|
@ -182,8 +182,8 @@ Function::~Function() {
|
||||
ArgumentList.clear();
|
||||
delete SymTab;
|
||||
|
||||
// Remove the function from the on-the-side collector table.
|
||||
clearCollector();
|
||||
// Remove the function from the on-the-side GC table.
|
||||
clearGC();
|
||||
}
|
||||
|
||||
void Function::BuildLazyArguments() const {
|
||||
@ -240,39 +240,39 @@ void Function::removeParamAttr(unsigned i, ParameterAttributes attr) {
|
||||
setParamAttrs(PAL);
|
||||
}
|
||||
|
||||
// Maintain the collector name for each function in an on-the-side table. This
|
||||
// saves allocating an additional word in Function for programs which do not use
|
||||
// GC (i.e., most programs) at the cost of increased overhead for clients which
|
||||
// do use GC.
|
||||
static DenseMap<const Function*,PooledStringPtr> *CollectorNames;
|
||||
static StringPool *CollectorNamePool;
|
||||
// Maintain the GC name for each function in an on-the-side table. This saves
|
||||
// allocating an additional word in Function for programs which do not use GC
|
||||
// (i.e., most programs) at the cost of increased overhead for clients which do
|
||||
// use GC.
|
||||
static DenseMap<const Function*,PooledStringPtr> *GCNames;
|
||||
static StringPool *GCNamePool;
|
||||
|
||||
bool Function::hasCollector() const {
|
||||
return CollectorNames && CollectorNames->count(this);
|
||||
bool Function::hasGC() const {
|
||||
return GCNames && GCNames->count(this);
|
||||
}
|
||||
|
||||
const char *Function::getCollector() const {
|
||||
assert(hasCollector() && "Function has no collector");
|
||||
return *(*CollectorNames)[this];
|
||||
const char *Function::getGC() const {
|
||||
assert(hasGC() && "Function has no collector");
|
||||
return *(*GCNames)[this];
|
||||
}
|
||||
|
||||
void Function::setCollector(const char *Str) {
|
||||
if (!CollectorNamePool)
|
||||
CollectorNamePool = new StringPool();
|
||||
if (!CollectorNames)
|
||||
CollectorNames = new DenseMap<const Function*,PooledStringPtr>();
|
||||
(*CollectorNames)[this] = CollectorNamePool->intern(Str);
|
||||
void Function::setGC(const char *Str) {
|
||||
if (!GCNamePool)
|
||||
GCNamePool = new StringPool();
|
||||
if (!GCNames)
|
||||
GCNames = new DenseMap<const Function*,PooledStringPtr>();
|
||||
(*GCNames)[this] = GCNamePool->intern(Str);
|
||||
}
|
||||
|
||||
void Function::clearCollector() {
|
||||
if (CollectorNames) {
|
||||
CollectorNames->erase(this);
|
||||
if (CollectorNames->empty()) {
|
||||
delete CollectorNames;
|
||||
CollectorNames = 0;
|
||||
if (CollectorNamePool->empty()) {
|
||||
delete CollectorNamePool;
|
||||
CollectorNamePool = 0;
|
||||
void Function::clearGC() {
|
||||
if (GCNames) {
|
||||
GCNames->erase(this);
|
||||
if (GCNames->empty()) {
|
||||
delete GCNames;
|
||||
GCNames = 0;
|
||||
if (GCNamePool->empty()) {
|
||||
delete GCNamePool;
|
||||
GCNamePool = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -286,8 +286,10 @@ void Function::copyAttributesFrom(const GlobalValue *Src) {
|
||||
const Function *SrcF = cast<Function>(Src);
|
||||
setCallingConv(SrcF->getCallingConv());
|
||||
setParamAttrs(SrcF->getParamAttrs());
|
||||
if (SrcF->hasCollector())
|
||||
setCollector(SrcF->getCollector());
|
||||
if (SrcF->hasGC())
|
||||
setGC(SrcF->getGC());
|
||||
else
|
||||
clearGC();
|
||||
}
|
||||
|
||||
/// getIntrinsicID - This method returns the ID number of the specified
|
||||
|
@ -1308,8 +1308,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
break;
|
||||
}
|
||||
|
||||
Assert1(CI.getParent()->getParent()->hasCollector(),
|
||||
"Enclosing function does not specify a collector algorithm.",
|
||||
Assert1(CI.getParent()->getParent()->hasGC(),
|
||||
"Enclosing function does not use GC.",
|
||||
&CI);
|
||||
} break;
|
||||
case Intrinsic::init_trampoline:
|
||||
|
@ -569,16 +569,16 @@ let test_functions () =
|
||||
insist (CallConv.fast = function_call_conv fn);
|
||||
ignore (build_unreachable (builder_at_end (entry_block fn)));
|
||||
|
||||
begin group "collector";
|
||||
begin group "gc";
|
||||
(* RUN: grep {Fn6.*gc.*shadowstack} < %t.ll
|
||||
*)
|
||||
let fn = define_function "Fn6" ty m in
|
||||
insist (None = collector fn);
|
||||
set_collector (Some "ocaml") fn;
|
||||
insist (Some "ocaml" = collector fn);
|
||||
set_collector None fn;
|
||||
insist (None = collector fn);
|
||||
set_collector (Some "shadowstack") fn;
|
||||
insist (None = gc fn);
|
||||
set_gc (Some "ocaml") fn;
|
||||
insist (Some "ocaml" = gc fn);
|
||||
set_gc None fn;
|
||||
insist (None = gc fn);
|
||||
set_gc (Some "shadowstack") fn;
|
||||
ignore (build_unreachable (builder_at_end (entry_block fn)));
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user