diff options
Diffstat (limited to 'llvm/docs/tutorial/LangImpl08.rst')
-rw-r--r-- | llvm/docs/tutorial/LangImpl08.rst | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/llvm/docs/tutorial/LangImpl08.rst b/llvm/docs/tutorial/LangImpl08.rst new file mode 100644 index 00000000000..b2eeb35ae3a --- /dev/null +++ b/llvm/docs/tutorial/LangImpl08.rst @@ -0,0 +1,218 @@ +======================================== + Kaleidoscope: Compiling to Object Code +======================================== + +.. contents:: + :local: + +Chapter 8 Introduction +====================== + +Welcome to Chapter 8 of the "`Implementing a language with LLVM +<index.html>`_" tutorial. This chapter describes how to compile our +language down to object files. + +Choosing a target +================= + +LLVM has native support for cross-compilation. You can compile to the +architecture of your current machine, or just as easily compile for +other architectures. In this tutorial, we'll target the current +machine. + +To specify the architecture that you want to target, we use a string +called a "target triple". This takes the form +``<arch><sub>-<vendor>-<sys>-<abi>`` (see the `cross compilation docs +<http://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_). + +As an example, we can see what clang thinks is our current target +triple: + +:: + + $ clang --version | grep Target + Target: x86_64-unknown-linux-gnu + +Running this command may show something different on your machine as +you might be using a different architecture or operating system to me. + +Fortunately, we don't need to hard-code a target triple to target the +current machine. LLVM provides ``sys::getDefaultTargetTriple``, which +returns the target triple of the current machine. + +.. code-block:: c++ + + auto TargetTriple = sys::getDefaultTargetTriple(); + +LLVM doesn't require us to to link in all the target +functionality. For example, if we're just using the JIT, we don't need +the assembly printers. Similarly, if we're only targetting certain +architectures, we can only link in the functionality for those +architectures. + +For this example, we'll initialize all the targets for emitting object +code. + +.. code-block:: c++ + + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + +We can now use our target triple to get a ``Target``: + +.. code-block:: c++ + + std::string Error; + auto Target = TargetRegistry::lookupTarget(TargetTriple, Error); + + // Print an error and exit if we couldn't find the requested target. + // This generally occurs if we've forgotten to initialise the + // TargetRegistry or we have a bogus target triple. + if (!Target) { + errs() << Error; + return 1; + } + +Target Machine +============== + +We will also need a ``TargetMachine``. This class provides a complete +machine description of the machine we're targetting. If we want to +target a specific feature (such as SSE) or a specific CPU (such as +Intel's Sandylake), we do so now. + +To see which features and CPUs that LLVM knows about, we can use +``llc``. For example, let's look at x86: + +:: + + $ llvm-as < /dev/null | llc -march=x86 -mattr=help + Available CPUs for this target: + + amdfam10 - Select the amdfam10 processor. + athlon - Select the athlon processor. + athlon-4 - Select the athlon-4 processor. + ... + + Available features for this target: + + 16bit-mode - 16-bit mode (i8086). + 32bit-mode - 32-bit mode (80386). + 3dnow - Enable 3DNow! instructions. + 3dnowa - Enable 3DNow! Athlon instructions. + ... + +For our example, we'll use the generic CPU without any additional +features, options or relocation model. + +.. code-block:: c++ + + auto CPU = "generic"; + auto Features = ""; + + TargetOptions opt; + auto RM = Optional<Reloc::Model>(); + auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); + + +Configuring the Module +====================== + +We're now ready to configure our module, to specify the target and +data layout. This isn't strictly necessary, but the `frontend +performance guide <../Frontend/PerformanceTips.html>`_ recommends +this. Optimizations benefit from knowing about the target and data +layout. + +.. code-block:: c++ + + TheModule->setDataLayout(TargetMachine->createDataLayout()); + TheModule->setTargetTriple(TargetTriple); + +Emit Object Code +================ + +We're ready to emit object code! Let's define where we want to write +our file to: + +.. code-block:: c++ + + auto Filename = "output.o"; + std::error_code EC; + raw_fd_ostream dest(Filename, EC, sys::fs::F_None); + + if (EC) { + errs() << "Could not open file: " << EC.message(); + return 1; + } + +Finally, we define a pass that emits object code, then we run that +pass: + +.. code-block:: c++ + + legacy::PassManager pass; + auto FileType = TargetMachine::CGFT_ObjectFile; + + if (TargetMachine->addPassesToEmitFile(pass, dest, FileType)) { + errs() << "TargetMachine can't emit a file of this type"; + return 1; + } + + pass.run(*TheModule); + dest.flush(); + +Putting It All Together +======================= + +Does it work? Let's give it a try. We need to compile our code, but +note that the arguments to ``llvm-config`` are different to the previous chapters. + +:: + + $ clang++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs all` -o toy + +Let's run it, and define a simple ``average`` function. Press Ctrl-D +when you're done. + +:: + + $ ./toy + ready> def average(x y) (x + y) * 0.5; + ^D + Wrote output.o + +We have an object file! To test it, let's write a simple program and +link it with our output. Here's the source code: + +.. code-block:: c++ + + #include <iostream> + + extern "C" { + double average(double, double); + } + + int main() { + std::cout << "average of 3.0 and 4.0: " << average(3.0, 4.0) << std::endl; + } + +We link our program to output.o and check the result is what we +expected: + +:: + + $ clang++ main.cpp output.o -o main + $ ./main + average of 3.0 and 4.0: 3.5 + +Full Code Listing +================= + +.. literalinclude:: ../../examples/Kaleidoscope/Chapter8/toy.cpp + :language: c++ + +`Next: Adding Debug Information <LangImpl09.html>`_ |