annotate gcc/jit/docs/intro/tutorial02.rst @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 .. Copyright (C) 2014-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2 Originally contributed by David Malcolm <dmalcolm@redhat.com>
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This is free software: you can redistribute it and/or modify it
kono
parents:
diff changeset
5 under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
6 the Free Software Foundation, either version 3 of the License, or
kono
parents:
diff changeset
7 (at your option) any later version.
kono
parents:
diff changeset
8
kono
parents:
diff changeset
9 This program is distributed in the hope that it will be useful, but
kono
parents:
diff changeset
10 WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kono
parents:
diff changeset
12 General Public License for more details.
kono
parents:
diff changeset
13
kono
parents:
diff changeset
14 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
15 along with this program. If not, see
kono
parents:
diff changeset
16 <http://www.gnu.org/licenses/>.
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 .. default-domain:: c
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 Tutorial part 2: Creating a trivial machine code function
kono
parents:
diff changeset
21 ---------------------------------------------------------
kono
parents:
diff changeset
22
kono
parents:
diff changeset
23 Consider this C function:
kono
parents:
diff changeset
24
kono
parents:
diff changeset
25 .. code-block:: c
kono
parents:
diff changeset
26
kono
parents:
diff changeset
27 int square (int i)
kono
parents:
diff changeset
28 {
kono
parents:
diff changeset
29 return i * i;
kono
parents:
diff changeset
30 }
kono
parents:
diff changeset
31
kono
parents:
diff changeset
32 How can we construct this at run-time using libgccjit?
kono
parents:
diff changeset
33
kono
parents:
diff changeset
34 First we need to include the relevant header:
kono
parents:
diff changeset
35
kono
parents:
diff changeset
36 .. code-block:: c
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 #include <libgccjit.h>
kono
parents:
diff changeset
39
kono
parents:
diff changeset
40 All state associated with compilation is associated with a
kono
parents:
diff changeset
41 :c:type:`gcc_jit_context *`.
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43 Create one using :c:func:`gcc_jit_context_acquire`:
kono
parents:
diff changeset
44
kono
parents:
diff changeset
45 .. code-block:: c
kono
parents:
diff changeset
46
kono
parents:
diff changeset
47 gcc_jit_context *ctxt;
kono
parents:
diff changeset
48 ctxt = gcc_jit_context_acquire ();
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 The JIT library has a system of types. It is statically-typed: every
kono
parents:
diff changeset
51 expression is of a specific type, fixed at compile-time. In our example,
kono
parents:
diff changeset
52 all of the expressions are of the C `int` type, so let's obtain this from
kono
parents:
diff changeset
53 the context, as a :c:type:`gcc_jit_type *`, using
kono
parents:
diff changeset
54 :c:func:`gcc_jit_context_get_type`:
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 .. code-block:: c
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 gcc_jit_type *int_type =
kono
parents:
diff changeset
59 gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 :c:type:`gcc_jit_type *` is an example of a "contextual" object: every
kono
parents:
diff changeset
62 entity in the API is associated with a :c:type:`gcc_jit_context *`.
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 Memory management is easy: all such "contextual" objects are automatically
kono
parents:
diff changeset
65 cleaned up for you when the context is released, using
kono
parents:
diff changeset
66 :c:func:`gcc_jit_context_release`:
kono
parents:
diff changeset
67
kono
parents:
diff changeset
68 .. code-block:: c
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 gcc_jit_context_release (ctxt);
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 so you don't need to manually track and cleanup all objects, just the
kono
parents:
diff changeset
73 contexts.
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 Although the API is C-based, there is a form of class hierarchy, which
kono
parents:
diff changeset
76 looks like this::
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 +- gcc_jit_object
kono
parents:
diff changeset
79 +- gcc_jit_location
kono
parents:
diff changeset
80 +- gcc_jit_type
kono
parents:
diff changeset
81 +- gcc_jit_struct
kono
parents:
diff changeset
82 +- gcc_jit_field
kono
parents:
diff changeset
83 +- gcc_jit_function
kono
parents:
diff changeset
84 +- gcc_jit_block
kono
parents:
diff changeset
85 +- gcc_jit_rvalue
kono
parents:
diff changeset
86 +- gcc_jit_lvalue
kono
parents:
diff changeset
87 +- gcc_jit_param
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 There are casting methods for upcasting from subclasses to parent classes.
kono
parents:
diff changeset
90 For example, :c:func:`gcc_jit_type_as_object`:
kono
parents:
diff changeset
91
kono
parents:
diff changeset
92 .. code-block:: c
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 One thing you can do with a :c:type:`gcc_jit_object *` is
kono
parents:
diff changeset
97 to ask it for a human-readable description, using
kono
parents:
diff changeset
98 :c:func:`gcc_jit_object_get_debug_string`:
kono
parents:
diff changeset
99
kono
parents:
diff changeset
100 .. code-block:: c
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 giving this text on stdout:
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106 .. code-block:: bash
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 obj: int
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 This is invaluable when debugging.
kono
parents:
diff changeset
111
kono
parents:
diff changeset
112 Let's create the function. To do so, we first need to construct
kono
parents:
diff changeset
113 its single parameter, specifying its type and giving it a name,
kono
parents:
diff changeset
114 using :c:func:`gcc_jit_context_new_param`:
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 .. code-block:: c
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 gcc_jit_param *param_i =
kono
parents:
diff changeset
119 gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
kono
parents:
diff changeset
120
kono
parents:
diff changeset
121 Now we can create the function, using
kono
parents:
diff changeset
122 :c:func:`gcc_jit_context_new_function`:
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 .. code-block:: c
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 gcc_jit_function *func =
kono
parents:
diff changeset
127 gcc_jit_context_new_function (ctxt, NULL,
kono
parents:
diff changeset
128 GCC_JIT_FUNCTION_EXPORTED,
kono
parents:
diff changeset
129 int_type,
kono
parents:
diff changeset
130 "square",
kono
parents:
diff changeset
131 1, &param_i,
kono
parents:
diff changeset
132 0);
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 To define the code within the function, we must create basic blocks
kono
parents:
diff changeset
135 containing statements.
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 Every basic block contains a list of statements, eventually terminated
kono
parents:
diff changeset
138 by a statement that either returns, or jumps to another basic block.
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 Our function has no control-flow, so we just need one basic block:
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 .. code-block:: c
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 Our basic block is relatively simple: it immediately terminates by
kono
parents:
diff changeset
147 returning the value of an expression.
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 .. code-block:: c
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 gcc_jit_rvalue *expr =
kono
parents:
diff changeset
154 gcc_jit_context_new_binary_op (
kono
parents:
diff changeset
155 ctxt, NULL,
kono
parents:
diff changeset
156 GCC_JIT_BINARY_OP_MULT, int_type,
kono
parents:
diff changeset
157 gcc_jit_param_as_rvalue (param_i),
kono
parents:
diff changeset
158 gcc_jit_param_as_rvalue (param_i));
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 A :c:type:`gcc_jit_rvalue *` is another example of a
kono
parents:
diff changeset
161 :c:type:`gcc_jit_object *` subclass. We can upcast it using
kono
parents:
diff changeset
162 :c:func:`gcc_jit_rvalue_as_object` and as before print it with
kono
parents:
diff changeset
163 :c:func:`gcc_jit_object_get_debug_string`.
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 .. code-block:: c
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 printf ("expr: %s\n",
kono
parents:
diff changeset
168 gcc_jit_object_get_debug_string (
kono
parents:
diff changeset
169 gcc_jit_rvalue_as_object (expr)));
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 giving this output:
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 .. code-block:: bash
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 expr: i * i
kono
parents:
diff changeset
176
kono
parents:
diff changeset
177 Creating the expression in itself doesn't do anything; we have to add
kono
parents:
diff changeset
178 this expression to a statement within the block. In this case, we use it
kono
parents:
diff changeset
179 to build a return statement, which terminates the basic block:
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 .. code-block:: c
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 gcc_jit_block_end_with_return (block, NULL, expr);
kono
parents:
diff changeset
184
kono
parents:
diff changeset
185 OK, we've populated the context. We can now compile it using
kono
parents:
diff changeset
186 :c:func:`gcc_jit_context_compile`:
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 .. code-block:: c
kono
parents:
diff changeset
189
kono
parents:
diff changeset
190 gcc_jit_result *result;
kono
parents:
diff changeset
191 result = gcc_jit_context_compile (ctxt);
kono
parents:
diff changeset
192
kono
parents:
diff changeset
193 and get a :c:type:`gcc_jit_result *`.
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 At this point we're done with the context; we can release it:
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 .. code-block:: c
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 gcc_jit_context_release (ctxt);
kono
parents:
diff changeset
200
kono
parents:
diff changeset
201 We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
kono
parents:
diff changeset
202 machine code routine within the result, in this case, the function we
kono
parents:
diff changeset
203 created above.
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 .. code-block:: c
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 void *fn_ptr = gcc_jit_result_get_code (result, "square");
kono
parents:
diff changeset
208 if (!fn_ptr)
kono
parents:
diff changeset
209 {
kono
parents:
diff changeset
210 fprintf (stderr, "NULL fn_ptr");
kono
parents:
diff changeset
211 goto error;
kono
parents:
diff changeset
212 }
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 We can now cast the pointer to an appropriate function pointer type, and
kono
parents:
diff changeset
215 then call it:
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 .. code-block:: c
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 typedef int (*fn_type) (int);
kono
parents:
diff changeset
220 fn_type square = (fn_type)fn_ptr;
kono
parents:
diff changeset
221 printf ("result: %d", square (5));
kono
parents:
diff changeset
222
kono
parents:
diff changeset
223 .. code-block:: bash
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 result: 25
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 Once we're done with the code, we can release the result:
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 .. code-block:: c
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 gcc_jit_result_release (result);
kono
parents:
diff changeset
232
kono
parents:
diff changeset
233 We can't call ``square`` anymore once we've released ``result``.
kono
parents:
diff changeset
234
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 Error-handling
kono
parents:
diff changeset
237 **************
kono
parents:
diff changeset
238 Various kinds of errors are possible when using the API, such as
kono
parents:
diff changeset
239 mismatched types in an assignment. You can only compile and get code
kono
parents:
diff changeset
240 from a context if no errors occur.
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242 Errors are printed on stderr; they typically contain the name of the API
kono
parents:
diff changeset
243 entrypoint where the error occurred, and pertinent information on the
kono
parents:
diff changeset
244 problem:
kono
parents:
diff changeset
245
kono
parents:
diff changeset
246 .. code-block:: console
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 ./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *)
kono
parents:
diff changeset
249
kono
parents:
diff changeset
250 The API is designed to cope with errors without crashing, so you can get
kono
parents:
diff changeset
251 away with having a single error-handling check in your code:
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 .. code-block:: c
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 void *fn_ptr = gcc_jit_result_get_code (result, "square");
kono
parents:
diff changeset
256 if (!fn_ptr)
kono
parents:
diff changeset
257 {
kono
parents:
diff changeset
258 fprintf (stderr, "NULL fn_ptr");
kono
parents:
diff changeset
259 goto error;
kono
parents:
diff changeset
260 }
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 For more information, see the :ref:`error-handling guide <error-handling>`
kono
parents:
diff changeset
263 within the Topic eference.
kono
parents:
diff changeset
264
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 Options
kono
parents:
diff changeset
267 *******
kono
parents:
diff changeset
268
kono
parents:
diff changeset
269 To get more information on what's going on, you can set debugging flags
kono
parents:
diff changeset
270 on the context using :c:func:`gcc_jit_context_set_bool_option`.
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 .. (I'm deliberately not mentioning
kono
parents:
diff changeset
273 :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
kono
parents:
diff changeset
274 it's probably more of use to implementors than to users)
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
kono
parents:
diff changeset
277 C-like representation to stderr when you compile (GCC's "GIMPLE"
kono
parents:
diff changeset
278 representation):
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 .. code-block:: c
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 gcc_jit_context_set_bool_option (
kono
parents:
diff changeset
283 ctxt,
kono
parents:
diff changeset
284 GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
kono
parents:
diff changeset
285 1);
kono
parents:
diff changeset
286 result = gcc_jit_context_compile (ctxt);
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 .. code-block:: c
kono
parents:
diff changeset
289
kono
parents:
diff changeset
290 square (signed int i)
kono
parents:
diff changeset
291 {
kono
parents:
diff changeset
292 signed int D.260;
kono
parents:
diff changeset
293
kono
parents:
diff changeset
294 entry:
kono
parents:
diff changeset
295 D.260 = i * i;
kono
parents:
diff changeset
296 return D.260;
kono
parents:
diff changeset
297 }
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 We can see the generated machine code in assembler form (on stderr) by
kono
parents:
diff changeset
300 setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
kono
parents:
diff changeset
301 before compiling:
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 .. code-block:: c
kono
parents:
diff changeset
304
kono
parents:
diff changeset
305 gcc_jit_context_set_bool_option (
kono
parents:
diff changeset
306 ctxt,
kono
parents:
diff changeset
307 GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
kono
parents:
diff changeset
308 1);
kono
parents:
diff changeset
309 result = gcc_jit_context_compile (ctxt);
kono
parents:
diff changeset
310
kono
parents:
diff changeset
311 .. code-block:: gas
kono
parents:
diff changeset
312
kono
parents:
diff changeset
313 .file "fake.c"
kono
parents:
diff changeset
314 .text
kono
parents:
diff changeset
315 .globl square
kono
parents:
diff changeset
316 .type square, @function
kono
parents:
diff changeset
317 square:
kono
parents:
diff changeset
318 .LFB6:
kono
parents:
diff changeset
319 .cfi_startproc
kono
parents:
diff changeset
320 pushq %rbp
kono
parents:
diff changeset
321 .cfi_def_cfa_offset 16
kono
parents:
diff changeset
322 .cfi_offset 6, -16
kono
parents:
diff changeset
323 movq %rsp, %rbp
kono
parents:
diff changeset
324 .cfi_def_cfa_register 6
kono
parents:
diff changeset
325 movl %edi, -4(%rbp)
kono
parents:
diff changeset
326 .L14:
kono
parents:
diff changeset
327 movl -4(%rbp), %eax
kono
parents:
diff changeset
328 imull -4(%rbp), %eax
kono
parents:
diff changeset
329 popq %rbp
kono
parents:
diff changeset
330 .cfi_def_cfa 7, 8
kono
parents:
diff changeset
331 ret
kono
parents:
diff changeset
332 .cfi_endproc
kono
parents:
diff changeset
333 .LFE6:
kono
parents:
diff changeset
334 .size square, .-square
kono
parents:
diff changeset
335 .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
kono
parents:
diff changeset
336 .section .note.GNU-stack,"",@progbits
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 By default, no optimizations are performed, the equivalent of GCC's
kono
parents:
diff changeset
339 `-O0` option. We can turn things up to e.g. `-O3` by calling
kono
parents:
diff changeset
340 :c:func:`gcc_jit_context_set_int_option` with
kono
parents:
diff changeset
341 :c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
kono
parents:
diff changeset
342
kono
parents:
diff changeset
343 .. code-block:: c
kono
parents:
diff changeset
344
kono
parents:
diff changeset
345 gcc_jit_context_set_int_option (
kono
parents:
diff changeset
346 ctxt,
kono
parents:
diff changeset
347 GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
kono
parents:
diff changeset
348 3);
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 .. code-block:: gas
kono
parents:
diff changeset
351
kono
parents:
diff changeset
352 .file "fake.c"
kono
parents:
diff changeset
353 .text
kono
parents:
diff changeset
354 .p2align 4,,15
kono
parents:
diff changeset
355 .globl square
kono
parents:
diff changeset
356 .type square, @function
kono
parents:
diff changeset
357 square:
kono
parents:
diff changeset
358 .LFB7:
kono
parents:
diff changeset
359 .cfi_startproc
kono
parents:
diff changeset
360 .L16:
kono
parents:
diff changeset
361 movl %edi, %eax
kono
parents:
diff changeset
362 imull %edi, %eax
kono
parents:
diff changeset
363 ret
kono
parents:
diff changeset
364 .cfi_endproc
kono
parents:
diff changeset
365 .LFE7:
kono
parents:
diff changeset
366 .size square, .-square
kono
parents:
diff changeset
367 .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
kono
parents:
diff changeset
368 .section .note.GNU-stack,"",@progbits
kono
parents:
diff changeset
369
kono
parents:
diff changeset
370 Naturally this has only a small effect on such a trivial function.
kono
parents:
diff changeset
371
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 Full example
kono
parents:
diff changeset
374 ************
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 Here's what the above looks like as a complete program:
kono
parents:
diff changeset
377
kono
parents:
diff changeset
378 .. literalinclude:: ../examples/tut02-square.c
kono
parents:
diff changeset
379 :lines: 1-
kono
parents:
diff changeset
380 :language: c
kono
parents:
diff changeset
381
kono
parents:
diff changeset
382 Building and running it:
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 .. code-block:: console
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 $ gcc \
kono
parents:
diff changeset
387 tut02-square.c \
kono
parents:
diff changeset
388 -o tut02-square \
kono
parents:
diff changeset
389 -lgccjit
kono
parents:
diff changeset
390
kono
parents:
diff changeset
391 # Run the built program:
kono
parents:
diff changeset
392 $ ./tut02-square
kono
parents:
diff changeset
393 result: 25