2015-01-15 Richard Sandiford <richard.sandiford@arm.com>
[official-gcc.git] / gcc / jit / docs / intro / tutorial02.rst
blob196ac44de60bfe14d848003f9ca23d47fbe73fd9
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:: c
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?
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 :c:type:`gcc_jit_context *`.
43 Create one using :c:func:`gcc_jit_context_acquire`:
45 .. code-block:: c
47   gcc_jit_context *ctxt;
48   ctxt = gcc_jit_context_acquire ();
50 The JIT library has a system of types.  It is statically-typed: every
51 expression is of a specific type, fixed at compile-time.  In our example,
52 all of the expressions are of the C `int` type, so let's obtain this from
53 the context, as a :c:type:`gcc_jit_type *`, using
54 :c:func:`gcc_jit_context_get_type`:
56 .. code-block:: c
58   gcc_jit_type *int_type =
59     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
61 :c:type:`gcc_jit_type *` is an example of a "contextual" object: every
62 entity in the API is associated with a :c:type:`gcc_jit_context *`.
64 Memory management is easy: all such "contextual" objects are automatically
65 cleaned up for you when the context is released, using
66 :c:func:`gcc_jit_context_release`:
68 .. code-block:: c
70   gcc_jit_context_release (ctxt);
72 so you don't need to manually track and cleanup all objects, just the
73 contexts.
75 Although the API is C-based, there is a form of class hierarchy, which
76 looks like this::
78   +- gcc_jit_object
79       +- gcc_jit_location
80       +- gcc_jit_type
81          +- gcc_jit_struct
82       +- gcc_jit_field
83       +- gcc_jit_function
84       +- gcc_jit_block
85       +- gcc_jit_rvalue
86           +- gcc_jit_lvalue
87              +- gcc_jit_param
89 There are casting methods for upcasting from subclasses to parent classes.
90 For example, :c:func:`gcc_jit_type_as_object`:
92 .. code-block:: c
94    gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
96 One thing you can do with a :c:type:`gcc_jit_object *` is
97 to ask it for a human-readable description, using
98 :c:func:`gcc_jit_object_get_debug_string`:
100 .. code-block:: c
102    printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
104 giving this text on stdout:
106 .. code-block:: bash
108    obj: int
110 This is invaluable when debugging.
112 Let's create the function.  To do so, we first need to construct
113 its single parameter, specifying its type and giving it a name,
114 using :c:func:`gcc_jit_context_new_param`:
116 .. code-block:: c
118   gcc_jit_param *param_i =
119     gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
121 Now we can create the function, using
122 :c:func:`gcc_jit_context_new_function`:
124 .. code-block:: c
126   gcc_jit_function *func =
127     gcc_jit_context_new_function (ctxt, NULL,
128                                   GCC_JIT_FUNCTION_EXPORTED,
129                                   int_type,
130                                   "square",
131                                   1, &param_i,
132                                   0);
134 To define the code within the function, we must create basic blocks
135 containing statements.
137 Every basic block contains a list of statements, eventually terminated
138 by a statement that either returns, or jumps to another basic block.
140 Our function has no control-flow, so we just need one basic block:
142 .. code-block:: c
144   gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
146 Our basic block is relatively simple: it immediately terminates by
147 returning the value of an expression.
149 We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
151 .. code-block:: c
153    gcc_jit_rvalue *expr =
154      gcc_jit_context_new_binary_op (
155        ctxt, NULL,
156        GCC_JIT_BINARY_OP_MULT, int_type,
157        gcc_jit_param_as_rvalue (param_i),
158        gcc_jit_param_as_rvalue (param_i));
160 A :c:type:`gcc_jit_rvalue *` is another example of a
161 :c:type:`gcc_jit_object *` subclass.  We can upcast it using
162 :c:func:`gcc_jit_rvalue_as_object` and as before print it with
163 :c:func:`gcc_jit_object_get_debug_string`.
165 .. code-block:: c
167    printf ("expr: %s\n",
168            gcc_jit_object_get_debug_string (
169              gcc_jit_rvalue_as_object (expr)));
171 giving this output:
173 .. code-block:: bash
175    expr: i * i
177 Creating the expression in itself doesn't do anything; we have to add
178 this expression to a statement within the block.  In this case, we use it
179 to build a return statement, which terminates the basic block:
181 .. code-block:: c
183   gcc_jit_block_end_with_return (block, NULL, expr);
185 OK, we've populated the context.  We can now compile it using
186 :c:func:`gcc_jit_context_compile`:
188 .. code-block:: c
190    gcc_jit_result *result;
191    result = gcc_jit_context_compile (ctxt);
193 and get a :c:type:`gcc_jit_result *`.
195 At this point we're done with the context; we can release it:
197 .. code-block:: c
199    gcc_jit_context_release (ctxt);
201 We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
202 machine code routine within the result, in this case, the function we
203 created above.
205 .. code-block:: c
207    void *fn_ptr = gcc_jit_result_get_code (result, "square");
208    if (!fn_ptr)
209      {
210        fprintf (stderr, "NULL fn_ptr");
211        goto error;
212      }
214 We can now cast the pointer to an appropriate function pointer type, and
215 then call it:
217 .. code-block:: c
219   typedef int (*fn_type) (int);
220   fn_type square = (fn_type)fn_ptr;
221   printf ("result: %d", square (5));
223 .. code-block:: bash
225   result: 25
227 Once we're done with the code, we can release the result:
229 .. code-block:: c
231    gcc_jit_result_release (result);
233 We can't call ``square`` anymore once we've released ``result``.
236 Error-handling
237 **************
238 Various kinds of errors are possible when using the API, such as
239 mismatched types in an assignment.  You can only compile and get code
240 from a context if no errors occur.
242 Errors are printed on stderr; they typically contain the name of the API
243 entrypoint where the error occurred, and pertinent information on the
244 problem:
246 .. code-block:: console
248   ./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *)
250 The API is designed to cope with errors without crashing, so you can get
251 away with having a single error-handling check in your code:
253 .. code-block:: c
255    void *fn_ptr = gcc_jit_result_get_code (result, "square");
256    if (!fn_ptr)
257      {
258        fprintf (stderr, "NULL fn_ptr");
259        goto error;
260      }
262 For more information, see the :ref:`error-handling guide <error-handling>`
263 within the Topic eference.
266 Options
267 *******
269 To get more information on what's going on, you can set debugging flags
270 on the context using :c:func:`gcc_jit_context_set_bool_option`.
272 .. (I'm deliberately not mentioning
273     :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
274     it's probably more of use to implementors than to users)
276 Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
277 C-like representation to stderr when you compile (GCC's "GIMPLE"
278 representation):
280 .. code-block:: c
282    gcc_jit_context_set_bool_option (
283      ctxt,
284      GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
285      1);
286    result = gcc_jit_context_compile (ctxt);
288 .. code-block:: c
290   square (signed int i)
291   {
292     signed int D.260;
294     entry:
295     D.260 = i * i;
296     return D.260;
297   }
299 We can see the generated machine code in assembler form (on stderr) by
300 setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
301 before compiling:
303 .. code-block:: c
305   gcc_jit_context_set_bool_option (
306     ctxt,
307     GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
308     1);
309   result = gcc_jit_context_compile (ctxt);
311 .. code-block:: gas
313         .file   "fake.c"
314         .text
315         .globl  square
316         .type   square, @function
317   square:
318   .LFB6:
319         .cfi_startproc
320         pushq   %rbp
321         .cfi_def_cfa_offset 16
322         .cfi_offset 6, -16
323         movq    %rsp, %rbp
324         .cfi_def_cfa_register 6
325         movl    %edi, -4(%rbp)
326   .L14:
327         movl    -4(%rbp), %eax
328         imull   -4(%rbp), %eax
329         popq    %rbp
330         .cfi_def_cfa 7, 8
331         ret
332         .cfi_endproc
333   .LFE6:
334         .size   square, .-square
335         .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
336         .section       .note.GNU-stack,"",@progbits
338 By default, no optimizations are performed, the equivalent of GCC's
339 `-O0` option.  We can turn things up to e.g. `-O3` by calling
340 :c:func:`gcc_jit_context_set_int_option` with
341 :c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
343 .. code-block:: c
345   gcc_jit_context_set_int_option (
346     ctxt,
347     GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
348     3);
350 .. code-block:: gas
352         .file   "fake.c"
353         .text
354         .p2align 4,,15
355         .globl  square
356         .type   square, @function
357   square:
358   .LFB7:
359         .cfi_startproc
360   .L16:
361         movl    %edi, %eax
362         imull   %edi, %eax
363         ret
364         .cfi_endproc
365   .LFE7:
366         .size   square, .-square
367         .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
368         .section        .note.GNU-stack,"",@progbits
370 Naturally this has only a small effect on such a trivial function.
373 Full example
374 ************
376 Here's what the above looks like as a complete program:
378    .. literalinclude:: ../examples/tut02-square.c
379     :lines: 1-
380     :language: c
382 Building and running it:
384 .. code-block:: console
386   $ gcc \
387       tut02-square.c \
388       -o tut02-square \
389       -lgccjit
391   # Run the built program:
392   $ ./tut02-square
393   result: 25