llvm.org GIT mirror llvm / a7007af
[ORC][Kaleidoscope] Update Chapter 1 of BuildingAJIT to incorporate recent ORC API changes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310947 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 2 years ago
3 changed file(s) with 110 addition(s) and 85 deletion(s). Raw diff Collapse all Expand all
7474 std::unique_ptr M = buildModule();
7575 JIT J;
7676 Handle H = J.addModule(*M);
77 int (*Main)(int, char*[]) =
78 (int(*)(int, char*[])J.findSymbol("main").getAddress();
77 int (*Main)(int, char*[]) = (int(*)(int, char*[]))J.getSymbolAddress("main");
7978 int Result = Main();
8079 J.removeModule(H);
8180
82 The APIs that we build in these tutorials will all be variations on this simple
81 The APIs that we build in these tutorials will all be aovariations on this simple
8382 theme. Behind the API we will refine the implementation of the JIT to add
8483 support for optimization and lazy compilation. Eventually we will extend the
8584 API itself to allow higher-level program representations (e.g. ASTs) to be
110109 #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
111110 #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
112111
112 #include "llvm/ADT/STLExtras.h"
113113 #include "llvm/ExecutionEngine/ExecutionEngine.h"
114114 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
115115 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
118118 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
119119 #include "llvm/IR/Mangler.h"
120120 #include "llvm/Support/DynamicLibrary.h"
121 #include "llvm/Support/raw_ostream.h"
122 #include "llvm/Target/TargetMachine.h"
123 #include
124 #include
125 #include
126 #include
121127
122128 namespace llvm {
123129 namespace orc {
126132 private:
127133 std::unique_ptr TM;
128134 const DataLayout DL;
129 ObjectLinkingLayer<> ObjectLayer;
130 IRCompileLayer CompileLayer;
135 RTDyldObjectLinkingLayer ObjectLayer;
136 IRCompileLayer CompileLayer;
131137
132138 public:
133 typedef decltype(CompileLayer)::ModuleSetHandleT ModuleHandleT;
134
135 Our class begins with four members: A TargetMachine, TM, which will be used
136 to build our LLVM compiler instance; A DataLayout, DL, which will be used for
139 using ModuleHandle = decltype(CompileLayer)::ModuleHandleT;
140
141 Our class begins with four members: A TargetMachine, TM, which will be used to
142 build our LLVM compiler instance; A DataLayout, DL, which will be used for
137143 symbol mangling (more on that later), and two ORC *layers*: an
138 ObjectLinkingLayer and a IRCompileLayer. We'll be talking more about layers in
139 the next chapter, but for now you can think of them as analogous to LLVM
144 RTDyldObjectLinkingLayer and a CompileLayer. We'll be talking more about layers
145 in the next chapter, but for now you can think of them as analogous to LLVM
140146 Passes: they wrap up useful JIT utilities behind an easy to compose interface.
141 The first layer, ObjectLinkingLayer, is the foundation of our JIT: it takes
142 in-memory object files produced by a compiler and links them on the fly to make
143 them executable. This JIT-on-top-of-a-linker design was introduced in MCJIT,
144 however the linker was hidden inside the MCJIT class. In ORC we expose the
145 linker so that clients can access and configure it directly if they need to. In
146 this tutorial our ObjectLinkingLayer will just be used to support the next layer
147 in our stack: the IRCompileLayer, which will be responsible for taking LLVM IR,
148 compiling it, and passing the resulting in-memory object files down to the
149 object linking layer below.
147 The first layer, ObjectLayer, is the foundation of our JIT: it takes in-memory
148 object files produced by a compiler and links them on the fly to make them
149 executable. This JIT-on-top-of-a-linker design was introduced in MCJIT, however
150 the linker was hidden inside the MCJIT class. In ORC we expose the linker so
151 that clients can access and configure it directly if they need to. In this
152 tutorial our ObjectLayer will just be used to support the next layer in our
153 stack: the CompileLayer, which will be responsible for taking LLVM IR, compiling
154 it, and passing the resulting in-memory object files down to the object linking
155 layer below.
150156
151157 That's it for member variables, after that we have a single typedef:
152 ModuleHandleT. This is the handle type that will be returned from our JIT's
158 ModuleHandle. This is the handle type that will be returned from our JIT's
153159 addModule method, and can be passed to the removeModule method to remove a
154160 module. The IRCompileLayer class already provides a convenient handle type
155 (IRCompileLayer::ModuleSetHandleT), so we just alias our ModuleHandleT to this.
161 (IRCompileLayer::ModuleSetHandleT), so we just alias our ModuleHandle to this.
156162
157163 .. code-block:: c++
158164
159165 KaleidoscopeJIT()
160166 : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
167 ObjectLayer([]() { return std::make_shared(); }),
161168 CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
162169 llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
163170 }
165172 TargetMachine &getTargetMachine() { return *TM; }
166173
167174 Next up we have our class constructor. We begin by initializing TM using the
168 EngineBuilder::selectTarget helper method, which constructs a TargetMachine for
169 the current process. Next we use our newly created TargetMachine to initialize
170 DL, our DataLayout. Then we initialize our IRCompileLayer. Our IRCompile layer
171 needs two things: (1) A reference to our object linking layer, and (2) a
172 compiler instance to use to perform the actual compilation from IR to object
173 files. We use the off-the-shelf SimpleCompiler instance for now. Finally, in
174 the body of the constructor, we call the DynamicLibrary::LoadLibraryPermanently
175 method with a nullptr argument. Normally the LoadLibraryPermanently method is
176 called with the path of a dynamic library to load, but when passed a null
177 pointer it will 'load' the host process itself, making its exported symbols
178 available for execution.
175 EngineBuilder::selectTarget helper method which constructs a TargetMachine for
176 the current process. Then we use our newly created TargetMachine to initialize
177 DL, our DataLayout. After that we need to initialize our ObjectLayer. The
178 ObjectLayer requires a function object that will build a JIT memory manager for
179 each module that is added (a JIT memory manager manages memory allocations,
180 memory permissions, and registration of exception handlers for JIT'd code). For
181 this we use a lambda that returns a SectionMemoryManager, an off-the-shelf
182 utility that provides all the basic memory management functionality required for
183 this chapter. Next we initialize our CompileLayer. The Compile laye needs two
184 things: (1) A reference to our object layer, and (2) a compiler instance to use
185 to perform the actual compilation from IR to object files. We use the
186 off-the-shelf SimpleCompiler instance for now. Finally, in the body of the
187 constructor, we call the DynamicLibrary::LoadLibraryPermanently method with a
188 nullptr argument. Normally the LoadLibraryPermanently method is called with the
189 path of a dynamic library to load, but when passed a null pointer it will 'load'
190 the host process itself, making its exported symbols available for execution.
179191
180192 .. code-block:: c++
181193
190202 return Sym;
191203 return JITSymbol(nullptr);
192204 },
193 [](const std::string &S) {
205 [](const std::string &Name) {
194206 if (auto SymAddr =
195207 RTDyldMemoryManager::getSymbolAddressInProcess(Name))
196208 return JITSymbol(SymAddr, JITSymbolFlags::Exported);
197209 return JITSymbol(nullptr);
198210 });
199211
200 // Build a singleton module set to hold our module.
201 std::vector> Ms;
202 Ms.push_back(std::move(M));
203
204212 // Add the set to the JIT with the resolver we created above and a newly
205213 // created SectionMemoryManager.
206 return CompileLayer.addModuleSet(std::move(Ms),
207 make_unique(),
208 std::move(Resolver));
214 return cantFail(CompileLayer.addModule(std::move(M),
215 std::move(Resolver)));
209216 }
210217
211218 Now we come to the first of our JIT API methods: addModule. This method is
212219 responsible for adding IR to the JIT and making it available for execution. In
213220 this initial implementation of our JIT we will make our modules "available for
214 execution" by adding them straight to the IRCompileLayer, which will
215 immediately compile them. In later chapters we will teach our JIT to be lazier
216 and instead add the Modules to a "pending" list to be compiled if and when they
217 are first executed.
218
219 To add our module to the IRCompileLayer we need to supply two auxiliary objects
220 (as well as the module itself): a memory manager and a symbol resolver. The
221 memory manager will be responsible for managing the memory allocated to JIT'd
222 machine code, setting memory permissions, and registering exception handling
223 tables (if the JIT'd code uses exceptions). For our memory manager we will use
224 the SectionMemoryManager class: another off-the-shelf utility that provides all
225 the basic functionality we need. The second auxiliary class, the symbol
226 resolver, is more interesting for us. It exists to tell the JIT where to look
227 when it encounters an *external symbol* in the module we are adding. External
221 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
223 of individual functions until they're actually called.
224
225 To add our module to the CompileLayer we need to supply both the module and a
226 symbol resolver. The symbol resolver is responsible for supplying the JIT with
227 an address for each *external symbol* in the module we are adding. External
228228 symbols are any symbol not defined within the module itself, including calls to
229229 functions outside the JIT and calls to functions defined in other modules that
230 have already been added to the JIT. It may seem as though modules added to the
231 JIT should "know about one another" by default, but since we would still have to
230 have already been added to the JIT. (It may seem as though modules added to the
231 JIT should know about one another by default, but since we would still have to
232232 supply a symbol resolver for references to code outside the JIT it turns out to
233 be easier to just re-use this one mechanism for all symbol resolution. This has
234 the added benefit that the user has full control over the symbol resolution
233 be easier to re-use this one mechanism for all symbol resolution.) This has the
234 added benefit that the user has full control over the symbol resolution
235235 process. Should we search for definitions within the JIT first, then fall back
236236 on external definitions? Or should we prefer external definitions where
237237 available and only JIT code if we don't already have an available
262262 module, returning a "symbol not found" error.
263263
264264 Now that we've built our symbol resolver, we're ready to add our module to the
265 JIT. We do this by calling the CompileLayer's addModuleSet method [4]_. Since
266 we only have a single Module and addModuleSet expects a collection, we will
267 create a vector of modules and add our module as the only member. Since we
268 have already typedef'd our ModuleHandleT type to be the same as the
269 CompileLayer's handle type, we can return the handle from addModuleSet
270 directly from our addModule method.
265 JIT. We do this by calling the CompileLayer's addModule method. The addModule
266 method returns an ``Expected``, since in more
267 advanced JIT configurations it could fail. In our basic configuration we know
268 that it will always succeed so we use the cantFail utility to assert that no
269 error occurred, and extract the handle value. Since we have already typedef'd
270 our ModuleHandle type to be the same as the CompileLayer's handle type, we can
271 return the unwrapped handle directly.
271272
272273 .. code-block:: c++
273274
278279 return CompileLayer.findSymbol(MangledNameStream.str(), true);
279280 }
280281
282 JITTargetAddress getSymbolAddress(const std::string Name) {
283 return cantFail(findSymbol(Name).getAddress());
284 }
285
281286 void removeModule(ModuleHandle H) {
282 CompileLayer.removeModuleSet(H);
287 cantFail(CompileLayer.removeModule(H));
283288 }
284289
285290 Now that we can add code to our JIT, we need a way to find the symbols we've
286 added to it. To do that we call the findSymbol method on our IRCompileLayer,
287 but with a twist: We have to *mangle* the name of the symbol we're searching
288 for first. The reason for this is that the ORC JIT components use mangled
289 symbols internally the same way a static compiler and linker would, rather
290 than using plain IR symbol names. The kind of mangling will depend on the
291 DataLayout, which in turn depends on the target platform. To allow us to
292 remain portable and search based on the un-mangled name, we just re-produce
293 this mangling ourselves.
291 added to it. To do that we call the findSymbol method on our CompileLayer, but
292 with a twist: We have to *mangle* the name of the symbol we're searching for
293 first. The ORC JIT components use mangled symbols internally the same way a
294 static compiler and linker would, rather than using plain IR symbol names. This
295 allows JIT'd code to interoperate easily with precompiled code in the
296 application or shared libraries. The kind of mangling will depend on the
297 DataLayout, which in turn depends on the target platform. To allow us to remain
298 portable and search based on the un-mangled name, we just re-produce this
299 mangling ourselves.
300
301 Next we have a convenience function, getSymbolAddress, which returns the address
302 of a given symbol. Like CompileLayer's addModule function, JITSymbol's getAddress
303 function is allowed to fail [4]_, however we know that it will not in our simple
304 example, so we wrap it in a call to cantFail.
294305
295306 We now come to the last method in our JIT API: removeModule. This method is
296307 responsible for destructing the MemoryManager and SymbolResolver that were
301312 entered. It is generally good to free any module that you know you won't need
302313 to call further, just to free up the resources dedicated to it. However, you
303314 don't strictly need to do this: All resources will be cleaned up when your
304 JIT class is destructed, if they haven't been freed before then.
315 JIT class is destructed, if they haven't been freed before then. Like
316 ``CompileLayer::addModule`` and ``JITSymbol::getAddress``, removeModule may
317 fail in general but will never fail in our example, so we wrap it in a call to
318 cantFail.
305319
306320 This brings us to the end of Chapter 1 of Building a JIT. You now have a basic
307321 but fully functioning JIT stack that you can use to take LLVM IR and make it
339353 .. [2] +-----------------------+-----------------------------------------------+
340354 | File | Reason for inclusion |
341355 +=======================+===============================================+
356 | STLExtras.h | LLVM utilities that are useful when working |
357 | | with the STL. |
358 +-----------------------+-----------------------------------------------+
342359 | ExecutionEngine.h | Access to the EngineBuilder::selectTarget |
343360 | | method. |
344361 +-----------------------+-----------------------------------------------+
362379 | DynamicLibrary.h | Provides the DynamicLibrary class, which |
363380 | | makes symbols in the host process searchable. |
364381 +-----------------------+-----------------------------------------------+
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 +-----------------------+-----------------------------------------------+
365388
366389 .. [3] Actually they don't have to be lambdas, any object with a call operator
367390 will do, including plain old functions or std::functions.
368391
369 .. [4] ORC layers accept sets of Modules, rather than individual ones, so that
370 all Modules in the set could be co-located by the memory manager, though
371 this feature is not yet implemented.
392 .. [4] ``JITSymbol::getAddress`` will force the JIT to compile the definition of
393 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.
8585 return CompileLayer.findSymbol(MangledNameStream.str(), true);
8686 }
8787
88 JITTargetAddress getSymbolAddress(const std::string Name) {
89 return cantFail(findSymbol(Name).getAddress());
90 }
91
8892 void removeModule(ModuleHandle H) {
8993 cantFail(CompileLayer.removeModule(H));
9094 }
11431143 auto H = TheJIT->addModule(std::move(TheModule));
11441144 InitializeModule();
11451145
1146 // Search the JIT for the __anon_expr symbol.
1147 auto ExprSymbol = TheJIT->findSymbol("__anon_expr");
1148 assert(ExprSymbol && "Function not found");
1149
1150 // Get the symbol's address and cast it to the right type (takes no
1151 // arguments, returns a double) so we can call it as a native function.
1152 double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
1146 // Get the anonymous expression's address and cast it to the right type,
1147 // double(*)(), so we can call it as a native function.
1148 double (*FP)() =
1149 (double (*)())(intptr_t)TheJIT->getSymbolAddress("__anon_expr");
1150 assert(FP && "Failed to codegen function");
11531151 fprintf(stderr, "Evaluated to %f\n", FP());
11541152
11551153 // Delete the anonymous expression module from the JIT.