gcc/gcc/jit/docs/_build/texinfo/libgccjit.texi

6538 lines
163 KiB
Plaintext

\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename libgccjit.info
@documentencoding UTF-8
@ifinfo
@*Generated by Sphinx 1.1.3.@*
@end ifinfo
@settitle libgccjit Documentation
@defindex ge
@paragraphindent 2
@exampleindent 4
@afourlatex
@dircategory Miscellaneous
@direntry
* libgccjit: (libgccjit.info). One line description of project.
@end direntry
@c %**end of header
@copying
@quotation
libgccjit 5.0.0 (experimental 20141110), November 10, 2014
David Malcolm
Copyright @copyright{} 2014, Free Software Foundation
@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 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 <http://www.gnu.org/licenses/>.
Contents:
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@menu
* Tutorial::
* Topic Reference::
* 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 2: Creating a trivial machine code function
* 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::
Topic Reference
* Compilation contexts::
* Objects::
* Types::
* Expressions::
* Creating and using functions::
* Source Locations::
* Compilation results::
Compilation contexts
* Lifetime-management::
* Thread-safety::
* Error-handling::
* Debugging::
* Options: Options<2>.
Options
* String Options::
* Boolean options::
* Integer options::
Types
* Standard types::
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Structures and unions::
Expressions
* Rvalues::
* Lvalues::
* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
Rvalues
* Simple expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
* Type-coercion::
Lvalues
* Global variables::
Creating and using functions
* Params::
* Functions::
* Blocks::
* Statements::
Source Locations
* Faking it::
Internals
* Working on the JIT library::
* Running the test suite::
* Environment variables::
* Overview of code structure::
@end detailmenu
@end menu
@node Tutorial,Topic Reference,Top,Top
@anchor{intro/index libgccjit}@anchor{1}@anchor{intro/index doc}@anchor{2}@anchor{intro/index tutorial}@anchor{3}
@chapter Tutorial
@c Copyright (C) 2014 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 <http://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.
@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 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
@noindent
@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
@noindent
You should then be able to run the built program:
@example
$ ./tut01-hello-world
hello world
@end example
@noindent
@c Copyright (C) 2014 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 <http://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
@noindent
How can we construct this at run-time using libgccjit?
First we need to include the relevant header:
@example
#include <libgccjit.h>
@end example
@noindent
All state associated with compilation is associated with a
@pxref{8,,gcc_jit_context *}.
Create one using @pxref{9,,gcc_jit_context_acquire()}:
@example
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
@end example
@noindent
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 @pxref{a,,gcc_jit_type *}, using
@pxref{b,,gcc_jit_context_get_type()}:
@example
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
@end example
@noindent
@pxref{a,,gcc_jit_type *} is an example of a "contextual" object: every
entity in the API is associated with a @pxref{8,,gcc_jit_context *}.
Memory management is easy: all such "contextual" objects are automatically
cleaned up for you when the context is released, using
@pxref{c,,gcc_jit_context_release()}:
@example
gcc_jit_context_release (ctxt);
@end example
@noindent
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
@noindent
There are casting methods for upcasting from subclasses to parent classes.
For example, @pxref{d,,gcc_jit_type_as_object()}:
@example
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
@end example
@noindent
One thing you can do with a @pxref{e,,gcc_jit_object *} is
to ask it for a human-readable description, using
@pxref{f,,gcc_jit_object_get_debug_string()}:
@example
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
@end example
@noindent
giving this text on stdout:
@example
obj: int
@end example
@noindent
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 @pxref{10,,gcc_jit_context_new_param()}:
@example
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
@end example
@noindent
Now we can create the function, using
@pxref{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
@noindent
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
@noindent
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
We can build the expression using @pxref{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
@noindent
A @pxref{13,,gcc_jit_rvalue *} is another example of a
@pxref{e,,gcc_jit_object *} subclass. We can upcast it using
@pxref{14,,gcc_jit_rvalue_as_object()} and as before print it with
@pxref{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
@noindent
giving this output:
@example
expr: i * i
@end example
@noindent
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
@noindent
OK, we've populated the context. We can now compile it using
@pxref{15,,gcc_jit_context_compile()}:
@example
gcc_jit_result *result;
result = gcc_jit_context_compile (ctxt);
@end example
@noindent
and get a @pxref{16,,gcc_jit_result *}.
We can now use @pxref{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
@noindent
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
@noindent
@example
result: 25
@end example
@noindent
@menu
* Options::
* Full example::
@end menu
@node Options,Full example,,Tutorial part 2 Creating a trivial machine code function
@anchor{intro/tutorial02 options}@anchor{18}
@subsection Options
To get more information on what's going on, you can set debugging flags
on the context using @pxref{19,,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 @pxref{1a,,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
@noindent
@example
square (signed int i)
@{
signed int D.260;
entry:
D.260 = i * i;
return D.260;
@}
@end example
@noindent
We can see the generated machine code in assembler form (on stderr) by
setting @pxref{1b,,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
@noindent
@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
@noindent
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
@pxref{1c,,gcc_jit_context_set_int_option()} with
@pxref{1d,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
@end example
@noindent
@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
@noindent
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{1e}
@subsection Full example
Here's what the above looks like as a complete program:
@quotation
@example
/* Usage example for libgccjit.so
Copyright (C) 2014 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;
@}
/* 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", square (5));
error:
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
return 0;
@}
@end example
@noindent
@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
@noindent
@c Copyright (C) 2014 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 <http://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 tutorial-part-3-loops-and-variables}@anchor{1f}@anchor{intro/tutorial03 doc}@anchor{20}
@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
@noindent
@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
@noindent
@end quotation
Here's what the final control flow graph will look like:
@quotation
@float Figure
@image{sum-of-squares,,,image of a control flow graph,png}
@end float
@end quotation
As before, we include the libgccjit header and make a
@pxref{8,,gcc_jit_context *}.
@example
#include <libgccjit.h>
void test (void)
@{
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
@end example
@noindent
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
@noindent
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
@noindent
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
@noindent
@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{21}
@subsection Expressions: lvalues and rvalues
The base class of expression is the @pxref{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
@pxref{a,,gcc_jit_type *}.
Anothe important class is @pxref{22,,gcc_jit_lvalue *}.
A @pxref{22,,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
@noindent
Note that @pxref{22,,gcc_jit_lvalue *} is a subclass of
@pxref{13,,gcc_jit_rvalue *}, where in an assignment of the form:
@example
LVALUE_A = LVALUE_B;
@end example
@noindent
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
@noindent
which is a @pxref{13,,gcc_jit_rvalue *}, and the various function
parameters: @cite{param_i} and @cite{param_n}, instances of
@pxref{23,,gcc_jit_param *}, which is a subclass of
@pxref{22,,gcc_jit_lvalue *} (and, in turn, of @pxref{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 @pxref{24,,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
@noindent
These are instances of @pxref{22,,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
@noindent
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{25}
@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 @pxref{26,,gcc_jit_block *} instances within the
@pxref{27,,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
@noindent
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
@pxref{28,,gcc_jit_block_add_assignment()} to add
an assignment statement, and using @pxref{29,,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
@noindent
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
@noindent
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
@pxref{13,,gcc_jit_rvalue *}, in this case the comparison of @cite{i} and @cite{n}.
We build the comparison using @pxref{2a,,gcc_jit_context_new_comparison()}:
@example
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
@noindent
and can then use this to add @cite{b_loop_cond}'s sole statement, via
@pxref{2b,,gcc_jit_block_end_with_conditional()}:
@example
gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
@end example
@noindent
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
@pxref{2c,,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
@noindent
The @cite{i++} can be thought of as @cite{i += 1}, and can thus be handled in
a similar way. We use @pxref{2d,,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
@noindent
@cartouche
@quotation Note
For numeric constants other than 0 or 1, we could use
@pxref{2e,,gcc_jit_context_new_rvalue_from_int()} and
@pxref{2f,,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
@noindent
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
@noindent
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
@noindent
@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
@noindent
@example
result: 285
@end example
@noindent
@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{30}
@subsection Visualizing the control flow graph
You can see the control flow graph of a function using
@pxref{31,,gcc_jit_function_dump_to_dot()}:
@example
gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
@end example
@noindent
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
@noindent
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{sum-of-squares,,,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{32}
@subsection Full example
@quotation
@example
/* Usage example for libgccjit.so
Copyright (C) 2014 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
@noindent
@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
@noindent
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Tutorial part 4 Adding JIT-compilation to a toy interpreter,,Tutorial part 3 Loops and variables,Tutorial
@anchor{intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{33}@anchor{intro/tutorial04 doc}@anchor{34}
@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{35}
@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
@noindent
@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
@noindent
@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{36}
@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_func) (int);
@end example
@noindent
@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
@noindent
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
@noindent
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
@noindent
@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{37}
@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
@noindent
@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
@noindent
@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
@noindent
@end quotation
We will support single-stepping through the generated code in the
debugger, so we need to create @pxref{38,,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
@noindent
@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
@noindent
@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
@noindent
@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{39}
@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
@noindent
@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[16];
sprintf (buf, "instr%i", pc);
state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
@}
@end example
@noindent
@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
@noindent
@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
@noindent
@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
@noindent
@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
@pxref{3a,,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
@noindent
@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
@noindent
@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
@noindent
@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{3b}
@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 @pxref{31,,gcc_jit_function_dump_to_dot()}:
@example
gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot");
@end example
@noindent
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{factorial,,,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{3c}
@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
@example
gcc_jit_result *result = gcc_jit_context_compile (state.ctxt);
gcc_jit_context_release (state.ctxt);
return (toyvm_compiled_func)gcc_jit_result_get_code (result,
funcname);
@end example
@noindent
@end quotation
We can now run the result:
@quotation
@example
toyvm_compiled_func code = toyvm_function_compile (fn);
printf ("compiler result: %d\n",
code (atoi (argv[2])));
@end example
@noindent
@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{3d}
@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 @pxref{3e,,gcc_jit_context_new_location()} and using the
results.
@item
Enable the generation of debugging information, by setting
@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@pxref{8,,gcc_jit_context} via
@pxref{19,,gcc_jit_context_set_bool_option()}:
@example
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DEBUGINFO,
1);
@end example
@noindent
@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
@noindent
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
@noindent
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
@noindent
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{40}
@subsection Examining the generated code
How good is the optimized code?
We can turn up optimizations, by calling
@pxref{1c,,gcc_jit_context_set_int_option()} with
@pxref{1d,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
@end example
@noindent
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
@noindent
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
@noindent
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
@noindent
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
@noindent
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
@noindent
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
@noindent
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{41}
@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
@noindent
@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{42}
@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
@noindent
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
@noindent
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
@noindent
@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
@noindent
We can perhaps better see the code by turning off
@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to suppress all those @code{DEBUG}
statements, giving:
@example
$ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
@end example
@noindent
@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
@noindent
Note in the above how all the @pxref{26,,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{43}
@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
@noindent
@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
@noindent
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
@noindent
@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
@noindent
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
@noindent
@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
@noindent
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
@noindent
@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
@noindent
@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{44}
@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
@noindent
@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
@noindent
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Topic Reference,Internals,Tutorial,Top
@anchor{topics/index doc}@anchor{45}@anchor{topics/index topic-reference}@anchor{46}
@chapter Topic Reference
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@menu
* Compilation contexts::
* Objects::
* Types::
* Expressions::
* Creating and using functions::
* Source Locations::
* Compilation results::
Compilation contexts
* Lifetime-management::
* Thread-safety::
* Error-handling::
* Debugging::
* Options: Options<2>.
Options
* String Options::
* Boolean options::
* Integer options::
Types
* Standard types::
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Structures and unions::
Expressions
* Rvalues::
* Lvalues::
* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
Rvalues
* Simple expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
* Type-coercion::
Lvalues
* Global variables::
Creating and using functions
* Params::
* Functions::
* Blocks::
* Statements::
Source Locations
* Faking it::
@end menu
@node Compilation contexts,Objects,,Topic Reference
@anchor{topics/contexts compilation-contexts}@anchor{47}@anchor{topics/contexts doc}@anchor{48}
@section Compilation contexts
@geindex gcc_jit_context (C type)
@anchor{topics/contexts gcc_jit_context}@anchor{8}
@deffn {C Type} gcc_jit_context
@end deffn
The top-level of the API is the @pxref{8,,gcc_jit_context} type.
A @pxref{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 @pxref{15,,gcc_jit_context_compile()} on it gives you a
@pxref{16,,gcc_jit_result}.
@menu
* Lifetime-management::
* Thread-safety::
* Error-handling::
* Debugging::
* Options: Options<2>.
@end menu
@node Lifetime-management,Thread-safety,,Compilation contexts
@anchor{topics/contexts lifetime-management}@anchor{49}
@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 gcc_jit_context_acquire}@anchor{9}
@deffn {C Function} gcc_jit_context *gcc_jit_context_acquire (void)
This function acquires a new @pxref{e,,gcc_jit_object *} 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 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 @pxref{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
@noindent
@end deffn
@geindex gcc_jit_context_new_child_context (C function)
@anchor{topics/contexts gcc_jit_context_new_child_context}@anchor{4a}
@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,Lifetime-management,Compilation contexts
@anchor{topics/contexts thread-safety}@anchor{4b}
@subsection Thread-safety
Instances of @pxref{e,,gcc_jit_object *} created via
@pxref{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 @pxref{4a,,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,Debugging,Thread-safety,Compilation contexts
@anchor{topics/contexts error-handling}@anchor{4c}
@subsection Error-handling
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
@pxref{4d,,gcc_jit_context_get_first_error()}.
@geindex gcc_jit_context_get_first_error (C function)
@anchor{topics/contexts gcc_jit_context_get_first_error}@anchor{4d}
@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
@node Debugging,Options<2>,Error-handling,Compilation contexts
@anchor{topics/contexts debugging}@anchor{4e}
@subsection Debugging
@geindex gcc_jit_context_dump_to_file (C function)
@anchor{topics/contexts gcc_jit_context_dump_to_file}@anchor{4f}
@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 @pxref{38,,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
@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to allow stepping through the
code in a debugger.
@end deffn
@node Options<2>,,Debugging,Compilation contexts
@anchor{topics/contexts options}@anchor{50}
@subsection Options
@menu
* String Options::
* Boolean options::
* Integer options::
@end menu
@node String Options,Boolean options,,Options<2>
@anchor{topics/contexts string-options}@anchor{51}
@subsubsection String Options
@geindex gcc_jit_context_set_str_option (C function)
@anchor{topics/contexts gcc_jit_context_set_str_option}@anchor{52}
@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 gcc_jit_str_option}@anchor{53}
@deffn {C Type} enum gcc_jit_str_option
@end deffn
There is currently just one string option:
@geindex GCC_JIT_STR_OPTION_PROGNAME (C macro)
@anchor{topics/contexts GCC_JIT_STR_OPTION_PROGNAME}@anchor{54}
@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{55}
@subsubsection Boolean options
@geindex gcc_jit_context_set_bool_option (C function)
@anchor{topics/contexts gcc_jit_context_set_bool_option}@anchor{19}
@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 gcc_jit_bool_option}@anchor{56}
@deffn {C Type} enum gcc_jit_bool_option
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DEBUGINFO (C macro)
@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DEBUGINFO}@anchor{3f}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DEBUGINFO
If true, @pxref{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
@pxref{38,,gcc_jit_location} instances).
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE (C macro)
@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}@anchor{57}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
If true, @pxref{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
@noindent
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE (C macro)
@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE}@anchor{1a}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
If true, @pxref{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
@noindent
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE (C macro)
@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE}@anchor{1b}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
If true, @pxref{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
@noindent
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_SUMMARY (C macro)
@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_SUMMARY}@anchor{58}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
If true, @pxref{15,,gcc_jit_context_compile()} will print information to stderr
on the actions it is performing, followed by a profile showing
the time taken and memory usage of each phase.
@end deffn
@geindex GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING (C macro)
@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING}@anchor{59}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
If true, @pxref{15,,gcc_jit_context_compile()} will dump copious
amount of information on what it's doing to various
files within a temporary directory. Use
@pxref{5a,,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 GCC_JIT_BOOL_OPTION_SELFCHECK_GC}@anchor{5b}
@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 GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES}@anchor{5a}
@deffn {C Macro} GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
If true, the @pxref{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
@node Integer options,,Boolean options,Options<2>
@anchor{topics/contexts integer-options}@anchor{5c}
@subsubsection Integer options
@geindex gcc_jit_context_set_int_option (C function)
@anchor{topics/contexts gcc_jit_context_set_int_option}@anchor{1c}
@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 gcc_jit_int_option}@anchor{5d}
@deffn {C Type} enum gcc_jit_int_option
@end deffn
There is currently just one integer option:
@geindex GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL (C macro)
@anchor{topics/contexts GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}@anchor{1d}
@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
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Objects,Types,Compilation contexts,Topic Reference
@anchor{topics/objects objects}@anchor{5e}@anchor{topics/objects doc}@anchor{5f}
@section Objects
@geindex gcc_jit_object (C type)
@anchor{topics/objects gcc_jit_object}@anchor{e}
@deffn {C Type} gcc_jit_object
@end deffn
Almost every entity in the API (with the exception of
@pxref{8,,gcc_jit_context *} and @pxref{16,,gcc_jit_result *}) is a
"contextual" object, a @pxref{e,,gcc_jit_object *}
A JIT object:
@quotation
@itemize *
@item
is associated with a @pxref{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
@end example
@noindent
There are casting methods for upcasting from subclasses to parent classes.
For example, @pxref{d,,gcc_jit_type_as_object()}:
@example
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
@end example
@noindent
The object "base class" has the following operations:
@geindex gcc_jit_object_get_context (C function)
@anchor{topics/objects gcc_jit_object_get_context}@anchor{60}
@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 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
@noindent
might give this text on stdout:
@example
obj: 4.0 * (float)i
@end example
@noindent
@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 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 <http://www.gnu.org/licenses/>.
@node Types,Expressions,Objects,Topic Reference
@anchor{topics/types doc}@anchor{61}@anchor{topics/types types}@anchor{62}
@section Types
@geindex gcc_jit_type (C type)
@anchor{topics/types 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 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
@pxref{b,,gcc_jit_context_get_type()}:
@example
gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
@end example
@noindent
See @pxref{b,,gcc_jit_context_get_type()} for the available types.
@item
derived types can be accessed by using functions such as
@pxref{63,,gcc_jit_type_get_pointer()} and @pxref{64,,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
@noindent
@item
by creating structures (see below).
@end itemize
@menu
* Standard types::
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Structures and unions::
@end menu
@node Standard types,Pointers const and volatile,,Types
@anchor{topics/types standard-types}@anchor{65}
@subsection Standard types
@geindex gcc_jit_context_get_type (C function)
@anchor{topics/types 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 {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {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_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 *)}
@end multitable
@end deffn
@geindex gcc_jit_context_get_int_type (C function)
@anchor{topics/types gcc_jit_context_get_int_type}@anchor{66}
@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,Structures and unions,Standard types,Types
@anchor{topics/types pointers-const-and-volatile}@anchor{67}
@subsection Pointers, @cite{const}, and @cite{volatile}
@geindex gcc_jit_type_get_pointer (C function)
@anchor{topics/types gcc_jit_type_get_pointer}@anchor{63}
@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 gcc_jit_type_get_const}@anchor{64}
@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 gcc_jit_type_get_volatile}@anchor{68}
@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 gcc_jit_context_new_array_type}@anchor{69}
@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 type "T", get type "T[N]" (for a constant N).
@end deffn
@node Structures and unions,,Pointers const and volatile,Types
@anchor{topics/types structures-and-unions}@anchor{6a}
@subsection Structures and unions
@geindex gcc_jit_struct (C type)
@anchor{topics/types gcc_jit_struct}@anchor{6b}
@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 gcc_jit_field}@anchor{6c}
@deffn {C Type} gcc_jit_field
@end deffn
A field within a @pxref{6b,,gcc_jit_struct}.
You can model C @cite{struct} types by creating @pxref{6b,,gcc_jit_struct *} and
@pxref{6c,,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
@noindent
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
@noindent
@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
@noindent
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
@noindent
@end itemize
@geindex gcc_jit_context_new_field (C function)
@anchor{topics/types gcc_jit_context_new_field}@anchor{6d}
@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.
@end deffn
@geindex gcc_jit_field_as_object (C function)
@anchor{topics/types gcc_jit_field_as_object}@anchor{6e}
@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 gcc_jit_context_new_struct_type}@anchor{6f}
@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.
@end quotation
@end deffn
@geindex gcc_jit_context_new_opaque_struct (C function)
@anchor{topics/types gcc_jit_context_new_opaque_struct}@anchor{70}
@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
@pxref{71,,gcc_jit_struct_set_fields()}.
@end deffn
@geindex gcc_jit_struct_as_type (C function)
@anchor{topics/types gcc_jit_struct_as_type}@anchor{72}
@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 gcc_jit_struct_set_fields}@anchor{71}
@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
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Expressions,Creating and using functions,Types,Topic Reference
@anchor{topics/expressions expressions}@anchor{73}@anchor{topics/expressions doc}@anchor{74}
@section Expressions
@menu
* Rvalues::
* Lvalues::
* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
Rvalues
* Simple expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
* Type-coercion::
Lvalues
* Global variables::
@end menu
@node Rvalues,Lvalues,,Expressions
@anchor{topics/expressions rvalues}@anchor{75}
@subsection Rvalues
@geindex gcc_jit_rvalue (C type)
@anchor{topics/expressions gcc_jit_rvalue}@anchor{13}
@deffn {C Type} gcc_jit_rvalue
@end deffn
A @pxref{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 gcc_jit_rvalue_get_type}@anchor{76}
@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 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::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
* Type-coercion::
@end menu
@node Simple expressions,Unary Operations,,Rvalues
@anchor{topics/expressions simple-expressions}@anchor{77}
@subsubsection Simple expressions
@geindex gcc_jit_context_new_rvalue_from_int (C function)
@anchor{topics/expressions gcc_jit_context_new_rvalue_from_int}@anchor{2e}
@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 value.
@end deffn
@geindex gcc_jit_context_zero (C function)
@anchor{topics/expressions gcc_jit_context_zero}@anchor{29}
@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
@noindent
@end deffn
@geindex gcc_jit_context_one (C function)
@anchor{topics/expressions gcc_jit_context_one}@anchor{2d}
@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
zero. Essentially this is just a shortcut for:
@example
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
@end example
@noindent
@end deffn
@geindex gcc_jit_context_new_rvalue_from_double (C function)
@anchor{topics/expressions gcc_jit_context_new_rvalue_from_double}@anchor{2f}
@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 value.
@end deffn
@geindex gcc_jit_context_new_rvalue_from_ptr (C function)
@anchor{topics/expressions gcc_jit_context_new_rvalue_from_ptr}@anchor{78}
@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 gcc_jit_context_null}@anchor{79}
@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
@noindent
@end deffn
@geindex gcc_jit_context_new_string_literal (C function)
@anchor{topics/expressions gcc_jit_context_new_string_literal}@anchor{7a}
@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}.
@end deffn
@node Unary Operations,Binary Operations,Simple expressions,Rvalues
@anchor{topics/expressions unary-operations}@anchor{7b}
@subsubsection Unary Operations
@geindex gcc_jit_context_new_unary_op (C function)
@anchor{topics/expressions gcc_jit_context_new_unary_op}@anchor{7c}
@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.
@end deffn
@geindex gcc_jit_unary_op (C type)
@anchor{topics/expressions gcc_jit_unary_op}@anchor{7d}
@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
@pxref{7e,,GCC_JIT_UNARY_OP_MINUS}
@tab
@cite{-(EXPR)}
@item
@pxref{7f,,GCC_JIT_UNARY_OP_BITWISE_NEGATE}
@tab
@cite{~(EXPR)}
@item
@pxref{80,,GCC_JIT_UNARY_OP_LOGICAL_NEGATE}
@tab
@cite{!(EXPR)}
@end multitable
@geindex GCC_JIT_UNARY_OP_MINUS (C macro)
@anchor{topics/expressions GCC_JIT_UNARY_OP_MINUS}@anchor{7e}
@deffn {C Macro} GCC_JIT_UNARY_OP_MINUS
Negate an arithmetic value; analogous to:
@example
-(EXPR)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_BITWISE_NEGATE (C macro)
@anchor{topics/expressions GCC_JIT_UNARY_OP_BITWISE_NEGATE}@anchor{7f}
@deffn {C Macro} GCC_JIT_UNARY_OP_BITWISE_NEGATE
Bitwise negation of an integer value (one's complement); analogous
to:
@example
~(EXPR)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_LOGICAL_NEGATE (C macro)
@anchor{topics/expressions GCC_JIT_UNARY_OP_LOGICAL_NEGATE}@anchor{80}
@deffn {C Macro} GCC_JIT_UNARY_OP_LOGICAL_NEGATE
Logical negation of an arithmetic or pointer value; analogous to:
@example
!(EXPR)
@end example
@noindent
in C.
@end deffn
@node Binary Operations,Comparisons,Unary Operations,Rvalues
@anchor{topics/expressions binary-operations}@anchor{81}
@subsubsection Binary Operations
@geindex gcc_jit_context_new_binary_op (C function)
@anchor{topics/expressions 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.
@end deffn
@geindex gcc_jit_binary_op (C type)
@anchor{topics/expressions gcc_jit_binary_op}@anchor{82}
@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
@pxref{83,,GCC_JIT_BINARY_OP_PLUS}
@tab
@cite{x + y}
@item
@code{GCC_JIT_BINARY_OP_MINUS}
@tab
@cite{x - y}
@item
@pxref{84,,GCC_JIT_BINARY_OP_MULT}
@tab
@cite{x * y}
@item
@pxref{85,,GCC_JIT_BINARY_OP_DIVIDE}
@tab
@cite{x / y}
@item
@pxref{86,,GCC_JIT_BINARY_OP_MODULO}
@tab
@cite{x % y}
@item
@pxref{87,,GCC_JIT_BINARY_OP_BITWISE_AND}
@tab
@cite{x & y}
@item
@pxref{88,,GCC_JIT_BINARY_OP_BITWISE_XOR}
@tab
@cite{x ^ y}
@item
@pxref{89,,GCC_JIT_BINARY_OP_BITWISE_OR}
@tab
@cite{x | y}
@item
@pxref{8a,,GCC_JIT_BINARY_OP_LOGICAL_AND}
@tab
@cite{x && y}
@item
@pxref{8b,,GCC_JIT_BINARY_OP_LOGICAL_OR}
@tab
@cite{x || y}
@item
@pxref{8c,,GCC_JIT_BINARY_OP_LSHIFT}
@tab
@cite{x << y}
@item
@pxref{8d,,GCC_JIT_BINARY_OP_RSHIFT}
@tab
@cite{x >> y}
@end multitable
@geindex GCC_JIT_BINARY_OP_PLUS (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_PLUS}@anchor{83}
@deffn {C Macro} GCC_JIT_BINARY_OP_PLUS
Addition of arithmetic values; analogous to:
@example
(EXPR_A) + (EXPR_B)
@end example
@noindent
in C.
For pointer addition, use @pxref{8e,,gcc_jit_context_new_array_access()}.
@end deffn
@deffn {C Macro} GCC_JIT_BINARY_OP_MINUS`
Subtraction of arithmetic values; analogous to:
@example
(EXPR_A) - (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_MULT (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_MULT}@anchor{84}
@deffn {C Macro} GCC_JIT_BINARY_OP_MULT
Multiplication of a pair of arithmetic values; analogous to:
@example
(EXPR_A) * (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_DIVIDE (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_DIVIDE}@anchor{85}
@deffn {C Macro} GCC_JIT_BINARY_OP_DIVIDE
Quotient of division of arithmetic values; analogous to:
@example
(EXPR_A) / (EXPR_B)
@end example
@noindent
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 GCC_JIT_BINARY_OP_MODULO}@anchor{86}
@deffn {C Macro} GCC_JIT_BINARY_OP_MODULO
Remainder of division of arithmetic values; analogous to:
@example
(EXPR_A) % (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_AND (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_AND}@anchor{87}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_AND
Bitwise AND; analogous to:
@example
(EXPR_A) & (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_XOR (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_XOR}@anchor{88}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_XOR
Bitwise exclusive OR; analogous to:
@example
(EXPR_A) ^ (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_OR (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_OR}@anchor{89}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_OR
Bitwise inclusive OR; analogous to:
@example
(EXPR_A) | (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LOGICAL_AND (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_AND}@anchor{8a}
@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_AND
Logical AND; analogous to:
@example
(EXPR_A) && (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LOGICAL_OR (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_OR}@anchor{8b}
@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_OR
Logical OR; analogous to:
@example
(EXPR_A) || (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LSHIFT (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_LSHIFT}@anchor{8c}
@deffn {C Macro} GCC_JIT_BINARY_OP_LSHIFT
Left shift; analogous to:
@example
(EXPR_A) << (EXPR_B)
@end example
@noindent
in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_RSHIFT (C macro)
@anchor{topics/expressions GCC_JIT_BINARY_OP_RSHIFT}@anchor{8d}
@deffn {C Macro} GCC_JIT_BINARY_OP_RSHIFT
Right shift; analogous to:
@example
(EXPR_A) >> (EXPR_B)
@end example
@noindent
in C.
@end deffn
@node Comparisons,Function calls,Binary Operations,Rvalues
@anchor{topics/expressions comparisons}@anchor{8f}
@subsubsection Comparisons
@geindex gcc_jit_context_new_comparison (C function)
@anchor{topics/expressions gcc_jit_context_new_comparison}@anchor{2a}
@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 gcc_jit_comparison}@anchor{90}
@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,Type-coercion,Comparisons,Rvalues
@anchor{topics/expressions function-calls}@anchor{91}
@subsubsection Function calls
@geindex gcc_jit_context_new_call (C function)
@anchor{topics/expressions gcc_jit_context_new_call}@anchor{92}
@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
@pxref{92,,gcc_jit_context_new_call()} merely builds a
@pxref{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
@pxref{93,,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
@noindent
@end quotation
@end cartouche
@end deffn
@node Type-coercion,,Function calls,Rvalues
@anchor{topics/expressions type-coercion}@anchor{94}
@subsubsection Type-coercion
@geindex gcc_jit_context_new_cast (C function)
@anchor{topics/expressions gcc_jit_context_new_cast}@anchor{95}
@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
@node Lvalues,Working with pointers structs and unions,Rvalues,Expressions
@anchor{topics/expressions lvalues}@anchor{96}
@subsection Lvalues
@geindex gcc_jit_lvalue (C type)
@anchor{topics/expressions gcc_jit_lvalue}@anchor{22}
@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 gcc_jit_lvalue_as_object}@anchor{97}
@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 gcc_jit_lvalue_as_rvalue}@anchor{98}
@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 gcc_jit_lvalue_get_address}@anchor{99}
@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
@noindent
in C.
@end deffn
@menu
* Global variables::
@end menu
@node Global variables,,,Lvalues
@anchor{topics/expressions global-variables}@anchor{9a}
@subsubsection Global variables
@geindex gcc_jit_context_new_global (C function)
@anchor{topics/expressions gcc_jit_context_new_global}@anchor{9b}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
Add a new global variable of the given type and name to the context.
@end deffn
@node Working with pointers structs and unions,,Lvalues,Expressions
@anchor{topics/expressions working-with-pointers-structs-and-unions}@anchor{9c}
@subsection Working with pointers, structs and unions
@geindex gcc_jit_rvalue_dereference (C function)
@anchor{topics/expressions gcc_jit_rvalue_dereference}@anchor{9d}
@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
@noindent
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 gcc_jit_lvalue_access_field}@anchor{9e}
@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
@noindent
in C.
@end deffn
@geindex gcc_jit_rvalue_access_field (C function)
@anchor{topics/expressions gcc_jit_rvalue_access_field}@anchor{9f}
@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
@noindent
in C.
@end deffn
@geindex gcc_jit_rvalue_dereference_field (C function)
@anchor{topics/expressions gcc_jit_rvalue_dereference_field}@anchor{a0}
@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
@noindent
in C, itself equivalent to @code{(*EXPR).FIELD}.
@end deffn
@geindex gcc_jit_context_new_array_access (C function)
@anchor{topics/expressions gcc_jit_context_new_array_access}@anchor{8e}
@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
@noindent
in C (or, indeed, to @code{PTR + INDEX}).
@end deffn
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Creating and using functions,Source Locations,Expressions,Topic Reference
@anchor{topics/functions doc}@anchor{a1}@anchor{topics/functions creating-and-using-functions}@anchor{a2}
@section Creating and using functions
@menu
* Params::
* Functions::
* Blocks::
* Statements::
@end menu
@node Params,Functions,,Creating and using functions
@anchor{topics/functions params}@anchor{a3}
@subsection Params
@geindex gcc_jit_param (C type)
@anchor{topics/functions gcc_jit_param}@anchor{23}
@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 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.
@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 gcc_jit_param_as_lvalue}@anchor{a4}
@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 gcc_jit_param_as_rvalue}@anchor{a5}
@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 gcc_jit_param_as_object}@anchor{a6}
@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{a7}
@subsection Functions
@geindex gcc_jit_function (C type)
@anchor{topics/functions gcc_jit_function}@anchor{27}
@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 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 gcc_jit_function_kind}@anchor{a8}
@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 GCC_JIT_FUNCTION_EXPORTED}@anchor{a9}
@deffn {C Macro} GCC_JIT_FUNCTION_EXPORTED
Function is defined by the client code and visible
by name outside of the JIT.
@end deffn
@geindex GCC_JIT_FUNCTION_INTERNAL (C macro)
@anchor{topics/functions GCC_JIT_FUNCTION_INTERNAL}@anchor{aa}
@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 GCC_JIT_FUNCTION_IMPORTED}@anchor{ab}
@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 GCC_JIT_FUNCTION_ALWAYS_INLINE}@anchor{ac}
@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
@end deffn
@geindex gcc_jit_context_get_builtin_function (C function)
@anchor{topics/functions gcc_jit_context_get_builtin_function}@anchor{ad}
@deffn {C Function} gcc_jit_function *gcc_jit_context_get_builtin_function (gcc_jit_context@w{ }*ctxt, const char@w{ }*name)
@end deffn
@geindex gcc_jit_function_as_object (C function)
@anchor{topics/functions gcc_jit_function_as_object}@anchor{ae}
@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 gcc_jit_function_get_param}@anchor{af}
@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 gcc_jit_function_dump_to_dot}@anchor{31}
@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 gcc_jit_function_new_local}@anchor{24}
@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.
@end deffn
@node Blocks,Statements,Functions,Creating and using functions
@anchor{topics/functions blocks}@anchor{b0}
@subsection Blocks
@geindex gcc_jit_block (C type)
@anchor{topics/functions gcc_jit_block}@anchor{26}
@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, or a return.
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 gcc_jit_function_new_block}@anchor{b1}
@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.
@end deffn
@geindex gcc_jit_block_as_object (C function)
@anchor{topics/functions gcc_jit_block_as_object}@anchor{b2}
@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 gcc_jit_block_get_function}@anchor{b3}
@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{b4}
@subsection Statements
@geindex gcc_jit_block_add_eval (C function)
@anchor{topics/functions gcc_jit_block_add_eval}@anchor{93}
@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
@noindent
@end deffn
@geindex gcc_jit_block_add_assignment (C function)
@anchor{topics/functions gcc_jit_block_add_assignment}@anchor{28}
@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
@noindent
@end deffn
@geindex gcc_jit_block_add_assignment_op (C function)
@anchor{topics/functions gcc_jit_block_add_assignment_op}@anchor{2c}
@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
@noindent
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
@noindent
@end deffn
@geindex gcc_jit_block_add_comment (C function)
@anchor{topics/functions gcc_jit_block_add_comment}@anchor{3a}
@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 @pxref{57,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}
and @pxref{1a,,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.
@end deffn
@geindex gcc_jit_block_end_with_conditional (C function)
@anchor{topics/functions gcc_jit_block_end_with_conditional}@anchor{2b}
@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
@noindent
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 gcc_jit_block_end_with_jump}@anchor{b5}
@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
@noindent
@end deffn
@geindex gcc_jit_block_end_with_return (C function)
@anchor{topics/functions gcc_jit_block_end_with_return}@anchor{b6}
@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
@noindent
@end deffn
@geindex gcc_jit_block_end_with_void_return (C function)
@anchor{topics/functions gcc_jit_block_end_with_void_return}@anchor{b7}
@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
@noindent
@end deffn
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Source Locations,Compilation results,Creating and using functions,Topic Reference
@anchor{topics/locations source-locations}@anchor{b8}@anchor{topics/locations doc}@anchor{b9}
@section Source Locations
@geindex gcc_jit_location (C type)
@anchor{topics/locations gcc_jit_location}@anchor{38}
@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 @pxref{3e,,gcc_jit_context_new_location()}.
You need to enable @pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@pxref{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
@noindent
@end deffn
@geindex gcc_jit_context_new_location (C function)
@anchor{topics/locations gcc_jit_context_new_location}@anchor{3e}
@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.
@end deffn
@menu
* Faking it::
@end menu
@node Faking it,,,Source Locations
@anchor{topics/locations faking-it}@anchor{ba}
@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 @pxref{4f,,gcc_jit_context_dump_to_file()}:
@example
gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
1 /* update_locations */);
@end example
@noindent
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 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 <http://www.gnu.org/licenses/>.
@node Compilation results,,Source Locations,Topic Reference
@anchor{topics/results compilation-results}@anchor{bb}@anchor{topics/results doc}@anchor{bc}
@section Compilation results
@geindex gcc_jit_result (C type)
@anchor{topics/results gcc_jit_result}@anchor{16}
@deffn {C Type} gcc_jit_result
A @cite{gcc_jit_result} encapsulates the result of compiling a context.
@end deffn
@geindex gcc_jit_context_compile (C function)
@anchor{topics/results 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 *}.
@end deffn
@geindex gcc_jit_result_get_code (C function)
@anchor{topics/results 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.
This will need to be cast to a function pointer of the
correct type before it can be called.
@end deffn
@geindex gcc_jit_result_release (C function)
@anchor{topics/results gcc_jit_result_release}@anchor{bd}
@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.
@end deffn
@c Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
@node Internals,Indices and tables,Topic Reference,Top
@anchor{internals/index internals}@anchor{be}@anchor{internals/index doc}@anchor{bf}
@chapter Internals
@menu
* Working on the JIT library::
* Running the test suite::
* Environment variables::
* Overview of code structure::
@end menu
@node Working on the JIT library,Running the test suite,,Internals
@anchor{internals/index working-on-the-jit-library}@anchor{c0}
@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 \
--disable-bootstrap \
--enable-checking=release \
--prefix=$PREFIX
nice make -j4 # altering the "4" to however many cores you have
@end example
@noindent
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
@noindent
Here's what those configuration options mean:
@geindex command line option; --enable-host-shared
@anchor{internals/index cmdoption--enable-host-shared}@anchor{c1}
@deffn {Option} --enable-host-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
@anchor{internals/index cmdoption--enable-languages}@anchor{c2}
@deffn {Option} --enable-languages=jit
This specifies which frontends to build. The JIT library looks like
a frontend to the rest of the code.
@end deffn
@geindex command line option; --disable-bootstrap
@anchor{internals/index cmdoption--disable-bootstrap}@anchor{c3}
@deffn {Option} --disable-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{c4}
@deffn {Option} --enable-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{c5}
@section Running the test suite
@example
[build] $ cd gcc
[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
@end example
@noindent
A summary of the tests can then be seen in:
@example
jit/build/gcc/testsuite/jit/jit.sum
@end example
@noindent
and detailed logs in:
@example
jit/build/gcc/testsuite/jit/jit.log
@end example
@noindent
The test executables can be seen as:
@example
jit/build/gcc/testsuite/jit/*.exe
@end example
@noindent
which can be run independently.
You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.:
@example
[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
@end example
@noindent
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.exe
@end example
@noindent
@node Environment variables,Overview of code structure,Running the test suite,Internals
@anchor{internals/index environment-variables}@anchor{c6}
@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{c7}
@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
@noindent
@end deffn
@geindex environment variable; PATH
@anchor{internals/index envvar-PATH}@anchor{c8}
@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{c9}
@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
@noindent
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
@noindent
@node Overview of code structure,,Environment variables,Internals
@anchor{internals/index overview-of-code-structure}@anchor{ca}
@section Overview of code structure
@itemize *
@item
@code{libgccjit.c} implements the API entrypoints. It performs error
checking, then calls into classes of the gcc::jit::recording namespace
within @code{jit-recording.c} and @code{jit-recording.h}.
@item
The gcc::jit::recording classes (within @code{jit-recording.c} and
@code{jit-recording.h}) record the API calls that are made:
@quotation
@example
/* Indentation indicates inheritance: */
class context;
class builtins_manager; // declared within jit-builtins.h
class memento;
class string;
class location;
class type;
class function_type;
class compound_type;
class struct_;
class union_;
class field;
class fields;
class function;
class block;
class rvalue;
class lvalue;
class local;
class global;
class param;
class statement;
@end example
@noindent
@end quotation
@item
When the context is compiled, the gcc::jit::playback classes (within
@code{jit-playback.c} 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;
@end example
@noindent
@example
Client Code . Generated . libgccjit.so
. code .
. . JIT API . JIT "Frontend". (libbackend.a)
....................................................................................
│ . . . .
──────────────────────────> . .
. . │ . .
. . V . .
. . ──> libgccjit.c .
. . │ (error-checking).
. . │ .
. . ──> jit-recording.c
. . (record API calls)
. . <─────── .
. . │ . .
<─────────────────────────── . .
│ . . . .
│ . . . .
V . . gcc_jit_context_compile .
──────────────────────────> . .
. . │ . .
. . │ ACQUIRE MUTEX .
. . │ . .
. . V───────────────────────> toplev::main (for now)
. . . . │
. . . . (various code)
. . . . │
. . . . V
. . . <───────────────── langhook:parse_file
. . . │ .
. . . │ (jit_langhook_parse_file)
. . . │ .
..........................................│..................VVVVVVVVVVVVV...
. . . │ . No GC in here
. . . │ jit-playback.c
. . . │ (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
. . │ RELEASE MUTEX .
. . │ . .
. . │ Convert assembler to DSO
. . │ . .
. . │ Load DSO .
<─────────────────────────── . .
│ . . . .
Get (void*). . . .
│ . . . .
│ Call it . . . .
───────────────> . . .
. │ . . .
. │ . . .
<─────────────── . . .
│ . . . .
│ . . . .
etc
@end example
@noindent
@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
This document describes libgccjit@footnote{http://gcc.gnu.org/wiki/JIT}, an API
for embedding GCC inside programs and libraries.
Note that libgccjit is currently of "Alpha" quality;
the APIs are not yet set in stone, and they shouldn't be used in
production yet.
@node Indices and tables,Index,Internals,Top
@anchor{index indices-and-tables}@anchor{cb}
@unnumbered Indices and tables
@itemize *
@item
@emph{genindex}
@item
@emph{modindex}
@item
@emph{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 http://sphinx-doc.org/domains.html#the-c-domain
@node Index,,Indices and tables,Top
@unnumbered Index
@printindex ge
@c %**end of body
@bye