summaryrefslogtreecommitdiff
path: root/docs/tutorial
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2016-07-19 00:25:52 +0000
committerLang Hames <lhames@gmail.com>2016-07-19 00:25:52 +0000
commit5a04b09d43cb0186c95decd72dbae480b61a7d3c (patch)
tree6de4d3d83105eab630a810bea296d677a118ec2a /docs/tutorial
parentaaf3f191a5d5a972ea139be595f0cf7c9f3d3593 (diff)
[Kaleidoscope][BuildingAJIT] More work on the text for Chapter 3.
Add an overview of stubs and compile callbacks before the discussion of the source changes. -- This line, and those below, will be ignored-- M docs/tutorial/BuildingAJIT3.rst git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275933 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'docs/tutorial')
-rw-r--r--docs/tutorial/BuildingAJIT3.rst79
1 files changed, 46 insertions, 33 deletions
diff --git a/docs/tutorial/BuildingAJIT3.rst b/docs/tutorial/BuildingAJIT3.rst
index ba0dab91c4e..216e65c6fa1 100644
--- a/docs/tutorial/BuildingAJIT3.rst
+++ b/docs/tutorial/BuildingAJIT3.rst
@@ -22,26 +22,43 @@ 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:
+work to make a Module executable is done up front, is 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:
+The CompileOnDemandLayer class conforms to the layer interface described in
+Chapter 2, but its addModuleSet method behaves quite differently from the layers
+we have seen so far: rather than doing any work up front, it just scans the
+Modules being added and arranges for each function in them to be compiled the
+first time it is called. To do this, the CompileOnDemandLayer creates two small
+utilities for each function that it scans: a *stub* and a *compile
+callback*. The stub is a pair of a function pointer (which will be pointed at
+the function's implementation once the function has been compiled) and an
+indirect jump through the pointer. By fixing the address of the indirect jump
+for the lifetime of the program we can give the function a permanent "effective
+address", one that can be safely used for indirection and function pointer
+comparison even if the function's implementation is never compiled, or if it is
+compiled more than once (due to, for example, recompiling the function at a
+higher optimization level) and changes address. The second utility, the compile
+callback, represents a re-entry point from the program into the compiler that
+will trigger compilation and then execution of a function. By initializing the
+function's stub to point at the function's compile callback, we enable lazy
+compilation: The first attempted call to the function will follow the function
+pointer and trigger the compile callback instead. The compile callback will
+compile the function, update the function pointer for the stub, then execute
+the function. On all subsequent calls to the function, the function pointer
+will point at the already-compiled function, so there is no further overhead
+from the compiler. We will look at this process in more detail in the next
+chapter of this tutorial, but for now we'll trust the CompileOnDemandLayer to
+set all the stubs and callbacks up for us. All we need to do is to add the
+CompileOnDemandLayer to the top of our stack and we'll get the benefits of
+lazy compilation. We just need a few changes to the source:
.. code-block:: c++
@@ -71,12 +88,8 @@ We just need a few changes:
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.
+to our class. The CompileCallbackManager member is used by the CompileOnDemandLayer
+to create the compile callback needed for each function.
.. code-block:: c++
@@ -103,7 +116,7 @@ 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.
+function that throws an exception in order to unwind the JIT'd code's 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
@@ -116,13 +129,13 @@ 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
+manager builder": a utility function that constructs IndirectStubManagers, which
+are in turn used to build the stubs for the functions in 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 in the set. 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.
.. code-block:: c++
@@ -148,7 +161,7 @@ findSymbol, and removeModule methods. With that, we're up and running.
**To be done:**
-** Discuss CompileCallbackManagers and IndirectStubManagers in more detail.**
+** Chapter conclusion.**
Full Code Listing
=================