mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-01 13:37:55 +00:00
Delete trailing whitespace.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62307 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a10f15949d
commit
5c1799b293
@ -8,7 +8,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// Defines a registry template for discovering pluggable modules.
|
// Defines a registry template for discovering pluggable modules.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef LLVM_SUPPORT_REGISTRY_H
|
#ifndef LLVM_SUPPORT_REGISTRY_H
|
||||||
@ -23,34 +23,34 @@ namespace llvm {
|
|||||||
class SimpleRegistryEntry {
|
class SimpleRegistryEntry {
|
||||||
const char *Name, *Desc;
|
const char *Name, *Desc;
|
||||||
T *(*Ctor)();
|
T *(*Ctor)();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SimpleRegistryEntry(const char *N, const char *D, T *(*C)())
|
SimpleRegistryEntry(const char *N, const char *D, T *(*C)())
|
||||||
: Name(N), Desc(D), Ctor(C)
|
: Name(N), Desc(D), Ctor(C)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const char *getName() const { return Name; }
|
const char *getName() const { return Name; }
|
||||||
const char *getDesc() const { return Desc; }
|
const char *getDesc() const { return Desc; }
|
||||||
T *instantiate() const { return Ctor(); }
|
T *instantiate() const { return Ctor(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Traits for registry entries. If using other than SimpleRegistryEntry, it
|
/// Traits for registry entries. If using other than SimpleRegistryEntry, it
|
||||||
/// is necessary to define an alternate traits class.
|
/// is necessary to define an alternate traits class.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class RegistryTraits {
|
class RegistryTraits {
|
||||||
RegistryTraits(); // Do not implement.
|
RegistryTraits(); // Do not implement.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef SimpleRegistryEntry<T> entry;
|
typedef SimpleRegistryEntry<T> entry;
|
||||||
|
|
||||||
/// nameof/descof - Accessors for name and description of entries. These are
|
/// nameof/descof - Accessors for name and description of entries. These are
|
||||||
// used to generate help for command-line options.
|
// used to generate help for command-line options.
|
||||||
static const char *nameof(const entry &Entry) { return Entry.getName(); }
|
static const char *nameof(const entry &Entry) { return Entry.getName(); }
|
||||||
static const char *descof(const entry &Entry) { return Entry.getDesc(); }
|
static const char *descof(const entry &Entry) { return Entry.getDesc(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// A global registry used in conjunction with static constructors to make
|
/// A global registry used in conjunction with static constructors to make
|
||||||
/// pluggable components (like targets or garbage collectors) "just work" when
|
/// pluggable components (like targets or garbage collectors) "just work" when
|
||||||
/// linked with an executable.
|
/// linked with an executable.
|
||||||
@ -59,37 +59,37 @@ namespace llvm {
|
|||||||
public:
|
public:
|
||||||
typedef U traits;
|
typedef U traits;
|
||||||
typedef typename U::entry entry;
|
typedef typename U::entry entry;
|
||||||
|
|
||||||
class node;
|
class node;
|
||||||
class listener;
|
class listener;
|
||||||
class iterator;
|
class iterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Registry(); // Do not implement.
|
Registry(); // Do not implement.
|
||||||
|
|
||||||
static void Announce(const entry &E) {
|
static void Announce(const entry &E) {
|
||||||
for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next)
|
for (listener *Cur = ListenerHead; Cur; Cur = Cur->Next)
|
||||||
Cur->registered(E);
|
Cur->registered(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class node;
|
friend class node;
|
||||||
static node *Head, *Tail;
|
static node *Head, *Tail;
|
||||||
|
|
||||||
friend class listener;
|
friend class listener;
|
||||||
static listener *ListenerHead, *ListenerTail;
|
static listener *ListenerHead, *ListenerTail;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class iterator;
|
class iterator;
|
||||||
|
|
||||||
|
|
||||||
/// Node in linked list of entries.
|
/// Node in linked list of entries.
|
||||||
///
|
///
|
||||||
class node {
|
class node {
|
||||||
friend class iterator;
|
friend class iterator;
|
||||||
|
|
||||||
node *Next;
|
node *Next;
|
||||||
const entry& Val;
|
const entry& Val;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
node(const entry& V) : Next(0), Val(V) {
|
node(const entry& V) : Next(0), Val(V) {
|
||||||
if (Tail)
|
if (Tail)
|
||||||
@ -97,63 +97,63 @@ namespace llvm {
|
|||||||
else
|
else
|
||||||
Head = this;
|
Head = this;
|
||||||
Tail = this;
|
Tail = this;
|
||||||
|
|
||||||
Announce(V);
|
Announce(V);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Iterators for registry entries.
|
/// Iterators for registry entries.
|
||||||
///
|
///
|
||||||
class iterator {
|
class iterator {
|
||||||
const node *Cur;
|
const node *Cur;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit iterator(const node *N) : Cur(N) {}
|
explicit iterator(const node *N) : Cur(N) {}
|
||||||
|
|
||||||
bool operator==(const iterator &That) const { return Cur == That.Cur; }
|
bool operator==(const iterator &That) const { return Cur == That.Cur; }
|
||||||
bool operator!=(const iterator &That) const { return Cur != That.Cur; }
|
bool operator!=(const iterator &That) const { return Cur != That.Cur; }
|
||||||
iterator &operator++() { Cur = Cur->Next; return *this; }
|
iterator &operator++() { Cur = Cur->Next; return *this; }
|
||||||
const entry &operator*() const { return Cur->Val; }
|
const entry &operator*() const { return Cur->Val; }
|
||||||
const entry *operator->() const { return &Cur->Val; }
|
const entry *operator->() const { return &Cur->Val; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static iterator begin() { return iterator(Head); }
|
static iterator begin() { return iterator(Head); }
|
||||||
static iterator end() { return iterator(0); }
|
static iterator end() { return iterator(0); }
|
||||||
|
|
||||||
|
|
||||||
/// Abstract base class for registry listeners, which are informed when new
|
/// Abstract base class for registry listeners, which are informed when new
|
||||||
/// entries are added to the registry. Simply subclass and instantiate:
|
/// entries are added to the registry. Simply subclass and instantiate:
|
||||||
///
|
///
|
||||||
/// class CollectorPrinter : public Registry<Collector>::listener {
|
/// class CollectorPrinter : public Registry<Collector>::listener {
|
||||||
/// protected:
|
/// protected:
|
||||||
/// void registered(const Registry<Collector>::entry &e) {
|
/// void registered(const Registry<Collector>::entry &e) {
|
||||||
/// cerr << "collector now available: " << e->getName() << "\n";
|
/// cerr << "collector now available: " << e->getName() << "\n";
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// public:
|
/// public:
|
||||||
/// CollectorPrinter() { init(); } // Print those already registered.
|
/// CollectorPrinter() { init(); } // Print those already registered.
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// CollectorPrinter Printer;
|
/// CollectorPrinter Printer;
|
||||||
///
|
///
|
||||||
class listener {
|
class listener {
|
||||||
listener *Prev, *Next;
|
listener *Prev, *Next;
|
||||||
|
|
||||||
friend void Registry::Announce(const entry &E);
|
friend void Registry::Announce(const entry &E);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Called when an entry is added to the registry.
|
/// Called when an entry is added to the registry.
|
||||||
///
|
///
|
||||||
virtual void registered(const entry &) = 0;
|
virtual void registered(const entry &) = 0;
|
||||||
|
|
||||||
/// Calls 'registered' for each pre-existing entry.
|
/// Calls 'registered' for each pre-existing entry.
|
||||||
///
|
///
|
||||||
void init() {
|
void init() {
|
||||||
for (iterator I = begin(), E = end(); I != E; ++I)
|
for (iterator I = begin(), E = end(); I != E; ++I)
|
||||||
registered(*I);
|
registered(*I);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
listener() : Prev(ListenerTail), Next(0) {
|
listener() : Prev(ListenerTail), Next(0) {
|
||||||
if (Prev)
|
if (Prev)
|
||||||
@ -162,7 +162,7 @@ namespace llvm {
|
|||||||
ListenerHead = this;
|
ListenerHead = this;
|
||||||
ListenerTail = this;
|
ListenerTail = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~listener() {
|
virtual ~listener() {
|
||||||
if (Next)
|
if (Next)
|
||||||
Next->Prev = Prev;
|
Next->Prev = Prev;
|
||||||
@ -174,79 +174,79 @@ namespace llvm {
|
|||||||
ListenerHead = Next;
|
ListenerHead = Next;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// A static registration template. Use like such:
|
/// A static registration template. Use like such:
|
||||||
///
|
///
|
||||||
/// Registry<Collector>::Add<FancyGC>
|
/// Registry<Collector>::Add<FancyGC>
|
||||||
/// X("fancy-gc", "Newfangled garbage collector.");
|
/// X("fancy-gc", "Newfangled garbage collector.");
|
||||||
///
|
///
|
||||||
/// Use of this template requires that:
|
/// Use of this template requires that:
|
||||||
///
|
///
|
||||||
/// 1. The registered subclass has a default constructor.
|
/// 1. The registered subclass has a default constructor.
|
||||||
//
|
//
|
||||||
/// 2. The registry entry type has a constructor compatible with this
|
/// 2. The registry entry type has a constructor compatible with this
|
||||||
/// signature:
|
/// signature:
|
||||||
///
|
///
|
||||||
/// entry(const char *Name, const char *ShortDesc, T *(*Ctor)());
|
/// entry(const char *Name, const char *ShortDesc, T *(*Ctor)());
|
||||||
///
|
///
|
||||||
/// If you have more elaborate requirements, then copy and modify.
|
/// If you have more elaborate requirements, then copy and modify.
|
||||||
///
|
///
|
||||||
template <typename V>
|
template <typename V>
|
||||||
class Add {
|
class Add {
|
||||||
entry Entry;
|
entry Entry;
|
||||||
node Node;
|
node Node;
|
||||||
|
|
||||||
static T *CtorFn() { return new V(); }
|
static T *CtorFn() { return new V(); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Add(const char *Name, const char *Desc)
|
Add(const char *Name, const char *Desc)
|
||||||
: Entry(Name, Desc, CtorFn), Node(Entry) {}
|
: Entry(Name, Desc, CtorFn), Node(Entry) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// A command-line parser for a registry. Use like such:
|
/// A command-line parser for a registry. Use like such:
|
||||||
///
|
///
|
||||||
/// static cl::opt<Registry<Collector>::entry, false,
|
/// static cl::opt<Registry<Collector>::entry, false,
|
||||||
/// Registry<Collector>::Parser>
|
/// Registry<Collector>::Parser>
|
||||||
/// GCOpt("gc", cl::desc("Garbage collector to use."),
|
/// GCOpt("gc", cl::desc("Garbage collector to use."),
|
||||||
/// cl::value_desc());
|
/// cl::value_desc());
|
||||||
///
|
///
|
||||||
/// To make use of the value:
|
/// To make use of the value:
|
||||||
///
|
///
|
||||||
/// Collector *TheCollector = GCOpt->instantiate();
|
/// Collector *TheCollector = GCOpt->instantiate();
|
||||||
///
|
///
|
||||||
class Parser : public cl::parser<const typename U::entry*>, public listener{
|
class Parser : public cl::parser<const typename U::entry*>, public listener{
|
||||||
typedef U traits;
|
typedef U traits;
|
||||||
typedef typename U::entry entry;
|
typedef typename U::entry entry;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void registered(const entry &E) {
|
void registered(const entry &E) {
|
||||||
addLiteralOption(traits::nameof(E), &E, traits::descof(E));
|
addLiteralOption(traits::nameof(E), &E, traits::descof(E));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void initialize(cl::Option &O) {
|
void initialize(cl::Option &O) {
|
||||||
listener::init();
|
listener::init();
|
||||||
cl::parser<const typename U::entry*>::initialize(O);
|
cl::parser<const typename U::entry*>::initialize(O);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
typename Registry<T,U>::node *Registry<T,U>::Head;
|
typename Registry<T,U>::node *Registry<T,U>::Head;
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
typename Registry<T,U>::node *Registry<T,U>::Tail;
|
typename Registry<T,U>::node *Registry<T,U>::Tail;
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
typename Registry<T,U>::listener *Registry<T,U>::ListenerHead;
|
typename Registry<T,U>::listener *Registry<T,U>::ListenerHead;
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
typename Registry<T,U>::listener *Registry<T,U>::ListenerTail;
|
typename Registry<T,U>::listener *Registry<T,U>::ListenerTail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,14 +22,14 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
class Module;
|
class Module;
|
||||||
class TargetMachine;
|
class TargetMachine;
|
||||||
|
|
||||||
struct TargetMachineRegistryEntry {
|
struct TargetMachineRegistryEntry {
|
||||||
const char *Name;
|
const char *Name;
|
||||||
const char *ShortDesc;
|
const char *ShortDesc;
|
||||||
TargetMachine *(*CtorFn)(const Module &, const std::string &);
|
TargetMachine *(*CtorFn)(const Module &, const std::string &);
|
||||||
unsigned (*ModuleMatchQualityFn)(const Module &M);
|
unsigned (*ModuleMatchQualityFn)(const Module &M);
|
||||||
unsigned (*JITMatchQualityFn)();
|
unsigned (*JITMatchQualityFn)();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TargetMachineRegistryEntry(const char *N, const char *SD,
|
TargetMachineRegistryEntry(const char *N, const char *SD,
|
||||||
TargetMachine *(*CF)(const Module &, const std::string &),
|
TargetMachine *(*CF)(const Module &, const std::string &),
|
||||||
@ -38,12 +38,12 @@ namespace llvm {
|
|||||||
: Name(N), ShortDesc(SD), CtorFn(CF), ModuleMatchQualityFn(MMF),
|
: Name(N), ShortDesc(SD), CtorFn(CF), ModuleMatchQualityFn(MMF),
|
||||||
JITMatchQualityFn(JMF) {}
|
JITMatchQualityFn(JMF) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class RegistryTraits<TargetMachine> {
|
class RegistryTraits<TargetMachine> {
|
||||||
public:
|
public:
|
||||||
typedef TargetMachineRegistryEntry entry;
|
typedef TargetMachineRegistryEntry entry;
|
||||||
|
|
||||||
static const char *nameof(const entry &Entry) { return Entry.Name; }
|
static const char *nameof(const entry &Entry) { return Entry.Name; }
|
||||||
static const char *descof(const entry &Entry) { return Entry.ShortDesc; }
|
static const char *descof(const entry &Entry) { return Entry.ShortDesc; }
|
||||||
};
|
};
|
||||||
@ -67,12 +67,12 @@ namespace llvm {
|
|||||||
/// themselves with the tool they are linked. Targets should define an
|
/// themselves with the tool they are linked. Targets should define an
|
||||||
/// instance of this and implement the static methods described in the
|
/// instance of this and implement the static methods described in the
|
||||||
/// TargetMachine comments.
|
/// TargetMachine comments.
|
||||||
/// The type 'TargetMachineImpl' should provide a constructor with two
|
/// The type 'TargetMachineImpl' should provide a constructor with two
|
||||||
/// parameters:
|
/// parameters:
|
||||||
/// - const Module& M: the module that is being compiled:
|
/// - const Module& M: the module that is being compiled:
|
||||||
/// - const std::string& FS: target-specific string describing target
|
/// - const std::string& FS: target-specific string describing target
|
||||||
/// flavour.
|
/// flavour.
|
||||||
|
|
||||||
template<class TargetMachineImpl>
|
template<class TargetMachineImpl>
|
||||||
struct RegisterTarget {
|
struct RegisterTarget {
|
||||||
RegisterTarget(const char *Name, const char *ShortDesc)
|
RegisterTarget(const char *Name, const char *ShortDesc)
|
||||||
@ -85,7 +85,7 @@ namespace llvm {
|
|||||||
private:
|
private:
|
||||||
TargetMachineRegistry::entry Entry;
|
TargetMachineRegistry::entry Entry;
|
||||||
TargetMachineRegistry::node Node;
|
TargetMachineRegistry::node Node;
|
||||||
|
|
||||||
static TargetMachine *Allocator(const Module &M, const std::string &FS) {
|
static TargetMachine *Allocator(const Module &M, const std::string &FS) {
|
||||||
return new TargetMachineImpl(M, FS);
|
return new TargetMachineImpl(M, FS);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
// This file implements printing the assembly code for an Ocaml frametable.
|
// This file implements printing the assembly code for an Ocaml frametable.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/CodeGen/GCs.h"
|
#include "llvm/CodeGen/GCs.h"
|
||||||
#include "llvm/CodeGen/AsmPrinter.h"
|
#include "llvm/CodeGen/AsmPrinter.h"
|
||||||
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
||||||
@ -28,11 +28,11 @@ namespace {
|
|||||||
public:
|
public:
|
||||||
void beginAssembly(raw_ostream &OS, AsmPrinter &AP,
|
void beginAssembly(raw_ostream &OS, AsmPrinter &AP,
|
||||||
const TargetAsmInfo &TAI);
|
const TargetAsmInfo &TAI);
|
||||||
|
|
||||||
void finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
void finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
||||||
const TargetAsmInfo &TAI);
|
const TargetAsmInfo &TAI);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
|
static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
|
||||||
@ -43,7 +43,7 @@ void llvm::linkOcamlGCPrinter() { }
|
|||||||
static void EmitCamlGlobal(const Module &M, raw_ostream &OS, AsmPrinter &AP,
|
static void EmitCamlGlobal(const Module &M, raw_ostream &OS, AsmPrinter &AP,
|
||||||
const TargetAsmInfo &TAI, const char *Id) {
|
const TargetAsmInfo &TAI, const char *Id) {
|
||||||
const std::string &MId = M.getModuleIdentifier();
|
const std::string &MId = M.getModuleIdentifier();
|
||||||
|
|
||||||
std::string Mangled;
|
std::string Mangled;
|
||||||
Mangled += TAI.getGlobalPrefix();
|
Mangled += TAI.getGlobalPrefix();
|
||||||
Mangled += "caml";
|
Mangled += "caml";
|
||||||
@ -51,10 +51,10 @@ static void EmitCamlGlobal(const Module &M, raw_ostream &OS, AsmPrinter &AP,
|
|||||||
Mangled.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
|
Mangled.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
|
||||||
Mangled += "__";
|
Mangled += "__";
|
||||||
Mangled += Id;
|
Mangled += Id;
|
||||||
|
|
||||||
// Capitalize the first letter of the module name.
|
// Capitalize the first letter of the module name.
|
||||||
Mangled[Letter] = toupper(Mangled[Letter]);
|
Mangled[Letter] = toupper(Mangled[Letter]);
|
||||||
|
|
||||||
if (const char *GlobalDirective = TAI.getGlobalDirective())
|
if (const char *GlobalDirective = TAI.getGlobalDirective())
|
||||||
OS << GlobalDirective << Mangled << "\n";
|
OS << GlobalDirective << Mangled << "\n";
|
||||||
OS << Mangled << ":\n";
|
OS << Mangled << ":\n";
|
||||||
@ -64,13 +64,13 @@ void OcamlGCMetadataPrinter::beginAssembly(raw_ostream &OS, AsmPrinter &AP,
|
|||||||
const TargetAsmInfo &TAI) {
|
const TargetAsmInfo &TAI) {
|
||||||
AP.SwitchToSection(TAI.getTextSection());
|
AP.SwitchToSection(TAI.getTextSection());
|
||||||
EmitCamlGlobal(getModule(), OS, AP, TAI, "code_begin");
|
EmitCamlGlobal(getModule(), OS, AP, TAI, "code_begin");
|
||||||
|
|
||||||
AP.SwitchToSection(TAI.getDataSection());
|
AP.SwitchToSection(TAI.getDataSection());
|
||||||
EmitCamlGlobal(getModule(), OS, AP, TAI, "data_begin");
|
EmitCamlGlobal(getModule(), OS, AP, TAI, "data_begin");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emitAssembly - Print the frametable. The ocaml frametable format is thus:
|
/// emitAssembly - Print the frametable. The ocaml frametable format is thus:
|
||||||
///
|
///
|
||||||
/// extern "C" struct align(sizeof(intptr_t)) {
|
/// extern "C" struct align(sizeof(intptr_t)) {
|
||||||
/// uint16_t NumDescriptors;
|
/// uint16_t NumDescriptors;
|
||||||
/// struct align(sizeof(intptr_t)) {
|
/// struct align(sizeof(intptr_t)) {
|
||||||
@ -80,11 +80,11 @@ void OcamlGCMetadataPrinter::beginAssembly(raw_ostream &OS, AsmPrinter &AP,
|
|||||||
/// uint16_t LiveOffsets[NumLiveOffsets];
|
/// uint16_t LiveOffsets[NumLiveOffsets];
|
||||||
/// } Descriptors[NumDescriptors];
|
/// } Descriptors[NumDescriptors];
|
||||||
/// } caml${module}__frametable;
|
/// } caml${module}__frametable;
|
||||||
///
|
///
|
||||||
/// Note that this precludes programs from stack frames larger than 64K
|
/// Note that this precludes programs from stack frames larger than 64K
|
||||||
/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
|
/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
|
||||||
/// either condition is detected in a function which uses the GC.
|
/// either condition is detected in a function which uses the GC.
|
||||||
///
|
///
|
||||||
void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
||||||
const TargetAsmInfo &TAI) {
|
const TargetAsmInfo &TAI) {
|
||||||
const char *AddressDirective;
|
const char *AddressDirective;
|
||||||
@ -99,19 +99,19 @@ void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
|||||||
|
|
||||||
AP.SwitchToSection(TAI.getTextSection());
|
AP.SwitchToSection(TAI.getTextSection());
|
||||||
EmitCamlGlobal(getModule(), OS, AP, TAI, "code_end");
|
EmitCamlGlobal(getModule(), OS, AP, TAI, "code_end");
|
||||||
|
|
||||||
AP.SwitchToSection(TAI.getDataSection());
|
AP.SwitchToSection(TAI.getDataSection());
|
||||||
EmitCamlGlobal(getModule(), OS, AP, TAI, "data_end");
|
EmitCamlGlobal(getModule(), OS, AP, TAI, "data_end");
|
||||||
|
|
||||||
OS << AddressDirective << 0; // FIXME: Why does ocaml emit this??
|
OS << AddressDirective << 0; // FIXME: Why does ocaml emit this??
|
||||||
AP.EOL();
|
AP.EOL();
|
||||||
|
|
||||||
AP.SwitchToSection(TAI.getDataSection());
|
AP.SwitchToSection(TAI.getDataSection());
|
||||||
EmitCamlGlobal(getModule(), OS, AP, TAI, "frametable");
|
EmitCamlGlobal(getModule(), OS, AP, TAI, "frametable");
|
||||||
|
|
||||||
for (iterator I = begin(), IE = end(); I != IE; ++I) {
|
for (iterator I = begin(), IE = end(); I != IE; ++I) {
|
||||||
GCFunctionInfo &FI = **I;
|
GCFunctionInfo &FI = **I;
|
||||||
|
|
||||||
uint64_t FrameSize = FI.getFrameSize();
|
uint64_t FrameSize = FI.getFrameSize();
|
||||||
if (FrameSize >= 1<<16) {
|
if (FrameSize >= 1<<16) {
|
||||||
cerr << "Function '" << FI.getFunction().getNameStart()
|
cerr << "Function '" << FI.getFunction().getNameStart()
|
||||||
@ -120,10 +120,10 @@ void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
|||||||
cerr << "(" << uintptr_t(&FI) << ")\n";
|
cerr << "(" << uintptr_t(&FI) << ")\n";
|
||||||
abort(); // Very rude!
|
abort(); // Very rude!
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << "\t" << TAI.getCommentString() << " live roots for "
|
OS << "\t" << TAI.getCommentString() << " live roots for "
|
||||||
<< FI.getFunction().getNameStart() << "\n";
|
<< FI.getFunction().getNameStart() << "\n";
|
||||||
|
|
||||||
for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
|
for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
|
||||||
size_t LiveCount = FI.live_size(J);
|
size_t LiveCount = FI.live_size(J);
|
||||||
if (LiveCount >= 1<<16) {
|
if (LiveCount >= 1<<16) {
|
||||||
@ -132,27 +132,27 @@ void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP,
|
|||||||
<< "Live root count " << LiveCount << " >= 65536.\n";
|
<< "Live root count " << LiveCount << " >= 65536.\n";
|
||||||
abort(); // Very rude!
|
abort(); // Very rude!
|
||||||
}
|
}
|
||||||
|
|
||||||
OS << AddressDirective
|
OS << AddressDirective
|
||||||
<< TAI.getPrivateGlobalPrefix() << "label" << J->Num;
|
<< TAI.getPrivateGlobalPrefix() << "label" << J->Num;
|
||||||
AP.EOL("call return address");
|
AP.EOL("call return address");
|
||||||
|
|
||||||
AP.EmitInt16(FrameSize);
|
AP.EmitInt16(FrameSize);
|
||||||
AP.EOL("stack frame size");
|
AP.EOL("stack frame size");
|
||||||
|
|
||||||
AP.EmitInt16(LiveCount);
|
AP.EmitInt16(LiveCount);
|
||||||
AP.EOL("live root count");
|
AP.EOL("live root count");
|
||||||
|
|
||||||
for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
|
for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
|
||||||
KE = FI.live_end(J); K != KE; ++K) {
|
KE = FI.live_end(J); K != KE; ++K) {
|
||||||
assert(K->StackOffset < 1<<16 &&
|
assert(K->StackOffset < 1<<16 &&
|
||||||
"GC root stack offset is outside of fixed stack frame and out "
|
"GC root stack offset is outside of fixed stack frame and out "
|
||||||
"of range for ocaml GC!");
|
"of range for ocaml GC!");
|
||||||
|
|
||||||
OS << "\t.word\t" << K->StackOffset;
|
OS << "\t.word\t" << K->StackOffset;
|
||||||
AP.EOL("stack offset");
|
AP.EOL("stack offset");
|
||||||
}
|
}
|
||||||
|
|
||||||
AP.EmitAlignment(AddressAlignLog);
|
AP.EmitAlignment(AddressAlignLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
//
|
//
|
||||||
// This file implements lowering for the llvm.gc* intrinsics compatible with
|
// This file implements lowering for the llvm.gc* intrinsics compatible with
|
||||||
// Objective Caml 3.10.0, which uses a liveness-accurate static stack map.
|
// Objective Caml 3.10.0, which uses a liveness-accurate static stack map.
|
||||||
//
|
//
|
||||||
// The frametable emitter is in OcamlGCPrinter.cpp.
|
// The frametable emitter is in OcamlGCPrinter.cpp.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/CodeGen/GCs.h"
|
#include "llvm/CodeGen/GCs.h"
|
||||||
#include "llvm/CodeGen/GCStrategy.h"
|
#include "llvm/CodeGen/GCStrategy.h"
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -36,26 +36,26 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class VISIBILITY_HIDDEN ShadowStackGC : public GCStrategy {
|
class VISIBILITY_HIDDEN ShadowStackGC : public GCStrategy {
|
||||||
/// RootChain - This is the global linked-list that contains the chain of GC
|
/// RootChain - This is the global linked-list that contains the chain of GC
|
||||||
/// roots.
|
/// roots.
|
||||||
GlobalVariable *Head;
|
GlobalVariable *Head;
|
||||||
|
|
||||||
/// StackEntryTy - Abstract type of a link in the shadow stack.
|
/// StackEntryTy - Abstract type of a link in the shadow stack.
|
||||||
///
|
///
|
||||||
const StructType *StackEntryTy;
|
const StructType *StackEntryTy;
|
||||||
|
|
||||||
/// Roots - GC roots in the current function. Each is a pair of the
|
/// Roots - GC roots in the current function. Each is a pair of the
|
||||||
/// intrinsic call and its corresponding alloca.
|
/// intrinsic call and its corresponding alloca.
|
||||||
std::vector<std::pair<CallInst*,AllocaInst*> > Roots;
|
std::vector<std::pair<CallInst*,AllocaInst*> > Roots;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ShadowStackGC();
|
ShadowStackGC();
|
||||||
|
|
||||||
bool initializeCustomLowering(Module &M);
|
bool initializeCustomLowering(Module &M);
|
||||||
bool performCustomLowering(Function &F);
|
bool performCustomLowering(Function &F);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsNullValue(Value *V);
|
bool IsNullValue(Value *V);
|
||||||
Constant *GetFrameMap(Function &F);
|
Constant *GetFrameMap(Function &F);
|
||||||
@ -68,58 +68,58 @@ namespace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GCRegistry::Add<ShadowStackGC>
|
static GCRegistry::Add<ShadowStackGC>
|
||||||
X("shadow-stack", "Very portable GC for uncooperative code generators");
|
X("shadow-stack", "Very portable GC for uncooperative code generators");
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// EscapeEnumerator - This is a little algorithm to find all escape points
|
/// EscapeEnumerator - This is a little algorithm to find all escape points
|
||||||
/// from a function so that "finally"-style code can be inserted. In addition
|
/// from a function so that "finally"-style code can be inserted. In addition
|
||||||
/// to finding the existing return and unwind instructions, it also (if
|
/// to finding the existing return and unwind instructions, it also (if
|
||||||
/// necessary) transforms any call instructions into invokes and sends them to
|
/// necessary) transforms any call instructions into invokes and sends them to
|
||||||
/// a landing pad.
|
/// a landing pad.
|
||||||
///
|
///
|
||||||
/// It's wrapped up in a state machine using the same transform C# uses for
|
/// It's wrapped up in a state machine using the same transform C# uses for
|
||||||
/// 'yield return' enumerators, This transform allows it to be non-allocating.
|
/// 'yield return' enumerators, This transform allows it to be non-allocating.
|
||||||
class VISIBILITY_HIDDEN EscapeEnumerator {
|
class VISIBILITY_HIDDEN EscapeEnumerator {
|
||||||
Function &F;
|
Function &F;
|
||||||
const char *CleanupBBName;
|
const char *CleanupBBName;
|
||||||
|
|
||||||
// State.
|
// State.
|
||||||
int State;
|
int State;
|
||||||
Function::iterator StateBB, StateE;
|
Function::iterator StateBB, StateE;
|
||||||
IRBuilder<> Builder;
|
IRBuilder<> Builder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EscapeEnumerator(Function &F, const char *N = "cleanup")
|
EscapeEnumerator(Function &F, const char *N = "cleanup")
|
||||||
: F(F), CleanupBBName(N), State(0) {}
|
: F(F), CleanupBBName(N), State(0) {}
|
||||||
|
|
||||||
IRBuilder<> *Next() {
|
IRBuilder<> *Next() {
|
||||||
switch (State) {
|
switch (State) {
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
StateBB = F.begin();
|
StateBB = F.begin();
|
||||||
StateE = F.end();
|
StateE = F.end();
|
||||||
State = 1;
|
State = 1;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// Find all 'return' and 'unwind' instructions.
|
// Find all 'return' and 'unwind' instructions.
|
||||||
while (StateBB != StateE) {
|
while (StateBB != StateE) {
|
||||||
BasicBlock *CurBB = StateBB++;
|
BasicBlock *CurBB = StateBB++;
|
||||||
|
|
||||||
// Branches and invokes do not escape, only unwind and return do.
|
// Branches and invokes do not escape, only unwind and return do.
|
||||||
TerminatorInst *TI = CurBB->getTerminator();
|
TerminatorInst *TI = CurBB->getTerminator();
|
||||||
if (!isa<UnwindInst>(TI) && !isa<ReturnInst>(TI))
|
if (!isa<UnwindInst>(TI) && !isa<ReturnInst>(TI))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Builder.SetInsertPoint(TI->getParent(), TI);
|
Builder.SetInsertPoint(TI->getParent(), TI);
|
||||||
return &Builder;
|
return &Builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
State = 2;
|
State = 2;
|
||||||
|
|
||||||
// Find all 'call' instructions.
|
// Find all 'call' instructions.
|
||||||
SmallVector<Instruction*,16> Calls;
|
SmallVector<Instruction*,16> Calls;
|
||||||
for (Function::iterator BB = F.begin(),
|
for (Function::iterator BB = F.begin(),
|
||||||
@ -130,33 +130,33 @@ namespace {
|
|||||||
if (!CI->getCalledFunction() ||
|
if (!CI->getCalledFunction() ||
|
||||||
!CI->getCalledFunction()->getIntrinsicID())
|
!CI->getCalledFunction()->getIntrinsicID())
|
||||||
Calls.push_back(CI);
|
Calls.push_back(CI);
|
||||||
|
|
||||||
if (Calls.empty())
|
if (Calls.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Create a cleanup block.
|
// Create a cleanup block.
|
||||||
BasicBlock *CleanupBB = BasicBlock::Create(CleanupBBName, &F);
|
BasicBlock *CleanupBB = BasicBlock::Create(CleanupBBName, &F);
|
||||||
UnwindInst *UI = new UnwindInst(CleanupBB);
|
UnwindInst *UI = new UnwindInst(CleanupBB);
|
||||||
|
|
||||||
// Transform the 'call' instructions into 'invoke's branching to the
|
// Transform the 'call' instructions into 'invoke's branching to the
|
||||||
// cleanup block. Go in reverse order to make prettier BB names.
|
// cleanup block. Go in reverse order to make prettier BB names.
|
||||||
SmallVector<Value*,16> Args;
|
SmallVector<Value*,16> Args;
|
||||||
for (unsigned I = Calls.size(); I != 0; ) {
|
for (unsigned I = Calls.size(); I != 0; ) {
|
||||||
CallInst *CI = cast<CallInst>(Calls[--I]);
|
CallInst *CI = cast<CallInst>(Calls[--I]);
|
||||||
|
|
||||||
// Split the basic block containing the function call.
|
// Split the basic block containing the function call.
|
||||||
BasicBlock *CallBB = CI->getParent();
|
BasicBlock *CallBB = CI->getParent();
|
||||||
BasicBlock *NewBB =
|
BasicBlock *NewBB =
|
||||||
CallBB->splitBasicBlock(CI, CallBB->getName() + ".cont");
|
CallBB->splitBasicBlock(CI, CallBB->getName() + ".cont");
|
||||||
|
|
||||||
// Remove the unconditional branch inserted at the end of CallBB.
|
// Remove the unconditional branch inserted at the end of CallBB.
|
||||||
CallBB->getInstList().pop_back();
|
CallBB->getInstList().pop_back();
|
||||||
NewBB->getInstList().remove(CI);
|
NewBB->getInstList().remove(CI);
|
||||||
|
|
||||||
// Create a new invoke instruction.
|
// Create a new invoke instruction.
|
||||||
Args.clear();
|
Args.clear();
|
||||||
Args.append(CI->op_begin() + 1, CI->op_end());
|
Args.append(CI->op_begin() + 1, CI->op_end());
|
||||||
|
|
||||||
InvokeInst *II = InvokeInst::Create(CI->getOperand(0),
|
InvokeInst *II = InvokeInst::Create(CI->getOperand(0),
|
||||||
NewBB, CleanupBB,
|
NewBB, CleanupBB,
|
||||||
Args.begin(), Args.end(),
|
Args.begin(), Args.end(),
|
||||||
@ -166,7 +166,7 @@ namespace {
|
|||||||
CI->replaceAllUsesWith(II);
|
CI->replaceAllUsesWith(II);
|
||||||
delete CI;
|
delete CI;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder.SetInsertPoint(UI->getParent(), UI);
|
Builder.SetInsertPoint(UI->getParent(), UI);
|
||||||
return &Builder;
|
return &Builder;
|
||||||
}
|
}
|
||||||
@ -185,9 +185,9 @@ ShadowStackGC::ShadowStackGC() : Head(0), StackEntryTy(0) {
|
|||||||
|
|
||||||
Constant *ShadowStackGC::GetFrameMap(Function &F) {
|
Constant *ShadowStackGC::GetFrameMap(Function &F) {
|
||||||
// doInitialization creates the abstract type of this value.
|
// doInitialization creates the abstract type of this value.
|
||||||
|
|
||||||
Type *VoidPtr = PointerType::getUnqual(Type::Int8Ty);
|
Type *VoidPtr = PointerType::getUnqual(Type::Int8Ty);
|
||||||
|
|
||||||
// Truncate the ShadowStackDescriptor if some metadata is null.
|
// Truncate the ShadowStackDescriptor if some metadata is null.
|
||||||
unsigned NumMeta = 0;
|
unsigned NumMeta = 0;
|
||||||
SmallVector<Constant*,16> Metadata;
|
SmallVector<Constant*,16> Metadata;
|
||||||
@ -197,33 +197,33 @@ Constant *ShadowStackGC::GetFrameMap(Function &F) {
|
|||||||
NumMeta = I + 1;
|
NumMeta = I + 1;
|
||||||
Metadata.push_back(ConstantExpr::getBitCast(C, VoidPtr));
|
Metadata.push_back(ConstantExpr::getBitCast(C, VoidPtr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Constant *BaseElts[] = {
|
Constant *BaseElts[] = {
|
||||||
ConstantInt::get(Type::Int32Ty, Roots.size(), false),
|
ConstantInt::get(Type::Int32Ty, Roots.size(), false),
|
||||||
ConstantInt::get(Type::Int32Ty, NumMeta, false),
|
ConstantInt::get(Type::Int32Ty, NumMeta, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
Constant *DescriptorElts[] = {
|
Constant *DescriptorElts[] = {
|
||||||
ConstantStruct::get(BaseElts, 2),
|
ConstantStruct::get(BaseElts, 2),
|
||||||
ConstantArray::get(ArrayType::get(VoidPtr, NumMeta),
|
ConstantArray::get(ArrayType::get(VoidPtr, NumMeta),
|
||||||
Metadata.begin(), NumMeta)
|
Metadata.begin(), NumMeta)
|
||||||
};
|
};
|
||||||
|
|
||||||
Constant *FrameMap = ConstantStruct::get(DescriptorElts, 2);
|
Constant *FrameMap = ConstantStruct::get(DescriptorElts, 2);
|
||||||
|
|
||||||
std::string TypeName("gc_map.");
|
std::string TypeName("gc_map.");
|
||||||
TypeName += utostr(NumMeta);
|
TypeName += utostr(NumMeta);
|
||||||
F.getParent()->addTypeName(TypeName, FrameMap->getType());
|
F.getParent()->addTypeName(TypeName, FrameMap->getType());
|
||||||
|
|
||||||
// FIXME: Is this actually dangerous as WritingAnLLVMPass.html claims? Seems
|
// FIXME: Is this actually dangerous as WritingAnLLVMPass.html claims? Seems
|
||||||
// that, short of multithreaded LLVM, it should be safe; all that is
|
// that, short of multithreaded LLVM, it should be safe; all that is
|
||||||
// necessary is that a simple Module::iterator loop not be invalidated.
|
// necessary is that a simple Module::iterator loop not be invalidated.
|
||||||
// Appending to the GlobalVariable list is safe in that sense.
|
// Appending to the GlobalVariable list is safe in that sense.
|
||||||
//
|
//
|
||||||
// All of the output passes emit globals last. The ExecutionEngine
|
// All of the output passes emit globals last. The ExecutionEngine
|
||||||
// explicitly supports adding globals to the module after
|
// explicitly supports adding globals to the module after
|
||||||
// initialization.
|
// initialization.
|
||||||
//
|
//
|
||||||
// Still, if it isn't deemed acceptable, then this transformation needs
|
// Still, if it isn't deemed acceptable, then this transformation needs
|
||||||
// to be a ModulePass (which means it cannot be in the 'llc' pipeline
|
// to be a ModulePass (which means it cannot be in the 'llc' pipeline
|
||||||
// (which uses a FunctionPassManager (which segfaults (not asserts) if
|
// (which uses a FunctionPassManager (which segfaults (not asserts) if
|
||||||
@ -232,7 +232,7 @@ Constant *ShadowStackGC::GetFrameMap(Function &F) {
|
|||||||
GlobalVariable::InternalLinkage,
|
GlobalVariable::InternalLinkage,
|
||||||
FrameMap, "__gc_" + F.getName(),
|
FrameMap, "__gc_" + F.getName(),
|
||||||
F.getParent());
|
F.getParent());
|
||||||
|
|
||||||
Constant *GEPIndices[2] = { ConstantInt::get(Type::Int32Ty, 0),
|
Constant *GEPIndices[2] = { ConstantInt::get(Type::Int32Ty, 0),
|
||||||
ConstantInt::get(Type::Int32Ty, 0) };
|
ConstantInt::get(Type::Int32Ty, 0) };
|
||||||
return ConstantExpr::getGetElementPtr(GV, GEPIndices, 2);
|
return ConstantExpr::getGetElementPtr(GV, GEPIndices, 2);
|
||||||
@ -245,11 +245,11 @@ const Type* ShadowStackGC::GetConcreteStackEntryType(Function &F) {
|
|||||||
for (size_t I = 0; I != Roots.size(); I++)
|
for (size_t I = 0; I != Roots.size(); I++)
|
||||||
EltTys.push_back(Roots[I].second->getAllocatedType());
|
EltTys.push_back(Roots[I].second->getAllocatedType());
|
||||||
Type *Ty = StructType::get(EltTys);
|
Type *Ty = StructType::get(EltTys);
|
||||||
|
|
||||||
std::string TypeName("gc_stackentry.");
|
std::string TypeName("gc_stackentry.");
|
||||||
TypeName += F.getName();
|
TypeName += F.getName();
|
||||||
F.getParent()->addTypeName(TypeName, Ty);
|
F.getParent()->addTypeName(TypeName, Ty);
|
||||||
|
|
||||||
return Ty;
|
return Ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,25 +267,25 @@ bool ShadowStackGC::initializeCustomLowering(Module &M) {
|
|||||||
StructType *FrameMapTy = StructType::get(EltTys);
|
StructType *FrameMapTy = StructType::get(EltTys);
|
||||||
M.addTypeName("gc_map", FrameMapTy);
|
M.addTypeName("gc_map", FrameMapTy);
|
||||||
PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
|
PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
|
||||||
|
|
||||||
// struct StackEntry {
|
// struct StackEntry {
|
||||||
// ShadowStackEntry *Next; // Caller's stack entry.
|
// ShadowStackEntry *Next; // Caller's stack entry.
|
||||||
// FrameMap *Map; // Pointer to constant FrameMap.
|
// FrameMap *Map; // Pointer to constant FrameMap.
|
||||||
// void *Roots[]; // Stack roots (in-place array, so we pretend).
|
// void *Roots[]; // Stack roots (in-place array, so we pretend).
|
||||||
// };
|
// };
|
||||||
OpaqueType *RecursiveTy = OpaqueType::get();
|
OpaqueType *RecursiveTy = OpaqueType::get();
|
||||||
|
|
||||||
EltTys.clear();
|
EltTys.clear();
|
||||||
EltTys.push_back(PointerType::getUnqual(RecursiveTy));
|
EltTys.push_back(PointerType::getUnqual(RecursiveTy));
|
||||||
EltTys.push_back(FrameMapPtrTy);
|
EltTys.push_back(FrameMapPtrTy);
|
||||||
PATypeHolder LinkTyH = StructType::get(EltTys);
|
PATypeHolder LinkTyH = StructType::get(EltTys);
|
||||||
|
|
||||||
RecursiveTy->refineAbstractTypeTo(LinkTyH.get());
|
RecursiveTy->refineAbstractTypeTo(LinkTyH.get());
|
||||||
StackEntryTy = cast<StructType>(LinkTyH.get());
|
StackEntryTy = cast<StructType>(LinkTyH.get());
|
||||||
const PointerType *StackEntryPtrTy = PointerType::getUnqual(StackEntryTy);
|
const PointerType *StackEntryPtrTy = PointerType::getUnqual(StackEntryTy);
|
||||||
M.addTypeName("gc_stackentry", LinkTyH.get()); // FIXME: Is this safe from
|
M.addTypeName("gc_stackentry", LinkTyH.get()); // FIXME: Is this safe from
|
||||||
// a FunctionPass?
|
// a FunctionPass?
|
||||||
|
|
||||||
// Get the root chain if it already exists.
|
// Get the root chain if it already exists.
|
||||||
Head = M.getGlobalVariable("llvm_gc_root_chain");
|
Head = M.getGlobalVariable("llvm_gc_root_chain");
|
||||||
if (!Head) {
|
if (!Head) {
|
||||||
@ -299,7 +299,7 @@ bool ShadowStackGC::initializeCustomLowering(Module &M) {
|
|||||||
Head->setInitializer(Constant::getNullValue(StackEntryPtrTy));
|
Head->setInitializer(Constant::getNullValue(StackEntryPtrTy));
|
||||||
Head->setLinkage(GlobalValue::LinkOnceLinkage);
|
Head->setLinkage(GlobalValue::LinkOnceLinkage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,11 +313,11 @@ void ShadowStackGC::CollectRoots(Function &F) {
|
|||||||
// FIXME: Account for original alignment. Could fragment the root array.
|
// FIXME: Account for original alignment. Could fragment the root array.
|
||||||
// Approach 1: Null initialize empty slots at runtime. Yuck.
|
// Approach 1: Null initialize empty slots at runtime. Yuck.
|
||||||
// Approach 2: Emit a map of the array instead of just a count.
|
// Approach 2: Emit a map of the array instead of just a count.
|
||||||
|
|
||||||
assert(Roots.empty() && "Not cleaned up?");
|
assert(Roots.empty() && "Not cleaned up?");
|
||||||
|
|
||||||
SmallVector<std::pair<CallInst*,AllocaInst*>,16> MetaRoots;
|
SmallVector<std::pair<CallInst*,AllocaInst*>,16> MetaRoots;
|
||||||
|
|
||||||
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
||||||
for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;)
|
for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;)
|
||||||
if (IntrinsicInst *CI = dyn_cast<IntrinsicInst>(II++))
|
if (IntrinsicInst *CI = dyn_cast<IntrinsicInst>(II++))
|
||||||
@ -330,7 +330,7 @@ void ShadowStackGC::CollectRoots(Function &F) {
|
|||||||
else
|
else
|
||||||
MetaRoots.push_back(Pair);
|
MetaRoots.push_back(Pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number roots with metadata (usually empty) at the beginning, so that the
|
// Number roots with metadata (usually empty) at the beginning, so that the
|
||||||
// FrameMap::Meta array can be elided.
|
// FrameMap::Meta array can be elided.
|
||||||
Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());
|
Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());
|
||||||
@ -343,9 +343,9 @@ ShadowStackGC::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
|||||||
ConstantInt::get(Type::Int32Ty, Idx),
|
ConstantInt::get(Type::Int32Ty, Idx),
|
||||||
ConstantInt::get(Type::Int32Ty, Idx2) };
|
ConstantInt::get(Type::Int32Ty, Idx2) };
|
||||||
Value* Val = B.CreateGEP(BasePtr, Indices, Indices + 3, Name);
|
Value* Val = B.CreateGEP(BasePtr, Indices, Indices + 3, Name);
|
||||||
|
|
||||||
assert(isa<GetElementPtrInst>(Val) && "Unexpected folded constant");
|
assert(isa<GetElementPtrInst>(Val) && "Unexpected folded constant");
|
||||||
|
|
||||||
return dyn_cast<GetElementPtrInst>(Val);
|
return dyn_cast<GetElementPtrInst>(Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +355,7 @@ ShadowStackGC::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
|||||||
Value *Indices[] = { ConstantInt::get(Type::Int32Ty, 0),
|
Value *Indices[] = { ConstantInt::get(Type::Int32Ty, 0),
|
||||||
ConstantInt::get(Type::Int32Ty, Idx) };
|
ConstantInt::get(Type::Int32Ty, Idx) };
|
||||||
Value *Val = B.CreateGEP(BasePtr, Indices, Indices + 2, Name);
|
Value *Val = B.CreateGEP(BasePtr, Indices, Indices + 2, Name);
|
||||||
|
|
||||||
assert(isa<GetElementPtrInst>(Val) && "Unexpected folded constant");
|
assert(isa<GetElementPtrInst>(Val) && "Unexpected folded constant");
|
||||||
|
|
||||||
return dyn_cast<GetElementPtrInst>(Val);
|
return dyn_cast<GetElementPtrInst>(Val);
|
||||||
@ -365,55 +365,55 @@ ShadowStackGC::CreateGEP(IRBuilder<> &B, Value *BasePtr,
|
|||||||
bool ShadowStackGC::performCustomLowering(Function &F) {
|
bool ShadowStackGC::performCustomLowering(Function &F) {
|
||||||
// Find calls to llvm.gcroot.
|
// Find calls to llvm.gcroot.
|
||||||
CollectRoots(F);
|
CollectRoots(F);
|
||||||
|
|
||||||
// If there are no roots in this function, then there is no need to add a
|
// If there are no roots in this function, then there is no need to add a
|
||||||
// stack map entry for it.
|
// stack map entry for it.
|
||||||
if (Roots.empty())
|
if (Roots.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Build the constant map and figure the type of the shadow stack entry.
|
// Build the constant map and figure the type of the shadow stack entry.
|
||||||
Value *FrameMap = GetFrameMap(F);
|
Value *FrameMap = GetFrameMap(F);
|
||||||
const Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);
|
const Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);
|
||||||
|
|
||||||
// Build the shadow stack entry at the very start of the function.
|
// Build the shadow stack entry at the very start of the function.
|
||||||
BasicBlock::iterator IP = F.getEntryBlock().begin();
|
BasicBlock::iterator IP = F.getEntryBlock().begin();
|
||||||
IRBuilder<> AtEntry(IP->getParent(), IP);
|
IRBuilder<> AtEntry(IP->getParent(), IP);
|
||||||
|
|
||||||
Instruction *StackEntry = AtEntry.CreateAlloca(ConcreteStackEntryTy, 0,
|
Instruction *StackEntry = AtEntry.CreateAlloca(ConcreteStackEntryTy, 0,
|
||||||
"gc_frame");
|
"gc_frame");
|
||||||
|
|
||||||
while (isa<AllocaInst>(IP)) ++IP;
|
while (isa<AllocaInst>(IP)) ++IP;
|
||||||
AtEntry.SetInsertPoint(IP->getParent(), IP);
|
AtEntry.SetInsertPoint(IP->getParent(), IP);
|
||||||
|
|
||||||
// Initialize the map pointer and load the current head of the shadow stack.
|
// Initialize the map pointer and load the current head of the shadow stack.
|
||||||
Instruction *CurrentHead = AtEntry.CreateLoad(Head, "gc_currhead");
|
Instruction *CurrentHead = AtEntry.CreateLoad(Head, "gc_currhead");
|
||||||
Instruction *EntryMapPtr = CreateGEP(AtEntry, StackEntry,0,1,"gc_frame.map");
|
Instruction *EntryMapPtr = CreateGEP(AtEntry, StackEntry,0,1,"gc_frame.map");
|
||||||
AtEntry.CreateStore(FrameMap, EntryMapPtr);
|
AtEntry.CreateStore(FrameMap, EntryMapPtr);
|
||||||
|
|
||||||
// After all the allocas...
|
// After all the allocas...
|
||||||
for (unsigned I = 0, E = Roots.size(); I != E; ++I) {
|
for (unsigned I = 0, E = Roots.size(); I != E; ++I) {
|
||||||
// For each root, find the corresponding slot in the aggregate...
|
// For each root, find the corresponding slot in the aggregate...
|
||||||
Value *SlotPtr = CreateGEP(AtEntry, StackEntry, 1 + I, "gc_root");
|
Value *SlotPtr = CreateGEP(AtEntry, StackEntry, 1 + I, "gc_root");
|
||||||
|
|
||||||
// And use it in lieu of the alloca.
|
// And use it in lieu of the alloca.
|
||||||
AllocaInst *OriginalAlloca = Roots[I].second;
|
AllocaInst *OriginalAlloca = Roots[I].second;
|
||||||
SlotPtr->takeName(OriginalAlloca);
|
SlotPtr->takeName(OriginalAlloca);
|
||||||
OriginalAlloca->replaceAllUsesWith(SlotPtr);
|
OriginalAlloca->replaceAllUsesWith(SlotPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move past the original stores inserted by GCStrategy::InitRoots. This isn't
|
// Move past the original stores inserted by GCStrategy::InitRoots. This isn't
|
||||||
// really necessary (the collector would never see the intermediate state at
|
// 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
|
// runtime), but it's nicer not to push the half-initialized entry onto the
|
||||||
// shadow stack.
|
// shadow stack.
|
||||||
while (isa<StoreInst>(IP)) ++IP;
|
while (isa<StoreInst>(IP)) ++IP;
|
||||||
AtEntry.SetInsertPoint(IP->getParent(), IP);
|
AtEntry.SetInsertPoint(IP->getParent(), IP);
|
||||||
|
|
||||||
// Push the entry onto the shadow stack.
|
// Push the entry onto the shadow stack.
|
||||||
Instruction *EntryNextPtr = CreateGEP(AtEntry,StackEntry,0,0,"gc_frame.next");
|
Instruction *EntryNextPtr = CreateGEP(AtEntry,StackEntry,0,0,"gc_frame.next");
|
||||||
Instruction *NewHeadVal = CreateGEP(AtEntry,StackEntry, 0, "gc_newhead");
|
Instruction *NewHeadVal = CreateGEP(AtEntry,StackEntry, 0, "gc_newhead");
|
||||||
AtEntry.CreateStore(CurrentHead, EntryNextPtr);
|
AtEntry.CreateStore(CurrentHead, EntryNextPtr);
|
||||||
AtEntry.CreateStore(NewHeadVal, Head);
|
AtEntry.CreateStore(NewHeadVal, Head);
|
||||||
|
|
||||||
// For each instruction that escapes...
|
// For each instruction that escapes...
|
||||||
EscapeEnumerator EE(F, "gc_cleanup");
|
EscapeEnumerator EE(F, "gc_cleanup");
|
||||||
while (IRBuilder<> *AtExit = EE.Next()) {
|
while (IRBuilder<> *AtExit = EE.Next()) {
|
||||||
@ -424,7 +424,7 @@ bool ShadowStackGC::performCustomLowering(Function &F) {
|
|||||||
Value *SavedHead = AtExit->CreateLoad(EntryNextPtr2, "gc_savedhead");
|
Value *SavedHead = AtExit->CreateLoad(EntryNextPtr2, "gc_savedhead");
|
||||||
AtExit->CreateStore(SavedHead, Head);
|
AtExit->CreateStore(SavedHead, Head);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the original allocas (which are no longer used) and the intrinsic
|
// Delete the original allocas (which are no longer used) and the intrinsic
|
||||||
// calls (which are no longer valid). Doing this last avoids invalidating
|
// calls (which are no longer valid). Doing this last avoids invalidating
|
||||||
// iterators.
|
// iterators.
|
||||||
@ -432,7 +432,7 @@ bool ShadowStackGC::performCustomLowering(Function &F) {
|
|||||||
Roots[I].first->eraseFromParent();
|
Roots[I].first->eraseFromParent();
|
||||||
Roots[I].second->eraseFromParent();
|
Roots[I].second->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
Roots.clear();
|
Roots.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,13 @@ static cl::opt<const TargetMachineRegistry::entry*, false,
|
|||||||
MArch("march", cl::desc("Architecture to generate assembly for:"));
|
MArch("march", cl::desc("Architecture to generate assembly for:"));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
MCPU("mcpu",
|
MCPU("mcpu",
|
||||||
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
||||||
cl::value_desc("cpu-name"),
|
cl::value_desc("cpu-name"),
|
||||||
cl::init(""));
|
cl::init(""));
|
||||||
|
|
||||||
static cl::list<std::string>
|
static cl::list<std::string>
|
||||||
MAttrs("mattr",
|
MAttrs("mattr",
|
||||||
cl::CommaSeparated,
|
cl::CommaSeparated,
|
||||||
cl::desc("Target specific attributes (-mattr=help for details)"),
|
cl::desc("Target specific attributes (-mattr=help for details)"),
|
||||||
cl::value_desc("a1,+a2,-a3,..."));
|
cl::value_desc("a1,+a2,-a3,..."));
|
||||||
|
@ -53,7 +53,7 @@ OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
|
|||||||
|
|
||||||
static cl::opt<bool> Force("f", cl::desc("Overwrite output files"));
|
static cl::opt<bool> Force("f", cl::desc("Overwrite output files"));
|
||||||
|
|
||||||
static cl::opt<bool> Fast("fast",
|
static cl::opt<bool> Fast("fast",
|
||||||
cl::desc("Generate code quickly, potentially sacrificing code quality"));
|
cl::desc("Generate code quickly, potentially sacrificing code quality"));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
@ -64,13 +64,13 @@ static cl::opt<const TargetMachineRegistry::entry*, false,
|
|||||||
MArch("march", cl::desc("Architecture to generate code for:"));
|
MArch("march", cl::desc("Architecture to generate code for:"));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
MCPU("mcpu",
|
MCPU("mcpu",
|
||||||
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
||||||
cl::value_desc("cpu-name"),
|
cl::value_desc("cpu-name"),
|
||||||
cl::init(""));
|
cl::init(""));
|
||||||
|
|
||||||
static cl::list<std::string>
|
static cl::list<std::string>
|
||||||
MAttrs("mattr",
|
MAttrs("mattr",
|
||||||
cl::CommaSeparated,
|
cl::CommaSeparated,
|
||||||
cl::desc("Target specific attributes (-mattr=help for details)"),
|
cl::desc("Target specific attributes (-mattr=help for details)"),
|
||||||
cl::value_desc("a1,+a2,-a3,..."));
|
cl::value_desc("a1,+a2,-a3,..."));
|
||||||
@ -134,14 +134,14 @@ static raw_ostream *GetOutputStream(const char *ProgName) {
|
|||||||
|
|
||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InputFilename == "-") {
|
if (InputFilename == "-") {
|
||||||
OutputFilename = "-";
|
OutputFilename = "-";
|
||||||
return &outs();
|
return &outs();
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputFilename = GetFileNameRoot(InputFilename);
|
OutputFilename = GetFileNameRoot(InputFilename);
|
||||||
|
|
||||||
bool Binary = false;
|
bool Binary = false;
|
||||||
switch (FileType) {
|
switch (FileType) {
|
||||||
case TargetMachine::AssemblyFile:
|
case TargetMachine::AssemblyFile:
|
||||||
@ -164,7 +164,7 @@ static raw_ostream *GetOutputStream(const char *ProgName) {
|
|||||||
Binary = true;
|
Binary = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Force && std::ifstream(OutputFilename.c_str())) {
|
if (!Force && std::ifstream(OutputFilename.c_str())) {
|
||||||
// If force is not specified, make sure not to overwrite a file!
|
// If force is not specified, make sure not to overwrite a file!
|
||||||
std::cerr << ProgName << ": error opening '" << OutputFilename
|
std::cerr << ProgName << ": error opening '" << OutputFilename
|
||||||
@ -172,11 +172,11 @@ static raw_ostream *GetOutputStream(const char *ProgName) {
|
|||||||
<< "Use -f command line argument to force output\n";
|
<< "Use -f command line argument to force output\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that the Out file gets unlinked from the disk if we get a
|
// Make sure that the Out file gets unlinked from the disk if we get a
|
||||||
// SIGINT
|
// SIGINT
|
||||||
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
|
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
|
||||||
|
|
||||||
std::string error;
|
std::string error;
|
||||||
raw_ostream *Out = new raw_fd_ostream(OutputFilename.c_str(), Binary, error);
|
raw_ostream *Out = new raw_fd_ostream(OutputFilename.c_str(), Binary, error);
|
||||||
if (!error.empty()) {
|
if (!error.empty()) {
|
||||||
@ -184,7 +184,7 @@ static raw_ostream *GetOutputStream(const char *ProgName) {
|
|||||||
delete Out;
|
delete Out;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ int main(int argc, char **argv) {
|
|||||||
// Load the module to be compiled...
|
// Load the module to be compiled...
|
||||||
std::string ErrorMessage;
|
std::string ErrorMessage;
|
||||||
std::auto_ptr<Module> M;
|
std::auto_ptr<Module> M;
|
||||||
|
|
||||||
std::auto_ptr<MemoryBuffer> Buffer(
|
std::auto_ptr<MemoryBuffer> Buffer(
|
||||||
MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage));
|
MemoryBuffer::getFileOrSTDIN(InputFilename, &ErrorMessage));
|
||||||
if (Buffer.get())
|
if (Buffer.get())
|
||||||
@ -209,11 +209,11 @@ int main(int argc, char **argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Module &mod = *M.get();
|
Module &mod = *M.get();
|
||||||
|
|
||||||
// If we are supposed to override the target triple, do so now.
|
// If we are supposed to override the target triple, do so now.
|
||||||
if (!TargetTriple.empty())
|
if (!TargetTriple.empty())
|
||||||
mod.setTargetTriple(TargetTriple);
|
mod.setTargetTriple(TargetTriple);
|
||||||
|
|
||||||
// Allocate target machine. First, check whether the user has
|
// Allocate target machine. First, check whether the user has
|
||||||
// explicitly specified an architecture to compile for.
|
// explicitly specified an architecture to compile for.
|
||||||
if (MArch == 0) {
|
if (MArch == 0) {
|
||||||
@ -236,7 +236,7 @@ int main(int argc, char **argv) {
|
|||||||
Features.AddFeature(MAttrs[i]);
|
Features.AddFeature(MAttrs[i]);
|
||||||
FeaturesStr = Features.getString();
|
FeaturesStr = Features.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::auto_ptr<TargetMachine> target(MArch->CtorFn(mod, FeaturesStr));
|
std::auto_ptr<TargetMachine> target(MArch->CtorFn(mod, FeaturesStr));
|
||||||
assert(target.get() && "Could not allocate target machine!");
|
assert(target.get() && "Could not allocate target machine!");
|
||||||
TargetMachine &Target = *target.get();
|
TargetMachine &Target = *target.get();
|
||||||
@ -244,7 +244,7 @@ int main(int argc, char **argv) {
|
|||||||
// Figure out where we are going to send the output...
|
// Figure out where we are going to send the output...
|
||||||
raw_ostream *Out = GetOutputStream(argv[0]);
|
raw_ostream *Out = GetOutputStream(argv[0]);
|
||||||
if (Out == 0) return 1;
|
if (Out == 0) return 1;
|
||||||
|
|
||||||
// If this target requires addPassesToEmitWholeFile, do it now. This is
|
// If this target requires addPassesToEmitWholeFile, do it now. This is
|
||||||
// used by strange things like the C backend.
|
// used by strange things like the C backend.
|
||||||
if (Target.WantsWholeFile()) {
|
if (Target.WantsWholeFile()) {
|
||||||
@ -252,7 +252,7 @@ int main(int argc, char **argv) {
|
|||||||
PM.add(new TargetData(*Target.getTargetData()));
|
PM.add(new TargetData(*Target.getTargetData()));
|
||||||
if (!NoVerify)
|
if (!NoVerify)
|
||||||
PM.add(createVerifierPass());
|
PM.add(createVerifierPass());
|
||||||
|
|
||||||
// Ask the target to add backend passes as necessary.
|
// Ask the target to add backend passes as necessary.
|
||||||
if (Target.addPassesToEmitWholeFile(PM, *Out, FileType, Fast)) {
|
if (Target.addPassesToEmitWholeFile(PM, *Out, FileType, Fast)) {
|
||||||
std::cerr << argv[0] << ": target does not support generation of this"
|
std::cerr << argv[0] << ": target does not support generation of this"
|
||||||
@ -268,12 +268,12 @@ int main(int argc, char **argv) {
|
|||||||
ExistingModuleProvider Provider(M.release());
|
ExistingModuleProvider Provider(M.release());
|
||||||
FunctionPassManager Passes(&Provider);
|
FunctionPassManager Passes(&Provider);
|
||||||
Passes.add(new TargetData(*Target.getTargetData()));
|
Passes.add(new TargetData(*Target.getTargetData()));
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (!NoVerify)
|
if (!NoVerify)
|
||||||
Passes.add(createVerifierPass());
|
Passes.add(createVerifierPass());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ask the target to add backend passes as necessary.
|
// Ask the target to add backend passes as necessary.
|
||||||
MachineCodeEmitter *MCE = 0;
|
MachineCodeEmitter *MCE = 0;
|
||||||
|
|
||||||
@ -306,18 +306,18 @@ int main(int argc, char **argv) {
|
|||||||
sys::Path(OutputFilename).eraseFromDisk();
|
sys::Path(OutputFilename).eraseFromDisk();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Passes.doInitialization();
|
Passes.doInitialization();
|
||||||
|
|
||||||
// Run our queue of passes all at once now, efficiently.
|
// Run our queue of passes all at once now, efficiently.
|
||||||
// TODO: this could lazily stream functions out of the module.
|
// TODO: this could lazily stream functions out of the module.
|
||||||
for (Module::iterator I = mod.begin(), E = mod.end(); I != E; ++I)
|
for (Module::iterator I = mod.begin(), E = mod.end(); I != E; ++I)
|
||||||
if (!I->isDeclaration())
|
if (!I->isDeclaration())
|
||||||
Passes.run(*I);
|
Passes.run(*I);
|
||||||
|
|
||||||
Passes.doFinalization();
|
Passes.doFinalization();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the ostream if it's not a stdout stream
|
// Delete the ostream if it's not a stdout stream
|
||||||
if (Out != &outs()) delete Out;
|
if (Out != &outs()) delete Out;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user