2015-01-15 Richard Sandiford <richard.sandiford@arm.com>
[official-gcc.git] / gcc / jit / docs / cp / intro / tutorial02.rst
blobde260b8cc4c2d12928f02ac7714654e39f7fa2b1
1 .. Copyright (C) 2014-2015 Free Software Foundation, Inc.
2    Originally contributed by David Malcolm <dmalcolm@redhat.com>
4    This is free software: you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see
16    <http://www.gnu.org/licenses/>.
18 .. default-domain:: cpp
20 Tutorial part 2: Creating a trivial machine code function
21 ---------------------------------------------------------
23 Consider this C function:
25 .. code-block:: c
27    int square (int i)
28    {
29      return i * i;
30    }
32 How can we construct this at run-time using libgccjit's C++ API?
34 First we need to include the relevant header:
36 .. code-block:: c++
38   #include <libgccjit++.h>
40 All state associated with compilation is associated with a
41 :type:`gccjit::context`, which is a thin C++ wrapper around the C API's
42 :c:type:`gcc_jit_context *`.
44 Create one using :func:`gccjit::context::acquire`:
46 .. code-block:: c++
48   gccjit::context ctxt;
49   ctxt = gccjit::context::acquire ();
51 The JIT library has a system of types.  It is statically-typed: every
52 expression is of a specific type, fixed at compile-time.  In our example,
53 all of the expressions are of the C `int` type, so let's obtain this from
54 the context, as a :type:`gccjit::type`, using
55 :func:`gccjit::context::get_type`:
57 .. code-block:: c++
59   gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
61 :type:`gccjit::type` is an example of a "contextual" object: every
62 entity in the API is associated with a :type:`gccjit::context`.
64 Memory management is easy: all such "contextual" objects are automatically
65 cleaned up for you when the context is released, using
66 :func:`gccjit::context::release`:
68 .. code-block:: c++
70   ctxt.release ();
72 so you don't need to manually track and cleanup all objects, just the
73 contexts.
75 All of the C++ classes in the API are thin wrappers around pointers to
76 types in the C API.
78 The C++ class hierarchy within the ``gccjit`` namespace looks like this::
80   +- object
81       +- location
82       +- type
83          +- struct
84       +- field
85       +- function
86       +- block
87       +- rvalue
88           +- lvalue
89              +- param
91 One thing you can do with a :type:`gccjit::object` is
92 to ask it for a human-readable description as a :type:`std::string`, using
93 :func:`gccjit::object::get_debug_string`:
95 .. code-block:: c++
97    printf ("obj: %s\n", obj.get_debug_string ().c_str ());
99 giving this text on stdout:
101 .. code-block:: bash
103    obj: int
105 This is invaluable when debugging.
107 Let's create the function.  To do so, we first need to construct
108 its single parameter, specifying its type and giving it a name,
109 using :func:`gccjit::context::new_param`:
111 .. code-block:: c++
113   gccjit::param param_i = ctxt.new_param (int_type, "i");
115 and we can then make a vector of all of the params of the function,
116 in this case just one:
118 .. code-block:: c++
120   std::vector<gccjit::param> params;
121   params.push_back (param_i);
123 Now we can create the function, using
124 :c:func:`gccjit::context::new_function`:
126 .. code-block:: c++
128   gccjit::function func =
129     ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
130                        int_type,
131                        "square",
132                        params,
133                        0);
135 To define the code within the function, we must create basic blocks
136 containing statements.
138 Every basic block contains a list of statements, eventually terminated
139 by a statement that either returns, or jumps to another basic block.
141 Our function has no control-flow, so we just need one basic block:
143 .. code-block:: c++
145   gccjit::block block = func.new_block ();
147 Our basic block is relatively simple: it immediately terminates by
148 returning the value of an expression.
150 We can build the expression using :func:`gccjit::context::new_binary_op`:
152 .. code-block:: c++
154    gccjit::rvalue expr =
155      ctxt.new_binary_op (
156        GCC_JIT_BINARY_OP_MULT, int_type,
157        param_i, param_i);
159 A :type:`gccjit::rvalue` is another example of a
160 :type:`gccjit::object` subclass.  As before, we can print it with
161 :func:`gccjit::object::get_debug_string`.
163 .. code-block:: c++
165    printf ("expr: %s\n", expr.get_debug_string ().c_str ());
167 giving this output:
169 .. code-block:: bash
171    expr: i * i
173 Note that :type:`gccjit::rvalue` provides numerous overloaded operators
174 which can be used to dramatically reduce the amount of typing needed.
175 We can build the above binary operation more directly with this one-liner:
177 .. code-block:: c++
179    gccjit::rvalue expr = param_i * param_i;
181 Creating the expression in itself doesn't do anything; we have to add
182 this expression to a statement within the block.  In this case, we use it
183 to build a return statement, which terminates the basic block:
185 .. code-block:: c++
187   block.end_with_return (expr);
189 OK, we've populated the context.  We can now compile it using
190 :func:`gccjit::context::compile`:
192 .. code-block:: c++
194    gcc_jit_result *result;
195    result = ctxt.compile ();
197 and get a :c:type:`gcc_jit_result *`.
199 We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
200 machine code routine within the result, in this case, the function we
201 created above.
203 .. code-block:: c++
205    void *fn_ptr = gcc_jit_result_get_code (result, "square");
206    if (!fn_ptr)
207      {
208        fprintf (stderr, "NULL fn_ptr");
209        goto error;
210      }
212 We can now cast the pointer to an appropriate function pointer type, and
213 then call it:
215 .. code-block:: c++
217   typedef int (*fn_type) (int);
218   fn_type square = (fn_type)fn_ptr;
219   printf ("result: %d", square (5));
221 .. code-block:: bash
223   result: 25
226 Options
227 *******
229 To get more information on what's going on, you can set debugging flags
230 on the context using :func:`gccjit::context::set_bool_option`.
232 .. (I'm deliberately not mentioning
233     :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
234     it's probably more of use to implementors than to users)
236 Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
237 C-like representation to stderr when you compile (GCC's "GIMPLE"
238 representation):
240 .. code-block:: c++
242    ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
243    result = ctxt.compile ();
245 .. code-block:: c
247   square (signed int i)
248   {
249     signed int D.260;
251     entry:
252     D.260 = i * i;
253     return D.260;
254   }
256 We can see the generated machine code in assembler form (on stderr) by
257 setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
258 before compiling:
260 .. code-block:: c++
262   ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 1);
263   result = ctxt.compile ();
265 .. code-block:: gas
267         .file   "fake.c"
268         .text
269         .globl  square
270         .type   square, @function
271   square:
272   .LFB6:
273         .cfi_startproc
274         pushq   %rbp
275         .cfi_def_cfa_offset 16
276         .cfi_offset 6, -16
277         movq    %rsp, %rbp
278         .cfi_def_cfa_register 6
279         movl    %edi, -4(%rbp)
280   .L14:
281         movl    -4(%rbp), %eax
282         imull   -4(%rbp), %eax
283         popq    %rbp
284         .cfi_def_cfa 7, 8
285         ret
286         .cfi_endproc
287   .LFE6:
288         .size   square, .-square
289         .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
290         .section       .note.GNU-stack,"",@progbits
292 By default, no optimizations are performed, the equivalent of GCC's
293 `-O0` option.  We can turn things up to e.g. `-O3` by calling
294 :func:`gccjit::context::set_int_option` with
295 :c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
297 .. code-block:: c++
299   ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
301 .. code-block:: gas
303         .file   "fake.c"
304         .text
305         .p2align 4,,15
306         .globl  square
307         .type   square, @function
308   square:
309   .LFB7:
310         .cfi_startproc
311   .L16:
312         movl    %edi, %eax
313         imull   %edi, %eax
314         ret
315         .cfi_endproc
316   .LFE7:
317         .size   square, .-square
318         .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
319         .section        .note.GNU-stack,"",@progbits
321 Naturally this has only a small effect on such a trivial function.
324 Full example
325 ************
327 Here's what the above looks like as a complete program:
329    .. literalinclude:: ../../examples/tut02-square.cc
330     :lines: 1-
331     :language: c++
333 Building and running it:
335 .. code-block:: console
337   $ gcc \
338       tut02-square.cc \
339       -o tut02-square \
340       -lgccjit
342   # Run the built program:
343   $ ./tut02-square
344   result: 25