You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
218
external/llvm/docs/tutorial/LangImpl08.rst
vendored
218
external/llvm/docs/tutorial/LangImpl08.rst
vendored
@ -1,218 +0,0 @@
|
||||
========================================
|
||||
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 targeting 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 targeting. 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>`_
|
Reference in New Issue
Block a user