diff options
| author | 2020-08-03 15:06:44 +0000 | |
|---|---|---|
| committer | 2020-08-03 15:06:44 +0000 | |
| commit | b64793999546ed8adebaeebd9d8345d18db8927d (patch) | |
| tree | 4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/docs/tutorial/BuildingAJIT3.rst | |
| parent | Add support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff) | |
| download | wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip | |
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/docs/tutorial/BuildingAJIT3.rst')
| -rw-r--r-- | gnu/llvm/docs/tutorial/BuildingAJIT3.rst | 191 |
1 files changed, 0 insertions, 191 deletions
diff --git a/gnu/llvm/docs/tutorial/BuildingAJIT3.rst b/gnu/llvm/docs/tutorial/BuildingAJIT3.rst deleted file mode 100644 index 36ec2e707a7..00000000000 --- a/gnu/llvm/docs/tutorial/BuildingAJIT3.rst +++ /dev/null @@ -1,191 +0,0 @@ -============================================= -Building a JIT: Per-function Lazy Compilation -============================================= - -.. contents:: - :local: - -**This tutorial is under active development. It is incomplete and details may -change frequently.** Nonetheless we invite you to try it out as it stands, and -we welcome any feedback. - -Chapter 3 Introduction -====================== - -**Warning: This text is currently out of date due to ORC API updates.** - -**The example code has been updated and can be used. The text will be updated -once the API churn dies down.** - -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>`_. - -Lazy Compilation -================ - -When we add a module to the KaleidoscopeJIT class from Chapter 2 it is -immediately optimized, compiled and linked for us by the IRTransformLayer, -IRCompileLayer and RTDyldObjectLinkingLayer respectively. This scheme, where all the -work to make a Module executable is done up front, is simple to understand and -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 class conforms to the layer interface described in -Chapter 2, but its addModule 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++ - - ... - #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; - RTDyldObjectLinkingLayer ObjectLayer; - IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer; - - using OptimizeFunction = - std::function<std::shared_ptr<Module>(std::shared_ptr<Module>)>; - - IRTransformLayer<decltype(CompileLayer), OptimizeFunction> OptimizeLayer; - - std::unique_ptr<JITCompileCallbackManager> CompileCallbackManager; - CompileOnDemandLayer<decltype(OptimizeLayer)> CODLayer; - - public: - using ModuleHandle = decltype(CODLayer)::ModuleHandleT; - -First we need to include the CompileOnDemandLayer.h header, then add two new -members: a std::unique_ptr<JITCompileCallbackManager> and a CompileOnDemandLayer, -to our class. The CompileCallbackManager member is used by the CompileOnDemandLayer -to create the compile callback needed for each function. - -.. code-block:: c++ - - KaleidoscopeJIT() - : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), - ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }), - CompileLayer(ObjectLayer, SimpleCompiler(*TM)), - OptimizeLayer(CompileLayer, - [this](std::shared_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 -JITTargetAddress 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'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 -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": 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 addModule, 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++ - - // ... - if (auto Sym = CODLayer.findSymbol(Name, false)) - // ... - return cantFail(CODLayer.addModule(std::move(Ms), - std::move(Resolver))); - // ... - - // ... - return CODLayer.findSymbol(MangledNameStream.str(), true); - // ... - - // ... - CODLayer.removeModule(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:** - -** Chapter conclusion.** - -Full Code Listing -================= - -Here is the complete code listing for our running example with a CompileOnDemand -layer added to enable lazy function-at-a-time compilation. To build this example, use: - -.. code-block:: bash - - # Compile - clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy - # Run - ./toy - -Here is the code: - -.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h - :language: c++ - -`Next: Extreme Laziness -- Using Compile Callbacks to JIT directly from ASTs <BuildingAJIT4.html>`_ |
