diff options
Diffstat (limited to 'llvm/docs/tutorial/LangImpl04.rst')
-rw-r--r-- | llvm/docs/tutorial/LangImpl04.rst | 77 |
1 files changed, 58 insertions, 19 deletions
diff --git a/llvm/docs/tutorial/LangImpl04.rst b/llvm/docs/tutorial/LangImpl04.rst index 513bf8f4ab4..16d7164ae15 100644 --- a/llvm/docs/tutorial/LangImpl04.rst +++ b/llvm/docs/tutorial/LangImpl04.rst @@ -131,33 +131,29 @@ for us: void InitializeModuleAndPassManager(void) { // Open a new module. - Context LLVMContext; - TheModule = llvm::make_unique<Module>("my cool jit", LLVMContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheModule = llvm::make_unique<Module>("my cool jit", TheContext); // Create a new pass manager attached to it. TheFPM = llvm::make_unique<FunctionPassManager>(TheModule.get()); - // Provide basic AliasAnalysis support for GVN. - TheFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. - TheFPM.add(createInstructionCombiningPass()); + TheFPM->add(createInstructionCombiningPass()); // Reassociate expressions. - TheFPM.add(createReassociatePass()); + TheFPM->add(createReassociatePass()); // Eliminate Common SubExpressions. - TheFPM.add(createGVNPass()); + TheFPM->add(createGVNPass()); // Simplify the control flow graph (deleting unreachable blocks, etc). - TheFPM.add(createCFGSimplificationPass()); + TheFPM->add(createCFGSimplificationPass()); - TheFPM.doInitialization(); + 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 five passes: one analysis pass (alias analysis), -and four optimization passes. The passes we choose here are a pretty standard set +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 :). @@ -227,8 +223,10 @@ 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 declare and initialize the JIT. This is -done by adding a global variable ``TheJIT``, and initializing it in +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++ @@ -236,7 +234,21 @@ done by adding a global variable ``TheJIT``, and initializing it in 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. @@ -245,9 +257,24 @@ done by adding a global variable ``TheJIT``, and initializing it in 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. 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:: +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 @@ -554,7 +581,10 @@ 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. +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 @@ -567,12 +597,21 @@ if we add: .. code-block:: c++ + #ifdef LLVM_ON_WIN32 + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT + #endif + /// putchard - putchar that takes a double and returns 0. - extern "C" double putchard(double X) { + 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 |