| ============================================== | 
 | Kaleidoscope: Adding JIT and Optimizer Support | 
 | ============================================== | 
 |  | 
 | .. contents:: | 
 |    :local: | 
 |  | 
 | Chapter 4 Introduction | 
 | ====================== | 
 |  | 
 | Welcome to Chapter 4 of the "`Implementing a language with | 
 | LLVM <index.html>`_" tutorial. Chapters 1-3 described the implementation | 
 | of a simple language and added support for generating LLVM IR. This | 
 | chapter describes two new techniques: adding optimizer support to your | 
 | language, and adding JIT compiler support. These additions will | 
 | demonstrate how to get nice, efficient code for the Kaleidoscope | 
 | language. | 
 |  | 
 | Trivial Constant Folding | 
 | ======================== | 
 |  | 
 | Our demonstration for Chapter 3 is elegant and easy to extend. | 
 | Unfortunately, it does not produce wonderful code. The IRBuilder, | 
 | however, does give us obvious optimizations when compiling simple code: | 
 |  | 
 | :: | 
 |  | 
 |     ready> def test(x) 1+2+x; | 
 |     Read function definition: | 
 |     define double @test(double %x) { | 
 |     entry: | 
 |             %addtmp = fadd double 3.000000e+00, %x | 
 |             ret double %addtmp | 
 |     } | 
 |  | 
 | This code is not a literal transcription of the AST built by parsing the | 
 | input. That would be: | 
 |  | 
 | :: | 
 |  | 
 |     ready> def test(x) 1+2+x; | 
 |     Read function definition: | 
 |     define double @test(double %x) { | 
 |     entry: | 
 |             %addtmp = fadd double 2.000000e+00, 1.000000e+00 | 
 |             %addtmp1 = fadd double %addtmp, %x | 
 |             ret double %addtmp1 | 
 |     } | 
 |  | 
 | Constant folding, as seen above, in particular, is a very common and | 
 | very important optimization: so much so that many language implementors | 
 | implement constant folding support in their AST representation. | 
 |  | 
 | With LLVM, you don't need this support in the AST. Since all calls to | 
 | build LLVM IR go through the LLVM IR builder, the builder itself checked | 
 | to see if there was a constant folding opportunity when you call it. If | 
 | so, it just does the constant fold and return the constant instead of | 
 | creating an instruction. | 
 |  | 
 | Well, that was easy :). In practice, we recommend always using | 
 | ``IRBuilder`` when generating code like this. It has no "syntactic | 
 | overhead" for its use (you don't have to uglify your compiler with | 
 | constant checks everywhere) and it can dramatically reduce the amount of | 
 | LLVM IR that is generated in some cases (particular for languages with a | 
 | macro preprocessor or that use a lot of constants). | 
 |  | 
 | On the other hand, the ``IRBuilder`` is limited by the fact that it does | 
 | all of its analysis inline with the code as it is built. If you take a | 
 | slightly more complex example: | 
 |  | 
 | :: | 
 |  | 
 |     ready> def test(x) (1+2+x)*(x+(1+2)); | 
 |     ready> Read function definition: | 
 |     define double @test(double %x) { | 
 |     entry: | 
 |             %addtmp = fadd double 3.000000e+00, %x | 
 |             %addtmp1 = fadd double %x, 3.000000e+00 | 
 |             %multmp = fmul double %addtmp, %addtmp1 | 
 |             ret double %multmp | 
 |     } | 
 |  | 
 | In this case, the LHS and RHS of the multiplication are the same value. | 
 | We'd really like to see this generate "``tmp = x+3; result = tmp*tmp;``" | 
 | instead of computing "``x+3``" twice. | 
 |  | 
 | Unfortunately, no amount of local analysis will be able to detect and | 
 | correct this. This requires two transformations: reassociation of | 
 | expressions (to make the add's lexically identical) and Common | 
 | Subexpression Elimination (CSE) to delete the redundant add instruction. | 
 | Fortunately, LLVM provides a broad range of optimizations that you can | 
 | use, in the form of "passes". | 
 |  | 
 | LLVM Optimization Passes | 
 | ======================== | 
 |  | 
 | LLVM provides many optimization passes, which do many different sorts of | 
 | things and have different tradeoffs. Unlike other systems, LLVM doesn't | 
 | hold to the mistaken notion that one set of optimizations is right for | 
 | all languages and for all situations. LLVM allows a compiler implementor | 
 | to make complete decisions about what optimizations to use, in which | 
 | order, and in what situation. | 
 |  | 
 | As a concrete example, LLVM supports both "whole module" passes, which | 
 | look across as large of body of code as they can (often a whole file, | 
 | but if run at link time, this can be a substantial portion of the whole | 
 | program). It also supports and includes "per-function" passes which just | 
 | operate on a single function at a time, without looking at other | 
 | functions. For more information on passes and how they are run, see the | 
 | `How to Write a Pass <../WritingAnLLVMPass.html>`_ document and the | 
 | `List of LLVM Passes <../Passes.html>`_. | 
 |  | 
 | For Kaleidoscope, we are currently generating functions on the fly, one | 
 | at a time, as the user types them in. We aren't shooting for the | 
 | ultimate optimization experience in this setting, but we also want to | 
 | catch the easy and quick stuff where possible. As such, we will choose | 
 | to run a few per-function optimizations as the user types the function | 
 | in. If we wanted to make a "static Kaleidoscope compiler", we would use | 
 | exactly the code we have now, except that we would defer running the | 
 | optimizer until the entire file has been parsed. | 
 |  | 
 | In order to get per-function optimizations going, we need to set up a | 
 | `FunctionPassManager <../WritingAnLLVMPass.html#what-passmanager-doesr>`_ to hold | 
 | and organize the LLVM optimizations that we want to run. Once we have | 
 | that, we can add a set of optimizations to run. We'll need a new | 
 | FunctionPassManager for each module that we want to optimize, so we'll | 
 | write a function to create and initialize both the module and pass manager | 
 | for us: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     void InitializeModuleAndPassManager(void) { | 
 |       // Open a new module. | 
 |       TheModule = llvm::make_unique<Module>("my cool jit", TheContext); | 
 |  | 
 |       // Create a new pass manager attached to it. | 
 |       TheFPM = llvm::make_unique<FunctionPassManager>(TheModule.get()); | 
 |  | 
 |       // Do simple "peephole" optimizations and bit-twiddling optzns. | 
 |       TheFPM->add(createInstructionCombiningPass()); | 
 |       // Reassociate expressions. | 
 |       TheFPM->add(createReassociatePass()); | 
 |       // Eliminate Common SubExpressions. | 
 |       TheFPM->add(createGVNPass()); | 
 |       // Simplify the control flow graph (deleting unreachable blocks, etc). | 
 |       TheFPM->add(createCFGSimplificationPass()); | 
 |  | 
 |       TheFPM->doInitialization(); | 
 |     } | 
 |  | 
 | This code initializes the global module ``TheModule``, and the function pass | 
 | manager ``TheFPM``, which is attached to ``TheModule``. Once the pass manager is | 
 | set up, we use a series of "add" calls to add a bunch of LLVM passes. | 
 |  | 
 | In this case, we choose to add four optimization passes. | 
 | The passes we choose here are a pretty standard set | 
 | of "cleanup" optimizations that are useful for a wide variety of code. I won't | 
 | delve into what they do but, believe me, they are a good starting place :). | 
 |  | 
 | Once the PassManager is set up, we need to make use of it. We do this by | 
 | running it after our newly created function is constructed (in | 
 | ``FunctionAST::codegen()``), but before it is returned to the client: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |       if (Value *RetVal = Body->codegen()) { | 
 |         // Finish off the function. | 
 |         Builder.CreateRet(RetVal); | 
 |  | 
 |         // Validate the generated code, checking for consistency. | 
 |         verifyFunction(*TheFunction); | 
 |  | 
 |         // Optimize the function. | 
 |         TheFPM->run(*TheFunction); | 
 |  | 
 |         return TheFunction; | 
 |       } | 
 |  | 
 | As you can see, this is pretty straightforward. The | 
 | ``FunctionPassManager`` optimizes and updates the LLVM Function\* in | 
 | place, improving (hopefully) its body. With this in place, we can try | 
 | our test above again: | 
 |  | 
 | :: | 
 |  | 
 |     ready> def test(x) (1+2+x)*(x+(1+2)); | 
 |     ready> Read function definition: | 
 |     define double @test(double %x) { | 
 |     entry: | 
 |             %addtmp = fadd double %x, 3.000000e+00 | 
 |             %multmp = fmul double %addtmp, %addtmp | 
 |             ret double %multmp | 
 |     } | 
 |  | 
 | As expected, we now get our nicely optimized code, saving a floating | 
 | point add instruction from every execution of this function. | 
 |  | 
 | LLVM provides a wide variety of optimizations that can be used in | 
 | certain circumstances. Some `documentation about the various | 
 | passes <../Passes.html>`_ is available, but it isn't very complete. | 
 | Another good source of ideas can come from looking at the passes that | 
 | ``Clang`` runs to get started. The "``opt``" tool allows you to | 
 | experiment with passes from the command line, so you can see if they do | 
 | anything. | 
 |  | 
 | Now that we have reasonable code coming out of our front-end, let's talk | 
 | about executing it! | 
 |  | 
 | Adding a JIT Compiler | 
 | ===================== | 
 |  | 
 | Code that is available in LLVM IR can have a wide variety of tools | 
 | applied to it. For example, you can run optimizations on it (as we did | 
 | above), you can dump it out in textual or binary forms, you can compile | 
 | the code to an assembly file (.s) for some target, or you can JIT | 
 | compile it. The nice thing about the LLVM IR representation is that it | 
 | is the "common currency" between many different parts of the compiler. | 
 |  | 
 | In this section, we'll add JIT compiler support to our interpreter. The | 
 | basic idea that we want for Kaleidoscope is to have the user enter | 
 | function bodies as they do now, but immediately evaluate the top-level | 
 | expressions they type in. For example, if they type in "1 + 2;", we | 
 | should evaluate and print out 3. If they define a function, they should | 
 | be able to call it from the command line. | 
 |  | 
 | In order to do this, we first prepare the environment to create code for | 
 | the current native target and declare and initialize the JIT. This is | 
 | done by calling some ``InitializeNativeTarget\*`` functions and | 
 | adding a global variable ``TheJIT``, and initializing it in | 
 | ``main``: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     static std::unique_ptr<KaleidoscopeJIT> TheJIT; | 
 |     ... | 
 |     int main() { | 
 |       InitializeNativeTarget(); | 
 |       InitializeNativeTargetAsmPrinter(); | 
 |       InitializeNativeTargetAsmParser(); | 
 |  | 
 |       // Install standard binary operators. | 
 |       // 1 is lowest precedence. | 
 |       BinopPrecedence['<'] = 10; | 
 |       BinopPrecedence['+'] = 20; | 
 |       BinopPrecedence['-'] = 20; | 
 |       BinopPrecedence['*'] = 40; // highest. | 
 |  | 
 |       // Prime the first token. | 
 |       fprintf(stderr, "ready> "); | 
 |       getNextToken(); | 
 |  | 
 |       TheJIT = llvm::make_unique<KaleidoscopeJIT>(); | 
 |  | 
 |       // Run the main "interpreter loop" now. | 
 |       MainLoop(); | 
 |  | 
 |       return 0; | 
 |     } | 
 |  | 
 | We also need to setup the data layout for the JIT: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     void InitializeModuleAndPassManager(void) { | 
 |       // Open a new module. | 
 |       TheModule = llvm::make_unique<Module>("my cool jit", TheContext); | 
 |       TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); | 
 |  | 
 |       // Create a new pass manager attached to it. | 
 |       TheFPM = llvm::make_unique<FunctionPassManager>(TheModule.get()); | 
 |       ... | 
 |  | 
 | The KaleidoscopeJIT class is a simple JIT built specifically for these | 
 | tutorials, available inside the LLVM source code | 
 | at llvm-src/examples/Kaleidoscope/include/KaleidoscopeJIT.h. | 
 | In later chapters we will look at how it works and extend it with | 
 | new features, but for now we will take it as given. Its API is very simple: | 
 | ``addModule`` adds an LLVM IR module to the JIT, making its functions | 
 | available for execution; ``removeModule`` removes a module, freeing any | 
 | memory associated with the code in that module; and ``findSymbol`` allows us | 
 | to look up pointers to the compiled code. | 
 |  | 
 | We can take this simple API and change our code that parses top-level expressions to | 
 | look like this: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     static void HandleTopLevelExpression() { | 
 |       // Evaluate a top-level expression into an anonymous function. | 
 |       if (auto FnAST = ParseTopLevelExpr()) { | 
 |         if (FnAST->codegen()) { | 
 |  | 
 |           // JIT the module containing the anonymous expression, keeping a handle so | 
 |           // we can free it later. | 
 |           auto H = TheJIT->addModule(std::move(TheModule)); | 
 |           InitializeModuleAndPassManager(); | 
 |  | 
 |           // Search the JIT for the __anon_expr symbol. | 
 |           auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); | 
 |           assert(ExprSymbol && "Function not found"); | 
 |  | 
 |           // Get the symbol's address and cast it to the right type (takes no | 
 |           // arguments, returns a double) so we can call it as a native function. | 
 |           double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); | 
 |           fprintf(stderr, "Evaluated to %f\n", FP()); | 
 |  | 
 |           // Delete the anonymous expression module from the JIT. | 
 |           TheJIT->removeModule(H); | 
 |         } | 
 |  | 
 | If parsing and codegen succeeed, the next step is to add the module containing | 
 | the top-level expression to the JIT. We do this by calling addModule, which | 
 | triggers code generation for all the functions in the module, and returns a | 
 | handle that can be used to remove the module from the JIT later. Once the module | 
 | has been added to the JIT it can no longer be modified, so we also open a new | 
 | module to hold subsequent code by calling ``InitializeModuleAndPassManager()``. | 
 |  | 
 | Once we've added the module to the JIT we need to get a pointer to the final | 
 | generated code. We do this by calling the JIT's findSymbol method, and passing | 
 | the name of the top-level expression function: ``__anon_expr``. Since we just | 
 | added this function, we assert that findSymbol returned a result. | 
 |  | 
 | Next, we get the in-memory address of the ``__anon_expr`` function by calling | 
 | ``getAddress()`` on the symbol. Recall that we compile top-level expressions | 
 | into a self-contained LLVM function that takes no arguments and returns the | 
 | computed double. Because the LLVM JIT compiler matches the native platform ABI, | 
 | this means that you can just cast the result pointer to a function pointer of | 
 | that type and call it directly. This means, there is no difference between JIT | 
 | compiled code and native machine code that is statically linked into your | 
 | application. | 
 |  | 
 | Finally, since we don't support re-evaluation of top-level expressions, we | 
 | remove the module from the JIT when we're done to free the associated memory. | 
 | Recall, however, that the module we created a few lines earlier (via | 
 | ``InitializeModuleAndPassManager``) is still open and waiting for new code to be | 
 | added. | 
 |  | 
 | With just these two changes, let's see how Kaleidoscope works now! | 
 |  | 
 | :: | 
 |  | 
 |     ready> 4+5; | 
 |     Read top-level expression: | 
 |     define double @0() { | 
 |     entry: | 
 |       ret double 9.000000e+00 | 
 |     } | 
 |  | 
 |     Evaluated to 9.000000 | 
 |  | 
 | Well this looks like it is basically working. The dump of the function | 
 | shows the "no argument function that always returns double" that we | 
 | synthesize for each top-level expression that is typed in. This | 
 | demonstrates very basic functionality, but can we do more? | 
 |  | 
 | :: | 
 |  | 
 |     ready> def testfunc(x y) x + y*2; | 
 |     Read function definition: | 
 |     define double @testfunc(double %x, double %y) { | 
 |     entry: | 
 |       %multmp = fmul double %y, 2.000000e+00 | 
 |       %addtmp = fadd double %multmp, %x | 
 |       ret double %addtmp | 
 |     } | 
 |  | 
 |     ready> testfunc(4, 10); | 
 |     Read top-level expression: | 
 |     define double @1() { | 
 |     entry: | 
 |       %calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01) | 
 |       ret double %calltmp | 
 |     } | 
 |  | 
 |     Evaluated to 24.000000 | 
 |  | 
 |     ready> testfunc(5, 10); | 
 |     ready> LLVM ERROR: Program used external function 'testfunc' which could not be resolved! | 
 |  | 
 |  | 
 | Function definitions and calls also work, but something went very wrong on that | 
 | last line. The call looks valid, so what happened? As you may have guessed from | 
 | the API a Module is a unit of allocation for the JIT, and testfunc was part | 
 | of the same module that contained anonymous expression. When we removed that | 
 | module from the JIT to free the memory for the anonymous expression, we deleted | 
 | the definition of ``testfunc`` along with it. Then, when we tried to call | 
 | testfunc a second time, the JIT could no longer find it. | 
 |  | 
 | The easiest way to fix this is to put the anonymous expression in a separate | 
 | module from the rest of the function definitions. The JIT will happily resolve | 
 | function calls across module boundaries, as long as each of the functions called | 
 | has a prototype, and is added to the JIT before it is called. By putting the | 
 | anonymous expression in a different module we can delete it without affecting | 
 | the rest of the functions. | 
 |  | 
 | In fact, we're going to go a step further and put every function in its own | 
 | module. Doing so allows us to exploit a useful property of the KaleidoscopeJIT | 
 | that will make our environment more REPL-like: Functions can be added to the | 
 | JIT more than once (unlike a module where every function must have a unique | 
 | definition). When you look up a symbol in KaleidoscopeJIT it will always return | 
 | the most recent definition: | 
 |  | 
 | :: | 
 |  | 
 |     ready> def foo(x) x + 1; | 
 |     Read function definition: | 
 |     define double @foo(double %x) { | 
 |     entry: | 
 |       %addtmp = fadd double %x, 1.000000e+00 | 
 |       ret double %addtmp | 
 |     } | 
 |  | 
 |     ready> foo(2); | 
 |     Evaluated to 3.000000 | 
 |  | 
 |     ready> def foo(x) x + 2; | 
 |     define double @foo(double %x) { | 
 |     entry: | 
 |       %addtmp = fadd double %x, 2.000000e+00 | 
 |       ret double %addtmp | 
 |     } | 
 |  | 
 |     ready> foo(2); | 
 |     Evaluated to 4.000000 | 
 |  | 
 |  | 
 | To allow each function to live in its own module we'll need a way to | 
 | re-generate previous function declarations into each new module we open: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     static std::unique_ptr<KaleidoscopeJIT> TheJIT; | 
 |  | 
 |     ... | 
 |  | 
 |     Function *getFunction(std::string Name) { | 
 |       // First, see if the function has already been added to the current module. | 
 |       if (auto *F = TheModule->getFunction(Name)) | 
 |         return F; | 
 |  | 
 |       // If not, check whether we can codegen the declaration from some existing | 
 |       // prototype. | 
 |       auto FI = FunctionProtos.find(Name); | 
 |       if (FI != FunctionProtos.end()) | 
 |         return FI->second->codegen(); | 
 |  | 
 |       // If no existing prototype exists, return null. | 
 |       return nullptr; | 
 |     } | 
 |  | 
 |     ... | 
 |  | 
 |     Value *CallExprAST::codegen() { | 
 |       // Look up the name in the global module table. | 
 |       Function *CalleeF = getFunction(Callee); | 
 |  | 
 |     ... | 
 |  | 
 |     Function *FunctionAST::codegen() { | 
 |       // Transfer ownership of the prototype to the FunctionProtos map, but keep a | 
 |       // reference to it for use below. | 
 |       auto &P = *Proto; | 
 |       FunctionProtos[Proto->getName()] = std::move(Proto); | 
 |       Function *TheFunction = getFunction(P.getName()); | 
 |       if (!TheFunction) | 
 |         return nullptr; | 
 |  | 
 |  | 
 | To enable this, we'll start by adding a new global, ``FunctionProtos``, that | 
 | holds the most recent prototype for each function. We'll also add a convenience | 
 | method, ``getFunction()``, to replace calls to ``TheModule->getFunction()``. | 
 | Our convenience method searches ``TheModule`` for an existing function | 
 | declaration, falling back to generating a new declaration from FunctionProtos if | 
 | it doesn't find one. In ``CallExprAST::codegen()`` we just need to replace the | 
 | call to ``TheModule->getFunction()``. In ``FunctionAST::codegen()`` we need to | 
 | update the FunctionProtos map first, then call ``getFunction()``. With this | 
 | done, we can always obtain a function declaration in the current module for any | 
 | previously declared function. | 
 |  | 
 | We also need to update HandleDefinition and HandleExtern: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     static void HandleDefinition() { | 
 |       if (auto FnAST = ParseDefinition()) { | 
 |         if (auto *FnIR = FnAST->codegen()) { | 
 |           fprintf(stderr, "Read function definition:"); | 
 |           FnIR->print(errs()); | 
 |           fprintf(stderr, "\n"); | 
 |           TheJIT->addModule(std::move(TheModule)); | 
 |           InitializeModuleAndPassManager(); | 
 |         } | 
 |       } else { | 
 |         // Skip token for error recovery. | 
 |          getNextToken(); | 
 |       } | 
 |     } | 
 |  | 
 |     static void HandleExtern() { | 
 |       if (auto ProtoAST = ParseExtern()) { | 
 |         if (auto *FnIR = ProtoAST->codegen()) { | 
 |           fprintf(stderr, "Read extern: "); | 
 |           FnIR->print(errs()); | 
 |           fprintf(stderr, "\n"); | 
 |           FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); | 
 |         } | 
 |       } else { | 
 |         // Skip token for error recovery. | 
 |         getNextToken(); | 
 |       } | 
 |     } | 
 |  | 
 | In HandleDefinition, we add two lines to transfer the newly defined function to | 
 | the JIT and open a new module. In HandleExtern, we just need to add one line to | 
 | add the prototype to FunctionProtos. | 
 |  | 
 | With these changes made, let's try our REPL again (I removed the dump of the | 
 | anonymous functions this time, you should get the idea by now :) : | 
 |  | 
 | :: | 
 |  | 
 |     ready> def foo(x) x + 1; | 
 |     ready> foo(2); | 
 |     Evaluated to 3.000000 | 
 |  | 
 |     ready> def foo(x) x + 2; | 
 |     ready> foo(2); | 
 |     Evaluated to 4.000000 | 
 |  | 
 | It works! | 
 |  | 
 | Even with this simple code, we get some surprisingly powerful capabilities - | 
 | check this out: | 
 |  | 
 | :: | 
 |  | 
 |     ready> extern sin(x); | 
 |     Read extern: | 
 |     declare double @sin(double) | 
 |  | 
 |     ready> extern cos(x); | 
 |     Read extern: | 
 |     declare double @cos(double) | 
 |  | 
 |     ready> sin(1.0); | 
 |     Read top-level expression: | 
 |     define double @2() { | 
 |     entry: | 
 |       ret double 0x3FEAED548F090CEE | 
 |     } | 
 |  | 
 |     Evaluated to 0.841471 | 
 |  | 
 |     ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x); | 
 |     Read function definition: | 
 |     define double @foo(double %x) { | 
 |     entry: | 
 |       %calltmp = call double @sin(double %x) | 
 |       %multmp = fmul double %calltmp, %calltmp | 
 |       %calltmp2 = call double @cos(double %x) | 
 |       %multmp4 = fmul double %calltmp2, %calltmp2 | 
 |       %addtmp = fadd double %multmp, %multmp4 | 
 |       ret double %addtmp | 
 |     } | 
 |  | 
 |     ready> foo(4.0); | 
 |     Read top-level expression: | 
 |     define double @3() { | 
 |     entry: | 
 |       %calltmp = call double @foo(double 4.000000e+00) | 
 |       ret double %calltmp | 
 |     } | 
 |  | 
 |     Evaluated to 1.000000 | 
 |  | 
 | Whoa, how does the JIT know about sin and cos? The answer is surprisingly | 
 | simple: The KaleidoscopeJIT has a straightforward symbol resolution rule that | 
 | it uses to find symbols that aren't available in any given module: First | 
 | it searches all the modules that have already been added to the JIT, from the | 
 | most recent to the oldest, to find the newest definition. If no definition is | 
 | found inside the JIT, it falls back to calling "``dlsym("sin")``" on the | 
 | Kaleidoscope process itself. Since "``sin``" is defined within the JIT's | 
 | address space, it simply patches up calls in the module to call the libm | 
 | version of ``sin`` directly. But in some cases this even goes further: | 
 | as sin and cos are names of standard math functions, the constant folder | 
 | will directly evaluate the function calls to the correct result when called | 
 | with constants like in the "``sin(1.0)``" above. | 
 |  | 
 | In the future we'll see how tweaking this symbol resolution rule can be used to | 
 | enable all sorts of useful features, from security (restricting the set of | 
 | symbols available to JIT'd code), to dynamic code generation based on symbol | 
 | names, and even lazy compilation. | 
 |  | 
 | One immediate benefit of the symbol resolution rule is that we can now extend | 
 | the language by writing arbitrary C++ code to implement operations. For example, | 
 | if we add: | 
 |  | 
 | .. code-block:: c++ | 
 |  | 
 |     #ifdef _WIN32 | 
 |     #define DLLEXPORT __declspec(dllexport) | 
 |     #else | 
 |     #define DLLEXPORT | 
 |     #endif | 
 |  | 
 |     /// putchard - putchar that takes a double and returns 0. | 
 |     extern "C" DLLEXPORT double putchard(double X) { | 
 |       fputc((char)X, stderr); | 
 |       return 0; | 
 |     } | 
 |  | 
 | Note, that for Windows we need to actually export the functions because | 
 | the dynamic symbol loader will use GetProcAddress to find the symbols. | 
 |  | 
 | Now we can produce simple output to the console by using things like: | 
 | "``extern putchard(x); putchard(120);``", which prints a lowercase 'x' | 
 | on the console (120 is the ASCII code for 'x'). Similar code could be | 
 | used to implement file I/O, console input, and many other capabilities | 
 | in Kaleidoscope. | 
 |  | 
 | This completes the JIT and optimizer chapter of the Kaleidoscope | 
 | tutorial. At this point, we can compile a non-Turing-complete | 
 | programming language, optimize and JIT compile it in a user-driven way. | 
 | Next up we'll look into `extending the language with control flow | 
 | constructs <LangImpl05.html>`_, tackling some interesting LLVM IR issues | 
 | along the way. | 
 |  | 
 | Full Code Listing | 
 | ================= | 
 |  | 
 | Here is the complete code listing for our running example, enhanced with | 
 | the LLVM JIT and optimizer. To build this example, use: | 
 |  | 
 | .. code-block:: bash | 
 |  | 
 |     # Compile | 
 |     clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core mcjit native` -O3 -o toy | 
 |     # Run | 
 |     ./toy | 
 |  | 
 | If you are compiling this on Linux, make sure to add the "-rdynamic" | 
 | option as well. This makes sure that the external functions are resolved | 
 | properly at runtime. | 
 |  | 
 | Here is the code: | 
 |  | 
 | .. literalinclude:: ../../examples/Kaleidoscope/Chapter4/toy.cpp | 
 |    :language: c++ | 
 |  | 
 | `Next: Extending the language: control flow <LangImpl05.html>`_ | 
 |  |