summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2016-07-15 01:39:49 +0000
committerLang Hames <lhames@gmail.com>2016-07-15 01:39:49 +0000
commit8e1c20f81376fcedbbf33d39a57c92021d5180e2 (patch)
treea1f6d47e42bba6fa9c33927187eec5e0ea33b11b
parent343b2711ecbe862c86f5a410e2b57c904f7bf9ce (diff)
[Kaleidoscope][BuildingAJIT] Start filling in text for chapter 3.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275518 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/tutorial/BuildingAJIT3.rst133
-rw-r--r--examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h7
-rw-r--r--examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h11
-rw-r--r--examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h13
4 files changed, 144 insertions, 20 deletions
diff --git a/docs/tutorial/BuildingAJIT3.rst b/docs/tutorial/BuildingAJIT3.rst
index 35b0e24dc74..3e8d3fbef5a 100644
--- a/docs/tutorial/BuildingAJIT3.rst
+++ b/docs/tutorial/BuildingAJIT3.rst
@@ -16,15 +16,136 @@ Welcome to Chapter 3 of the "Building an ORC-based JIT in LLVM" tutorial. This
chapter discusses lazy JITing and shows you how to enable it by adding an ORC
CompileOnDemand layer the JIT from `Chapter 2 <BuildingAJIT2.html>`_.
-**To be done:**
+Lazy Compilation
+================
+
+When we add a module to the KaleidoscopeJIT class described in Chapter 2 it is
+immediately optimized, compiled and linked for us by the IRTransformLayer,
+IRCompileLayer and ObjectLinkingLayer respectively. This scheme, where all the
+work to make a Module executable is done up front, is relatively simple to
+understand its performance characteristics are easy to reason about. However,
+it will lead to very high startup times if the amount of code to be compiled is
+large, and may also do a lot of unnecessary compilation if only a few compiled
+functions are ever called at runtime. A truly "just-in-time" compiler should
+allow us to defer the compilation of any given function until the moment that
+function is first called, improving launch times and eliminating redundant work.
+In fact, the ORC APIs provide us with a layer to lazily compile LLVM IR:
+*CompileOnDemandLayer*.
+
+The CompileOnDemandLayer conforms to the layer interface described in Chapter 2,
+but the addModuleSet method behaves quite differently from the layers we have
+seen so far: rather than doing any work up front, it just constructs a *stub*
+for each function in the module and arranges for the stub to trigger compilation
+of the actual function the first time it is called. Because stub functions are
+very cheap to produce CompileOnDemand's addModuleSet method runs very quickly,
+reducing the time required to launch the first function to be executed, and
+saving us from doing any redundant compilation. By conforming to the layer
+interface, CompileOnDemand can be easily added on top of our existing JIT class.
+We just need a few changes:
+
+.. code-block:: c++
+
+ ...
+ #include "llvm/ExecutionEngine/SectionMemoryManager.h"
+ #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
+ #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+ ...
+
+ ...
+ class KaleidoscopeJIT {
+ private:
+ std::unique_ptr<TargetMachine> TM;
+ const DataLayout DL;
+ std::unique_ptr<JITCompileCallbackManager> CompileCallbackManager;
+ ObjectLinkingLayer<> ObjectLayer;
+ IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
+
+ typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>
+ OptimizeFunction;
+
+ IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
+ CompileOnDemandLayer<decltype(OptimizeLayer)> CODLayer;
+
+ public:
+ typedef decltype(CODLayer)::ModuleSetHandleT ModuleHandle;
-**(1) Describe lazy function-at-a-time JITing and how it differs from the kind
-of eager module-at-a-time JITing that we've been doing so far.**
+First we need to include the CompileOnDemandLayer.h header, then add two new
+members: a std::unique_ptr<CompileCallbackManager> and a CompileOnDemandLayer,
+to our class. The CompileCallbackManager is a utility that enables us to
+create re-entry points into the compiler for functions that we want to lazily
+compile. In the next chapter we'll be looking at this class in detail, but for
+now we'll be treating it as an opaque utility: We just need to pass a reference
+to it into our new CompileOnDemandLayer, and the layer will do all the work of
+setting up the callbacks using the callback manager we gave it.
-**(2) Discuss CompileCallbackManagers and IndirectStubManagers.**
-**(3) Describe CompileOnDemandLayer (automates these components and builds stubs
-and lazy compilation callbacks for IR) and how to add it to the JIT.**
+ KaleidoscopeJIT()
+ : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
+ CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
+ OptimizeLayer(CompileLayer,
+ [this](std::unique_ptr<Module> M) {
+ return optimizeModule(std::move(M));
+ }),
+ CompileCallbackManager(
+ orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)),
+ CODLayer(OptimizeLayer,
+ [this](Function &F) { return std::set<Function*>({&F}); },
+ *CompileCallbackManager,
+ orc::createLocalIndirectStubsManagerBuilder(
+ TM->getTargetTriple())) {
+ llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
+ }
+
+Next we have to update our constructor to initialize the new members. To create
+an appropriate compile callback manager we use the
+createLocalCompileCallbackManager function, which takes a TargetMachine and a
+TargetAddress to call if it receives a request to compile an unknown function.
+In our simple JIT this situation is unlikely to come up, so we'll cheat and
+just pass '0' here. In a production quality JIT you could give the address of a
+function that throws an exception in order to unwind the JIT'd code stack.
+
+Now we can construct our CompileOnDemandLayer. Following the pattern from
+previous layers we start by passing a reference to the next layer down in our
+stack -- the OptimizeLayer. Next we need to supply a 'partitioning function':
+when a not-yet-compiled function is called, the CompileOnDemandLayer will call
+this function to ask us what we would like to compile. At a minimum we need to
+compile the function being called (given by the argument to the partitioning
+function), but we could also request that the CompileOnDemandLayer compile other
+functions that are unconditionally called (or highly likely to be called) from
+the function being called. For KaleidoscopeJIT we'll keep it simple and just
+request compilation of the function that was called. Next we pass a reference to
+our CompileCallbackManager. Finally, we need to supply an "indirect stubs
+manager builder". This is a function that constructs IndirectStubManagers, which
+are in turn used to build the stubs for each module. The CompileOnDemandLayer
+will call the indirect stub manager builder once for each call to addModuleSet,
+and use the resulting indirect stubs manager to create stubs for all functions
+in all modules added. If/when the module set is removed from the JIT the
+indirect stubs manager will be deleted, freeing any memory allocated to the
+stubs. We supply this function by using the
+createLocalIndirectStubsManagerBuilder utility.
+
+ // ...
+ if (auto Sym = CODLayer.findSymbol(Name, false))
+ // ...
+ return CODLayer.addModuleSet(std::move(Ms),
+ make_unique<SectionMemoryManager>(),
+ std::move(Resolver));
+ // ...
+
+ // ...
+ return CODLayer.findSymbol(MangledNameStream.str(), true);
+ // ...
+
+ // ...
+ CODLayer.removeModuleSet(H);
+ // ...
+
+Finally, we need to replace the references to OptimizeLayer in our addModule,
+findSymbol, and removeModule methods. With that, we're up and running.
+
+**To be done:**
+
+** Discuss CompileCallbackManagers and IndirectStubManagers in more detail.**
Full Code Listing
=================
diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
index 7ef1d07d879..68bdafe9897 100644
--- a/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
+++ b/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
@@ -42,7 +42,6 @@ class KaleidoscopeJIT {
private:
std::unique_ptr<TargetMachine> TM;
const DataLayout DL;
- std::unique_ptr<JITCompileCallbackManager> CompileCallbackManager;
ObjectLinkingLayer<> ObjectLayer;
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
@@ -50,6 +49,8 @@ private:
OptimizeFunction;
IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
+
+ std::unique_ptr<JITCompileCallbackManager> CompileCallbackManager;
CompileOnDemandLayer<decltype(OptimizeLayer)> CODLayer;
public:
@@ -57,13 +58,13 @@ public:
KaleidoscopeJIT()
: TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
- CompileCallbackManager(
- orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)),
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
OptimizeLayer(CompileLayer,
[this](std::unique_ptr<Module> M) {
return optimizeModule(std::move(M));
}),
+ CompileCallbackManager(
+ orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)),
CODLayer(OptimizeLayer,
[this](Function &F) { return std::set<Function*>({&F}); },
*CompileCallbackManager,
diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
index b856bb5e4f3..d14c2b1805f 100644
--- a/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
+++ b/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
@@ -66,8 +66,6 @@ class KaleidoscopeJIT {
private:
std::unique_ptr<TargetMachine> TM;
const DataLayout DL;
- std::unique_ptr<JITCompileCallbackManager> CompileCallbackMgr;
- std::unique_ptr<IndirectStubsManager> IndirectStubsMgr;
ObjectLinkingLayer<> ObjectLayer;
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
@@ -76,19 +74,22 @@ private:
IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
+ std::unique_ptr<JITCompileCallbackManager> CompileCallbackMgr;
+ std::unique_ptr<IndirectStubsManager> IndirectStubsMgr;
+
public:
typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle;
KaleidoscopeJIT()
: TM(EngineBuilder().selectTarget()),
DL(TM->createDataLayout()),
- CompileCallbackMgr(
- orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)),
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
OptimizeLayer(CompileLayer,
[this](std::unique_ptr<Module> M) {
return optimizeModule(std::move(M));
- }) {
+ }),
+ CompileCallbackMgr(
+ orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)) {
auto IndirectStubsMgrBuilder =
orc::createLocalIndirectStubsManagerBuilder(TM->getTargetTriple());
IndirectStubsMgr = IndirectStubsMgrBuilder();
diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h
index 900ad844573..24d6dc9b7b8 100644
--- a/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h
+++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h
@@ -69,11 +69,8 @@ typedef remote::OrcRemoteTargetClient<FDRPCChannel> MyRemote;
class KaleidoscopeJIT {
private:
- MyRemote &Remote;
std::unique_ptr<TargetMachine> TM;
const DataLayout DL;
- JITCompileCallbackManager *CompileCallbackMgr;
- std::unique_ptr<IndirectStubsManager> IndirectStubsMgr;
ObjectLinkingLayer<> ObjectLayer;
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
@@ -82,18 +79,22 @@ private:
IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer;
+ JITCompileCallbackManager *CompileCallbackMgr;
+ std::unique_ptr<IndirectStubsManager> IndirectStubsMgr;
+ MyRemote &Remote;
+
public:
typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle;
KaleidoscopeJIT(MyRemote &Remote)
- : Remote(Remote),
- TM(EngineBuilder().selectTarget()),
+ : TM(EngineBuilder().selectTarget()),
DL(TM->createDataLayout()),
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
OptimizeLayer(CompileLayer,
[this](std::unique_ptr<Module> M) {
return optimizeModule(std::move(M));
- }) {
+ }),
+ Remote(Remote) {
auto CCMgrOrErr = Remote.enableCompileCallbacks(0);
if (!CCMgrOrErr) {
logAllUnhandledErrors(CCMgrOrErr.takeError(), errs(),