1.. Copyright (C) 2014-2020 Free Software Foundation, Inc.
2   Originally contributed by David Malcolm <dmalcolm@redhat.com>
3
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.
8
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.
13
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/>.
17
18.. default-domain:: c
19
20Tutorial part 2: Creating a trivial machine code function
21---------------------------------------------------------
22
23Consider this C function:
24
25.. code-block:: c
26
27   int square (int i)
28   {
29     return i * i;
30   }
31
32How can we construct this at run-time using libgccjit?
33
34First we need to include the relevant header:
35
36.. code-block:: c
37
38  #include <libgccjit.h>
39
40All state associated with compilation is associated with a
41:c:type:`gcc_jit_context *`.
42
43Create one using :c:func:`gcc_jit_context_acquire`:
44
45.. code-block:: c
46
47  gcc_jit_context *ctxt;
48  ctxt = gcc_jit_context_acquire ();
49
50The JIT library has a system of types.  It is statically-typed: every
51expression is of a specific type, fixed at compile-time.  In our example,
52all of the expressions are of the C `int` type, so let's obtain this from
53the context, as a :c:type:`gcc_jit_type *`, using
54:c:func:`gcc_jit_context_get_type`:
55
56.. code-block:: c
57
58  gcc_jit_type *int_type =
59    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
60
61:c:type:`gcc_jit_type *` is an example of a "contextual" object: every
62entity in the API is associated with a :c:type:`gcc_jit_context *`.
63
64Memory management is easy: all such "contextual" objects are automatically
65cleaned up for you when the context is released, using
66:c:func:`gcc_jit_context_release`:
67
68.. code-block:: c
69
70  gcc_jit_context_release (ctxt);
71
72so you don't need to manually track and cleanup all objects, just the
73contexts.
74
75Although the API is C-based, there is a form of class hierarchy, which
76looks like this::
77
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
88
89There are casting methods for upcasting from subclasses to parent classes.
90For example, :c:func:`gcc_jit_type_as_object`:
91
92.. code-block:: c
93
94   gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
95
96One thing you can do with a :c:type:`gcc_jit_object *` is
97to ask it for a human-readable description, using
98:c:func:`gcc_jit_object_get_debug_string`:
99
100.. code-block:: c
101
102   printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
103
104giving this text on stdout:
105
106.. code-block:: bash
107
108   obj: int
109
110This is invaluable when debugging.
111
112Let's create the function.  To do so, we first need to construct
113its single parameter, specifying its type and giving it a name,
114using :c:func:`gcc_jit_context_new_param`:
115
116.. code-block:: c
117
118  gcc_jit_param *param_i =
119    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
120
121Now we can create the function, using
122:c:func:`gcc_jit_context_new_function`:
123
124.. code-block:: c
125
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);
133
134To define the code within the function, we must create basic blocks
135containing statements.
136
137Every basic block contains a list of statements, eventually terminated
138by a statement that either returns, or jumps to another basic block.
139
140Our function has no control-flow, so we just need one basic block:
141
142.. code-block:: c
143
144  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
145
146Our basic block is relatively simple: it immediately terminates by
147returning the value of an expression.
148
149We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
150
151.. code-block:: c
152
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));
159
160A :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`.
164
165.. code-block:: c
166
167   printf ("expr: %s\n",
168           gcc_jit_object_get_debug_string (
169             gcc_jit_rvalue_as_object (expr)));
170
171giving this output:
172
173.. code-block:: bash
174
175   expr: i * i
176
177Creating the expression in itself doesn't do anything; we have to add
178this expression to a statement within the block.  In this case, we use it
179to build a return statement, which terminates the basic block:
180
181.. code-block:: c
182
183  gcc_jit_block_end_with_return (block, NULL, expr);
184
185OK, we've populated the context.  We can now compile it using
186:c:func:`gcc_jit_context_compile`:
187
188.. code-block:: c
189
190   gcc_jit_result *result;
191   result = gcc_jit_context_compile (ctxt);
192
193and get a :c:type:`gcc_jit_result *`.
194
195At this point we're done with the context; we can release it:
196
197.. code-block:: c
198
199   gcc_jit_context_release (ctxt);
200
201We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
202machine code routine within the result, in this case, the function we
203created above.
204
205.. code-block:: c
206
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     }
213
214We can now cast the pointer to an appropriate function pointer type, and
215then call it:
216
217.. code-block:: c
218
219  typedef int (*fn_type) (int);
220  fn_type square = (fn_type)fn_ptr;
221  printf ("result: %d", square (5));
222
223.. code-block:: bash
224
225  result: 25
226
227Once we're done with the code, we can release the result:
228
229.. code-block:: c
230
231   gcc_jit_result_release (result);
232
233We can't call ``square`` anymore once we've released ``result``.
234
235
236Error-handling
237**************
238Various kinds of errors are possible when using the API, such as
239mismatched types in an assignment.  You can only compile and get code
240from a context if no errors occur.
241
242Errors are printed on stderr; they typically contain the name of the API
243entrypoint where the error occurred, and pertinent information on the
244problem:
245
246.. code-block:: console
247
248  ./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *)
249
250The API is designed to cope with errors without crashing, so you can get
251away with having a single error-handling check in your code:
252
253.. code-block:: c
254
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     }
261
262For more information, see the :ref:`error-handling guide <error-handling>`
263within the Topic eference.
264
265
266Options
267*******
268
269To get more information on what's going on, you can set debugging flags
270on the context using :c:func:`gcc_jit_context_set_bool_option`.
271
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)
275
276Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
277C-like representation to stderr when you compile (GCC's "GIMPLE"
278representation):
279
280.. code-block:: c
281
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);
287
288.. code-block:: c
289
290  square (signed int i)
291  {
292    signed int D.260;
293
294    entry:
295    D.260 = i * i;
296    return D.260;
297  }
298
299We can see the generated machine code in assembler form (on stderr) by
300setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
301before compiling:
302
303.. code-block:: c
304
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);
310
311.. code-block:: gas
312
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
337
338By 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`:
342
343.. code-block:: c
344
345  gcc_jit_context_set_int_option (
346    ctxt,
347    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
348    3);
349
350.. code-block:: gas
351
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
369
370Naturally this has only a small effect on such a trivial function.
371
372
373Full example
374************
375
376Here's what the above looks like as a complete program:
377
378   .. literalinclude:: ../examples/tut02-square.c
379    :lines: 1-
380    :language: c
381
382Building and running it:
383
384.. code-block:: console
385
386  $ gcc \
387      tut02-square.c \
388      -o tut02-square \
389      -lgccjit
390
391  # Run the built program:
392  $ ./tut02-square
393  result: 25
394