1*8feb0f0bSmrg.. Copyright (C) 2014-2020 Free Software Foundation, Inc. 236ac495dSmrg Originally contributed by David Malcolm <dmalcolm@redhat.com> 336ac495dSmrg 436ac495dSmrg This is free software: you can redistribute it and/or modify it 536ac495dSmrg under the terms of the GNU General Public License as published by 636ac495dSmrg the Free Software Foundation, either version 3 of the License, or 736ac495dSmrg (at your option) any later version. 836ac495dSmrg 936ac495dSmrg This program is distributed in the hope that it will be useful, but 1036ac495dSmrg WITHOUT ANY WARRANTY; without even the implied warranty of 1136ac495dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1236ac495dSmrg General Public License for more details. 1336ac495dSmrg 1436ac495dSmrg You should have received a copy of the GNU General Public License 1536ac495dSmrg along with this program. If not, see 1636ac495dSmrg <http://www.gnu.org/licenses/>. 1736ac495dSmrg 1836ac495dSmrg.. default-domain:: c 1936ac495dSmrg 2036ac495dSmrgTutorial part 2: Creating a trivial machine code function 2136ac495dSmrg--------------------------------------------------------- 2236ac495dSmrg 2336ac495dSmrgConsider this C function: 2436ac495dSmrg 2536ac495dSmrg.. code-block:: c 2636ac495dSmrg 2736ac495dSmrg int square (int i) 2836ac495dSmrg { 2936ac495dSmrg return i * i; 3036ac495dSmrg } 3136ac495dSmrg 3236ac495dSmrgHow can we construct this at run-time using libgccjit? 3336ac495dSmrg 3436ac495dSmrgFirst we need to include the relevant header: 3536ac495dSmrg 3636ac495dSmrg.. code-block:: c 3736ac495dSmrg 3836ac495dSmrg #include <libgccjit.h> 3936ac495dSmrg 4036ac495dSmrgAll state associated with compilation is associated with a 4136ac495dSmrg:c:type:`gcc_jit_context *`. 4236ac495dSmrg 4336ac495dSmrgCreate one using :c:func:`gcc_jit_context_acquire`: 4436ac495dSmrg 4536ac495dSmrg.. code-block:: c 4636ac495dSmrg 4736ac495dSmrg gcc_jit_context *ctxt; 4836ac495dSmrg ctxt = gcc_jit_context_acquire (); 4936ac495dSmrg 5036ac495dSmrgThe JIT library has a system of types. It is statically-typed: every 5136ac495dSmrgexpression is of a specific type, fixed at compile-time. In our example, 5236ac495dSmrgall of the expressions are of the C `int` type, so let's obtain this from 5336ac495dSmrgthe context, as a :c:type:`gcc_jit_type *`, using 5436ac495dSmrg:c:func:`gcc_jit_context_get_type`: 5536ac495dSmrg 5636ac495dSmrg.. code-block:: c 5736ac495dSmrg 5836ac495dSmrg gcc_jit_type *int_type = 5936ac495dSmrg gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); 6036ac495dSmrg 6136ac495dSmrg:c:type:`gcc_jit_type *` is an example of a "contextual" object: every 6236ac495dSmrgentity in the API is associated with a :c:type:`gcc_jit_context *`. 6336ac495dSmrg 6436ac495dSmrgMemory management is easy: all such "contextual" objects are automatically 6536ac495dSmrgcleaned up for you when the context is released, using 6636ac495dSmrg:c:func:`gcc_jit_context_release`: 6736ac495dSmrg 6836ac495dSmrg.. code-block:: c 6936ac495dSmrg 7036ac495dSmrg gcc_jit_context_release (ctxt); 7136ac495dSmrg 7236ac495dSmrgso you don't need to manually track and cleanup all objects, just the 7336ac495dSmrgcontexts. 7436ac495dSmrg 7536ac495dSmrgAlthough the API is C-based, there is a form of class hierarchy, which 7636ac495dSmrglooks like this:: 7736ac495dSmrg 7836ac495dSmrg +- gcc_jit_object 7936ac495dSmrg +- gcc_jit_location 8036ac495dSmrg +- gcc_jit_type 8136ac495dSmrg +- gcc_jit_struct 8236ac495dSmrg +- gcc_jit_field 8336ac495dSmrg +- gcc_jit_function 8436ac495dSmrg +- gcc_jit_block 8536ac495dSmrg +- gcc_jit_rvalue 8636ac495dSmrg +- gcc_jit_lvalue 8736ac495dSmrg +- gcc_jit_param 8836ac495dSmrg 8936ac495dSmrgThere are casting methods for upcasting from subclasses to parent classes. 9036ac495dSmrgFor example, :c:func:`gcc_jit_type_as_object`: 9136ac495dSmrg 9236ac495dSmrg.. code-block:: c 9336ac495dSmrg 9436ac495dSmrg gcc_jit_object *obj = gcc_jit_type_as_object (int_type); 9536ac495dSmrg 9636ac495dSmrgOne thing you can do with a :c:type:`gcc_jit_object *` is 9736ac495dSmrgto ask it for a human-readable description, using 9836ac495dSmrg:c:func:`gcc_jit_object_get_debug_string`: 9936ac495dSmrg 10036ac495dSmrg.. code-block:: c 10136ac495dSmrg 10236ac495dSmrg printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj)); 10336ac495dSmrg 10436ac495dSmrggiving this text on stdout: 10536ac495dSmrg 10636ac495dSmrg.. code-block:: bash 10736ac495dSmrg 10836ac495dSmrg obj: int 10936ac495dSmrg 11036ac495dSmrgThis is invaluable when debugging. 11136ac495dSmrg 11236ac495dSmrgLet's create the function. To do so, we first need to construct 11336ac495dSmrgits single parameter, specifying its type and giving it a name, 11436ac495dSmrgusing :c:func:`gcc_jit_context_new_param`: 11536ac495dSmrg 11636ac495dSmrg.. code-block:: c 11736ac495dSmrg 11836ac495dSmrg gcc_jit_param *param_i = 11936ac495dSmrg gcc_jit_context_new_param (ctxt, NULL, int_type, "i"); 12036ac495dSmrg 12136ac495dSmrgNow we can create the function, using 12236ac495dSmrg:c:func:`gcc_jit_context_new_function`: 12336ac495dSmrg 12436ac495dSmrg.. code-block:: c 12536ac495dSmrg 12636ac495dSmrg gcc_jit_function *func = 12736ac495dSmrg gcc_jit_context_new_function (ctxt, NULL, 12836ac495dSmrg GCC_JIT_FUNCTION_EXPORTED, 12936ac495dSmrg int_type, 13036ac495dSmrg "square", 13136ac495dSmrg 1, ¶m_i, 13236ac495dSmrg 0); 13336ac495dSmrg 13436ac495dSmrgTo define the code within the function, we must create basic blocks 13536ac495dSmrgcontaining statements. 13636ac495dSmrg 13736ac495dSmrgEvery basic block contains a list of statements, eventually terminated 13836ac495dSmrgby a statement that either returns, or jumps to another basic block. 13936ac495dSmrg 14036ac495dSmrgOur function has no control-flow, so we just need one basic block: 14136ac495dSmrg 14236ac495dSmrg.. code-block:: c 14336ac495dSmrg 14436ac495dSmrg gcc_jit_block *block = gcc_jit_function_new_block (func, NULL); 14536ac495dSmrg 14636ac495dSmrgOur basic block is relatively simple: it immediately terminates by 14736ac495dSmrgreturning the value of an expression. 14836ac495dSmrg 14936ac495dSmrgWe can build the expression using :c:func:`gcc_jit_context_new_binary_op`: 15036ac495dSmrg 15136ac495dSmrg.. code-block:: c 15236ac495dSmrg 15336ac495dSmrg gcc_jit_rvalue *expr = 15436ac495dSmrg gcc_jit_context_new_binary_op ( 15536ac495dSmrg ctxt, NULL, 15636ac495dSmrg GCC_JIT_BINARY_OP_MULT, int_type, 15736ac495dSmrg gcc_jit_param_as_rvalue (param_i), 15836ac495dSmrg gcc_jit_param_as_rvalue (param_i)); 15936ac495dSmrg 16036ac495dSmrgA :c:type:`gcc_jit_rvalue *` is another example of a 16136ac495dSmrg:c:type:`gcc_jit_object *` subclass. We can upcast it using 16236ac495dSmrg:c:func:`gcc_jit_rvalue_as_object` and as before print it with 16336ac495dSmrg:c:func:`gcc_jit_object_get_debug_string`. 16436ac495dSmrg 16536ac495dSmrg.. code-block:: c 16636ac495dSmrg 16736ac495dSmrg printf ("expr: %s\n", 16836ac495dSmrg gcc_jit_object_get_debug_string ( 16936ac495dSmrg gcc_jit_rvalue_as_object (expr))); 17036ac495dSmrg 17136ac495dSmrggiving this output: 17236ac495dSmrg 17336ac495dSmrg.. code-block:: bash 17436ac495dSmrg 17536ac495dSmrg expr: i * i 17636ac495dSmrg 17736ac495dSmrgCreating the expression in itself doesn't do anything; we have to add 17836ac495dSmrgthis expression to a statement within the block. In this case, we use it 17936ac495dSmrgto build a return statement, which terminates the basic block: 18036ac495dSmrg 18136ac495dSmrg.. code-block:: c 18236ac495dSmrg 18336ac495dSmrg gcc_jit_block_end_with_return (block, NULL, expr); 18436ac495dSmrg 18536ac495dSmrgOK, we've populated the context. We can now compile it using 18636ac495dSmrg:c:func:`gcc_jit_context_compile`: 18736ac495dSmrg 18836ac495dSmrg.. code-block:: c 18936ac495dSmrg 19036ac495dSmrg gcc_jit_result *result; 19136ac495dSmrg result = gcc_jit_context_compile (ctxt); 19236ac495dSmrg 19336ac495dSmrgand get a :c:type:`gcc_jit_result *`. 19436ac495dSmrg 19536ac495dSmrgAt this point we're done with the context; we can release it: 19636ac495dSmrg 19736ac495dSmrg.. code-block:: c 19836ac495dSmrg 19936ac495dSmrg gcc_jit_context_release (ctxt); 20036ac495dSmrg 20136ac495dSmrgWe can now use :c:func:`gcc_jit_result_get_code` to look up a specific 20236ac495dSmrgmachine code routine within the result, in this case, the function we 20336ac495dSmrgcreated above. 20436ac495dSmrg 20536ac495dSmrg.. code-block:: c 20636ac495dSmrg 20736ac495dSmrg void *fn_ptr = gcc_jit_result_get_code (result, "square"); 20836ac495dSmrg if (!fn_ptr) 20936ac495dSmrg { 21036ac495dSmrg fprintf (stderr, "NULL fn_ptr"); 21136ac495dSmrg goto error; 21236ac495dSmrg } 21336ac495dSmrg 21436ac495dSmrgWe can now cast the pointer to an appropriate function pointer type, and 21536ac495dSmrgthen call it: 21636ac495dSmrg 21736ac495dSmrg.. code-block:: c 21836ac495dSmrg 21936ac495dSmrg typedef int (*fn_type) (int); 22036ac495dSmrg fn_type square = (fn_type)fn_ptr; 22136ac495dSmrg printf ("result: %d", square (5)); 22236ac495dSmrg 22336ac495dSmrg.. code-block:: bash 22436ac495dSmrg 22536ac495dSmrg result: 25 22636ac495dSmrg 22736ac495dSmrgOnce we're done with the code, we can release the result: 22836ac495dSmrg 22936ac495dSmrg.. code-block:: c 23036ac495dSmrg 23136ac495dSmrg gcc_jit_result_release (result); 23236ac495dSmrg 23336ac495dSmrgWe can't call ``square`` anymore once we've released ``result``. 23436ac495dSmrg 23536ac495dSmrg 23636ac495dSmrgError-handling 23736ac495dSmrg************** 23836ac495dSmrgVarious kinds of errors are possible when using the API, such as 23936ac495dSmrgmismatched types in an assignment. You can only compile and get code 24036ac495dSmrgfrom a context if no errors occur. 24136ac495dSmrg 24236ac495dSmrgErrors are printed on stderr; they typically contain the name of the API 24336ac495dSmrgentrypoint where the error occurred, and pertinent information on the 24436ac495dSmrgproblem: 24536ac495dSmrg 24636ac495dSmrg.. code-block:: console 24736ac495dSmrg 24836ac495dSmrg ./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *) 24936ac495dSmrg 25036ac495dSmrgThe API is designed to cope with errors without crashing, so you can get 25136ac495dSmrgaway with having a single error-handling check in your code: 25236ac495dSmrg 25336ac495dSmrg.. code-block:: c 25436ac495dSmrg 25536ac495dSmrg void *fn_ptr = gcc_jit_result_get_code (result, "square"); 25636ac495dSmrg if (!fn_ptr) 25736ac495dSmrg { 25836ac495dSmrg fprintf (stderr, "NULL fn_ptr"); 25936ac495dSmrg goto error; 26036ac495dSmrg } 26136ac495dSmrg 26236ac495dSmrgFor more information, see the :ref:`error-handling guide <error-handling>` 26336ac495dSmrgwithin the Topic eference. 26436ac495dSmrg 26536ac495dSmrg 26636ac495dSmrgOptions 26736ac495dSmrg******* 26836ac495dSmrg 26936ac495dSmrgTo get more information on what's going on, you can set debugging flags 27036ac495dSmrgon the context using :c:func:`gcc_jit_context_set_bool_option`. 27136ac495dSmrg 27236ac495dSmrg.. (I'm deliberately not mentioning 27336ac495dSmrg :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think 27436ac495dSmrg it's probably more of use to implementors than to users) 27536ac495dSmrg 27636ac495dSmrgSetting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a 27736ac495dSmrgC-like representation to stderr when you compile (GCC's "GIMPLE" 27836ac495dSmrgrepresentation): 27936ac495dSmrg 28036ac495dSmrg.. code-block:: c 28136ac495dSmrg 28236ac495dSmrg gcc_jit_context_set_bool_option ( 28336ac495dSmrg ctxt, 28436ac495dSmrg GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 28536ac495dSmrg 1); 28636ac495dSmrg result = gcc_jit_context_compile (ctxt); 28736ac495dSmrg 28836ac495dSmrg.. code-block:: c 28936ac495dSmrg 29036ac495dSmrg square (signed int i) 29136ac495dSmrg { 29236ac495dSmrg signed int D.260; 29336ac495dSmrg 29436ac495dSmrg entry: 29536ac495dSmrg D.260 = i * i; 29636ac495dSmrg return D.260; 29736ac495dSmrg } 29836ac495dSmrg 29936ac495dSmrgWe can see the generated machine code in assembler form (on stderr) by 30036ac495dSmrgsetting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context 30136ac495dSmrgbefore compiling: 30236ac495dSmrg 30336ac495dSmrg.. code-block:: c 30436ac495dSmrg 30536ac495dSmrg gcc_jit_context_set_bool_option ( 30636ac495dSmrg ctxt, 30736ac495dSmrg GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 30836ac495dSmrg 1); 30936ac495dSmrg result = gcc_jit_context_compile (ctxt); 31036ac495dSmrg 31136ac495dSmrg.. code-block:: gas 31236ac495dSmrg 31336ac495dSmrg .file "fake.c" 31436ac495dSmrg .text 31536ac495dSmrg .globl square 31636ac495dSmrg .type square, @function 31736ac495dSmrg square: 31836ac495dSmrg .LFB6: 31936ac495dSmrg .cfi_startproc 32036ac495dSmrg pushq %rbp 32136ac495dSmrg .cfi_def_cfa_offset 16 32236ac495dSmrg .cfi_offset 6, -16 32336ac495dSmrg movq %rsp, %rbp 32436ac495dSmrg .cfi_def_cfa_register 6 32536ac495dSmrg movl %edi, -4(%rbp) 32636ac495dSmrg .L14: 32736ac495dSmrg movl -4(%rbp), %eax 32836ac495dSmrg imull -4(%rbp), %eax 32936ac495dSmrg popq %rbp 33036ac495dSmrg .cfi_def_cfa 7, 8 33136ac495dSmrg ret 33236ac495dSmrg .cfi_endproc 33336ac495dSmrg .LFE6: 33436ac495dSmrg .size square, .-square 33536ac495dSmrg .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)" 33636ac495dSmrg .section .note.GNU-stack,"",@progbits 33736ac495dSmrg 33836ac495dSmrgBy default, no optimizations are performed, the equivalent of GCC's 33936ac495dSmrg`-O0` option. We can turn things up to e.g. `-O3` by calling 34036ac495dSmrg:c:func:`gcc_jit_context_set_int_option` with 34136ac495dSmrg:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`: 34236ac495dSmrg 34336ac495dSmrg.. code-block:: c 34436ac495dSmrg 34536ac495dSmrg gcc_jit_context_set_int_option ( 34636ac495dSmrg ctxt, 34736ac495dSmrg GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 34836ac495dSmrg 3); 34936ac495dSmrg 35036ac495dSmrg.. code-block:: gas 35136ac495dSmrg 35236ac495dSmrg .file "fake.c" 35336ac495dSmrg .text 35436ac495dSmrg .p2align 4,,15 35536ac495dSmrg .globl square 35636ac495dSmrg .type square, @function 35736ac495dSmrg square: 35836ac495dSmrg .LFB7: 35936ac495dSmrg .cfi_startproc 36036ac495dSmrg .L16: 36136ac495dSmrg movl %edi, %eax 36236ac495dSmrg imull %edi, %eax 36336ac495dSmrg ret 36436ac495dSmrg .cfi_endproc 36536ac495dSmrg .LFE7: 36636ac495dSmrg .size square, .-square 36736ac495dSmrg .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)" 36836ac495dSmrg .section .note.GNU-stack,"",@progbits 36936ac495dSmrg 37036ac495dSmrgNaturally this has only a small effect on such a trivial function. 37136ac495dSmrg 37236ac495dSmrg 37336ac495dSmrgFull example 37436ac495dSmrg************ 37536ac495dSmrg 37636ac495dSmrgHere's what the above looks like as a complete program: 37736ac495dSmrg 37836ac495dSmrg .. literalinclude:: ../examples/tut02-square.c 37936ac495dSmrg :lines: 1- 38036ac495dSmrg :language: c 38136ac495dSmrg 38236ac495dSmrgBuilding and running it: 38336ac495dSmrg 38436ac495dSmrg.. code-block:: console 38536ac495dSmrg 38636ac495dSmrg $ gcc \ 38736ac495dSmrg tut02-square.c \ 38836ac495dSmrg -o tut02-square \ 38936ac495dSmrg -lgccjit 39036ac495dSmrg 39136ac495dSmrg # Run the built program: 39236ac495dSmrg $ ./tut02-square 39336ac495dSmrg result: 25 394