]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/docs/intro/tutorial02.rst
Update copyright years.
[thirdparty/gcc.git] / gcc / jit / docs / intro / tutorial02.rst
CommitLineData
8d9254fc 1.. Copyright (C) 2014-2020 Free Software Foundation, Inc.
35485da9
DM
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
81ba15f1
DM
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
35485da9
DM
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
e250f0dc
DM
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
35485da9
DM
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