llvm.org GIT mirror llvm / 95ed232
[ORC][Kaleidoscope] Update ORCJit tutorial. Summary: Fix a few typos and update names to match current source. Differential Revision: https://reviews.llvm.org/D37948 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313473 91177308-0d34-0410-b5e6-96231b3b80d8 Don Hinton 1 year, 11 months ago
5 changed file(s) with 106 addition(s) and 107 deletion(s). Raw diff Collapse all Expand all
7878 int Result = Main();
7979 J.removeModule(H);
8080
81 The APIs that we build in these tutorials will all be aovariations on this simple
81 The APIs that we build in these tutorials will all be variations on this simple
8282 theme. Behind the API we will refine the implementation of the JIT to add
8383 support for optimization and lazy compilation. Eventually we will extend the
8484 API itself to allow higher-level program representations (e.g. ASTs) to be
111111
112112 #include "llvm/ADT/STLExtras.h"
113113 #include "llvm/ExecutionEngine/ExecutionEngine.h"
114 #include "llvm/ExecutionEngine/JITSymbol.h"
114115 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
116 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
115117 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
116118 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
117119 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
118 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
120 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
121 #include "llvm/IR/DataLayout.h"
119122 #include "llvm/IR/Mangler.h"
120123 #include "llvm/Support/DynamicLibrary.h"
121124 #include "llvm/Support/raw_ostream.h"
158161 ModuleHandle. This is the handle type that will be returned from our JIT's
159162 addModule method, and can be passed to the removeModule method to remove a
160163 module. The IRCompileLayer class already provides a convenient handle type
161 (IRCompileLayer::ModuleSetHandleT), so we just alias our ModuleHandle to this.
164 (IRCompileLayer::ModuleHandleT), so we just alias our ModuleHandle to this.
162165
163166 .. code-block:: c++
164167
180183 memory permissions, and registration of exception handlers for JIT'd code). For
181184 this we use a lambda that returns a SectionMemoryManager, an off-the-shelf
182185 utility that provides all the basic memory management functionality required for
183 this chapter. Next we initialize our CompileLayer. The Compile laye needs two
186 this chapter. Next we initialize our CompileLayer. The CompileLayer needs two
184187 things: (1) A reference to our object layer, and (2) a compiler instance to use
185188 to perform the actual compilation from IR to object files. We use the
186189 off-the-shelf SimpleCompiler instance for now. Finally, in the body of the
219222 responsible for adding IR to the JIT and making it available for execution. In
220223 this initial implementation of our JIT we will make our modules "available for
221224 execution" by adding them straight to the CompileLayer, which will immediately
222 compile them. In later chapters we will teach our JIT to be defer compilation
225 compile them. In later chapters we will teach our JIT to defer compilation
223226 of individual functions until they're actually called.
224227
225228 To add our module to the CompileLayer we need to supply both the module and a
334337 .. code-block:: bash
335338
336339 # Compile
337 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy
340 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
338341 # Run
339342 ./toy
340343
350353 left as an exercise for the reader. (The KaleidoscopeJIT.h used in the
351354 original tutorials will be a helpful reference).
352355
353 .. [2] +-----------------------+-----------------------------------------------+
354 | File | Reason for inclusion |
355 +=======================+===============================================+
356 | STLExtras.h | LLVM utilities that are useful when working |
357 | | with the STL. |
358 +-----------------------+-----------------------------------------------+
359 | ExecutionEngine.h | Access to the EngineBuilder::selectTarget |
360 | | method. |
361 +-----------------------+-----------------------------------------------+
362 | | Access to the |
363 | RTDyldMemoryManager.h | RTDyldMemoryManager::getSymbolAddressInProcess|
364 | | method. |
365 +-----------------------+-----------------------------------------------+
366 | CompileUtils.h | Provides the SimpleCompiler class. |
367 +-----------------------+-----------------------------------------------+
368 | IRCompileLayer.h | Provides the IRCompileLayer class. |
369 +-----------------------+-----------------------------------------------+
370 | | Access the createLambdaResolver function, |
371 | LambdaResolver.h | which provides easy construction of symbol |
372 | | resolvers. |
373 +-----------------------+-----------------------------------------------+
374 | ObjectLinkingLayer.h | Provides the ObjectLinkingLayer class. |
375 +-----------------------+-----------------------------------------------+
376 | Mangler.h | Provides the Mangler class for platform |
377 | | specific name-mangling. |
378 +-----------------------+-----------------------------------------------+
379 | DynamicLibrary.h | Provides the DynamicLibrary class, which |
380 | | makes symbols in the host process searchable. |
381 +-----------------------+-----------------------------------------------+
382 | | A fast output stream class. We use the |
383 | raw_ostream.h | raw_string_ostream subclass for symbol |
384 | | mangling |
385 +-----------------------+-----------------------------------------------+
386 | TargetMachine.h | LLVM target machine description class. |
387 +-----------------------+-----------------------------------------------+
356 .. [2] +-----------------------------+-----------------------------------------------+
357 | File | Reason for inclusion |
358 +=============================+===============================================+
359 | STLExtras.h | LLVM utilities that are useful when working |
360 | | with the STL. |
361 +-----------------------------+-----------------------------------------------+
362 | ExecutionEngine.h | Access to the EngineBuilder::selectTarget |
363 | | method. |
364 +-----------------------------+-----------------------------------------------+
365 | | Access to the |
366 | RTDyldMemoryManager.h | RTDyldMemoryManager::getSymbolAddressInProcess|
367 | | method. |
368 +-----------------------------+-----------------------------------------------+
369 | CompileUtils.h | Provides the SimpleCompiler class. |
370 +-----------------------------+-----------------------------------------------+
371 | IRCompileLayer.h | Provides the IRCompileLayer class. |
372 +-----------------------------+-----------------------------------------------+
373 | | Access the createLambdaResolver function, |
374 | LambdaResolver.h | which provides easy construction of symbol |
375 | | resolvers. |
376 +-----------------------------+-----------------------------------------------+
377 | RTDyldObjectLinkingLayer.h | Provides the RTDyldObjectLinkingLayer class. |
378 +-----------------------------+-----------------------------------------------+
379 | Mangler.h | Provides the Mangler class for platform |
380 | | specific name-mangling. |
381 +-----------------------------+-----------------------------------------------+
382 | DynamicLibrary.h | Provides the DynamicLibrary class, which |
383 | | makes symbols in the host process searchable. |
384 +-----------------------------+-----------------------------------------------+
385 | | A fast output stream class. We use the |
386 | raw_ostream.h | raw_string_ostream subclass for symbol |
387 | | mangling |
388 +-----------------------------+-----------------------------------------------+
389 | TargetMachine.h | LLVM target machine description class. |
390 +-----------------------------+-----------------------------------------------+
388391
389392 .. [3] Actually they don't have to be lambdas, any object with a call operator
390393 will do, including plain old functions or std::functions.
391394
392395 .. [4] ``JITSymbol::getAddress`` will force the JIT to compile the definition of
393396 the symbol if it hasn't already been compiled, and since the compilation
394 process could fail getAddress must be able to return this failure.
397 process could fail getAddress must be able to return this failure.
4545 IRTransformLayer works in more detail below, but the interface is simple: the
4646 constructor for this layer takes a reference to the layer below (as all layers
4747 do) plus an *IR optimization function* that it will apply to each Module that
48 is added via addModuleSet:
48 is added via addModule:
4949
5050 .. code-block:: c++
5151
5353 private:
5454 std::unique_ptr TM;
5555 const DataLayout DL;
56 ObjectLinkingLayer<> ObjectLayer;
56 RTDyldObjectLinkingLayer<> ObjectLayer;
5757 IRCompileLayer CompileLayer;
5858
59 typedef std::function(std::unique_ptr)>
60 OptimizeFunction;
59 using OptimizeFunction =
60 std::function(std::shared_ptr)>;
6161
6262 IRTransformLayer OptimizeLayer;
6363
6464 public:
65 typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle;
65 using ModuleHandle = decltype(OptimizeLayer)::ModuleHandleT;
6666
6767 KaleidoscopeJIT()
6868 : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
69 ObjectLayer([]() { return std::make_shared(); }),
6970 CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
7071 OptimizeLayer(CompileLayer,
7172 [this](std::unique_ptr M) {
100101 .. code-block:: c++
101102
102103 // ...
103 return OptimizeLayer.addModuleSet(std::move(Ms),
104 make_unique(),
105 std::move(Resolver));
104 return cantFail(OptimizeLayer.addModule(std::move(M),
105 std::move(Resolver)));
106106 // ...
107107
108108 .. code-block:: c++
114114 .. code-block:: c++
115115
116116 // ...
117 OptimizeLayer.removeModuleSet(H);
117 cantFail(OptimizeLayer.removeModule(H));
118118 // ...
119119
120120 Next we need to replace references to 'CompileLayer' with references to
121121 OptimizeLayer in our key methods: addModule, findSymbol, and removeModule. In
122122 addModule we need to be careful to replace both references: the findSymbol call
123 inside our resolver, and the call through to addModuleSet.
124
125 .. code-block:: c++
126
127 std::unique_ptr optimizeModule(std::unique_ptr M) {
123 inside our resolver, and the call through to addModule.
124
125 .. code-block:: c++
126
127 std::shared_ptr optimizeModule(std::shared_ptr M) {
128128 // Create a function pass manager.
129129 auto FPM = llvm::make_unique(M.get());
130130
165165 template
166166 class IRTransformLayer {
167167 public:
168 typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT;
168 using ModuleHandleT = typename BaseLayerT::ModuleHandleT;
169169
170170 IRTransformLayer(BaseLayerT &BaseLayer,
171171 TransformFtor Transform = TransformFtor())
172172 : BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
173173
174 template
175 typename SymbolResolverPtrT>
176 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
177 MemoryManagerPtrT MemMgr,
178 SymbolResolverPtrT Resolver) {
179
180 for (auto I = Ms.begin(), E = Ms.end(); I != E; ++I)
181 *I = Transform(std::move(*I));
182
183 return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr),
184 std::move(Resolver));
185 }
186
187 void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeModuleSet(H); }
174 Expected
175 addModule(std::shared_ptr M,
176 std::shared_ptr Resolver) {
177 return BaseLayer.addModule(Transform(std::move(M)), std::move(Resolver));
178 }
179
180 void removeModule(ModuleHandleT H) { BaseLayer.removeModule(H); }
188181
189182 JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
190183 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
191184 }
192185
193 JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
186 JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name,
194187 bool ExportedSymbolsOnly) {
195188 return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
196189 }
197190
198 void emitAndFinalize(ModuleSetHandleT H) {
191 void emitAndFinalize(ModuleHandleT H) {
199192 BaseLayer.emitAndFinalize(H);
200193 }
201194
214207 ``TransformFtor`` that provide the type of the base layer and the type of the
215208 "transform functor" (in our case a std::function) respectively. This class is
216209 concerned with two very simple jobs: (1) Running every IR Module that is added
217 with addModuleSet through the transform functor, and (2) conforming to the ORC
210 with addModule through the transform functor, and (2) conforming to the ORC
218211 layer interface. The interface consists of one typedef and five methods:
219212
220213 +------------------+-----------------------------------------------------------+
221214 | Interface | Description |
222215 +==================+===========================================================+
223216 | | Provides a handle that can be used to identify a module |
224 | ModuleSetHandleT | set when calling findSymbolIn, removeModuleSet, or |
217 | ModuleHandleT | set when calling findSymbolIn, removeModule, or |
225218 | | emitAndFinalize. |
226219 +------------------+-----------------------------------------------------------+
227220 | | Takes a given set of Modules and makes them "available |
230223 | | the address of the symbols should be read/writable (for |
231224 | | data symbols), or executable (for function symbols) after |
232225 | | JITSymbol::getAddress() is called. Note: This means that |
233 | addModuleSet | addModuleSet doesn't have to compile (or do any other |
226 | addModule | addModule doesn't have to compile (or do any other |
234227 | | work) up-front. It *can*, like IRCompileLayer, act |
235228 | | eagerly, but it can also simply record the module and |
236229 | | take no further action until somebody calls |
237230 | | JITSymbol::getAddress(). In IRTransformLayer's case |
238 | | addModuleSet eagerly applies the transform functor to |
231 | | addModule eagerly applies the transform functor to |
239232 | | each module in the set, then passes the resulting set |
240233 | | of mutated modules down to the layer below. |
241234 +------------------+-----------------------------------------------------------+
242235 | | Removes a set of modules from the JIT. Code or data |
243 | removeModuleSet | defined in these modules will no longer be available, and |
236 | removeModule | defined in these modules will no longer be available, and |
244237 | | the memory holding the JIT'd definitions will be freed. |
245238 +------------------+-----------------------------------------------------------+
246239 | | Searches for the named symbol in all modules that have |
247 | | previously been added via addModuleSet (and not yet |
248 | findSymbol | removed by a call to removeModuleSet). In |
240 | | previously been added via addModule (and not yet |
241 | findSymbol | removed by a call to removeModule). In |
249242 | | IRTransformLayer we just pass the query on to the layer |
250243 | | below. In our REPL this is our default way to search for |
251244 | | function definitions. |
252245 +------------------+-----------------------------------------------------------+
253246 | | Searches for the named symbol in the module set indicated |
254 | | by the given ModuleSetHandleT. This is just an optimized |
247 | | by the given ModuleHandleT. This is just an optimized |
255248 | | search, better for lookup-speed when you know exactly |
256249 | | a symbol definition should be found. In IRTransformLayer |
257250 | findSymbolIn | we just pass this query on to the layer below. In our |
261254 | | we just added. |
262255 +------------------+-----------------------------------------------------------+
263256 | | Forces all of the actions required to make the code and |
264 | | data in a module set (represented by a ModuleSetHandleT) |
257 | | data in a module set (represented by a ModuleHandleT) |
265258 | | accessible. Behaves as if some symbol in the set had been |
266259 | | searched for and JITSymbol::getSymbolAddress called. This |
267260 | emitAndFinalize | is rarely needed, but can be useful when dealing with |
275268 operations we identified in Chapter 1. Conforming to the layer concept allows
276269 classes to compose neatly by implementing their behaviors in terms of the these
277270 same operations, carried out on the layer below. For example, an eager layer
278 (like IRTransformLayer) can implement addModuleSet by running each module in the
271 (like IRTransformLayer) can implement addModule by running each module in the
279272 set through its transform up-front and immediately passing the result to the
280 layer below. A lazy layer, by contrast, could implement addModuleSet by
273 layer below. A lazy layer, by contrast, could implement addModule by
281274 squirreling away the modules doing no other up-front work, but applying the
282 transform (and calling addModuleSet on the layer below) when the client calls
275 transform (and calling addModule on the layer below) when the client calls
283276 findSymbol instead. The JIT'd program behavior will be the same either way, but
284277 these choices will have different performance characteristics: Doing work
285278 eagerly means the JIT takes longer up-front, but proceeds smoothly once this is
318311 .. code-block:: bash
319312
320313 # Compile
321 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy
314 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
322315 # Run
323316 ./toy
324317
328321 :language: c++
329322
330323 .. [1] When we add our top-level expression to the JIT, any calls to functions
331 that we defined earlier will appear to the ObjectLinkingLayer as
332 external symbols. The ObjectLinkingLayer will call the SymbolResolver
333 that we defined in addModuleSet, which in turn calls findSymbol on the
324 that we defined earlier will appear to the RTDyldObjectLinkingLayer as
325 external symbols. The RTDyldObjectLinkingLayer will call the SymbolResolver
326 that we defined in addModule, which in turn calls findSymbol on the
334327 OptimizeLayer, at which point even a lazy transform layer will have to
335328 do its work.
2020
2121 When we add a module to the KaleidoscopeJIT class from Chapter 2 it is
2222 immediately optimized, compiled and linked for us by the IRTransformLayer,
23 IRCompileLayer and ObjectLinkingLayer respectively. This scheme, where all the
23 IRCompileLayer and RTDyldObjectLinkingLayer respectively. This scheme, where all the
2424 work to make a Module executable is done up front, is simple to understand and
2525 its performance characteristics are easy to reason about. However, it will lead
2626 to very high startup times if the amount of code to be compiled is large, and
3232 *CompileOnDemandLayer*.
3333
3434 The CompileOnDemandLayer class conforms to the layer interface described in
35 Chapter 2, but its addModuleSet method behaves quite differently from the layers
35 Chapter 2, but its addModule method behaves quite differently from the layers
3636 we have seen so far: rather than doing any work up front, it just scans the
3737 Modules being added and arranges for each function in them to be compiled the
3838 first time it is called. To do this, the CompileOnDemandLayer creates two small
7272 private:
7373 std::unique_ptr TM;
7474 const DataLayout DL;
75 std::unique_ptr CompileCallbackManager;
76 ObjectLinkingLayer<> ObjectLayer;
77 IRCompileLayer CompileLayer;
75 RTDyldObjectLinkingLayer ObjectLayer;
76 IRCompileLayer CompileLayer;
7877
79 typedef std::function(std::unique_ptr)>
80 OptimizeFunction;
78 using OptimizeFunction =
79 std::function(std::shared_ptr)>;
8180
8281 IRTransformLayer OptimizeLayer;
82
83 std::unique_ptr CompileCallbackManager;
8384 CompileOnDemandLayer CODLayer;
8485
8586 public:
86 typedef decltype(CODLayer)::ModuleSetHandleT ModuleHandle;
87 using ModuleHandle = decltype(CODLayer)::ModuleHandleT;
8788
8889 First we need to include the CompileOnDemandLayer.h header, then add two new
89 members: a std::unique_ptr<CompileCallbackManager> and a CompileOnDemandLayer,
90 members: a std::unique_ptr<JITCompileCallbackManager> and a CompileOnDemandLayer,
9091 to our class. The CompileCallbackManager member is used by the CompileOnDemandLayer
9192 to create the compile callback needed for each function.
9293
9495
9596 KaleidoscopeJIT()
9697 : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
98 ObjectLayer([]() { return std::make_shared(); }),
9799 CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
98100 OptimizeLayer(CompileLayer,
99 [this](std::unique_ptr M) {
101 [this](std::shared_ptr M) {
100102 return optimizeModule(std::move(M));
101103 }),
102104 CompileCallbackManager(
132134 manager builder": a utility function that constructs IndirectStubManagers, which
133135 are in turn used to build the stubs for the functions in each module. The
134136 CompileOnDemandLayer will call the indirect stub manager builder once for each
135 call to addModuleSet, and use the resulting indirect stubs manager to create
137 call to addModule, and use the resulting indirect stubs manager to create
136138 stubs for all functions in all modules in the set. If/when the module set is
137139 removed from the JIT the indirect stubs manager will be deleted, freeing any
138140 memory allocated to the stubs. We supply this function by using the
143145 // ...
144146 if (auto Sym = CODLayer.findSymbol(Name, false))
145147 // ...
146 return CODLayer.addModuleSet(std::move(Ms),
147 make_unique(),
148 std::move(Resolver));
148 return cantFail(CODLayer.addModule(std::move(Ms),
149 std::move(Resolver)));
149150 // ...
150151
151152 // ...
153154 // ...
154155
155156 // ...
156 CODLayer.removeModuleSet(H);
157 CODLayer.removeModule(H);
157158 // ...
158159
159160 Finally, we need to replace the references to OptimizeLayer in our addModule,
172173 .. code-block:: bash
173174
174175 # Compile
175 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy
176 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
176177 # Run
177178 ./toy
178179
3535 .. code-block:: bash
3636
3737 # Compile
38 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy
38 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
3939 # Run
4040 ./toy
4141
3939 .. code-block:: bash
4040
4141 # Compile
42 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy
42 clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy
43 clang++ -g Server/server.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy-server
4344 # Run
45 ./toy-server &
4446 ./toy
4547
4648 Here is the code for the modified KaleidoscopeJIT: