Sindbad~EG File Manager
This is libgccjit.info, produced by makeinfo version 7.1 from
libgccjit.texi.
libgccjit 12.0.1 (experimental 20220411), Apr 12, 2022
David Malcolm
Copyright © 2014-2023 Free Software Foundation, Inc.
INFO-DIR-SECTION Miscellaneous
START-INFO-DIR-ENTRY
* libgccjit: (libgccjit.info). GCC-based Just In Time compiler library.
END-INFO-DIR-ENTRY
Generated by Sphinx 2.2.2.
File: libgccjit.info, Node: Top, Next: Tutorial, Up: (dir)
libgccjit Documentation
***********************
libgccjit 12.0.1 (experimental 20220411), Apr 12, 2022
David Malcolm
Copyright © 2014-2023 Free Software Foundation, Inc.
This document describes libgccjit(1), an API for embedding GCC inside
programs and libraries.
There are actually two APIs for the library:
* a pure C API: ‘libgccjit.h’
* a C++ wrapper API: ‘libgccjit++.h’. This is a collection of “thin”
wrapper classes around the C API, to save typing.
Contents:
* Menu:
* Tutorial::
* Topic Reference::
* C++ bindings for libgccjit::
* Internals::
* Indices and tables::
* Index::
-- The Detailed Node Listing --
Tutorial
* Tutorial part 1; “Hello world”: Tutorial part 1 “Hello world”.
* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function.
* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables.
* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter.
* Tutorial part 5; Implementing an Ahead-of-Time compiler: Tutorial part 5 Implementing an Ahead-of-Time compiler.
Tutorial part 2: Creating a trivial machine code function
* Error-handling::
* Options::
* Full example::
Tutorial part 3: Loops and variables
* Expressions; lvalues and rvalues: Expressions lvalues and rvalues.
* Control flow::
* Visualizing the control flow graph::
* Full example: Full example<2>.
Tutorial part 4: Adding JIT-compilation to a toy interpreter
* Our toy interpreter::
* Compiling to machine code::
* Setting things up::
* Populating the function::
* Verifying the control flow graph::
* Compiling the context::
* Single-stepping through the generated code::
* Examining the generated code::
* Putting it all together::
* Behind the curtain; How does our code get optimized?: Behind the curtain How does our code get optimized?.
Behind the curtain: How does our code get optimized?
* Optimizing away stack manipulation::
* Elimination of tail recursion::
Tutorial part 5: Implementing an Ahead-of-Time compiler
* The “brainf” language::
* Converting a brainf script to libgccjit IR::
* Compiling a context to a file::
* Other forms of ahead-of-time-compilation::
Topic Reference
* Compilation contexts::
* Objects::
* Types::
* Expressions::
* Creating and using functions::
* Function pointers: Function pointers<2>.
* Source Locations::
* Compiling a context::
* ABI and API compatibility::
* Performance::
* Using Assembly Language with libgccjit::
Compilation contexts
* Lifetime-management::
* Thread-safety::
* Error-handling: Error-handling<2>.
* Debugging::
* Options: Options<2>.
Options
* String Options::
* Boolean options::
* Integer options::
* Additional command-line options::
Types
* Standard types::
* Pointers, const, and volatile: Pointers const and volatile.
* Vector types::
* Structures and unions::
* Function pointer types::
* Reflection API::
Expressions
* Rvalues::
* Lvalues::
* Working with pointers, structs and unions: Working with pointers structs and unions.
Rvalues
* Simple expressions::
* Constructor expressions::
* Vector expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
* Function pointers::
* Type-coercion::
Lvalues
* Global variables::
Creating and using functions
* Params::
* Functions::
* Blocks::
* Statements::
Source Locations
* Faking it::
Compiling a context
* In-memory compilation::
* Ahead-of-time compilation::
ABI and API compatibility
* Programmatically checking version::
* ABI symbol tags::
ABI symbol tags
* LIBGCCJIT_ABI_0::
* LIBGCCJIT_ABI_1::
* LIBGCCJIT_ABI_2::
* LIBGCCJIT_ABI_3::
* LIBGCCJIT_ABI_4::
* LIBGCCJIT_ABI_5::
* LIBGCCJIT_ABI_6::
* LIBGCCJIT_ABI_7::
* LIBGCCJIT_ABI_8::
* LIBGCCJIT_ABI_9::
* LIBGCCJIT_ABI_10::
* LIBGCCJIT_ABI_11::
* LIBGCCJIT_ABI_12::
* LIBGCCJIT_ABI_13::
* LIBGCCJIT_ABI_14::
* LIBGCCJIT_ABI_15::
* LIBGCCJIT_ABI_16::
* LIBGCCJIT_ABI_17::
* LIBGCCJIT_ABI_18::
* LIBGCCJIT_ABI_19::
* LIBGCCJIT_ABI_20::
* LIBGCCJIT_ABI_21::
* LIBGCCJIT_ABI_22::
* LIBGCCJIT_ABI_23::
* LIBGCCJIT_ABI_24::
Performance
* The timing API::
Using Assembly Language with libgccjit
* Adding assembler instructions within a function::
* Adding top-level assembler statements::
C++ bindings for libgccjit
* Tutorial: Tutorial<2>.
* Topic Reference: Topic Reference<2>.
Tutorial
* Tutorial part 1; “Hello world”: Tutorial part 1 “Hello world”<2>.
* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function<2>.
* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables<2>.
* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>.
Tutorial part 2: Creating a trivial machine code function
* Options: Options<3>.
* Full example: Full example<3>.
Tutorial part 3: Loops and variables
* Expressions; lvalues and rvalues: Expressions lvalues and rvalues<2>.
* Control flow: Control flow<2>.
* Visualizing the control flow graph: Visualizing the control flow graph<2>.
* Full example: Full example<4>.
Tutorial part 4: Adding JIT-compilation to a toy interpreter
* Our toy interpreter: Our toy interpreter<2>.
* Compiling to machine code: Compiling to machine code<2>.
* Setting things up: Setting things up<2>.
* Populating the function: Populating the function<2>.
* Verifying the control flow graph: Verifying the control flow graph<2>.
* Compiling the context: Compiling the context<2>.
* Single-stepping through the generated code: Single-stepping through the generated code<2>.
* Examining the generated code: Examining the generated code<2>.
* Putting it all together: Putting it all together<2>.
* Behind the curtain; How does our code get optimized?: Behind the curtain How does our code get optimized?<2>.
Behind the curtain: How does our code get optimized?
* Optimizing away stack manipulation: Optimizing away stack manipulation<2>.
* Elimination of tail recursion: Elimination of tail recursion<2>.
Topic Reference
* Compilation contexts: Compilation contexts<2>.
* Objects: Objects<2>.
* Types: Types<2>.
* Expressions: Expressions<2>.
* Creating and using functions: Creating and using functions<2>.
* Source Locations: Source Locations<2>.
* Compiling a context: Compiling a context<2>.
* Using Assembly Language with libgccjit++::
Compilation contexts
* Lifetime-management: Lifetime-management<2>.
* Thread-safety: Thread-safety<2>.
* Error-handling: Error-handling<3>.
* Debugging: Debugging<2>.
* Options: Options<4>.
Options
* String Options: String Options<2>.
* Boolean options: Boolean options<2>.
* Integer options: Integer options<2>.
* Additional command-line options: Additional command-line options<2>.
Types
* Standard types: Standard types<2>.
* Pointers, const, and volatile: Pointers const and volatile<2>.
* Vector types: Vector types<2>.
* Structures and unions: Structures and unions<2>.
Expressions
* Rvalues: Rvalues<2>.
* Lvalues: Lvalues<2>.
* Working with pointers, structs and unions: Working with pointers structs and unions<2>.
Rvalues
* Simple expressions: Simple expressions<2>.
* Vector expressions: Vector expressions<2>.
* Unary Operations: Unary Operations<2>.
* Binary Operations: Binary Operations<2>.
* Comparisons: Comparisons<2>.
* Function calls: Function calls<2>.
* Function pointers: Function pointers<3>.
* Type-coercion: Type-coercion<2>.
Lvalues
* Global variables: Global variables<2>.
Creating and using functions
* Params: Params<2>.
* Functions: Functions<2>.
* Blocks: Blocks<2>.
* Statements: Statements<2>.
Source Locations
* Faking it: Faking it<2>.
Compiling a context
* In-memory compilation: In-memory compilation<2>.
* Ahead-of-time compilation: Ahead-of-time compilation<2>.
Using Assembly Language with libgccjit++
* Adding assembler instructions within a function: Adding assembler instructions within a function<2>.
* Adding top-level assembler statements: Adding top-level assembler statements<2>.
Internals
* Working on the JIT library::
* Running the test suite::
* Environment variables::
* Packaging notes::
* Overview of code structure::
* Design notes::
* Submitting patches::
Running the test suite
* Running under valgrind::
---------- Footnotes ----------
(1) https://gcc.gnu.org/wiki/JIT
File: libgccjit.info, Node: Tutorial, Next: Topic Reference, Prev: Top, Up: Top
1 Tutorial
**********
* Menu:
* Tutorial part 1; “Hello world”: Tutorial part 1 “Hello world”.
* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function.
* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables.
* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter.
* Tutorial part 5; Implementing an Ahead-of-Time compiler: Tutorial part 5 Implementing an Ahead-of-Time compiler.
File: libgccjit.info, Node: Tutorial part 1 “Hello world”, Next: Tutorial part 2 Creating a trivial machine code function, Up: Tutorial
1.1 Tutorial part 1: “Hello world”
==================================
Before we look at the details of the API, let’s look at building and
running programs that use the library.
Here’s a toy “hello world” program that uses the library to synthesize a
call to ‘printf’ and uses it to write a message to stdout.
Don’t worry about the content of the program for now; we’ll cover the
details in later parts of this tutorial.
/* Smoketest example for libgccjit.so
Copyright (C) 2014-2023 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include <libgccjit.h>
#include <stdlib.h>
#include <stdio.h>
static void
create_code (gcc_jit_context *ctxt)
{
/* Let's try to inject the equivalent of:
void
greet (const char *name)
{
printf ("hello %s\n", name);
}
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *const_char_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
gcc_jit_param *param_name =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"greet",
1, ¶m_name,
0);
gcc_jit_param *param_format =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
gcc_jit_function *printf_func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
gcc_jit_context_get_type (
ctxt, GCC_JIT_TYPE_INT),
"printf",
1, ¶m_format,
1);
gcc_jit_rvalue *args[2];
args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
args[1] = gcc_jit_param_as_rvalue (param_name);
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt,
NULL,
printf_func,
2, args));
gcc_jit_block_end_with_void_return (block, NULL);
}
int
main (int argc, char **argv)
{
gcc_jit_context *ctxt;
gcc_jit_result *result;
/* Get a "context" object for working with the library. */
ctxt = gcc_jit_context_acquire ();
if (!ctxt)
{
fprintf (stderr, "NULL ctxt");
exit (1);
}
/* Set some options on the context.
Let's see the code being generated, in assembler form. */
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = gcc_jit_context_compile (ctxt);
if (!result)
{
fprintf (stderr, "NULL result");
exit (1);
}
/* Extract the generated code from "result". */
typedef void (*fn_type) (const char *);
fn_type greet =
(fn_type)gcc_jit_result_get_code (result, "greet");
if (!greet)
{
fprintf (stderr, "NULL greet");
exit (1);
}
/* Now call the generated function: */
greet ("world");
fflush (stdout);
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
return 0;
}
Copy the above to ‘tut01-hello-world.c’.
Assuming you have the jit library installed, build the test program
using:
$ gcc \
tut01-hello-world.c \
-o tut01-hello-world \
-lgccjit
You should then be able to run the built program:
$ ./tut01-hello-world
hello world
File: libgccjit.info, Node: Tutorial part 2 Creating a trivial machine code function, Next: Tutorial part 3 Loops and variables, Prev: Tutorial part 1 “Hello world”, Up: Tutorial
1.2 Tutorial part 2: Creating a trivial machine code function
=============================================================
Consider this C function:
int square (int i)
{
return i * i;
}
How can we construct this at run-time using libgccjit?
First we need to include the relevant header:
#include <libgccjit.h>
All state associated with compilation is associated with a *note
gcc_jit_context *: 8.
Create one using *note gcc_jit_context_acquire(): 9.:
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
The JIT library has a system of types. It is statically-typed: every
expression is of a specific type, fixed at compile-time. In our
example, all of the expressions are of the C ‘int’ type, so let’s obtain
this from the context, as a *note gcc_jit_type *: a, using *note
gcc_jit_context_get_type(): b.:
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
*note gcc_jit_type *: a. is an example of a “contextual” object: every
entity in the API is associated with a *note gcc_jit_context *: 8.
Memory management is easy: all such “contextual” objects are
automatically cleaned up for you when the context is released, using
*note gcc_jit_context_release(): c.:
gcc_jit_context_release (ctxt);
so you don’t need to manually track and cleanup all objects, just the
contexts.
Although the API is C-based, there is a form of class hierarchy, which
looks like this:
+- gcc_jit_object
+- gcc_jit_location
+- gcc_jit_type
+- gcc_jit_struct
+- gcc_jit_field
+- gcc_jit_function
+- gcc_jit_block
+- gcc_jit_rvalue
+- gcc_jit_lvalue
+- gcc_jit_param
There are casting methods for upcasting from subclasses to parent
classes. For example, *note gcc_jit_type_as_object(): d.:
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
One thing you can do with a *note gcc_jit_object *: e. is to ask it for
a human-readable description, using *note
gcc_jit_object_get_debug_string(): f.:
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
giving this text on stdout:
obj: int
This is invaluable when debugging.
Let’s create the function. To do so, we first need to construct its
single parameter, specifying its type and giving it a name, using *note
gcc_jit_context_new_param(): 10.:
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
Now we can create the function, using *note
gcc_jit_context_new_function(): 11.:
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
1, ¶m_i,
0);
To define the code within the function, we must create basic blocks
containing statements.
Every basic block contains a list of statements, eventually terminated
by a statement that either returns, or jumps to another basic block.
Our function has no control-flow, so we just need one basic block:
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
We can build the expression using *note gcc_jit_context_new_binary_op():
12.:
gcc_jit_rvalue *expr =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, int_type,
gcc_jit_param_as_rvalue (param_i),
gcc_jit_param_as_rvalue (param_i));
A *note gcc_jit_rvalue *: 13. is another example of a *note
gcc_jit_object *: e. subclass. We can upcast it using *note
gcc_jit_rvalue_as_object(): 14. and as before print it with *note
gcc_jit_object_get_debug_string(): f.
printf ("expr: %s\n",
gcc_jit_object_get_debug_string (
gcc_jit_rvalue_as_object (expr)));
giving this output:
expr: i * i
Creating the expression in itself doesn’t do anything; we have to add
this expression to a statement within the block. In this case, we use
it to build a return statement, which terminates the basic block:
gcc_jit_block_end_with_return (block, NULL, expr);
OK, we’ve populated the context. We can now compile it using *note
gcc_jit_context_compile(): 15.:
gcc_jit_result *result;
result = gcc_jit_context_compile (ctxt);
and get a *note gcc_jit_result *: 16.
At this point we’re done with the context; we can release it:
gcc_jit_context_release (ctxt);
We can now use *note gcc_jit_result_get_code(): 17. to look up a
specific machine code routine within the result, in this case, the
function we created above.
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
{
fprintf (stderr, "NULL fn_ptr");
goto error;
}
We can now cast the pointer to an appropriate function pointer type, and
then call it:
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d", square (5));
result: 25
Once we’re done with the code, we can release the result:
gcc_jit_result_release (result);
We can’t call ‘square’ anymore once we’ve released ‘result’.
* Menu:
* Error-handling::
* Options::
* Full example::
File: libgccjit.info, Node: Error-handling, Next: Options, Up: Tutorial part 2 Creating a trivial machine code function
1.2.1 Error-handling
--------------------
Various kinds of errors are possible when using the API, such as
mismatched types in an assignment. You can only compile and get code
from a context if no errors occur.
Errors are printed on stderr; they typically contain the name of the API
entrypoint where the error occurred, and pertinent information on the
problem:
./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *)
The API is designed to cope with errors without crashing, so you can get
away with having a single error-handling check in your code:
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
{
fprintf (stderr, "NULL fn_ptr");
goto error;
}
For more information, see the *note error-handling guide: 19. within the
Topic eference.
File: libgccjit.info, Node: Options, Next: Full example, Prev: Error-handling, Up: Tutorial part 2 Creating a trivial machine code function
1.2.2 Options
-------------
To get more information on what’s going on, you can set debugging flags
on the context using *note gcc_jit_context_set_bool_option(): 1b.
Setting *note GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE: 1c. will dump a
C-like representation to stderr when you compile (GCC’s “GIMPLE”
representation):
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
1);
result = gcc_jit_context_compile (ctxt);
square (signed int i)
{
signed int D.260;
entry:
D.260 = i * i;
return D.260;
}
We can see the generated machine code in assembler form (on stderr) by
setting *note GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE: 1d. on the
context before compiling:
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
1);
result = gcc_jit_context_compile (ctxt);
.file "fake.c"
.text
.globl square
.type square, @function
square:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
.L14:
movl -4(%rbp), %eax
imull -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size square, .-square
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
.section .note.GNU-stack,"",@progbits
By default, no optimizations are performed, the equivalent of GCC’s
‘-O0’ option. We can turn things up to e.g. ‘-O3’ by calling *note
gcc_jit_context_set_int_option(): 1e. with *note
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL: 1f.:
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
.file "fake.c"
.text
.p2align 4,,15
.globl square
.type square, @function
square:
.LFB7:
.cfi_startproc
.L16:
movl %edi, %eax
imull %edi, %eax
ret
.cfi_endproc
.LFE7:
.size square, .-square
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
.section .note.GNU-stack,"",@progbits
Naturally this has only a small effect on such a trivial function.
File: libgccjit.info, Node: Full example, Prev: Options, Up: Tutorial part 2 Creating a trivial machine code function
1.2.3 Full example
------------------
Here’s what the above looks like as a complete program:
/* Usage example for libgccjit.so
Copyright (C) 2014-2023 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include <libgccjit.h>
#include <stdlib.h>
#include <stdio.h>
void
create_code (gcc_jit_context *ctxt)
{
/* Let's try to inject the equivalent of:
int square (int i)
{
return i * i;
}
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
1, ¶m_i,
0);
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
gcc_jit_rvalue *expr =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, int_type,
gcc_jit_param_as_rvalue (param_i),
gcc_jit_param_as_rvalue (param_i));
gcc_jit_block_end_with_return (block, NULL, expr);
}
int
main (int argc, char **argv)
{
gcc_jit_context *ctxt = NULL;
gcc_jit_result *result = NULL;
/* Get a "context" object for working with the library. */
ctxt = gcc_jit_context_acquire ();
if (!ctxt)
{
fprintf (stderr, "NULL ctxt");
goto error;
}
/* Set some options on the context.
Let's see the code being generated, in assembler form. */
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = gcc_jit_context_compile (ctxt);
if (!result)
{
fprintf (stderr, "NULL result");
goto error;
}
/* We're done with the context; we can release it: */
gcc_jit_context_release (ctxt);
ctxt = NULL;
/* Extract the generated code from "result". */
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
{
fprintf (stderr, "NULL fn_ptr");
goto error;
}
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d\n", square (5));
error:
if (ctxt)
gcc_jit_context_release (ctxt);
if (result)
gcc_jit_result_release (result);
return 0;
}
Building and running it:
$ gcc \
tut02-square.c \
-o tut02-square \
-lgccjit
# Run the built program:
$ ./tut02-square
result: 25
File: libgccjit.info, Node: Tutorial part 3 Loops and variables, Next: Tutorial part 4 Adding JIT-compilation to a toy interpreter, Prev: Tutorial part 2 Creating a trivial machine code function, Up: Tutorial
1.3 Tutorial part 3: Loops and variables
========================================
Consider this C function:
int loop_test (int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
sum += i * i;
return sum;
}
This example demonstrates some more features of libgccjit, with local
variables and a loop.
To break this down into libgccjit terms, it’s usually easier to reword
the ‘for’ loop as a ‘while’ loop, giving:
int loop_test (int n)
{
int sum = 0;
int i = 0;
while (i < n)
{
sum += i * i;
i++;
}
return sum;
}
Here’s what the final control flow graph will look like:
[image src="libgccjit-figures/sum-of-squares1.png" alt="image of a control flow graph"