blob: 9c90de39f63a0115514472412918edd7b6781185 [file] [log] [blame]
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename libgccjit.info
@documentencoding UTF-8
@ifinfo
@*Generated by Sphinx 2.2.2.@*
@end ifinfo
@settitle libgccjit Documentation
@defindex ge
@paragraphindent 0
@exampleindent 4
@finalout
@dircategory Miscellaneous
@direntry
* libgccjit: (libgccjit.info). GCC-based Just In Time compiler library.
@end direntry
@definfoenclose strong,`,'
@definfoenclose emph,`,'
@c %**end of header
@copying
@quotation
libgccjit 12.0.1 (experimental 20220411), Apr 12, 2022
David Malcolm
Copyright @copyright{} 2014-2022 Free Software Foundation, Inc.
@end quotation
@end copying
@titlepage
@title libgccjit Documentation
@insertcopying
@end titlepage
@contents
@c %** start of user preamble
@c %** end of user preamble
@ifnottex
@node Top
@top libgccjit Documentation
@insertcopying
@end ifnottex
@c %**start of body
@anchor{index doc}@anchor{0}
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
This document describes libgccjit@footnote{https://gcc.gnu.org/wiki/JIT}, an API
for embedding GCC inside programs and libraries.
There are actually two APIs for the library:
@itemize *
@item
a pure C API: @code{libgccjit.h}
@item
a C++ wrapper API: @code{libgccjit++.h}. This is a collection of “thin”
wrapper classes around the C API, to save typing.
@end itemize
Contents:
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@menu
* Tutorial::
* Topic Reference::
* C++ bindings for libgccjit::
* Internals::
* Indices and tables::
* Index::
@detailmenu
--- 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@comma{} const@comma{} and volatile: Pointers const and volatile.
* Vector types::
* Structures and unions::
* Function pointer types::
* Reflection API::
Expressions
* Rvalues::
* Lvalues::
* Working with pointers@comma{} 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@comma{} const@comma{} 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@comma{} 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::
@end detailmenu
@end menu
@node Tutorial,Topic Reference,Top,Top
@anchor{intro/index doc}@anchor{1}@anchor{intro/index libgccjit}@anchor{2}@anchor{intro/index tutorial}@anchor{3}
@chapter Tutorial
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@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.
@end menu
@node Tutorial part 1 “Hello world”,Tutorial part 2 Creating a trivial machine code function,,Tutorial
@anchor{intro/tutorial01 doc}@anchor{4}@anchor{intro/tutorial01 tutorial-part-1-hello-world}@anchor{5}
@section 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 @cite{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.
@quotation
@example
/* Smoketest example for libgccjit.so
Copyright (C) 2014-2022 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, &param_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, &param_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;
@}
@end example
@end quotation
Copy the above to @cite{tut01-hello-world.c}.
Assuming you have the jit library installed, build the test program
using:
@example
$ gcc \
tut01-hello-world.c \
-o tut01-hello-world \
-lgccjit
@end example
You should then be able to run the built program:
@example
$ ./tut01-hello-world
hello world
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 2 Creating a trivial machine code function,Tutorial part 3 Loops and variables,Tutorial part 1 “Hello world”,Tutorial
@anchor{intro/tutorial02 doc}@anchor{6}@anchor{intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{7}
@section Tutorial part 2: Creating a trivial machine code function
Consider this C function:
@example
int square (int i)
@{
return i * i;
@}
@end example
How can we construct this at run-time using libgccjit?
First we need to include the relevant header:
@example
#include <libgccjit.h>
@end example
All state associated with compilation is associated with a
@ref{8,,gcc_jit_context *}.
Create one using @ref{9,,gcc_jit_context_acquire()}:
@example
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
@end example
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 @cite{int} type, so let’s obtain this from
the context, as a @ref{a,,gcc_jit_type *}, using
@ref{b,,gcc_jit_context_get_type()}:
@example
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
@end example
@ref{a,,gcc_jit_type *} is an example of a “contextual” object: every
entity in the API is associated with a @ref{8,,gcc_jit_context *}.
Memory management is easy: all such “contextual” objects are automatically
cleaned up for you when the context is released, using
@ref{c,,gcc_jit_context_release()}:
@example
gcc_jit_context_release (ctxt);
@end example
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:
@example
+- 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
@end example
There are casting methods for upcasting from subclasses to parent classes.
For example, @ref{d,,gcc_jit_type_as_object()}:
@example
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
@end example
One thing you can do with a @ref{e,,gcc_jit_object *} is
to ask it for a human-readable description, using
@ref{f,,gcc_jit_object_get_debug_string()}:
@example
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
@end example
giving this text on stdout:
@example
obj: int
@end example
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 @ref{10,,gcc_jit_context_new_param()}:
@example
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
@end example
Now we can create the function, using
@ref{11,,gcc_jit_context_new_function()}:
@example
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
1, &param_i,
0);
@end example
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:
@example
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
@end example
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
We can build the expression using @ref{12,,gcc_jit_context_new_binary_op()}:
@example
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));
@end example
A @ref{13,,gcc_jit_rvalue *} is another example of a
@ref{e,,gcc_jit_object *} subclass. We can upcast it using
@ref{14,,gcc_jit_rvalue_as_object()} and as before print it with
@ref{f,,gcc_jit_object_get_debug_string()}.
@example
printf ("expr: %s\n",
gcc_jit_object_get_debug_string (
gcc_jit_rvalue_as_object (expr)));
@end example
giving this output:
@example
expr: i * i
@end example
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:
@example
gcc_jit_block_end_with_return (block, NULL, expr);
@end example
OK, we’ve populated the context. We can now compile it using
@ref{15,,gcc_jit_context_compile()}:
@example
gcc_jit_result *result;
result = gcc_jit_context_compile (ctxt);
@end example
and get a @ref{16,,gcc_jit_result *}.
At this point we’re done with the context; we can release it:
@example
gcc_jit_context_release (ctxt);
@end example
We can now use @ref{17,,gcc_jit_result_get_code()} to look up a specific
machine code routine within the result, in this case, the function we
created above.
@example
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
@{
fprintf (stderr, "NULL fn_ptr");
goto error;
@}
@end example
We can now cast the pointer to an appropriate function pointer type, and
then call it:
@example
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d", square (5));
@end example
@example
result: 25
@end example
Once we’re done with the code, we can release the result:
@example
gcc_jit_result_release (result);
@end example
We can’t call @code{square} anymore once we’ve released @code{result}.
@menu
* Error-handling::
* Options::
* Full example::
@end menu
@node Error-handling,Options,,Tutorial part 2 Creating a trivial machine code function
@anchor{intro/tutorial02 error-handling}@anchor{18}
@subsection 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:
@example
./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *)
@end example
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:
@example
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
@{
fprintf (stderr, "NULL fn_ptr");
goto error;
@}
@end example
For more information, see the @ref{19,,error-handling guide}
within the Topic eference.
@node Options,Full example,Error-handling,Tutorial part 2 Creating a trivial machine code function
@anchor{intro/tutorial02 options}@anchor{1a}
@subsection Options
To get more information on what’s going on, you can set debugging flags
on the context using @ref{1b,,gcc_jit_context_set_bool_option()}.
@c (I'm deliberately not mentioning
@c :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
@c it's probably more of use to implementors than to users)
Setting @ref{1c,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE} will dump a
C-like representation to stderr when you compile (GCC’s “GIMPLE”
representation):
@example
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
1);
result = gcc_jit_context_compile (ctxt);
@end example
@example
square (signed int i)
@{
signed int D.260;
entry:
D.260 = i * i;
return D.260;
@}
@end example
We can see the generated machine code in assembler form (on stderr) by
setting @ref{1d,,GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE} on the context
before compiling:
@example
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
1);
result = gcc_jit_context_compile (ctxt);
@end example
@example
.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
@end example
By default, no optimizations are performed, the equivalent of GCC’s
@cite{-O0} option. We can turn things up to e.g. @cite{-O3} by calling
@ref{1e,,gcc_jit_context_set_int_option()} with
@ref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
@end example
@example
.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
@end example
Naturally this has only a small effect on such a trivial function.
@node Full example,,Options,Tutorial part 2 Creating a trivial machine code function
@anchor{intro/tutorial02 full-example}@anchor{20}
@subsection Full example
Here’s what the above looks like as a complete program:
@quotation
@example
/* Usage example for libgccjit.so
Copyright (C) 2014-2022 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, &param_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;
@}
@end example
@end quotation
Building and running it:
@example
$ gcc \
tut02-square.c \
-o tut02-square \
-lgccjit
# Run the built program:
$ ./tut02-square
result: 25
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 3 Loops and variables,Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial part 2 Creating a trivial machine code function,Tutorial
@anchor{intro/tutorial03 doc}@anchor{21}@anchor{intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{22}
@section Tutorial part 3: Loops and variables
Consider this C function:
@quotation
@example
int loop_test (int n)
@{
int sum = 0;
for (int i = 0; i < n; i++)
sum += i * i;
return sum;
@}
@end example
@end quotation
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 @cite{for} loop as a @cite{while} loop, giving:
@quotation
@example
int loop_test (int n)
@{
int sum = 0;
int i = 0;
while (i < n)
@{
sum += i * i;
i++;
@}
return sum;
@}
@end example
@end quotation
Here’s what the final control flow graph will look like:
@quotation
@float Figure
@image{libgccjit-figures/sum-of-squares1,,,image of a control flow graph,png}
@end float
@end quotation
As before, we include the libgccjit header and make a
@ref{8,,gcc_jit_context *}.
@example
#include <libgccjit.h>
void test (void)
@{
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
@end example
The function works with the C @cite{int} type:
@example
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = the_type;
@end example
though we could equally well make it work on, say, @cite{double}:
@example
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
@end example
Let’s build the function:
@example
gcc_jit_param *n =
gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
gcc_jit_param *params[1] = @{n@};
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
1, params, 0);
@end example
@menu
* Expressions; lvalues and rvalues: Expressions lvalues and rvalues.
* Control flow::
* Visualizing the control flow graph::
* Full example: Full example<2>.
@end menu
@node Expressions lvalues and rvalues,Control flow,,Tutorial part 3 Loops and variables
@anchor{intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{23}
@subsection Expressions: lvalues and rvalues
The base class of expression is the @ref{13,,gcc_jit_rvalue *},
representing an expression that can be on the @emph{right}-hand side of
an assignment: a value that can be computed somehow, and assigned
@emph{to} a storage area (such as a variable). It has a specific
@ref{a,,gcc_jit_type *}.
Anothe important class is @ref{24,,gcc_jit_lvalue *}.
A @ref{24,,gcc_jit_lvalue *}. is something that can of the @emph{left}-hand
side of an assignment: a storage area (such as a variable).
In other words, every assignment can be thought of as:
@example
LVALUE = RVALUE;
@end example
Note that @ref{24,,gcc_jit_lvalue *} is a subclass of
@ref{13,,gcc_jit_rvalue *}, where in an assignment of the form:
@example
LVALUE_A = LVALUE_B;
@end example
the @cite{LVALUE_B} implies reading the current value of that storage
area, assigning it into the @cite{LVALUE_A}.
So far the only expressions we’ve seen are @cite{i * i}:
@example
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));
@end example
which is a @ref{13,,gcc_jit_rvalue *}, and the various function
parameters: @cite{param_i} and @cite{param_n}, instances of
@ref{25,,gcc_jit_param *}, which is a subclass of
@ref{24,,gcc_jit_lvalue *} (and, in turn, of @ref{13,,gcc_jit_rvalue *}):
we can both read from and write to function parameters within the
body of a function.
Our new example has a couple of local variables. We create them by
calling @ref{26,,gcc_jit_function_new_local()}, supplying a type and a
name:
@example
/* Build locals: */
gcc_jit_lvalue *i =
gcc_jit_function_new_local (func, NULL, the_type, "i");
gcc_jit_lvalue *sum =
gcc_jit_function_new_local (func, NULL, the_type, "sum");
@end example
These are instances of @ref{24,,gcc_jit_lvalue *} - they can be read from
and written to.
Note that there is no precanned way to create @emph{and} initialize a variable
like in C:
@example
int i = 0;
@end example
Instead, having added the local to the function, we have to separately add
an assignment of @cite{0} to @cite{local_i} at the beginning of the function.
@node Control flow,Visualizing the control flow graph,Expressions lvalues and rvalues,Tutorial part 3 Loops and variables
@anchor{intro/tutorial03 control-flow}@anchor{27}
@subsection Control flow
This function has a loop, so we need to build some basic blocks to
handle the control flow. In this case, we need 4 blocks:
@enumerate
@item
before the loop (initializing the locals)
@item
the conditional at the top of the loop (comparing @cite{i < n})
@item
the body of the loop
@item
after the loop terminates (@cite{return sum})
@end enumerate
so we create these as @ref{28,,gcc_jit_block *} instances within the
@ref{29,,gcc_jit_function *}:
@example
gcc_jit_block *b_initial =
gcc_jit_function_new_block (func, "initial");
gcc_jit_block *b_loop_cond =
gcc_jit_function_new_block (func, "loop_cond");
gcc_jit_block *b_loop_body =
gcc_jit_function_new_block (func, "loop_body");
gcc_jit_block *b_after_loop =
gcc_jit_function_new_block (func, "after_loop");
@end example
We now populate each block with statements.
The entry block @cite{b_initial} consists of initializations followed by a jump
to the conditional. We assign @cite{0} to @cite{i} and to @cite{sum}, using
@ref{2a,,gcc_jit_block_add_assignment()} to add
an assignment statement, and using @ref{2b,,gcc_jit_context_zero()} to get
the constant value @cite{0} for the relevant type for the right-hand side of
the assignment:
@example
/* sum = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
sum,
gcc_jit_context_zero (ctxt, the_type));
/* i = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
i,
gcc_jit_context_zero (ctxt, the_type));
@end example
We can then terminate the entry block by jumping to the conditional:
@example
gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
@end example
The conditional block is equivalent to the line @cite{while (i < n)} from our
C example. It contains a single statement: a conditional, which jumps to
one of two destination blocks depending on a boolean
@ref{13,,gcc_jit_rvalue *}, in this case the comparison of @cite{i} and @cite{n}.
We build the comparison using @ref{2c,,gcc_jit_context_new_comparison()}:
@example
/* (i >= n) */
gcc_jit_rvalue *guard =
gcc_jit_context_new_comparison (
ctxt, NULL,
GCC_JIT_COMPARISON_GE,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_param_as_rvalue (n));
@end example
and can then use this to add @cite{b_loop_cond}’s sole statement, via
@ref{2d,,gcc_jit_block_end_with_conditional()}:
@example
/* Equivalent to:
if (guard)
goto after_loop;
else
goto loop_body; */
gcc_jit_block_end_with_conditional (
b_loop_cond, NULL,
guard,
b_after_loop, /* on_true */
b_loop_body); /* on_false */
@end example
Next, we populate the body of the loop.
The C statement @cite{sum += i * i;} is an assignment operation, where an
lvalue is modified “in-place”. We use
@ref{2e,,gcc_jit_block_add_assignment_op()} to handle these operations:
@example
/* sum += i * i */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
sum,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, the_type,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_lvalue_as_rvalue (i)));
@end example
The @cite{i++} can be thought of as @cite{i += 1}, and can thus be handled in
a similar way. We use @ref{2f,,gcc_jit_context_one()} to get the constant
value @cite{1} (for the relevant type) for the right-hand side
of the assignment.
@example
/* i++ */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, the_type));
@end example
@cartouche
@quotation Note
For numeric constants other than 0 or 1, we could use
@ref{30,,gcc_jit_context_new_rvalue_from_int()} and
@ref{31,,gcc_jit_context_new_rvalue_from_double()}.
@end quotation
@end cartouche
The loop body completes by jumping back to the conditional:
@example
gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
@end example
Finally, we populate the @cite{b_after_loop} block, reached when the loop
conditional is false. We want to generate the equivalent of:
@example
return sum;
@end example
so the block is just one statement:
@example
/* return sum */
gcc_jit_block_end_with_return (
b_after_loop,
NULL,
gcc_jit_lvalue_as_rvalue (sum));
@end example
@cartouche
@quotation Note
You can intermingle block creation with statement creation,
but given that the terminator statements generally include references
to other blocks, I find it’s clearer to create all the blocks,
@emph{then} all the statements.
@end quotation
@end cartouche
We’ve finished populating the function. As before, we can now compile it
to machine code:
@example
gcc_jit_result *result;
result = gcc_jit_context_compile (ctxt);
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
goto error;
printf ("result: %d", loop_test (10));
@end example
@example
result: 285
@end example
@node Visualizing the control flow graph,Full example<2>,Control flow,Tutorial part 3 Loops and variables
@anchor{intro/tutorial03 visualizing-the-control-flow-graph}@anchor{32}
@subsection Visualizing the control flow graph
You can see the control flow graph of a function using
@ref{33,,gcc_jit_function_dump_to_dot()}:
@example
gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
@end example
giving a .dot file in GraphViz format.
You can convert this to an image using @cite{dot}:
@example
$ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
@end example
or use a viewer (my preferred one is xdot.py; see
@indicateurl{https://github.com/jrfonseca/xdot.py}; on Fedora you can
install it with @cite{yum install python-xdot}):
@quotation
@float Figure
@image{libgccjit-figures/sum-of-squares1,,,image of a control flow graph,png}
@end float
@end quotation
@node Full example<2>,,Visualizing the control flow graph,Tutorial part 3 Loops and variables
@anchor{intro/tutorial03 full-example}@anchor{34}
@subsection Full example
@quotation
@example
/* Usage example for libgccjit.so
Copyright (C) 2014-2022 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)
@{
/*
Simple sum-of-squares, to test conditionals and looping
int loop_test (int n)
@{
int i;
int sum = 0;
for (i = 0; i < n ; i ++)
@{
sum += i * i;
@}
return sum;
*/
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = the_type;
gcc_jit_param *n =
gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
gcc_jit_param *params[1] = @{n@};
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
1, params, 0);
/* Build locals: */
gcc_jit_lvalue *i =
gcc_jit_function_new_local (func, NULL, the_type, "i");
gcc_jit_lvalue *sum =
gcc_jit_function_new_local (func, NULL, the_type, "sum");
gcc_jit_block *b_initial =
gcc_jit_function_new_block (func, "initial");
gcc_jit_block *b_loop_cond =
gcc_jit_function_new_block (func, "loop_cond");
gcc_jit_block *b_loop_body =
gcc_jit_function_new_block (func, "loop_body");
gcc_jit_block *b_after_loop =
gcc_jit_function_new_block (func, "after_loop");
/* sum = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
sum,
gcc_jit_context_zero (ctxt, the_type));
/* i = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
i,
gcc_jit_context_zero (ctxt, the_type));
gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
/* if (i >= n) */
gcc_jit_block_end_with_conditional (
b_loop_cond, NULL,
gcc_jit_context_new_comparison (
ctxt, NULL,
GCC_JIT_COMPARISON_GE,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_param_as_rvalue (n)),
b_after_loop,
b_loop_body);
/* sum += i * i */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
sum,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, the_type,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_lvalue_as_rvalue (i)));
/* i++ */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, the_type));
gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
/* return sum */
gcc_jit_block_end_with_return (
b_after_loop,
NULL,
gcc_jit_lvalue_as_rvalue (sum));
@}
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;
@}
/* Extract the generated code from "result". */
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
@{
fprintf (stderr, "NULL loop_test");
goto error;
@}
/* Run the generated code. */
int val = loop_test (10);
printf("loop_test returned: %d\n", val);
error:
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
return 0;
@}
@end example
@end quotation
Building and running it:
@example
$ gcc \
tut03-sum-of-squares.c \
-o tut03-sum-of-squares \
-lgccjit
# Run the built program:
$ ./tut03-sum-of-squares
loop_test returned: 285
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial part 5 Implementing an Ahead-of-Time compiler,Tutorial part 3 Loops and variables,Tutorial
@anchor{intro/tutorial04 doc}@anchor{35}@anchor{intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{36}
@section Tutorial part 4: Adding JIT-compilation to a toy interpreter
In this example we construct a “toy” interpreter, and add JIT-compilation
to it.
@menu
* 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?.
@end menu
@node Our toy interpreter,Compiling to machine code,,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 our-toy-interpreter}@anchor{37}
@subsection Our toy interpreter
It’s a stack-based interpreter, and is intended as a (very simple) example
of the kind of bytecode interpreter seen in dynamic languages such as
Python, Ruby etc.
For the sake of simplicity, our toy virtual machine is very limited:
@quotation
@itemize *
@item
The only data type is @cite{int}
@item
It can only work on one function at a time (so that the only
function call that can be made is to recurse).
@item
Functions can only take one parameter.
@item
Functions have a stack of @cite{int} values.
@item
We’ll implement function call within the interpreter by calling a
function in our implementation, rather than implementing our own
frame stack.
@item
The parser is only good enough to get the examples to work.
@end itemize
@end quotation
Naturally, a real interpreter would be much more complicated that this.
The following operations are supported:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxx}
@headitem
Operation
@tab
Meaning
@tab
Old Stack
@tab
New Stack
@item
DUP
@tab
Duplicate top of stack.
@tab
@code{[..., x]}
@tab
@code{[..., x, x]}
@item
ROT
@tab
Swap top two elements
of stack.
@tab
@code{[..., x, y]}
@tab
@code{[..., y, x]}
@item
BINARY_ADD
@tab
Add the top two elements
on the stack.
@tab
@code{[..., x, y]}
@tab
@code{[..., (x+y)]}
@item
BINARY_SUBTRACT
@tab
Likewise, but subtract.
@tab
@code{[..., x, y]}
@tab
@code{[..., (x-y)]}
@item
BINARY_MULT
@tab
Likewise, but multiply.
@tab
@code{[..., x, y]}
@tab
@code{[..., (x*y)]}
@item
BINARY_COMPARE_LT
@tab
Compare the top two
elements on the stack
and push a nonzero/zero
if (x<y).
@tab
@code{[..., x, y]}
@tab
@code{[..., (x<y)]}
@item
RECURSE
@tab
Recurse, passing the top
of the stack, and
popping the result.
@tab
@code{[..., x]}
@tab
@code{[..., fn(x)]}
@item
RETURN
@tab
Return the top of the
stack.
@tab
@code{[x]}
@tab
@code{[]}
@item
PUSH_CONST @cite{arg}
@tab
Push an int const.
@tab
@code{[...]}
@tab
@code{[..., arg]}
@item
JUMP_ABS_IF_TRUE @cite{arg}
@tab
Pop; if top of stack was
nonzero, jump to
@code{arg}.
@tab
@code{[..., x]}
@tab
@code{[...]}
@end multitable
Programs can be interpreted, disassembled, and compiled to machine code.
The interpreter reads @code{.toy} scripts. Here’s what a simple recursive
factorial program looks like, the script @code{factorial.toy}.
The parser ignores lines beginning with a @cite{#}.
@quotation
@example
# Simple recursive factorial implementation, roughly equivalent to:
#
# int factorial (int arg)
# @{
# if (arg < 2)
# return arg
# return arg * factorial (arg - 1)
# @}
# Initial state:
# stack: [arg]
# 0:
DUP
# stack: [arg, arg]
# 1:
PUSH_CONST 2
# stack: [arg, arg, 2]
# 2:
BINARY_COMPARE_LT
# stack: [arg, (arg < 2)]
# 3:
JUMP_ABS_IF_TRUE 9
# stack: [arg]
# 4:
DUP
# stack: [arg, arg]
# 5:
PUSH_CONST 1
# stack: [arg, arg, 1]
# 6:
BINARY_SUBTRACT
# stack: [arg, (arg - 1)
# 7:
RECURSE
# stack: [arg, factorial(arg - 1)]
# 8:
BINARY_MULT
# stack: [arg * factorial(arg - 1)]
# 9:
RETURN
@end example
@end quotation
The interpreter is a simple infinite loop with a big @code{switch} statement
based on what the next opcode is:
@quotation
@example
static int
toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
@{
toyvm_frame frame;
#define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
#define POP(ARG) (toyvm_frame_pop (&frame))
frame.frm_function = fn;
frame.frm_pc = 0;
frame.frm_cur_depth = 0;
PUSH (arg);
while (1)
@{
toyvm_op *op;
int x, y;
assert (frame.frm_pc < fn->fn_num_ops);
op = &fn->fn_ops[frame.frm_pc++];
if (trace)
@{
toyvm_frame_dump_stack (&frame, trace);
toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
@}
switch (op->op_opcode)
@{
/* Ops taking no operand. */
case DUP:
x = POP ();
PUSH (x);
PUSH (x);
break;
case ROT:
y = POP ();
x = POP ();
PUSH (y);
PUSH (x);
break;
case BINARY_ADD:
y = POP ();
x = POP ();
PUSH (x + y);
break;
case BINARY_SUBTRACT:
y = POP ();
x = POP ();
PUSH (x - y);
break;
case BINARY_MULT:
y = POP ();
x = POP ();
PUSH (x * y);
break;
case BINARY_COMPARE_LT:
y = POP ();
x = POP ();
PUSH (x < y);
break;
case RECURSE:
x = POP ();
x = toyvm_function_interpret (fn, x, trace);
PUSH (x);
break;
case RETURN:
return POP ();
/* Ops taking an operand. */
case PUSH_CONST:
PUSH (op->op_operand);
break;
case JUMP_ABS_IF_TRUE:
x = POP ();
if (x)
frame.frm_pc = op->op_operand;
break;
default:
assert (0); /* unknown opcode */
@} /* end of switch on opcode */
@} /* end of while loop */
#undef PUSH
#undef POP
@}
@end example
@end quotation
@node Compiling to machine code,Setting things up,Our toy interpreter,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 compiling-to-machine-code}@anchor{38}
@subsection Compiling to machine code
We want to generate machine code that can be cast to this type and
then directly executed in-process:
@quotation
@example
typedef int (*toyvm_compiled_code) (int);
@end example
@end quotation
The lifetime of the code is tied to that of a @ref{16,,gcc_jit_result *}.
We’ll handle this by bundling them up in a structure, so that we can
clean them up together by calling @ref{39,,gcc_jit_result_release()}:
@quotation
@example
struct toyvm_compiled_function
@{
gcc_jit_result *cf_jit_result;
toyvm_compiled_code cf_code;
@};
@end example
@end quotation
Our compiler isn’t very sophisticated; it takes the implementation of
each opcode above, and maps it directly to the operations supported by
the libgccjit API.
How should we handle the stack? In theory we could calculate what the
stack depth will be at each opcode, and optimize away the stack
manipulation “by hand”. We’ll see below that libgccjit is able to do
this for us, so we’ll implement stack manipulation
in a direct way, by creating a @code{stack} array and @code{stack_depth}
variables, local within the generated function, equivalent to this C code:
@example
int stack_depth;
int stack[MAX_STACK_DEPTH];
@end example
We’ll also have local variables @code{x} and @code{y} for use when implementing
the opcodes, equivalent to this:
@example
int x;
int y;
@end example
This means our compiler has the following state:
@quotation
@example
struct compilation_state
@{
gcc_jit_context *ctxt;
gcc_jit_type *int_type;
gcc_jit_type *bool_type;
gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
gcc_jit_rvalue *const_one;
gcc_jit_function *fn;
gcc_jit_param *param_arg;
gcc_jit_lvalue *stack;
gcc_jit_lvalue *stack_depth;
gcc_jit_lvalue *x;
gcc_jit_lvalue *y;
gcc_jit_location *op_locs[MAX_OPS];
gcc_jit_block *initial_block;
gcc_jit_block *op_blocks[MAX_OPS];
@};
@end example
@end quotation
@node Setting things up,Populating the function,Compiling to machine code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 setting-things-up}@anchor{3a}
@subsection Setting things up
First we create our types:
@quotation
@example
state.int_type =
gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
state.bool_type =
gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
state.stack_type =
gcc_jit_context_new_array_type (state.ctxt, NULL,
state.int_type, MAX_STACK_DEPTH);
@end example
@end quotation
along with extracting a useful @cite{int} constant:
@quotation
@example
state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
@end example
@end quotation
We’ll implement push and pop in terms of the @code{stack} array and
@code{stack_depth}. Here are helper functions for adding statements to
a block, implementing pushing and popping values:
@quotation
@example
static void
add_push (compilation_state *state,
gcc_jit_block *block,
gcc_jit_rvalue *rvalue,
gcc_jit_location *loc)
@{
/* stack[stack_depth] = RVALUE */
gcc_jit_block_add_assignment (
block,
loc,
/* stack[stack_depth] */
gcc_jit_context_new_array_access (
state->ctxt,
loc,
gcc_jit_lvalue_as_rvalue (state->stack),
gcc_jit_lvalue_as_rvalue (state->stack_depth)),
rvalue);
/* "stack_depth++;". */
gcc_jit_block_add_assignment_op (
block,
loc,
state->stack_depth,
GCC_JIT_BINARY_OP_PLUS,
state->const_one);
@}
static void
add_pop (compilation_state *state,
gcc_jit_block *block,
gcc_jit_lvalue *lvalue,
gcc_jit_location *loc)
@{
/* "--stack_depth;". */
gcc_jit_block_add_assignment_op (
block,
loc,
state->stack_depth,
GCC_JIT_BINARY_OP_MINUS,
state->const_one);
/* "LVALUE = stack[stack_depth];". */
gcc_jit_block_add_assignment (
block,
loc,
lvalue,
/* stack[stack_depth] */
gcc_jit_lvalue_as_rvalue (
gcc_jit_context_new_array_access (
state->ctxt,
loc,
gcc_jit_lvalue_as_rvalue (state->stack),
gcc_jit_lvalue_as_rvalue (state->stack_depth))));
@}
@end example
@end quotation
We will support single-stepping through the generated code in the
debugger, so we need to create @ref{3b,,gcc_jit_location} instances, one
per operation in the source code. These will reference the lines of
e.g. @code{factorial.toy}.
@quotation
@example
for (pc = 0; pc < fn->fn_num_ops; pc++)
@{
toyvm_op *op = &fn->fn_ops[pc];
state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
fn->fn_filename,
op->op_linenum,
0); /* column */
@}
@end example
@end quotation
Let’s create the function itself. As usual, we create its parameter
first, then use the parameter to create the function:
@quotation
@example
state.param_arg =
gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
state.int_type, "arg");
state.fn =
gcc_jit_context_new_function (state.ctxt,
state.op_locs[0],
GCC_JIT_FUNCTION_EXPORTED,
state.int_type,
funcname,
1, &state.param_arg, 0);
@end example
@end quotation
We create the locals within the function.
@quotation
@example
state.stack =
gcc_jit_function_new_local (state.fn, NULL,
state.stack_type, "stack");
state.stack_depth =
gcc_jit_function_new_local (state.fn, NULL,
state.int_type, "stack_depth");
state.x =
gcc_jit_function_new_local (state.fn, NULL,
state.int_type, "x");
state.y =
gcc_jit_function_new_local (state.fn, NULL,
state.int_type, "y");
@end example
@end quotation
@node Populating the function,Verifying the control flow graph,Setting things up,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 populating-the-function}@anchor{3c}
@subsection Populating the function
There’s some one-time initialization, and the API treats the first block
you create as the entrypoint of the function, so we need to create that
block first:
@quotation
@example
state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
@end example
@end quotation
We can now create blocks for each of the operations. Most of these will
be consolidated into larger blocks when the optimizer runs.
@quotation
@example
for (pc = 0; pc < fn->fn_num_ops; pc++)
@{
char buf[100];
sprintf (buf, "instr%i", pc);
state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
@}
@end example
@end quotation
Now that we have a block it can jump to when it’s done, we can populate
the initial block:
@quotation
@example
/* "stack_depth = 0;". */
gcc_jit_block_add_assignment (
state.initial_block,
state.op_locs[0],
state.stack_depth,
gcc_jit_context_zero (state.ctxt, state.int_type));
/* "PUSH (arg);". */
add_push (&state,
state.initial_block,
gcc_jit_param_as_rvalue (state.param_arg),
state.op_locs[0]);
/* ...and jump to insn 0. */
gcc_jit_block_end_with_jump (state.initial_block,
state.op_locs[0],
state.op_blocks[0]);
@end example
@end quotation
We can now populate the blocks for the individual operations. We loop
through them, adding instructions to their blocks:
@quotation
@example
for (pc = 0; pc < fn->fn_num_ops; pc++)
@{
gcc_jit_location *loc = state.op_locs[pc];
gcc_jit_block *block = state.op_blocks[pc];
gcc_jit_block *next_block = (pc < fn->fn_num_ops
? state.op_blocks[pc + 1]
: NULL);
toyvm_op *op;
op = &fn->fn_ops[pc];
@end example
@end quotation
We’re going to have another big @code{switch} statement for implementing
the opcodes, this time for compiling them, rather than interpreting
them. It’s helpful to have macros for implementing push and pop, so that
we can make the @code{switch} statement that’s coming up look as much as
possible like the one above within the interpreter:
@example
#define X_EQUALS_POP()\
add_pop (&state, block, state.x, loc)
#define Y_EQUALS_POP()\
add_pop (&state, block, state.y, loc)
#define PUSH_RVALUE(RVALUE)\
add_push (&state, block, (RVALUE), loc)
#define PUSH_X()\
PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
#define PUSH_Y() \
PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
@end example
@cartouche
@quotation Note
A particularly clever implementation would have an @emph{identical}
@code{switch} statement shared by the interpreter and the compiler, with
some preprocessor “magic”. We’re not doing that here, for the sake
of simplicity.
@end quotation
@end cartouche
When I first implemented this compiler, I accidentally missed an edit
when copying and pasting the @code{Y_EQUALS_POP} macro, so that popping the
stack into @code{y} instead erroneously assigned it to @code{x}, leaving @code{y}
uninitialized.
To track this kind of thing down, we can use
@ref{3d,,gcc_jit_block_add_comment()} to add descriptive comments
to the internal representation. This is invaluable when looking through
the generated IR for, say @code{factorial}:
@quotation
@example
gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
@end example
@end quotation
We can now write the big @code{switch} statement that implements the
individual opcodes, populating the relevant block with statements:
@quotation
@example
switch (op->op_opcode)
@{
case DUP:
X_EQUALS_POP ();
PUSH_X ();
PUSH_X ();
break;
case ROT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_Y ();
PUSH_X ();
break;
case BINARY_ADD:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
gcc_jit_context_new_binary_op (
state.ctxt,
loc,
GCC_JIT_BINARY_OP_PLUS,
state.int_type,
gcc_jit_lvalue_as_rvalue (state.x),
gcc_jit_lvalue_as_rvalue (state.y)));
break;
case BINARY_SUBTRACT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
gcc_jit_context_new_binary_op (
state.ctxt,
loc,
GCC_JIT_BINARY_OP_MINUS,
state.int_type,
gcc_jit_lvalue_as_rvalue (state.x),
gcc_jit_lvalue_as_rvalue (state.y)));
break;
case BINARY_MULT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
gcc_jit_context_new_binary_op (
state.ctxt,
loc,
GCC_JIT_BINARY_OP_MULT,
state.int_type,
gcc_jit_lvalue_as_rvalue (state.x),
gcc_jit_lvalue_as_rvalue (state.y)));
break;
case BINARY_COMPARE_LT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
/* cast of bool to int */
gcc_jit_context_new_cast (
state.ctxt,
loc,
/* (x < y) as a bool */
gcc_jit_context_new_comparison (
state.ctxt,
loc,
GCC_JIT_COMPARISON_LT,
gcc_jit_lvalue_as_rvalue (state.x),
gcc_jit_lvalue_as_rvalue (state.y)),
state.int_type));
break;
case RECURSE:
@{
X_EQUALS_POP ();
gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
PUSH_RVALUE (
gcc_jit_context_new_call (
state.ctxt,
loc,
state.fn,
1, &arg));
break;
@}
case RETURN:
X_EQUALS_POP ();
gcc_jit_block_end_with_return (
block,
loc,
gcc_jit_lvalue_as_rvalue (state.x));
break;
/* Ops taking an operand. */
case PUSH_CONST:
PUSH_RVALUE (
gcc_jit_context_new_rvalue_from_int (
state.ctxt,
state.int_type,
op->op_operand));
break;
case JUMP_ABS_IF_TRUE:
X_EQUALS_POP ();
gcc_jit_block_end_with_conditional (
block,
loc,
/* "(bool)x". */
gcc_jit_context_new_cast (
state.ctxt,
loc,
gcc_jit_lvalue_as_rvalue (state.x),
state.bool_type),
state.op_blocks[op->op_operand], /* on_true */
next_block); /* on_false */
break;
default:
assert(0);
@} /* end of switch on opcode */
@end example
@end quotation
Every block must be terminated, via a call to one of the
@code{gcc_jit_block_end_with_} entrypoints. This has been done for two
of the opcodes, but we need to do it for the other ones, by jumping
to the next block.
@quotation
@example
if (op->op_opcode != JUMP_ABS_IF_TRUE
&& op->op_opcode != RETURN)
gcc_jit_block_end_with_jump (
block,
loc,
next_block);
@end example
@end quotation
This is analogous to simply incrementing the program counter.
@node Verifying the control flow graph,Compiling the context,Populating the function,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 verifying-the-control-flow-graph}@anchor{3e}
@subsection Verifying the control flow graph
Having finished looping over the blocks, the context is complete.
As before, we can verify that the control flow and statements are sane by
using @ref{33,,gcc_jit_function_dump_to_dot()}:
@example
gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot");
@end example
and viewing the result. Note how the label names, comments, and
variable names show up in the dump, to make it easier to spot
errors in our compiler.
@quotation
@float Figure
@image{libgccjit-figures/factorial1,,,image of a control flow graph,png}
@end float
@end quotation
@node Compiling the context,Single-stepping through the generated code,Verifying the control flow graph,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 compiling-the-context}@anchor{3f}
@subsection Compiling the context
Having finished looping over the blocks and populating them with
statements, the context is complete.
We can now compile it, and extract machine code from the result:
@quotation
@end quotation
We can now run the result:
@quotation
@example
toyvm_compiled_function *compiled_fn
= toyvm_function_compile (fn);
toyvm_compiled_code code = compiled_fn->cf_code;
printf ("compiler result: %d\n",
code (atoi (argv[2])));
gcc_jit_result_release (compiled_fn->cf_jit_result);
free (compiled_fn);
@end example
@end quotation
@node Single-stepping through the generated code,Examining the generated code,Compiling the context,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 single-stepping-through-the-generated-code}@anchor{40}
@subsection Single-stepping through the generated code
It’s possible to debug the generated code. To do this we need to both:
@quotation
@itemize *
@item
Set up source code locations for our statements, so that we can
meaningfully step through the code. We did this above by
calling @ref{41,,gcc_jit_context_new_location()} and using the
results.
@item
Enable the generation of debugging information, by setting
@ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@ref{8,,gcc_jit_context} via
@ref{1b,,gcc_jit_context_set_bool_option()}:
@example
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DEBUGINFO,
1);
@end example
@end itemize
@end quotation
Having done this, we can put a breakpoint on the generated function:
@example
$ gdb --args ./toyvm factorial.toy 10
(gdb) break factorial
Function "factorial" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (factorial) pending.
(gdb) run
Breakpoint 1, factorial (arg=10) at factorial.toy:14
14 DUP
@end example
We’ve set up location information, which references @code{factorial.toy}.
This allows us to use e.g. @code{list} to see where we are in the script:
@example
(gdb) list
9
10 # Initial state:
11 # stack: [arg]
12
13 # 0:
14 DUP
15 # stack: [arg, arg]
16
17 # 1:
18 PUSH_CONST 2
@end example
and to step through the function, examining the data:
@example
(gdb) n
18 PUSH_CONST 2
(gdb) n
22 BINARY_COMPARE_LT
(gdb) print stack
$5 = @{10, 10, 2, 0, -7152, 32767, 0, 0@}
(gdb) print stack_depth
$6 = 3
@end example
You’ll see that the parts of the @code{stack} array that haven’t been
touched yet are uninitialized.
@cartouche
@quotation Note
Turning on optimizations may lead to unpredictable results when
stepping through the generated code: the execution may appear to
“jump around” the source code. This is analogous to turning up the
optimization level in a regular compiler.
@end quotation
@end cartouche
@node Examining the generated code,Putting it all together,Single-stepping through the generated code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 examining-the-generated-code}@anchor{43}
@subsection Examining the generated code
How good is the optimized code?
We can turn up optimizations, by calling
@ref{1e,,gcc_jit_context_set_int_option()} with
@ref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
@end example
One of GCC’s internal representations is called “gimple”. A dump of the
initial gimple representation of the code can be seen by setting:
@example
gcc_jit_context_set_bool_option (ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
1);
@end example
With optimization on and source locations displayed, this gives:
@c We'll use "c" for gimple dumps
@example
factorial (signed int arg)
@{
<unnamed type> D.80;
signed int D.81;
signed int D.82;
signed int D.83;
signed int D.84;
signed int D.85;
signed int y;
signed int x;
signed int stack_depth;
signed int stack[8];
try
@{
initial:
stack_depth = 0;
stack[stack_depth] = arg;
stack_depth = stack_depth + 1;
goto instr0;
instr0:
/* DUP */:
stack_depth = stack_depth + -1;
x = stack[stack_depth];
stack[stack_depth] = x;
stack_depth = stack_depth + 1;
stack[stack_depth] = x;
stack_depth = stack_depth + 1;
goto instr1;
instr1:
/* PUSH_CONST */:
stack[stack_depth] = 2;
stack_depth = stack_depth + 1;
goto instr2;
/* etc */
@end example
You can see the generated machine code in assembly form via:
@example
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
1);
result = gcc_jit_context_compile (ctxt);
@end example
which shows that (on this x86_64 box) the compiler has unrolled the loop
and is using MMX instructions to perform several multiplications
simultaneously:
@example
.file "fake.c"
.text
.Ltext0:
.p2align 4,,15
.globl factorial
.type factorial, @@function
factorial:
.LFB0:
.file 1 "factorial.toy"
.loc 1 14 0
.cfi_startproc
.LVL0:
.L2:
.loc 1 26 0
cmpl $1, %edi
jle .L13
leal -1(%rdi), %edx
movl %edx, %ecx
shrl $2, %ecx
leal 0(,%rcx,4), %esi
testl %esi, %esi
je .L14
cmpl $9, %edx
jbe .L14
leal -2(%rdi), %eax
movl %eax, -16(%rsp)
leal -3(%rdi), %eax
movd -16(%rsp), %xmm0
movl %edi, -16(%rsp)
movl %eax, -12(%rsp)
movd -16(%rsp), %xmm1
xorl %eax, %eax
movl %edx, -16(%rsp)
movd -12(%rsp), %xmm4
movd -16(%rsp), %xmm6
punpckldq %xmm4, %xmm0
movdqa .LC1(%rip), %xmm4
punpckldq %xmm6, %xmm1
punpcklqdq %xmm0, %xmm1
movdqa .LC0(%rip), %xmm0
jmp .L5
# etc - edited for brevity
@end example
This is clearly overkill for a function that will likely overflow the
@code{int} type before the vectorization is worthwhile - but then again, this
is a toy example.
Turning down the optimization level to 2:
@example
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
@end example
yields this code, which is simple enough to quote in its entirety:
@example
.file "fake.c"
.text
.p2align 4,,15
.globl factorial
.type factorial, @@function
factorial:
.LFB0:
.cfi_startproc
.L2:
cmpl $1, %edi
jle .L8
movl $1, %edx
jmp .L4
.p2align 4,,10
.p2align 3
.L6:
movl %eax, %edi
.L4:
.L5:
leal -1(%rdi), %eax
imull %edi, %edx
cmpl $1, %eax
jne .L6
.L3:
.L7:
imull %edx, %eax
ret
.L8:
movl %edi, %eax
movl $1, %edx
jmp .L7
.cfi_endproc
.LFE0:
.size factorial, .-factorial
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-%@{gcc_release@})"
.section .note.GNU-stack,"",@@progbits
@end example
Note that the stack pushing and popping have been eliminated, as has the
recursive call (in favor of an iteration).
@node Putting it all together,Behind the curtain How does our code get optimized?,Examining the generated code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 putting-it-all-together}@anchor{44}
@subsection Putting it all together
The complete example can be seen in the source tree at
@code{gcc/jit/docs/examples/tut04-toyvm/toyvm.c}
along with a Makefile and a couple of sample .toy scripts:
@example
$ ls -al
drwxrwxr-x. 2 david david 4096 Sep 19 17:46 .
drwxrwxr-x. 3 david david 4096 Sep 19 15:26 ..
-rw-rw-r--. 1 david david 615 Sep 19 12:43 factorial.toy
-rw-rw-r--. 1 david david 834 Sep 19 13:08 fibonacci.toy
-rw-rw-r--. 1 david david 238 Sep 19 14:22 Makefile
-rw-rw-r--. 1 david david 16457 Sep 19 17:07 toyvm.c
$ make toyvm
g++ -Wall -g -o toyvm toyvm.c -lgccjit
$ ./toyvm factorial.toy 10
interpreter result: 3628800
compiler result: 3628800
$ ./toyvm fibonacci.toy 10
interpreter result: 55
compiler result: 55
@end example
@node Behind the curtain How does our code get optimized?,,Putting it all together,Tutorial part 4 Adding JIT-compilation to a toy interpreter
@anchor{intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{45}
@subsection Behind the curtain: How does our code get optimized?
Our example is done, but you may be wondering about exactly how the
compiler turned what we gave it into the machine code seen above.
We can examine what the compiler is doing in detail by setting:
@example
gcc_jit_context_set_bool_option (state.ctxt,
GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
1);
gcc_jit_context_set_bool_option (state.ctxt,
GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
1);
@end example
This will dump detailed information about the compiler’s state to a
directory under @code{/tmp}, and keep it from being cleaned up.
The precise names and their formats of these files is subject to change.
Higher optimization levels lead to more files.
Here’s what I saw (edited for brevity; there were almost 200 files):
@example
intermediate files written to /tmp/libgccjit-KPQbGw
$ ls /tmp/libgccjit-KPQbGw/
fake.c.000i.cgraph
fake.c.000i.type-inheritance
fake.c.004t.gimple
fake.c.007t.omplower
fake.c.008t.lower
fake.c.011t.eh
fake.c.012t.cfg
fake.c.014i.visibility
fake.c.015i.early_local_cleanups
fake.c.016t.ssa
# etc
@end example
The gimple code is converted into Static Single Assignment form,
with annotations for use when generating the debuginfo:
@example
$ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
signed int _56;
initial:
stack_depth_3 = 0;
# DEBUG stack_depth => stack_depth_3
stack[stack_depth_3] = arg_5(D);
stack_depth_7 = stack_depth_3 + 1;
# DEBUG stack_depth => stack_depth_7
# DEBUG instr0 => NULL
# DEBUG /* DUP */ => NULL
stack_depth_8 = stack_depth_7 + -1;
# DEBUG stack_depth => stack_depth_8
x_9 = stack[stack_depth_8];
# DEBUG x => x_9
stack[stack_depth_8] = x_9;
stack_depth_11 = stack_depth_8 + 1;
# DEBUG stack_depth => stack_depth_11
stack[stack_depth_11] = x_9;
stack_depth_13 = stack_depth_11 + 1;
# DEBUG stack_depth => stack_depth_13
# DEBUG instr1 => NULL
# DEBUG /* PUSH_CONST */ => NULL
stack[stack_depth_13] = 2;
/* etc; edited for brevity */
@end example
We can perhaps better see the code by turning off
@ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to suppress all those @code{DEBUG}
statements, giving:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
signed int _56;
initial:
stack_depth_3 = 0;
stack[stack_depth_3] = arg_5(D);
stack_depth_7 = stack_depth_3 + 1;
stack_depth_8 = stack_depth_7 + -1;
x_9 = stack[stack_depth_8];
stack[stack_depth_8] = x_9;
stack_depth_11 = stack_depth_8 + 1;
stack[stack_depth_11] = x_9;
stack_depth_13 = stack_depth_11 + 1;
stack[stack_depth_13] = 2;
stack_depth_15 = stack_depth_13 + 1;
stack_depth_16 = stack_depth_15 + -1;
y_17 = stack[stack_depth_16];
stack_depth_18 = stack_depth_16 + -1;
x_19 = stack[stack_depth_18];
_20 = x_19 < y_17;
_21 = (signed int) _20;
stack[stack_depth_18] = _21;
stack_depth_23 = stack_depth_18 + 1;
stack_depth_24 = stack_depth_23 + -1;
x_25 = stack[stack_depth_24];
if (x_25 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
stack_depth_26 = stack_depth_24 + -1;
x_27 = stack[stack_depth_26];
stack[stack_depth_26] = x_27;
stack_depth_29 = stack_depth_26 + 1;
stack[stack_depth_29] = x_27;
stack_depth_31 = stack_depth_29 + 1;
stack[stack_depth_31] = 1;
stack_depth_33 = stack_depth_31 + 1;
stack_depth_34 = stack_depth_33 + -1;
y_35 = stack[stack_depth_34];
stack_depth_36 = stack_depth_34 + -1;
x_37 = stack[stack_depth_36];
_38 = x_37 - y_35;
stack[stack_depth_36] = _38;
stack_depth_40 = stack_depth_36 + 1;
stack_depth_41 = stack_depth_40 + -1;
x_42 = stack[stack_depth_41];
_44 = factorial (x_42);
stack[stack_depth_41] = _44;
stack_depth_46 = stack_depth_41 + 1;
stack_depth_47 = stack_depth_46 + -1;
y_48 = stack[stack_depth_47];
stack_depth_49 = stack_depth_47 + -1;
x_50 = stack[stack_depth_49];
_51 = x_50 * y_48;
stack[stack_depth_49] = _51;
stack_depth_53 = stack_depth_49 + 1;
# stack_depth_1 = PHI <stack_depth_24(2), stack_depth_53(3)>
instr9:
/* RETURN */:
stack_depth_54 = stack_depth_1 + -1;
x_55 = stack[stack_depth_54];
_56 = x_55;
stack =@{v@} @{CLOBBER@};
return _56;
@}
@end example
Note in the above how all the @ref{28,,gcc_jit_block} instances we
created have been consolidated into just 3 blocks in GCC’s internal
representation: @code{initial}, @code{instr4} and @code{instr9}.
@menu
* Optimizing away stack manipulation::
* Elimination of tail recursion::
@end menu
@node Optimizing away stack manipulation,Elimination of tail recursion,,Behind the curtain How does our code get optimized?
@anchor{intro/tutorial04 optimizing-away-stack-manipulation}@anchor{46}
@subsubsection Optimizing away stack manipulation
Recall our simple implementation of stack operations. Let’s examine
how the stack operations are optimized away.
After a pass of constant-propagation, the depth of the stack at each
opcode can be determined at compile-time:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
initial:
stack[0] = arg_5(D);
x_9 = stack[0];
stack[0] = x_9;
stack[1] = x_9;
stack[2] = 2;
y_17 = stack[2];
x_19 = stack[1];
_20 = x_19 < y_17;
_21 = (signed int) _20;
stack[1] = _21;
x_25 = stack[1];
if (x_25 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
x_27 = stack[0];
stack[0] = x_27;
stack[1] = x_27;
stack[2] = 1;
y_35 = stack[2];
x_37 = stack[1];
_38 = x_37 - y_35;
stack[1] = _38;
x_42 = stack[1];
_44 = factorial (x_42);
stack[1] = _44;
y_48 = stack[1];
x_50 = stack[0];
_51 = x_50 * y_48;
stack[0] = _51;
instr9:
/* RETURN */:
x_55 = stack[0];
x_56 = x_55;
stack =@{v@} @{CLOBBER@};
return x_56;
@}
@end example
Note how, in the above, all those @code{stack_depth} values are now just
constants: we’re accessing specific stack locations at each opcode.
The “esra” pass (“Early Scalar Replacement of Aggregates”) breaks
out our “stack” array into individual elements:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
Created a replacement for stack offset: 0, size: 32: stack$0
Created a replacement for stack offset: 32, size: 32: stack$1
Created a replacement for stack offset: 64, size: 32: stack$2
Symbols to be put in SSA form
@{ D.89 D.90 D.91 @}
Incremental SSA update started at block: 0
Number of blocks in CFG: 5
Number of blocks to update: 4 ( 80%)
factorial (signed int arg)
@{
signed int stack$2;
signed int stack$1;
signed int stack$0;
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
initial:
stack$0_45 = arg_5(D);
x_9 = stack$0_45;
stack$0_39 = x_9;
stack$1_32 = x_9;
stack$2_30 = 2;
y_17 = stack$2_30;
x_19 = stack$1_32;
_20 = x_19 < y_17;
_21 = (signed int) _20;
stack$1_28 = _21;
x_25 = stack$1_28;
if (x_25 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
x_27 = stack$0_39;
stack$0_22 = x_27;
stack$1_14 = x_27;
stack$2_12 = 1;
y_35 = stack$2_12;
x_37 = stack$1_14;
_38 = x_37 - y_35;
stack$1_10 = _38;
x_42 = stack$1_10;
_44 = factorial (x_42);
stack$1_6 = _44;
y_48 = stack$1_6;
x_50 = stack$0_22;
_51 = x_50 * y_48;
stack$0_1 = _51;
# stack$0_52 = PHI <stack$0_39(2), stack$0_1(3)>
instr9:
/* RETURN */:
x_55 = stack$0_52;
x_56 = x_55;
stack =@{v@} @{CLOBBER@};
return x_56;
@}
@end example
Hence at this point, all those pushes and pops of the stack are now
simply assignments to specific temporary variables.
After some copy propagation, the stack manipulation has been completely
optimized away:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack$2;
signed int stack$1;
signed int stack$0;
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
initial:
stack$0_39 = arg_5(D);
_20 = arg_5(D) <= 1;
_21 = (signed int) _20;
if (_21 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
_38 = arg_5(D) + -1;
_44 = factorial (_38);
_51 = arg_5(D) * _44;
stack$0_1 = _51;
# stack$0_52 = PHI <arg_5(D)(2), _51(3)>
instr9:
/* RETURN */:
stack =@{v@} @{CLOBBER@};
return stack$0_52;
@}
@end example
Later on, another pass finally eliminated @code{stack_depth} local and the
unused parts of the @cite{stack`} array altogether:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
Released 44 names, 314.29%, removed 44 holes
factorial (signed int arg)
@{
signed int stack$0;
signed int mult_acc_1;
<unnamed type> _5;
signed int _6;
signed int _7;
signed int mul_tmp_10;
signed int mult_acc_11;
signed int mult_acc_13;
# arg_9 = PHI <arg_8(D)(0)>
# mult_acc_13 = PHI <1(0)>
initial:
<bb 5>:
# arg_4 = PHI <arg_9(2), _7(3)>
# mult_acc_1 = PHI <mult_acc_13(2), mult_acc_11(3)>
_5 = arg_4 <= 1;
_6 = (signed int) _5;
if (_6 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
_7 = arg_4 + -1;
mult_acc_11 = mult_acc_1 * arg_4;
goto <bb 5>;
# stack$0_12 = PHI <arg_4(5)>
instr9:
/* RETURN */:
mul_tmp_10 = mult_acc_1 * stack$0_12;
return mul_tmp_10;
@}
@end example
@node Elimination of tail recursion,,Optimizing away stack manipulation,Behind the curtain How does our code get optimized?
@anchor{intro/tutorial04 elimination-of-tail-recursion}@anchor{47}
@subsubsection Elimination of tail recursion
Another significant optimization is the detection that the call to
@code{factorial} is tail recursion, which can be eliminated in favor of
an iteration:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
Symbols to be put in SSA form
@{ D.88 @}
Incremental SSA update started at block: 0
Number of blocks in CFG: 5
Number of blocks to update: 4 ( 80%)
factorial (signed int arg)
@{
signed int stack$2;
signed int stack$1;
signed int stack$0;
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
signed int mult_acc_1;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int mul_tmp_44;
signed int mult_acc_51;
# arg_5 = PHI <arg_39(D)(0), _38(3)>
# mult_acc_1 = PHI <1(0), mult_acc_51(3)>
initial:
_20 = arg_5 <= 1;
_21 = (signed int) _20;
if (_21 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
_38 = arg_5 + -1;
mult_acc_51 = mult_acc_1 * arg_5;
goto <bb 2> (initial);
# stack$0_52 = PHI <arg_5(2)>
instr9:
/* RETURN */:
stack =@{v@} @{CLOBBER@};
mul_tmp_44 = mult_acc_1 * stack$0_52;
return mul_tmp_44;
@}
@end example
@c Copyright (C) 2015-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 5 Implementing an Ahead-of-Time compiler,,Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial
@anchor{intro/tutorial05 doc}@anchor{48}@anchor{intro/tutorial05 tutorial-part-5-implementing-an-ahead-of-time-compiler}@anchor{49}
@section Tutorial part 5: Implementing an Ahead-of-Time compiler
If you have a pre-existing language frontend that’s compatible with
libgccjit’s license, it’s possible to hook it up to libgccjit as a
backend. In the previous example we showed
how to do that for in-memory JIT-compilation, but libgccjit can also
compile code directly to a file, allowing you to implement a more
traditional ahead-of-time compiler (“JIT” is something of a misnomer
for this use-case).
The essential difference is to compile the context using
@ref{4a,,gcc_jit_context_compile_to_file()} rather than
@ref{15,,gcc_jit_context_compile()}.
@menu
* The “brainf” language::
* Converting a brainf script to libgccjit IR::
* Compiling a context to a file::
* Other forms of ahead-of-time-compilation::
@end menu
@node The “brainf” language,Converting a brainf script to libgccjit IR,,Tutorial part 5 Implementing an Ahead-of-Time compiler
@anchor{intro/tutorial05 the-brainf-language}@anchor{4b}
@subsection The “brainf” language
In this example we use libgccjit to construct an ahead-of-time compiler
for an esoteric programming language that we shall refer to as “brainf”.
brainf scripts operate on an array of bytes, with a notional data pointer
within the array.
brainf is hard for humans to read, but it’s trivial to write a parser for
it, as there is no lexing; just a stream of bytes. The operations are:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
@headitem
Character
@tab
Meaning
@item
@code{>}
@tab
@code{idx += 1}
@item
@code{<}
@tab
@code{idx -= 1}
@item
@code{+}
@tab
@code{data[idx] += 1}
@item
@code{-}
@tab
@code{data[idx] -= 1}
@item
@code{.}
@tab
@code{output (data[idx])}
@item
@code{,}
@tab
@code{data[idx] = input ()}
@item
@code{[}
@tab
loop until @code{data[idx] == 0}
@item
@code{]}
@tab
end of loop
@item
Anything else
@tab
ignored
@end multitable
Unlike the previous example, we’ll implement an ahead-of-time compiler,
which reads @code{.bf} scripts and outputs executables (though it would
be trivial to have it run them JIT-compiled in-process).
Here’s what a simple @code{.bf} script looks like:
@quotation
@example
[
Emit the uppercase alphabet
]
cell 0 = 26
++++++++++++++++++++++++++
cell 1 = 65
>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
while cell#0 != 0
[
>
. emit cell#1
+ increment cell@@1
<- decrement cell@@0
]
@end example
@end quotation
@cartouche
@quotation Note
This example makes use of whitespace and comments for legibility, but
could have been written as:
@example
++++++++++++++++++++++++++
>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
[>.+<-]
@end example
It’s not a particularly useful language, except for providing
compiler-writers with a test case that’s easy to parse. The point
is that you can use @ref{4a,,gcc_jit_context_compile_to_file()}
to use libgccjit as a backend for a pre-existing language frontend
(provided that the pre-existing frontend is compatible with libgccjit’s
license).
@end quotation
@end cartouche
@node Converting a brainf script to libgccjit IR,Compiling a context to a file,The “brainf” language,Tutorial part 5 Implementing an Ahead-of-Time compiler
@anchor{intro/tutorial05 converting-a-brainf-script-to-libgccjit-ir}@anchor{4c}
@subsection Converting a brainf script to libgccjit IR
As before we write simple code to populate a @ref{8,,gcc_jit_context *}.
@quotation
@example
typedef struct bf_compiler
@{
const char *filename;
int line;
int column;
gcc_jit_context *ctxt;
gcc_jit_type *void_type;
gcc_jit_type *int_type;
gcc_jit_type *byte_type;
gcc_jit_type *array_type;
gcc_jit_function *func_getchar;
gcc_jit_function *func_putchar;
gcc_jit_function *func;
gcc_jit_block *curblock;
gcc_jit_rvalue *int_zero;
gcc_jit_rvalue *int_one;
gcc_jit_rvalue *byte_zero;
gcc_jit_rvalue *byte_one;
gcc_jit_lvalue *data_cells;
gcc_jit_lvalue *idx;
int num_open_parens;
gcc_jit_block *paren_test[MAX_OPEN_PARENS];
gcc_jit_block *paren_body[MAX_OPEN_PARENS];
gcc_jit_block *paren_after[MAX_OPEN_PARENS];
@} bf_compiler;
/* Bail out, with a message on stderr. */
static void
fatal_error (bf_compiler *bfc, const char *msg)
@{
fprintf (stderr,
"%s:%i:%i: %s",
bfc->filename, bfc->line, bfc->column, msg);
abort ();
@}
/* Get "data_cells[idx]" as an lvalue. */
static gcc_jit_lvalue *
bf_get_current_data (bf_compiler *bfc, gcc_jit_location *loc)
@{
return gcc_jit_context_new_array_access (
bfc->ctxt,
loc,
gcc_jit_lvalue_as_rvalue (bfc->data_cells),
gcc_jit_lvalue_as_rvalue (bfc->idx));
@}
/* Get "data_cells[idx] == 0" as a boolean rvalue. */
static gcc_jit_rvalue *
bf_current_data_is_zero (bf_compiler *bfc, gcc_jit_location *loc)
@{
return gcc_jit_context_new_comparison (
bfc->ctxt,
loc,
GCC_JIT_COMPARISON_EQ,
gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
bfc->byte_zero);
@}
/* Compile one bf character. */
static void
bf_compile_char (bf_compiler *bfc,
unsigned char ch)
@{
gcc_jit_location *loc =
gcc_jit_context_new_location (bfc->ctxt,
bfc->filename,
bfc->line,
bfc->column);
/* Turn this on to trace execution, by injecting putchar ()
of each source char. */
if (0)
@{
gcc_jit_rvalue *arg =
gcc_jit_context_new_rvalue_from_int (
bfc->ctxt,
bfc->int_type,
ch);
gcc_jit_rvalue *call =
gcc_jit_context_new_call (bfc->ctxt,
loc,
bfc->func_putchar,
1, &arg);
gcc_jit_block_add_eval (bfc->curblock,
loc,
call);
@}
switch (ch)
@{
case '>':
gcc_jit_block_add_comment (bfc->curblock,
loc,
"'>': idx += 1;");
gcc_jit_block_add_assignment_op (bfc->curblock,
loc,
bfc->idx,
GCC_JIT_BINARY_OP_PLUS,
bfc->int_one);
break;
case '<':
gcc_jit_block_add_comment (bfc->curblock,
loc,
"'<': idx -= 1;");
gcc_jit_block_add_assignment_op (bfc->curblock,
loc,
bfc->idx,
GCC_JIT_BINARY_OP_MINUS,
bfc->int_one);
break;
case '+':
gcc_jit_block_add_comment (bfc->curblock,
loc,
"'+': data[idx] += 1;");
gcc_jit_block_add_assignment_op (bfc->curblock,
loc,
bf_get_current_data (bfc, loc),
GCC_JIT_BINARY_OP_PLUS,
bfc->byte_one);
break;
case '-':
gcc_jit_block_add_comment (bfc->curblock,
loc,
"'-': data[idx] -= 1;");
gcc_jit_block_add_assignment_op (bfc->curblock,
loc,
bf_get_current_data (bfc, loc),
GCC_JIT_BINARY_OP_MINUS,
bfc->byte_one);
break;
case '.':
@{
gcc_jit_rvalue *arg =
gcc_jit_context_new_cast (
bfc->ctxt,
loc,
gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
bfc->int_type);
gcc_jit_rvalue *call =
gcc_jit_context_new_call (bfc->ctxt,
loc,
bfc->func_putchar,
1, &arg);
gcc_jit_block_add_comment (bfc->curblock,
loc,
"'.': putchar ((int)data[idx]);");
gcc_jit_block_add_eval (bfc->curblock,
loc,
call);
@}
break;
case ',':
@{
gcc_jit_rvalue *call =
gcc_jit_context_new_call (bfc->ctxt,
loc,
bfc->func_getchar,
0, NULL);
gcc_jit_block_add_comment (
bfc->curblock,
loc,
"',': data[idx] = (unsigned char)getchar ();");
gcc_jit_block_add_assignment (bfc->curblock,
loc,
bf_get_current_data (bfc, loc),
gcc_jit_context_new_cast (
bfc->ctxt,
loc,
call,
bfc->byte_type));
@}
break;
case '[':
@{
gcc_jit_block *loop_test =
gcc_jit_function_new_block (bfc->func, NULL);
gcc_jit_block *on_zero =
gcc_jit_function_new_block (bfc->func, NULL);
gcc_jit_block *on_non_zero =
gcc_jit_function_new_block (bfc->func, NULL);
if (bfc->num_open_parens == MAX_OPEN_PARENS)
fatal_error (bfc, "too many open parens");
gcc_jit_block_end_with_jump (
bfc->curblock,
loc,
loop_test);
gcc_jit_block_add_comment (
loop_test,
loc,
"'['");
gcc_jit_block_end_with_conditional (
loop_test,
loc,
bf_current_data_is_zero (bfc, loc),
on_zero,
on_non_zero);
bfc->paren_test[bfc->num_open_parens] = loop_test;
bfc->paren_body[bfc->num_open_parens] = on_non_zero;
bfc->paren_after[bfc->num_open_parens] = on_zero;
bfc->num_open_parens += 1;
bfc->curblock = on_non_zero;
@}
break;
case ']':
@{
gcc_jit_block_add_comment (
bfc->curblock,
loc,
"']'");
if (bfc->num_open_parens == 0)
fatal_error (bfc, "mismatching parens");
bfc->num_open_parens -= 1;
gcc_jit_block_end_with_jump (
bfc->curblock,
loc,
bfc->paren_test[bfc->num_open_parens]);
bfc->curblock = bfc->paren_after[bfc->num_open_parens];
@}
break;
case '\n':
bfc->line +=1;
bfc->column = 0;
break;
@}
if (ch != '\n')
bfc->column += 1;
@}
/* Compile the given .bf file into a gcc_jit_context, containing a
single "main" function suitable for compiling into an executable. */
gcc_jit_context *
bf_compile (const char *filename)
@{
bf_compiler bfc;
FILE *f_in;
int ch;
memset (&bfc, 0, sizeof (bfc));
bfc.filename = filename;
f_in = fopen (filename, "r");
if (!f_in)
fatal_error (&bfc, "unable to open file");
bfc.line = 1;
bfc.ctxt = gcc_jit_context_acquire ();
gcc_jit_context_set_int_option (
bfc.ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
gcc_jit_context_set_bool_option (
bfc.ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
0);
gcc_jit_context_set_bool_option (
bfc.ctxt,
GCC_JIT_BOOL_OPTION_DEBUGINFO,
1);
gcc_jit_context_set_bool_option (
bfc.ctxt,
GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
0);
gcc_jit_context_set_bool_option (
bfc.ctxt,
GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
0);
bfc.void_type =
gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_VOID);
bfc.int_type =
gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_INT);
bfc.byte_type =
gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
bfc.array_type =
gcc_jit_context_new_array_type (bfc.ctxt,
NULL,
bfc.byte_type,
30000);
bfc.func_getchar =
gcc_jit_context_new_function (bfc.ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
bfc.int_type,
"getchar",
0, NULL,
0);
gcc_jit_param *param_c =
gcc_jit_context_new_param (bfc.ctxt, NULL, bfc.int_type, "c");
bfc.func_putchar =
gcc_jit_context_new_function (bfc.ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
bfc.void_type,
"putchar",
1, &param_c,
0);
bfc.func = make_main (bfc.ctxt);
bfc.curblock =
gcc_jit_function_new_block (bfc.func, "initial");
bfc.int_zero = gcc_jit_context_zero (bfc.ctxt, bfc.int_type);
bfc.int_one = gcc_jit_context_one (bfc.ctxt, bfc.int_type);
bfc.byte_zero = gcc_jit_context_zero (bfc.ctxt, bfc.byte_type);
bfc.byte_one = gcc_jit_context_one (bfc.ctxt, bfc.byte_type);
bfc.data_cells =
gcc_jit_context_new_global (bfc.ctxt, NULL,
GCC_JIT_GLOBAL_INTERNAL,
bfc.array_type,
"data_cells");
bfc.idx =
gcc_jit_function_new_local (bfc.func, NULL,
bfc.int_type,
"idx");
gcc_jit_block_add_comment (bfc.curblock,
NULL,
"idx = 0;");
gcc_jit_block_add_assignment (bfc.curblock,
NULL,
bfc.idx,
bfc.int_zero);
bfc.num_open_parens = 0;
while ( EOF != (ch = fgetc (f_in)))
bf_compile_char (&bfc, (unsigned char)ch);
gcc_jit_block_end_with_return (bfc.curblock, NULL, bfc.int_zero);
fclose (f_in);
return bfc.ctxt;
@}
@end example
@end quotation
@node Compiling a context to a file,Other forms of ahead-of-time-compilation,Converting a brainf script to libgccjit IR,Tutorial part 5 Implementing an Ahead-of-Time compiler
@anchor{intro/tutorial05 compiling-a-context-to-a-file}@anchor{4d}
@subsection Compiling a context to a file
Unlike the previous tutorial, this time we’ll compile the context
directly to an executable, using @ref{4a,,gcc_jit_context_compile_to_file()}:
@example
gcc_jit_context_compile_to_file (ctxt,
GCC_JIT_OUTPUT_KIND_EXECUTABLE,
output_file);
@end example
Here’s the top-level of the compiler, which is what actually calls into
@ref{4a,,gcc_jit_context_compile_to_file()}:
@quotation
@example
int
main (int argc, char **argv)
@{
const char *input_file;
const char *output_file;
gcc_jit_context *ctxt;
const char *err;
if (argc != 3)
@{
fprintf (stderr, "%s: INPUT_FILE OUTPUT_FILE\n", argv[0]);
return 1;
@}
input_file = argv[1];
output_file = argv[2];
ctxt = bf_compile (input_file);
gcc_jit_context_compile_to_file (ctxt,
GCC_JIT_OUTPUT_KIND_EXECUTABLE,
output_file);
err = gcc_jit_context_get_first_error (ctxt);
if (err)
@{
gcc_jit_context_release (ctxt);
return 1;
@}
gcc_jit_context_release (ctxt);
return 0;
@}
@end example
@end quotation
Note how once the context is populated you could trivially instead compile
it to memory using @ref{15,,gcc_jit_context_compile()} and run it in-process
as in the previous tutorial.
To create an executable, we need to export a @code{main} function. Here’s
how to create one from the JIT API:
@quotation
@example
/* Make "main" function:
int
main (int argc, char **argv)
@{
...
@}
*/
static gcc_jit_function *
make_main (gcc_jit_context *ctxt)
@{
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_param *param_argc =
gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
gcc_jit_type *char_ptr_ptr_type =
gcc_jit_type_get_pointer (
gcc_jit_type_get_pointer (
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
gcc_jit_param *param_argv =
gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
gcc_jit_param *params[2] = @{param_argc, param_argv@};
gcc_jit_function *func_main =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"main",
2, params,
0);
return func_main;
@}
@end example
@end quotation
@cartouche
@quotation Note
The above implementation ignores @code{argc} and @code{argv}, but you could
make use of them by exposing @code{param_argc} and @code{param_argv} to the
caller.
@end quotation
@end cartouche
Upon compiling this C code, we obtain a bf-to-machine-code compiler;
let’s call it @code{bfc}:
@example
$ gcc \
tut05-bf.c \
-o bfc \
-lgccjit
@end example
We can now use @code{bfc} to compile .bf files into machine code executables:
@example
$ ./bfc \
emit-alphabet.bf \
a.out
@end example
which we can run directly:
@example
$ ./a.out
ABCDEFGHIJKLMNOPQRSTUVWXYZ
@end example
Success!
We can also inspect the generated executable using standard tools:
@example
$ objdump -d a.out |less
@end example
which shows that libgccjit has managed to optimize the function
somewhat (for example, the runs of 26 and 65 increment operations
have become integer constants 0x1a and 0x41):
@example
0000000000400620 <main>:
400620: 80 3d 39 0a 20 00 00 cmpb $0x0,0x200a39(%rip) # 601060 <data
400627: 74 07 je 400630 <main
400629: eb fe jmp 400629 <main+0x9>
40062b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
400630: 48 83 ec 08 sub $0x8,%rsp
400634: 0f b6 05 26 0a 20 00 movzbl 0x200a26(%rip),%eax # 601061 <data_cells+0x1>
40063b: c6 05 1e 0a 20 00 1a movb $0x1a,0x200a1e(%rip) # 601060 <data_cells>
400642: 8d 78 41 lea 0x41(%rax),%edi
400645: 40 88 3d 15 0a 20 00 mov %dil,0x200a15(%rip) # 601061 <data_cells+0x1>
40064c: 0f 1f 40 00 nopl 0x0(%rax)
400650: 40 0f b6 ff movzbl %dil,%edi
400654: e8 87 fe ff ff callq 4004e0 <putchar@@plt>
400659: 0f b6 05 01 0a 20 00 movzbl 0x200a01(%rip),%eax # 601061 <data_cells+0x1>
400660: 80 2d f9 09 20 00 01 subb $0x1,0x2009f9(%rip) # 601060 <data_cells>
400667: 8d 78 01 lea 0x1(%rax),%edi
40066a: 40 88 3d f0 09 20 00 mov %dil,0x2009f0(%rip) # 601061 <data_cells+0x1>
400671: 75 dd jne 400650 <main+0x30>
400673: 31 c0 xor %eax,%eax
400675: 48 83 c4 08 add $0x8,%rsp
400679: c3 retq
40067a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
@end example
We also set up debugging information (via
@ref{41,,gcc_jit_context_new_location()} and
@ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO}), so it’s possible to use @code{gdb}
to singlestep through the generated binary and inspect the internal
state @code{idx} and @code{data_cells}:
@example
(gdb) break main
Breakpoint 1 at 0x400790
(gdb) run
Starting program: a.out
Breakpoint 1, 0x0000000000400790 in main (argc=1, argv=0x7fffffffe448)
(gdb) stepi
0x0000000000400797 in main (argc=1, argv=0x7fffffffe448)
(gdb) stepi
0x00000000004007a0 in main (argc=1, argv=0x7fffffffe448)
(gdb) stepi
9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
(gdb) list
4
5 cell 0 = 26
6 ++++++++++++++++++++++++++
7
8 cell 1 = 65
9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
10
11 while cell#0 != 0
12 [
13 >
(gdb) n
6 ++++++++++++++++++++++++++
(gdb) n
9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
(gdb) p idx
$1 = 1
(gdb) p data_cells
$2 = "\032", '\000' <repeats 29998 times>
(gdb) p data_cells[0]
$3 = 26 '\032'
(gdb) p data_cells[1]
$4 = 0 '\000'
(gdb) list
4
5 cell 0 = 26
6 ++++++++++++++++++++++++++
7
8 cell 1 = 65
9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
10
11 while cell#0 != 0
12 [
13 >
@end example
@node Other forms of ahead-of-time-compilation,,Compiling a context to a file,Tutorial part 5 Implementing an Ahead-of-Time compiler
@anchor{intro/tutorial05 other-forms-of-ahead-of-time-compilation}@anchor{4e}
@subsection Other forms of ahead-of-time-compilation
The above demonstrates compiling a @ref{8,,gcc_jit_context *} directly
to an executable. It’s also possible to compile it to an object file,
and to a dynamic library. See the documentation of
@ref{4a,,gcc_jit_context_compile_to_file()} for more information.
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Topic Reference,C++ bindings for libgccjit,Tutorial,Top
@anchor{topics/index doc}@anchor{4f}@anchor{topics/index topic-reference}@anchor{50}
@chapter Topic Reference
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@menu
* 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::
@end menu
@node Compilation contexts,Objects,,Topic Reference
@anchor{topics/contexts doc}@anchor{51}@anchor{topics/contexts compilation-contexts}@anchor{52}
@section Compilation contexts
@geindex gcc_jit_context (C type)
@anchor{topics/contexts c gcc_jit_context}@anchor{8}
@deffn {C Type} gcc_jit_context
@end deffn
The top-level of the API is the @ref{8,,gcc_jit_context} type.
A @ref{8,,gcc_jit_context} instance encapsulates the state of a
compilation.
You can set up options on it, and add types, functions and code.
Invoking @ref{15,,gcc_jit_context_compile()} on it gives you a
@ref{16,,gcc_jit_result}.
@menu
* Lifetime-management::
* Thread-safety::
* Error-handling: Error-handling<2>.
* Debugging::
* Options: Options<2>.
@end menu
@node Lifetime-management,Thread-safety,,Compilation contexts
@anchor{topics/contexts lifetime-management}@anchor{53}
@subsection Lifetime-management
Contexts are the unit of lifetime-management within the API: objects
have their lifetime bounded by the context they are created within, and
cleanup of such objects is done for you when the context is released.
@geindex gcc_jit_context_acquire (C function)
@anchor{topics/contexts c gcc_jit_context_acquire}@anchor{9}
@deffn {C Function} gcc_jit_context *gcc_jit_context_acquire (void)
This function acquires a new @ref{8,,gcc_jit_context *} instance,
which is independent of any others that may be present within this
process.
@end deffn
@geindex gcc_jit_context_release (C function)
@anchor{topics/contexts c gcc_jit_context_release}@anchor{c}
@deffn {C Function} void gcc_jit_context_release (gcc_jit_context@w{ }*ctxt)
This function releases all resources associated with the given context.
Both the context itself and all of its @ref{e,,gcc_jit_object *}
instances are cleaned up. It should be called exactly once on a given
context.
It is invalid to use the context or any of its “contextual” objects
after calling this.
@example
gcc_jit_context_release (ctxt);
@end example
@end deffn
@geindex gcc_jit_context_new_child_context (C function)
@anchor{topics/contexts c gcc_jit_context_new_child_context}@anchor{54}
@deffn {C Function} gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context@w{ }*parent_ctxt)
Given an existing JIT context, create a child context.
The child inherits a copy of all option-settings from the parent.
The child can reference objects created within the parent, but not
vice-versa.
The lifetime of the child context must be bounded by that of the
parent: you should release a child context before releasing the parent
context.
If you use a function from a parent context within a child context,
you have to compile the parent context before you can compile the
child context, and the gcc_jit_result of the parent context must
outlive the gcc_jit_result of the child context.
This allows caching of shared initializations. For example, you could
create types and declarations of global functions in a parent context
once within a process, and then create child contexts whenever a
function or loop becomes hot. Each such child context can be used for
JIT-compiling just one function or loop, but can reference types
and helper functions created within the parent context.
Contexts can be arbitrarily nested, provided the above rules are
followed, but it’s probably not worth going above 2 or 3 levels, and
there will likely be a performance hit for such nesting.
@end deffn
@node Thread-safety,Error-handling<2>,Lifetime-management,Compilation contexts
@anchor{topics/contexts thread-safety}@anchor{55}
@subsection Thread-safety
Instances of @ref{8,,gcc_jit_context *} created via
@ref{9,,gcc_jit_context_acquire()} are independent from each other:
only one thread may use a given context at once, but multiple threads
could each have their own contexts without needing locks.
Contexts created via @ref{54,,gcc_jit_context_new_child_context()} are
related to their parent context. They can be partitioned by their
ultimate ancestor into independent “family trees”. Only one thread
within a process may use a given “family tree” of such contexts at once,
and if you’re using multiple threads you should provide your own locking
around entire such context partitions.
@node Error-handling<2>,Debugging,Thread-safety,Compilation contexts
@anchor{topics/contexts error-handling}@anchor{19}@anchor{topics/contexts id1}@anchor{56}
@subsection 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 and can be queried using
@ref{57,,gcc_jit_context_get_first_error()}.
They typically contain the name of the API entrypoint where the error
occurred, and pertinent information on the problem:
@example
./buggy-program: error: gcc_jit_block_add_assignment: mismatching types: assignment to i (type: int) from "hello world" (type: const char *)
@end example
In general, if an error occurs when using an API entrypoint, the
entrypoint returns NULL. You don’t have to check everywhere for NULL
results, since the API handles a NULL being passed in for any
argument by issuing another error. This typically leads to a cascade of
followup error messages, but is safe (albeit verbose). The first error
message is usually the one to pay attention to, since it is likely to
be responsible for all of the rest:
@geindex gcc_jit_context_get_first_error (C function)
@anchor{topics/contexts c gcc_jit_context_get_first_error}@anchor{57}
@deffn {C Function} const char * gcc_jit_context_get_first_error (gcc_jit_context@w{ }*ctxt)
Returns the first error message that occurred on the context.
The returned string is valid for the rest of the lifetime of the
context.
If no errors occurred, this will be NULL.
@end deffn
If you are wrapping the C API for a higher-level language that supports
exception-handling, you may instead be interested in the last error that
occurred on the context, so that you can embed this in an exception:
@geindex gcc_jit_context_get_last_error (C function)
@anchor{topics/contexts c gcc_jit_context_get_last_error}@anchor{58}
@deffn {C Function} const char * gcc_jit_context_get_last_error (gcc_jit_context@w{ }*ctxt)
Returns the last error message that occurred on the context.
If no errors occurred, this will be NULL.
If non-NULL, the returned string is only guaranteed to be valid until
the next call to libgccjit relating to this context.
@end deffn
@node Debugging,Options<2>,Error-handling<2>,Compilation contexts
@anchor{topics/contexts debugging}@anchor{59}
@subsection Debugging
@geindex gcc_jit_context_dump_to_file (C function)
@anchor{topics/contexts c gcc_jit_context_dump_to_file}@anchor{5a}
@deffn {C Function} void gcc_jit_context_dump_to_file (gcc_jit_context@w{ }*ctxt, const char@w{ }*path, int@w{ }update_locations)
To help with debugging: dump a C-like representation to the given path,
describing what’s been set up on the context.
If “update_locations” is true, then also set up @ref{3b,,gcc_jit_location}
information throughout the context, pointing at the dump file as if it
were a source file. This may be of use in conjunction with
@ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to allow stepping through the
code in a debugger.
@end deffn
@geindex gcc_jit_context_set_logfile (C function)
@anchor{topics/contexts c gcc_jit_context_set_logfile}@anchor{5b}
@deffn {C Function} void gcc_jit_context_set_logfile (gcc_jit_context@w{ }*ctxt, FILE@w{ }*logfile, int@w{ }flags, int@w{ }verbosity)
To help with debugging; enable ongoing logging of the context’s
activity to the given file.
For example, the following will enable logging to stderr.
@example
gcc_jit_context_set_logfile (ctxt, stderr, 0, 0);
@end example
Examples of information logged include:
@itemize *
@item
API calls
@item
the various steps involved within compilation
@item
activity on any @ref{16,,gcc_jit_result} instances created by
the context
@item
activity within any child contexts
@end itemize
An example of a log can be seen @ref{5c,,here},
though the precise format and kinds of information logged is subject
to change.
The caller remains responsible for closing @cite{logfile}, and it must not
be closed until all users are released. In particular, note that
child contexts and @ref{16,,gcc_jit_result} instances created by
the context will use the logfile.
There may a performance cost for logging.
You can turn off logging on @cite{ctxt} by passing @cite{NULL} for @cite{logfile}.
Doing so only affects the context; it does not affect child contexts
or @ref{16,,gcc_jit_result} instances already created by
the context.
The parameters “flags” and “verbosity” are reserved for future
expansion, and must be zero for now.
@end deffn
To contrast the above: @ref{5a,,gcc_jit_context_dump_to_file()} dumps the
current state of a context to the given path, whereas
@ref{5b,,gcc_jit_context_set_logfile()} enables on-going logging of
future activies on a context to the given @cite{FILE *}.
@geindex gcc_jit_context_dump_reproducer_to_file (C function)
@anchor{topics/contexts c gcc_jit_context_dump_reproducer_to_file}@anchor{5d}
@deffn {C Function} void gcc_jit_context_dump_reproducer_to_file (gcc_jit_context@w{ }*ctxt, const char@w{ }*path)
Write C source code into @cite{path} that can be compiled into a
self-contained executable (i.e. with libgccjit as the only dependency).
The generated code will attempt to replay the API calls that have been
made into the given context.
This may be useful when debugging the library or client code, for
reducing a complicated recipe for reproducing a bug into a simpler
form. For example, consider client code that parses some source file
into some internal representation, and then walks this IR, calling into
libgccjit. If this encounters a bug, a call to
@cite{gcc_jit_context_dump_reproducer_to_file} will write out C code for
a much simpler executable that performs the equivalent calls into
libgccjit, without needing the client code and its data.
Typically you need to supply @code{-Wno-unused-variable} when
compiling the generated file (since the result of each API call is
assigned to a unique variable within the generated C source, and not
all are necessarily then used).
@end deffn
@geindex gcc_jit_context_enable_dump (C function)
@anchor{topics/contexts c gcc_jit_context_enable_dump}@anchor{5e}
@deffn {C Function} void gcc_jit_context_enable_dump (gcc_jit_context@w{ }*ctxt, const char@w{ }*dumpname, char@w{ }**out_ptr)
Enable the dumping of a specific set of internal state from the
compilation, capturing the result in-memory as a buffer.
Parameter “dumpname” corresponds to the equivalent gcc command-line
option, without the “-fdump-” prefix.
For example, to get the equivalent of @code{-fdump-tree-vrp1},
supply @code{"tree-vrp1"}:
@example
static char *dump_vrp1;
void
create_code (gcc_jit_context *ctxt)
@{
gcc_jit_context_enable_dump (ctxt, "tree-vrp1", &dump_vrp1);
/* (other API calls omitted for brevity) */
@}
@end example
The context directly stores the dumpname as a @code{(const char *)}, so
the passed string must outlive the context.
@ref{15,,gcc_jit_context_compile()} will capture the dump as a
dynamically-allocated buffer, writing it to @code{*out_ptr}.
The caller becomes responsible for calling:
@example
free (*out_ptr)
@end example
each time that @ref{15,,gcc_jit_context_compile()} is called.
@code{*out_ptr} will be written to, either with the address of a buffer,
or with @code{NULL} if an error occurred.
@cartouche
@quotation Warning
This API entrypoint is likely to be less stable than the others.
In particular, both the precise dumpnames, and the format and content
of the dumps are subject to change.
It exists primarily for writing the library’s own test suite.
@end quotation
@end cartouche
@end deffn
@node Options<2>,,Debugging,Compilation contexts
@anchor{topics/contexts options}@anchor{5f}
@subsection Options
Options present in the initial release of libgccjit were handled using
enums, whereas those added subsequently have their own per-option API
entrypoints.
Adding entrypoints for each new option means that client code that use
the new options can be identified directly from binary metadata, which
would not be possible if we instead extended the various
@code{enum gcc_jit_*_option}.
@menu
* String Options::
* Boolean options::
* Integer options::
* Additional command-line options::
@end menu
@node String Options,Boolean options,,Options<2>
@anchor{topics/contexts string-options}@anchor{60}
@subsubsection String Options
@geindex gcc_jit_context_set_str_option (C function)
@anchor{topics/contexts c gcc_jit_context_set_str_option}@anchor{61}
@deffn {C Function} void gcc_jit_context_set_str_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_str_option@w{ }opt, const char@w{ }*value)
Set a string option of the context.
@geindex gcc_jit_str_option (C type)
@anchor{topics/contexts c gcc_jit_str_option}@anchor{62}
@deffn {C Type} enum gcc_jit_str_option
@end deffn
The parameter @code{value} can be NULL. If non-NULL, the call takes a
copy of the underlying string, so it is valid to pass in a pointer to
an on-stack buffer.
There is just one string option specified this way:
@geindex GCC_JIT_STR_OPTION_PROGNAME (C macro)
@anchor{topics/contexts c GCC_JIT_STR_OPTION_PROGNAME}@anchor{63}
@deffn {C Macro} GCC_JIT_STR_OPTION_PROGNAME
The name of the program, for use as a prefix when printing error
messages to stderr. If @cite{NULL}, or default, “libgccjit.so” is used.
@end deffn
@end deffn
@node Boolean options,Integer options,String Options,Options<2>
@anchor{topics/contexts boolean-options}@anchor{64}
@subsubsection Boolean options
@geindex gcc_jit_context_set_bool_option (C function)
@anchor{topics/contexts c gcc_jit_context_set_bool_option}@anchor{1b}
@deffn {C Function} void gcc_jit_context_set_bool_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_bool_option@w{ }opt, int@w{ }value)
Set a boolean option of the context.
Zero is “false” (the default), non-zero is “true”.
@geindex gcc_jit_bool_option (C type)
@anchor{topics/contexts c gcc_jit_bool_option}@anchor{65}
@deffn {C Type} enum gcc_jit_bool_option
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DEBUGINFO (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_DEBUGINFO}@anchor{42}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DEBUGINFO
If true, @ref{15,,gcc_jit_context_compile()} will attempt to do the right
thing so that if you attach a debugger to the process, it will
be able to inspect variables and step through your code.
Note that you can’t step through code unless you set up source
location information for the code (by creating and passing in
@ref{3b,,gcc_jit_location} instances).
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}@anchor{66}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
If true, @ref{15,,gcc_jit_context_compile()} will dump its initial
“tree” representation of your code to stderr (before any
optimizations).
Here’s some sample output (from the @cite{square} example):
@example
<statement_list 0x7f4875a62cc0
type <void_type 0x7f4875a64bd0 VOID
align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
pointer_to_this <pointer_type 0x7f4875a64c78>>
side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
side-effects
arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
VOID file (null) line 0 col 0
align 1 context <function_decl 0x7f4875a77500 square>>>
stmt <return_expr 0x7f4875a62d00
type <integer_type 0x7f4875a645e8 public SI
size <integer_cst 0x7f4875a623a0 constant 32>
unit size <integer_cst 0x7f4875a623c0 constant 4>
align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
pointer_to_this <pointer_type 0x7f4875a6b348>>
side-effects
arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
@end example
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE}@anchor{1c}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
If true, @ref{15,,gcc_jit_context_compile()} will dump the “gimple”
representation of your code to stderr, before any optimizations
are performed. The dump resembles C code:
@example
square (signed int i)
@{
signed int D.56;
entry:
D.56 = i * i;
return D.56;
@}
@end example
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE}@anchor{1d}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
If true, @ref{15,,gcc_jit_context_compile()} will dump the final
generated code to stderr, in the form of assembly language:
@example
.file "fake.c"
.text
.globl square
.type square, @@function
square:
.LFB0:
.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)
.L2:
movl -4(%rbp), %eax
imull -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size square, .-square
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%@{gcc_release@})"
.section .note.GNU-stack,"",@@progbits
@end example
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_SUMMARY (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_DUMP_SUMMARY}@anchor{67}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
If true, @ref{15,,gcc_jit_context_compile()} will print information to stderr
on the actions it is performing.
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING}@anchor{68}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
If true, @ref{15,,gcc_jit_context_compile()} will dump copious
amount of information on what it’s doing to various
files within a temporary directory. Use
@ref{69,,GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES} (see below) to
see the results. The files are intended to be human-readable,
but the exact files and their formats are subject to change.
@end deffn
@geindex GCC_JIT_BOOL_OPTION_SELFCHECK_GC (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_SELFCHECK_GC}@anchor{6a}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_SELFCHECK_GC
If true, libgccjit will aggressively run its garbage collector, to
shake out bugs (greatly slowing down the compile). This is likely
to only be of interest to developers @emph{of} the library. It is
used when running the selftest suite.
@end deffn
@geindex GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (C macro)
@anchor{topics/contexts c GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES}@anchor{69}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
If true, the @ref{8,,gcc_jit_context} will not clean up intermediate files
written to the filesystem, and will display their location on stderr.
@end deffn
@end deffn
@geindex gcc_jit_context_set_bool_allow_unreachable_blocks (C function)
@anchor{topics/contexts c gcc_jit_context_set_bool_allow_unreachable_blocks}@anchor{6b}
@deffn {C Function} void gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context@w{ }*ctxt, int@w{ }bool_value)
By default, libgccjit will issue an error about unreachable blocks
within a function.
This entrypoint can be used to disable that error.
This entrypoint was added in @ref{6c,,LIBGCCJIT_ABI_2}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_allow_unreachable_blocks
@end example
@end deffn
@geindex gcc_jit_context_set_bool_use_external_driver (C function)
@anchor{topics/contexts c gcc_jit_context_set_bool_use_external_driver}@anchor{6d}
@deffn {C Function} void gcc_jit_context_set_bool_use_external_driver (gcc_jit_context@w{ }*ctxt, int@w{ }bool_value)
libgccjit internally generates assembler, and uses “driver” code
for converting it to other formats (e.g. shared libraries).
By default, libgccjit will use an embedded copy of the driver
code.
This option can be used to instead invoke an external driver executable
as a subprocess.
This entrypoint was added in @ref{6e,,LIBGCCJIT_ABI_5}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
@end example
@end deffn
@geindex gcc_jit_context_set_bool_print_errors_to_stderr (C function)
@anchor{topics/contexts c gcc_jit_context_set_bool_print_errors_to_stderr}@anchor{6f}
@deffn {C Function} void gcc_jit_context_set_bool_print_errors_to_stderr (gcc_jit_context@w{ }*ctxt, int@w{ }enabled)
By default, libgccjit will print errors to stderr.
This entrypoint can be used to disable the printing.
This entrypoint was added in @ref{70,,LIBGCCJIT_ABI_23}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_print_errors_to_stderr
@end example
@end deffn
@node Integer options,Additional command-line options,Boolean options,Options<2>
@anchor{topics/contexts integer-options}@anchor{71}
@subsubsection Integer options
@geindex gcc_jit_context_set_int_option (C function)
@anchor{topics/contexts c gcc_jit_context_set_int_option}@anchor{1e}
@deffn {C Function} void gcc_jit_context_set_int_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_int_option@w{ }opt, int@w{ }value)
Set an integer option of the context.
@geindex gcc_jit_int_option (C type)
@anchor{topics/contexts c gcc_jit_int_option}@anchor{72}
@deffn {C Type} enum gcc_jit_int_option
@end deffn
There is just one integer option specified this way:
@geindex GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL (C macro)
@anchor{topics/contexts c GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}@anchor{1f}
@deffn {C Macro} GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
How much to optimize the code.
Valid values are 0-3, corresponding to GCC’s command-line options
-O0 through -O3.
The default value is 0 (unoptimized).
@end deffn
@end deffn
@node Additional command-line options,,Integer options,Options<2>
@anchor{topics/contexts additional-command-line-options}@anchor{73}
@subsubsection Additional command-line options
@geindex gcc_jit_context_add_command_line_option (C function)
@anchor{topics/contexts c gcc_jit_context_add_command_line_option}@anchor{74}
@deffn {C Function} void gcc_jit_context_add_command_line_option (gcc_jit_context@w{ }*ctxt, const char@w{ }*optname)
Add an arbitrary gcc command-line option to the context, for use
by @ref{15,,gcc_jit_context_compile()} and
@ref{4a,,gcc_jit_context_compile_to_file()}.
The parameter @code{optname} must be non-NULL. The underlying buffer is
copied, so that it does not need to outlive the call.
Extra options added by @cite{gcc_jit_context_add_command_line_option} are
applied @emph{after} the regular options above, potentially overriding them.
Options from parent contexts are inherited by child contexts; options
from the parent are applied @emph{before} those from the child.
For example:
@example
gcc_jit_context_add_command_line_option (ctxt, "-ffast-math");
gcc_jit_context_add_command_line_option (ctxt, "-fverbose-asm");
@end example
Note that only some options are likely to be meaningful; there is no
“frontend” within libgccjit, so typically only those affecting
optimization and code-generation are likely to be useful.
This entrypoint was added in @ref{75,,LIBGCCJIT_ABI_1}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option
@end example
@end deffn
@geindex gcc_jit_context_add_driver_option (C function)
@anchor{topics/contexts c gcc_jit_context_add_driver_option}@anchor{76}
@deffn {C Function} void gcc_jit_context_add_driver_option (gcc_jit_context@w{ }*ctxt, const char@w{ }*optname)
Add an arbitrary gcc driver option to the context, for use by
@ref{15,,gcc_jit_context_compile()} and
@ref{4a,,gcc_jit_context_compile_to_file()}.
The parameter @code{optname} must be non-NULL. The underlying buffer is
copied, so that it does not need to outlive the call.
Extra options added by @cite{gcc_jit_context_add_driver_option} are
applied @emph{after} all other options potentially overriding them.
Options from parent contexts are inherited by child contexts; options
from the parent are applied @emph{before} those from the child.
For example:
@example
gcc_jit_context_add_driver_option (ctxt, "-lm");
gcc_jit_context_add_driver_option (ctxt, "-fuse-linker-plugin");
gcc_jit_context_add_driver_option (ctxt, "obj.o");
gcc_jit_context_add_driver_option (ctxt, "-L.");
gcc_jit_context_add_driver_option (ctxt, "-lwhatever");
@end example
Note that only some options are likely to be meaningful; there is no
“frontend” within libgccjit, so typically only those affecting
assembler and linker are likely to be useful.
This entrypoint was added in @ref{77,,LIBGCCJIT_ABI_11}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option
@end example
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Objects,Types,Compilation contexts,Topic Reference
@anchor{topics/objects doc}@anchor{78}@anchor{topics/objects objects}@anchor{79}
@section Objects
@geindex gcc_jit_object (C type)
@anchor{topics/objects c gcc_jit_object}@anchor{e}
@deffn {C Type} gcc_jit_object
@end deffn
Almost every entity in the API (with the exception of
@ref{8,,gcc_jit_context *} and @ref{16,,gcc_jit_result *}) is a
“contextual” object, a @ref{e,,gcc_jit_object *}
A JIT object:
@quotation
@itemize *
@item
is associated with a @ref{8,,gcc_jit_context *}.
@item
is automatically cleaned up for you when its context is released so
you don’t need to manually track and cleanup all objects, just the
contexts.
@end itemize
@end quotation
Although the API is C-based, there is a form of class hierarchy, which
looks like this:
@example
+- 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
+- gcc_jit_case
+- gcc_jit_extended_asm
@end example
There are casting methods for upcasting from subclasses to parent classes.
For example, @ref{d,,gcc_jit_type_as_object()}:
@example
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
@end example
The object “base class” has the following operations:
@geindex gcc_jit_object_get_context (C function)
@anchor{topics/objects c gcc_jit_object_get_context}@anchor{7a}
@deffn {C Function} gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object@w{ }*obj)
Which context is “obj” within?
@end deffn
@geindex gcc_jit_object_get_debug_string (C function)
@anchor{topics/objects c gcc_jit_object_get_debug_string}@anchor{f}
@deffn {C Function} const char *gcc_jit_object_get_debug_string (gcc_jit_object@w{ }*obj)
Generate a human-readable description for the given object.
For example,
@example
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
@end example
might give this text on stdout:
@example
obj: 4.0 * (float)i
@end example
@cartouche
@quotation Note
If you call this on an object, the @cite{const char *} buffer is allocated
and generated on the first call for that object, and the buffer will
have the same lifetime as the object i.e. it will exist until the
object’s context is released.
@end quotation
@end cartouche
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Types,Expressions,Objects,Topic Reference
@anchor{topics/types doc}@anchor{7b}@anchor{topics/types types}@anchor{7c}
@section Types
@geindex gcc_jit_type (C type)
@anchor{topics/types c gcc_jit_type}@anchor{a}
@deffn {C Type} gcc_jit_type
gcc_jit_type represents a type within the library.
@end deffn
@geindex gcc_jit_type_as_object (C function)
@anchor{topics/types c gcc_jit_type_as_object}@anchor{d}
@deffn {C Function} gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type@w{ }*type)
Upcast a type to an object.
@end deffn
Types can be created in several ways:
@itemize *
@item
fundamental types can be accessed using
@ref{b,,gcc_jit_context_get_type()}:
@example
gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
@end example
See @ref{b,,gcc_jit_context_get_type()} for the available types.
@item
derived types can be accessed by using functions such as
@ref{7d,,gcc_jit_type_get_pointer()} and @ref{7e,,gcc_jit_type_get_const()}:
@example
gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
@end example
@item
by creating structures (see below).
@end itemize
@menu
* Standard types::
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Vector types::
* Structures and unions::
* Function pointer types::
* Reflection API::
@end menu
@node Standard types,Pointers const and volatile,,Types
@anchor{topics/types standard-types}@anchor{7f}
@subsection Standard types
@geindex gcc_jit_context_get_type (C function)
@anchor{topics/types c gcc_jit_context_get_type}@anchor{b}
@deffn {C Function} gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context@w{ }*ctxt, enum gcc_jit_types@w{ }type_)
Access a specific type. The available types are:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
@headitem
@cite{enum gcc_jit_types} value
@tab
Meaning
@item
@code{GCC_JIT_TYPE_VOID}
@tab
C’s @code{void} type.
@item
@code{GCC_JIT_TYPE_VOID_PTR}
@tab
C’s @code{void *}.
@item
@code{GCC_JIT_TYPE_BOOL}
@tab
C++’s @code{bool} type; also C99’s
@code{_Bool} type, aka @code{bool} if
using stdbool.h.
@item
@code{GCC_JIT_TYPE_CHAR}
@tab
C’s @code{char} (of some signedness)
@item
@code{GCC_JIT_TYPE_SIGNED_CHAR}
@tab
C’s @code{signed char}
@item
@code{GCC_JIT_TYPE_UNSIGNED_CHAR}
@tab
C’s @code{unsigned char}
@item
@code{GCC_JIT_TYPE_SHORT}
@tab
C’s @code{short} (signed)
@item
@code{GCC_JIT_TYPE_UNSIGNED_SHORT}
@tab
C’s @code{unsigned short}
@item
@code{GCC_JIT_TYPE_INT}
@tab
C’s @code{int} (signed)
@item
@code{GCC_JIT_TYPE_UNSIGNED_INT}
@tab
C’s @code{unsigned int}
@item
@code{GCC_JIT_TYPE_LONG}
@tab
C’s @code{long} (signed)
@item
@code{GCC_JIT_TYPE_UNSIGNED_LONG}
@tab
C’s @code{unsigned long}
@item
@code{GCC_JIT_TYPE_LONG_LONG}
@tab
C99’s @code{long long} (signed)
@item
@code{GCC_JIT_TYPE_UNSIGNED_LONG_LONG}
@tab
C99’s @code{unsigned long long}
@item
@code{GCC_JIT_TYPE_UINT8_T}
@tab
C99’s @code{uint8_t}
@item
@code{GCC_JIT_TYPE_UINT16_T}
@tab
C99’s @code{uint16_t}
@item
@code{GCC_JIT_TYPE_UINT32_T}
@tab
C99’s @code{uint32_t}
@item
@code{GCC_JIT_TYPE_UINT64_T}
@tab
C99’s @code{uint64_t}
@item
@code{GCC_JIT_TYPE_UINT128_T}
@tab
C99’s @code{__uint128_t}
@item
@code{GCC_JIT_TYPE_INT8_T}
@tab
C99’s @code{int8_t}
@item
@code{GCC_JIT_TYPE_INT16_T}
@tab
C99’s @code{int16_t}
@item
@code{GCC_JIT_TYPE_INT32_T}
@tab
C99’s @code{int32_t}
@item
@code{GCC_JIT_TYPE_INT64_T}
@tab
C99’s @code{int64_t}
@item
@code{GCC_JIT_TYPE_INT128_T}
@tab
C99’s @code{__int128_t}
@item
@code{GCC_JIT_TYPE_FLOAT}
@tab
@item
@code{GCC_JIT_TYPE_DOUBLE}
@tab
@item
@code{GCC_JIT_TYPE_LONG_DOUBLE}
@tab
@item
@code{GCC_JIT_TYPE_CONST_CHAR_PTR}
@tab
C type: @code{(const char *)}
@item
@code{GCC_JIT_TYPE_SIZE_T}
@tab
C’s @code{size_t} type
@item
@code{GCC_JIT_TYPE_FILE_PTR}
@tab
C type: @code{(FILE *)}
@item
@code{GCC_JIT_TYPE_COMPLEX_FLOAT}
@tab
C99’s @code{_Complex float}
@item
@code{GCC_JIT_TYPE_COMPLEX_DOUBLE}
@tab
C99’s @code{_Complex double}
@item
@code{GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE}
@tab
C99’s @code{_Complex long double}
@end multitable
@end deffn
@geindex gcc_jit_context_get_int_type (C function)
@anchor{topics/types c gcc_jit_context_get_int_type}@anchor{80}
@deffn {C Function} gcc_jit_type * gcc_jit_context_get_int_type (gcc_jit_context@w{ }*ctxt, int@w{ }num_bytes, int@w{ }is_signed)
Access the integer type of the given size.
@end deffn
@node Pointers const and volatile,Vector types,Standard types,Types
@anchor{topics/types pointers-const-and-volatile}@anchor{81}
@subsection Pointers, @cite{const}, and @cite{volatile}
@geindex gcc_jit_type_get_pointer (C function)
@anchor{topics/types c gcc_jit_type_get_pointer}@anchor{7d}
@deffn {C Function} gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type@w{ }*type)
Given type “T”, get type “T*”.
@end deffn
@geindex gcc_jit_type_get_const (C function)
@anchor{topics/types c gcc_jit_type_get_const}@anchor{7e}
@deffn {C Function} gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type@w{ }*type)
Given type “T”, get type “const T”.
@end deffn
@geindex gcc_jit_type_get_volatile (C function)
@anchor{topics/types c gcc_jit_type_get_volatile}@anchor{82}
@deffn {C Function} gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type@w{ }*type)
Given type “T”, get type “volatile T”.
@end deffn
@geindex gcc_jit_context_new_array_type (C function)
@anchor{topics/types c gcc_jit_context_new_array_type}@anchor{83}
@deffn {C Function} gcc_jit_type * gcc_jit_context_new_array_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*element_type, int@w{ }num_elements)
Given non-@cite{void} type “T”, get type “T[N]” (for a constant N).
@end deffn
@geindex gcc_jit_type_get_aligned (C function)
@anchor{topics/types c gcc_jit_type_get_aligned}@anchor{84}
@deffn {C Function} gcc_jit_type * gcc_jit_type_get_aligned (gcc_jit_type@w{ }*type, size_t@w{ }alignment_in_bytes)
Given non-@cite{void} type “T”, get type:
@example
T __attribute__ ((aligned (ALIGNMENT_IN_BYTES)))
@end example
The alignment must be a power of two.
This entrypoint was added in @ref{85,,LIBGCCJIT_ABI_7}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_aligned
@end example
@end deffn
@node Vector types,Structures and unions,Pointers const and volatile,Types
@anchor{topics/types vector-types}@anchor{86}
@subsection Vector types
@geindex gcc_jit_type_get_vector (C function)
@anchor{topics/types c gcc_jit_type_get_vector}@anchor{87}
@deffn {C Function} gcc_jit_type * gcc_jit_type_get_vector (gcc_jit_type@w{ }*type, size_t@w{ }num_units)
Given type “T”, get type:
@example
T __attribute__ ((vector_size (sizeof(T) * num_units))
@end example
T must be integral or floating point; num_units must be a power of two.
This can be used to construct a vector type in which operations
are applied element-wise. The compiler will automatically
use SIMD instructions where possible. See:
@indicateurl{https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html}
For example, assuming 4-byte @code{ints}, then:
@example
typedef int v4si __attribute__ ((vector_size (16)));
@end example
can be obtained using:
@example
gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt,
GCC_JIT_TYPE_INT);
gcc_jit_type *v4si_type = gcc_jit_type_get_vector (int_type, 4);
@end example
This API entrypoint was added in @ref{88,,LIBGCCJIT_ABI_8}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_vector
@end example
Vector rvalues can be generated using
@ref{89,,gcc_jit_context_new_rvalue_from_vector()}.
@end deffn
@node Structures and unions,Function pointer types,Vector types,Types
@anchor{topics/types structures-and-unions}@anchor{8a}
@subsection Structures and unions
@geindex gcc_jit_struct (C type)
@anchor{topics/types c gcc_jit_struct}@anchor{8b}
@deffn {C Type} gcc_jit_struct
@end deffn
A compound type analagous to a C @cite{struct}.
@geindex gcc_jit_field (C type)
@anchor{topics/types c gcc_jit_field}@anchor{8c}
@deffn {C Type} gcc_jit_field
@end deffn
A field within a @ref{8b,,gcc_jit_struct}.
You can model C @cite{struct} types by creating @ref{8b,,gcc_jit_struct} and
@ref{8c,,gcc_jit_field} instances, in either order:
@itemize *
@item
by creating the fields, then the structure. For example, to model:
@example
struct coord @{double x; double y; @};
@end example
you could call:
@example
gcc_jit_field *field_x =
gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
gcc_jit_field *field_y =
gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
gcc_jit_field *fields[2] = @{field_x, field_y@};
gcc_jit_struct *coord =
gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
@end example
@item
by creating the structure, then populating it with fields, typically
to allow modelling self-referential structs such as:
@example
struct node @{ int m_hash; struct node *m_next; @};
@end example
like this:
@example
gcc_jit_type *node =
gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
gcc_jit_type *node_ptr =
gcc_jit_type_get_pointer (node);
gcc_jit_field *field_hash =
gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
gcc_jit_field *field_next =
gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
gcc_jit_field *fields[2] = @{field_hash, field_next@};
gcc_jit_struct_set_fields (node, NULL, 2, fields);
@end example
@end itemize
@geindex gcc_jit_context_new_field (C function)
@anchor{topics/types c gcc_jit_context_new_field}@anchor{8d}
@deffn {C Function} gcc_jit_field * gcc_jit_context_new_field (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
Construct a new field, with the given type and name.
The parameter @code{type} must be non-@cite{void}.
The parameter @code{name} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
@end deffn
@geindex gcc_jit_context_new_bitfield (C function)
@anchor{topics/types c gcc_jit_context_new_bitfield}@anchor{8e}
@deffn {C Function} gcc_jit_field * gcc_jit_context_new_bitfield (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, int@w{ }width, const char@w{ }*name)
Construct a new bit field, with the given type width and name.
The parameter @code{name} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
The parameter @code{type} must be an integer type.
The parameter @code{width} must be a positive integer that does not exceed the
size of @code{type}.
This API entrypoint was added in @ref{8f,,LIBGCCJIT_ABI_12}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_bitfield
@end example
@end deffn
@geindex gcc_jit_field_as_object (C function)
@anchor{topics/types c gcc_jit_field_as_object}@anchor{90}
@deffn {C Function} gcc_jit_object * gcc_jit_field_as_object (gcc_jit_field@w{ }*field)
Upcast from field to object.
@end deffn
@geindex gcc_jit_context_new_struct_type (C function)
@anchor{topics/types c gcc_jit_context_new_struct_type}@anchor{91}
@deffn {C Function} gcc_jit_struct *gcc_jit_context_new_struct_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
@quotation
Construct a new struct type, with the given name and fields.
The parameter @code{name} must be non-NULL. The call takes a copy of
the underlying string, so it is valid to pass in a pointer to an
on-stack buffer.
@end quotation
@end deffn
@geindex gcc_jit_context_new_opaque_struct (C function)
@anchor{topics/types c gcc_jit_context_new_opaque_struct}@anchor{92}
@deffn {C Function} gcc_jit_struct * gcc_jit_context_new_opaque_struct (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name)
Construct a new struct type, with the given name, but without
specifying the fields. The fields can be omitted (in which case the
size of the struct is not known), or later specified using
@ref{93,,gcc_jit_struct_set_fields()}.
The parameter @code{name} must be non-NULL. The call takes a copy of
the underlying string, so it is valid to pass in a pointer to an
on-stack buffer.
@end deffn
@geindex gcc_jit_struct_as_type (C function)
@anchor{topics/types c gcc_jit_struct_as_type}@anchor{94}
@deffn {C Function} gcc_jit_type * gcc_jit_struct_as_type (gcc_jit_struct@w{ }*struct_type)
Upcast from struct to type.
@end deffn
@geindex gcc_jit_struct_set_fields (C function)
@anchor{topics/types c gcc_jit_struct_set_fields}@anchor{93}
@deffn {C Function} void gcc_jit_struct_set_fields (gcc_jit_struct@w{ }*struct_type, gcc_jit_location@w{ }*loc, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
Populate the fields of a formerly-opaque struct type.
This can only be called once on a given struct type.
@end deffn
@geindex gcc_jit_context_new_union_type (C function)
@anchor{topics/types c gcc_jit_context_new_union_type}@anchor{95}
@deffn {C Function} gcc_jit_type * gcc_jit_context_new_union_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
Construct a new union type, with the given name and fields.
The parameter @code{name} must be non-NULL. It is copied, so the input
buffer does not need to outlive the call.
Example of use:
@example
union int_or_float
@{
int as_int;
float as_float;
@};
void
create_code (gcc_jit_context *ctxt, void *user_data)
@{
/* Let's try to inject the equivalent of:
float
test_union (int i)
@{
union int_or_float u;
u.as_int = i;
return u.as_float;
@}
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *float_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
gcc_jit_field *as_int =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"as_int");
gcc_jit_field *as_float =
gcc_jit_context_new_field (ctxt,
NULL,
float_type,
"as_float");
gcc_jit_field *fields[] = @{as_int, as_float@};
gcc_jit_type *union_type =
gcc_jit_context_new_union_type (ctxt, NULL,
"int_or_float", 2, fields);
/* Build the test function. */
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
float_type,
"test_union",
1, &param_i,
0);
gcc_jit_lvalue *u =
gcc_jit_function_new_local (test_fn, NULL,
union_type, "u");
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* u.as_int = i; */
gcc_jit_block_add_assignment (
block,
NULL,
/* "u.as_int = ..." */
gcc_jit_lvalue_access_field (u,
NULL,
as_int),
gcc_jit_param_as_rvalue (param_i));
/* return u.as_float; */
gcc_jit_block_end_with_return (
block, NULL,
gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
NULL,
as_float));
@}
@end example
@end deffn
@node Function pointer types,Reflection API,Structures and unions,Types
@anchor{topics/types function-pointer-types}@anchor{96}
@subsection Function pointer types
Function pointer types can be created using
@ref{97,,gcc_jit_context_new_function_ptr_type()}.
@node Reflection API,,Function pointer types,Types
@anchor{topics/types reflection-api}@anchor{98}
@subsection Reflection API
@geindex gcc_jit_type_dyncast_array (C function)
@anchor{topics/types c gcc_jit_type_dyncast_array}@anchor{99}
@deffn {C Function} gcc_jit_type * gcc_jit_type_dyncast_array (gcc_jit_type@w{ }*type)
Get the element type of an array type or NULL if it’s not an array.
@end deffn
@geindex gcc_jit_type_is_bool (C function)
@anchor{topics/types c gcc_jit_type_is_bool}@anchor{9a}
@deffn {C Function} int gcc_jit_type_is_bool (gcc_jit_type@w{ }*type)
Return non-zero if the type is a bool.
@end deffn
@geindex gcc_jit_type_dyncast_function_ptr_type (C function)
@anchor{topics/types c gcc_jit_type_dyncast_function_ptr_type}@anchor{9b}
@deffn {C Function} gcc_jit_function_type * gcc_jit_type_dyncast_function_ptr_type (gcc_jit_type@w{ }*type)
Return the function type if it is one or NULL.
@end deffn
@geindex gcc_jit_function_type_get_return_type (C function)
@anchor{topics/types c gcc_jit_function_type_get_return_type}@anchor{9c}
@deffn {C Function} gcc_jit_type * gcc_jit_function_type_get_return_type (gcc_jit_function_type@w{ }*function_type)
Given a function type, return its return type.
@end deffn
@geindex gcc_jit_function_type_get_param_count (C function)
@anchor{topics/types c gcc_jit_function_type_get_param_count}@anchor{9d}
@deffn {C Function} size_t gcc_jit_function_type_get_param_count (gcc_jit_function_type@w{ }*function_type)
Given a function type, return its number of parameters.
@end deffn
@geindex gcc_jit_function_type_get_param_type (C function)
@anchor{topics/types c gcc_jit_function_type_get_param_type}@anchor{9e}
@deffn {C Function} gcc_jit_type * gcc_jit_function_type_get_param_type (gcc_jit_function_type@w{ }*function_type, size_t@w{ }index)
Given a function type, return the type of the specified parameter.
@end deffn
@geindex gcc_jit_type_is_integral (C function)
@anchor{topics/types c gcc_jit_type_is_integral}@anchor{9f}
@deffn {C Function} int gcc_jit_type_is_integral (gcc_jit_type@w{ }*type)
Return non-zero if the type is an integral.
@end deffn
@geindex gcc_jit_type_is_pointer (C function)
@anchor{topics/types c gcc_jit_type_is_pointer}@anchor{a0}
@deffn {C Function} gcc_jit_type * gcc_jit_type_is_pointer (gcc_jit_type@w{ }*type)
Return the type pointed by the pointer type or NULL if it’s not a pointer.
@end deffn
@geindex gcc_jit_type_dyncast_vector (C function)
@anchor{topics/types c gcc_jit_type_dyncast_vector}@anchor{a1}
@deffn {C Function} gcc_jit_vector_type * gcc_jit_type_dyncast_vector (gcc_jit_type@w{ }*type)
Given a type, return a dynamic cast to a vector type or NULL.
@end deffn
@geindex gcc_jit_type_is_struct (C function)
@anchor{topics/types c gcc_jit_type_is_struct}@anchor{a2}
@deffn {C Function} gcc_jit_struct * gcc_jit_type_is_struct (gcc_jit_type@w{ }*type)
Given a type, return a dynamic cast to a struct type or NULL.
@end deffn
@geindex gcc_jit_vector_type_get_num_units (C function)
@anchor{topics/types c gcc_jit_vector_type_get_num_units}@anchor{a3}
@deffn {C Function} size_t gcc_jit_vector_type_get_num_units (gcc_jit_vector_type@w{ }*vector_type)
Given a vector type, return the number of units it contains.
@end deffn
@geindex gcc_jit_vector_type_get_element_type (C function)
@anchor{topics/types c gcc_jit_vector_type_get_element_type}@anchor{a4}
@deffn {C Function} gcc_jit_type * gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *@w{ }vector_type)
Given a vector type, return the type of its elements.
@end deffn
@geindex gcc_jit_type_unqualified (C function)
@anchor{topics/types c gcc_jit_type_unqualified}@anchor{a5}
@deffn {C Function} gcc_jit_type * gcc_jit_type_unqualified (gcc_jit_type@w{ }*type)
Given a type, return the unqualified type, removing “const”, “volatile” and
alignment qualifiers.
@end deffn
@geindex gcc_jit_struct_get_field (C function)
@anchor{topics/types c gcc_jit_struct_get_field}@anchor{a6}
@deffn {C Function} gcc_jit_field * gcc_jit_struct_get_field (gcc_jit_struct@w{ }*struct_type, size_t@w{ }index)
Get a struct field by index.
@end deffn
@geindex gcc_jit_struct_get_field_count (C function)
@anchor{topics/types c gcc_jit_struct_get_field_count}@anchor{a7}
@deffn {C Function} size_t gcc_jit_struct_get_field_count (gcc_jit_struct@w{ }*struct_type)
@quotation
Get the number of fields in the struct.
@end quotation
The API entrypoints related to the reflection API:
@quotation
@itemize *
@item
@ref{9c,,gcc_jit_function_type_get_return_type()}
@item
@ref{9d,,gcc_jit_function_type_get_param_count()}
@item
@ref{9e,,gcc_jit_function_type_get_param_type()}
@item
@ref{a5,,gcc_jit_type_unqualified()}
@item
@ref{99,,gcc_jit_type_dyncast_array()}
@item
@ref{9a,,gcc_jit_type_is_bool()}
@item
@ref{9b,,gcc_jit_type_dyncast_function_ptr_type()}
@item
@ref{9f,,gcc_jit_type_is_integral()}
@item
@ref{a0,,gcc_jit_type_is_pointer()}
@item
@ref{a1,,gcc_jit_type_dyncast_vector()}
@item
@ref{a4,,gcc_jit_vector_type_get_element_type()}
@item
@ref{a3,,gcc_jit_vector_type_get_num_units()}
@item
@ref{a6,,gcc_jit_struct_get_field()}
@item
@ref{a2,,gcc_jit_type_is_struct()}
@item
@ref{a7,,gcc_jit_struct_get_field_count()}
@end itemize
@end quotation
were added in @ref{a8,,LIBGCCJIT_ABI_16}; you can test for their presence
using
@example
#ifdef LIBGCCJIT_HAVE_REFLECTION
@end example
@geindex gcc_jit_case (C type)
@anchor{topics/types c gcc_jit_case}@anchor{a9}
@deffn {C Type} gcc_jit_case
@end deffn
@end deffn
@geindex gcc_jit_compatible_types (C function)
@anchor{topics/types c gcc_jit_compatible_types}@anchor{aa}
@deffn {C Function} int gcc_jit_compatible_types (gcc_jit_type@w{ }*ltype, gcc_jit_type@w{ }*rtype)
@quotation
Return non-zero if the two types are compatible. For instance,
if @code{GCC_JIT_TYPE_UINT64_T} and @code{GCC_JIT_TYPE_UNSIGNED_LONG}
are the same size on the target, this will return non-zero.
The parameters @code{ltype} and @code{rtype} must be non-NULL.
Return 0 on errors.
@end quotation
This entrypoint was added in @ref{ab,,LIBGCCJIT_ABI_20}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_SIZED_INTEGERS
@end example
@end deffn
@geindex gcc_jit_type_get_size (C function)
@anchor{topics/types c gcc_jit_type_get_size}@anchor{ac}
@deffn {C Function} ssize_t gcc_jit_type_get_size (gcc_jit_type@w{ }*type)
@quotation
Return the size of a type, in bytes. It only works on integer types for now.
The parameter @code{type} must be non-NULL.
Return -1 on errors.
@end quotation
This entrypoint was added in @ref{ab,,LIBGCCJIT_ABI_20}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_SIZED_INTEGERS
@end example
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Expressions,Creating and using functions,Types,Topic Reference
@anchor{topics/expressions doc}@anchor{ad}@anchor{topics/expressions expressions}@anchor{ae}
@section Expressions
@menu
* Rvalues::
* Lvalues::
* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
@end menu
@node Rvalues,Lvalues,,Expressions
@anchor{topics/expressions rvalues}@anchor{af}
@subsection Rvalues
@geindex gcc_jit_rvalue (C type)
@anchor{topics/expressions c gcc_jit_rvalue}@anchor{13}
@deffn {C Type} gcc_jit_rvalue
@end deffn
A @ref{13,,gcc_jit_rvalue} is an expression that can be computed.
It can be simple, e.g.:
@quotation
@itemize *
@item
an integer value e.g. @cite{0} or @cite{42}
@item
a string literal e.g. @cite{“Hello world”}
@item
a variable e.g. @cite{i}. These are also lvalues (see below).
@end itemize
@end quotation
or compound e.g.:
@quotation
@itemize *
@item
a unary expression e.g. @cite{!cond}
@item
a binary expression e.g. @cite{(a + b)}
@item
a function call e.g. @cite{get_distance (&player_ship@comma{} &target)}
@item
etc.
@end itemize
@end quotation
Every rvalue has an associated type, and the API will check to ensure
that types match up correctly (otherwise the context will emit an error).
@geindex gcc_jit_rvalue_get_type (C function)
@anchor{topics/expressions c gcc_jit_rvalue_get_type}@anchor{b0}
@deffn {C Function} gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue@w{ }*rvalue)
Get the type of this rvalue.
@end deffn
@geindex gcc_jit_rvalue_as_object (C function)
@anchor{topics/expressions c gcc_jit_rvalue_as_object}@anchor{14}
@deffn {C Function} gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue@w{ }*rvalue)
Upcast the given rvalue to be an object.
@end deffn
@menu
* Simple expressions::
* Constructor expressions::
* Vector expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
* Function pointers::
* Type-coercion::
@end menu
@node Simple expressions,Constructor expressions,,Rvalues
@anchor{topics/expressions simple-expressions}@anchor{b1}
@subsubsection Simple expressions
@geindex gcc_jit_context_new_rvalue_from_int (C function)
@anchor{topics/expressions c gcc_jit_context_new_rvalue_from_int}@anchor{30}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_int (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, int@w{ }value)
Given a numeric type (integer or floating point), build an rvalue for
the given constant @code{int} value.
@end deffn
@geindex gcc_jit_context_new_rvalue_from_long (C function)
@anchor{topics/expressions c gcc_jit_context_new_rvalue_from_long}@anchor{b2}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_long (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, long@w{ }value)
Given a numeric type (integer or floating point), build an rvalue for
the given constant @code{long} value.
@end deffn
@geindex gcc_jit_context_zero (C function)
@anchor{topics/expressions c gcc_jit_context_zero}@anchor{2b}
@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type)
Given a numeric type (integer or floating point), get the rvalue for
zero. Essentially this is just a shortcut for:
@example
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
@end example
@end deffn
@geindex gcc_jit_context_one (C function)
@anchor{topics/expressions c gcc_jit_context_one}@anchor{2f}
@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type)
Given a numeric type (integer or floating point), get the rvalue for
one. Essentially this is just a shortcut for:
@example
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
@end example
@end deffn
@geindex gcc_jit_context_new_rvalue_from_double (C function)
@anchor{topics/expressions c gcc_jit_context_new_rvalue_from_double}@anchor{31}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_double (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, double@w{ }value)
Given a numeric type (integer or floating point), build an rvalue for
the given constant @code{double} value.
@end deffn
@geindex gcc_jit_context_new_rvalue_from_ptr (C function)
@anchor{topics/expressions c gcc_jit_context_new_rvalue_from_ptr}@anchor{b3}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type, void@w{ }*value)
Given a pointer type, build an rvalue for the given address.
@end deffn
@geindex gcc_jit_context_null (C function)
@anchor{topics/expressions c gcc_jit_context_null}@anchor{b4}
@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type)
Given a pointer type, build an rvalue for @code{NULL}. Essentially this
is just a shortcut for:
@example
gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
@end example
@end deffn
@geindex gcc_jit_context_new_string_literal (C function)
@anchor{topics/expressions c gcc_jit_context_new_string_literal}@anchor{b5}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_string_literal (gcc_jit_context@w{ }*ctxt, const char@w{ }*value)
Generate an rvalue for the given NIL-terminated string, of type
@code{GCC_JIT_TYPE_CONST_CHAR_PTR}.
The parameter @code{value} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
@end deffn
@node Constructor expressions,Vector expressions,Simple expressions,Rvalues
@anchor{topics/expressions constructor-expressions}@anchor{b6}
@subsubsection Constructor expressions
@quotation
The following functions make constructors for array, struct and union
types.
The constructor rvalue can be used for assignment to locals.
It can be used to initialize global variables with
@ref{b7,,gcc_jit_global_set_initializer_rvalue()}. It can also be used as a
temporary value for function calls and return values, but its address
can’t be taken.
Note that arrays in libgccjit do not collapse to pointers like in
C. I.e. if an array constructor is used as e.g. a return value, the whole
array would be returned by value - array constructors can be assigned to
array variables.
The constructor can contain nested constructors.
Note that a string literal rvalue can’t be used to construct a char array;
the latter needs one rvalue for each char.
These entrypoints were added in @ref{b8,,LIBGCCJIT_ABI_19}; you can test for
their presence using:
@example
#ifdef LIBGCCJIT_HAVE_CTORS
@end example
@end quotation
@geindex gcc_jit_context_new_array_constructor (C function)
@anchor{topics/expressions c gcc_jit_context_new_array_constructor}@anchor{b9}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_array_constructor (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, size_t@w{ }num_values, gcc_jit_rvalue@w{ }**values)
Create a constructor for an array as an rvalue.
Returns NULL on error. @code{values} are copied and
do not have to outlive the context.
@code{type} specifies what the constructor will build and has to be
an array.
@code{num_values} specifies the number of elements in @code{values} and
it can’t have more elements than the array type.
Each value in @code{values} sets the corresponding value in the array.
If the array type itself has more elements than @code{values}, the
left-over elements will be zeroed.
Each value in @code{values} need to be the same unqualified type as the
array type’s element type.
If @code{num_values} is 0, the @code{values} parameter will be
ignored and zero initialization will be used.
This entrypoint was added in @ref{b8,,LIBGCCJIT_ABI_19}; you can test for its
presence using:
@example
#ifdef LIBGCCJIT_HAVE_CTORS
@end example
@end deffn
@geindex gcc_jit_context_new_struct_constructor (C function)
@anchor{topics/expressions c gcc_jit_context_new_struct_constructor}@anchor{ba}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_struct_constructor (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, size_t@w{ }num_values, gcc_jit_field@w{ }**fields, gcc_jit_rvalue@w{ }**values)
Create a constructor for a struct as an rvalue.
Returns NULL on error. The two parameter arrays are copied and
do not have to outlive the context.
@code{type} specifies what the constructor will build and has to be
a struct.
@code{num_values} specifies the number of elements in @code{values}.
@code{fields} need to have the same length as @code{values}, or be NULL.
If @code{fields} is null, the values are applied in definition order.
Otherwise, each field in @code{fields} specifies which field in the struct to
set to the corresponding value in @code{values}. @code{fields} and @code{values}
are paired by index.
The fields in @code{fields} have to be in definition order, but there
can be gaps. Any field in the struct that is not specified in
@code{fields} will be zeroed.
The fields in @code{fields} need to be the same objects that were used
to create the struct.
Each value has to have have the same unqualified type as the field
it is applied to.
A NULL value element in @code{values} is a shorthand for zero initialization
of the corresponding field.
If @code{num_values} is 0, the array parameters will be
ignored and zero initialization will be used.
This entrypoint was added in @ref{b8,,LIBGCCJIT_ABI_19}; you can test for its
presence using:
@example
#ifdef LIBGCCJIT_HAVE_CTORS
@end example
@end deffn
@geindex gcc_jit_context_new_union_constructor (C function)
@anchor{topics/expressions c gcc_jit_context_new_union_constructor}@anchor{bb}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_union_constructor (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, gcc_jit_field@w{ }*field, gcc_jit_rvalue@w{ }*value)
Create a constructor for a union as an rvalue.
Returns NULL on error.
@code{type} specifies what the constructor will build and has to be
an union.
@code{field} specifies which field to set. If it is NULL, the first
field in the union will be set.`@w{`}field`@w{`} need to be the same object
that were used to create the union.
@code{value} specifies what value to set the corresponding field to.
If @code{value} is NULL, zero initialization will be used.
Each value has to have have the same unqualified type as the field
it is applied to.
This entrypoint was added in @ref{b8,,LIBGCCJIT_ABI_19}; you can test for its
presence using:
@example
#ifdef LIBGCCJIT_HAVE_CTORS
@end example
@end deffn
@node Vector expressions,Unary Operations,Constructor expressions,Rvalues
@anchor{topics/expressions vector-expressions}@anchor{bc}
@subsubsection Vector expressions
@geindex gcc_jit_context_new_rvalue_from_vector (C function)
@anchor{topics/expressions c gcc_jit_context_new_rvalue_from_vector}@anchor{89}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_vector (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*vec_type, size_t@w{ }num_elements, gcc_jit_rvalue@w{ }**elements)
Build a vector rvalue from an array of elements.
“vec_type” should be a vector type, created using
@ref{87,,gcc_jit_type_get_vector()}.
“num_elements” should match that of the vector type.
This entrypoint was added in @ref{bd,,LIBGCCJIT_ABI_10}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
@end example
@end deffn
@node Unary Operations,Binary Operations,Vector expressions,Rvalues
@anchor{topics/expressions unary-operations}@anchor{be}
@subsubsection Unary Operations
@geindex gcc_jit_context_new_unary_op (C function)
@anchor{topics/expressions c gcc_jit_context_new_unary_op}@anchor{bf}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_unary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_unary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*rvalue)
Build a unary operation out of an input rvalue.
The parameter @code{result_type} must be a numeric type.
@end deffn
@geindex gcc_jit_unary_op (C type)
@anchor{topics/expressions c gcc_jit_unary_op}@anchor{c0}
@deffn {C Type} enum gcc_jit_unary_op
@end deffn
The available unary operations are:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx}
@headitem
Unary Operation
@tab
C equivalent
@item
@ref{c1,,GCC_JIT_UNARY_OP_MINUS}
@tab
@cite{-(EXPR)}
@item
@ref{c2,,GCC_JIT_UNARY_OP_BITWISE_NEGATE}
@tab
@cite{~(EXPR)}
@item
@ref{c3,,GCC_JIT_UNARY_OP_LOGICAL_NEGATE}
@tab
@cite{!(EXPR)}
@item
@ref{c4,,GCC_JIT_UNARY_OP_ABS}
@tab
@cite{abs (EXPR)}
@end multitable
@geindex GCC_JIT_UNARY_OP_MINUS (C macro)
@anchor{topics/expressions c GCC_JIT_UNARY_OP_MINUS}@anchor{c1}
@deffn {C Macro} GCC_JIT_UNARY_OP_MINUS
Negate an arithmetic value; analogous to:
@example
-(EXPR)
@end example
in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_BITWISE_NEGATE (C macro)
@anchor{topics/expressions c GCC_JIT_UNARY_OP_BITWISE_NEGATE}@anchor{c2}
@deffn {C Macro} GCC_JIT_UNARY_OP_BITWISE_NEGATE
Bitwise negation of an integer value (one’s complement); analogous
to:
@example
~(EXPR)
@end example
in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_LOGICAL_NEGATE (C macro)
@anchor{topics/expressions c GCC_JIT_UNARY_OP_LOGICAL_NEGATE}@anchor{c3}
@deffn {C Macro} GCC_JIT_UNARY_OP_LOGICAL_NEGATE
Logical negation of an arithmetic or pointer value; analogous to:
@example
!(EXPR)
@end example
in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_ABS (C macro)
@anchor{topics/expressions c GCC_JIT_UNARY_OP_ABS}@anchor{c4}
@deffn {C Macro} GCC_JIT_UNARY_OP_ABS
Absolute value of an arithmetic expression; analogous to:
@example
abs (EXPR)
@end example
in C.
@end deffn
@node Binary Operations,Comparisons,Unary Operations,Rvalues
@anchor{topics/expressions binary-operations}@anchor{c5}
@subsubsection Binary Operations
@geindex gcc_jit_context_new_binary_op (C function)
@anchor{topics/expressions c gcc_jit_context_new_binary_op}@anchor{12}
@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_binary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*a, gcc_jit_rvalue@w{ }*b)
Build a binary operation out of two constituent rvalues.
The parameter @code{result_type} must be a numeric type.
@end deffn
@geindex gcc_jit_binary_op (C type)
@anchor{topics/expressions c gcc_jit_binary_op}@anchor{c6}
@deffn {C Type} enum gcc_jit_binary_op
@end deffn
The available binary operations are:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx}
@headitem
Binary Operation
@tab
C equivalent
@item
@ref{c7,,GCC_JIT_BINARY_OP_PLUS}
@tab
@cite{x + y}
@item
@ref{c8,,GCC_JIT_BINARY_OP_MINUS}
@tab
@cite{x - y}
@item
@ref{c9,,GCC_JIT_BINARY_OP_MULT}
@tab
@cite{x * y}
@item
@ref{ca,,GCC_JIT_BINARY_OP_DIVIDE}
@tab
@cite{x / y}
@item
@ref{cb,,GCC_JIT_BINARY_OP_MODULO}
@tab
@cite{x % y}
@item
@ref{cc,,GCC_JIT_BINARY_OP_BITWISE_AND}
@tab
@cite{x & y}
@item
@ref{cd,,GCC_JIT_BINARY_OP_BITWISE_XOR}
@tab
@cite{x ^ y}
@item
@ref{ce,,GCC_JIT_BINARY_OP_BITWISE_OR}
@tab
@cite{x | y}
@item
@ref{cf,,GCC_JIT_BINARY_OP_LOGICAL_AND}
@tab
@cite{x && y}
@item
@ref{d0,,GCC_JIT_BINARY_OP_LOGICAL_OR}
@tab
@cite{x || y}
@item
@ref{d1,,GCC_JIT_BINARY_OP_LSHIFT}
@tab
@cite{x << y}
@item
@ref{d2,,GCC_JIT_BINARY_OP_RSHIFT}
@tab
@cite{x >> y}
@end multitable
@geindex GCC_JIT_BINARY_OP_PLUS (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_PLUS}@anchor{c7}
@deffn {C Macro} GCC_JIT_BINARY_OP_PLUS
Addition of arithmetic values; analogous to:
@example
(EXPR_A) + (EXPR_B)
@end example
in C.
For pointer addition, use @ref{d3,,gcc_jit_context_new_array_access()}.
@end deffn
@geindex GCC_JIT_BINARY_OP_MINUS (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_MINUS}@anchor{c8}
@deffn {C Macro} GCC_JIT_BINARY_OP_MINUS
Subtraction of arithmetic values; analogous to:
@example
(EXPR_A) - (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_MULT (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_MULT}@anchor{c9}
@deffn {C Macro} GCC_JIT_BINARY_OP_MULT
Multiplication of a pair of arithmetic values; analogous to:
@example
(EXPR_A) * (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_DIVIDE (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_DIVIDE}@anchor{ca}
@deffn {C Macro} GCC_JIT_BINARY_OP_DIVIDE
Quotient of division of arithmetic values; analogous to:
@example
(EXPR_A) / (EXPR_B)
@end example
in C.
The result type affects the kind of division: if the result type is
integer-based, then the result is truncated towards zero, whereas
a floating-point result type indicates floating-point division.
@end deffn
@geindex GCC_JIT_BINARY_OP_MODULO (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_MODULO}@anchor{cb}
@deffn {C Macro} GCC_JIT_BINARY_OP_MODULO
Remainder of division of arithmetic values; analogous to:
@example
(EXPR_A) % (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_AND (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_BITWISE_AND}@anchor{cc}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_AND
Bitwise AND; analogous to:
@example
(EXPR_A) & (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_XOR (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_BITWISE_XOR}@anchor{cd}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_XOR
Bitwise exclusive OR; analogous to:
@example
(EXPR_A) ^ (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_OR (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_BITWISE_OR}@anchor{ce}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_OR
Bitwise inclusive OR; analogous to:
@example
(EXPR_A) | (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LOGICAL_AND (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_LOGICAL_AND}@anchor{cf}
@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_AND
Logical AND; analogous to:
@example
(EXPR_A) && (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LOGICAL_OR (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_LOGICAL_OR}@anchor{d0}
@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_OR
Logical OR; analogous to:
@example
(EXPR_A) || (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LSHIFT (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_LSHIFT}@anchor{d1}
@deffn {C Macro} GCC_JIT_BINARY_OP_LSHIFT
Left shift; analogous to:
@example
(EXPR_A) << (EXPR_B)
@end example
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_RSHIFT (C macro)
@anchor{topics/expressions c GCC_JIT_BINARY_OP_RSHIFT}@anchor{d2}
@deffn {C Macro} GCC_JIT_BINARY_OP_RSHIFT
Right shift; analogous to:
@example
(EXPR_A) >> (EXPR_B)
@end example
in C.
@end deffn
@node Comparisons,Function calls,Binary Operations,Rvalues
@anchor{topics/expressions comparisons}@anchor{d4}
@subsubsection Comparisons
@geindex gcc_jit_context_new_comparison (C function)
@anchor{topics/expressions c gcc_jit_context_new_comparison}@anchor{2c}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_comparison (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_comparison@w{ }op, gcc_jit_rvalue@w{ }*a, gcc_jit_rvalue@w{ }*b)
Build a boolean rvalue out of the comparison of two other rvalues.
@end deffn
@geindex gcc_jit_comparison (C type)
@anchor{topics/expressions c gcc_jit_comparison}@anchor{d5}
@deffn {C Type} enum gcc_jit_comparison
@end deffn
@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx}
@headitem
Comparison
@tab
C equivalent
@item
@code{GCC_JIT_COMPARISON_EQ}
@tab
@cite{x == y}
@item
@code{GCC_JIT_COMPARISON_NE}
@tab
@cite{x != y}
@item
@code{GCC_JIT_COMPARISON_LT}
@tab
@cite{x < y}
@item
@code{GCC_JIT_COMPARISON_LE}
@tab
@cite{x <= y}
@item
@code{GCC_JIT_COMPARISON_GT}
@tab
@cite{x > y}
@item
@code{GCC_JIT_COMPARISON_GE}
@tab
@cite{x >= y}
@end multitable
@node Function calls,Function pointers,Comparisons,Rvalues
@anchor{topics/expressions function-calls}@anchor{d6}
@subsubsection Function calls
@geindex gcc_jit_context_new_call (C function)
@anchor{topics/expressions c gcc_jit_context_new_call}@anchor{d7}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_call (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_function@w{ }*func, int@w{ }numargs, gcc_jit_rvalue@w{ }**args)
Given a function and the given table of argument rvalues, construct a
call to the function, with the result as an rvalue.
@cartouche
@quotation Note
@ref{d7,,gcc_jit_context_new_call()} merely builds a
@ref{13,,gcc_jit_rvalue} i.e. an expression that can be evaluated,
perhaps as part of a more complicated expression.
The call @emph{won’t} happen unless you add a statement to a function
that evaluates the expression.
For example, if you want to call a function and discard the result
(or to call a function with @code{void} return type), use
@ref{d8,,gcc_jit_block_add_eval()}:
@example
/* Add "(void)printf (arg0, arg1);". */
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (
ctxt,
NULL,
printf_func,
2, args));
@end example
@end quotation
@end cartouche
@end deffn
@geindex gcc_jit_context_new_call_through_ptr (C function)
@anchor{topics/expressions c gcc_jit_context_new_call_through_ptr}@anchor{d9}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_call_through_ptr (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*fn_ptr, int@w{ }numargs, gcc_jit_rvalue@w{ }**args)
Given an rvalue of function pointer type (e.g. from
@ref{97,,gcc_jit_context_new_function_ptr_type()}), and the given table of
argument rvalues, construct a call to the function pointer, with the
result as an rvalue.
@cartouche
@quotation Note
The same caveat as for @ref{d7,,gcc_jit_context_new_call()} applies.
@end quotation
@end cartouche
@end deffn
@geindex gcc_jit_rvalue_set_bool_require_tail_call (C function)
@anchor{topics/expressions c gcc_jit_rvalue_set_bool_require_tail_call}@anchor{da}
@deffn {C Function} void gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue@w{ }*call, int@w{ }require_tail_call)
Given an @ref{13,,gcc_jit_rvalue} for a call created through
@ref{d7,,gcc_jit_context_new_call()} or
@ref{d9,,gcc_jit_context_new_call_through_ptr()}, mark/clear the
call as needing tail-call optimization. The optimizer will
attempt to optimize the call into a jump instruction; if it is
unable to do do, an error will be emitted.
This may be useful when implementing functions that use the
continuation-passing style (e.g. for functional programming
languages), in which every function “returns” by calling a
“continuation” function pointer. This call must be
guaranteed to be implemented as a jump, otherwise the program
could consume an arbitrary amount of stack space as it executed.
This entrypoint was added in @ref{db,,LIBGCCJIT_ABI_6}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
@end example
@end deffn
@node Function pointers,Type-coercion,Function calls,Rvalues
@anchor{topics/expressions function-pointers}@anchor{dc}
@subsubsection Function pointers
Function pointers can be obtained:
@quotation
@itemize *
@item
from a @ref{29,,gcc_jit_function} using
@ref{dd,,gcc_jit_function_get_address()}, or
@item
from an existing function using
@ref{b3,,gcc_jit_context_new_rvalue_from_ptr()},
using a function pointer type obtained using
@ref{97,,gcc_jit_context_new_function_ptr_type()}.
@end itemize
@end quotation
@node Type-coercion,,Function pointers,Rvalues
@anchor{topics/expressions type-coercion}@anchor{de}
@subsubsection Type-coercion
@geindex gcc_jit_context_new_cast (C function)
@anchor{topics/expressions c gcc_jit_context_new_cast}@anchor{df}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_cast (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue, gcc_jit_type@w{ }*type)
Given an rvalue of T, construct another rvalue of another type.
Currently only a limited set of conversions are possible:
@quotation
@itemize *
@item
int <-> float
@item
int <-> bool
@item
P* <-> Q*, for pointer types P and Q
@end itemize
@end quotation
@end deffn
@geindex gcc_jit_context_new_bitcast (C function)
@anchor{topics/expressions c gcc_jit_context_new_bitcast}@anchor{e0}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_bitcast (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue, gcc_jit_type@w{ }*type)
Given an rvalue of T, bitcast it to another type, meaning that this will
generate a new rvalue by interpreting the bits of @code{rvalue} to the layout
of @code{type}.
The type of rvalue must be the same size as the size of @code{type}.
This entrypoint was added in @ref{e1,,LIBGCCJIT_ABI_21}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_bitcast
@end example
@end deffn
@node Lvalues,Working with pointers structs and unions,Rvalues,Expressions
@anchor{topics/expressions lvalues}@anchor{e2}
@subsection Lvalues
@geindex gcc_jit_lvalue (C type)
@anchor{topics/expressions c gcc_jit_lvalue}@anchor{24}
@deffn {C Type} gcc_jit_lvalue
@end deffn
An lvalue is something that can of the @emph{left}-hand side of an assignment:
a storage area (such as a variable). It is also usable as an rvalue,
where the rvalue is computed by reading from the storage area.
@geindex gcc_jit_lvalue_as_object (C function)
@anchor{topics/expressions c gcc_jit_lvalue_as_object}@anchor{e3}
@deffn {C Function} gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue@w{ }*lvalue)
Upcast an lvalue to be an object.
@end deffn
@geindex gcc_jit_lvalue_as_rvalue (C function)
@anchor{topics/expressions c gcc_jit_lvalue_as_rvalue}@anchor{e4}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue@w{ }*lvalue)
Upcast an lvalue to be an rvalue.
@end deffn
@geindex gcc_jit_lvalue_get_address (C function)
@anchor{topics/expressions c gcc_jit_lvalue_get_address}@anchor{e5}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_lvalue_get_address (gcc_jit_lvalue@w{ }*lvalue, gcc_jit_location@w{ }*loc)
Take the address of an lvalue; analogous to:
@example
&(EXPR)
@end example
in C.
@end deffn
@geindex gcc_jit_lvalue_set_tls_model (C function)
@anchor{topics/expressions c gcc_jit_lvalue_set_tls_model}@anchor{e6}
@deffn {C Function} void gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue@w{ }*lvalue, enum gcc_jit_tls_model@w{ }model)
Make a variable a thread-local variable.
The “model” parameter determines the thread-local storage model of the “lvalue”:
@geindex gcc_jit_tls_model (C type)
@anchor{topics/expressions c gcc_jit_tls_model}@anchor{e7}
@deffn {C Type} enum gcc_jit_tls_model
@end deffn
@geindex GCC_JIT_TLS_MODEL_NONE (C macro)
@anchor{topics/expressions c GCC_JIT_TLS_MODEL_NONE}@anchor{e8}
@deffn {C Macro} GCC_JIT_TLS_MODEL_NONE
Don’t set the TLS model.
@end deffn
@geindex GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC (C macro)
@anchor{topics/expressions c GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC}@anchor{e9}
@deffn {C Macro} GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC
@end deffn
@geindex GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC (C macro)
@anchor{topics/expressions c GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC}@anchor{ea}
@deffn {C Macro} GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC
@end deffn
@geindex GCC_JIT_TLS_MODEL_INITIAL_EXEC (C macro)
@anchor{topics/expressions c GCC_JIT_TLS_MODEL_INITIAL_EXEC}@anchor{eb}
@deffn {C Macro} GCC_JIT_TLS_MODEL_INITIAL_EXEC
@end deffn
@geindex GCC_JIT_TLS_MODEL_LOCAL_EXEC (C macro)
@anchor{topics/expressions c GCC_JIT_TLS_MODEL_LOCAL_EXEC}@anchor{ec}
@deffn {C Macro} GCC_JIT_TLS_MODEL_LOCAL_EXEC
@end deffn
This is analogous to:
@example
_Thread_local int foo __attribute__ ((tls_model("MODEL")));
@end example
in C.
This entrypoint was added in @ref{ed,,LIBGCCJIT_ABI_17}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model
@end example
@end deffn
@geindex gcc_jit_lvalue_set_link_section (C function)
@anchor{topics/expressions c gcc_jit_lvalue_set_link_section}@anchor{ee}
@deffn {C Function} void gcc_jit_lvalue_set_link_section (gcc_jit_lvalue@w{ }*lvalue, const char@w{ }*section_name)
Set the link section of a variable.
The parameter @code{section_name} must be non-NULL and must contain the
leading dot. Analogous to:
@example
int variable __attribute__((section(".section")));
@end example
in C.
This entrypoint was added in @ref{ef,,LIBGCCJIT_ABI_18}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_link_section
@end example
@end deffn
@deffn {C Function} void gcc_jit_lvalue_set_register_name (gcc_jit_lvalue *lvalue, const char *reg_name);
Set the register name of a variable.
The parameter @code{reg_name} must be non-NULL. Analogous to:
@example
register int variable asm ("r12");
@end example
in C.
This entrypoint was added in @ref{f0,,LIBGCCJIT_ABI_22}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_register_name
@end example
@end deffn
@geindex gcc_jit_lvalue_set_alignment (C function)
@anchor{topics/expressions c gcc_jit_lvalue_set_alignment}@anchor{f1}
@deffn {C Function} void gcc_jit_lvalue_set_alignment (gcc_jit_lvalue@w{ }*lvalue, unsigned@w{ }bytes)
Set the alignment of a variable, in bytes.
Analogous to:
@example
int variable __attribute__((aligned (16)));
@end example
in C.
This entrypoint was added in @ref{f2,,LIBGCCJIT_ABI_24}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_ALIGNMENT
@end example
@end deffn
@geindex gcc_jit_lvalue_get_alignment (C function)
@anchor{topics/expressions c gcc_jit_lvalue_get_alignment}@anchor{f3}
@deffn {C Function} unsigned gcc_jit_lvalue_get_alignment (gcc_jit_lvalue@w{ }*lvalue)
Return the alignment of a variable set by @code{gcc_jit_lvalue_set_alignment}.
Return 0 if the alignment was not set. Analogous to:
@example
_Alignof (variable)
@end example
in C.
This entrypoint was added in @ref{f2,,LIBGCCJIT_ABI_24}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_ALIGNMENT
@end example
@end deffn
@menu
* Global variables::
@end menu
@node Global variables,,,Lvalues
@anchor{topics/expressions global-variables}@anchor{f4}
@subsubsection Global variables
@geindex gcc_jit_context_new_global (C function)
@anchor{topics/expressions c gcc_jit_context_new_global}@anchor{f5}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_global_kind@w{ }kind, gcc_jit_type@w{ }*type, const char@w{ }*name)
Add a new global variable of the given type and name to the context.
The parameter @code{type} must be non-@cite{void}.
The parameter @code{name} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
The “kind” parameter determines the visibility of the “global” outside
of the @ref{16,,gcc_jit_result}:
@geindex gcc_jit_global_kind (C type)
@anchor{topics/expressions c gcc_jit_global_kind}@anchor{f6}
@deffn {C Type} enum gcc_jit_global_kind
@end deffn
@geindex GCC_JIT_GLOBAL_EXPORTED (C macro)
@anchor{topics/expressions c GCC_JIT_GLOBAL_EXPORTED}@anchor{f7}
@deffn {C Macro} GCC_JIT_GLOBAL_EXPORTED
Global is defined by the client code and is visible
by name outside of this JIT context via
@ref{f8,,gcc_jit_result_get_global()} (and this value is required for
the global to be accessible via that entrypoint).
@end deffn
@geindex GCC_JIT_GLOBAL_INTERNAL (C macro)
@anchor{topics/expressions c GCC_JIT_GLOBAL_INTERNAL}@anchor{f9}
@deffn {C Macro} GCC_JIT_GLOBAL_INTERNAL
Global is defined by the client code, but is invisible
outside of it. Analogous to a “static” global within a .c file.
Specifically, the variable will only be visible within this
context and within child contexts.
@end deffn
@geindex GCC_JIT_GLOBAL_IMPORTED (C macro)
@anchor{topics/expressions c GCC_JIT_GLOBAL_IMPORTED}@anchor{fa}
@deffn {C Macro} GCC_JIT_GLOBAL_IMPORTED
Global is not defined by the client code; we’re merely
referring to it. Analogous to using an “extern” global from a
header file.
@end deffn
@end deffn
@geindex gcc_jit_global_set_initializer (C function)
@anchor{topics/expressions c gcc_jit_global_set_initializer}@anchor{fb}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_global_set_initializer (gcc_jit_lvalue@w{ }*global, const void@w{ }*blob, size_t@w{ }num_bytes)
Set an initializer for @code{global} using the memory content pointed
by @code{blob} for @code{num_bytes}. @code{global} must be an array of an
integral type. Return the global itself.
The parameter @code{blob} must be non-NULL. The call copies the memory
pointed by @code{blob} for @code{num_bytes} bytes, so it is valid to pass
in a pointer to an on-stack buffer. The content will be stored in
the compilation unit and used as initialization value of the array.
This entrypoint was added in @ref{fc,,LIBGCCJIT_ABI_14}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
@end example
@end deffn
@geindex gcc_jit_global_set_initializer_rvalue (C function)
@anchor{topics/expressions c gcc_jit_global_set_initializer_rvalue}@anchor{b7}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue@w{ }*global, gcc_jit_rvalue@w{ }*init_value)
Set the initial value of a global with an rvalue.
The rvalue needs to be a constant expression, e.g. no function calls.
The global can’t have the @code{kind} @ref{fa,,GCC_JIT_GLOBAL_IMPORTED}.
As a non-comprehensive example it is OK to do the equivalent of:
@example
int foo = 3 * 2; /* rvalue from gcc_jit_context_new_binary_op. */
int arr[] = @{1,2,3,4@}; /* rvalue from gcc_jit_context_new_constructor. */
int *bar = &arr[2] + 1; /* rvalue from nested "get address" of "array access". */
const int baz = 3; /* rvalue from gcc_jit_context_rvalue_from_int. */
int boz = baz; /* rvalue from gcc_jit_lvalue_as_rvalue. */
@end example
Use together with @ref{ba,,gcc_jit_context_new_struct_constructor()},
@ref{bb,,gcc_jit_context_new_union_constructor()}, @ref{b9,,gcc_jit_context_new_array_constructor()}
to initialize structs, unions and arrays.
On success, returns the @code{global} parameter unchanged. Otherwise, @code{NULL}.
This entrypoint was added in @ref{b8,,LIBGCCJIT_ABI_19}; you can test for its
presence using:
@example
#ifdef LIBGCCJIT_HAVE_CTORS
@end example
@end deffn
@node Working with pointers structs and unions,,Lvalues,Expressions
@anchor{topics/expressions working-with-pointers-structs-and-unions}@anchor{fd}
@subsection Working with pointers, structs and unions
@geindex gcc_jit_rvalue_dereference (C function)
@anchor{topics/expressions c gcc_jit_rvalue_dereference}@anchor{fe}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_rvalue_dereference (gcc_jit_rvalue@w{ }*rvalue, gcc_jit_location@w{ }*loc)
Given an rvalue of pointer type @code{T *}, dereferencing the pointer,
getting an lvalue of type @code{T}. Analogous to:
@example
*(EXPR)
@end example
in C.
@end deffn
Field access is provided separately for both lvalues and rvalues.
@geindex gcc_jit_lvalue_access_field (C function)
@anchor{topics/expressions c gcc_jit_lvalue_access_field}@anchor{ff}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_lvalue_access_field (gcc_jit_lvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
Given an lvalue of struct or union type, access the given field,
getting an lvalue of the field’s type. Analogous to:
@example
(EXPR).field = ...;
@end example
in C.
@end deffn
@geindex gcc_jit_rvalue_access_field (C function)
@anchor{topics/expressions c gcc_jit_rvalue_access_field}@anchor{100}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_rvalue_access_field (gcc_jit_rvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
Given an rvalue of struct or union type, access the given field
as an rvalue. Analogous to:
@example
(EXPR).field
@end example
in C.
@end deffn
@geindex gcc_jit_rvalue_dereference_field (C function)
@anchor{topics/expressions c gcc_jit_rvalue_dereference_field}@anchor{101}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_rvalue_dereference_field (gcc_jit_rvalue@w{ }*ptr, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
Given an rvalue of pointer type @code{T *} where T is of struct or union
type, access the given field as an lvalue. Analogous to:
@example
(EXPR)->field
@end example
in C, itself equivalent to @code{(*EXPR).FIELD}.
@end deffn
@geindex gcc_jit_context_new_array_access (C function)
@anchor{topics/expressions c gcc_jit_context_new_array_access}@anchor{d3}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_array_access (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*ptr, gcc_jit_rvalue@w{ }*index)
Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at
the given index, using standard C array indexing rules i.e. each
increment of @code{index} corresponds to @code{sizeof(T)} bytes.
Analogous to:
@example
PTR[INDEX]
@end example
in C (or, indeed, to @code{PTR + INDEX}).
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Creating and using functions,Function pointers<2>,Expressions,Topic Reference
@anchor{topics/functions doc}@anchor{102}@anchor{topics/functions creating-and-using-functions}@anchor{103}
@section Creating and using functions
@menu
* Params::
* Functions::
* Blocks::
* Statements::
@end menu
@node Params,Functions,,Creating and using functions
@anchor{topics/functions params}@anchor{104}
@subsection Params
@geindex gcc_jit_param (C type)
@anchor{topics/functions c gcc_jit_param}@anchor{25}
@deffn {C Type} gcc_jit_param
A @cite{gcc_jit_param} represents a parameter to a function.
@end deffn
@geindex gcc_jit_context_new_param (C function)
@anchor{topics/functions c gcc_jit_context_new_param}@anchor{10}
@deffn {C Function} gcc_jit_param * gcc_jit_context_new_param (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
In preparation for creating a function, create a new parameter of the
given type and name.
The parameter @code{type} must be non-@cite{void}.
The parameter @code{name} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
@end deffn
Parameters are lvalues, and thus are also rvalues (and objects), so the
following upcasts are available:
@geindex gcc_jit_param_as_lvalue (C function)
@anchor{topics/functions c gcc_jit_param_as_lvalue}@anchor{105}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_param_as_lvalue (gcc_jit_param@w{ }*param)
Upcasting from param to lvalue.
@end deffn
@geindex gcc_jit_param_as_rvalue (C function)
@anchor{topics/functions c gcc_jit_param_as_rvalue}@anchor{106}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_param_as_rvalue (gcc_jit_param@w{ }*param)
Upcasting from param to rvalue.
@end deffn
@geindex gcc_jit_param_as_object (C function)
@anchor{topics/functions c gcc_jit_param_as_object}@anchor{107}
@deffn {C Function} gcc_jit_object * gcc_jit_param_as_object (gcc_jit_param@w{ }*param)
Upcasting from param to object.
@end deffn
@node Functions,Blocks,Params,Creating and using functions
@anchor{topics/functions functions}@anchor{108}
@subsection Functions
@geindex gcc_jit_function (C type)
@anchor{topics/functions c gcc_jit_function}@anchor{29}
@deffn {C Type} gcc_jit_function
A @cite{gcc_jit_function} represents a function - either one that we’re
creating ourselves, or one that we’re referencing.
@end deffn
@geindex gcc_jit_context_new_function (C function)
@anchor{topics/functions c gcc_jit_context_new_function}@anchor{11}
@deffn {C Function} gcc_jit_function * gcc_jit_context_new_function (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_function_kind@w{ }kind, gcc_jit_type@w{ }*return_type, const char@w{ }*name, int@w{ }num_params, gcc_jit_param@w{ }**params, int@w{ }is_variadic)
Create a gcc_jit_function with the given name and parameters.
@geindex gcc_jit_function_kind (C type)
@anchor{topics/functions c gcc_jit_function_kind}@anchor{109}
@deffn {C Type} enum gcc_jit_function_kind
@end deffn
This enum controls the kind of function created, and has the following
values:
@quotation
@geindex GCC_JIT_FUNCTION_EXPORTED (C macro)
@anchor{topics/functions c GCC_JIT_FUNCTION_EXPORTED}@anchor{10a}
@deffn {C Macro} GCC_JIT_FUNCTION_EXPORTED
Function is defined by the client code and visible
by name outside of the JIT.
This value is required if you want to extract machine code
for this function from a @ref{16,,gcc_jit_result} via
@ref{17,,gcc_jit_result_get_code()}.
@end deffn
@geindex GCC_JIT_FUNCTION_INTERNAL (C macro)
@anchor{topics/functions c GCC_JIT_FUNCTION_INTERNAL}@anchor{10b}
@deffn {C Macro} GCC_JIT_FUNCTION_INTERNAL
Function is defined by the client code, but is invisible
outside of the JIT. Analogous to a “static” function.
@end deffn
@geindex GCC_JIT_FUNCTION_IMPORTED (C macro)
@anchor{topics/functions c GCC_JIT_FUNCTION_IMPORTED}@anchor{10c}
@deffn {C Macro} GCC_JIT_FUNCTION_IMPORTED
Function is not defined by the client code; we’re merely
referring to it. Analogous to using an “extern” function from a
header file.
@end deffn
@geindex GCC_JIT_FUNCTION_ALWAYS_INLINE (C macro)
@anchor{topics/functions c GCC_JIT_FUNCTION_ALWAYS_INLINE}@anchor{10d}
@deffn {C Macro} GCC_JIT_FUNCTION_ALWAYS_INLINE
Function is only ever inlined into other functions, and is
invisible outside of the JIT.
Analogous to prefixing with @code{inline} and adding
@code{__attribute__((always_inline))}
Inlining will only occur when the optimization level is
above 0; when optimization is off, this is essentially the
same as GCC_JIT_FUNCTION_INTERNAL.
@end deffn
@end quotation
The parameter @code{name} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
@end deffn
@geindex gcc_jit_context_get_builtin_function (C function)
@anchor{topics/functions c gcc_jit_context_get_builtin_function}@anchor{10e}
@deffn {C Function} gcc_jit_function * gcc_jit_context_get_builtin_function (gcc_jit_context@w{ }*ctxt, const char@w{ }*name)
Get the @ref{29,,gcc_jit_function} for the built-in function with the
given name. For example:
@example
gcc_jit_function *fn
= gcc_jit_context_get_builtin_function (ctxt, "__builtin_memcpy");
@end example
@cartouche
@quotation Note
Due to technical limitations with how libgccjit interacts with
the insides of GCC, not all built-in functions are supported. More
precisely, not all types are supported for parameters of built-in
functions from libgccjit. Attempts to get a built-in function that
uses such a parameter will lead to an error being emitted within
the context.
@end quotation
@end cartouche
@end deffn
@geindex gcc_jit_function_as_object (C function)
@anchor{topics/functions c gcc_jit_function_as_object}@anchor{10f}
@deffn {C Function} gcc_jit_object * gcc_jit_function_as_object (gcc_jit_function@w{ }*func)
Upcasting from function to object.
@end deffn
@geindex gcc_jit_function_get_param (C function)
@anchor{topics/functions c gcc_jit_function_get_param}@anchor{110}
@deffn {C Function} gcc_jit_param * gcc_jit_function_get_param (gcc_jit_function@w{ }*func, int@w{ }index)
Get the param of the given index (0-based).
@end deffn
@geindex gcc_jit_function_dump_to_dot (C function)
@anchor{topics/functions c gcc_jit_function_dump_to_dot}@anchor{33}
@deffn {C Function} void gcc_jit_function_dump_to_dot (gcc_jit_function@w{ }*func, const char@w{ }*path)
Emit the function in graphviz format to the given path.
@end deffn
@geindex gcc_jit_function_new_local (C function)
@anchor{topics/functions c gcc_jit_function_new_local}@anchor{26}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_function_new_local (gcc_jit_function@w{ }*func, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
Create a new local variable within the function, of the given type and
name.
The parameter @code{type} must be non-@cite{void}.
The parameter @code{name} must be non-NULL. The call takes a copy of the
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
@end deffn
@geindex gcc_jit_function_get_param_count (C function)
@anchor{topics/functions c gcc_jit_function_get_param_count}@anchor{111}
@deffn {C Function} size_t gcc_jit_function_get_param_count (gcc_jit_function@w{ }*func)
Get the number of parameters of the function.
@end deffn
@geindex gcc_jit_function_get_return_type (C function)
@anchor{topics/functions c gcc_jit_function_get_return_type}@anchor{112}
@deffn {C Function} gcc_jit_type * gcc_jit_function_get_return_type (gcc_jit_function@w{ }*func)
Get the return type of the function.
The API entrypoints relating to getting info about parameters and return
types:
@quotation
@itemize *
@item
@ref{112,,gcc_jit_function_get_return_type()}
@item
@ref{111,,gcc_jit_function_get_param_count()}
@end itemize
@end quotation
were added in @ref{a8,,LIBGCCJIT_ABI_16}; you can test for their presence
using
@example
#ifdef LIBGCCJIT_HAVE_REFLECTION
@end example
@geindex gcc_jit_case (C type)
@anchor{topics/functions c gcc_jit_case}@anchor{113}
@deffn {C Type} gcc_jit_case
@end deffn
@end deffn
@node Blocks,Statements,Functions,Creating and using functions
@anchor{topics/functions blocks}@anchor{114}
@subsection Blocks
@geindex gcc_jit_block (C type)
@anchor{topics/functions c gcc_jit_block}@anchor{28}
@deffn {C Type} gcc_jit_block
A @cite{gcc_jit_block} represents a basic block within a function i.e. a
sequence of statements with a single entry point and a single exit
point.
The first basic block that you create within a function will
be the entrypoint.
Each basic block that you create within a function must be
terminated, either with a conditional, a jump, a return, or a
switch.
It’s legal to have multiple basic blocks that return within
one function.
@end deffn
@geindex gcc_jit_function_new_block (C function)
@anchor{topics/functions c gcc_jit_function_new_block}@anchor{115}
@deffn {C Function} gcc_jit_block * gcc_jit_function_new_block (gcc_jit_function@w{ }*func, const char@w{ }*name)
Create a basic block of the given name. The name may be NULL, but
providing meaningful names is often helpful when debugging: it may
show up in dumps of the internal representation, and in error
messages. It is copied, so the input buffer does not need to outlive
the call; you can pass in a pointer to an on-stack buffer, e.g.:
@example
for (pc = 0; pc < fn->fn_num_ops; pc++)
@{
char buf[16];
sprintf (buf, "instr%i", pc);
state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
@}
@end example
@end deffn
@geindex gcc_jit_block_as_object (C function)
@anchor{topics/functions c gcc_jit_block_as_object}@anchor{116}
@deffn {C Function} gcc_jit_object * gcc_jit_block_as_object (gcc_jit_block@w{ }*block)
Upcast from block to object.
@end deffn
@geindex gcc_jit_block_get_function (C function)
@anchor{topics/functions c gcc_jit_block_get_function}@anchor{117}
@deffn {C Function} gcc_jit_function * gcc_jit_block_get_function (gcc_jit_block@w{ }*block)
Which function is this block within?
@end deffn
@node Statements,,Blocks,Creating and using functions
@anchor{topics/functions statements}@anchor{118}
@subsection Statements
@geindex gcc_jit_block_add_eval (C function)
@anchor{topics/functions c gcc_jit_block_add_eval}@anchor{d8}
@deffn {C Function} void gcc_jit_block_add_eval (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
Add evaluation of an rvalue, discarding the result
(e.g. a function call that “returns” void).
This is equivalent to this C code:
@example
(void)expression;
@end example
@end deffn
@geindex gcc_jit_block_add_assignment (C function)
@anchor{topics/functions c gcc_jit_block_add_assignment}@anchor{2a}
@deffn {C Function} void gcc_jit_block_add_assignment (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_lvalue@w{ }*lvalue, gcc_jit_rvalue@w{ }*rvalue)
Add evaluation of an rvalue, assigning the result to the given
lvalue.
This is roughly equivalent to this C code:
@example
lvalue = rvalue;
@end example
@end deffn
@geindex gcc_jit_block_add_assignment_op (C function)
@anchor{topics/functions c gcc_jit_block_add_assignment_op}@anchor{2e}
@deffn {C Function} void gcc_jit_block_add_assignment_op (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_lvalue@w{ }*lvalue, enum gcc_jit_binary_op@w{ }op, gcc_jit_rvalue@w{ }*rvalue)
Add evaluation of an rvalue, using the result to modify an
lvalue.
This is analogous to “+=” and friends:
@example
lvalue += rvalue;
lvalue *= rvalue;
lvalue /= rvalue;
@end example
etc. For example:
@example
/* "i++" */
gcc_jit_block_add_assignment_op (
loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, int_type));
@end example
@end deffn
@geindex gcc_jit_block_add_comment (C function)
@anchor{topics/functions c gcc_jit_block_add_comment}@anchor{3d}
@deffn {C Function} void gcc_jit_block_add_comment (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*text)
Add a no-op textual comment to the internal representation of the
code. It will be optimized away, but will be visible in the dumps
seen via @ref{66,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}
and @ref{1c,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE},
and thus may be of use when debugging how your project’s internal
representation gets converted to the libgccjit IR.
The parameter @code{text} must be non-NULL. It is copied, so the input
buffer does not need to outlive the call. For example:
@example
char buf[100];
snprintf (buf, sizeof (buf),
"op%i: %s",
pc, opcode_names[op->op_opcode]);
gcc_jit_block_add_comment (block, loc, buf);
@end example
@end deffn
@geindex gcc_jit_block_end_with_conditional (C function)
@anchor{topics/functions c gcc_jit_block_end_with_conditional}@anchor{2d}
@deffn {C Function} void gcc_jit_block_end_with_conditional (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*boolval, gcc_jit_block@w{ }*on_true, gcc_jit_block@w{ }*on_false)
Terminate a block by adding evaluation of an rvalue, branching on the
result to the appropriate successor block.
This is roughly equivalent to this C code:
@example
if (boolval)
goto on_true;
else
goto on_false;
@end example
block, boolval, on_true, and on_false must be non-NULL.
@end deffn
@geindex gcc_jit_block_end_with_jump (C function)
@anchor{topics/functions c gcc_jit_block_end_with_jump}@anchor{119}
@deffn {C Function} void gcc_jit_block_end_with_jump (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_block@w{ }*target)
Terminate a block by adding a jump to the given target block.
This is roughly equivalent to this C code:
@example
goto target;
@end example
@end deffn
@geindex gcc_jit_block_end_with_return (C function)
@anchor{topics/functions c gcc_jit_block_end_with_return}@anchor{11a}
@deffn {C Function} void gcc_jit_block_end_with_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
Terminate a block by adding evaluation of an rvalue, returning the value.
This is roughly equivalent to this C code:
@example
return expression;
@end example
@end deffn
@geindex gcc_jit_block_end_with_void_return (C function)
@anchor{topics/functions c gcc_jit_block_end_with_void_return}@anchor{11b}
@deffn {C Function} void gcc_jit_block_end_with_void_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc)
Terminate a block by adding a valueless return, for use within a function
with “void” return type.
This is equivalent to this C code:
@example
return;
@end example
@end deffn
@geindex gcc_jit_block_end_with_switch (C function)
@anchor{topics/functions c gcc_jit_block_end_with_switch}@anchor{11c}
@deffn {C Function} void gcc_jit_block_end_with_switch (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*expr, gcc_jit_block@w{ }*default_block, int@w{ }num_cases, gcc_jit_case@w{ }**cases)
Terminate a block by adding evalation of an rvalue, then performing
a multiway branch.
This is roughly equivalent to this C code:
@example
switch (expr)
@{
default:
goto default_block;
case C0.min_value ... C0.max_value:
goto C0.dest_block;
case C1.min_value ... C1.max_value:
goto C1.dest_block;
...etc...
case C[N - 1].min_value ... C[N - 1].max_value:
goto C[N - 1].dest_block;
@}
@end example
@code{block}, @code{expr}, @code{default_block} and @code{cases} must all be
non-NULL.
@code{expr} must be of the same integer type as all of the @code{min_value}
and @code{max_value} within the cases.
@code{num_cases} must be >= 0.
The ranges of the cases must not overlap (or have duplicate
values).
The API entrypoints relating to switch statements and cases:
@quotation
@itemize *
@item
@ref{11c,,gcc_jit_block_end_with_switch()}
@item
@ref{11d,,gcc_jit_case_as_object()}
@item
@ref{11e,,gcc_jit_context_new_case()}
@end itemize
@end quotation
were added in @ref{11f,,LIBGCCJIT_ABI_3}; you can test for their presence
using
@example
#ifdef LIBGCCJIT_HAVE_SWITCH_STATEMENTS
@end example
@geindex gcc_jit_case (C type)
@deffn {C Type} gcc_jit_case
@end deffn
A @cite{gcc_jit_case} represents a case within a switch statement, and
is created within a particular @ref{8,,gcc_jit_context} using
@ref{11e,,gcc_jit_context_new_case()}.
Each case expresses a multivalued range of integer values. You
can express single-valued cases by passing in the same value for
both @cite{min_value} and @cite{max_value}.
@geindex gcc_jit_context_new_case (C function)
@anchor{topics/functions c gcc_jit_context_new_case}@anchor{11e}
@deffn {C Function} gcc_jit_case * gcc_jit_context_new_case (gcc_jit_context@w{ }*ctxt, gcc_jit_rvalue@w{ }*min_value, gcc_jit_rvalue@w{ }*max_value, gcc_jit_block@w{ }*dest_block)
Create a new gcc_jit_case instance for use in a switch statement.
@cite{min_value} and @cite{max_value} must be constants of an integer type,
which must match that of the expression of the switch statement.
@cite{dest_block} must be within the same function as the switch
statement.
@end deffn
@geindex gcc_jit_case_as_object (C function)
@anchor{topics/functions c gcc_jit_case_as_object}@anchor{11d}
@deffn {C Function} gcc_jit_object * gcc_jit_case_as_object (gcc_jit_case@w{ }*case_)
Upcast from a case to an object.
@end deffn
Here’s an example of creating a switch statement:
@quotation
@example
void
create_code (gcc_jit_context *ctxt, void *user_data)
@{
/* Let's try to inject the equivalent of:
int
test_switch (int x)
@{
switch (x)
@{
case 0 ... 5:
return 3;
case 25 ... 27:
return 4;
case -42 ... -17:
return 83;
case 40:
return 8;
default:
return 10;
@}
@}
*/
gcc_jit_type *t_int =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = t_int;
gcc_jit_param *x =
gcc_jit_context_new_param (ctxt, NULL, t_int, "x");
gcc_jit_param *params[1] = @{x@};
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"test_switch",
1, params, 0);
gcc_jit_block *b_initial =
gcc_jit_function_new_block (func, "initial");
gcc_jit_block *b_default =
gcc_jit_function_new_block (func, "default");
gcc_jit_block *b_case_0_5 =
gcc_jit_function_new_block (func, "case_0_5");
gcc_jit_block *b_case_25_27 =
gcc_jit_function_new_block (func, "case_25_27");
gcc_jit_block *b_case_m42_m17 =
gcc_jit_function_new_block (func, "case_m42_m17");
gcc_jit_block *b_case_40 =
gcc_jit_function_new_block (func, "case_40");
gcc_jit_case *cases[4] = @{
gcc_jit_context_new_case (
ctxt,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 0),
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 5),
b_case_0_5),
gcc_jit_context_new_case (
ctxt,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 25),
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 27),
b_case_25_27),
gcc_jit_context_new_case (
ctxt,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, -42),
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, -17),
b_case_m42_m17),
gcc_jit_context_new_case (
ctxt,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 40),
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 40),
b_case_40)
@};
gcc_jit_block_end_with_switch (
b_initial, NULL,
gcc_jit_param_as_rvalue (x),
b_default,
4, cases);
gcc_jit_block_end_with_return (
b_case_0_5, NULL,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 3));
gcc_jit_block_end_with_return (
b_case_25_27, NULL,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 4));
gcc_jit_block_end_with_return (
b_case_m42_m17, NULL,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 83));
gcc_jit_block_end_with_return (
b_case_40, NULL,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 8));
gcc_jit_block_end_with_return (
b_default, NULL,
gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 10));
@}
@end example
@end quotation
@end deffn
See also @ref{120,,gcc_jit_extended_asm} for entrypoints for adding inline
assembler statements to a function.
@c Copyright (C) 2017-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Function pointers<2>,Source Locations,Creating and using functions,Topic Reference
@anchor{topics/function-pointers doc}@anchor{121}@anchor{topics/function-pointers function-pointers}@anchor{122}
@section Function pointers
You can generate calls that use a function pointer via
@ref{d9,,gcc_jit_context_new_call_through_ptr()}.
To do requires a @ref{13,,gcc_jit_rvalue} of the correct function pointer type.
Function pointers for a @ref{29,,gcc_jit_function} can be obtained
via @ref{dd,,gcc_jit_function_get_address()}.
@geindex gcc_jit_function_get_address (C function)
@anchor{topics/function-pointers c gcc_jit_function_get_address}@anchor{dd}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_function_get_address (gcc_jit_function@w{ }*fn, gcc_jit_location@w{ }*loc)
Get the address of a function as an rvalue, of function pointer
type.
This entrypoint was added in @ref{123,,LIBGCCJIT_ABI_9}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
@end example
@end deffn
Alternatively, given an existing function, you can obtain a pointer
to it in @ref{13,,gcc_jit_rvalue} form using
@ref{b3,,gcc_jit_context_new_rvalue_from_ptr()}, using a function pointer
type obtained using @ref{97,,gcc_jit_context_new_function_ptr_type()}.
Here’s an example of creating a function pointer type corresponding to C’s
@code{void (*) (int, int, int)}:
@example
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the function ptr type. */
gcc_jit_type *param_types[3];
param_types[0] = int_type;
param_types[1] = int_type;
param_types[2] = int_type;
gcc_jit_type *fn_ptr_type =
gcc_jit_context_new_function_ptr_type (ctxt, NULL,
void_type,
3, param_types, 0);
@end example
@geindex gcc_jit_context_new_function_ptr_type (C function)
@anchor{topics/function-pointers c gcc_jit_context_new_function_ptr_type}@anchor{97}
@deffn {C Function} gcc_jit_type * gcc_jit_context_new_function_ptr_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*return_type, int@w{ }num_params, gcc_jit_type@w{ }**param_types, int@w{ }is_variadic)
Generate a @ref{a,,gcc_jit_type} for a function pointer with the
given return type and parameters.
Each of @cite{param_types} must be non-@cite{void}; @cite{return_type} may be @cite{void}.
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Source Locations,Compiling a context,Function pointers<2>,Topic Reference
@anchor{topics/locations doc}@anchor{124}@anchor{topics/locations source-locations}@anchor{125}
@section Source Locations
@geindex gcc_jit_location (C type)
@anchor{topics/locations c gcc_jit_location}@anchor{3b}
@deffn {C Type} gcc_jit_location
A @cite{gcc_jit_location} encapsulates a source code location, so that
you can (optionally) associate locations in your language with
statements in the JIT-compiled code, allowing the debugger to
single-step through your language.
@cite{gcc_jit_location} instances are optional: you can always pass NULL to
any API entrypoint accepting one.
You can construct them using @ref{41,,gcc_jit_context_new_location()}.
You need to enable @ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@ref{8,,gcc_jit_context} for these locations to actually be usable by
the debugger:
@example
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DEBUGINFO,
1);
@end example
@end deffn
@geindex gcc_jit_context_new_location (C function)
@anchor{topics/locations c gcc_jit_context_new_location}@anchor{41}
@deffn {C Function} gcc_jit_location * gcc_jit_context_new_location (gcc_jit_context@w{ }*ctxt, const char@w{ }*filename, int@w{ }line, int@w{ }column)
Create a @cite{gcc_jit_location} instance representing the given source
location.
The parameter @code{filename} must be non-NULL. The call takes a copy of
the underlying string, so it is valid to pass in a pointer to an
on-stack buffer.
@end deffn
@menu
* Faking it::
@end menu
@node Faking it,,,Source Locations
@anchor{topics/locations faking-it}@anchor{126}
@subsection Faking it
If you don’t have source code for your internal representation, but need
to debug, you can generate a C-like representation of the functions in
your context using @ref{5a,,gcc_jit_context_dump_to_file()}:
@example
gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
1 /* update_locations */);
@end example
This will dump C-like code to the given path. If the @cite{update_locations}
argument is true, this will also set up @cite{gcc_jit_location} information
throughout the context, pointing at the dump file as if it were a source
file, giving you @emph{something} you can step through in the debugger.
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Compiling a context,ABI and API compatibility,Source Locations,Topic Reference
@anchor{topics/compilation doc}@anchor{127}@anchor{topics/compilation compiling-a-context}@anchor{128}
@section Compiling a context
Once populated, a @ref{8,,gcc_jit_context *} can be compiled to
machine code, either in-memory via @ref{15,,gcc_jit_context_compile()} or
to disk via @ref{4a,,gcc_jit_context_compile_to_file()}.
You can compile a context multiple times (using either form of
compilation), although any errors that occur on the context will
prevent any future compilation of that context.
@menu
* In-memory compilation::
* Ahead-of-time compilation::
@end menu
@node In-memory compilation,Ahead-of-time compilation,,Compiling a context
@anchor{topics/compilation in-memory-compilation}@anchor{129}
@subsection In-memory compilation
@geindex gcc_jit_context_compile (C function)
@anchor{topics/compilation c gcc_jit_context_compile}@anchor{15}
@deffn {C Function} gcc_jit_result * gcc_jit_context_compile (gcc_jit_context@w{ }*ctxt)
This calls into GCC and builds the code, returning a
@cite{gcc_jit_result *}.
If the result is non-NULL, the caller becomes responsible for
calling @ref{39,,gcc_jit_result_release()} on it once they’re done
with it.
@end deffn
@geindex gcc_jit_result (C type)
@anchor{topics/compilation c gcc_jit_result}@anchor{16}
@deffn {C Type} gcc_jit_result
A @cite{gcc_jit_result} encapsulates the result of compiling a context
in-memory, and the lifetimes of any machine code functions or globals
that are within the result.
@end deffn
@geindex gcc_jit_result_get_code (C function)
@anchor{topics/compilation c gcc_jit_result_get_code}@anchor{17}
@deffn {C Function} void * gcc_jit_result_get_code (gcc_jit_result@w{ }*result, const char@w{ }*funcname)
Locate a given function within the built machine code.
Functions are looked up by name. For this to succeed, a function
with a name matching @cite{funcname} must have been created on
@cite{result}’s context (or a parent context) via a call to
@ref{11,,gcc_jit_context_new_function()} with @cite{kind}
@ref{10a,,GCC_JIT_FUNCTION_EXPORTED}:
@example
gcc_jit_context_new_function (ctxt,
any_location, /* or NULL */
/* Required for func to be visible to
gcc_jit_result_get_code: */
GCC_JIT_FUNCTION_EXPORTED,
any_return_type,
/* Must string-compare equal: */
funcname,
/* etc */);
@end example
If such a function is not found (or @cite{result} or @cite{funcname} are
@code{NULL}), an error message will be emitted on stderr and
@code{NULL} will be returned.
If the function is found, the result will need to be cast to a
function pointer of the correct type before it can be called.
Note that the resulting machine code becomes invalid after
@ref{39,,gcc_jit_result_release()} is called on the
@ref{16,,gcc_jit_result *}; attempting to call it after that may lead
to a segmentation fault.
@end deffn
@geindex gcc_jit_result_get_global (C function)
@anchor{topics/compilation c gcc_jit_result_get_global}@anchor{f8}
@deffn {C Function} void * gcc_jit_result_get_global (gcc_jit_result@w{ }*result, const char@w{ }*name)
Locate a given global within the built machine code.
Globals are looked up by name. For this to succeed, a global
with a name matching @cite{name} must have been created on
@cite{result}’s context (or a parent context) via a call to
@ref{f5,,gcc_jit_context_new_global()} with @cite{kind}
@ref{f7,,GCC_JIT_GLOBAL_EXPORTED}.
If the global is found, the result will need to be cast to a
pointer of the correct type before it can be called.
This is a @emph{pointer} to the global, so e.g. for an @code{int} this is
an @code{int *}.
For example, given an @code{int foo;} created this way:
@example
gcc_jit_lvalue *exported_global =
gcc_jit_context_new_global (ctxt,
any_location, /* or NULL */
GCC_JIT_GLOBAL_EXPORTED,
int_type,
"foo");
@end example
we can access it like this:
@example
int *ptr_to_foo =
(int *)gcc_jit_result_get_global (result, "foo");
@end example
If such a global is not found (or @cite{result} or @cite{name} are
@code{NULL}), an error message will be emitted on stderr and
@code{NULL} will be returned.
Note that the resulting address becomes invalid after
@ref{39,,gcc_jit_result_release()} is called on the
@ref{16,,gcc_jit_result *}; attempting to use it after that may lead
to a segmentation fault.
@end deffn
@geindex gcc_jit_result_release (C function)
@anchor{topics/compilation c gcc_jit_result_release}@anchor{39}
@deffn {C Function} void gcc_jit_result_release (gcc_jit_result@w{ }*result)
Once we’re done with the code, this unloads the built .so file.
This cleans up the result; after calling this, it’s no longer
valid to use the result, or any code or globals that were obtained
by calling @ref{17,,gcc_jit_result_get_code()} or
@ref{f8,,gcc_jit_result_get_global()} on it.
@end deffn
@node Ahead-of-time compilation,,In-memory compilation,Compiling a context
@anchor{topics/compilation ahead-of-time-compilation}@anchor{12a}
@subsection Ahead-of-time compilation
Although libgccjit is primarily aimed at just-in-time compilation, it
can also be used for implementing more traditional ahead-of-time
compilers, via the @ref{4a,,gcc_jit_context_compile_to_file()}
API entrypoint.
For linking in object files, use @ref{76,,gcc_jit_context_add_driver_option()}.
@geindex gcc_jit_context_compile_to_file (C function)
@anchor{topics/compilation c gcc_jit_context_compile_to_file}@anchor{4a}
@deffn {C Function} void gcc_jit_context_compile_to_file (gcc_jit_context@w{ }*ctxt, enum gcc_jit_output_kind@w{ }output_kind, const char@w{ }*output_path)
Compile the @ref{8,,gcc_jit_context *} to a file of the given
kind.
@end deffn
@ref{4a,,gcc_jit_context_compile_to_file()} ignores the suffix of
@code{output_path}, and insteads uses the given
@code{enum gcc_jit_output_kind} to decide what to do.
@cartouche
@quotation Note
This is different from the @code{gcc} program, which does make use of the
suffix of the output file when determining what to do.
@end quotation
@end cartouche
@geindex gcc_jit_output_kind (C type)
@anchor{topics/compilation c gcc_jit_output_kind}@anchor{12b}
@deffn {C Type} enum gcc_jit_output_kind
@end deffn
The available kinds of output are:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxx}
@headitem
Output kind
@tab
Typical suffix
@item
@ref{12c,,GCC_JIT_OUTPUT_KIND_ASSEMBLER}
@tab
.s
@item
@ref{12d,,GCC_JIT_OUTPUT_KIND_OBJECT_FILE}
@tab
.o
@item
@ref{12e,,GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}
@tab
.so or .dll
@item
@ref{12f,,GCC_JIT_OUTPUT_KIND_EXECUTABLE}
@tab
None, or .exe
@end multitable
@geindex GCC_JIT_OUTPUT_KIND_ASSEMBLER (C macro)
@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_ASSEMBLER}@anchor{12c}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_ASSEMBLER
Compile the context to an assembler file.
@end deffn
@geindex GCC_JIT_OUTPUT_KIND_OBJECT_FILE (C macro)
@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_OBJECT_FILE}@anchor{12d}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_OBJECT_FILE
Compile the context to an object file.
@end deffn
@geindex GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY (C macro)
@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}@anchor{12e}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
Compile the context to a dynamic library.
@end deffn
@geindex GCC_JIT_OUTPUT_KIND_EXECUTABLE (C macro)
@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_EXECUTABLE}@anchor{12f}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_EXECUTABLE
Compile the context to an executable.
@end deffn
@c Copyright (C) 2015-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node ABI and API compatibility,Performance,Compiling a context,Topic Reference
@anchor{topics/compatibility doc}@anchor{130}@anchor{topics/compatibility abi-and-api-compatibility}@anchor{131}
@section ABI and API compatibility
The libgccjit developers strive for ABI and API backward-compatibility:
programs built against libgccjit.so stand a good chance of running
without recompilation against newer versions of libgccjit.so, and
ought to recompile without modification against newer versions of
libgccjit.h.
@cartouche
@quotation Note
The libgccjit++.h C++ API is more experimental, and less
locked-down at this time.
@end quotation
@end cartouche
API compatibility is achieved by extending the API rather than changing
it. For ABI compatiblity, we avoid bumping the SONAME, and instead use
symbol versioning to tag each symbol, so that a binary linked against
libgccjit.so is tagged according to the symbols that it uses.
For example, @ref{74,,gcc_jit_context_add_command_line_option()} was added in
@code{LIBGCCJIT_ABI_1}. If a client program uses it, this can be detected
from metadata by using @code{objdump}:
@example
$ objdump -p testsuite/jit/test-extra-options.c.exe | tail -n 8
Version References:
required from libgccjit.so.0:
0x00824161 0x00 04 LIBGCCJIT_ABI_1
0x00824160 0x00 03 LIBGCCJIT_ABI_0
required from libc.so.6:
@end example
You can see the symbol tags provided by libgccjit.so using @code{objdump}:
@example
$ objdump -p libgccjit.so | less
[...snip...]
Version definitions:
1 0x01 0x0ff81f20 libgccjit.so.0
2 0x00 0x00824160 LIBGCCJIT_ABI_0
3 0x00 0x00824161 LIBGCCJIT_ABI_1
LIBGCCJIT_ABI_0
[...snip...]
@end example
@menu
* Programmatically checking version::
* ABI symbol tags::
@end menu
@node Programmatically checking version,ABI symbol tags,,ABI and API compatibility
@anchor{topics/compatibility programmatically-checking-version}@anchor{132}
@subsection Programmatically checking version
Client code can programmatically check libgccjit version using:
@geindex gcc_jit_version_major (C function)
@anchor{topics/compatibility c gcc_jit_version_major}@anchor{133}
@deffn {C Function} int gcc_jit_version_major (void)
Return libgccjit major version. This is analogous to __GNUC__ in C code.
@end deffn
@geindex gcc_jit_version_minor (C function)
@anchor{topics/compatibility c gcc_jit_version_minor}@anchor{134}
@deffn {C Function} int gcc_jit_version_minor (void)
Return libgccjit minor version. This is analogous to
__GNUC_MINOR__ in C code.
@end deffn
@geindex gcc_jit_version_patchlevel (C function)
@anchor{topics/compatibility c gcc_jit_version_patchlevel}@anchor{135}
@deffn {C Function} int gcc_jit_version_patchlevel (void)
Return libgccjit patchlevel version. This is analogous to
__GNUC_PATCHLEVEL__ in C code.
@end deffn
@cartouche
@quotation Note
These entry points has been added with @code{LIBGCCJIT_ABI_13}
(see below).
@end quotation
@end cartouche
@node ABI symbol tags,,Programmatically checking version,ABI and API compatibility
@anchor{topics/compatibility abi-symbol-tags}@anchor{136}
@subsection ABI symbol tags
The initial release of libgccjit (in gcc 5.1) did not use symbol versioning.
Newer releases use the following tags.
@menu
* 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::
@end menu
@node LIBGCCJIT_ABI_0,LIBGCCJIT_ABI_1,,ABI symbol tags
@anchor{topics/compatibility id1}@anchor{137}@anchor{topics/compatibility libgccjit-abi-0}@anchor{138}
@subsubsection @code{LIBGCCJIT_ABI_0}
All entrypoints in the initial release of libgccjit are tagged with
@code{LIBGCCJIT_ABI_0}, to signify the transition to symbol versioning.
Binaries built against older copies of @code{libgccjit.so} should
continue to work, with this being handled transparently by the linker
(see this post@footnote{https://gcc.gnu.org/ml/gcc-patches/2015-06/msg02126.html})
@node LIBGCCJIT_ABI_1,LIBGCCJIT_ABI_2,LIBGCCJIT_ABI_0,ABI symbol tags
@anchor{topics/compatibility id2}@anchor{139}@anchor{topics/compatibility libgccjit-abi-1}@anchor{75}
@subsubsection @code{LIBGCCJIT_ABI_1}
@code{LIBGCCJIT_ABI_1} covers the addition of
@ref{74,,gcc_jit_context_add_command_line_option()}
@node LIBGCCJIT_ABI_2,LIBGCCJIT_ABI_3,LIBGCCJIT_ABI_1,ABI symbol tags
@anchor{topics/compatibility id3}@anchor{13a}@anchor{topics/compatibility libgccjit-abi-2}@anchor{6c}
@subsubsection @code{LIBGCCJIT_ABI_2}
@code{LIBGCCJIT_ABI_2} covers the addition of
@ref{6b,,gcc_jit_context_set_bool_allow_unreachable_blocks()}
@node LIBGCCJIT_ABI_3,LIBGCCJIT_ABI_4,LIBGCCJIT_ABI_2,ABI symbol tags
@anchor{topics/compatibility id4}@anchor{13b}@anchor{topics/compatibility libgccjit-abi-3}@anchor{11f}
@subsubsection @code{LIBGCCJIT_ABI_3}
@code{LIBGCCJIT_ABI_3} covers the addition of switch statements via API
entrypoints:
@quotation
@itemize *
@item
@ref{11c,,gcc_jit_block_end_with_switch()}
@item
@ref{11d,,gcc_jit_case_as_object()}
@item
@ref{11e,,gcc_jit_context_new_case()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_4,LIBGCCJIT_ABI_5,LIBGCCJIT_ABI_3,ABI symbol tags
@anchor{topics/compatibility id5}@anchor{13c}@anchor{topics/compatibility libgccjit-abi-4}@anchor{13d}
@subsubsection @code{LIBGCCJIT_ABI_4}
@code{LIBGCCJIT_ABI_4} covers the addition of timers via API
entrypoints:
@quotation
@itemize *
@item
@ref{13e,,gcc_jit_context_get_timer()}
@item
@ref{13f,,gcc_jit_context_set_timer()}
@item
@ref{140,,gcc_jit_timer_new()}
@item
@ref{141,,gcc_jit_timer_release()}
@item
@ref{142,,gcc_jit_timer_push()}
@item
@ref{143,,gcc_jit_timer_pop()}
@item
@ref{144,,gcc_jit_timer_print()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_5,LIBGCCJIT_ABI_6,LIBGCCJIT_ABI_4,ABI symbol tags
@anchor{topics/compatibility id6}@anchor{145}@anchor{topics/compatibility libgccjit-abi-5}@anchor{6e}
@subsubsection @code{LIBGCCJIT_ABI_5}
@code{LIBGCCJIT_ABI_5} covers the addition of
@ref{6d,,gcc_jit_context_set_bool_use_external_driver()}
@node LIBGCCJIT_ABI_6,LIBGCCJIT_ABI_7,LIBGCCJIT_ABI_5,ABI symbol tags
@anchor{topics/compatibility id7}@anchor{146}@anchor{topics/compatibility libgccjit-abi-6}@anchor{db}
@subsubsection @code{LIBGCCJIT_ABI_6}
@code{LIBGCCJIT_ABI_6} covers the addition of
@ref{da,,gcc_jit_rvalue_set_bool_require_tail_call()}
@node LIBGCCJIT_ABI_7,LIBGCCJIT_ABI_8,LIBGCCJIT_ABI_6,ABI symbol tags
@anchor{topics/compatibility id8}@anchor{147}@anchor{topics/compatibility libgccjit-abi-7}@anchor{85}
@subsubsection @code{LIBGCCJIT_ABI_7}
@code{LIBGCCJIT_ABI_7} covers the addition of
@ref{84,,gcc_jit_type_get_aligned()}
@node LIBGCCJIT_ABI_8,LIBGCCJIT_ABI_9,LIBGCCJIT_ABI_7,ABI symbol tags
@anchor{topics/compatibility id9}@anchor{148}@anchor{topics/compatibility libgccjit-abi-8}@anchor{88}
@subsubsection @code{LIBGCCJIT_ABI_8}
@code{LIBGCCJIT_ABI_8} covers the addition of
@ref{87,,gcc_jit_type_get_vector()}
@node LIBGCCJIT_ABI_9,LIBGCCJIT_ABI_10,LIBGCCJIT_ABI_8,ABI symbol tags
@anchor{topics/compatibility id10}@anchor{149}@anchor{topics/compatibility libgccjit-abi-9}@anchor{123}
@subsubsection @code{LIBGCCJIT_ABI_9}
@code{LIBGCCJIT_ABI_9} covers the addition of
@ref{dd,,gcc_jit_function_get_address()}
@node LIBGCCJIT_ABI_10,LIBGCCJIT_ABI_11,LIBGCCJIT_ABI_9,ABI symbol tags
@anchor{topics/compatibility id11}@anchor{14a}@anchor{topics/compatibility libgccjit-abi-10}@anchor{bd}
@subsubsection @code{LIBGCCJIT_ABI_10}
@code{LIBGCCJIT_ABI_10} covers the addition of
@ref{89,,gcc_jit_context_new_rvalue_from_vector()}
@node LIBGCCJIT_ABI_11,LIBGCCJIT_ABI_12,LIBGCCJIT_ABI_10,ABI symbol tags
@anchor{topics/compatibility id12}@anchor{14b}@anchor{topics/compatibility libgccjit-abi-11}@anchor{77}
@subsubsection @code{LIBGCCJIT_ABI_11}
@code{LIBGCCJIT_ABI_11} covers the addition of
@ref{76,,gcc_jit_context_add_driver_option()}
@node LIBGCCJIT_ABI_12,LIBGCCJIT_ABI_13,LIBGCCJIT_ABI_11,ABI symbol tags
@anchor{topics/compatibility id13}@anchor{14c}@anchor{topics/compatibility libgccjit-abi-12}@anchor{8f}
@subsubsection @code{LIBGCCJIT_ABI_12}
@code{LIBGCCJIT_ABI_12} covers the addition of
@ref{8e,,gcc_jit_context_new_bitfield()}
@node LIBGCCJIT_ABI_13,LIBGCCJIT_ABI_14,LIBGCCJIT_ABI_12,ABI symbol tags
@anchor{topics/compatibility id14}@anchor{14d}@anchor{topics/compatibility libgccjit-abi-13}@anchor{14e}
@subsubsection @code{LIBGCCJIT_ABI_13}
@code{LIBGCCJIT_ABI_13} covers the addition of version functions via API
entrypoints:
@quotation
@itemize *
@item
@ref{133,,gcc_jit_version_major()}
@item
@ref{134,,gcc_jit_version_minor()}
@item
@ref{135,,gcc_jit_version_patchlevel()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_14,LIBGCCJIT_ABI_15,LIBGCCJIT_ABI_13,ABI symbol tags
@anchor{topics/compatibility id15}@anchor{14f}@anchor{topics/compatibility libgccjit-abi-14}@anchor{fc}
@subsubsection @code{LIBGCCJIT_ABI_14}
@code{LIBGCCJIT_ABI_14} covers the addition of
@ref{fb,,gcc_jit_global_set_initializer()}
@node LIBGCCJIT_ABI_15,LIBGCCJIT_ABI_16,LIBGCCJIT_ABI_14,ABI symbol tags
@anchor{topics/compatibility id16}@anchor{150}@anchor{topics/compatibility libgccjit-abi-15}@anchor{151}
@subsubsection @code{LIBGCCJIT_ABI_15}
@code{LIBGCCJIT_ABI_15} covers the addition of API entrypoints for directly
embedding assembler instructions:
@quotation
@itemize *
@item
@ref{152,,gcc_jit_block_add_extended_asm()}
@item
@ref{153,,gcc_jit_block_end_with_extended_asm_goto()}
@item
@ref{154,,gcc_jit_extended_asm_as_object()}
@item
@ref{155,,gcc_jit_extended_asm_set_volatile_flag()}
@item
@ref{156,,gcc_jit_extended_asm_set_inline_flag()}
@item
@ref{157,,gcc_jit_extended_asm_add_output_operand()}
@item
@ref{158,,gcc_jit_extended_asm_add_input_operand()}
@item
@ref{159,,gcc_jit_extended_asm_add_clobber()}
@item
@ref{15a,,gcc_jit_context_add_top_level_asm()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_16,LIBGCCJIT_ABI_17,LIBGCCJIT_ABI_15,ABI symbol tags
@anchor{topics/compatibility id17}@anchor{15b}@anchor{topics/compatibility libgccjit-abi-16}@anchor{a8}
@subsubsection @code{LIBGCCJIT_ABI_16}
@code{LIBGCCJIT_ABI_16} covers the addition of reflection functions via API
entrypoints:
@quotation
@itemize *
@item
@ref{112,,gcc_jit_function_get_return_type()}
@item
@ref{111,,gcc_jit_function_get_param_count()}
@item
@ref{99,,gcc_jit_type_dyncast_array()}
@item
@ref{9a,,gcc_jit_type_is_bool()}
@item
@ref{9f,,gcc_jit_type_is_integral()}
@item
@ref{a0,,gcc_jit_type_is_pointer()}
@item
@ref{a2,,gcc_jit_type_is_struct()}
@item
@ref{a1,,gcc_jit_type_dyncast_vector()}
@item
@ref{a5,,gcc_jit_type_unqualified()}
@item
@ref{9b,,gcc_jit_type_dyncast_function_ptr_type()}
@item
@ref{9c,,gcc_jit_function_type_get_return_type()}
@item
@ref{9d,,gcc_jit_function_type_get_param_count()}
@item
@ref{9e,,gcc_jit_function_type_get_param_type()}
@item
@ref{a3,,gcc_jit_vector_type_get_num_units()}
@item
@ref{a4,,gcc_jit_vector_type_get_element_type()}
@item
@ref{a6,,gcc_jit_struct_get_field()}
@item
@ref{a7,,gcc_jit_struct_get_field_count()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_17,LIBGCCJIT_ABI_18,LIBGCCJIT_ABI_16,ABI symbol tags
@anchor{topics/compatibility id18}@anchor{15c}@anchor{topics/compatibility libgccjit-abi-17}@anchor{ed}
@subsubsection @code{LIBGCCJIT_ABI_17}
@code{LIBGCCJIT_ABI_17} covers the addition of an API entrypoint to set the
thread-local storage model of a variable:
@quotation
@itemize *
@item
@ref{e6,,gcc_jit_lvalue_set_tls_model()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_18,LIBGCCJIT_ABI_19,LIBGCCJIT_ABI_17,ABI symbol tags
@anchor{topics/compatibility id19}@anchor{15d}@anchor{topics/compatibility libgccjit-abi-18}@anchor{ef}
@subsubsection @code{LIBGCCJIT_ABI_18}
@code{LIBGCCJIT_ABI_18} covers the addition of an API entrypoint to set the link
section of a variable:
@quotation
@itemize *
@item
@ref{ee,,gcc_jit_lvalue_set_link_section()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_19,LIBGCCJIT_ABI_20,LIBGCCJIT_ABI_18,ABI symbol tags
@anchor{topics/compatibility id20}@anchor{15e}@anchor{topics/compatibility libgccjit-abi-19}@anchor{b8}
@subsubsection @code{LIBGCCJIT_ABI_19}
@code{LIBGCCJIT_ABI_19} covers the addition of API entrypoints to set the initial value
of a global with an rvalue and to use constructors:
@quotation
@itemize *
@item
@ref{b9,,gcc_jit_context_new_array_constructor()}
@item
@ref{ba,,gcc_jit_context_new_struct_constructor()}
@item
@ref{bb,,gcc_jit_context_new_union_constructor()}
@item
@ref{b7,,gcc_jit_global_set_initializer_rvalue()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_20,LIBGCCJIT_ABI_21,LIBGCCJIT_ABI_19,ABI symbol tags
@anchor{topics/compatibility id21}@anchor{15f}@anchor{topics/compatibility libgccjit-abi-20}@anchor{ab}
@subsubsection @code{LIBGCCJIT_ABI_20}
@code{LIBGCCJIT_ABI_20} covers the addition of sized integer types, including
128-bit integers and helper functions for types:
@quotation
@itemize *
@item
@ref{aa,,gcc_jit_compatible_types()}
@item
@ref{ac,,gcc_jit_type_get_size()}
@item
@code{GCC_JIT_TYPE_UINT8_T}
@item
@code{GCC_JIT_TYPE_UINT16_T}
@item
@code{GCC_JIT_TYPE_UINT32_T}
@item
@code{GCC_JIT_TYPE_UINT64_T}
@item
@code{GCC_JIT_TYPE_UINT128_T}
@item
@code{GCC_JIT_TYPE_INT8_T}
@item
@code{GCC_JIT_TYPE_INT16_T}
@item
@code{GCC_JIT_TYPE_INT32_T}
@item
@code{GCC_JIT_TYPE_INT64_T}
@item
@code{GCC_JIT_TYPE_INT128_T}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_21,LIBGCCJIT_ABI_22,LIBGCCJIT_ABI_20,ABI symbol tags
@anchor{topics/compatibility id22}@anchor{160}@anchor{topics/compatibility libgccjit-abi-21}@anchor{e1}
@subsubsection @code{LIBGCCJIT_ABI_21}
@code{LIBGCCJIT_ABI_21} covers the addition of an API entrypoint to bitcast a
value from one type to another:
@quotation
@itemize *
@item
@ref{e0,,gcc_jit_context_new_bitcast()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_22,LIBGCCJIT_ABI_23,LIBGCCJIT_ABI_21,ABI symbol tags
@anchor{topics/compatibility id23}@anchor{161}@anchor{topics/compatibility libgccjit-abi-22}@anchor{f0}
@subsubsection @code{LIBGCCJIT_ABI_22}
@code{LIBGCCJIT_ABI_22} covers the addition of an API entrypoint to set the
register name of a variable:
@quotation
@itemize *
@item
@code{gcc_jit_lvalue_set_register_name()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_23,LIBGCCJIT_ABI_24,LIBGCCJIT_ABI_22,ABI symbol tags
@anchor{topics/compatibility id24}@anchor{162}@anchor{topics/compatibility libgccjit-abi-23}@anchor{70}
@subsubsection @code{LIBGCCJIT_ABI_23}
@code{LIBGCCJIT_ABI_23} covers the addition of an API entrypoint to hide stderr
logs:
@quotation
@itemize *
@item
@ref{6f,,gcc_jit_context_set_bool_print_errors_to_stderr()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_24,,LIBGCCJIT_ABI_23,ABI symbol tags
@anchor{topics/compatibility id25}@anchor{163}@anchor{topics/compatibility libgccjit-abi-24}@anchor{f2}
@subsubsection @code{LIBGCCJIT_ABI_24}
@code{LIBGCCJIT_ABI_24} covers the addition of functions to get and set the
alignment of a variable:
@quotation
@itemize *
@item
@ref{f1,,gcc_jit_lvalue_set_alignment()}
@item
@ref{f3,,gcc_jit_lvalue_get_alignment()}
@end itemize
@end quotation
@c Copyright (C) 2015-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Performance,Using Assembly Language with libgccjit,ABI and API compatibility,Topic Reference
@anchor{topics/performance doc}@anchor{164}@anchor{topics/performance performance}@anchor{165}
@section Performance
@menu
* The timing API::
@end menu
@node The timing API,,,Performance
@anchor{topics/performance the-timing-api}@anchor{166}
@subsection The timing API
As of GCC 6, libgccjit exposes a timing API, for printing reports on
how long was spent in different parts of code.
You can create a @ref{167,,gcc_jit_timer} instance, which will
measure time spent since its creation. The timer maintains a stack
of “timer items”: as control flow moves through your code, you can push
and pop named items relating to your code onto the stack, and the timer
will account the time spent accordingly.
You can also asssociate a timer with a @ref{8,,gcc_jit_context}, in
which case the time spent inside compilation will be subdivided.
For example, the following code uses a timer, recording client items
“create_code”, “compile”, and “running code”:
@example
/* Create a timer. */
gcc_jit_timer *timer = gcc_jit_timer_new ();
if (!timer)
@{
error ("gcc_jit_timer_new failed");
return -1;
@}
/* Let's repeatedly compile and run some code, accumulating it
all into the timer. */
for (int i = 0; i < num_iterations; i++)
@{
/* Create a context and associate it with the timer. */
gcc_jit_context *ctxt = gcc_jit_context_acquire ();
if (!ctxt)
@{
error ("gcc_jit_context_acquire failed");
return -1;
@}
gcc_jit_context_set_timer (ctxt, timer);
/* Populate the context, timing it as client item "create_code". */
gcc_jit_timer_push (timer, "create_code");
create_code (ctxt);
gcc_jit_timer_pop (timer, "create_code");
/* Compile the context, timing it as client item "compile". */
gcc_jit_timer_push (timer, "compile");
result = gcc_jit_context_compile (ctxt);
gcc_jit_timer_pop (timer, "compile");
/* Run the generated code, timing it as client item "running code". */
gcc_jit_timer_push (timer, "running code");
run_the_code (ctxt, result);
gcc_jit_timer_pop (timer, "running code");
/* Clean up. */
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
@}
/* Print the accumulated timings. */
gcc_jit_timer_print (timer, stderr);
gcc_jit_timer_release (timer);
@end example
giving output like this, showing the internal GCC items at the top, then
client items, then the total:
@example
Execution times (seconds)
GCC items:
phase setup : 0.29 (14%) usr 0.00 ( 0%) sys 0.32 ( 5%) wall 10661 kB (50%) ggc
phase parsing : 0.02 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 653 kB ( 3%) ggc
phase finalize : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
dump files : 0.02 ( 1%) usr 0.00 ( 0%) sys 0.01 ( 0%) wall 0 kB ( 0%) ggc
callgraph construction : 0.02 ( 1%) usr 0.01 ( 6%) sys 0.01 ( 0%) wall 242 kB ( 1%) ggc
callgraph optimization : 0.03 ( 2%) usr 0.00 ( 0%) sys 0.02 ( 0%) wall 142 kB ( 1%) ggc
trivially dead code : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
df scan insns : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 9 kB ( 0%) ggc
df live regs : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.01 ( 0%) wall 0 kB ( 0%) ggc
inline parameters : 0.02 ( 1%) usr 0.00 ( 0%) sys 0.01 ( 0%) wall 82 kB ( 0%) ggc
tree CFG cleanup : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
tree PHI insertion : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.02 ( 0%) wall 64 kB ( 0%) ggc
tree SSA other : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.01 ( 0%) wall 18 kB ( 0%) ggc
expand : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 398 kB ( 2%) ggc
jump : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
loop init : 0.01 ( 0%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 67 kB ( 0%) ggc
integrated RA : 0.02 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 2468 kB (12%) ggc
thread pro- & epilogue : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 162 kB ( 1%) ggc
final : 0.01 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 216 kB ( 1%) ggc
rest of compilation : 1.37 (69%) usr 0.00 ( 0%) sys 1.13 (18%) wall 1391 kB ( 6%) ggc
assemble JIT code : 0.01 ( 1%) usr 0.00 ( 0%) sys 4.04 (66%) wall 0 kB ( 0%) ggc
load JIT result : 0.02 ( 1%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
JIT client code : 0.00 ( 0%) usr 0.01 ( 6%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
Client items:
create_code : 0.00 ( 0%) usr 0.01 ( 6%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
compile : 0.36 (18%) usr 0.15 (83%) sys 0.86 (14%) wall 14939 kB (70%) ggc
running code : 0.00 ( 0%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 0 kB ( 0%) ggc
TOTAL : 2.00 0.18 6.12 21444 kB
@end example
The exact format is intended to be human-readable, and is subject to change.
@geindex LIBGCCJIT_HAVE_TIMING_API (C macro)
@anchor{topics/performance c LIBGCCJIT_HAVE_TIMING_API}@anchor{168}
@deffn {C Macro} LIBGCCJIT_HAVE_TIMING_API
The timer API was added to libgccjit in GCC 6.
This macro is only defined in versions of libgccjit.h which have the
timer API, and so can be used to guard code that may need to compile
against earlier releases:
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
gcc_jit_timer *t = gcc_jit_timer_new ();
gcc_jit_context_set_timer (ctxt, t);
#endif
@end example
@end deffn
@geindex gcc_jit_timer (C type)
@anchor{topics/performance c gcc_jit_timer}@anchor{167}
@deffn {C Type} gcc_jit_timer
@end deffn
@geindex gcc_jit_timer_new (C function)
@anchor{topics/performance c gcc_jit_timer_new}@anchor{140}
@deffn {C Function} gcc_jit_timer * gcc_jit_timer_new (void)
Create a @ref{167,,gcc_jit_timer} instance, and start timing:
@example
gcc_jit_timer *t = gcc_jit_timer_new ();
@end example
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@geindex gcc_jit_timer_release (C function)
@anchor{topics/performance c gcc_jit_timer_release}@anchor{141}
@deffn {C Function} void gcc_jit_timer_release (gcc_jit_timer@w{ }*timer)
Release a @ref{167,,gcc_jit_timer} instance:
@example
gcc_jit_timer_release (t);
@end example
This should be called exactly once on a timer.
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@geindex gcc_jit_context_set_timer (C function)
@anchor{topics/performance c gcc_jit_context_set_timer}@anchor{13f}
@deffn {C Function} void gcc_jit_context_set_timer (gcc_jit_context@w{ }*ctxt, gcc_jit_timer@w{ }*timer)
Associate a @ref{167,,gcc_jit_timer} instance with a context:
@example
gcc_jit_context_set_timer (ctxt, t);
@end example
A timer instance can be shared between multiple
@ref{8,,gcc_jit_context} instances.
Timers have no locking, so if you have a multithreaded program, you
must provide your own locks if more than one thread could be working
with the same timer via timer-associated contexts.
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@geindex gcc_jit_context_get_timer (C function)
@anchor{topics/performance c gcc_jit_context_get_timer}@anchor{13e}
@deffn {C Function} gcc_jit_timer *gcc_jit_context_get_timer (gcc_jit_context@w{ }*ctxt)
Get the timer associated with a context (if any).
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@geindex gcc_jit_timer_push (C function)
@anchor{topics/performance c gcc_jit_timer_push}@anchor{142}
@deffn {C Function} void gcc_jit_timer_push (gcc_jit_timer@w{ }*timer, const char@w{ }*item_name)
Push the given item onto the timer’s stack:
@example
gcc_jit_timer_push (t, "running code");
run_the_code (ctxt, result);
gcc_jit_timer_pop (t, "running code");
@end example
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@geindex gcc_jit_timer_pop (C function)
@anchor{topics/performance c gcc_jit_timer_pop}@anchor{143}
@deffn {C Function} void gcc_jit_timer_pop (gcc_jit_timer@w{ }*timer, const char@w{ }*item_name)
Pop the top item from the timer’s stack.
If “item_name” is provided, it must match that of the top item.
Alternatively, @code{NULL} can be passed in, to suppress checking.
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@geindex gcc_jit_timer_print (C function)
@anchor{topics/performance c gcc_jit_timer_print}@anchor{144}
@deffn {C Function} void gcc_jit_timer_print (gcc_jit_timer@w{ }*timer, FILE@w{ }*f_out)
Print timing information to the given stream about activity since
the timer was started.
This API entrypoint was added in @ref{13d,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
#ifdef LIBGCCJIT_HAVE_TIMING_API
@end example
@end deffn
@c Copyright (C) 2020-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Using Assembly Language with libgccjit,,Performance,Topic Reference
@anchor{topics/asm doc}@anchor{169}@anchor{topics/asm using-assembly-language-with-libgccjit}@anchor{16a}
@section Using Assembly Language with libgccjit
libgccjit has some support for directly embedding assembler instructions.
This is based on GCC’s support for inline @code{asm} in C code, and the
following assumes a familiarity with that functionality. See
How to Use Inline Assembly Language in C Code@footnote{https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html}
in GCC’s documentation, the “Extended Asm” section in particular.
These entrypoints were added in @ref{151,,LIBGCCJIT_ABI_15}; you can test
for their presence using
@quotation
@example
#ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS
@end example
@end quotation
@menu
* Adding assembler instructions within a function::
* Adding top-level assembler statements::
@end menu
@node Adding assembler instructions within a function,Adding top-level assembler statements,,Using Assembly Language with libgccjit
@anchor{topics/asm adding-assembler-instructions-within-a-function}@anchor{16b}
@subsection Adding assembler instructions within a function
@geindex gcc_jit_extended_asm (C type)
@anchor{topics/asm c gcc_jit_extended_asm}@anchor{120}
@deffn {C Type} gcc_jit_extended_asm
A @cite{gcc_jit_extended_asm} represents an extended @code{asm} statement: a
series of low-level instructions inside a function that convert inputs
to outputs.
To avoid having an API entrypoint with a very large number of
parameters, an extended @code{asm} statement is made in stages:
an initial call to create the @ref{120,,gcc_jit_extended_asm},
followed by calls to add operands and set other properties of the
statement.
There are two API entrypoints for creating a @ref{120,,gcc_jit_extended_asm}:
@itemize *
@item
@ref{152,,gcc_jit_block_add_extended_asm()} for an @code{asm} statement with
no control flow, and
@item
@ref{153,,gcc_jit_block_end_with_extended_asm_goto()} for an @code{asm goto}.
@end itemize
For example, to create the equivalent of:
@example
asm ("mov %1, %0\n\t"
"add $1, %0"
: "=r" (dst)
: "r" (src));
@end example
the following API calls could be used:
@example
gcc_jit_extended_asm *ext_asm
= gcc_jit_block_add_extended_asm (block, NULL,
"mov %1, %0\n\t"
"add $1, %0");
gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst);
gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
gcc_jit_lvalue_as_rvalue (src));
@end example
@cartouche
@quotation Warning
When considering the numbering of operands within an
extended @code{asm} statement (e.g. the @code{%0} and @code{%1}
above), the equivalent to the C syntax is followed i.e. all
output operands, then all input operands, regardless of
what order the calls to
@ref{157,,gcc_jit_extended_asm_add_output_operand()} and
@ref{158,,gcc_jit_extended_asm_add_input_operand()} were made in.
@end quotation
@end cartouche
As in the C syntax, operands can be given symbolic names to avoid having
to number them. For example, to create the equivalent of:
@example
asm ("bsfl %[aMask], %[aIndex]"
: [aIndex] "=r" (Index)
: [aMask] "r" (Mask)
: "cc");
@end example
the following API calls could be used:
@example
gcc_jit_extended_asm *ext_asm
= gcc_jit_block_add_extended_asm (block, NULL,
"bsfl %[aMask], %[aIndex]");
gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index);
gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r",
gcc_jit_param_as_rvalue (mask));
gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
@end example
@end deffn
@geindex gcc_jit_block_add_extended_asm (C function)
@anchor{topics/asm c gcc_jit_block_add_extended_asm}@anchor{152}
@deffn {C Function} gcc_jit_extended_asm * gcc_jit_block_add_extended_asm (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*asm_template)
Create a @ref{120,,gcc_jit_extended_asm} for an extended @code{asm} statement
with no control flow (i.e. without the @code{goto} qualifier).
The parameter @code{asm_template} corresponds to the @cite{AssemblerTemplate}
within C’s extended @code{asm} syntax. It must be non-NULL. The call takes
a copy of the underlying string, so it is valid to pass in a pointer to
an on-stack buffer.
@end deffn
@geindex gcc_jit_block_end_with_extended_asm_goto (C function)
@anchor{topics/asm c gcc_jit_block_end_with_extended_asm_goto}@anchor{153}
@deffn {C Function} gcc_jit_extended_asm * gcc_jit_block_end_with_extended_asm_goto (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*asm_template, int@w{ }num_goto_blocks, gcc_jit_block@w{ }**goto_blocks, gcc_jit_block@w{ }*fallthrough_block)
Create a @ref{120,,gcc_jit_extended_asm} for an extended @code{asm} statement
that may perform jumps, and use it to terminate the given block.
This is equivalent to the @code{goto} qualifier in C’s extended @code{asm}
syntax.
For example, to create the equivalent of:
@example
asm goto ("btl %1, %0\n\t"
"jc %l[carry]"
: // No outputs
: "r" (p1), "r" (p2)
: "cc"
: carry);
@end example
the following API calls could be used:
@example
const char *asm_template =
(use_name
? /* Label referred to by name: "%l[carry]". */
("btl %1, %0\n\t"
"jc %l[carry]")
: /* Label referred to numerically: "%l2". */
("btl %1, %0\n\t"
"jc %l2"));
gcc_jit_extended_asm *ext_asm
= gcc_jit_block_end_with_extended_asm_goto (b_start, NULL,
asm_template,
1, &b_carry,
b_fallthru);
gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
gcc_jit_param_as_rvalue (p1));
gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
gcc_jit_param_as_rvalue (p2));
gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
@end example
here referencing a @ref{28,,gcc_jit_block} named “carry”.
@code{num_goto_blocks} must be >= 0.
@code{goto_blocks} must be non-NULL. This corresponds to the @code{GotoLabels}
parameter within C’s extended @code{asm} syntax. The block names can be
referenced within the assembler template.
@code{fallthrough_block} can be NULL. If non-NULL, it specifies the block
to fall through to after the statement.
@cartouche
@quotation Note
This is needed since each @ref{28,,gcc_jit_block} must have a
single exit point, as a basic block: you can’t jump from the
middle of a block. A “goto” is implicitly added after the
asm to handle the fallthrough case, which is equivalent to what
would have happened in the C case.
@end quotation
@end cartouche
@end deffn
@geindex gcc_jit_extended_asm_set_volatile_flag (C function)
@anchor{topics/asm c gcc_jit_extended_asm_set_volatile_flag}@anchor{155}
@deffn {C Function} void gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm@w{ }*ext_asm, int@w{ }flag)
Set whether the @ref{120,,gcc_jit_extended_asm} has side-effects, equivalent to the
volatile@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile}
qualifier in C’s extended asm syntax.
For example, to create the equivalent of:
@example
asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX.
"shl $32, %%rdx\n\t" // Shift the upper bits left.
"or %%rdx, %0" // 'Or' in the lower bits.
: "=a" (msr)
:
: "rdx");
@end example
the following API calls could be used:
@example
gcc_jit_extended_asm *ext_asm
= gcc_jit_block_add_extended_asm
(block, NULL,
"rdtsc\n\t" /* Returns the time in EDX:EAX. */
"shl $32, %%rdx\n\t" /* Shift the upper bits left. */
"or %%rdx, %0"); /* 'Or' in the lower bits. */
gcc_jit_extended_asm_set_volatile_flag (ext_asm, 1);
gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=a", msr);
gcc_jit_extended_asm_add_clobber (ext_asm, "rdx");
@end example
where the @ref{120,,gcc_jit_extended_asm} is flagged as volatile.
@end deffn
@geindex gcc_jit_extended_asm_set_inline_flag (C function)
@anchor{topics/asm c gcc_jit_extended_asm_set_inline_flag}@anchor{156}
@deffn {C Function} void gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm@w{ }*ext_asm, int@w{ }flag)
Set the equivalent of the
inline@footnote{https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html#Size-of-an-asm}
qualifier in C’s extended @code{asm} syntax.
@end deffn
@geindex gcc_jit_extended_asm_add_output_operand (C function)
@anchor{topics/asm c gcc_jit_extended_asm_add_output_operand}@anchor{157}
@deffn {C Function} void gcc_jit_extended_asm_add_output_operand (gcc_jit_extended_asm@w{ }*ext_asm, const char@w{ }*asm_symbolic_name, const char@w{ }*constraint, gcc_jit_lvalue@w{ }*dest)
Add an output operand to the extended @code{asm} statement. See the
Output Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands}
section of the documentation of the C syntax.
@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component of C’s
extended @code{asm} syntax. It can be NULL. If non-NULL it specifies the
symbolic name for the operand.
@code{constraint} corresponds to the @code{constraint} component of C’s extended
@code{asm} syntax. It must be non-NULL.
@code{dest} corresponds to the @code{cvariablename} component of C’s extended
@code{asm} syntax. It must be non-NULL.
@example
// Example with a NULL symbolic name, the equivalent of:
// : "=r" (dst)
gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst);
// Example with a symbolic name ("aIndex"), the equivalent of:
// : [aIndex] "=r" (index)
gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index);
@end example
This function can’t be called on an @code{asm goto} as such instructions can’t
have outputs; see the
Goto Labels@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels}
section of GCC’s “Extended Asm” documentation.
@end deffn
@geindex gcc_jit_extended_asm_add_input_operand (C function)
@anchor{topics/asm c gcc_jit_extended_asm_add_input_operand}@anchor{158}
@deffn {C Function} void gcc_jit_extended_asm_add_input_operand (gcc_jit_extended_asm@w{ }*ext_asm, const char@w{ }*asm_symbolic_name, const char@w{ }*constraint, gcc_jit_rvalue@w{ }*src)
Add an input operand to the extended @code{asm} statement. See the
Input Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands}
section of the documentation of the C syntax.
@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component of C’s
extended @code{asm} syntax. It can be NULL. If non-NULL it specifies the
symbolic name for the operand.
@code{constraint} corresponds to the @code{constraint} component of C’s extended
@code{asm} syntax. It must be non-NULL.
@code{src} corresponds to the @code{cexpression} component of C’s extended
@code{asm} syntax. It must be non-NULL.
@example
// Example with a NULL symbolic name, the equivalent of:
// : "r" (src)
gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
gcc_jit_lvalue_as_rvalue (src));
// Example with a symbolic name ("aMask"), the equivalent of:
// : [aMask] "r" (Mask)
gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r",
gcc_jit_lvalue_as_rvalue (mask));
@end example
@end deffn
@geindex gcc_jit_extended_asm_add_clobber (C function)
@anchor{topics/asm c gcc_jit_extended_asm_add_clobber}@anchor{159}
@deffn {C Function} void gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm@w{ }*ext_asm, const char@w{ }*victim)
Add @cite{victim} to the list of registers clobbered by the extended @code{asm}
statement. It must be non-NULL. See the
Clobbers and Scratch Registers@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers#}
section of the documentation of the C syntax.
Statements with multiple clobbers will require multiple calls, one per
clobber.
For example:
@example
gcc_jit_extended_asm_add_clobber (ext_asm, "r0");
gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
gcc_jit_extended_asm_add_clobber (ext_asm, "memory");
@end example
@end deffn
A @ref{120,,gcc_jit_extended_asm} is a @ref{e,,gcc_jit_object} “owned” by
the block’s context. The following upcast is available:
@geindex gcc_jit_extended_asm_as_object (C function)
@anchor{topics/asm c gcc_jit_extended_asm_as_object}@anchor{154}
@deffn {C Function} gcc_jit_object * gcc_jit_extended_asm_as_object (gcc_jit_extended_asm@w{ }*ext_asm)
Upcast from extended @code{asm} to object.
@end deffn
@node Adding top-level assembler statements,,Adding assembler instructions within a function,Using Assembly Language with libgccjit
@anchor{topics/asm adding-top-level-assembler-statements}@anchor{16c}
@subsection Adding top-level assembler statements
In addition to creating extended @code{asm} instructions within a function,
there is support for creating “top-level” assembler statements, outside
of any function.
@geindex gcc_jit_context_add_top_level_asm (C function)
@anchor{topics/asm c gcc_jit_context_add_top_level_asm}@anchor{15a}
@deffn {C Function} void gcc_jit_context_add_top_level_asm (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*asm_stmts)
Create a set of top-level asm statements, analogous to those created
by GCC’s “basic” @code{asm} syntax in C at file scope.
For example, to create the equivalent of:
@example
asm ("\t.pushsection .text\n"
"\t.globl add_asm\n"
"\t.type add_asm, @@function\n"
"add_asm:\n"
"\tmovq %rdi, %rax\n"
"\tadd %rsi, %rax\n"
"\tret\n"
"\t.popsection\n");
@end example
the following API calls could be used:
@example
gcc_jit_context_add_top_level_asm (ctxt, NULL,
"\t.pushsection .text\n"
"\t.globl add_asm\n"
"\t.type add_asm, @@function\n"
"add_asm:\n"
"\tmovq %rdi, %rax\n"
"\tadd %rsi, %rax\n"
"\tret\n"
"\t# some asm here\n"
"\t.popsection\n");
@end example
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node C++ bindings for libgccjit,Internals,Topic Reference,Top
@anchor{cp/index doc}@anchor{16d}@anchor{cp/index c-bindings-for-libgccjit}@anchor{16e}
@chapter C++ bindings for libgccjit
This document describes the C++ bindings to
libgccjit@footnote{https://gcc.gnu.org/wiki/JIT}, an API for embedding GCC
inside programs and libraries.
The C++ bindings consist of a single header file @code{libgccjit++.h}.
This is a collection of “thin” wrapper classes around the C API.
Everything is an inline function, implemented in terms of the C API,
so there is nothing extra to link against.
Contents:
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@menu
* Tutorial: Tutorial<2>.
* Topic Reference: Topic Reference<2>.
@end menu
@node Tutorial<2>,Topic Reference<2>,,C++ bindings for libgccjit
@anchor{cp/intro/index doc}@anchor{16f}@anchor{cp/intro/index tutorial}@anchor{170}
@section Tutorial
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@menu
* 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>.
@end menu
@node Tutorial part 1 “Hello world”<2>,Tutorial part 2 Creating a trivial machine code function<2>,,Tutorial<2>
@anchor{cp/intro/tutorial01 doc}@anchor{171}@anchor{cp/intro/tutorial01 tutorial-part-1-hello-world}@anchor{172}
@subsection 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’s C++ API to
synthesize a call to @cite{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.
@quotation
@example
/* Smoketest example for libgccjit.so C++ API
Copyright (C) 2014-2022 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 (gccjit::context ctxt)
@{
/* Let's try to inject the equivalent of this C code:
void
greet (const char *name)
@{
printf ("hello %s\n", name);
@}
*/
gccjit::type void_type = ctxt.get_type (GCC_JIT_TYPE_VOID);
gccjit::type const_char_ptr_type =
ctxt.get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
gccjit::param param_name =
ctxt.new_param (const_char_ptr_type, "name");
std::vector<gccjit::param> func_params;
func_params.push_back (param_name);
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
void_type,
"greet",
func_params, 0);
gccjit::param param_format =
ctxt.new_param (const_char_ptr_type, "format");
std::vector<gccjit::param> printf_params;
printf_params.push_back (param_format);
gccjit::function printf_func =
ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
ctxt.get_type (GCC_JIT_TYPE_INT),
"printf",
printf_params, 1);
gccjit::block block = func.new_block ();
block.add_eval (ctxt.new_call (printf_func,
ctxt.new_rvalue ("hello %s\n"),
param_name));
block.end_with_return ();
@}
int
main (int argc, char **argv)
@{
gccjit::context ctxt;
gcc_jit_result *result;
/* Get a "context" object for working with the library. */
ctxt = gccjit::context::acquire ();
/* Set some options on the context.
Turn this on to see the code being generated, in assembler form. */
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = ctxt.compile ();
if (!result)
@{
fprintf (stderr, "NULL result");
exit (1);
@}
ctxt.release ();
/* 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_result_release (result);
return 0;
@}
@end example
@end quotation
Copy the above to @cite{tut01-hello-world.cc}.
Assuming you have the jit library installed, build the test program
using:
@example
$ gcc \
tut01-hello-world.cc \
-o tut01-hello-world \
-lgccjit
@end example
You should then be able to run the built program:
@example
$ ./tut01-hello-world
hello world
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 2 Creating a trivial machine code function<2>,Tutorial part 3 Loops and variables<2>,Tutorial part 1 “Hello world”<2>,Tutorial<2>
@anchor{cp/intro/tutorial02 doc}@anchor{173}@anchor{cp/intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{174}
@subsection Tutorial part 2: Creating a trivial machine code function
Consider this C function:
@example
int square (int i)
@{
return i * i;
@}
@end example
How can we construct this at run-time using libgccjit’s C++ API?
First we need to include the relevant header:
@example
#include <libgccjit++.h>
@end example
All state associated with compilation is associated with a
@ref{175,,gccjit;;context}, which is a thin C++ wrapper around the C API’s
@ref{8,,gcc_jit_context *}.
Create one using @ref{176,,gccjit;;context;;acquire()}:
@example
gccjit::context ctxt;
ctxt = gccjit::context::acquire ();
@end example
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 @cite{int} type, so let’s obtain this from
the context, as a @ref{177,,gccjit;;type}, using
@ref{178,,gccjit;;context;;get_type()}:
@example
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
@end example
@ref{177,,gccjit;;type} is an example of a “contextual” object: every
entity in the API is associated with a @ref{175,,gccjit;;context}.
Memory management is easy: all such “contextual” objects are automatically
cleaned up for you when the context is released, using
@ref{179,,gccjit;;context;;release()}:
@example
ctxt.release ();
@end example
so you don’t need to manually track and cleanup all objects, just the
contexts.
All of the C++ classes in the API are thin wrappers around pointers to
types in the C API.
The C++ class hierarchy within the @code{gccjit} namespace looks like this:
@example
+- object
+- location
+- type
+- struct
+- field
+- function
+- block
+- rvalue
+- lvalue
+- param
@end example
One thing you can do with a @ref{17a,,gccjit;;object} is
to ask it for a human-readable description as a @code{std::string}, using
@ref{17b,,gccjit;;object;;get_debug_string()}:
@example
printf ("obj: %s\n", obj.get_debug_string ().c_str ());
@end example
giving this text on stdout:
@example
obj: int
@end example
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 @ref{17c,,gccjit;;context;;new_param()}:
@example
gccjit::param param_i = ctxt.new_param (int_type, "i");
@end example
and we can then make a vector of all of the params of the function,
in this case just one:
@example
std::vector<gccjit::param> params;
params.push_back (param_i);
@end example
Now we can create the function, using
@code{gccjit::context::new_function()}:
@example
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
params,
0);
@end example
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:
@example
gccjit::block block = func.new_block ();
@end example
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
We can build the expression using @ref{17d,,gccjit;;context;;new_binary_op()}:
@example
gccjit::rvalue expr =
ctxt.new_binary_op (
GCC_JIT_BINARY_OP_MULT, int_type,
param_i, param_i);
@end example
A @ref{17e,,gccjit;;rvalue} is another example of a
@ref{17a,,gccjit;;object} subclass. As before, we can print it with
@ref{17b,,gccjit;;object;;get_debug_string()}.
@example
printf ("expr: %s\n", expr.get_debug_string ().c_str ());
@end example
giving this output:
@example
expr: i * i
@end example
Note that @ref{17e,,gccjit;;rvalue} provides numerous overloaded operators
which can be used to dramatically reduce the amount of typing needed.
We can build the above binary operation more directly with this one-liner:
@example
gccjit::rvalue expr = param_i * param_i;
@end example
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:
@example
block.end_with_return (expr);
@end example
OK, we’ve populated the context. We can now compile it using
@ref{17f,,gccjit;;context;;compile()}:
@example
gcc_jit_result *result;
result = ctxt.compile ();
@end example
and get a @ref{16,,gcc_jit_result *}.
We can now use @ref{17,,gcc_jit_result_get_code()} to look up a specific
machine code routine within the result, in this case, the function we
created above.
@example
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
@{
fprintf (stderr, "NULL fn_ptr");
goto error;
@}
@end example
We can now cast the pointer to an appropriate function pointer type, and
then call it:
@example
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d", square (5));
@end example
@example
result: 25
@end example
@menu
* Options: Options<3>.
* Full example: Full example<3>.
@end menu
@node Options<3>,Full example<3>,,Tutorial part 2 Creating a trivial machine code function<2>
@anchor{cp/intro/tutorial02 options}@anchor{180}
@subsubsection Options
To get more information on what’s going on, you can set debugging flags
on the context using @ref{181,,gccjit;;context;;set_bool_option()}.
@c (I'm deliberately not mentioning
@c :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
@c it's probably more of use to implementors than to users)
Setting @ref{1c,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE} will dump a
C-like representation to stderr when you compile (GCC’s “GIMPLE”
representation):
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
result = ctxt.compile ();
@end example
@example
square (signed int i)
@{
signed int D.260;
entry:
D.260 = i * i;
return D.260;
@}
@end example
We can see the generated machine code in assembler form (on stderr) by
setting @ref{1d,,GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE} on the context
before compiling:
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 1);
result = ctxt.compile ();
@end example
@example
.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
@end example
By default, no optimizations are performed, the equivalent of GCC’s
@cite{-O0} option. We can turn things up to e.g. @cite{-O3} by calling
@ref{182,,gccjit;;context;;set_int_option()} with
@ref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
@end example
@example
.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
@end example
Naturally this has only a small effect on such a trivial function.
@node Full example<3>,,Options<3>,Tutorial part 2 Creating a trivial machine code function<2>
@anchor{cp/intro/tutorial02 full-example}@anchor{183}
@subsubsection Full example
Here’s what the above looks like as a complete program:
@quotation
@example
/* Usage example for libgccjit.so's C++ API
Copyright (C) 2014-2022 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 (gccjit::context ctxt)
@{
/* Let's try to inject the equivalent of this C code:
int square (int i)
@{
return i * i;
@}
*/
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
gccjit::param param_i = ctxt.new_param (int_type, "i");
std::vector<gccjit::param> params;
params.push_back (param_i);
gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
params, 0);
gccjit::block block = func.new_block ();
gccjit::rvalue expr =
ctxt.new_binary_op (GCC_JIT_BINARY_OP_MULT, int_type,
param_i, param_i);
block.end_with_return (expr);
@}
int
main (int argc, char **argv)
@{
/* Get a "context" object for working with the library. */
gccjit::context ctxt = gccjit::context::acquire ();
/* Set some options on the context.
Turn this on to see the code being generated, in assembler form. */
ctxt.set_bool_option (
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
gcc_jit_result *result = ctxt.compile ();
/* We're done with the context; we can release it: */
ctxt.release ();
if (!result)
@{
fprintf (stderr, "NULL result");
return 1;
@}
/* Extract the generated code from "result". */
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
@{
fprintf (stderr, "NULL fn_ptr");
gcc_jit_result_release (result);
return 1;
@}
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d\n", square (5));
gcc_jit_result_release (result);
return 0;
@}
@end example
@end quotation
Building and running it:
@example
$ gcc \
tut02-square.cc \
-o tut02-square \
-lgccjit
# Run the built program:
$ ./tut02-square
result: 25
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 3 Loops and variables<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>,Tutorial part 2 Creating a trivial machine code function<2>,Tutorial<2>
@anchor{cp/intro/tutorial03 doc}@anchor{184}@anchor{cp/intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{185}
@subsection Tutorial part 3: Loops and variables
Consider this C function:
@quotation
@example
int loop_test (int n)
@{
int sum = 0;
for (int i = 0; i < n; i++)
sum += i * i;
return sum;
@}
@end example
@end quotation
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 @cite{for} loop as a @cite{while} loop, giving:
@quotation
@example
int loop_test (int n)
@{
int sum = 0;
int i = 0;
while (i < n)
@{
sum += i * i;
i++;
@}
return sum;
@}
@end example
@end quotation
Here’s what the final control flow graph will look like:
@quotation
@float Figure
@image{libgccjit-figures/sum-of-squares,,,image of a control flow graph,png}
@end float
@end quotation
As before, we include the libgccjit++ header and make a
@ref{175,,gccjit;;context}.
@example
#include <libgccjit++.h>
void test (void)
@{
gccjit::context ctxt;
ctxt = gccjit::context::acquire ();
@end example
The function works with the C @cite{int} type.
In the previous tutorial we acquired this via
@example
gccjit::type the_type = ctxt.get_type (ctxt, GCC_JIT_TYPE_INT);
@end example
though we could equally well make it work on, say, @cite{double}:
@example
gccjit::type the_type = ctxt.get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
@end example
For integer types we can use @code{gccjit::context::get_int_type}
to directly bind a specific type:
@example
gccjit::type the_type = ctxt.get_int_type <int> ();
@end example
Let’s build the function:
@example
gcc_jit_param n = ctxt.new_param (the_type, "n");
std::vector<gccjit::param> params;
params.push_back (n);
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
params, 0);
@end example
@menu
* 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>.
@end menu
@node Expressions lvalues and rvalues<2>,Control flow<2>,,Tutorial part 3 Loops and variables<2>
@anchor{cp/intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{186}
@subsubsection Expressions: lvalues and rvalues
The base class of expression is the @ref{17e,,gccjit;;rvalue},
representing an expression that can be on the @emph{right}-hand side of
an assignment: a value that can be computed somehow, and assigned
@emph{to} a storage area (such as a variable). It has a specific
@ref{177,,gccjit;;type}.
Anothe important class is @ref{187,,gccjit;;lvalue}.
A @ref{187,,gccjit;;lvalue}. is something that can of the @emph{left}-hand
side of an assignment: a storage area (such as a variable).
In other words, every assignment can be thought of as:
@example
LVALUE = RVALUE;
@end example
Note that @ref{187,,gccjit;;lvalue} is a subclass of
@ref{17e,,gccjit;;rvalue}, where in an assignment of the form:
@example
LVALUE_A = LVALUE_B;
@end example
the @cite{LVALUE_B} implies reading the current value of that storage
area, assigning it into the @cite{LVALUE_A}.
So far the only expressions we’ve seen are from the previous tutorial:
@enumerate
@item
the multiplication @cite{i * i}:
@end enumerate
@quotation
@example
gccjit::rvalue expr =
ctxt.new_binary_op (
GCC_JIT_BINARY_OP_MULT, int_type,
param_i, param_i);
/* Alternatively, using operator-overloading: */
gccjit::rvalue expr = param_i * param_i;
@end example
which is a @ref{17e,,gccjit;;rvalue}, and
@end quotation
@enumerate 2
@item
the various function parameters: @cite{param_i} and @cite{param_n}, instances of
@ref{188,,gccjit;;param}, which is a subclass of @ref{187,,gccjit;;lvalue}
(and, in turn, of @ref{17e,,gccjit;;rvalue}):
we can both read from and write to function parameters within the
body of a function.
@end enumerate
Our new example has a new kind of expression: we have two local
variables. We create them by calling
@ref{189,,gccjit;;function;;new_local()}, supplying a type and a name:
@example
/* Build locals: */
gccjit::lvalue i = func.new_local (the_type, "i");
gccjit::lvalue sum = func.new_local (the_type, "sum");
@end example
These are instances of @ref{187,,gccjit;;lvalue} - they can be read from
and written to.
Note that there is no precanned way to create @emph{and} initialize a variable
like in C:
@example
int i = 0;
@end example
Instead, having added the local to the function, we have to separately add
an assignment of @cite{0} to @cite{local_i} at the beginning of the function.
@node Control flow<2>,Visualizing the control flow graph<2>,Expressions lvalues and rvalues<2>,Tutorial part 3 Loops and variables<2>
@anchor{cp/intro/tutorial03 control-flow}@anchor{18a}
@subsubsection Control flow
This function has a loop, so we need to build some basic blocks to
handle the control flow. In this case, we need 4 blocks:
@enumerate
@item
before the loop (initializing the locals)
@item
the conditional at the top of the loop (comparing @cite{i < n})
@item
the body of the loop
@item
after the loop terminates (@cite{return sum})
@end enumerate
so we create these as @ref{18b,,gccjit;;block} instances within the
@ref{18c,,gccjit;;function}:
@example
gccjit::block b_initial = func.new_block ("initial");
gccjit::block b_loop_cond = func.new_block ("loop_cond");
gccjit::block b_loop_body = func.new_block ("loop_body");
gccjit::block b_after_loop = func.new_block ("after_loop");
@end example
We now populate each block with statements.
The entry block @cite{b_initial} consists of initializations followed by a jump
to the conditional. We assign @cite{0} to @cite{i} and to @cite{sum}, using
@ref{18d,,gccjit;;block;;add_assignment()} to add
an assignment statement, and using @ref{18e,,gccjit;;context;;zero()} to get
the constant value @cite{0} for the relevant type for the right-hand side of
the assignment:
@example
/* sum = 0; */
b_initial.add_assignment (sum, ctxt.zero (the_type));
/* i = 0; */
b_initial.add_assignment (i, ctxt.zero (the_type));
@end example
We can then terminate the entry block by jumping to the conditional:
@example
b_initial.end_with_jump (b_loop_cond);
@end example
The conditional block is equivalent to the line @cite{while (i < n)} from our
C example. It contains a single statement: a conditional, which jumps to
one of two destination blocks depending on a boolean
@ref{17e,,gccjit;;rvalue}, in this case the comparison of @cite{i} and @cite{n}.
We could build the comparison using @ref{18f,,gccjit;;context;;new_comparison()}:
@example
gccjit::rvalue guard =
ctxt.new_comparison (GCC_JIT_COMPARISON_GE,
i, n);
@end example
and can then use this to add @cite{b_loop_cond}’s sole statement, via
@ref{190,,gccjit;;block;;end_with_conditional()}:
@example
b_loop_cond.end_with_conditional (guard,
b_after_loop, // on_true
b_loop_body); // on_false
@end example
However @ref{17e,,gccjit;;rvalue} has overloaded operators for this, so we
express the conditional as
@example
gccjit::rvalue guard = (i >= n);
@end example
and hence we can write the block more concisely as:
@example
b_loop_cond.end_with_conditional (
i >= n,
b_after_loop, // on_true
b_loop_body); // on_false
@end example
Next, we populate the body of the loop.
The C statement @cite{sum += i * i;} is an assignment operation, where an
lvalue is modified “in-place”. We use
@ref{191,,gccjit;;block;;add_assignment_op()} to handle these operations:
@example
/* sum += i * i */
b_loop_body.add_assignment_op (sum,
GCC_JIT_BINARY_OP_PLUS,
i * i);
@end example
The @cite{i++} can be thought of as @cite{i += 1}, and can thus be handled in
a similar way. We use @ref{2f,,gcc_jit_context_one()} to get the constant
value @cite{1} (for the relevant type) for the right-hand side
of the assignment.
@example
/* i++ */
b_loop_body.add_assignment_op (i,
GCC_JIT_BINARY_OP_PLUS,
ctxt.one (the_type));
@end example
@cartouche
@quotation Note
For numeric constants other than 0 or 1, we could use
@ref{192,,gccjit;;context;;new_rvalue()}, which has overloads
for both @code{int} and @code{double}.
@end quotation
@end cartouche
The loop body completes by jumping back to the conditional:
@example
b_loop_body.end_with_jump (b_loop_cond);
@end example
Finally, we populate the @cite{b_after_loop} block, reached when the loop
conditional is false. We want to generate the equivalent of:
@example
return sum;
@end example
so the block is just one statement:
@example
/* return sum */
b_after_loop.end_with_return (sum);
@end example
@cartouche
@quotation Note
You can intermingle block creation with statement creation,
but given that the terminator statements generally include references
to other blocks, I find it’s clearer to create all the blocks,
@emph{then} all the statements.
@end quotation
@end cartouche
We’ve finished populating the function. As before, we can now compile it
to machine code:
@example
gcc_jit_result *result;
result = ctxt.compile ();
ctxt.release ();
if (!result)
@{
fprintf (stderr, "NULL result");
return 1;
@}
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
@{
fprintf (stderr, "NULL loop_test");
gcc_jit_result_release (result);
return 1;
@}
printf ("result: %d", loop_test (10));
@end example
@example
result: 285
@end example
@node Visualizing the control flow graph<2>,Full example<4>,Control flow<2>,Tutorial part 3 Loops and variables<2>
@anchor{cp/intro/tutorial03 visualizing-the-control-flow-graph}@anchor{193}
@subsubsection Visualizing the control flow graph
You can see the control flow graph of a function using
@ref{194,,gccjit;;function;;dump_to_dot()}:
@example
func.dump_to_dot ("/tmp/sum-of-squares.dot");
@end example
giving a .dot file in GraphViz format.
You can convert this to an image using @cite{dot}:
@example
$ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
@end example
or use a viewer (my preferred one is xdot.py; see
@indicateurl{https://github.com/jrfonseca/xdot.py}; on Fedora you can
install it with @cite{yum install python-xdot}):
@quotation
@float Figure
@image{libgccjit-figures/sum-of-squares,,,image of a control flow graph,png}
@end float
@end quotation
@node Full example<4>,,Visualizing the control flow graph<2>,Tutorial part 3 Loops and variables<2>
@anchor{cp/intro/tutorial03 full-example}@anchor{195}
@subsubsection Full example
@quotation
@example
/* Usage example for libgccjit.so's C++ API
Copyright (C) 2014-2022 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 (gccjit::context ctxt)
@{
/*
Simple sum-of-squares, to test conditionals and looping
int loop_test (int n)
@{
int i;
int sum = 0;
for (i = 0; i < n ; i ++)
@{
sum += i * i;
@}
return sum;
*/
gccjit::type the_type = ctxt.get_int_type <int> ();
gccjit::type return_type = the_type;
gccjit::param n = ctxt.new_param (the_type, "n");
std::vector<gccjit::param> params;
params.push_back (n);
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
params, 0);
/* Build locals: */
gccjit::lvalue i = func.new_local (the_type, "i");
gccjit::lvalue sum = func.new_local (the_type, "sum");
gccjit::block b_initial = func.new_block ("initial");
gccjit::block b_loop_cond = func.new_block ("loop_cond");
gccjit::block b_loop_body = func.new_block ("loop_body");
gccjit::block b_after_loop = func.new_block ("after_loop");
/* sum = 0; */
b_initial.add_assignment (sum, ctxt.zero (the_type));
/* i = 0; */
b_initial.add_assignment (i, ctxt.zero (the_type));
b_initial.end_with_jump (b_loop_cond);
/* if (i >= n) */
b_loop_cond.end_with_conditional (
i >= n,
b_after_loop,
b_loop_body);
/* sum += i * i */
b_loop_body.add_assignment_op (sum,
GCC_JIT_BINARY_OP_PLUS,
i * i);
/* i++ */
b_loop_body.add_assignment_op (i,
GCC_JIT_BINARY_OP_PLUS,
ctxt.one (the_type));
b_loop_body.end_with_jump (b_loop_cond);
/* return sum */
b_after_loop.end_with_return (sum);
@}
int
main (int argc, char **argv)
@{
gccjit::context ctxt;
gcc_jit_result *result = NULL;
/* Get a "context" object for working with the library. */
ctxt = gccjit::context::acquire ();
/* Set some options on the context.
Turn this on to see the code being generated, in assembler form. */
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = ctxt.compile ();
ctxt.release ();
if (!result)
@{
fprintf (stderr, "NULL result");
return 1;
@}
/* Extract the generated code from "result". */
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
@{
fprintf (stderr, "NULL loop_test");
gcc_jit_result_release (result);
return 1;
@}
/* Run the generated code. */
int val = loop_test (10);
printf("loop_test returned: %d\n", val);
gcc_jit_result_release (result);
return 0;
@}
@end example
@end quotation
Building and running it:
@example
$ gcc \
tut03-sum-of-squares.cc \
-o tut03-sum-of-squares \
-lgccjit
# Run the built program:
$ ./tut03-sum-of-squares
loop_test returned: 285
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>,,Tutorial part 3 Loops and variables<2>,Tutorial<2>
@anchor{cp/intro/tutorial04 doc}@anchor{196}@anchor{cp/intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{197}
@subsection Tutorial part 4: Adding JIT-compilation to a toy interpreter
In this example we construct a “toy” interpreter, and add JIT-compilation
to it.
@menu
* 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>.
@end menu
@node Our toy interpreter<2>,Compiling to machine code<2>,,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 our-toy-interpreter}@anchor{198}
@subsubsection Our toy interpreter
It’s a stack-based interpreter, and is intended as a (very simple) example
of the kind of bytecode interpreter seen in dynamic languages such as
Python, Ruby etc.
For the sake of simplicity, our toy virtual machine is very limited:
@quotation
@itemize *
@item
The only data type is @cite{int}
@item
It can only work on one function at a time (so that the only
function call that can be made is to recurse).
@item
Functions can only take one parameter.
@item
Functions have a stack of @cite{int} values.
@item
We’ll implement function call within the interpreter by calling a
function in our implementation, rather than implementing our own
frame stack.
@item
The parser is only good enough to get the examples to work.
@end itemize
@end quotation
Naturally, a real interpreter would be much more complicated that this.
The following operations are supported:
@multitable {xxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxx}
@headitem
Operation
@tab
Meaning
@tab
Old Stack
@tab
New Stack
@item
DUP
@tab
Duplicate top of stack.
@tab
@code{[..., x]}
@tab
@code{[..., x, x]}
@item
ROT
@tab
Swap top two elements
of stack.
@tab
@code{[..., x, y]}
@tab
@code{[..., y, x]}
@item
BINARY_ADD
@tab
Add the top two elements
on the stack.
@tab
@code{[..., x, y]}
@tab
@code{[..., (x+y)]}
@item
BINARY_SUBTRACT
@tab
Likewise, but subtract.
@tab
@code{[..., x, y]}
@tab
@code{[..., (x-y)]}
@item
BINARY_MULT
@tab
Likewise, but multiply.
@tab
@code{[..., x, y]}
@tab
@code{[..., (x*y)]}
@item
BINARY_COMPARE_LT
@tab
Compare the top two
elements on the stack
and push a nonzero/zero
if (x<y).
@tab
@code{[..., x, y]}
@tab
@code{[..., (x<y)]}
@item
RECURSE
@tab
Recurse, passing the top
of the stack, and
popping the result.
@tab
@code{[..., x]}
@tab
@code{[..., fn(x)]}
@item
RETURN
@tab
Return the top of the
stack.
@tab
@code{[x]}
@tab
@code{[]}
@item
PUSH_CONST @cite{arg}
@tab
Push an int const.
@tab
@code{[...]}
@tab
@code{[..., arg]}
@item
JUMP_ABS_IF_TRUE @cite{arg}
@tab
Pop; if top of stack was
nonzero, jump to
@code{arg}.
@tab
@code{[..., x]}
@tab
@code{[...]}
@end multitable
Programs can be interpreted, disassembled, and compiled to machine code.
The interpreter reads @code{.toy} scripts. Here’s what a simple recursive
factorial program looks like, the script @code{factorial.toy}.
The parser ignores lines beginning with a @cite{#}.
@quotation
@example
# Simple recursive factorial implementation, roughly equivalent to:
#
# int factorial (int arg)
# @{
# if (arg < 2)
# return arg
# return arg * factorial (arg - 1)
# @}
# Initial state:
# stack: [arg]
# 0:
DUP
# stack: [arg, arg]
# 1:
PUSH_CONST 2
# stack: [arg, arg, 2]
# 2:
BINARY_COMPARE_LT
# stack: [arg, (arg < 2)]
# 3:
JUMP_ABS_IF_TRUE 9
# stack: [arg]
# 4:
DUP
# stack: [arg, arg]
# 5:
PUSH_CONST 1
# stack: [arg, arg, 1]
# 6:
BINARY_SUBTRACT
# stack: [arg, (arg - 1)
# 7:
RECURSE
# stack: [arg, factorial(arg - 1)]
# 8:
BINARY_MULT
# stack: [arg * factorial(arg - 1)]
# 9:
RETURN
@end example
@end quotation
The interpreter is a simple infinite loop with a big @code{switch} statement
based on what the next opcode is:
@quotation
@example
int
toyvm_function::interpret (int arg, FILE *trace)
@{
toyvm_frame frame;
#define PUSH(ARG) (frame.push (ARG))
#define POP(ARG) (frame.pop ())
frame.frm_function = this;
frame.frm_pc = 0;
frame.frm_cur_depth = 0;
PUSH (arg);
while (1)
@{
toyvm_op *op;
int x, y;
assert (frame.frm_pc < fn_num_ops);
op = &fn_ops[frame.frm_pc++];
if (trace)
@{
frame.dump_stack (trace);
disassemble_op (op, frame.frm_pc, trace);
@}
switch (op->op_opcode)
@{
/* Ops taking no operand. */
case DUP:
x = POP ();
PUSH (x);
PUSH (x);
break;
case ROT:
y = POP ();
x = POP ();
PUSH (y);
PUSH (x);
break;
case BINARY_ADD:
y = POP ();
x = POP ();
PUSH (x + y);
break;
case BINARY_SUBTRACT:
y = POP ();
x = POP ();
PUSH (x - y);
break;
case BINARY_MULT:
y = POP ();
x = POP ();
PUSH (x * y);
break;
case BINARY_COMPARE_LT:
y = POP ();
x = POP ();
PUSH (x < y);
break;
case RECURSE:
x = POP ();
x = interpret (x, trace);
PUSH (x);
break;
case RETURN:
return POP ();
/* Ops taking an operand. */
case PUSH_CONST:
PUSH (op->op_operand);
break;
case JUMP_ABS_IF_TRUE:
x = POP ();
if (x)
frame.frm_pc = op->op_operand;
break;
default:
assert (0); /* unknown opcode */
@} /* end of switch on opcode */
@} /* end of while loop */
#undef PUSH
#undef POP
@}
@end example
@end quotation
@node Compiling to machine code<2>,Setting things up<2>,Our toy interpreter<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 compiling-to-machine-code}@anchor{199}
@subsubsection Compiling to machine code
We want to generate machine code that can be cast to this type and
then directly executed in-process:
@quotation
@example
typedef int (*toyvm_compiled_func) (int);
@end example
@end quotation
Our compiler isn’t very sophisticated; it takes the implementation of
each opcode above, and maps it directly to the operations supported by
the libgccjit API.
How should we handle the stack? In theory we could calculate what the
stack depth will be at each opcode, and optimize away the stack
manipulation “by hand”. We’ll see below that libgccjit is able to do
this for us, so we’ll implement stack manipulation
in a direct way, by creating a @code{stack} array and @code{stack_depth}
variables, local within the generated function, equivalent to this C code:
@example
int stack_depth;
int stack[MAX_STACK_DEPTH];
@end example
We’ll also have local variables @code{x} and @code{y} for use when implementing
the opcodes, equivalent to this:
@example
int x;
int y;
@end example
This means our compiler has the following state:
@quotation
@example
toyvm_function &toyvmfn;
gccjit::context ctxt;
gccjit::type int_type;
gccjit::type bool_type;
gccjit::type stack_type; /* int[MAX_STACK_DEPTH] */
gccjit::rvalue const_one;
gccjit::function fn;
gccjit::param param_arg;
gccjit::lvalue stack;
gccjit::lvalue stack_depth;
gccjit::lvalue x;
gccjit::lvalue y;
gccjit::location op_locs[MAX_OPS];
gccjit::block initial_block;
gccjit::block op_blocks[MAX_OPS];
@end example
@end quotation
@node Setting things up<2>,Populating the function<2>,Compiling to machine code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 setting-things-up}@anchor{19a}
@subsubsection Setting things up
First we create our types:
@quotation
@example
void
compilation_state::create_types ()
@{
/* Create types. */
int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
bool_type = ctxt.get_type (GCC_JIT_TYPE_BOOL);
stack_type = ctxt.new_array_type (int_type, MAX_STACK_DEPTH);
@end example
@end quotation
along with extracting a useful @cite{int} constant:
@quotation
@example
const_one = ctxt.one (int_type);
@}
@end example
@end quotation
We’ll implement push and pop in terms of the @code{stack} array and
@code{stack_depth}. Here are helper functions for adding statements to
a block, implementing pushing and popping values:
@quotation
@example
void
compilation_state::add_push (gccjit::block block,
gccjit::rvalue rvalue,
gccjit::location loc)
@{
/* stack[stack_depth] = RVALUE */
block.add_assignment (
/* stack[stack_depth] */
ctxt.new_array_access (
stack,
stack_depth,
loc),
rvalue,
loc);
/* "stack_depth++;". */
block.add_assignment_op (
stack_depth,
GCC_JIT_BINARY_OP_PLUS,
const_one,
loc);
@}
void
compilation_state::add_pop (gccjit::block block,
gccjit::lvalue lvalue,
gccjit::location loc)
@{
/* "--stack_depth;". */
block.add_assignment_op (
stack_depth,
GCC_JIT_BINARY_OP_MINUS,
const_one,
loc);
/* "LVALUE = stack[stack_depth];". */
block.add_assignment (
lvalue,
/* stack[stack_depth] */
ctxt.new_array_access (stack,
stack_depth,
loc),
loc);
@}
@end example
@end quotation
We will support single-stepping through the generated code in the
debugger, so we need to create @ref{19b,,gccjit;;location} instances, one
per operation in the source code. These will reference the lines of
e.g. @code{factorial.toy}.
@quotation
@example
void
compilation_state::create_locations ()
@{
for (int pc = 0; pc < toyvmfn.fn_num_ops; pc++)
@{
toyvm_op *op = &toyvmfn.fn_ops[pc];
op_locs[pc] = ctxt.new_location (toyvmfn.fn_filename,
op->op_linenum,
0); /* column */
@}
@}
@end example
@end quotation
Let’s create the function itself. As usual, we create its parameter
first, then use the parameter to create the function:
@quotation
@example
void
compilation_state::create_function (const char *funcname)
@{
std::vector <gccjit::param> params;
param_arg = ctxt.new_param (int_type, "arg", op_locs[0]);
params.push_back (param_arg);
fn = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
int_type,
funcname,
params, 0,
op_locs[0]);
@end example
@end quotation
We create the locals within the function.
@quotation
@example
stack = fn.new_local (stack_type, "stack");
stack_depth = fn.new_local (int_type, "stack_depth");
x = fn.new_local (int_type, "x");
y = fn.new_local (int_type, "y");
@end example
@end quotation
@node Populating the function<2>,Verifying the control flow graph<2>,Setting things up<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 populating-the-function}@anchor{19c}
@subsubsection Populating the function
There’s some one-time initialization, and the API treats the first block
you create as the entrypoint of the function, so we need to create that
block first:
@quotation
@example
initial_block = fn.new_block ("initial");
@end example
@end quotation
We can now create blocks for each of the operations. Most of these will
be consolidated into larger blocks when the optimizer runs.
@quotation
@example
for (int pc = 0; pc < toyvmfn.fn_num_ops; pc++)
@{
char buf[100];
sprintf (buf, "instr%i", pc);
op_blocks[pc] = fn.new_block (buf);
@}
@end example
@end quotation
Now that we have a block it can jump to when it’s done, we can populate
the initial block:
@quotation
@example
/* "stack_depth = 0;". */
initial_block.add_assignment (stack_depth,
ctxt.zero (int_type),
op_locs[0]);
/* "PUSH (arg);". */
add_push (initial_block,
param_arg,
op_locs[0]);
/* ...and jump to insn 0. */
initial_block.end_with_jump (op_blocks[0],
op_locs[0]);
@end example
@end quotation
We can now populate the blocks for the individual operations. We loop
through them, adding instructions to their blocks:
@quotation
@example
for (int pc = 0; pc < toyvmfn.fn_num_ops; pc++)
@{
gccjit::location loc = op_locs[pc];
gccjit::block block = op_blocks[pc];
gccjit::block next_block = (pc < toyvmfn.fn_num_ops
? op_blocks[pc + 1]
: NULL);
toyvm_op *op;
op = &toyvmfn.fn_ops[pc];
@end example
@end quotation
We’re going to have another big @code{switch} statement for implementing
the opcodes, this time for compiling them, rather than interpreting
them. It’s helpful to have macros for implementing push and pop, so that
we can make the @code{switch} statement that’s coming up look as much as
possible like the one above within the interpreter:
@example
#define X_EQUALS_POP()\
add_pop (block, x, loc)
#define Y_EQUALS_POP()\
add_pop (block, y, loc)
#define PUSH_RVALUE(RVALUE)\
add_push (block, (RVALUE), loc)
#define PUSH_X()\
PUSH_RVALUE (x)
#define PUSH_Y() \
PUSH_RVALUE (y)
@end example
@cartouche
@quotation Note
A particularly clever implementation would have an @emph{identical}
@code{switch} statement shared by the interpreter and the compiler, with
some preprocessor “magic”. We’re not doing that here, for the sake
of simplicity.
@end quotation
@end cartouche
When I first implemented this compiler, I accidentally missed an edit
when copying and pasting the @code{Y_EQUALS_POP} macro, so that popping the
stack into @code{y} instead erroneously assigned it to @code{x}, leaving @code{y}
uninitialized.
To track this kind of thing down, we can use
@ref{19d,,gccjit;;block;;add_comment()} to add descriptive comments
to the internal representation. This is invaluable when looking through
the generated IR for, say @code{factorial}:
@quotation
@example
block.add_comment (opcode_names[op->op_opcode], loc);
@end example
@end quotation
We can now write the big @code{switch} statement that implements the
individual opcodes, populating the relevant block with statements:
@quotation
@example
switch (op->op_opcode)
@{
case DUP:
X_EQUALS_POP ();
PUSH_X ();
PUSH_X ();
break;
case ROT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_Y ();
PUSH_X ();
break;
case BINARY_ADD:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
ctxt.new_binary_op (
GCC_JIT_BINARY_OP_PLUS,
int_type,
x, y,
loc));
break;
case BINARY_SUBTRACT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
ctxt.new_binary_op (
GCC_JIT_BINARY_OP_MINUS,
int_type,
x, y,
loc));
break;
case BINARY_MULT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
ctxt.new_binary_op (
GCC_JIT_BINARY_OP_MULT,
int_type,
x, y,
loc));
break;
case BINARY_COMPARE_LT:
Y_EQUALS_POP ();
X_EQUALS_POP ();
PUSH_RVALUE (
/* cast of bool to int */
ctxt.new_cast (
/* (x < y) as a bool */
ctxt.new_comparison (
GCC_JIT_COMPARISON_LT,
x, y,
loc),
int_type,
loc));
break;
case RECURSE:
@{
X_EQUALS_POP ();
PUSH_RVALUE (
ctxt.new_call (
fn,
x,
loc));
break;
@}
case RETURN:
X_EQUALS_POP ();
block.end_with_return (x, loc);
break;
/* Ops taking an operand. */
case PUSH_CONST:
PUSH_RVALUE (
ctxt.new_rvalue (int_type, op->op_operand));
break;
case JUMP_ABS_IF_TRUE:
X_EQUALS_POP ();
block.end_with_conditional (
/* "(bool)x". */
ctxt.new_cast (x, bool_type, loc),
op_blocks[op->op_operand], /* on_true */
next_block, /* on_false */
loc);
break;
default:
assert(0);
@} /* end of switch on opcode */
@end example
@end quotation
Every block must be terminated, via a call to one of the
@code{gccjit::block::end_with_} entrypoints. This has been done for two
of the opcodes, but we need to do it for the other ones, by jumping
to the next block.
@quotation
@example
if (op->op_opcode != JUMP_ABS_IF_TRUE
&& op->op_opcode != RETURN)
block.end_with_jump (next_block, loc);
@end example
@end quotation
This is analogous to simply incrementing the program counter.
@node Verifying the control flow graph<2>,Compiling the context<2>,Populating the function<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 verifying-the-control-flow-graph}@anchor{19e}
@subsubsection Verifying the control flow graph
Having finished looping over the blocks, the context is complete.
As before, we can verify that the control flow and statements are sane by
using @ref{194,,gccjit;;function;;dump_to_dot()}:
@example
fn.dump_to_dot ("/tmp/factorial.dot");
@end example
and viewing the result. Note how the label names, comments, and
variable names show up in the dump, to make it easier to spot
errors in our compiler.
@quotation
@float Figure
@image{libgccjit-figures/factorial,,,image of a control flow graph,png}
@end float
@end quotation
@node Compiling the context<2>,Single-stepping through the generated code<2>,Verifying the control flow graph<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 compiling-the-context}@anchor{19f}
@subsubsection Compiling the context
Having finished looping over the blocks and populating them with
statements, the context is complete.
We can now compile it, extract machine code from the result, and
run it:
@quotation
@example
class compilation_result
@{
public:
compilation_result (gcc_jit_result *result) :
m_result (result)
@{
@}
~compilation_result ()
@{
gcc_jit_result_release (m_result);
@}
void *get_code (const char *funcname)
@{
return gcc_jit_result_get_code (m_result, funcname);
@}
private:
gcc_jit_result *m_result;
@};
@end example
@example
compilation_result compiler_result = fn->compile ();
const char *funcname = fn->get_function_name ();
toyvm_compiled_func code
= (toyvm_compiled_func)compiler_result.get_code (funcname);
printf ("compiler result: %d\n",
code (atoi (argv[2])));
@end example
@end quotation
@node Single-stepping through the generated code<2>,Examining the generated code<2>,Compiling the context<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 single-stepping-through-the-generated-code}@anchor{1a0}
@subsubsection Single-stepping through the generated code
It’s possible to debug the generated code. To do this we need to both:
@quotation
@itemize *
@item
Set up source code locations for our statements, so that we can
meaningfully step through the code. We did this above by
calling @ref{1a1,,gccjit;;context;;new_location()} and using the
results.
@item
Enable the generation of debugging information, by setting
@ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@ref{175,,gccjit;;context} via
@ref{181,,gccjit;;context;;set_bool_option()}:
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
@end example
@end itemize
@end quotation
Having done this, we can put a breakpoint on the generated function:
@example
$ gdb --args ./toyvm factorial.toy 10
(gdb) break factorial
Function "factorial" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (factorial) pending.
(gdb) run
Breakpoint 1, factorial (arg=10) at factorial.toy:14
14 DUP
@end example
We’ve set up location information, which references @code{factorial.toy}.
This allows us to use e.g. @code{list} to see where we are in the script:
@example
(gdb) list
9
10 # Initial state:
11 # stack: [arg]
12
13 # 0:
14 DUP
15 # stack: [arg, arg]
16
17 # 1:
18 PUSH_CONST 2
@end example
and to step through the function, examining the data:
@example
(gdb) n
18 PUSH_CONST 2
(gdb) n
22 BINARY_COMPARE_LT
(gdb) print stack
$5 = @{10, 10, 2, 0, -7152, 32767, 0, 0@}
(gdb) print stack_depth
$6 = 3
@end example
You’ll see that the parts of the @code{stack} array that haven’t been
touched yet are uninitialized.
@cartouche
@quotation Note
Turning on optimizations may lead to unpredictable results when
stepping through the generated code: the execution may appear to
“jump around” the source code. This is analogous to turning up the
optimization level in a regular compiler.
@end quotation
@end cartouche
@node Examining the generated code<2>,Putting it all together<2>,Single-stepping through the generated code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 examining-the-generated-code}@anchor{1a2}
@subsubsection Examining the generated code
How good is the optimized code?
We can turn up optimizations, by calling
@ref{182,,gccjit;;context;;set_int_option()} with
@ref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
@end example
One of GCC’s internal representations is called “gimple”. A dump of the
initial gimple representation of the code can be seen by setting:
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
@end example
With optimization on and source locations displayed, this gives:
@c We'll use "c" for gimple dumps
@example
factorial (signed int arg)
@{
<unnamed type> D.80;
signed int D.81;
signed int D.82;
signed int D.83;
signed int D.84;
signed int D.85;
signed int y;
signed int x;
signed int stack_depth;
signed int stack[8];
try
@{
initial:
stack_depth = 0;
stack[stack_depth] = arg;
stack_depth = stack_depth + 1;
goto instr0;
instr0:
/* DUP */:
stack_depth = stack_depth + -1;
x = stack[stack_depth];
stack[stack_depth] = x;
stack_depth = stack_depth + 1;
stack[stack_depth] = x;
stack_depth = stack_depth + 1;
goto instr1;
instr1:
/* PUSH_CONST */:
stack[stack_depth] = 2;
stack_depth = stack_depth + 1;
goto instr2;
/* etc */
@end example
You can see the generated machine code in assembly form via:
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 1);
result = ctxt.compile ();
@end example
which shows that (on this x86_64 box) the compiler has unrolled the loop
and is using MMX instructions to perform several multiplications
simultaneously:
@example
.file "fake.c"
.text
.Ltext0:
.p2align 4,,15
.globl factorial
.type factorial, @@function
factorial:
.LFB0:
.file 1 "factorial.toy"
.loc 1 14 0
.cfi_startproc
.LVL0:
.L2:
.loc 1 26 0
cmpl $1, %edi
jle .L13
leal -1(%rdi), %edx
movl %edx, %ecx
shrl $2, %ecx
leal 0(,%rcx,4), %esi
testl %esi, %esi
je .L14
cmpl $9, %edx
jbe .L14
leal -2(%rdi), %eax
movl %eax, -16(%rsp)
leal -3(%rdi), %eax
movd -16(%rsp), %xmm0
movl %edi, -16(%rsp)
movl %eax, -12(%rsp)
movd -16(%rsp), %xmm1
xorl %eax, %eax
movl %edx, -16(%rsp)
movd -12(%rsp), %xmm4
movd -16(%rsp), %xmm6
punpckldq %xmm4, %xmm0
movdqa .LC1(%rip), %xmm4
punpckldq %xmm6, %xmm1
punpcklqdq %xmm0, %xmm1
movdqa .LC0(%rip), %xmm0
jmp .L5
# etc - edited for brevity
@end example
This is clearly overkill for a function that will likely overflow the
@code{int} type before the vectorization is worthwhile - but then again, this
is a toy example.
Turning down the optimization level to 2:
@example
ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
@end example
yields this code, which is simple enough to quote in its entirety:
@example
.file "fake.c"
.text
.p2align 4,,15
.globl factorial
.type factorial, @@function
factorial:
.LFB0:
.cfi_startproc
.L2:
cmpl $1, %edi
jle .L8
movl $1, %edx
jmp .L4
.p2align 4,,10
.p2align 3
.L6:
movl %eax, %edi
.L4:
.L5:
leal -1(%rdi), %eax
imull %edi, %edx
cmpl $1, %eax
jne .L6
.L3:
.L7:
imull %edx, %eax
ret
.L8:
movl %edi, %eax
movl $1, %edx
jmp .L7
.cfi_endproc
.LFE0:
.size factorial, .-factorial
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-%@{gcc_release@})"
.section .note.GNU-stack,"",@@progbits
@end example
Note that the stack pushing and popping have been eliminated, as has the
recursive call (in favor of an iteration).
@node Putting it all together<2>,Behind the curtain How does our code get optimized?<2>,Examining the generated code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 putting-it-all-together}@anchor{1a3}
@subsubsection Putting it all together
The complete example can be seen in the source tree at
@code{gcc/jit/docs/examples/tut04-toyvm/toyvm.cc}
along with a Makefile and a couple of sample .toy scripts:
@example
$ ls -al
drwxrwxr-x. 2 david david 4096 Sep 19 17:46 .
drwxrwxr-x. 3 david david 4096 Sep 19 15:26 ..
-rw-rw-r--. 1 david david 615 Sep 19 12:43 factorial.toy
-rw-rw-r--. 1 david david 834 Sep 19 13:08 fibonacci.toy
-rw-rw-r--. 1 david david 238 Sep 19 14:22 Makefile
-rw-rw-r--. 1 david david 16457 Sep 19 17:07 toyvm.cc
$ make toyvm
g++ -Wall -g -o toyvm toyvm.cc -lgccjit
$ ./toyvm factorial.toy 10
interpreter result: 3628800
compiler result: 3628800
$ ./toyvm fibonacci.toy 10
interpreter result: 55
compiler result: 55
@end example
@node Behind the curtain How does our code get optimized?<2>,,Putting it all together<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
@anchor{cp/intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{1a4}
@subsubsection Behind the curtain: How does our code get optimized?
Our example is done, but you may be wondering about exactly how the
compiler turned what we gave it into the machine code seen above.
We can examine what the compiler is doing in detail by setting:
@example
state.ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING, 1);
state.ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES, 1);
@end example
This will dump detailed information about the compiler’s state to a
directory under @code{/tmp}, and keep it from being cleaned up.
The precise names and their formats of these files is subject to change.
Higher optimization levels lead to more files.
Here’s what I saw (edited for brevity; there were almost 200 files):
@example
intermediate files written to /tmp/libgccjit-KPQbGw
$ ls /tmp/libgccjit-KPQbGw/
fake.c.000i.cgraph
fake.c.000i.type-inheritance
fake.c.004t.gimple
fake.c.007t.omplower
fake.c.008t.lower
fake.c.011t.eh
fake.c.012t.cfg
fake.c.014i.visibility
fake.c.015i.early_local_cleanups
fake.c.016t.ssa
# etc
@end example
The gimple code is converted into Static Single Assignment form,
with annotations for use when generating the debuginfo:
@example
$ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
signed int _56;
initial:
stack_depth_3 = 0;
# DEBUG stack_depth => stack_depth_3
stack[stack_depth_3] = arg_5(D);
stack_depth_7 = stack_depth_3 + 1;
# DEBUG stack_depth => stack_depth_7
# DEBUG instr0 => NULL
# DEBUG /* DUP */ => NULL
stack_depth_8 = stack_depth_7 + -1;
# DEBUG stack_depth => stack_depth_8
x_9 = stack[stack_depth_8];
# DEBUG x => x_9
stack[stack_depth_8] = x_9;
stack_depth_11 = stack_depth_8 + 1;
# DEBUG stack_depth => stack_depth_11
stack[stack_depth_11] = x_9;
stack_depth_13 = stack_depth_11 + 1;
# DEBUG stack_depth => stack_depth_13
# DEBUG instr1 => NULL
# DEBUG /* PUSH_CONST */ => NULL
stack[stack_depth_13] = 2;
/* etc; edited for brevity */
@end example
We can perhaps better see the code by turning off
@ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to suppress all those @code{DEBUG}
statements, giving:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
signed int _56;
initial:
stack_depth_3 = 0;
stack[stack_depth_3] = arg_5(D);
stack_depth_7 = stack_depth_3 + 1;
stack_depth_8 = stack_depth_7 + -1;
x_9 = stack[stack_depth_8];
stack[stack_depth_8] = x_9;
stack_depth_11 = stack_depth_8 + 1;
stack[stack_depth_11] = x_9;
stack_depth_13 = stack_depth_11 + 1;
stack[stack_depth_13] = 2;
stack_depth_15 = stack_depth_13 + 1;
stack_depth_16 = stack_depth_15 + -1;
y_17 = stack[stack_depth_16];
stack_depth_18 = stack_depth_16 + -1;
x_19 = stack[stack_depth_18];
_20 = x_19 < y_17;
_21 = (signed int) _20;
stack[stack_depth_18] = _21;
stack_depth_23 = stack_depth_18 + 1;
stack_depth_24 = stack_depth_23 + -1;
x_25 = stack[stack_depth_24];
if (x_25 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
stack_depth_26 = stack_depth_24 + -1;
x_27 = stack[stack_depth_26];
stack[stack_depth_26] = x_27;
stack_depth_29 = stack_depth_26 + 1;
stack[stack_depth_29] = x_27;
stack_depth_31 = stack_depth_29 + 1;
stack[stack_depth_31] = 1;
stack_depth_33 = stack_depth_31 + 1;
stack_depth_34 = stack_depth_33 + -1;
y_35 = stack[stack_depth_34];
stack_depth_36 = stack_depth_34 + -1;
x_37 = stack[stack_depth_36];
_38 = x_37 - y_35;
stack[stack_depth_36] = _38;
stack_depth_40 = stack_depth_36 + 1;
stack_depth_41 = stack_depth_40 + -1;
x_42 = stack[stack_depth_41];
_44 = factorial (x_42);
stack[stack_depth_41] = _44;
stack_depth_46 = stack_depth_41 + 1;
stack_depth_47 = stack_depth_46 + -1;
y_48 = stack[stack_depth_47];
stack_depth_49 = stack_depth_47 + -1;
x_50 = stack[stack_depth_49];
_51 = x_50 * y_48;
stack[stack_depth_49] = _51;
stack_depth_53 = stack_depth_49 + 1;
# stack_depth_1 = PHI <stack_depth_24(2), stack_depth_53(3)>
instr9:
/* RETURN */:
stack_depth_54 = stack_depth_1 + -1;
x_55 = stack[stack_depth_54];
_56 = x_55;
stack =@{v@} @{CLOBBER@};
return _56;
@}
@end example
Note in the above how all the @ref{18b,,gccjit;;block} instances we
created have been consolidated into just 3 blocks in GCC’s internal
representation: @code{initial}, @code{instr4} and @code{instr9}.
@menu
* Optimizing away stack manipulation: Optimizing away stack manipulation<2>.
* Elimination of tail recursion: Elimination of tail recursion<2>.
@end menu
@node Optimizing away stack manipulation<2>,Elimination of tail recursion<2>,,Behind the curtain How does our code get optimized?<2>
@anchor{cp/intro/tutorial04 optimizing-away-stack-manipulation}@anchor{1a5}
@subsubsection Optimizing away stack manipulation
Recall our simple implementation of stack operations. Let’s examine
how the stack operations are optimized away.
After a pass of constant-propagation, the depth of the stack at each
opcode can be determined at compile-time:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
initial:
stack[0] = arg_5(D);
x_9 = stack[0];
stack[0] = x_9;
stack[1] = x_9;
stack[2] = 2;
y_17 = stack[2];
x_19 = stack[1];
_20 = x_19 < y_17;
_21 = (signed int) _20;
stack[1] = _21;
x_25 = stack[1];
if (x_25 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
x_27 = stack[0];
stack[0] = x_27;
stack[1] = x_27;
stack[2] = 1;
y_35 = stack[2];
x_37 = stack[1];
_38 = x_37 - y_35;
stack[1] = _38;
x_42 = stack[1];
_44 = factorial (x_42);
stack[1] = _44;
y_48 = stack[1];
x_50 = stack[0];
_51 = x_50 * y_48;
stack[0] = _51;
instr9:
/* RETURN */:
x_55 = stack[0];
x_56 = x_55;
stack =@{v@} @{CLOBBER@};
return x_56;
@}
@end example
Note how, in the above, all those @code{stack_depth} values are now just
constants: we’re accessing specific stack locations at each opcode.
The “esra” pass (“Early Scalar Replacement of Aggregates”) breaks
out our “stack” array into individual elements:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
Created a replacement for stack offset: 0, size: 32: stack$0
Created a replacement for stack offset: 32, size: 32: stack$1
Created a replacement for stack offset: 64, size: 32: stack$2
Symbols to be put in SSA form
@{ D.89 D.90 D.91 @}
Incremental SSA update started at block: 0
Number of blocks in CFG: 5
Number of blocks to update: 4 ( 80%)
factorial (signed int arg)
@{
signed int stack$2;
signed int stack$1;
signed int stack$0;
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
initial:
stack$0_45 = arg_5(D);
x_9 = stack$0_45;
stack$0_39 = x_9;
stack$1_32 = x_9;
stack$2_30 = 2;
y_17 = stack$2_30;
x_19 = stack$1_32;
_20 = x_19 < y_17;
_21 = (signed int) _20;
stack$1_28 = _21;
x_25 = stack$1_28;
if (x_25 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
x_27 = stack$0_39;
stack$0_22 = x_27;
stack$1_14 = x_27;
stack$2_12 = 1;
y_35 = stack$2_12;
x_37 = stack$1_14;
_38 = x_37 - y_35;
stack$1_10 = _38;
x_42 = stack$1_10;
_44 = factorial (x_42);
stack$1_6 = _44;
y_48 = stack$1_6;
x_50 = stack$0_22;
_51 = x_50 * y_48;
stack$0_1 = _51;
# stack$0_52 = PHI <stack$0_39(2), stack$0_1(3)>
instr9:
/* RETURN */:
x_55 = stack$0_52;
x_56 = x_55;
stack =@{v@} @{CLOBBER@};
return x_56;
@}
@end example
Hence at this point, all those pushes and pops of the stack are now
simply assignments to specific temporary variables.
After some copy propagation, the stack manipulation has been completely
optimized away:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
factorial (signed int arg)
@{
signed int stack$2;
signed int stack$1;
signed int stack$0;
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int _44;
signed int _51;
initial:
stack$0_39 = arg_5(D);
_20 = arg_5(D) <= 1;
_21 = (signed int) _20;
if (_21 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
_38 = arg_5(D) + -1;
_44 = factorial (_38);
_51 = arg_5(D) * _44;
stack$0_1 = _51;
# stack$0_52 = PHI <arg_5(D)(2), _51(3)>
instr9:
/* RETURN */:
stack =@{v@} @{CLOBBER@};
return stack$0_52;
@}
@end example
Later on, another pass finally eliminated @code{stack_depth} local and the
unused parts of the @cite{stack`} array altogether:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
Released 44 names, 314.29%, removed 44 holes
factorial (signed int arg)
@{
signed int stack$0;
signed int mult_acc_1;
<unnamed type> _5;
signed int _6;
signed int _7;
signed int mul_tmp_10;
signed int mult_acc_11;
signed int mult_acc_13;
# arg_9 = PHI <arg_8(D)(0)>
# mult_acc_13 = PHI <1(0)>
initial:
<bb 5>:
# arg_4 = PHI <arg_9(2), _7(3)>
# mult_acc_1 = PHI <mult_acc_13(2), mult_acc_11(3)>
_5 = arg_4 <= 1;
_6 = (signed int) _5;
if (_6 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
_7 = arg_4 + -1;
mult_acc_11 = mult_acc_1 * arg_4;
goto <bb 5>;
# stack$0_12 = PHI <arg_4(5)>
instr9:
/* RETURN */:
mul_tmp_10 = mult_acc_1 * stack$0_12;
return mul_tmp_10;
@}
@end example
@node Elimination of tail recursion<2>,,Optimizing away stack manipulation<2>,Behind the curtain How does our code get optimized?<2>
@anchor{cp/intro/tutorial04 elimination-of-tail-recursion}@anchor{1a6}
@subsubsection Elimination of tail recursion
Another significant optimization is the detection that the call to
@code{factorial} is tail recursion, which can be eliminated in favor of
an iteration:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1
@end example
@example
;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
Symbols to be put in SSA form
@{ D.88 @}
Incremental SSA update started at block: 0
Number of blocks in CFG: 5
Number of blocks to update: 4 ( 80%)
factorial (signed int arg)
@{
signed int stack$2;
signed int stack$1;
signed int stack$0;
signed int stack[8];
signed int stack_depth;
signed int x;
signed int y;
signed int mult_acc_1;
<unnamed type> _20;
signed int _21;
signed int _38;
signed int mul_tmp_44;
signed int mult_acc_51;
# arg_5 = PHI <arg_39(D)(0), _38(3)>
# mult_acc_1 = PHI <1(0), mult_acc_51(3)>
initial:
_20 = arg_5 <= 1;
_21 = (signed int) _20;
if (_21 != 0)
goto <bb 4> (instr9);
else
goto <bb 3> (instr4);
instr4:
/* DUP */:
_38 = arg_5 + -1;
mult_acc_51 = mult_acc_1 * arg_5;
goto <bb 2> (initial);
# stack$0_52 = PHI <arg_5(2)>
instr9:
/* RETURN */:
stack =@{v@} @{CLOBBER@};
mul_tmp_44 = mult_acc_1 * stack$0_52;
return mul_tmp_44;
@}
@end example
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Topic Reference<2>,,Tutorial<2>,C++ bindings for libgccjit
@anchor{cp/topics/index doc}@anchor{1a7}@anchor{cp/topics/index topic-reference}@anchor{1a8}
@section Topic Reference
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@menu
* 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++::
@end menu
@node Compilation contexts<2>,Objects<2>,,Topic Reference<2>
@anchor{cp/topics/contexts doc}@anchor{1a9}@anchor{cp/topics/contexts compilation-contexts}@anchor{1aa}
@subsection Compilation contexts
@geindex gccjit;;context (C++ class)
@anchor{cp/topics/contexts _CPPv4N6gccjit7contextE}@anchor{175}@anchor{cp/topics/contexts _CPPv3N6gccjit7contextE}@anchor{1ab}@anchor{cp/topics/contexts _CPPv2N6gccjit7contextE}@anchor{1ac}@anchor{cp/topics/contexts gccjit context}@anchor{1ad}
@deffn {C++ Class} gccjit::context
@end deffn
The top-level of the C++ API is the @ref{175,,gccjit;;context} type.
A @ref{175,,gccjit;;context} instance encapsulates the state of a
compilation.
You can set up options on it, and add types, functions and code.
Invoking @ref{17f,,gccjit;;context;;compile()} on it gives you a
@ref{16,,gcc_jit_result *}.
It is a thin wrapper around the C API’s @ref{8,,gcc_jit_context *}.
@menu
* Lifetime-management: Lifetime-management<2>.
* Thread-safety: Thread-safety<2>.
* Error-handling: Error-handling<3>.
* Debugging: Debugging<2>.
* Options: Options<4>.
@end menu
@node Lifetime-management<2>,Thread-safety<2>,,Compilation contexts<2>
@anchor{cp/topics/contexts lifetime-management}@anchor{1ae}
@subsubsection Lifetime-management
Contexts are the unit of lifetime-management within the API: objects
have their lifetime bounded by the context they are created within, and
cleanup of such objects is done for you when the context is released.
@geindex gccjit;;context;;acquire (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context7acquireEv}@anchor{176}@anchor{cp/topics/contexts _CPPv3N6gccjit7context7acquireEv}@anchor{1af}@anchor{cp/topics/contexts _CPPv2N6gccjit7context7acquireEv}@anchor{1b0}@anchor{cp/topics/contexts gccjit context acquire}@anchor{1b1}
@deffn {C++ Function} gccjit::@ref{175,,context} gccjit::@ref{175,,context}::acquire ()
This function acquires a new @ref{175,,gccjit;;context} instance,
which is independent of any others that may be present within this
process.
@end deffn
@geindex gccjit;;context;;release (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context7releaseEv}@anchor{179}@anchor{cp/topics/contexts _CPPv3N6gccjit7context7releaseEv}@anchor{1b2}@anchor{cp/topics/contexts _CPPv2N6gccjit7context7releaseEv}@anchor{1b3}@anchor{cp/topics/contexts gccjit context release}@anchor{1b4}
@deffn {C++ Function} void gccjit::@ref{175,,context}::release ()
This function releases all resources associated with the given context.
Both the context itself and all of its @code{gccjit::object *}
instances are cleaned up. It should be called exactly once on a given
context.
It is invalid to use the context or any of its “contextual” objects
after calling this.
@example
ctxt.release ();
@end example
@end deffn
@geindex gccjit;;context;;new_child_context (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context17new_child_contextEv}@anchor{1b5}@anchor{cp/topics/contexts _CPPv3N6gccjit7context17new_child_contextEv}@anchor{1b6}@anchor{cp/topics/contexts _CPPv2N6gccjit7context17new_child_contextEv}@anchor{1b7}@anchor{cp/topics/contexts gccjit context new_child_context}@anchor{1b8}
@deffn {C++ Function} gccjit::@ref{175,,context} gccjit::@ref{175,,context}::new_child_context ()
Given an existing JIT context, create a child context.
The child inherits a copy of all option-settings from the parent.
The child can reference objects created within the parent, but not
vice-versa.
The lifetime of the child context must be bounded by that of the
parent: you should release a child context before releasing the parent
context.
If you use a function from a parent context within a child context,
you have to compile the parent context before you can compile the
child context, and the gccjit::result of the parent context must
outlive the gccjit::result of the child context.
This allows caching of shared initializations. For example, you could
create types and declarations of global functions in a parent context
once within a process, and then create child contexts whenever a
function or loop becomes hot. Each such child context can be used for
JIT-compiling just one function or loop, but can reference types
and helper functions created within the parent context.
Contexts can be arbitrarily nested, provided the above rules are
followed, but it’s probably not worth going above 2 or 3 levels, and
there will likely be a performance hit for such nesting.
@end deffn
@node Thread-safety<2>,Error-handling<3>,Lifetime-management<2>,Compilation contexts<2>
@anchor{cp/topics/contexts thread-safety}@anchor{1b9}
@subsubsection Thread-safety
Instances of @ref{175,,gccjit;;context} created via
@ref{176,,gccjit;;context;;acquire()} are independent from each other:
only one thread may use a given context at once, but multiple threads
could each have their own contexts without needing locks.
Contexts created via @ref{1b5,,gccjit;;context;;new_child_context()} are
related to their parent context. They can be partitioned by their
ultimate ancestor into independent “family trees”. Only one thread
within a process may use a given “family tree” of such contexts at once,
and if you’re using multiple threads you should provide your own locking
around entire such context partitions.
@node Error-handling<3>,Debugging<2>,Thread-safety<2>,Compilation contexts<2>
@anchor{cp/topics/contexts error-handling}@anchor{1ba}
@subsubsection Error-handling
@c FIXME: How does error-handling work for C++ API?
You can only compile and get code from a context if no errors occur.
In general, if an error occurs when using an API entrypoint, it returns
NULL. You don’t have to check everywhere for NULL results, since the
API gracefully handles a NULL being passed in for any argument.
Errors are printed on stderr and can be queried using
@ref{1bb,,gccjit;;context;;get_first_error()}.
@geindex gccjit;;context;;get_first_error (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{1bb}@anchor{cp/topics/contexts _CPPv3N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{1bc}@anchor{cp/topics/contexts _CPPv2N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{1bd}@anchor{cp/topics/contexts gccjit context get_first_error__gccjit contextP}@anchor{1be}
@deffn {C++ Function} const char *gccjit::@ref{175,,context}::get_first_error (gccjit::context *ctxt)
Returns the first error message that occurred on the context.
The returned string is valid for the rest of the lifetime of the
context.
If no errors occurred, this will be NULL.
@end deffn
@node Debugging<2>,Options<4>,Error-handling<3>,Compilation contexts<2>
@anchor{cp/topics/contexts debugging}@anchor{1bf}
@subsubsection Debugging
@geindex gccjit;;context;;dump_to_file (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{1c0}@anchor{cp/topics/contexts _CPPv3N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{1c1}@anchor{cp/topics/contexts _CPPv2N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{1c2}@anchor{cp/topics/contexts gccjit context dump_to_file__ssCR i}@anchor{1c3}
@deffn {C++ Function} void gccjit::@ref{175,,context}::dump_to_file (const std::string &path, int update_locations)
To help with debugging: dump a C-like representation to the given path,
describing what’s been set up on the context.
If “update_locations” is true, then also set up @ref{19b,,gccjit;;location}
information throughout the context, pointing at the dump file as if it
were a source file. This may be of use in conjunction with
@code{GCCJIT::BOOL_OPTION_DEBUGINFO} to allow stepping through the
code in a debugger.
@end deffn
@geindex gccjit;;context;;dump_reproducer_to_file (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{1c4}@anchor{cp/topics/contexts _CPPv3N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{1c5}@anchor{cp/topics/contexts _CPPv2N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{1c6}@anchor{cp/topics/contexts gccjit context dump_reproducer_to_file__gcc_jit_contextP cCP}@anchor{1c7}
@deffn {C++ Function} void gccjit::@ref{175,,context}::dump_reproducer_to_file (gcc_jit_context *ctxt, const char *path)
This is a thin wrapper around the C API
@ref{5d,,gcc_jit_context_dump_reproducer_to_file()}, and hence works the
same way.
Note that the generated source is C code, not C++; this might be of use
for seeing what the C++ bindings are doing at the C level.
@end deffn
@node Options<4>,,Debugging<2>,Compilation contexts<2>
@anchor{cp/topics/contexts options}@anchor{1c8}
@subsubsection Options
@menu
* String Options: String Options<2>.
* Boolean options: Boolean options<2>.
* Integer options: Integer options<2>.
* Additional command-line options: Additional command-line options<2>.
@end menu
@node String Options<2>,Boolean options<2>,,Options<4>
@anchor{cp/topics/contexts string-options}@anchor{1c9}
@subsubsection String Options
@geindex gccjit;;context;;set_str_option (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{1ca}@anchor{cp/topics/contexts _CPPv3N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{1cb}@anchor{cp/topics/contexts _CPPv2N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{1cc}@anchor{cp/topics/contexts gccjit context set_str_option__gcc_jit_str_option cCP}@anchor{1cd}
@deffn {C++ Function} void gccjit::@ref{175,,context}::set_str_option (enum gcc_jit_str_option, const char *value)
Set a string option of the context.
This is a thin wrapper around the C API
@ref{61,,gcc_jit_context_set_str_option()}; the options have the same
meaning.
@end deffn
@node Boolean options<2>,Integer options<2>,String Options<2>,Options<4>
@anchor{cp/topics/contexts boolean-options}@anchor{1ce}
@subsubsection Boolean options
@geindex gccjit;;context;;set_bool_option (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{181}@anchor{cp/topics/contexts _CPPv3N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{1cf}@anchor{cp/topics/contexts _CPPv2N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{1d0}@anchor{cp/topics/contexts gccjit context set_bool_option__gcc_jit_bool_option i}@anchor{1d1}
@deffn {C++ Function} void gccjit::@ref{175,,context}::set_bool_option (enum gcc_jit_bool_option, int value)
Set a boolean option of the context.
This is a thin wrapper around the C API
@ref{1b,,gcc_jit_context_set_bool_option()}; the options have the same
meaning.
@end deffn
@geindex gccjit;;context;;set_bool_allow_unreachable_blocks (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{1d2}@anchor{cp/topics/contexts _CPPv3N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{1d3}@anchor{cp/topics/contexts _CPPv2N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{1d4}@anchor{cp/topics/contexts gccjit context set_bool_allow_unreachable_blocks__i}@anchor{1d5}
@deffn {C++ Function} void gccjit::@ref{175,,context}::set_bool_allow_unreachable_blocks (int bool_value)
By default, libgccjit will issue an error about unreachable blocks
within a function.
This entrypoint can be used to disable that error; it is a thin wrapper
around the C API
@ref{6b,,gcc_jit_context_set_bool_allow_unreachable_blocks()}.
This entrypoint was added in @ref{6c,,LIBGCCJIT_ABI_2}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_allow_unreachable_blocks
@end example
@end deffn
@geindex gccjit;;context;;set_bool_use_external_driver (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context28set_bool_use_external_driverEi}@anchor{1d6}@anchor{cp/topics/contexts _CPPv3N6gccjit7context28set_bool_use_external_driverEi}@anchor{1d7}@anchor{cp/topics/contexts _CPPv2N6gccjit7context28set_bool_use_external_driverEi}@anchor{1d8}@anchor{cp/topics/contexts gccjit context set_bool_use_external_driver__i}@anchor{1d9}
@deffn {C++ Function} void gccjit::@ref{175,,context}::set_bool_use_external_driver (int bool_value)
libgccjit internally generates assembler, and uses “driver” code
for converting it to other formats (e.g. shared libraries).
By default, libgccjit will use an embedded copy of the driver
code.
This option can be used to instead invoke an external driver executable
as a subprocess; it is a thin wrapper around the C API
@ref{6d,,gcc_jit_context_set_bool_use_external_driver()}.
This entrypoint was added in @ref{6e,,LIBGCCJIT_ABI_5}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
@end example
@end deffn
@node Integer options<2>,Additional command-line options<2>,Boolean options<2>,Options<4>
@anchor{cp/topics/contexts integer-options}@anchor{1da}
@subsubsection Integer options
@geindex gccjit;;context;;set_int_option (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{182}@anchor{cp/topics/contexts _CPPv3N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{1db}@anchor{cp/topics/contexts _CPPv2N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{1dc}@anchor{cp/topics/contexts gccjit context set_int_option__gcc_jit_int_option i}@anchor{1dd}
@deffn {C++ Function} void gccjit::@ref{175,,context}::set_int_option (enum gcc_jit_int_option, int value)
Set an integer option of the context.
This is a thin wrapper around the C API
@ref{1e,,gcc_jit_context_set_int_option()}; the options have the same
meaning.
@end deffn
@node Additional command-line options<2>,,Integer options<2>,Options<4>
@anchor{cp/topics/contexts additional-command-line-options}@anchor{1de}
@subsubsection Additional command-line options
@geindex gccjit;;context;;add_command_line_option (C++ function)
@anchor{cp/topics/contexts _CPPv4N6gccjit7context23add_command_line_optionEPKc}@anchor{1df}@anchor{cp/topics/contexts _CPPv3N6gccjit7context23add_command_line_optionEPKc}@anchor{1e0}@anchor{cp/topics/contexts _CPPv2N6gccjit7context23add_command_line_optionEPKc}@anchor{1e1}@anchor{cp/topics/contexts gccjit context add_command_line_option__cCP}@anchor{1e2}
@deffn {C++ Function} void gccjit::@ref{175,,context}::add_command_line_option (const char *optname)
Add an arbitrary gcc command-line option to the context for use
when compiling.
This is a thin wrapper around the C API
@ref{74,,gcc_jit_context_add_command_line_option()}.
This entrypoint was added in @ref{75,,LIBGCCJIT_ABI_1}; you can test for
its presence using
@example
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option
@end example
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Objects<2>,Types<2>,Compilation contexts<2>,Topic Reference<2>
@anchor{cp/topics/objects doc}@anchor{1e3}@anchor{cp/topics/objects objects}@anchor{1e4}
@subsection Objects
@geindex gccjit;;object (C++ class)
@anchor{cp/topics/objects _CPPv4N6gccjit6objectE}@anchor{17a}@anchor{cp/topics/objects _CPPv3N6gccjit6objectE}@anchor{1e5}@anchor{cp/topics/objects _CPPv2N6gccjit6objectE}@anchor{1e6}@anchor{cp/topics/objects gccjit object}@anchor{1e7}
@deffn {C++ Class} gccjit::object
@end deffn
Almost every entity in the API (with the exception of
@ref{175,,gccjit;;context} and @ref{16,,gcc_jit_result *}) is a
“contextual” object, a @ref{17a,,gccjit;;object}.
A JIT object:
@quotation
@itemize *
@item
is associated with a @ref{175,,gccjit;;context}.
@item
is automatically cleaned up for you when its context is released so
you don’t need to manually track and cleanup all objects, just the
contexts.
@end itemize
@end quotation
The C++ class hierarchy within the @code{gccjit} namespace looks like this:
@example
+- object
+- location
+- type
+- struct
+- field
+- function
+- block
+- rvalue
+- lvalue
+- param
+- case_
@end example
The @ref{17a,,gccjit;;object} base class has the following operations:
@geindex gccjit;;object;;get_context (C++ function)
@anchor{cp/topics/objects _CPPv4NK6gccjit6object11get_contextEv}@anchor{1e8}@anchor{cp/topics/objects _CPPv3NK6gccjit6object11get_contextEv}@anchor{1e9}@anchor{cp/topics/objects _CPPv2NK6gccjit6object11get_contextEv}@anchor{1ea}@anchor{cp/topics/objects gccjit object get_contextC}@anchor{1eb}
@deffn {C++ Function} gccjit::@ref{175,,context} gccjit::@ref{17a,,object}::get_context () const
Which context is the obj within?
@end deffn
@geindex gccjit;;object;;get_debug_string (C++ function)
@anchor{cp/topics/objects _CPPv4NK6gccjit6object16get_debug_stringEv}@anchor{17b}@anchor{cp/topics/objects _CPPv3NK6gccjit6object16get_debug_stringEv}@anchor{1ec}@anchor{cp/topics/objects _CPPv2NK6gccjit6object16get_debug_stringEv}@anchor{1ed}@anchor{cp/topics/objects gccjit object get_debug_stringC}@anchor{1ee}
@deffn {C++ Function} std::string gccjit::@ref{17a,,object}::get_debug_string () const
Generate a human-readable description for the given object.
For example,
@example
printf ("obj: %s\n", obj.get_debug_string ().c_str ());
@end example
might give this text on stdout:
@example
obj: 4.0 * (float)i
@end example
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Types<2>,Expressions<2>,Objects<2>,Topic Reference<2>
@anchor{cp/topics/types doc}@anchor{1ef}@anchor{cp/topics/types types}@anchor{1f0}
@subsection Types
@geindex gccjit;;type (C++ class)
@anchor{cp/topics/types _CPPv4N6gccjit4typeE}@anchor{177}@anchor{cp/topics/types _CPPv3N6gccjit4typeE}@anchor{1f1}@anchor{cp/topics/types _CPPv2N6gccjit4typeE}@anchor{1f2}@anchor{cp/topics/types gccjit type}@anchor{1f3}
@deffn {C++ Class} gccjit::type
gccjit::type represents a type within the library. It is a subclass
of @ref{17a,,gccjit;;object}.
@end deffn
Types can be created in several ways:
@itemize *
@item
fundamental types can be accessed using
@ref{178,,gccjit;;context;;get_type()}:
@example
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
@end example
or using the @code{gccjit::context::get_int_type} template:
@example
gccjit::type t = ctxt.get_int_type <unsigned short> ();
@end example
See @ref{b,,gcc_jit_context_get_type()} for the available types.
@item
derived types can be accessed by using functions such as
@ref{1f4,,gccjit;;type;;get_pointer()} and @ref{1f5,,gccjit;;type;;get_const()}:
@example
gccjit::type const_int_star = int_type.get_const ().get_pointer ();
gccjit::type int_const_star = int_type.get_pointer ().get_const ();
@end example
@item
by creating structures (see below).
@end itemize
@menu
* Standard types: Standard types<2>.
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile<2>.
* Vector types: Vector types<2>.
* Structures and unions: Structures and unions<2>.
@end menu
@node Standard types<2>,Pointers const and volatile<2>,,Types<2>
@anchor{cp/topics/types standard-types}@anchor{1f6}
@subsubsection Standard types
@geindex gccjit;;context;;get_type (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit7context8get_typeE13gcc_jit_types}@anchor{178}@anchor{cp/topics/types _CPPv3N6gccjit7context8get_typeE13gcc_jit_types}@anchor{1f7}@anchor{cp/topics/types _CPPv2N6gccjit7context8get_typeE13gcc_jit_types}@anchor{1f8}@anchor{cp/topics/types gccjit context get_type__gcc_jit_types}@anchor{1f9}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{175,,context}::get_type (enum gcc_jit_types)
Access a specific type. This is a thin wrapper around
@ref{b,,gcc_jit_context_get_type()}; the parameter has the same meaning.
@end deffn
@geindex gccjit;;context;;get_int_type (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit7context12get_int_typeE6size_ti}@anchor{1fa}@anchor{cp/topics/types _CPPv3N6gccjit7context12get_int_typeE6size_ti}@anchor{1fb}@anchor{cp/topics/types _CPPv2N6gccjit7context12get_int_typeE6size_ti}@anchor{1fc}@anchor{cp/topics/types gccjit context get_int_type__s i}@anchor{1fd}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{175,,context}::get_int_type (size_t num_bytes, int is_signed)
Access the integer type of the given size.
@end deffn
@geindex gccjit;;context;;get_int_type<T> (C++ function)
@anchor{cp/topics/types _CPPv4IEN6gccjit7context12get_int_typeI1TEEN6gccjit4typeEv}@anchor{1fe}@anchor{cp/topics/types _CPPv3IEN6gccjit7context12get_int_typeI1TEEv}@anchor{1ff}@anchor{cp/topics/types _CPPv2IEN6gccjit7context12get_int_typeI1TEEv}@anchor{200}
@deffn {C++ Function} template<>gccjit::@ref{177,,type} gccjit::@ref{175,,context}::get_int_type<T> ()
Access the given integer type. For example, you could map the
@code{unsigned short} type into a gccjit::type via:
@example
gccjit::type t = ctxt.get_int_type <unsigned short> ();
@end example
@end deffn
@node Pointers const and volatile<2>,Vector types<2>,Standard types<2>,Types<2>
@anchor{cp/topics/types pointers-const-and-volatile}@anchor{201}
@subsubsection Pointers, @cite{const}, and @cite{volatile}
@geindex gccjit;;type;;get_pointer (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit4type11get_pointerEv}@anchor{1f4}@anchor{cp/topics/types _CPPv3N6gccjit4type11get_pointerEv}@anchor{202}@anchor{cp/topics/types _CPPv2N6gccjit4type11get_pointerEv}@anchor{203}@anchor{cp/topics/types gccjit type get_pointer}@anchor{204}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{177,,type}::get_pointer ()
Given type “T”, get type “T*”.
@end deffn
@geindex gccjit;;type;;get_const (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit4type9get_constEv}@anchor{1f5}@anchor{cp/topics/types _CPPv3N6gccjit4type9get_constEv}@anchor{205}@anchor{cp/topics/types _CPPv2N6gccjit4type9get_constEv}@anchor{206}@anchor{cp/topics/types gccjit type get_const}@anchor{207}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{177,,type}::get_const ()
Given type “T”, get type “const T”.
@end deffn
@geindex gccjit;;type;;get_volatile (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit4type12get_volatileEv}@anchor{208}@anchor{cp/topics/types _CPPv3N6gccjit4type12get_volatileEv}@anchor{209}@anchor{cp/topics/types _CPPv2N6gccjit4type12get_volatileEv}@anchor{20a}@anchor{cp/topics/types gccjit type get_volatile}@anchor{20b}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{177,,type}::get_volatile ()
Given type “T”, get type “volatile T”.
@end deffn
@geindex gccjit;;type;;get_aligned (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit4type11get_alignedE6size_t}@anchor{20c}@anchor{cp/topics/types _CPPv3N6gccjit4type11get_alignedE6size_t}@anchor{20d}@anchor{cp/topics/types _CPPv2N6gccjit4type11get_alignedE6size_t}@anchor{20e}@anchor{cp/topics/types gccjit type get_aligned__s}@anchor{20f}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{177,,type}::get_aligned (size_t alignment_in_bytes)
Given type “T”, get type:
@example
T __attribute__ ((aligned (ALIGNMENT_IN_BYTES)))
@end example
The alignment must be a power of two.
@end deffn
@geindex gccjit;;context;;new_array_type (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{210}@anchor{cp/topics/types _CPPv3N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{211}@anchor{cp/topics/types _CPPv2N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{212}@anchor{cp/topics/types gccjit context new_array_type__gccjit type i gccjit location}@anchor{213}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{175,,context}::new_array_type (gccjit::type element_type, int num_elements, gccjit::location loc)
Given type “T”, get type “T[N]” (for a constant N).
Param “loc” is optional.
@end deffn
@node Vector types<2>,Structures and unions<2>,Pointers const and volatile<2>,Types<2>
@anchor{cp/topics/types vector-types}@anchor{214}
@subsubsection Vector types
@geindex gccjit;;type;;get_vector (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit4type10get_vectorE6size_t}@anchor{215}@anchor{cp/topics/types _CPPv3N6gccjit4type10get_vectorE6size_t}@anchor{216}@anchor{cp/topics/types _CPPv2N6gccjit4type10get_vectorE6size_t}@anchor{217}@anchor{cp/topics/types gccjit type get_vector__s}@anchor{218}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{177,,type}::get_vector (size_t num_units)
Given type “T”, get type:
@example
T __attribute__ ((vector_size (sizeof(T) * num_units))
@end example
T must be integral or floating point; num_units must be a power of two.
@end deffn
@node Structures and unions<2>,,Vector types<2>,Types<2>
@anchor{cp/topics/types structures-and-unions}@anchor{219}
@subsubsection Structures and unions
@geindex gccjit;;struct_ (C++ class)
@anchor{cp/topics/types _CPPv4N6gccjit7struct_E}@anchor{21a}@anchor{cp/topics/types _CPPv3N6gccjit7struct_E}@anchor{21b}@anchor{cp/topics/types _CPPv2N6gccjit7struct_E}@anchor{21c}@anchor{cp/topics/types gccjit struct_}@anchor{21d}
@deffn {C++ Class} gccjit::struct_
@end deffn
A compound type analagous to a C @cite{struct}.
@ref{21a,,gccjit;;struct_} is a subclass of @ref{177,,gccjit;;type} (and thus
of @ref{17a,,gccjit;;object} in turn).
@geindex gccjit;;field (C++ class)
@anchor{cp/topics/types _CPPv4N6gccjit5fieldE}@anchor{21e}@anchor{cp/topics/types _CPPv3N6gccjit5fieldE}@anchor{21f}@anchor{cp/topics/types _CPPv2N6gccjit5fieldE}@anchor{220}@anchor{cp/topics/types gccjit field}@anchor{221}
@deffn {C++ Class} gccjit::field
@end deffn
A field within a @ref{21a,,gccjit;;struct_}.
@ref{21e,,gccjit;;field} is a subclass of @ref{17a,,gccjit;;object}.
You can model C @cite{struct} types by creating @ref{21a,,gccjit;;struct_} and
@ref{21e,,gccjit;;field} instances, in either order:
@itemize *
@item
by creating the fields, then the structure. For example, to model:
@example
struct coord @{double x; double y; @};
@end example
you could call:
@example
gccjit::field field_x = ctxt.new_field (double_type, "x");
gccjit::field field_y = ctxt.new_field (double_type, "y");
std::vector fields;
fields.push_back (field_x);
fields.push_back (field_y);
gccjit::struct_ coord = ctxt.new_struct_type ("coord", fields);
@end example
@item
by creating the structure, then populating it with fields, typically
to allow modelling self-referential structs such as:
@example
struct node @{ int m_hash; struct node *m_next; @};
@end example
like this:
@example
gccjit::struct_ node = ctxt.new_opaque_struct_type ("node");
gccjit::type node_ptr = node.get_pointer ();
gccjit::field field_hash = ctxt.new_field (int_type, "m_hash");
gccjit::field field_next = ctxt.new_field (node_ptr, "m_next");
std::vector fields;
fields.push_back (field_hash);
fields.push_back (field_next);
node.set_fields (fields);
@end example
@end itemize
@c FIXME: the above API doesn't seem to exist yet
@geindex gccjit;;context;;new_field (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{222}@anchor{cp/topics/types _CPPv3N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{223}@anchor{cp/topics/types _CPPv2N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{224}@anchor{cp/topics/types gccjit context new_field__gccjit type cCP gccjit location}@anchor{225}
@deffn {C++ Function} gccjit::@ref{21e,,field} gccjit::@ref{175,,context}::new_field (gccjit::type type, const char *name, gccjit::location loc)
Construct a new field, with the given type and name.
@end deffn
@geindex gccjit;;context;;new_struct_type (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{226}@anchor{cp/topics/types _CPPv3N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{227}@anchor{cp/topics/types _CPPv2N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{228}@anchor{cp/topics/types gccjit context new_struct_type__ssCR std vector field R gccjit location}@anchor{229}
@deffn {C++ Function} gccjit::@ref{21a,,struct_} gccjit::@ref{175,,context}::new_struct_type (const std::string &name, std::vector<field> &fields, gccjit::location loc)
@quotation
Construct a new struct type, with the given name and fields.
@end quotation
@end deffn
@geindex gccjit;;context;;new_opaque_struct (C++ function)
@anchor{cp/topics/types _CPPv4N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{22a}@anchor{cp/topics/types _CPPv3N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{22b}@anchor{cp/topics/types _CPPv2N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{22c}@anchor{cp/topics/types gccjit context new_opaque_struct__ssCR gccjit location}@anchor{22d}
@deffn {C++ Function} gccjit::@ref{21a,,struct_} gccjit::@ref{175,,context}::new_opaque_struct (const std::string &name, gccjit::location loc)
Construct a new struct type, with the given name, but without
specifying the fields. The fields can be omitted (in which case the
size of the struct is not known), or later specified using
@ref{93,,gcc_jit_struct_set_fields()}.
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Expressions<2>,Creating and using functions<2>,Types<2>,Topic Reference<2>
@anchor{cp/topics/expressions doc}@anchor{22e}@anchor{cp/topics/expressions expressions}@anchor{22f}
@subsection Expressions
@menu
* Rvalues: Rvalues<2>.
* Lvalues: Lvalues<2>.
* Working with pointers@comma{} structs and unions: Working with pointers structs and unions<2>.
@end menu
@node Rvalues<2>,Lvalues<2>,,Expressions<2>
@anchor{cp/topics/expressions rvalues}@anchor{230}
@subsubsection Rvalues
@geindex gccjit;;rvalue (C++ class)
@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalueE}@anchor{17e}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalueE}@anchor{231}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalueE}@anchor{232}@anchor{cp/topics/expressions gccjit rvalue}@anchor{233}
@deffn {C++ Class} gccjit::rvalue
@end deffn
A @ref{17e,,gccjit;;rvalue} is an expression that can be computed. It is a
subclass of @ref{17a,,gccjit;;object}, and is a thin wrapper around
@ref{13,,gcc_jit_rvalue *} from the C API.
It can be simple, e.g.:
@quotation
@itemize *
@item
an integer value e.g. @cite{0} or @cite{42}
@item
a string literal e.g. @cite{“Hello world”}
@item
a variable e.g. @cite{i}. These are also lvalues (see below).
@end itemize
@end quotation
or compound e.g.:
@quotation
@itemize *
@item
a unary expression e.g. @cite{!cond}
@item
a binary expression e.g. @cite{(a + b)}
@item
a function call e.g. @cite{get_distance (&player_ship@comma{} &target)}
@item
etc.
@end itemize
@end quotation
Every rvalue has an associated type, and the API will check to ensure
that types match up correctly (otherwise the context will emit an error).
@geindex gccjit;;rvalue;;get_type (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue8get_typeEv}@anchor{234}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue8get_typeEv}@anchor{235}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue8get_typeEv}@anchor{236}@anchor{cp/topics/expressions gccjit rvalue get_type}@anchor{237}
@deffn {C++ Function} gccjit::@ref{177,,type} gccjit::@ref{17e,,rvalue}::get_type ()
Get the type of this rvalue.
@end deffn
@menu
* 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>.
@end menu
@node Simple expressions<2>,Vector expressions<2>,,Rvalues<2>
@anchor{cp/topics/expressions simple-expressions}@anchor{238}
@subsubsection Simple expressions
@geindex gccjit;;context;;new_rvalue (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{192}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{239}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{23a}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type iC}@anchor{23b}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_rvalue (gccjit::type numeric_type, int value) const
Given a numeric type (integer or floating point), build an rvalue for
the given constant @code{int} value.
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{23c}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{23d}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{23e}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type lC}@anchor{23f}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_rvalue (gccjit::type numeric_type, long value) const
Given a numeric type (integer or floating point), build an rvalue for
the given constant @code{long} value.
@end deffn
@geindex gccjit;;context;;zero (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{18e}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{240}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{241}@anchor{cp/topics/expressions gccjit context zero__gccjit typeC}@anchor{242}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::zero (gccjit::type numeric_type) const
Given a numeric type (integer or floating point), get the rvalue for
zero. Essentially this is just a shortcut for:
@example
ctxt.new_rvalue (numeric_type, 0)
@end example
@end deffn
@geindex gccjit;;context;;one (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context3oneEN6gccjit4typeE}@anchor{243}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context3oneEN6gccjit4typeE}@anchor{244}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context3oneEN6gccjit4typeE}@anchor{245}@anchor{cp/topics/expressions gccjit context one__gccjit typeC}@anchor{246}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::one (gccjit::type numeric_type) const
Given a numeric type (integer or floating point), get the rvalue for
one. Essentially this is just a shortcut for:
@example
ctxt.new_rvalue (numeric_type, 1)
@end example
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{247}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{248}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{249}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type doubleC}@anchor{24a}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_rvalue (gccjit::type numeric_type, double value) const
Given a numeric type (integer or floating point), build an rvalue for
the given constant @code{double} value.
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{24b}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{24c}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{24d}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type voidPC}@anchor{24e}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_rvalue (gccjit::type pointer_type, void *value) const
Given a pointer type, build an rvalue for the given address.
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{24f}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{250}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{251}@anchor{cp/topics/expressions gccjit context new_rvalue__ssCRC}@anchor{252}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_rvalue (const std::string &value) const
Generate an rvalue of type @code{GCC_JIT_TYPE_CONST_CHAR_PTR} for
the given string. This is akin to a string literal.
@end deffn
@node Vector expressions<2>,Unary Operations<2>,Simple expressions<2>,Rvalues<2>
@anchor{cp/topics/expressions vector-expressions}@anchor{253}
@subsubsection Vector expressions
@geindex gccjit;;context;;new_rvalue (C++ function)
@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{254}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{255}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{256}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type std vector gccjit rvalue C}@anchor{257}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_rvalue (gccjit::type vector_type, std::vector<gccjit::rvalue> elements) const
Given a vector type, and a vector of scalar rvalue elements, generate a
vector rvalue.
The number of elements needs to match that of the vector type.
@end deffn
@node Unary Operations<2>,Binary Operations<2>,Vector expressions<2>,Rvalues<2>
@anchor{cp/topics/expressions unary-operations}@anchor{258}
@subsubsection Unary Operations
@geindex gccjit;;context;;new_unary_op (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{259}@anchor{cp/topics/expressions _CPPv3N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25b}@anchor{cp/topics/expressions gccjit context new_unary_op__gcc_jit_unary_op gccjit type gccjit rvalue gccjit location}@anchor{25c}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_unary_op (enum gcc_jit_unary_op, gccjit::type result_type, gccjit::rvalue rvalue, gccjit::location loc)
Build a unary operation out of an input rvalue.
Parameter @code{loc} is optional.
This is a thin wrapper around the C API’s
@ref{bf,,gcc_jit_context_new_unary_op()} and the available unary
operations are documented there.
@end deffn
There are shorter ways to spell the various specific kinds of unary
operation:
@geindex gccjit;;context;;new_minus (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25f}@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit location}@anchor{260}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc)
Negate an arithmetic value; for example:
@example
gccjit::rvalue negpi = ctxt.new_minus (t_double, pi);
@end example
builds the equivalent of this C expression:
@example
-pi
@end example
@end deffn
@geindex new_bitwise_negate (C++ function)
@anchor{cp/topics/expressions _CPPv418new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{261}@anchor{cp/topics/expressions _CPPv318new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{262}@anchor{cp/topics/expressions _CPPv218new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{263}@anchor{cp/topics/expressions new_bitwise_negate__gccjit type gccjit rvalue gccjit location}@anchor{264}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} new_bitwise_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc)
Bitwise negation of an integer value (one’s complement); for example:
@example
gccjit::rvalue mask = ctxt.new_bitwise_negate (t_int, a);
@end example
builds the equivalent of this C expression:
@example
~a
@end example
@end deffn
@geindex new_logical_negate (C++ function)
@anchor{cp/topics/expressions _CPPv418new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{265}@anchor{cp/topics/expressions _CPPv318new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{266}@anchor{cp/topics/expressions _CPPv218new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{267}@anchor{cp/topics/expressions new_logical_negate__gccjit type gccjit rvalue gccjit location}@anchor{268}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} new_logical_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc)
Logical negation of an arithmetic or pointer value; for example:
@example
gccjit::rvalue guard = ctxt.new_logical_negate (t_bool, cond);
@end example
builds the equivalent of this C expression:
@example
!cond
@end example
@end deffn
The most concise way to spell them is with overloaded operators:
@geindex operator- (C++ function)
@anchor{cp/topics/expressions _CPPv4miN6gccjit6rvalueE}@anchor{269}@anchor{cp/topics/expressions _CPPv3miN6gccjit6rvalueE}@anchor{26a}@anchor{cp/topics/expressions _CPPv2miN6gccjit6rvalueE}@anchor{26b}@anchor{cp/topics/expressions sub-operator__gccjit rvalue}@anchor{26c}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator@w{-} (gccjit::rvalue a)
@example
gccjit::rvalue negpi = -pi;
@end example
@end deffn
@geindex operator~ (C++ function)
@anchor{cp/topics/expressions _CPPv4coN6gccjit6rvalueE}@anchor{26d}@anchor{cp/topics/expressions _CPPv3coN6gccjit6rvalueE}@anchor{26e}@anchor{cp/topics/expressions _CPPv2coN6gccjit6rvalueE}@anchor{26f}@anchor{cp/topics/expressions inv-operator__gccjit rvalue}@anchor{270}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator~ (gccjit::rvalue a)
@example
gccjit::rvalue mask = ~a;
@end example
@end deffn
@geindex operator! (C++ function)
@anchor{cp/topics/expressions _CPPv4ntN6gccjit6rvalueE}@anchor{271}@anchor{cp/topics/expressions _CPPv3ntN6gccjit6rvalueE}@anchor{272}@anchor{cp/topics/expressions _CPPv2ntN6gccjit6rvalueE}@anchor{273}@anchor{cp/topics/expressions not-operator__gccjit rvalue}@anchor{274}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator! (gccjit::rvalue a)
@example
gccjit::rvalue guard = !cond;
@end example
@end deffn
@node Binary Operations<2>,Comparisons<2>,Unary Operations<2>,Rvalues<2>
@anchor{cp/topics/expressions binary-operations}@anchor{275}
@subsubsection Binary Operations
@geindex gccjit;;context;;new_binary_op (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{17d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{276}@anchor{cp/topics/expressions _CPPv2N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{277}@anchor{cp/topics/expressions gccjit context new_binary_op__gcc_jit_binary_op gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{278}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_binary_op (enum gcc_jit_binary_op, gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
Build a binary operation out of two constituent rvalues.
Parameter @code{loc} is optional.
This is a thin wrapper around the C API’s
@ref{12,,gcc_jit_context_new_binary_op()} and the available binary
operations are documented there.
@end deffn
There are shorter ways to spell the various specific kinds of binary
operation:
@geindex gccjit;;context;;new_plus (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{279}@anchor{cp/topics/expressions _CPPv3N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{27a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{27b}@anchor{cp/topics/expressions gccjit context new_plus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{27c}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_plus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_minus (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{27d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{27e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{27f}@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{280}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_mult (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{281}@anchor{cp/topics/expressions _CPPv3N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{282}@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{283}@anchor{cp/topics/expressions gccjit context new_mult__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{284}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_mult (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_divide (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{285}@anchor{cp/topics/expressions _CPPv3N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{286}@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{287}@anchor{cp/topics/expressions gccjit context new_divide__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{288}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_divide (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_modulo (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{289}@anchor{cp/topics/expressions _CPPv3N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{28a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{28b}@anchor{cp/topics/expressions gccjit context new_modulo__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{28c}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_modulo (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_bitwise_and (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{28d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{28e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{28f}@anchor{cp/topics/expressions gccjit context new_bitwise_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{290}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_bitwise_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_bitwise_xor (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{291}@anchor{cp/topics/expressions _CPPv3N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{292}@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{293}@anchor{cp/topics/expressions gccjit context new_bitwise_xor__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{294}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_bitwise_xor (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_bitwise_or (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{295}@anchor{cp/topics/expressions _CPPv3N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{296}@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{297}@anchor{cp/topics/expressions gccjit context new_bitwise_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{298}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_bitwise_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_logical_and (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{299}@anchor{cp/topics/expressions _CPPv3N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29b}@anchor{cp/topics/expressions gccjit context new_logical_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{29c}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_logical_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_logical_or (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29f}@anchor{cp/topics/expressions gccjit context new_logical_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{2a0}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_logical_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
The most concise way to spell them is with overloaded operators:
@geindex operator+ (C++ function)
@anchor{cp/topics/expressions _CPPv4plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a1}@anchor{cp/topics/expressions _CPPv3plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a2}@anchor{cp/topics/expressions _CPPv2plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a3}@anchor{cp/topics/expressions add-operator__gccjit rvalue gccjit rvalue}@anchor{2a4}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator+ (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue sum = a + b;
@end example
@end deffn
@geindex operator- (C++ function)
@anchor{cp/topics/expressions _CPPv4miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a5}@anchor{cp/topics/expressions _CPPv3miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a6}@anchor{cp/topics/expressions _CPPv2miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a7}@anchor{cp/topics/expressions sub-operator__gccjit rvalue gccjit rvalue}@anchor{2a8}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator@w{-} (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue diff = a - b;
@end example
@end deffn
@geindex operator* (C++ function)
@anchor{cp/topics/expressions _CPPv4mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2a9}@anchor{cp/topics/expressions _CPPv3mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2aa}@anchor{cp/topics/expressions _CPPv2mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ab}@anchor{cp/topics/expressions mul-operator__gccjit rvalue gccjit rvalue}@anchor{2ac}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator* (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue prod = a * b;
@end example
@end deffn
@geindex operator/ (C++ function)
@anchor{cp/topics/expressions _CPPv4dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ad}@anchor{cp/topics/expressions _CPPv3dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ae}@anchor{cp/topics/expressions _CPPv2dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2af}@anchor{cp/topics/expressions div-operator__gccjit rvalue gccjit rvalue}@anchor{2b0}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator/ (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue result = a / b;
@end example
@end deffn
@geindex operator% (C++ function)
@anchor{cp/topics/expressions _CPPv4rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b1}@anchor{cp/topics/expressions _CPPv3rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b2}@anchor{cp/topics/expressions _CPPv2rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b3}@anchor{cp/topics/expressions mod-operator__gccjit rvalue gccjit rvalue}@anchor{2b4}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator% (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue mod = a % b;
@end example
@end deffn
@geindex operator& (C++ function)
@anchor{cp/topics/expressions _CPPv4anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b5}@anchor{cp/topics/expressions _CPPv3anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b6}@anchor{cp/topics/expressions _CPPv2anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b7}@anchor{cp/topics/expressions and-operator__gccjit rvalue gccjit rvalue}@anchor{2b8}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator& (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue x = a & b;
@end example
@end deffn
@geindex operator^ (C++ function)
@anchor{cp/topics/expressions _CPPv4eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b9}@anchor{cp/topics/expressions _CPPv3eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ba}@anchor{cp/topics/expressions _CPPv2eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2bb}@anchor{cp/topics/expressions xor-operator__gccjit rvalue gccjit rvalue}@anchor{2bc}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator^ (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue x = a ^ b;
@end example
@end deffn
@geindex operator| (C++ function)
@anchor{cp/topics/expressions _CPPv4orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2bd}@anchor{cp/topics/expressions _CPPv3orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2be}@anchor{cp/topics/expressions _CPPv2orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2bf}@anchor{cp/topics/expressions or-operator__gccjit rvalue gccjit rvalue}@anchor{2c0}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator| (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue x = a | b;
@end example
@end deffn
@geindex operator&& (C++ function)
@anchor{cp/topics/expressions _CPPv4aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c1}@anchor{cp/topics/expressions _CPPv3aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c2}@anchor{cp/topics/expressions _CPPv2aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c3}@anchor{cp/topics/expressions sand-operator__gccjit rvalue gccjit rvalue}@anchor{2c4}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator&& (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = a && b;
@end example
@end deffn
@geindex operator|| (C++ function)
@anchor{cp/topics/expressions _CPPv4ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c5}@anchor{cp/topics/expressions _CPPv3ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c6}@anchor{cp/topics/expressions _CPPv2ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c7}@anchor{cp/topics/expressions sor-operator__gccjit rvalue gccjit rvalue}@anchor{2c8}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator|| (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = a || b;
@end example
@end deffn
These can of course be combined, giving a terse way to build compound
expressions:
@quotation
@example
gccjit::rvalue discriminant = (b * b) - (four * a * c);
@end example
@end quotation
@node Comparisons<2>,Function calls<2>,Binary Operations<2>,Rvalues<2>
@anchor{cp/topics/expressions comparisons}@anchor{2c9}
@subsubsection Comparisons
@geindex gccjit;;context;;new_comparison (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{18f}@anchor{cp/topics/expressions _CPPv3N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2ca}@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2cb}@anchor{cp/topics/expressions gccjit context new_comparison__gcc_jit_comparison gccjit rvalue gccjit rvalue gccjit location}@anchor{2cc}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_comparison (enum gcc_jit_comparison, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
Build a boolean rvalue out of the comparison of two other rvalues.
Parameter @code{loc} is optional.
This is a thin wrapper around the C API’s
@ref{2c,,gcc_jit_context_new_comparison()} and the available kinds
of comparison are documented there.
@end deffn
There are shorter ways to spell the various specific kinds of binary
operation:
@geindex gccjit;;context;;new_eq (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2cd}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2ce}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2cf}@anchor{cp/topics/expressions gccjit context new_eq__gccjit rvalue gccjit rvalue gccjit location}@anchor{2d0}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_eq (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_ne (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d1}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d2}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d3}@anchor{cp/topics/expressions gccjit context new_ne__gccjit rvalue gccjit rvalue gccjit location}@anchor{2d4}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_ne (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_lt (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d5}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d6}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d7}@anchor{cp/topics/expressions gccjit context new_lt__gccjit rvalue gccjit rvalue gccjit location}@anchor{2d8}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_lt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_le (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2d9}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2da}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2db}@anchor{cp/topics/expressions gccjit context new_le__gccjit rvalue gccjit rvalue gccjit location}@anchor{2dc}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_le (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_gt (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2dd}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2de}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2df}@anchor{cp/topics/expressions gccjit context new_gt__gccjit rvalue gccjit rvalue gccjit location}@anchor{2e0}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_gt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_ge (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2e1}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2e2}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2e3}@anchor{cp/topics/expressions gccjit context new_ge__gccjit rvalue gccjit rvalue gccjit location}@anchor{2e4}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_ge (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
The most concise way to spell them is with overloaded operators:
@geindex operator== (C++ function)
@anchor{cp/topics/expressions _CPPv4eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2e5}@anchor{cp/topics/expressions _CPPv3eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2e6}@anchor{cp/topics/expressions _CPPv2eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2e7}@anchor{cp/topics/expressions eq-operator__gccjit rvalue gccjit rvalue}@anchor{2e8}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator== (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = (a == ctxt.zero (t_int));
@end example
@end deffn
@geindex operator!= (C++ function)
@anchor{cp/topics/expressions _CPPv4neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2e9}@anchor{cp/topics/expressions _CPPv3neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ea}@anchor{cp/topics/expressions _CPPv2neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2eb}@anchor{cp/topics/expressions neq-operator__gccjit rvalue gccjit rvalue}@anchor{2ec}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator!= (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = (i != j);
@end example
@end deffn
@geindex operator< (C++ function)
@anchor{cp/topics/expressions _CPPv4ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ed}@anchor{cp/topics/expressions _CPPv3ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ee}@anchor{cp/topics/expressions _CPPv2ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ef}@anchor{cp/topics/expressions lt-operator__gccjit rvalue gccjit rvalue}@anchor{2f0}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator< (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = i < n;
@end example
@end deffn
@geindex operator<= (C++ function)
@anchor{cp/topics/expressions _CPPv4leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f1}@anchor{cp/topics/expressions _CPPv3leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f2}@anchor{cp/topics/expressions _CPPv2leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f3}@anchor{cp/topics/expressions lte-operator__gccjit rvalue gccjit rvalue}@anchor{2f4}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator<= (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = i <= n;
@end example
@end deffn
@geindex operator> (C++ function)
@anchor{cp/topics/expressions _CPPv4gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f5}@anchor{cp/topics/expressions _CPPv3gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f6}@anchor{cp/topics/expressions _CPPv2gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f7}@anchor{cp/topics/expressions gt-operator__gccjit rvalue gccjit rvalue}@anchor{2f8}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator> (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = (ch > limit);
@end example
@end deffn
@geindex operator>= (C++ function)
@anchor{cp/topics/expressions _CPPv4geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2f9}@anchor{cp/topics/expressions _CPPv3geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2fa}@anchor{cp/topics/expressions _CPPv2geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2fb}@anchor{cp/topics/expressions gte-operator__gccjit rvalue gccjit rvalue}@anchor{2fc}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} operator>= (gccjit::rvalue a, gccjit::rvalue b)
@example
gccjit::rvalue cond = (score >= ctxt.new_rvalue (t_int, 100));
@end example
@end deffn
@c TODO: beyond this point
@node Function calls<2>,Function pointers<3>,Comparisons<2>,Rvalues<2>
@anchor{cp/topics/expressions function-calls}@anchor{2fd}
@subsubsection Function calls
@geindex gcc_jit_context_new_call (C++ function)
@anchor{cp/topics/expressions _CPPv424gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{2fe}@anchor{cp/topics/expressions _CPPv324gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{2ff}@anchor{cp/topics/expressions _CPPv224gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{300}@anchor{cp/topics/expressions gcc_jit_context_new_call__gcc_jit_contextP gcc_jit_locationP gcc_jit_functionP i gcc_jit_rvaluePP}@anchor{301}
@deffn {C++ Function} gcc_jit_rvalue *gcc_jit_context_new_call (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_function *func, int numargs, gcc_jit_rvalue **args)
Given a function and the given table of argument rvalues, construct a
call to the function, with the result as an rvalue.
@cartouche
@quotation Note
@code{gccjit::context::new_call()} merely builds a
@ref{17e,,gccjit;;rvalue} i.e. an expression that can be evaluated,
perhaps as part of a more complicated expression.
The call @emph{won’t} happen unless you add a statement to a function
that evaluates the expression.
For example, if you want to call a function and discard the result
(or to call a function with @code{void} return type), use
@ref{302,,gccjit;;block;;add_eval()}:
@example
/* Add "(void)printf (arg0, arg1);". */
block.add_eval (ctxt.new_call (printf_func, arg0, arg1));
@end example
@end quotation
@end cartouche
@end deffn
@node Function pointers<3>,Type-coercion<2>,Function calls<2>,Rvalues<2>
@anchor{cp/topics/expressions function-pointers}@anchor{303}
@subsubsection Function pointers
@geindex gccjit;;function;;get_address (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{304}@anchor{cp/topics/expressions _CPPv3N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{305}@anchor{cp/topics/expressions _CPPv2N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{306}@anchor{cp/topics/expressions gccjit function get_address__gccjit location}@anchor{307}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{18c,,function}::get_address (gccjit::location loc)
Get the address of a function as an rvalue, of function pointer
type.
@end deffn
@node Type-coercion<2>,,Function pointers<3>,Rvalues<2>
@anchor{cp/topics/expressions type-coercion}@anchor{308}
@subsubsection Type-coercion
@geindex gccjit;;context;;new_cast (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{309}@anchor{cp/topics/expressions _CPPv3N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{30a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{30b}@anchor{cp/topics/expressions gccjit context new_cast__gccjit rvalue gccjit type gccjit location}@anchor{30c}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{175,,context}::new_cast (gccjit::rvalue rvalue, gccjit::type type, gccjit::location loc)
Given an rvalue of T, construct another rvalue of another type.
Currently only a limited set of conversions are possible:
@quotation
@itemize *
@item
int <-> float
@item
int <-> bool
@item
P* <-> Q*, for pointer types P and Q
@end itemize
@end quotation
@end deffn
@node Lvalues<2>,Working with pointers structs and unions<2>,Rvalues<2>,Expressions<2>
@anchor{cp/topics/expressions lvalues}@anchor{30d}
@subsubsection Lvalues
@geindex gccjit;;lvalue (C++ class)
@anchor{cp/topics/expressions _CPPv4N6gccjit6lvalueE}@anchor{187}@anchor{cp/topics/expressions _CPPv3N6gccjit6lvalueE}@anchor{30e}@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalueE}@anchor{30f}@anchor{cp/topics/expressions gccjit lvalue}@anchor{310}
@deffn {C++ Class} gccjit::lvalue
@end deffn
An lvalue is something that can of the @emph{left}-hand side of an assignment:
a storage area (such as a variable). It is a subclass of
@ref{17e,,gccjit;;rvalue}, where the rvalue is computed by reading from the
storage area.
It iss a thin wrapper around @ref{24,,gcc_jit_lvalue *} from the C API.
@geindex gccjit;;lvalue;;get_address (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{311}@anchor{cp/topics/expressions _CPPv3N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{312}@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{313}@anchor{cp/topics/expressions gccjit lvalue get_address__gccjit location}@anchor{314}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{187,,lvalue}::get_address (gccjit::location loc)
Take the address of an lvalue; analogous to:
@example
&(EXPR)
@end example
in C.
Parameter “loc” is optional.
@end deffn
@menu
* Global variables: Global variables<2>.
@end menu
@node Global variables<2>,,,Lvalues<2>
@anchor{cp/topics/expressions global-variables}@anchor{315}
@subsubsection Global variables
@geindex gccjit;;context;;new_global (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{316}@anchor{cp/topics/expressions _CPPv3N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{317}@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{318}@anchor{cp/topics/expressions gccjit context new_global__gcc_jit_global_kind gccjit type cCP gccjit location}@anchor{319}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{175,,context}::new_global (enum gcc_jit_global_kind, gccjit::type type, const char *name, gccjit::location loc)
Add a new global variable of the given type and name to the context.
This is a thin wrapper around @ref{f5,,gcc_jit_context_new_global()} from
the C API; the “kind” parameter has the same meaning as there.
@end deffn
@node Working with pointers structs and unions<2>,,Lvalues<2>,Expressions<2>
@anchor{cp/topics/expressions working-with-pointers-structs-and-unions}@anchor{31a}
@subsubsection Working with pointers, structs and unions
@geindex gccjit;;rvalue;;dereference (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{31b}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{31c}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{31d}@anchor{cp/topics/expressions gccjit rvalue dereference__gccjit location}@anchor{31e}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{17e,,rvalue}::dereference (gccjit::location loc)
Given an rvalue of pointer type @code{T *}, dereferencing the pointer,
getting an lvalue of type @code{T}. Analogous to:
@example
*(EXPR)
@end example
in C.
Parameter “loc” is optional.
@end deffn
If you don’t need to specify the location, this can also be expressed using
an overloaded operator:
@geindex gccjit;;rvalue;;operator* (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6rvaluemlEv}@anchor{31f}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvaluemlEv}@anchor{320}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvaluemlEv}@anchor{321}@anchor{cp/topics/expressions gccjit rvalue mul-operator}@anchor{322}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{17e,,rvalue}::operator* ()
@example
gccjit::lvalue content = *ptr;
@end example
@end deffn
Field access is provided separately for both lvalues and rvalues:
@geindex gccjit;;lvalue;;access_field (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{323}@anchor{cp/topics/expressions _CPPv3N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{324}@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{325}@anchor{cp/topics/expressions gccjit lvalue access_field__gccjit field gccjit location}@anchor{326}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{187,,lvalue}::access_field (gccjit::field field, gccjit::location loc)
Given an lvalue of struct or union type, access the given field,
getting an lvalue of the field’s type. Analogous to:
@example
(EXPR).field = ...;
@end example
in C.
@end deffn
@geindex gccjit;;rvalue;;access_field (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{327}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{328}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{329}@anchor{cp/topics/expressions gccjit rvalue access_field__gccjit field gccjit location}@anchor{32a}
@deffn {C++ Function} gccjit::@ref{17e,,rvalue} gccjit::@ref{17e,,rvalue}::access_field (gccjit::field field, gccjit::location loc)
Given an rvalue of struct or union type, access the given field
as an rvalue. Analogous to:
@example
(EXPR).field
@end example
in C.
@end deffn
@geindex gccjit;;rvalue;;dereference_field (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{32b}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{32c}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{32d}@anchor{cp/topics/expressions gccjit rvalue dereference_field__gccjit field gccjit location}@anchor{32e}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{17e,,rvalue}::dereference_field (gccjit::field field, gccjit::location loc)
Given an rvalue of pointer type @code{T *} where T is of struct or union
type, access the given field as an lvalue. Analogous to:
@example
(EXPR)->field
@end example
in C, itself equivalent to @code{(*EXPR).FIELD}.
@end deffn
@geindex gccjit;;context;;new_array_access (C++ function)
@anchor{cp/topics/expressions _CPPv4N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{32f}@anchor{cp/topics/expressions _CPPv3N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{330}@anchor{cp/topics/expressions _CPPv2N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{331}@anchor{cp/topics/expressions gccjit context new_array_access__gccjit rvalue gccjit rvalue gccjit location}@anchor{332}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{175,,context}::new_array_access (gccjit::rvalue ptr, gccjit::rvalue index, gccjit::location loc)
Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at
the given index, using standard C array indexing rules i.e. each
increment of @code{index} corresponds to @code{sizeof(T)} bytes.
Analogous to:
@example
PTR[INDEX]
@end example
in C (or, indeed, to @code{PTR + INDEX}).
Parameter “loc” is optional.
@end deffn
For array accesses where you don’t need to specify a @ref{19b,,gccjit;;location},
two overloaded operators are available:
@quotation
gccjit::lvalue gccjit::rvalue::operator[] (gccjit::rvalue index)
@example
gccjit::lvalue element = array[idx];
@end example
gccjit::lvalue gccjit::rvalue::operator[] (int index)
@example
gccjit::lvalue element = array[0];
@end example
@end quotation
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Creating and using functions<2>,Source Locations<2>,Expressions<2>,Topic Reference<2>
@anchor{cp/topics/functions doc}@anchor{333}@anchor{cp/topics/functions creating-and-using-functions}@anchor{334}
@subsection Creating and using functions
@menu
* Params: Params<2>.
* Functions: Functions<2>.
* Blocks: Blocks<2>.
* Statements: Statements<2>.
@end menu
@node Params<2>,Functions<2>,,Creating and using functions<2>
@anchor{cp/topics/functions params}@anchor{335}
@subsubsection Params
@geindex gccjit;;param (C++ class)
@anchor{cp/topics/functions _CPPv4N6gccjit5paramE}@anchor{188}@anchor{cp/topics/functions _CPPv3N6gccjit5paramE}@anchor{336}@anchor{cp/topics/functions _CPPv2N6gccjit5paramE}@anchor{337}@anchor{cp/topics/functions gccjit param}@anchor{338}
@deffn {C++ Class} gccjit::param
A @cite{gccjit::param} represents a parameter to a function.
@end deffn
@geindex gccjit;;context;;new_param (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{17c}@anchor{cp/topics/functions _CPPv3N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{339}@anchor{cp/topics/functions _CPPv2N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{33a}@anchor{cp/topics/functions gccjit context new_param__gccjit type cCP gccjit location}@anchor{33b}
@deffn {C++ Function} gccjit::@ref{188,,param} gccjit::@ref{175,,context}::new_param (gccjit::type type, const char *name, gccjit::location loc)
In preparation for creating a function, create a new parameter of the
given type and name.
@end deffn
@ref{188,,gccjit;;param} is a subclass of @ref{187,,gccjit;;lvalue} (and thus
of @ref{17e,,gccjit;;rvalue} and @ref{17a,,gccjit;;object}). It is a thin
wrapper around the C API’s @ref{25,,gcc_jit_param *}.
@node Functions<2>,Blocks<2>,Params<2>,Creating and using functions<2>
@anchor{cp/topics/functions functions}@anchor{33c}
@subsubsection Functions
@geindex gccjit;;function (C++ class)
@anchor{cp/topics/functions _CPPv4N6gccjit8functionE}@anchor{18c}@anchor{cp/topics/functions _CPPv3N6gccjit8functionE}@anchor{33d}@anchor{cp/topics/functions _CPPv2N6gccjit8functionE}@anchor{33e}@anchor{cp/topics/functions gccjit function}@anchor{33f}
@deffn {C++ Class} gccjit::function
A @cite{gccjit::function} represents a function - either one that we’re
creating ourselves, or one that we’re referencing.
@end deffn
@geindex gccjit;;context;;new_function (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{340}@anchor{cp/topics/functions _CPPv3N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{341}@anchor{cp/topics/functions _CPPv2N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{342}@anchor{cp/topics/functions gccjit context new_function__gcc_jit_function_kind gccjit type cCP std vector param R i gccjit location}@anchor{343}
@deffn {C++ Function} gccjit::@ref{18c,,function} gccjit::@ref{175,,context}::new_function (enum gcc_jit_function_kind, gccjit::type return_type, const char *name, std::vector<param> &params, int is_variadic, gccjit::location loc)
Create a gcc_jit_function with the given name and parameters.
Parameters “is_variadic” and “loc” are optional.
This is a wrapper around the C API’s @ref{11,,gcc_jit_context_new_function()}.
@end deffn
@geindex gccjit;;context;;get_builtin_function (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit7context20get_builtin_functionEPKc}@anchor{344}@anchor{cp/topics/functions _CPPv3N6gccjit7context20get_builtin_functionEPKc}@anchor{345}@anchor{cp/topics/functions _CPPv2N6gccjit7context20get_builtin_functionEPKc}@anchor{346}@anchor{cp/topics/functions gccjit context get_builtin_function__cCP}@anchor{347}
@deffn {C++ Function} gccjit::@ref{18c,,function} gccjit::@ref{175,,context}::get_builtin_function (const char *name)
This is a wrapper around the C API’s
@ref{10e,,gcc_jit_context_get_builtin_function()}.
@end deffn
@geindex gccjit;;function;;get_param (C++ function)
@anchor{cp/topics/functions _CPPv4NK6gccjit8function9get_paramEi}@anchor{348}@anchor{cp/topics/functions _CPPv3NK6gccjit8function9get_paramEi}@anchor{349}@anchor{cp/topics/functions _CPPv2NK6gccjit8function9get_paramEi}@anchor{34a}@anchor{cp/topics/functions gccjit function get_param__iC}@anchor{34b}
@deffn {C++ Function} gccjit::@ref{188,,param} gccjit::@ref{18c,,function}::get_param (int index) const
Get the param of the given index (0-based).
@end deffn
@geindex gccjit;;function;;dump_to_dot (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit8function11dump_to_dotEPKc}@anchor{194}@anchor{cp/topics/functions _CPPv3N6gccjit8function11dump_to_dotEPKc}@anchor{34c}@anchor{cp/topics/functions _CPPv2N6gccjit8function11dump_to_dotEPKc}@anchor{34d}@anchor{cp/topics/functions gccjit function dump_to_dot__cCP}@anchor{34e}
@deffn {C++ Function} void gccjit::@ref{18c,,function}::dump_to_dot (const char *path)
Emit the function in graphviz format to the given path.
@end deffn
@geindex gccjit;;function;;new_local (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{189}@anchor{cp/topics/functions _CPPv3N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{34f}@anchor{cp/topics/functions _CPPv2N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{350}@anchor{cp/topics/functions gccjit function new_local__gccjit type cCP gccjit location}@anchor{351}
@deffn {C++ Function} gccjit::@ref{187,,lvalue} gccjit::@ref{18c,,function}::new_local (gccjit::type type, const char *name, gccjit::location loc)
Create a new local variable within the function, of the given type and
name.
@end deffn
@node Blocks<2>,Statements<2>,Functions<2>,Creating and using functions<2>
@anchor{cp/topics/functions blocks}@anchor{352}
@subsubsection Blocks
@geindex gccjit;;block (C++ class)
@anchor{cp/topics/functions _CPPv4N6gccjit5blockE}@anchor{18b}@anchor{cp/topics/functions _CPPv3N6gccjit5blockE}@anchor{353}@anchor{cp/topics/functions _CPPv2N6gccjit5blockE}@anchor{354}@anchor{cp/topics/functions gccjit block}@anchor{355}
@deffn {C++ Class} gccjit::block
A @cite{gccjit::block} represents a basic block within a function i.e. a
sequence of statements with a single entry point and a single exit
point.
@ref{18b,,gccjit;;block} is a subclass of @ref{17a,,gccjit;;object}.
The first basic block that you create within a function will
be the entrypoint.
Each basic block that you create within a function must be
terminated, either with a conditional, a jump, a return, or
a switch.
It’s legal to have multiple basic blocks that return within
one function.
@end deffn
@geindex gccjit;;function;;new_block (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit8function9new_blockEPKc}@anchor{356}@anchor{cp/topics/functions _CPPv3N6gccjit8function9new_blockEPKc}@anchor{357}@anchor{cp/topics/functions _CPPv2N6gccjit8function9new_blockEPKc}@anchor{358}@anchor{cp/topics/functions gccjit function new_block__cCP}@anchor{359}
@deffn {C++ Function} gccjit::@ref{18b,,block} gccjit::@ref{18c,,function}::new_block (const char *name)
Create a basic block of the given name. The name may be NULL, but
providing meaningful names is often helpful when debugging: it may
show up in dumps of the internal representation, and in error
messages.
@end deffn
@node Statements<2>,,Blocks<2>,Creating and using functions<2>
@anchor{cp/topics/functions statements}@anchor{35a}
@subsubsection Statements
@geindex gccjit;;block;;add_eval (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{302}@anchor{cp/topics/functions _CPPv3N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{35b}@anchor{cp/topics/functions _CPPv2N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{35c}@anchor{cp/topics/functions gccjit block add_eval__gccjit rvalue gccjit location}@anchor{35d}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::add_eval (gccjit::rvalue rvalue, gccjit::location loc)
Add evaluation of an rvalue, discarding the result
(e.g. a function call that “returns” void).
This is equivalent to this C code:
@example
(void)expression;
@end example
@end deffn
@geindex gccjit;;block;;add_assignment (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{18d}@anchor{cp/topics/functions _CPPv3N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{35e}@anchor{cp/topics/functions _CPPv2N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{35f}@anchor{cp/topics/functions gccjit block add_assignment__gccjit lvalue gccjit rvalue gccjit location}@anchor{360}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::add_assignment (gccjit::lvalue lvalue, gccjit::rvalue rvalue, gccjit::location loc)
Add evaluation of an rvalue, assigning the result to the given
lvalue.
This is roughly equivalent to this C code:
@example
lvalue = rvalue;
@end example
@end deffn
@geindex gccjit;;block;;add_assignment_op (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{191}@anchor{cp/topics/functions _CPPv3N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{361}@anchor{cp/topics/functions _CPPv2N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{362}@anchor{cp/topics/functions gccjit block add_assignment_op__gccjit lvalue gcc_jit_binary_op gccjit rvalue gccjit location}@anchor{363}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::add_assignment_op (gccjit::lvalue lvalue, enum gcc_jit_binary_op, gccjit::rvalue rvalue, gccjit::location loc)
Add evaluation of an rvalue, using the result to modify an
lvalue.
This is analogous to “+=” and friends:
@example
lvalue += rvalue;
lvalue *= rvalue;
lvalue /= rvalue;
@end example
etc. For example:
@example
/* "i++" */
loop_body.add_assignment_op (
i,
GCC_JIT_BINARY_OP_PLUS,
ctxt.one (int_type));
@end example
@end deffn
@geindex gccjit;;block;;add_comment (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{19d}@anchor{cp/topics/functions _CPPv3N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{364}@anchor{cp/topics/functions _CPPv2N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{365}@anchor{cp/topics/functions gccjit block add_comment__cCP gccjit location}@anchor{366}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::add_comment (const char *text, gccjit::location loc)
Add a no-op textual comment to the internal representation of the
code. It will be optimized away, but will be visible in the dumps
seen via @ref{66,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}
and @ref{1c,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE},
and thus may be of use when debugging how your project’s internal
representation gets converted to the libgccjit IR.
Parameter “loc” is optional.
@end deffn
@geindex gccjit;;block;;end_with_conditional (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{190}@anchor{cp/topics/functions _CPPv3N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{367}@anchor{cp/topics/functions _CPPv2N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{368}@anchor{cp/topics/functions gccjit block end_with_conditional__gccjit rvalue gccjit block gccjit block gccjit location}@anchor{369}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::end_with_conditional (gccjit::rvalue boolval, gccjit::block on_true, gccjit::block on_false, gccjit::location loc)
Terminate a block by adding evaluation of an rvalue, branching on the
result to the appropriate successor block.
This is roughly equivalent to this C code:
@example
if (boolval)
goto on_true;
else
goto on_false;
@end example
block, boolval, on_true, and on_false must be non-NULL.
@end deffn
@geindex gccjit;;block;;end_with_jump (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{36a}@anchor{cp/topics/functions _CPPv3N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{36b}@anchor{cp/topics/functions _CPPv2N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{36c}@anchor{cp/topics/functions gccjit block end_with_jump__gccjit block gccjit location}@anchor{36d}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::end_with_jump (gccjit::block target, gccjit::location loc)
Terminate a block by adding a jump to the given target block.
This is roughly equivalent to this C code:
@example
goto target;
@end example
@end deffn
@geindex gccjit;;block;;end_with_return (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{36e}@anchor{cp/topics/functions _CPPv3N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{36f}@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{370}@anchor{cp/topics/functions gccjit block end_with_return__gccjit rvalue gccjit location}@anchor{371}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::end_with_return (gccjit::rvalue rvalue, gccjit::location loc)
Terminate a block.
Both params are optional.
An rvalue must be provided for a function returning non-void, and
must not be provided by a function “returning” @cite{void}.
If an rvalue is provided, the block is terminated by evaluating the
rvalue and returning the value.
This is roughly equivalent to this C code:
@example
return expression;
@end example
If an rvalue is not provided, the block is terminated by adding a
valueless return, for use within a function with “void” return type.
This is equivalent to this C code:
@example
return;
@end example
@end deffn
@geindex gccjit;;block;;end_with_switch (C++ function)
@anchor{cp/topics/functions _CPPv4N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{372}@anchor{cp/topics/functions _CPPv3N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{373}@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{374}@anchor{cp/topics/functions gccjit block end_with_switch__gccjit rvalue gccjit block std vector gccjit case_ gccjit location}@anchor{375}
@deffn {C++ Function} void gccjit::@ref{18b,,block}::end_with_switch (gccjit::rvalue expr, gccjit::block default_block, std::vector<gccjit::case_> cases, gccjit::location loc)
Terminate a block by adding evalation of an rvalue, then performing
a multiway branch.
This is roughly equivalent to this C code:
@example
switch (expr)
@{
default:
goto default_block;
case C0.min_value ... C0.max_value:
goto C0.dest_block;
case C1.min_value ... C1.max_value:
goto C1.dest_block;
...etc...
case C[N - 1].min_value ... C[N - 1].max_value:
goto C[N - 1].dest_block;
@}
@end example
@code{expr} must be of the same integer type as all of the @code{min_value}
and @code{max_value} within the cases.
The ranges of the cases must not overlap (or have duplicate
values).
The API entrypoints relating to switch statements and cases:
@quotation
@itemize *
@item
@ref{372,,gccjit;;block;;end_with_switch()}
@item
@code{gccjit::context::new_case()}
@end itemize
@end quotation
were added in @ref{11f,,LIBGCCJIT_ABI_3}; you can test for their presence
using
@example
#ifdef LIBGCCJIT_HAVE_SWITCH_STATEMENTS
@end example
A @cite{gccjit::case_} represents a case within a switch statement, and
is created within a particular @ref{175,,gccjit;;context} using
@code{gccjit::context::new_case()}. It is a subclass of
@ref{17a,,gccjit;;object}.
Each case expresses a multivalued range of integer values. You
can express single-valued cases by passing in the same value for
both @cite{min_value} and @cite{max_value}.
Here’s an example of creating a switch statement:
@quotation
@example
void
create_code (gcc_jit_context *c_ctxt, void *user_data)
@{
/* Let's try to inject the equivalent of:
int
test_switch (int x)
@{
switch (x)
@{
case 0 ... 5:
return 3;
case 25 ... 27:
return 4;
case -42 ... -17:
return 83;
case 40:
return 8;
default:
return 10;
@}
@}
*/
gccjit::context ctxt (c_ctxt);
gccjit::type t_int = ctxt.get_type (GCC_JIT_TYPE_INT);
gccjit::type return_type = t_int;
gccjit::param x = ctxt.new_param (t_int, "x");
std::vector <gccjit::param> params;
params.push_back (x);
gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
return_type,
"test_switch",
params, 0);
gccjit::block b_initial = func.new_block ("initial");
gccjit::block b_default = func.new_block ("default");
gccjit::block b_case_0_5 = func.new_block ("case_0_5");
gccjit::block b_case_25_27 = func.new_block ("case_25_27");
gccjit::block b_case_m42_m17 = func.new_block ("case_m42_m17");
gccjit::block b_case_40 = func.new_block ("case_40");
std::vector <gccjit::case_> cases;
cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, 0),
ctxt.new_rvalue (t_int, 5),
b_case_0_5));
cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, 25),
ctxt.new_rvalue (t_int, 27),
b_case_25_27));
cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, -42),
ctxt.new_rvalue (t_int, -17),
b_case_m42_m17));
cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, 40),
ctxt.new_rvalue (t_int, 40),
b_case_40));
b_initial.end_with_switch (x,
b_default,
cases);
b_case_0_5.end_with_return (ctxt.new_rvalue (t_int, 3));
b_case_25_27.end_with_return (ctxt.new_rvalue (t_int, 4));
b_case_m42_m17.end_with_return (ctxt.new_rvalue (t_int, 83));
b_case_40.end_with_return (ctxt.new_rvalue (t_int, 8));
b_default.end_with_return (ctxt.new_rvalue (t_int, 10));
@}
@end example
@end quotation
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Source Locations<2>,Compiling a context<2>,Creating and using functions<2>,Topic Reference<2>
@anchor{cp/topics/locations doc}@anchor{376}@anchor{cp/topics/locations source-locations}@anchor{377}
@subsection Source Locations
@geindex gccjit;;location (C++ class)
@anchor{cp/topics/locations _CPPv4N6gccjit8locationE}@anchor{19b}@anchor{cp/topics/locations _CPPv3N6gccjit8locationE}@anchor{378}@anchor{cp/topics/locations _CPPv2N6gccjit8locationE}@anchor{379}@anchor{cp/topics/locations gccjit location}@anchor{37a}
@deffn {C++ Class} gccjit::location
A @cite{gccjit::location} encapsulates a source code location, so that
you can (optionally) associate locations in your language with
statements in the JIT-compiled code, allowing the debugger to
single-step through your language.
@cite{gccjit::location} instances are optional: you can always omit them
from any C++ API entrypoint accepting one.
You can construct them using @ref{1a1,,gccjit;;context;;new_location()}.
You need to enable @ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@ref{175,,gccjit;;context} for these locations to actually be usable by
the debugger:
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
@end example
@end deffn
@geindex gccjit;;context;;new_location (C++ function)
@anchor{cp/topics/locations _CPPv4N6gccjit7context12new_locationEPKcii}@anchor{1a1}@anchor{cp/topics/locations _CPPv3N6gccjit7context12new_locationEPKcii}@anchor{37b}@anchor{cp/topics/locations _CPPv2N6gccjit7context12new_locationEPKcii}@anchor{37c}@anchor{cp/topics/locations gccjit context new_location__cCP i i}@anchor{37d}
@deffn {C++ Function} gccjit::@ref{19b,,location} gccjit::@ref{175,,context}::new_location (const char *filename, int line, int column)
Create a @cite{gccjit::location} instance representing the given source
location.
@end deffn
@menu
* Faking it: Faking it<2>.
@end menu
@node Faking it<2>,,,Source Locations<2>
@anchor{cp/topics/locations faking-it}@anchor{37e}
@subsubsection Faking it
If you don’t have source code for your internal representation, but need
to debug, you can generate a C-like representation of the functions in
your context using @ref{1c0,,gccjit;;context;;dump_to_file()}:
@example
ctxt.dump_to_file ("/tmp/something.c",
1 /* update_locations */);
@end example
This will dump C-like code to the given path. If the @cite{update_locations}
argument is true, this will also set up @cite{gccjit::location} information
throughout the context, pointing at the dump file as if it were a source
file, giving you @emph{something} you can step through in the debugger.
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Compiling a context<2>,Using Assembly Language with libgccjit++,Source Locations<2>,Topic Reference<2>
@anchor{cp/topics/compilation doc}@anchor{37f}@anchor{cp/topics/compilation compiling-a-context}@anchor{380}
@subsection Compiling a context
Once populated, a @ref{175,,gccjit;;context} can be compiled to
machine code, either in-memory via @ref{17f,,gccjit;;context;;compile()} or
to disk via @ref{381,,gccjit;;context;;compile_to_file()}.
You can compile a context multiple times (using either form of
compilation), although any errors that occur on the context will
prevent any future compilation of that context.
@menu
* In-memory compilation: In-memory compilation<2>.
* Ahead-of-time compilation: Ahead-of-time compilation<2>.
@end menu
@node In-memory compilation<2>,Ahead-of-time compilation<2>,,Compiling a context<2>
@anchor{cp/topics/compilation in-memory-compilation}@anchor{382}
@subsubsection In-memory compilation
@geindex gccjit;;context;;compile (C++ function)
@anchor{cp/topics/compilation _CPPv4N6gccjit7context7compileEv}@anchor{17f}@anchor{cp/topics/compilation _CPPv3N6gccjit7context7compileEv}@anchor{383}@anchor{cp/topics/compilation _CPPv2N6gccjit7context7compileEv}@anchor{384}@anchor{cp/topics/compilation gccjit context compile}@anchor{385}
@deffn {C++ Function} gcc_jit_result *gccjit::@ref{175,,context}::compile ()
This calls into GCC and builds the code, returning a
@cite{gcc_jit_result *}.
This is a thin wrapper around the
@ref{15,,gcc_jit_context_compile()} API entrypoint.
@end deffn
@node Ahead-of-time compilation<2>,,In-memory compilation<2>,Compiling a context<2>
@anchor{cp/topics/compilation ahead-of-time-compilation}@anchor{386}
@subsubsection Ahead-of-time compilation
Although libgccjit is primarily aimed at just-in-time compilation, it
can also be used for implementing more traditional ahead-of-time
compilers, via the @ref{381,,gccjit;;context;;compile_to_file()} method.
@geindex gccjit;;context;;compile_to_file (C++ function)
@anchor{cp/topics/compilation _CPPv4N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{381}@anchor{cp/topics/compilation _CPPv3N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{387}@anchor{cp/topics/compilation _CPPv2N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{388}@anchor{cp/topics/compilation gccjit context compile_to_file__gcc_jit_output_kind cCP}@anchor{389}
@deffn {C++ Function} void gccjit::@ref{175,,context}::compile_to_file (enum gcc_jit_output_kind, const char *output_path)
Compile the @ref{175,,gccjit;;context} to a file of the given
kind.
This is a thin wrapper around the
@ref{4a,,gcc_jit_context_compile_to_file()} API entrypoint.
@end deffn
@c Copyright (C) 2020-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Using Assembly Language with libgccjit++,,Compiling a context<2>,Topic Reference<2>
@anchor{cp/topics/asm doc}@anchor{38a}@anchor{cp/topics/asm using-assembly-language-with-libgccjit}@anchor{38b}
@subsection Using Assembly Language with libgccjit++
libgccjit has some support for directly embedding assembler instructions.
This is based on GCC’s support for inline @code{asm} in C code, and the
following assumes a familiarity with that functionality. See
How to Use Inline Assembly Language in C Code@footnote{https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html}
in GCC’s documentation, the “Extended Asm” section in particular.
These entrypoints were added in @ref{151,,LIBGCCJIT_ABI_15}; you can test
for their presence using
@quotation
@example
#ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS
@end example
@end quotation
@menu
* Adding assembler instructions within a function: Adding assembler instructions within a function<2>.
* Adding top-level assembler statements: Adding top-level assembler statements<2>.
@end menu
@node Adding assembler instructions within a function<2>,Adding top-level assembler statements<2>,,Using Assembly Language with libgccjit++
@anchor{cp/topics/asm adding-assembler-instructions-within-a-function}@anchor{38c}
@subsubsection Adding assembler instructions within a function
@geindex gccjit;;extended_asm (C++ class)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asmE}@anchor{38d}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asmE}@anchor{38e}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asmE}@anchor{38f}@anchor{cp/topics/asm gccjit extended_asm}@anchor{390}
@deffn {C++ Class} gccjit::extended_asm
A @cite{gccjit::extended_asm} represents an extended @code{asm} statement: a
series of low-level instructions inside a function that convert inputs
to outputs.
@ref{38d,,gccjit;;extended_asm} is a subclass of @ref{17a,,gccjit;;object}.
It is a thin wrapper around the C API’s @ref{120,,gcc_jit_extended_asm *}.
To avoid having an API entrypoint with a very large number of
parameters, an extended @code{asm} statement is made in stages:
an initial call to create the @ref{38d,,gccjit;;extended_asm},
followed by calls to add operands and set other properties of the
statement.
There are two API entrypoints for creating a @ref{38d,,gccjit;;extended_asm}:
@itemize *
@item
@ref{391,,gccjit;;block;;add_extended_asm()} for an @code{asm} statement with
no control flow, and
@item
@ref{392,,gccjit;;block;;end_with_extended_asm_goto()} for an @code{asm goto}.
@end itemize
For example, to create the equivalent of:
@example
asm ("mov %1, %0\n\t"
"add $1, %0"
: "=r" (dst)
: "r" (src));
@end example
the following API calls could be used:
@example
block.add_extended_asm ("mov %1, %0\n\t"
"add $1, %0")
.add_output_operand ("=r", dst)
.add_input_operand ("r", src);
@end example
@cartouche
@quotation Warning
When considering the numbering of operands within an
extended @code{asm} statement (e.g. the @code{%0} and @code{%1}
above), the equivalent to the C syntax is followed i.e. all
output operands, then all input operands, regardless of
what order the calls to
@ref{393,,gccjit;;extended_asm;;add_output_operand()} and
@ref{394,,gccjit;;extended_asm;;add_input_operand()} were made in.
@end quotation
@end cartouche
As in the C syntax, operands can be given symbolic names to avoid having
to number them. For example, to create the equivalent of:
@example
asm ("bsfl %[aMask], %[aIndex]"
: [aIndex] "=r" (Index)
: [aMask] "r" (Mask)
: "cc");
@end example
the following API calls could be used:
@example
block.add_extended_asm ("bsfl %[aMask], %[aIndex]")
.add_output_operand ("aIndex", "=r", index)
.add_input_operand ("aMask", "r", mask)
.add_clobber ("cc");
@end example
@end deffn
@geindex gccjit;;block;;add_extended_asm (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit5block16add_extended_asmERKNSt6stringEN6gccjit8locationE}@anchor{391}@anchor{cp/topics/asm _CPPv3N6gccjit5block16add_extended_asmERKNSt6stringEN6gccjit8locationE}@anchor{395}@anchor{cp/topics/asm _CPPv2N6gccjit5block16add_extended_asmERKNSt6stringEN6gccjit8locationE}@anchor{396}@anchor{cp/topics/asm gccjit block add_extended_asm__ssCR gccjit location}@anchor{397}
@deffn {C++ Function} @ref{38d,,extended_asm} gccjit::@ref{18b,,block}::add_extended_asm (const std::string &asm_template, gccjit::location loc = location())
Create a @ref{38d,,gccjit;;extended_asm} for an extended @code{asm} statement
with no control flow (i.e. without the @code{goto} qualifier).
The parameter @code{asm_template} corresponds to the @cite{AssemblerTemplate}
within C’s extended @code{asm} syntax. It must be non-NULL. The call takes
a copy of the underlying string, so it is valid to pass in a pointer to
an on-stack buffer.
@end deffn
@geindex gccjit;;block;;end_with_extended_asm_goto (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit5block26end_with_extended_asm_gotoERKNSt6stringENSt6vectorI5blockEEP5block8location}@anchor{392}@anchor{cp/topics/asm _CPPv3N6gccjit5block26end_with_extended_asm_gotoERKNSt6stringENSt6vectorI5blockEEP5block8location}@anchor{398}@anchor{cp/topics/asm _CPPv2N6gccjit5block26end_with_extended_asm_gotoERKNSt6stringENSt6vectorI5blockEEP5block8location}@anchor{399}@anchor{cp/topics/asm gccjit block end_with_extended_asm_goto__ssCR std vector block blockP location}@anchor{39a}
@deffn {C++ Function} @ref{38d,,extended_asm} gccjit::@ref{18b,,block}::end_with_extended_asm_goto (const std::string &asm_template, std::vector<block> goto_blocks, block *fallthrough_block, location loc = location())
Create a @ref{38d,,gccjit;;extended_asm} for an extended @code{asm} statement
that may perform jumps, and use it to terminate the given block.
This is equivalent to the @code{goto} qualifier in C’s extended @code{asm}
syntax.
For example, to create the equivalent of:
@example
asm goto ("btl %1, %0\n\t"
"jc %l[carry]"
: // No outputs
: "r" (p1), "r" (p2)
: "cc"
: carry);
@end example
the following API calls could be used:
@example
const char *asm_template =
(use_name
? /* Label referred to by name: "%l[carry]". */
("btl %1, %0\n\t"
"jc %l[carry]")
: /* Label referred to numerically: "%l2". */
("btl %1, %0\n\t"
"jc %l2"));
std::vector<gccjit::block> goto_blocks (@{b_carry@});
gccjit::extended_asm ext_asm
= (b_start.end_with_extended_asm_goto (asm_template,
goto_blocks,
&b_fallthru)
.add_input_operand ("r", p1)
.add_input_operand ("r", p2)
.add_clobber ("cc"));
@end example
here referencing a @code{gcc_jit_block} named “carry”.
@code{num_goto_blocks} corresponds to the @code{GotoLabels} parameter within C’s
extended @code{asm} syntax. The block names can be referenced within the
assembler template.
@code{fallthrough_block} can be NULL. If non-NULL, it specifies the block
to fall through to after the statement.
@cartouche
@quotation Note
This is needed since each @ref{18b,,gccjit;;block} must have a
single exit point, as a basic block: you can’t jump from the
middle of a block. A “goto” is implicitly added after the
asm to handle the fallthrough case, which is equivalent to what
would have happened in the C case.
@end quotation
@end cartouche
@end deffn
@geindex gccjit;;extended_asm;;set_volatile_flag (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm17set_volatile_flagEb}@anchor{39b}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm17set_volatile_flagEb}@anchor{39c}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm17set_volatile_flagEb}@anchor{39d}@anchor{cp/topics/asm gccjit extended_asm set_volatile_flag__b}@anchor{39e}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::set_volatile_flag (bool flag)
Set whether the @ref{38d,,gccjit;;extended_asm} has side-effects, equivalent to the
volatile@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile}
qualifier in C’s extended asm syntax.
For example, to create the equivalent of:
@example
asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX.
"shl $32, %%rdx\n\t" // Shift the upper bits left.
"or %%rdx, %0" // 'Or' in the lower bits.
: "=a" (msr)
:
: "rdx");
@end example
the following API calls could be used:
@example
gccjit::extended_asm ext_asm
= block.add_extended_asm
("rdtsc\n\t" /* Returns the time in EDX:EAX. */
"shl $32, %%rdx\n\t" /* Shift the upper bits left. */
"or %%rdx, %0") /* 'Or' in the lower bits. */
.set_volatile_flag (true)
.add_output_operand ("=a", msr)
.add_clobber ("rdx");
@end example
where the @ref{38d,,gccjit;;extended_asm} is flagged as volatile.
@end deffn
@geindex gccjit;;extended_asm;;set_inline_flag (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm15set_inline_flagEb}@anchor{39f}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm15set_inline_flagEb}@anchor{3a0}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm15set_inline_flagEb}@anchor{3a1}@anchor{cp/topics/asm gccjit extended_asm set_inline_flag__b}@anchor{3a2}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::set_inline_flag (bool flag)
Set the equivalent of the
inline@footnote{https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html#Size-of-an-asm}
qualifier in C’s extended @code{asm} syntax.
@end deffn
@geindex gccjit;;extended_asm;;add_output_operand (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm18add_output_operandERKNSt6stringERKNSt6stringEN6gccjit6lvalueE}@anchor{393}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm18add_output_operandERKNSt6stringERKNSt6stringEN6gccjit6lvalueE}@anchor{3a3}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm18add_output_operandERKNSt6stringERKNSt6stringEN6gccjit6lvalueE}@anchor{3a4}@anchor{cp/topics/asm gccjit extended_asm add_output_operand__ssCR ssCR gccjit lvalue}@anchor{3a5}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::add_output_operand (const std::string &asm_symbolic_name, const std::string &constraint, gccjit::lvalue dest)
Add an output operand to the extended @code{asm} statement. See the
Output Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands}
section of the documentation of the C syntax.
@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component of
C’s extended @code{asm} syntax, and specifies the symbolic name for the operand.
See the overload below for an alternative that does not supply a symbolic
name.
@code{constraint} corresponds to the @code{constraint} component of C’s extended
@code{asm} syntax.
@code{dest} corresponds to the @code{cvariablename} component of C’s extended
@code{asm} syntax.
@example
// Example with a symbolic name ("aIndex"), the equivalent of:
// : [aIndex] "=r" (index)
ext_asm.add_output_operand ("aIndex", "=r", index);
@end example
This function can’t be called on an @code{asm goto} as such instructions can’t
have outputs; see the
Goto Labels@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels}
section of GCC’s “Extended Asm” documentation.
@end deffn
@geindex gccjit;;extended_asm;;add_output_operand (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm18add_output_operandERKNSt6stringEN6gccjit6lvalueE}@anchor{3a6}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm18add_output_operandERKNSt6stringEN6gccjit6lvalueE}@anchor{3a7}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm18add_output_operandERKNSt6stringEN6gccjit6lvalueE}@anchor{3a8}@anchor{cp/topics/asm gccjit extended_asm add_output_operand__ssCR gccjit lvalue}@anchor{3a9}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::add_output_operand (const std::string &constraint, gccjit::lvalue dest)
As above, but don’t supply a symbolic name for the operand.
@example
// Example without a symbolic name, the equivalent of:
// : "=r" (dst)
ext_asm.add_output_operand ("=r", dst);
@end example
@end deffn
@geindex gccjit;;extended_asm;;add_input_operand (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm17add_input_operandERKNSt6stringERKNSt6stringEN6gccjit6rvalueE}@anchor{394}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm17add_input_operandERKNSt6stringERKNSt6stringEN6gccjit6rvalueE}@anchor{3aa}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm17add_input_operandERKNSt6stringERKNSt6stringEN6gccjit6rvalueE}@anchor{3ab}@anchor{cp/topics/asm gccjit extended_asm add_input_operand__ssCR ssCR gccjit rvalue}@anchor{3ac}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::add_input_operand (const std::string &asm_symbolic_name, const std::string &constraint, gccjit::rvalue src)
Add an input operand to the extended @code{asm} statement. See the
Input Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands}
section of the documentation of the C syntax.
@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component
of C’s extended @code{asm} syntax. See the overload below for an alternative
that does not supply a symbolic name.
@code{constraint} corresponds to the @code{constraint} component of C’s extended
@code{asm} syntax.
@code{src} corresponds to the @code{cexpression} component of C’s extended
@code{asm} syntax.
@example
// Example with a symbolic name ("aMask"), the equivalent of:
// : [aMask] "r" (Mask)
ext_asm.add_input_operand ("aMask", "r", mask);
@end example
@end deffn
@geindex gccjit;;extended_asm;;add_input_operand (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm17add_input_operandERKNSt6stringEN6gccjit6rvalueE}@anchor{3ad}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm17add_input_operandERKNSt6stringEN6gccjit6rvalueE}@anchor{3ae}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm17add_input_operandERKNSt6stringEN6gccjit6rvalueE}@anchor{3af}@anchor{cp/topics/asm gccjit extended_asm add_input_operand__ssCR gccjit rvalue}@anchor{3b0}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::add_input_operand (const std::string &constraint, gccjit::rvalue src)
As above, but don’t supply a symbolic name for the operand.
@example
// Example without a symbolic name, the equivalent of:
// : "r" (src)
ext_asm.add_input_operand ("r", src);
@end example
@end deffn
@geindex gccjit;;extended_asm;;add_clobber (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm11add_clobberERKNSt6stringE}@anchor{3b1}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm11add_clobberERKNSt6stringE}@anchor{3b2}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm11add_clobberERKNSt6stringE}@anchor{3b3}@anchor{cp/topics/asm gccjit extended_asm add_clobber__ssCR}@anchor{3b4}
@deffn {C++ Function} gccjit::@ref{38d,,extended_asm} &gccjit::@ref{38d,,extended_asm}::add_clobber (const std::string &victim)
Add @cite{victim} to the list of registers clobbered by the extended @code{asm}
statement. See the
Clobbers and Scratch Registers@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers#}
section of the documentation of the C syntax.
Statements with multiple clobbers will require multiple calls, one per
clobber.
For example:
@example
ext_asm.add_clobber ("r0").add_clobber ("cc").add_clobber ("memory");
@end example
@end deffn
@node Adding top-level assembler statements<2>,,Adding assembler instructions within a function<2>,Using Assembly Language with libgccjit++
@anchor{cp/topics/asm adding-top-level-assembler-statements}@anchor{3b5}
@subsubsection Adding top-level assembler statements
In addition to creating extended @code{asm} instructions within a function,
there is support for creating “top-level” assembler statements, outside
of any function.
@geindex gccjit;;context;;add_top_level_asm (C++ function)
@anchor{cp/topics/asm _CPPv4N6gccjit7context17add_top_level_asmEPKcN6gccjit8locationE}@anchor{3b6}@anchor{cp/topics/asm _CPPv3N6gccjit7context17add_top_level_asmEPKcN6gccjit8locationE}@anchor{3b7}@anchor{cp/topics/asm _CPPv2N6gccjit7context17add_top_level_asmEPKcN6gccjit8locationE}@anchor{3b8}@anchor{cp/topics/asm gccjit context add_top_level_asm__cCP gccjit location}@anchor{3b9}
@deffn {C++ Function} void gccjit::@ref{175,,context}::add_top_level_asm (const char *asm_stmts, gccjit::location loc = location())
Create a set of top-level asm statements, analogous to those created
by GCC’s “basic” @code{asm} syntax in C at file scope.
For example, to create the equivalent of:
@example
asm ("\t.pushsection .text\n"
"\t.globl add_asm\n"
"\t.type add_asm, @@function\n"
"add_asm:\n"
"\tmovq %rdi, %rax\n"
"\tadd %rsi, %rax\n"
"\tret\n"
"\t.popsection\n");
@end example
the following API calls could be used:
@example
ctxt.add_top_level_asm ("\t.pushsection .text\n"
"\t.globl add_asm\n"
"\t.type add_asm, @@function\n"
"add_asm:\n"
"\tmovq %rdi, %rax\n"
"\tadd %rsi, %rax\n"
"\tret\n"
"\t# some asm here\n"
"\t.popsection\n");
@end example
@end deffn
@c Copyright (C) 2014-2022 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@c This is free software: you can redistribute it and/or modify it
@c under the terms of the GNU General Public License as published by
@c the Free Software Foundation, either version 3 of the License, or
@c (at your option) any later version.
@c
@c This program is distributed in the hope that it will be useful, but
@c WITHOUT ANY WARRANTY; without even the implied warranty of
@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@c General Public License for more details.
@c
@c You should have received a copy of the GNU General Public License
@c along with this program. If not, see
@c <https://www.gnu.org/licenses/>.
@node Internals,Indices and tables,C++ bindings for libgccjit,Top
@anchor{internals/index doc}@anchor{3ba}@anchor{internals/index internals}@anchor{3bb}
@chapter Internals
@menu
* Working on the JIT library::
* Running the test suite::
* Environment variables::
* Packaging notes::
* Overview of code structure::
* Design notes::
* Submitting patches::
@end menu
@node Working on the JIT library,Running the test suite,,Internals
@anchor{internals/index working-on-the-jit-library}@anchor{3bc}
@section Working on the JIT library
Having checked out the source code (to “src”), you can configure and build
the JIT library like this:
@example
mkdir build
mkdir install
PREFIX=$(pwd)/install
cd build
../src/configure \
--enable-host-shared \
--enable-languages=jit,c++ \
--disable-bootstrap \
--enable-checking=release \
--prefix=$PREFIX
nice make -j4 # altering the "4" to however many cores you have
@end example
This should build a libgccjit.so within jit/build/gcc:
@example
[build] $ file gcc/libgccjit.so*
gcc/libgccjit.so: symbolic link to `libgccjit.so.0'
gcc/libgccjit.so.0: symbolic link to `libgccjit.so.0.0.1'
gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
@end example
Here’s what those configuration options mean:
@geindex command line option; --enable-host-shared
@anchor{internals/index cmdoption-enable-host-shared}@anchor{3bd}
@deffn {Option} @w{-}@w{-}enable@w{-}host@w{-}shared
Configuring with this option means that the compiler is built as
position-independent code, which incurs a slight performance hit,
but it necessary for a shared library.
@end deffn
@geindex command line option; --enable-languages=jit@comma{}c++
@anchor{internals/index cmdoption-enable-languages}@anchor{3be}
@deffn {Option} @w{-}@w{-}enable@w{-}languages=jit,c++
This specifies which frontends to build. The JIT library looks like
a frontend to the rest of the code.
The C++ portion of the JIT test suite requires the C++ frontend to be
enabled at configure-time, or you may see errors like this when
running the test suite:
@example
xgcc: error: /home/david/jit/src/gcc/testsuite/jit.dg/test-quadratic.cc: C++ compiler not installed on this system
c++: error trying to exec 'cc1plus': execvp: No such file or directory
@end example
@end deffn
@geindex command line option; --disable-bootstrap
@anchor{internals/index cmdoption-disable-bootstrap}@anchor{3bf}
@deffn {Option} @w{-}@w{-}disable@w{-}bootstrap
For hacking on the “jit” subdirectory, performing a full
bootstrap can be overkill, since it’s unused by a bootstrap. However,
when submitting patches, you should remove this option, to ensure that
the compiler can still bootstrap itself.
@end deffn
@geindex command line option; --enable-checking=release
@anchor{internals/index cmdoption-enable-checking}@anchor{3c0}
@deffn {Option} @w{-}@w{-}enable@w{-}checking=release
The compile can perform extensive self-checking as it runs, useful when
debugging, but slowing things down.
For maximum speed, configure with @code{--enable-checking=release} to
disable this self-checking.
@end deffn
@node Running the test suite,Environment variables,Working on the JIT library,Internals
@anchor{internals/index running-the-test-suite}@anchor{3c1}
@section Running the test suite
@example
[build] $ cd gcc
[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
@end example
A summary of the tests can then be seen in:
@example
jit/build/gcc/testsuite/jit/jit.sum
@end example
and detailed logs in:
@example
jit/build/gcc/testsuite/jit/jit.log
@end example
The test executables are normally deleted after each test is run. For
debugging, they can be preserved by setting
@geindex PRESERVE_EXECUTABLES
@geindex environment variable; PRESERVE_EXECUTABLES
@code{PRESERVE_EXECUTABLES}
in the environment. If so, they can then be seen as:
@example
jit/build/gcc/testsuite/jit/*.exe
@end example
which can be run independently.
You can compile and run individual tests by passing “jit.exp=TESTNAME” to RUNTESTFLAGS e.g.:
@example
[gcc] $ PRESERVE_EXECUTABLES= \
make check-jit \
RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
@end example
and once a test has been compiled, you can debug it directly:
@example
[gcc] $ PATH=.:$PATH \
LD_LIBRARY_PATH=. \
LIBRARY_PATH=. \
gdb --args \
testsuite/jit/test-factorial.c.exe
@end example
@menu
* Running under valgrind::
@end menu
@node Running under valgrind,,,Running the test suite
@anchor{internals/index running-under-valgrind}@anchor{3c2}
@subsection Running under valgrind
The jit testsuite detects if
@geindex RUN_UNDER_VALGRIND
@geindex environment variable; RUN_UNDER_VALGRIND
@code{RUN_UNDER_VALGRIND} is present in the
environment (with any value). If it is present, it runs the test client
code under valgrind@footnote{https://valgrind.org},
specifcally, the default
memcheck@footnote{https://valgrind.org/docs/manual/mc-manual.html}
tool with
--leak-check=full@footnote{https://valgrind.org/docs/manual/mc-manual.html#opt.leak-check}.
It automatically parses the output from valgrind, injecting XFAIL results if
any issues are found, or PASS results if the output is clean. The output
is saved to @code{TESTNAME.exe.valgrind.txt}.
For example, the following invocation verbosely runs the testcase
@code{test-sum-of-squares.c} under valgrind, showing an issue:
@example
$ RUN_UNDER_VALGRIND= \
make check-jit \
RUNTESTFLAGS="-v -v -v jit.exp=test-sum-of-squares.c"
(...verbose log contains detailed valgrind errors, if any...)
=== jit Summary ===
# of expected passes 28
# of expected failures 2
$ less testsuite/jit/jit.sum
(...other results...)
XFAIL: jit.dg/test-sum-of-squares.c: test-sum-of-squares.c.exe.valgrind.txt: definitely lost: 8 bytes in 1 blocks
XFAIL: jit.dg/test-sum-of-squares.c: test-sum-of-squares.c.exe.valgrind.txt: unsuppressed errors: 1
(...other results...)
$ less testsuite/jit/test-sum-of-squares.c.exe.valgrind.txt
(...shows full valgrind report for this test case...)
@end example
When running under valgrind, it’s best to have configured gcc with
@code{--enable-valgrind-annotations}, which automatically suppresses
various known false positives.
@node Environment variables,Packaging notes,Running the test suite,Internals
@anchor{internals/index environment-variables}@anchor{3c3}
@section Environment variables
When running client code against a locally-built libgccjit, three
environment variables need to be set up:
@geindex environment variable; LD_LIBRARY_PATH
@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{3c4}
@deffn {Environment Variable} LD_LIBRARY_PATH
@quotation
@cite{libgccjit.so} is dynamically linked into client code, so if running
against a locally-built library, @code{LD_LIBRARY_PATH} needs to be set
up appropriately. The library can be found within the “gcc”
subdirectory of the build tree:
@end quotation
@example
$ file libgccjit.so*
libgccjit.so: symbolic link to `libgccjit.so.0'
libgccjit.so.0: symbolic link to `libgccjit.so.0.0.1'
libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, not stripped
@end example
@end deffn
@geindex environment variable; PATH
@anchor{internals/index envvar-PATH}@anchor{3c5}
@deffn {Environment Variable} PATH
The library uses a driver executable for converting from .s assembler
files to .so shared libraries. Specifically, it looks for a name
expanded from
@code{$@{target_noncanonical@}-gcc-$@{gcc_BASEVER@}$@{exeext@}}
such as @code{x86_64-unknown-linux-gnu-gcc-5.0.0}.
Hence @code{PATH} needs to include a directory where the library can
locate this executable.
The executable is normally installed to the installation bindir
(e.g. /usr/bin), but a copy is also created within the “gcc”
subdirectory of the build tree for running the testsuite, and for ease
of development.
@end deffn
@geindex environment variable; LIBRARY_PATH
@anchor{internals/index envvar-LIBRARY_PATH}@anchor{3c6}
@deffn {Environment Variable} LIBRARY_PATH
The driver executable invokes the linker, and the latter needs to locate
support libraries needed by the generated code, or you will see errors
like:
@example
ld: cannot find crtbeginS.o: No such file or directory
ld: cannot find -lgcc
ld: cannot find -lgcc_s
@end example
Hence if running directly from a locally-built copy (without installing),
@code{LIBRARY_PATH} needs to contain the “gcc” subdirectory of the build
tree.
@end deffn
For example, to run a binary that uses the library against a non-installed
build of the library in LIBGCCJIT_BUILD_DIR you need an invocation of the
client code like this, to preprend the dir to each of the environment
variables:
@example
$ LD_LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LD_LIBRARY_PATH) \
PATH=$(LIBGCCJIT_BUILD_DIR):$(PATH) \
LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LIBRARY_PATH) \
./jit-hello-world
hello world
@end example
@node Packaging notes,Overview of code structure,Environment variables,Internals
@anchor{internals/index packaging-notes}@anchor{3c7}
@section Packaging notes
The configure-time option @ref{3bd,,--enable-host-shared} is needed when
building the jit in order to get position-independent code. This will
slow down the regular compiler by a few percent. Hence when packaging gcc
with libgccjit, please configure and build twice:
@quotation
@itemize *
@item
once without @ref{3bd,,--enable-host-shared} for most languages, and
@item
once with @ref{3bd,,--enable-host-shared} for the jit
@end itemize
@end quotation
For example:
@example
# Configure and build with --enable-host-shared
# for the jit:
mkdir configuration-for-jit
pushd configuration-for-jit
$(SRCDIR)/configure \
--enable-host-shared \
--enable-languages=jit \
--prefix=$(DESTDIR)
make
popd
# Configure and build *without* --enable-host-shared
# for maximum speed:
mkdir standard-configuration
pushd standard-configuration
$(SRCDIR)/configure \
--enable-languages=all \
--prefix=$(DESTDIR)
make
popd
# Both of the above are configured to install to $(DESTDIR)
# Install the configuration with --enable-host-shared first
# *then* the one without, so that the faster build
# of "cc1" et al overwrites the slower build.
pushd configuration-for-jit
make install
popd
pushd standard-configuration
make install
popd
@end example
@node Overview of code structure,Design notes,Packaging notes,Internals
@anchor{internals/index overview-of-code-structure}@anchor{3c8}
@section Overview of code structure
The library is implemented in C++. The source files have the @code{.c}
extension for legacy reasons.
@itemize *
@item
@code{libgccjit.cc} implements the API entrypoints. It performs error
checking, then calls into classes of the gcc::jit::recording namespace
within @code{jit-recording.cc} and @code{jit-recording.h}.
@item
The gcc::jit::recording classes (within @code{jit-recording.cc} and
@code{jit-recording.h}) record the API calls that are made:
@quotation
@example
/* Indentation indicates inheritance: */
class context;
class memento;
class string;
class location;
class type;
class function_type;
class compound_type;
class struct_;
class union_;
class vector_type;
class field;
class bitfield;
class fields;
class function;
class block;
class rvalue;
class lvalue;
class local;
class global;
class param;
class base_call;
class function_pointer;
class statement;
class extended_asm;
class case_;
class top_level_asm;
@end example
@end quotation
@item
When the context is compiled, the gcc::jit::playback classes (within
@code{jit-playback.cc} and @code{jit-playback.h}) replay the API calls
within langhook:parse_file:
@quotation
@example
/* Indentation indicates inheritance: */
class context;
class wrapper;
class type;
class compound_type;
class field;
class function;
class block;
class rvalue;
class lvalue;
class param;
class source_file;
class source_line;
class location;
class case_;
@end example
@example
Client Code . Generated . libgccjit.so
. code .
. . JIT API . JIT "Frontend". (libbackend.a)
....................................................................................
│ . . . .
──────────────────────────> . .
. . │ . .
. . V . .
. . ──> libgccjit.cc .
. . │ (error-checking).
. . │ .
. . ──> jit-recording.cc
. . (record API calls)
. . <─────── .
. . │ . .
<─────────────────────────── . .
│ . . . .
│ . . . .
V . . gcc_jit_context_compile .
──────────────────────────> . .
. . │ start of recording::context::compile ()
. . │ . .
. . │ start of playback::context::compile ()
. . │ (create tempdir) .
. . │ . .
. . │ ACQUIRE MUTEX .
. . │ . .
. . V───────────────────────> toplev::main (for now)
. . . . │
. . . . (various code)
. . . . │
. . . . V
. . . <───────────────── langhook:parse_file
. . . │ .
. . . │ (jit_langhook_parse_file)
. . . │ .
..........................................│..................VVVVVVVVVVVVV...
. . . │ . No GC in here
. . . │ jit-playback.cc
. . . │ (playback of API calls)
. . . ───────────────> creation of functions,
. . . . types, expression trees
. . . <──────────────── etc
. . . │(handle_locations: add locations to
. . . │ linemap and associate them with trees)
. . . │ .
. . . │ . No GC in here
..........................................│..................AAAAAAAAAAAAA...
. . . │ for each function
. . . ──> postprocess
. . . │ .
. . . ────────────> cgraph_finalize_function
. . . <────────────
. . . <── .
. . . │ .
. . . ──────────────────> (end of
. . . . │ langhook_parse_file)
. . . . │
. . . . (various code)
. . . . │
. . . . ↓
. . . <───────────────── langhook:write_globals
. . . │ .
. . . │ (jit_langhook_write_globals)
. . . │ .
. . . │ .
. . . ──────────────────> finalize_compilation_unit
. . . . │
. . . . (the middle─end and backend)
. . . . ↓
. . <───────────────────────────── end of toplev::main
. . │ . .
. . V───────────────────────> toplev::finalize
. . . . │ (purge internal state)
. . <──────────────────────── end of toplev::finalize
. . │ . .
. . V─> playback::context::postprocess:
. . │ . .
. . │ (assuming an in-memory compile):
. . │ . .
. . --> Convert assembler to DSO, via embedded
. . copy of driver:
. . driver::main ()
. . invocation of "as"
. . invocation of "ld"
. . driver::finalize ()
. . <----
. . │ . .
. . │ . Load DSO (dlopen "fake.so")
. . │ . .
. . │ . Bundle it up in a jit::result
. . <── . .
. . │ . .
. . │ RELEASE MUTEX .
. . │ . .
. . │ end of playback::context::compile ()
. . │ . .
. . │ playback::context dtor
. . ──> . .
. . │ Normally we cleanup the tempdir here:
. . │ ("fake.so" is unlinked from the
. . │ filesystem at this point)
. . │ If the client code requested debuginfo, the
. . │ cleanup happens later (in gcc_jit_result_release)
. . │ to make it easier on the debugger (see PR jit/64206)
. . <── . .
. . │ . .
. . │ end of recording::context::compile ()
<─────────────────────────── . .
│ . . . .
V . . gcc_jit_result_get_code .
──────────────────────────> . .
. . │ dlsym () within loaded DSO
<─────────────────────────── . .
Get (void*). . . .
│ . . . .
│ Call it . . . .
───────────────> . . .
. │ . . .
. │ . . .
<─────────────── . . .
│ . . . .
etc│ . . . .
│ . . . .
V . . gcc_jit_result_release .
──────────────────────────> . .
. . │ dlclose () the loaded DSO
. . │ (code becomes uncallable)
. . │ . .
. . │ If the client code requested debuginfo, then
. . │ cleanup of the tempdir was delayed.
. . │ If that was the case, clean it up now.
<─────────────────────────── . .
│ . . . .
@end example
@end quotation
@end itemize
Here is a high-level summary from @code{jit-common.h}:
@quotation
In order to allow jit objects to be usable outside of a compile
whilst working with the existing structure of GCC’s code the
C API is implemented in terms of a gcc::jit::recording::context,
which records the calls made to it.
When a gcc_jit_context is compiled, the recording context creates a
playback context. The playback context invokes the bulk of the GCC
code, and within the “frontend” parsing hook, plays back the recorded
API calls, creating GCC tree objects.
So there are two parallel families of classes: those relating to
recording, and those relating to playback:
@itemize *
@item
Visibility: recording objects are exposed back to client code,
whereas playback objects are internal to the library.
@item
Lifetime: recording objects have a lifetime equal to that of the
recording context that created them, whereas playback objects only
exist within the frontend hook.
@item
Memory allocation: recording objects are allocated by the recording
context, and automatically freed by it when the context is released,
whereas playback objects are allocated within the GC heap, and
garbage-collected; they can own GC-references.
@item
Integration with rest of GCC: recording objects are unrelated to the
rest of GCC, whereas playback objects are wrappers around “tree”
instances. Hence you can’t ask a recording rvalue or lvalue what its
type is, whereas you can for a playback rvalue of lvalue (since it
can work with the underlying GCC tree nodes).
@item
Instancing: There can be multiple recording contexts “alive” at once
(albeit it only one compiling at once), whereas there can only be one
playback context alive at one time (since it interacts with the GC).
@end itemize
Ultimately if GCC could support multiple GC heaps and contexts, and
finer-grained initialization, then this recording vs playback
distinction could be eliminated.
During a playback, we associate objects from the recording with
their counterparts during this playback. For simplicity, we store this
within the recording objects, as @code{void *m_playback_obj}, casting it to
the appropriate playback object subclass. For these casts to make
sense, the two class hierarchies need to have the same structure.
Note that the playback objects that @code{m_playback_obj} points to are
GC-allocated, but the recording objects don’t own references:
these associations only exist within a part of the code where
the GC doesn’t collect, and are set back to NULL before the GC can
run.
@end quotation
@anchor{internals/index example-of-log-file}@anchor{5c}
Another way to understand the structure of the code is to enable logging,
via @ref{5b,,gcc_jit_context_set_logfile()}. Here is an example of a log
generated via this call:
@example
JIT: libgccjit (GCC) version 6.0.0 20150803 (experimental) (x86_64-pc-linux-gnu)
JIT: compiled by GNU C version 4.8.3 20140911 (Red Hat 4.8.3-7), GMP version 5.1.2, MPFR version 3.1.2, MPC version 1.0.1
JIT: entering: gcc_jit_context_set_str_option
JIT: GCC_JIT_STR_OPTION_PROGNAME: "./test-hello-world.c.exe"
JIT: exiting: gcc_jit_context_set_str_option
JIT: entering: gcc_jit_context_set_int_option
JIT: GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL: 3
JIT: exiting: gcc_jit_context_set_int_option
JIT: entering: gcc_jit_context_set_bool_option
JIT: GCC_JIT_BOOL_OPTION_DEBUGINFO: true
JIT: exiting: gcc_jit_context_set_bool_option
JIT: entering: gcc_jit_context_set_bool_option
JIT: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE: false
JIT: exiting: gcc_jit_context_set_bool_option
JIT: entering: gcc_jit_context_set_bool_option
JIT: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE: false
JIT: exiting: gcc_jit_context_set_bool_option
JIT: entering: gcc_jit_context_set_bool_option
JIT: GCC_JIT_BOOL_OPTION_SELFCHECK_GC: true
JIT: exiting: gcc_jit_context_set_bool_option
JIT: entering: gcc_jit_context_set_bool_option
JIT: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY: false
JIT: exiting: gcc_jit_context_set_bool_option
JIT: entering: gcc_jit_context_get_type
JIT: exiting: gcc_jit_context_get_type
JIT: entering: gcc_jit_context_get_type
JIT: exiting: gcc_jit_context_get_type
JIT: entering: gcc_jit_context_new_param
JIT: exiting: gcc_jit_context_new_param
JIT: entering: gcc_jit_context_new_function
JIT: exiting: gcc_jit_context_new_function
JIT: entering: gcc_jit_context_new_param
JIT: exiting: gcc_jit_context_new_param
JIT: entering: gcc_jit_context_get_type
JIT: exiting: gcc_jit_context_get_type
JIT: entering: gcc_jit_context_new_function
JIT: exiting: gcc_jit_context_new_function
JIT: entering: gcc_jit_context_new_string_literal
JIT: exiting: gcc_jit_context_new_string_literal
JIT: entering: gcc_jit_function_new_block
JIT: exiting: gcc_jit_function_new_block
JIT: entering: gcc_jit_block_add_comment
JIT: exiting: gcc_jit_block_add_comment
JIT: entering: gcc_jit_context_new_call
JIT: exiting: gcc_jit_context_new_call
JIT: entering: gcc_jit_block_add_eval
JIT: exiting: gcc_jit_block_add_eval
JIT: entering: gcc_jit_block_end_with_void_return
JIT: exiting: gcc_jit_block_end_with_void_return
JIT: entering: gcc_jit_context_dump_reproducer_to_file
JIT: entering: void gcc::jit::recording::context::dump_reproducer_to_file(const char*)
JIT: exiting: void gcc::jit::recording::context::dump_reproducer_to_file(const char*)
JIT: exiting: gcc_jit_context_dump_reproducer_to_file
JIT: entering: gcc_jit_context_compile
JIT: in-memory compile of ctxt: 0x1283e20
JIT: entering: gcc::jit::result* gcc::jit::recording::context::compile()
JIT: GCC_JIT_STR_OPTION_PROGNAME: "./test-hello-world.c.exe"
JIT: GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL: 3
JIT: GCC_JIT_BOOL_OPTION_DEBUGINFO: true
JIT: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE: false
JIT: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE: false
JIT: GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE: false
JIT: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY: false
JIT: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING: false
JIT: GCC_JIT_BOOL_OPTION_SELFCHECK_GC: true
JIT: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES: false
JIT: gcc_jit_context_set_bool_allow_unreachable_blocks: false
JIT: gcc_jit_context_set_bool_use_external_driver: false
JIT: entering: void gcc::jit::recording::context::validate()
JIT: exiting: void gcc::jit::recording::context::validate()
JIT: entering: gcc::jit::playback::context::context(gcc::jit::recording::context*)
JIT: exiting: gcc::jit::playback::context::context(gcc::jit::recording::context*)
JIT: entering: gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
JIT: exiting: gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
JIT: entering: void gcc::jit::playback::context::compile()
JIT: entering: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
JIT: exiting: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
JIT: entering: bool gcc::jit::tempdir::create()
JIT: m_path_template: /tmp/libgccjit-XXXXXX
JIT: m_path_tempdir: /tmp/libgccjit-CKq1M9
JIT: exiting: bool gcc::jit::tempdir::create()
JIT: entering: void gcc::jit::playback::context::acquire_mutex()
JIT: exiting: void gcc::jit::playback::context::acquire_mutex()
JIT: entering: void gcc::jit::playback::context::make_fake_args(vec<char*>*, const char*, vec<gcc::jit::recording::requested_dump>*)
JIT: reusing cached configure-time options
JIT: configure_time_options[0]: -mtune=generic
JIT: configure_time_options[1]: -march=x86-64
JIT: exiting: void gcc::jit::playback::context::make_fake_args(vec<char*>*, const char*, vec<gcc::jit::recording::requested_dump>*)
JIT: entering: toplev::main
JIT: argv[0]: ./test-hello-world.c.exe
JIT: argv[1]: /tmp/libgccjit-CKq1M9/fake.c
JIT: argv[2]: -fPIC
JIT: argv[3]: -O3
JIT: argv[4]: -g
JIT: argv[5]: -quiet
JIT: argv[6]: --param
JIT: argv[7]: ggc-min-expand=0
JIT: argv[8]: --param
JIT: argv[9]: ggc-min-heapsize=0
JIT: argv[10]: -mtune=generic
JIT: argv[11]: -march=x86-64
JIT: entering: bool jit_langhook_init()
JIT: exiting: bool jit_langhook_init()
JIT: entering: void gcc::jit::playback::context::replay()
JIT: entering: void gcc::jit::recording::context::replay_into(gcc::jit::replayer*)
JIT: exiting: void gcc::jit::recording::context::replay_into(gcc::jit::replayer*)
JIT: entering: void gcc::jit::recording::context::disassociate_from_playback()
JIT: exiting: void gcc::jit::recording::context::disassociate_from_playback()
JIT: entering: void gcc::jit::playback::context::handle_locations()
JIT: exiting: void gcc::jit::playback::context::handle_locations()
JIT: entering: void gcc::jit::playback::function::build_stmt_list()
JIT: exiting: void gcc::jit::playback::function::build_stmt_list()
JIT: entering: void gcc::jit::playback::function::build_stmt_list()
JIT: exiting: void gcc::jit::playback::function::build_stmt_list()
JIT: entering: void gcc::jit::playback::function::postprocess()
JIT: exiting: void gcc::jit::playback::function::postprocess()
JIT: entering: void gcc::jit::playback::function::postprocess()
JIT: exiting: void gcc::jit::playback::function::postprocess()
JIT: exiting: void gcc::jit::playback::context::replay()
JIT: exiting: toplev::main
JIT: entering: void gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
JIT: exiting: void gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
JIT: entering: toplev::finalize
JIT: exiting: toplev::finalize
JIT: entering: virtual void gcc::jit::playback::compile_to_memory::postprocess(const char*)
JIT: entering: void gcc::jit::playback::context::convert_to_dso(const char*)
JIT: entering: void gcc::jit::playback::context::invoke_driver(const char*, const char*, const char*, timevar_id_t, bool, bool)
JIT: entering: void gcc::jit::playback::context::add_multilib_driver_arguments(vec<char*>*)
JIT: exiting: void gcc::jit::playback::context::add_multilib_driver_arguments(vec<char*>*)
JIT: argv[0]: x86_64-unknown-linux-gnu-gcc-6.0.0
JIT: argv[1]: -m64
JIT: argv[2]: -shared
JIT: argv[3]: /tmp/libgccjit-CKq1M9/fake.s
JIT: argv[4]: -o
JIT: argv[5]: /tmp/libgccjit-CKq1M9/fake.so
JIT: argv[6]: -fno-use-linker-plugin
JIT: entering: void gcc::jit::playback::context::invoke_embedded_driver(const vec<char*>*)
JIT: exiting: void gcc::jit::playback::context::invoke_embedded_driver(const vec<char*>*)
JIT: exiting: void gcc::jit::playback::context::invoke_driver(const char*, const char*, const char*, timevar_id_t, bool, bool)
JIT: exiting: void gcc::jit::playback::context::convert_to_dso(const char*)
JIT: entering: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
JIT: GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir to jit::result
JIT: entering: gcc::jit::result::result(gcc::jit::logger*, void*, gcc::jit::tempdir*)
JIT: exiting: gcc::jit::result::result(gcc::jit::logger*, void*, gcc::jit::tempdir*)
JIT: exiting: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
JIT: exiting: virtual void gcc::jit::playback::compile_to_memory::postprocess(const char*)
JIT: entering: void gcc::jit::playback::context::release_mutex()
JIT: exiting: void gcc::jit::playback::context::release_mutex()
JIT: exiting: void gcc::jit::playback::context::compile()
JIT: entering: gcc::jit::playback::context::~context()
JIT: exiting: gcc::jit::playback::context::~context()
JIT: exiting: gcc::jit::result* gcc::jit::recording::context::compile()
JIT: gcc_jit_context_compile: returning (gcc_jit_result *)0x12f75d0
JIT: exiting: gcc_jit_context_compile
JIT: entering: gcc_jit_result_get_code
JIT: locating fnname: hello_world
JIT: entering: void* gcc::jit::result::get_code(const char*)
JIT: exiting: void* gcc::jit::result::get_code(const char*)
JIT: gcc_jit_result_get_code: returning (void *)0x7ff6b8cd87f0
JIT: exiting: gcc_jit_result_get_code
JIT: entering: gcc_jit_context_release
JIT: deleting ctxt: 0x1283e20
JIT: entering: gcc::jit::recording::context::~context()
JIT: exiting: gcc::jit::recording::context::~context()
JIT: exiting: gcc_jit_context_release
JIT: entering: gcc_jit_result_release
JIT: deleting result: 0x12f75d0
JIT: entering: virtual gcc::jit::result::~result()
JIT: entering: gcc::jit::tempdir::~tempdir()
JIT: unlinking .s file: /tmp/libgccjit-CKq1M9/fake.s
JIT: unlinking .so file: /tmp/libgccjit-CKq1M9/fake.so
JIT: removing tempdir: /tmp/libgccjit-CKq1M9
JIT: exiting: gcc::jit::tempdir::~tempdir()
JIT: exiting: virtual gcc::jit::result::~result()
JIT: exiting: gcc_jit_result_release
JIT: gcc::jit::logger::~logger()
@end example
@node Design notes,Submitting patches,Overview of code structure,Internals
@anchor{internals/index design-notes}@anchor{3c9}
@section Design notes
It should not be possible for client code to cause an internal compiler
error. If this @emph{does} happen, the root cause should be isolated (perhaps
using @ref{5d,,gcc_jit_context_dump_reproducer_to_file()}) and the cause
should be rejected via additional checking. The checking ideally should
be within the libgccjit API entrypoints in libgccjit.cc, since this is as
close as possible to the error; failing that, a good place is within
@code{recording::context::validate ()} in jit-recording.cc.
@node Submitting patches,,Design notes,Internals
@anchor{internals/index submitting-patches}@anchor{3ca}
@section Submitting patches
Please read the contribution guidelines for gcc at
@indicateurl{https://gcc.gnu.org/contribute.html}.
Patches for the jit should be sent to both the
@email{gcc-patches@@gcc.gnu.org} and @email{jit@@gcc.gnu.org} mailing lists,
with “jit” and “PATCH” in the Subject line.
You don’t need to do a full bootstrap for code that just touches the
@code{jit} and @code{testsuite/jit.dg} subdirectories. However, please run
@code{make check-jit} before submitting the patch, and mention the results
in your email (along with the host triple that the tests were run on).
A good patch should contain the information listed in the
gcc contribution guide linked to above; for a @code{jit} patch, the patch
shold contain:
@quotation
@itemize *
@item
the code itself (for example, a new API entrypoint will typically
touch @code{libgccjit.h} and @code{.c}, along with support code in
@code{jit-recording.[ch]} and @code{jit-playback.[ch]} as appropriate)
@item
test coverage
@item
documentation for the C API
@item
documentation for the C++ API
@end itemize
@end quotation
A patch that adds new API entrypoints should also contain:
@quotation
@itemize *
@item
a feature macro in @code{libgccjit.h} so that client code that doesn’t
use a “configure” mechanism can still easily detect the presence of
the entrypoint. See e.g. @code{LIBGCCJIT_HAVE_SWITCH_STATEMENTS} (for
a category of entrypoints) and
@code{LIBGCCJIT_HAVE_gcc_jit_context_set_bool_allow_unreachable_blocks}
(for an individual entrypoint).
@item
a new ABI tag containing the new symbols (in @code{libgccjit.map}), so
that we can detect client code that uses them
@item
Support for @ref{5d,,gcc_jit_context_dump_reproducer_to_file()}. Most
jit testcases attempt to dump their contexts to a .c file; @code{jit.exp}
then sanity-checks the generated c by compiling them (though
not running them). A new API entrypoint
needs to “know” how to write itself back out to C (by implementing
@code{gcc::jit::recording::memento::write_reproducer} for the appropriate
@code{memento} subclass).
@item
C++ bindings for the new entrypoints (see @code{libgccjit++.h}); ideally
with test coverage, though the C++ API test coverage is admittedly
spotty at the moment
@item
documentation for the new C entrypoints
@item
documentation for the new C++ entrypoints
@item
documentation for the new ABI tag (see @code{topics/compatibility.rst}).
@end itemize
@end quotation
Depending on the patch you can either extend an existing test case, or
add a new test case. If you add an entirely new testcase: @code{jit.exp}
expects jit testcases to begin with @code{test-}, or @code{test-error-} (for a
testcase that generates an error on a @ref{8,,gcc_jit_context}).
Every new testcase that doesn’t generate errors should also touch
@code{gcc/testsuite/jit.dg/all-non-failing-tests.h}:
@quotation
@itemize *
@item
Testcases that don’t generate errors should ideally be added to the
@code{testcases} array in that file; this means that, in addition
to being run standalone, they also get run within
@code{test-combination.c} (which runs all successful tests inside one
big @ref{8,,gcc_jit_context}), and @code{test-threads.c} (which runs all
successful tests in one process, each one running in a different
thread on a different @ref{8,,gcc_jit_context}).
@cartouche
@quotation Note
Given that exported functions within a @ref{8,,gcc_jit_context}
must have unique names, and most testcases are run within
@code{test-combination.c}, this means that every jit-compiled test
function typically needs a name that’s unique across the entire
test suite.
@end quotation
@end cartouche
@item
Testcases that aren’t to be added to the @code{testcases} array should
instead add a comment to the file clarifying why they’re not in that
array. See the file for examples.
@end itemize
@end quotation
Typically a patch that touches the .rst documentation will also need the
texinfo to be regenerated. You can do this with
Sphinx 1.0@footnote{https://sphinx-doc.org/} or later by
running @code{make texinfo} within @code{SRCDIR/gcc/jit/docs}. Don’t do this
within the patch sent to the mailing list; it can often be relatively
large and inconsequential (e.g. anchor renumbering), rather like generated
“configure” changes from configure.ac. You can regenerate it when
committing to svn.
@node Indices and tables,Index,Internals,Top
@anchor{index indices-and-tables}@anchor{3cb}
@unnumbered Indices and tables
@itemize *
@item
genindex
@item
modindex
@item
search
@end itemize
@c Some notes:
@c
@c The Sphinx C domain appears to lack explicit support for enum values,
@c so I've been using :c:macro: for them.
@c
@c See https://sphinx-doc.org/domains.html#the-c-domain
@node Index,,Indices and tables,Top
@unnumbered Index
@printindex ge
@c %**end of body
@bye