diff options
Diffstat (limited to 'gcc/jit/docs/_build/texinfo/libgccjit.texi')
-rw-r--r-- | gcc/jit/docs/_build/texinfo/libgccjit.texi | 6537 |
1 files changed, 6537 insertions, 0 deletions
diff --git a/gcc/jit/docs/_build/texinfo/libgccjit.texi b/gcc/jit/docs/_build/texinfo/libgccjit.texi new file mode 100644 index 000000000000..58ba150c0560 --- /dev/null +++ b/gcc/jit/docs/_build/texinfo/libgccjit.texi @@ -0,0 +1,6537 @@ +\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, ¶m_name, + 0); + + gcc_jit_param *param_format = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format"); + gcc_jit_function *printf_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + gcc_jit_context_get_type ( + ctxt, GCC_JIT_TYPE_INT), + "printf", + 1, ¶m_format, + 1); + gcc_jit_rvalue *args[2]; + args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n"); + args[1] = gcc_jit_param_as_rvalue (param_name); + + gcc_jit_block *block = gcc_jit_function_new_block (func, NULL); + + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + printf_func, + 2, args)); + gcc_jit_block_end_with_void_return (block, NULL); +@} + +int +main (int argc, char **argv) +@{ + gcc_jit_context *ctxt; + gcc_jit_result *result; + + /* Get a "context" object for working with the library. */ + ctxt = gcc_jit_context_acquire (); + if (!ctxt) + @{ + fprintf (stderr, "NULL ctxt"); + exit (1); + @} + + /* Set some options on the context. + Let's see the code being generated, in assembler form. */ + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, + 0); + + /* Populate the context. */ + create_code (ctxt); + + /* Compile the code. */ + result = gcc_jit_context_compile (ctxt); + if (!result) + @{ + fprintf (stderr, "NULL result"); + exit (1); + @} + + /* Extract the generated code from "result". */ + typedef void (*fn_type) (const char *); + fn_type greet = + (fn_type)gcc_jit_result_get_code (result, "greet"); + if (!greet) + @{ + fprintf (stderr, "NULL greet"); + exit (1); + @} + + /* Now call the generated function: */ + greet ("world"); + fflush (stdout); + + gcc_jit_context_release (ctxt); + gcc_jit_result_release (result); + return 0; +@} + +@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, ¶m_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, ¶m_i, + 0); + + gcc_jit_block *block = gcc_jit_function_new_block (func, NULL); + + gcc_jit_rvalue *expr = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, int_type, + gcc_jit_param_as_rvalue (param_i), + gcc_jit_param_as_rvalue (param_i)); + + gcc_jit_block_end_with_return (block, NULL, expr); +@} + +int +main (int argc, char **argv) +@{ + gcc_jit_context *ctxt = NULL; + gcc_jit_result *result = NULL; + + /* Get a "context" object for working with the library. */ + ctxt = gcc_jit_context_acquire (); + if (!ctxt) + @{ + fprintf (stderr, "NULL ctxt"); + goto error; + @} + + /* Set some options on the context. + Let's see the code being generated, in assembler form. */ + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, + 0); + + /* Populate the context. */ + create_code (ctxt); + + /* Compile the code. */ + result = gcc_jit_context_compile (ctxt); + if (!result) + @{ + fprintf (stderr, "NULL result"); + goto error; + @} + + /* 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 |