reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
:orphan:

========================================
 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 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::OF_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, nullptr, 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>`_