diff options
Diffstat (limited to 'gcc/jit/docs')
30 files changed, 12169 insertions, 0 deletions
diff --git a/gcc/jit/docs/Makefile b/gcc/jit/docs/Makefile new file mode 100644 index 00000000000..7d20702455a --- /dev/null +++ b/gcc/jit/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libgccjit.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libgccjit.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/libgccjit" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libgccjit" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/gcc/jit/docs/_build/texinfo/Makefile b/gcc/jit/docs/_build/texinfo/Makefile new file mode 100644 index 00000000000..87e3048f44f --- /dev/null +++ b/gcc/jit/docs/_build/texinfo/Makefile @@ -0,0 +1,50 @@ +# Makefile for Sphinx Texinfo output + +infodir ?= /usr/share/info + +MAKEINFO = makeinfo --no-split +MAKEINFO_html = makeinfo --no-split --html +MAKEINFO_plaintext = makeinfo --no-split --plaintext +TEXI2PDF = texi2pdf --batch --expand +INSTALL_INFO = install-info + +ALLDOCS = $(basename $(wildcard *.texi)) + +all: info +info: $(addsuffix .info,$(ALLDOCS)) +plaintext: $(addsuffix .txt,$(ALLDOCS)) +html: $(addsuffix .html,$(ALLDOCS)) +pdf: $(addsuffix .pdf,$(ALLDOCS)) + +install-info: info + for f in *.info; do \ + cp -t $(infodir) "$$f" && \ + $(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \ + done + +uninstall-info: info + for f in *.info; do \ + rm -f "$(infodir)/$$f" ; \ + $(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \ + done + +%.info: %.texi + $(MAKEINFO) -o '$@' '$<' + +%.txt: %.texi + $(MAKEINFO_plaintext) -o '$@' '$<' + +%.html: %.texi + $(MAKEINFO_html) -o '$@' '$<' + +%.pdf: %.texi + -$(TEXI2PDF) '$<' + -$(TEXI2PDF) '$<' + -$(TEXI2PDF) '$<' + +clean: + -rm -f *.info *.pdf *.txt *.html + -rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ky *.pg + -rm -f *.vr *.tp *.fn *.fns *.def *.defs *.cp *.cps *.ge *.ges *.mo + +.PHONY: all info plaintext html pdf install-info uninstall-info clean diff --git a/gcc/jit/docs/_build/texinfo/factorial.png b/gcc/jit/docs/_build/texinfo/factorial.png Binary files differnew file mode 100644 index 00000000000..dff47ce2767 --- /dev/null +++ b/gcc/jit/docs/_build/texinfo/factorial.png diff --git a/gcc/jit/docs/_build/texinfo/libgccjit.texi b/gcc/jit/docs/_build/texinfo/libgccjit.texi new file mode 100644 index 00000000000..58ba150c056 --- /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 diff --git a/gcc/jit/docs/_build/texinfo/sum-of-squares.png b/gcc/jit/docs/_build/texinfo/sum-of-squares.png Binary files differnew file mode 100644 index 00000000000..7a3b4afff38 --- /dev/null +++ b/gcc/jit/docs/_build/texinfo/sum-of-squares.png diff --git a/gcc/jit/docs/conf.py b/gcc/jit/docs/conf.py new file mode 100644 index 00000000000..c300339322f --- /dev/null +++ b/gcc/jit/docs/conf.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- +# +# libgccjit documentation build configuration file, created by +# sphinx-quickstart on Wed Jul 30 13:39:01 2014. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'libgccjit' +copyright = u'2014, Free Software Foundation' + +# GCC-specific: extract version information from "gcc" src subdir for +# use in "version" and "release" below. +def __read_file(name): + gcc_srcdir = '../..' + path = os.path.join(gcc_srcdir, name) + if os.path.exists(path): + return open(path).read().strip() + else: + return '' +gcc_BASEVER = __read_file('BASE-VER') +gcc_DEVPHASE = __read_file('DEV-PHASE') +gcc_DATESTAMP = __read_file('DATESTAMP') +gcc_REVISION = __read_file('REVISION') + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = gcc_BASEVER +# The full version, including alpha/beta/rc tags. +release = ('%s (%s %s%s)' + % (gcc_BASEVER, gcc_DEVPHASE, gcc_DATESTAMP, + (' %s' % gcc_REVISION) if gcc_REVISION else '')) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'pyramid' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libgccjitdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'libgccjit.tex', u'libgccjit Documentation', + u'David Malcolm', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'libgccjit', u'libgccjit Documentation', + [u'David Malcolm'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'libgccjit', u'libgccjit Documentation', + u'David Malcolm', 'libgccjit', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/gcc/jit/docs/examples/tut01-hello-world.c b/gcc/jit/docs/examples/tut01-hello-world.c new file mode 100644 index 00000000000..49c9651db2b --- /dev/null +++ b/gcc/jit/docs/examples/tut01-hello-world.c @@ -0,0 +1,123 @@ +/* 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; +} diff --git a/gcc/jit/docs/examples/tut02-square.c b/gcc/jit/docs/examples/tut02-square.c new file mode 100644 index 00000000000..5eae1799949 --- /dev/null +++ b/gcc/jit/docs/examples/tut02-square.c @@ -0,0 +1,107 @@ +/* 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; +} diff --git a/gcc/jit/docs/examples/tut03-sum-of-squares.c b/gcc/jit/docs/examples/tut03-sum-of-squares.c new file mode 100644 index 00000000000..594230b5563 --- /dev/null +++ b/gcc/jit/docs/examples/tut03-sum-of-squares.c @@ -0,0 +1,172 @@ +/* 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; +} diff --git a/gcc/jit/docs/examples/tut04-toyvm/Makefile b/gcc/jit/docs/examples/tut04-toyvm/Makefile new file mode 100644 index 00000000000..1b45c8de186 --- /dev/null +++ b/gcc/jit/docs/examples/tut04-toyvm/Makefile @@ -0,0 +1,11 @@ +factorial: toyvm + ./toyvm factorial.toy 10 + +fibonacci: toyvm + ./toyvm fibonacci.toy 8 + +toyvm: toyvm.c Makefile + g++ -Wall -g -o $@ $< $(shell pkg-config --cflags --libs libgccjit) + +clean: + rm -f *.o toyvm diff --git a/gcc/jit/docs/examples/tut04-toyvm/factorial.toy b/gcc/jit/docs/examples/tut04-toyvm/factorial.toy new file mode 100644 index 00000000000..48e4034e8ac --- /dev/null +++ b/gcc/jit/docs/examples/tut04-toyvm/factorial.toy @@ -0,0 +1,50 @@ +# 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 diff --git a/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy b/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy new file mode 100644 index 00000000000..5ae0a406252 --- /dev/null +++ b/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy @@ -0,0 +1,66 @@ +# Simple recursive fibonacci implementation, roughly equivalent to: +# +# int fibonacci (int arg) +# { +# if (arg < 2) +# return arg +# return fibonacci (arg-1) + fibonacci (arg-2) +# } + +# 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 13 +# 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, fib(arg - 1)] + +# 8: +ROT +# stack: [fib(arg - 1), arg] + +# 9: +PUSH_CONST 2 +# stack: [fib(arg - 1), arg, 2] + +# 10: +BINARY_SUBTRACT +# stack: [fib(arg - 1), arg, (arg - 2) + +# 11: +RECURSE +# stack: [fib(arg - 1), fib(arg - 1)] + +# 12: +BINARY_ADD +# stack: [fib(arg - 1) + fib(arg - 1)] + +# 13: +RETURN diff --git a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c new file mode 100644 index 00000000000..666bf2ed2d3 --- /dev/null +++ b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c @@ -0,0 +1,861 @@ +/* A simple stack-based virtual machine to demonstrate + JIT-compilation. + 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <dejagnu.h> + +#include <libgccjit.h> + +/* Typedefs. */ +typedef struct toyvm_op toyvm_op; +typedef struct toyvm_function toyvm_function; +typedef struct toyvm_frame toyvm_frame; +typedef struct compilation_state compilation_state; + +/* Functions are compiled to this function ptr type. */ +typedef int (*toyvm_compiled_func) (int); + +enum opcode { + /* Ops taking no operand. */ + DUP, + ROT, + BINARY_ADD, + BINARY_SUBTRACT, + BINARY_MULT, + BINARY_COMPARE_LT, + RECURSE, + RETURN, + + /* Ops taking an operand. */ + PUSH_CONST, + JUMP_ABS_IF_TRUE +}; + +#define FIRST_UNARY_OPCODE (PUSH_CONST) + +const char * const opcode_names[] = { + "DUP", + "ROT", + "BINARY_ADD", + "BINARY_SUBTRACT", + "BINARY_MULT", + "BINARY_COMPARE_LT", + "RECURSE", + "RETURN", + + "PUSH_CONST", + "JUMP_ABS_IF_TRUE", +}; + +struct toyvm_op +{ + /* Which operation. */ + enum opcode op_opcode; + + /* Some opcodes take an argument. */ + int op_operand; + + /* The line number of the operation within the source file. */ + int op_linenum; +}; + +#define MAX_OPS (64) + +struct toyvm_function +{ + const char *fn_filename; + int fn_num_ops; + toyvm_op fn_ops[MAX_OPS]; +}; + +#define MAX_STACK_DEPTH (8) + +struct toyvm_frame +{ + toyvm_function *frm_function; + int frm_pc; + int frm_stack[MAX_STACK_DEPTH]; + int frm_cur_depth; +}; + +static void +add_op (toyvm_function *fn, enum opcode opcode, + int operand, int linenum) +{ + toyvm_op *op; + assert (fn->fn_num_ops < MAX_OPS); + op = &fn->fn_ops[fn->fn_num_ops++]; + op->op_opcode = opcode; + op->op_operand = operand; + op->op_linenum = linenum; +} + +static void +add_unary_op (toyvm_function *fn, enum opcode opcode, + const char *rest_of_line, int linenum) +{ + int operand = atoi (rest_of_line); + add_op (fn, opcode, operand, linenum); +} + +static toyvm_function * +toyvm_function_parse (const char *filename, const char *name) +{ + FILE *f = NULL; + toyvm_function *fn = NULL; + char *line = NULL; + ssize_t linelen; + size_t bufsize; + int linenum = 0; + + assert (filename); + assert (name); + + f = fopen (filename, "r"); + if (!f) + { + fprintf (stderr, + "cannot open file %s: %s\n", + filename, strerror (errno)); + goto error; + } + + fn = (toyvm_function *)calloc (1, sizeof (toyvm_function)); + if (!fn) + { + fprintf (stderr, "out of memory allocating toyvm_function\n"); + goto error; + } + fn->fn_filename = name; + + /* Read the lines of the file. */ + while ((linelen = getline (&line, &bufsize, f)) != -1) + { + /* Note that this is a terrible parser, but it avoids the need to + bring in lex/yacc as a dependency. */ + linenum++; + + if (0) + fprintf (stdout, "%3d: %s", linenum, line); + + /* Lines beginning with # are comments. */ + if (line[0] == '#') + continue; + + /* Skip blank lines. */ + if (line[0] == '\n') + continue; + +#define LINE_MATCHES(OPCODE) (0 == strncmp ((OPCODE), line, strlen (OPCODE))) + if (LINE_MATCHES ("DUP\n")) + add_op (fn, DUP, 0, linenum); + else if (LINE_MATCHES ("ROT\n")) + add_op (fn, ROT, 0, linenum); + else if (LINE_MATCHES ("BINARY_ADD\n")) + add_op (fn, BINARY_ADD, 0, linenum); + else if (LINE_MATCHES ("BINARY_SUBTRACT\n")) + add_op (fn, BINARY_SUBTRACT, 0, linenum); + else if (LINE_MATCHES ("BINARY_MULT\n")) + add_op (fn, BINARY_MULT, 0, linenum); + else if (LINE_MATCHES ("BINARY_COMPARE_LT\n")) + add_op (fn, BINARY_COMPARE_LT, 0, linenum); + else if (LINE_MATCHES ("RECURSE\n")) + add_op (fn, RECURSE, 0, linenum); + else if (LINE_MATCHES ("RETURN\n")) + add_op (fn, RETURN, 0, linenum); + else if (LINE_MATCHES ("PUSH_CONST ")) + add_unary_op (fn, PUSH_CONST, + line + strlen ("PUSH_CONST "), linenum); + else if (LINE_MATCHES ("JUMP_ABS_IF_TRUE ")) + add_unary_op (fn, JUMP_ABS_IF_TRUE, + line + strlen("JUMP_ABS_IF_TRUE "), linenum); + else + { + fprintf (stderr, "%s:%d: parse error\n", filename, linenum); + free (fn); + fn = NULL; + goto error; + } +#undef LINE_MATCHES + } + free (line); + fclose (f); + + return fn; + + error: + free (line); + fclose (f); + free (fn); + return NULL; +} + +static void +toyvm_function_disassemble_op (toyvm_function *fn, toyvm_op *op, int index, FILE *out) +{ + fprintf (out, "%s:%d: index %d: %s", + fn->fn_filename, op->op_linenum, index, + opcode_names[op->op_opcode]); + if (op->op_opcode >= FIRST_UNARY_OPCODE) + fprintf (out, " %d", op->op_operand); + fprintf (out, "\n"); +} + +static void +toyvm_function_disassemble (toyvm_function *fn, FILE *out) +{ + int i; + for (i = 0; i < fn->fn_num_ops; i++) + { + toyvm_op *op = &fn->fn_ops[i]; + toyvm_function_disassemble_op (fn, op, i, out); + } +} + +static void +toyvm_frame_push (toyvm_frame *frame, int arg) +{ + assert (frame->frm_cur_depth < MAX_STACK_DEPTH); + frame->frm_stack[frame->frm_cur_depth++] = arg; +} + +static int +toyvm_frame_pop (toyvm_frame *frame) +{ + assert (frame->frm_cur_depth > 0); + return frame->frm_stack[--frame->frm_cur_depth]; +} + +static void +toyvm_frame_dump_stack (toyvm_frame *frame, FILE *out) +{ + int i; + fprintf (out, "stack:"); + for (i = 0; i < frame->frm_cur_depth; i++) + { + fprintf (out, " %d", frame->frm_stack[i]); + } + fprintf (out, "\n"); +} + +/* Execute the given function. */ + +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 +} + +/* JIT compilation. */ + +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]; + +}; + +/* Stack manipulation. */ + +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)))); +} + +/* The main compilation hook. */ + +static toyvm_compiled_func +toyvm_function_compile (toyvm_function *fn) +{ + compilation_state state; + int pc; + char *funcname; + + memset (&state, 0, sizeof (state)); + + /* Copy filename to funcname. */ + funcname = (char *)malloc (strlen (fn->fn_filename) + 1); + strcpy (funcname, fn->fn_filename); + + /* Convert "." to NIL terminator. */ + *(strchr (funcname, '.')) = '\0'; + + state.ctxt = gcc_jit_context_acquire (); + + gcc_jit_context_set_bool_option (state.ctxt, + GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, + 0); + gcc_jit_context_set_bool_option (state.ctxt, + GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, + 0); + gcc_jit_context_set_int_option (state.ctxt, + GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, + 3); + gcc_jit_context_set_bool_option (state.ctxt, + GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES, + 0); + gcc_jit_context_set_bool_option (state.ctxt, + GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING, + 0); + gcc_jit_context_set_bool_option (state.ctxt, + GCC_JIT_BOOL_OPTION_DEBUGINFO, + 1); + + /* Create types. */ + 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); + + /* The constant value 1. */ + state.const_one = gcc_jit_context_one (state.ctxt, state.int_type); + + /* Create locations. */ + 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 */ + } + + /* Creating the function. */ + 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); + + /* Create stack lvalues. */ + 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"); + + /* 1st pass: create blocks, one per opcode. */ + + /* We need an entry block to do one-time initialization, so create that + first. */ + state.initial_block = gcc_jit_function_new_block (state.fn, "initial"); + + /* Create a block per operation. */ + 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); + } + + /* Populate the initial block. */ + + /* "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]); + + /* 2nd pass: fill in instructions. */ + 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]; + + /* Helper macros. */ + +#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)) + + gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]); + + /* Handle the individual opcodes. */ + + 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 */ + + /* Go to the next block. */ + if (op->op_opcode != JUMP_ABS_IF_TRUE + && op->op_opcode != RETURN) + gcc_jit_block_end_with_jump ( + block, + loc, + next_block); + + } /* end of loop on PC locations. */ + + /* We've now finished populating the context. Compile it. */ + 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); + /* (this leaks "result" and "funcname") */ +} + +char test[1024]; + +#define CHECK_NON_NULL(PTR) \ + do { \ + if ((PTR) != NULL) \ + { \ + pass ("%s: %s is non-null", test, #PTR); \ + } \ + else \ + { \ + fail ("%s: %s is NULL", test, #PTR); \ + abort (); \ + } \ + } while (0) + +#define CHECK_VALUE(ACTUAL, EXPECTED) \ + do { \ + if ((ACTUAL) == (EXPECTED)) \ + { \ + pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \ + } \ + else \ + { \ + fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \ + fprintf (stderr, "incorrect value\n"); \ + abort (); \ + } \ + } while (0) + +static void +test_script (const char *scripts_dir, const char *script_name, int input, + int expected_result) +{ + char *script_path; + toyvm_function *fn; + int interpreted_result; + toyvm_compiled_func code; + int compiled_result; + + snprintf (test, sizeof (test), "toyvm.c: %s", script_name); + + script_path = (char *)malloc (strlen (scripts_dir) + + strlen (script_name) + 1); + CHECK_NON_NULL (script_path); + sprintf (script_path, "%s%s", scripts_dir, script_name); + + fn = toyvm_function_parse (script_path, script_name); + CHECK_NON_NULL (fn); + + interpreted_result = toyvm_function_interpret (fn, input, NULL); + CHECK_VALUE (interpreted_result, expected_result); + + code = toyvm_function_compile (fn); + CHECK_NON_NULL (code); + + compiled_result = code (input); + CHECK_VALUE (compiled_result, expected_result); + + free (script_path); +} + +#define PATH_TO_SCRIPTS ("/jit/docs/examples/tut04-toyvm/") + +static void +test_suite (void) +{ + const char *srcdir; + char *scripts_dir; + + snprintf (test, sizeof (test), "toyvm.c"); + + /* We need to locate the test scripts. + Rely on "srcdir" being set in the environment. */ + + srcdir = getenv ("srcdir"); + CHECK_NON_NULL (srcdir); + + scripts_dir = (char *)malloc (strlen (srcdir) + strlen(PATH_TO_SCRIPTS) + + 1); + CHECK_NON_NULL (scripts_dir); + sprintf (scripts_dir, "%s%s", srcdir, PATH_TO_SCRIPTS); + + test_script (scripts_dir, "factorial.toy", 10, 3628800); + test_script (scripts_dir, "fibonacci.toy", 10, 55); + + free (scripts_dir); +} + +int +main (int argc, char **argv) +{ + const char *filename = NULL; + toyvm_function *fn = NULL; + + /* If called with no args, assume we're being run by the test suite. */ + if (argc < 3) + { + test_suite (); + return 0; + } + + if (argc != 3) + { + fprintf (stdout, + "%s FILENAME INPUT: Parse and run a .toy file\n", + argv[0]); + exit (1); + } + + filename = argv[1]; + fn = toyvm_function_parse (filename, filename); + if (!fn) + exit (1); + + if (0) + toyvm_function_disassemble (fn, stdout); + + printf ("interpreter result: %d\n", + toyvm_function_interpret (fn, atoi (argv[2]), NULL)); + + /* JIT-compilation. */ + toyvm_compiled_func code = toyvm_function_compile (fn); + printf ("compiler result: %d\n", + code (atoi (argv[2]))); + + return 0; +} diff --git a/gcc/jit/docs/index.rst b/gcc/jit/docs/index.rst new file mode 100644 index 00000000000..ed75e36c201 --- /dev/null +++ b/gcc/jit/docs/index.rst @@ -0,0 +1,50 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +libgccjit +========= + +Contents: + +.. toctree:: + :maxdepth: 2 + + intro/index.rst + topics/index.rst + internals/index.rst + +This document describes `libgccjit <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. + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. Some notes: + + The Sphinx C domain appears to lack explicit support for enum values, + so I've been using :c:macro: for them. + + See http://sphinx-doc.org/domains.html#the-c-domain diff --git a/gcc/jit/docs/internals/index.rst b/gcc/jit/docs/internals/index.rst new file mode 100644 index 00000000000..80626e4a10b --- /dev/null +++ b/gcc/jit/docs/internals/index.rst @@ -0,0 +1,216 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +Internals +========= + +Working on the JIT library +-------------------------- +Having checked out the source code (to "src"), you can configure and build +the JIT library like this: + +.. code-block:: bash + + 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 + +This should build a libgccjit.so within jit/build/gcc: + +.. code-block:: console + + [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 + +Here's what those configuration options mean: + +.. 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. + +.. option:: --enable-languages=jit + + This specifies which frontends to build. The JIT library looks like + a frontend to the rest of the code. + +.. 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. + +.. 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 ``--enable-checking=release`` to + disable this self-checking. + +Running the test suite +---------------------- + +.. code-block:: console + + [build] $ cd gcc + [gcc] $ make check-jit RUNTESTFLAGS="-v -v -v" + +A summary of the tests can then be seen in: + +.. code-block:: console + + jit/build/gcc/testsuite/jit/jit.sum + +and detailed logs in: + +.. code-block:: console + + jit/build/gcc/testsuite/jit/jit.log + +The test executables can be seen as: + +.. code-block:: console + + jit/build/gcc/testsuite/jit/*.exe + +which can be run independently. + +You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.: + +.. code-block:: console + + [gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c" + +and once a test has been compiled, you can debug it directly: + +.. code-block:: console + + [gcc] $ PATH=.:$PATH \ + LD_LIBRARY_PATH=. \ + LIBRARY_PATH=. \ + gdb --args \ + testsuite/jit/test-factorial.exe + +Environment variables +--------------------- +When running client code against a locally-built libgccjit, three +environment variables need to be set up: + +.. envvar:: LD_LIBRARY_PATH + + `libgccjit.so` is dynamically linked into client code, so if running + against a locally-built library, ``LD_LIBRARY_PATH`` needs to be set + up appropriately. The library can be found within the "gcc" + subdirectory of the build tree: + + .. code-block:: console + + $ 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 + +.. envvar:: 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 + ``${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}`` + such as ``x86_64-unknown-linux-gnu-gcc-5.0.0``. + + Hence ``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. + +.. envvar:: 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: + + .. code-block:: console + + ld: cannot find crtbeginS.o: No such file or directory + ld: cannot find -lgcc + ld: cannot find -lgcc_s + + Hence if running directly from a locally-built copy (without installing), + ``LIBRARY_PATH`` needs to contain the "gcc" subdirectory of the build + tree. + +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: + +.. code-block:: console + + $ 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 + +Overview of code structure +-------------------------- + +* ``libgccjit.c`` implements the API entrypoints. It performs error + checking, then calls into classes of the gcc::jit::recording namespace + within ``jit-recording.c`` and ``jit-recording.h``. + +* The gcc::jit::recording classes (within ``jit-recording.c`` and + ``jit-recording.h``) record the API calls that are made: + + .. literalinclude:: ../../jit-common.h + :start-after: /* Recording types. */ + :end-before: /* End of recording types. */ + :language: c++ + +* When the context is compiled, the gcc::jit::playback classes (within + ``jit-playback.c`` and ``jit-playback.h``) replay the API calls + within langhook:parse_file: + + .. literalinclude:: ../../jit-common.h + :start-after: /* Playback types. */ + :end-before: /* End of playback types. */ + :language: c++ + + .. literalinclude:: ../../notes.txt + :lines: 1- + +Here is a high-level summary from ``jit-common.h``: + +.. include:: ../../jit-common.h + :start-after: This comment is included by the docs. + :end-before: End of comment for inclusion in the docs. */ diff --git a/gcc/jit/docs/intro/factorial.png b/gcc/jit/docs/intro/factorial.png Binary files differnew file mode 100644 index 00000000000..dff47ce2767 --- /dev/null +++ b/gcc/jit/docs/intro/factorial.png diff --git a/gcc/jit/docs/intro/index.rst b/gcc/jit/docs/intro/index.rst new file mode 100644 index 00000000000..d3bcec93c75 --- /dev/null +++ b/gcc/jit/docs/intro/index.rst @@ -0,0 +1,27 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +Tutorial +======== + +.. toctree:: + :maxdepth: 2 + + tutorial01.rst + tutorial02.rst + tutorial03.rst + tutorial04.rst diff --git a/gcc/jit/docs/intro/sum-of-squares.png b/gcc/jit/docs/intro/sum-of-squares.png Binary files differnew file mode 100644 index 00000000000..7a3b4afff38 --- /dev/null +++ b/gcc/jit/docs/intro/sum-of-squares.png diff --git a/gcc/jit/docs/intro/tutorial01.rst b/gcc/jit/docs/intro/tutorial01.rst new file mode 100644 index 00000000000..b1a51288d7b --- /dev/null +++ b/gcc/jit/docs/intro/tutorial01.rst @@ -0,0 +1,52 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Tutorial part 1: "Hello world" +============================== + +Before we look at the details of the API, let's look at building and +running programs that use the library. + +Here's a toy "hello world" program that uses the library to synthesize +a call to `printf` and uses it to write a message to stdout. + +Don't worry about the content of the program for now; we'll cover +the details in later parts of this tutorial. + + .. literalinclude:: ../examples/tut01-hello-world.c + :language: c + +Copy the above to `tut01-hello-world.c`. + +Assuming you have the jit library installed, build the test program +using: + +.. code-block:: console + + $ gcc \ + tut01-hello-world.c \ + -o tut01-hello-world \ + -lgccjit + +You should then be able to run the built program: + +.. code-block:: console + + $ ./tut01-hello-world + hello world diff --git a/gcc/jit/docs/intro/tutorial02.rst b/gcc/jit/docs/intro/tutorial02.rst new file mode 100644 index 00000000000..f52499ea0aa --- /dev/null +++ b/gcc/jit/docs/intro/tutorial02.rst @@ -0,0 +1,349 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Tutorial part 2: Creating a trivial machine code function +--------------------------------------------------------- + +Consider this C function: + +.. code-block:: c + + int square (int i) + { + return i * i; + } + +How can we construct this at run-time using libgccjit? + +First we need to include the relevant header: + +.. code-block:: c + + #include <libgccjit.h> + +All state associated with compilation is associated with a +:c:type:`gcc_jit_context *`. + +Create one using :c:func:`gcc_jit_context_acquire`: + +.. code-block:: c + + gcc_jit_context *ctxt; + ctxt = gcc_jit_context_acquire (); + +The JIT library has a system of types. It is statically-typed: every +expression is of a specific type, fixed at compile-time. In our example, +all of the expressions are of the C `int` type, so let's obtain this from +the context, as a :c:type:`gcc_jit_type *`, using +:c:func:`gcc_jit_context_get_type`: + +.. code-block:: c + + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + +:c:type:`gcc_jit_type *` is an example of a "contextual" object: every +entity in the API is associated with a :c:type:`gcc_jit_context *`. + +Memory management is easy: all such "contextual" objects are automatically +cleaned up for you when the context is released, using +:c:func:`gcc_jit_context_release`: + +.. code-block:: c + + gcc_jit_context_release (ctxt); + +so you don't need to manually track and cleanup all objects, just the +contexts. + +Although the API is C-based, there is a form of class hierarchy, which +looks like this:: + + +- gcc_jit_object + +- gcc_jit_location + +- gcc_jit_type + +- gcc_jit_struct + +- gcc_jit_field + +- gcc_jit_function + +- gcc_jit_block + +- gcc_jit_rvalue + +- gcc_jit_lvalue + +- gcc_jit_param + +There are casting methods for upcasting from subclasses to parent classes. +For example, :c:func:`gcc_jit_type_as_object`: + +.. code-block:: c + + gcc_jit_object *obj = gcc_jit_type_as_object (int_type); + +One thing you can do with a :c:type:`gcc_jit_object *` is +to ask it for a human-readable description, using +:c:func:`gcc_jit_object_get_debug_string`: + +.. code-block:: c + + printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj)); + +giving this text on stdout: + +.. code-block:: bash + + obj: int + +This is invaluable when debugging. + +Let's create the function. To do so, we first need to construct +its single parameter, specifying its type and giving it a name, +using :c:func:`gcc_jit_context_new_param`: + +.. code-block:: c + + gcc_jit_param *param_i = + gcc_jit_context_new_param (ctxt, NULL, int_type, "i"); + +Now we can create the function, using +:c:func:`gcc_jit_context_new_function`: + +.. code-block:: c + + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "square", + 1, ¶m_i, + 0); + +To define the code within the function, we must create basic blocks +containing statements. + +Every basic block contains a list of statements, eventually terminated +by a statement that either returns, or jumps to another basic block. + +Our function has no control-flow, so we just need one basic block: + +.. code-block:: c + + gcc_jit_block *block = gcc_jit_function_new_block (func, NULL); + +Our basic block is relatively simple: it immediately terminates by +returning the value of an expression. + +We can build the expression using :c:func:`gcc_jit_context_new_binary_op`: + +.. code-block:: c + + gcc_jit_rvalue *expr = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, int_type, + gcc_jit_param_as_rvalue (param_i), + gcc_jit_param_as_rvalue (param_i)); + +A :c:type:`gcc_jit_rvalue *` is another example of a +:c:type:`gcc_jit_object *` subclass. We can upcast it using +:c:func:`gcc_jit_rvalue_as_object` and as before print it with +:c:func:`gcc_jit_object_get_debug_string`. + +.. code-block:: c + + printf ("expr: %s\n", + gcc_jit_object_get_debug_string ( + gcc_jit_rvalue_as_object (expr))); + +giving this output: + +.. code-block:: bash + + expr: i * i + +Creating the expression in itself doesn't do anything; we have to add +this expression to a statement within the block. In this case, we use it +to build a return statement, which terminates the basic block: + +.. code-block:: c + + gcc_jit_block_end_with_return (block, NULL, expr); + +OK, we've populated the context. We can now compile it using +:c:func:`gcc_jit_context_compile`: + +.. code-block:: c + + gcc_jit_result *result; + result = gcc_jit_context_compile (ctxt); + +and get a :c:type:`gcc_jit_result *`. + +We can now use :c:func:`gcc_jit_result_get_code` to look up a specific +machine code routine within the result, in this case, the function we +created above. + +.. code-block:: c + + void *fn_ptr = gcc_jit_result_get_code (result, "square"); + if (!fn_ptr) + { + fprintf (stderr, "NULL fn_ptr"); + goto error; + } + +We can now cast the pointer to an appropriate function pointer type, and +then call it: + +.. code-block:: c + + typedef int (*fn_type) (int); + fn_type square = (fn_type)fn_ptr; + printf ("result: %d", square (5)); + +.. code-block:: bash + + result: 25 + + +Options +******* + +To get more information on what's going on, you can set debugging flags +on the context using :c:func:`gcc_jit_context_set_bool_option`. + +.. (I'm deliberately not mentioning + :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think + it's probably more of use to implementors than to users) + +Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a +C-like representation to stderr when you compile (GCC's "GIMPLE" +representation): + +.. code-block:: c + + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, + 1); + result = gcc_jit_context_compile (ctxt); + +.. code-block:: c + + square (signed int i) + { + signed int D.260; + + entry: + D.260 = i * i; + return D.260; + } + +We can see the generated machine code in assembler form (on stderr) by +setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context +before compiling: + +.. code-block:: c + + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, + 1); + result = gcc_jit_context_compile (ctxt); + +.. code-block:: gas + + .file "fake.c" + .text + .globl square + .type square, @function + square: + .LFB6: + .cfi_startproc + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset 6, -16 + movq %rsp, %rbp + .cfi_def_cfa_register 6 + movl %edi, -4(%rbp) + .L14: + movl -4(%rbp), %eax + imull -4(%rbp), %eax + popq %rbp + .cfi_def_cfa 7, 8 + ret + .cfi_endproc + .LFE6: + .size square, .-square + .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)" + .section .note.GNU-stack,"",@progbits + +By default, no optimizations are performed, the equivalent of GCC's +`-O0` option. We can turn things up to e.g. `-O3` by calling +:c:func:`gcc_jit_context_set_int_option` with +:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`: + +.. code-block:: c + + gcc_jit_context_set_int_option ( + ctxt, + GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, + 3); + +.. code-block:: gas + + .file "fake.c" + .text + .p2align 4,,15 + .globl square + .type square, @function + square: + .LFB7: + .cfi_startproc + .L16: + movl %edi, %eax + imull %edi, %eax + ret + .cfi_endproc + .LFE7: + .size square, .-square + .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)" + .section .note.GNU-stack,"",@progbits + +Naturally this has only a small effect on such a trivial function. + + +Full example +************ + +Here's what the above looks like as a complete program: + + .. literalinclude:: ../examples/tut02-square.c + :lines: 1- + :language: c + +Building and running it: + +.. code-block:: console + + $ gcc \ + tut02-square.c \ + -o tut02-square \ + -lgccjit + + # Run the built program: + $ ./tut02-square + result: 25 diff --git a/gcc/jit/docs/intro/tutorial03.rst b/gcc/jit/docs/intro/tutorial03.rst new file mode 100644 index 00000000000..08451509d16 --- /dev/null +++ b/gcc/jit/docs/intro/tutorial03.rst @@ -0,0 +1,378 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +Tutorial part 3: Loops and variables +------------------------------------ +Consider this C function: + + .. code-block:: c + + int loop_test (int n) + { + int sum = 0; + for (int i = 0; i < n; i++) + sum += i * i; + return sum; + } + +This example demonstrates some more features of libgccjit, with local +variables and a loop. + +To break this down into libgccjit terms, it's usually easier to reword +the `for` loop as a `while` loop, giving: + + .. code-block:: c + + int loop_test (int n) + { + int sum = 0; + int i = 0; + while (i < n) + { + sum += i * i; + i++; + } + return sum; + } + +Here's what the final control flow graph will look like: + + .. figure:: sum-of-squares.png + :alt: image of a control flow graph + +As before, we include the libgccjit header and make a +:c:type:`gcc_jit_context *`. + +.. code-block:: c + + #include <libgccjit.h> + + void test (void) + { + gcc_jit_context *ctxt; + ctxt = gcc_jit_context_acquire (); + +The function works with the C `int` type: + +.. code-block:: c + + gcc_jit_type *the_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *return_type = the_type; + +though we could equally well make it work on, say, `double`: + +.. code-block:: c + + gcc_jit_type *the_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + +Let's build the function: + +.. code-block:: c + + 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); + +Expressions: lvalues and rvalues +******************************** + +The base class of expression is the :c:type:`gcc_jit_rvalue *`, +representing an expression that can be on the *right*-hand side of +an assignment: a value that can be computed somehow, and assigned +*to* a storage area (such as a variable). It has a specific +:c:type:`gcc_jit_type *`. + +Anothe important class is :c:type:`gcc_jit_lvalue *`. +A :c:type:`gcc_jit_lvalue *`. is something that can of the *left*-hand +side of an assignment: a storage area (such as a variable). + +In other words, every assignment can be thought of as: + +.. code-block:: c + + LVALUE = RVALUE; + +Note that :c:type:`gcc_jit_lvalue *` is a subclass of +:c:type:`gcc_jit_rvalue *`, where in an assignment of the form: + +.. code-block:: c + + LVALUE_A = LVALUE_B; + +the `LVALUE_B` implies reading the current value of that storage +area, assigning it into the `LVALUE_A`. + +So far the only expressions we've seen are `i * i`: + +.. code-block:: c + + 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)); + +which is a :c:type:`gcc_jit_rvalue *`, and the various function +parameters: `param_i` and `param_n`, instances of +:c:type:`gcc_jit_param *`, which is a subclass of +:c:type:`gcc_jit_lvalue *` (and, in turn, of :c:type:`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 :c:func:`gcc_jit_function_new_local`, supplying a type and a +name: + +.. code-block:: c + + /* 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"); + +These are instances of :c:type:`gcc_jit_lvalue *` - they can be read from +and written to. + +Note that there is no precanned way to create *and* initialize a variable +like in C: + +.. code-block:: c + + int i = 0; + +Instead, having added the local to the function, we have to separately add +an assignment of `0` to `local_i` at the beginning of the function. + +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: + +1. before the loop (initializing the locals) +2. the conditional at the top of the loop (comparing `i < n`) +3. the body of the loop +4. after the loop terminates (`return sum`) + +so we create these as :c:type:`gcc_jit_block *` instances within the +:c:type:`gcc_jit_function *`: + +.. code-block:: c + + 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"); + +We now populate each block with statements. + +The entry block `b_initial` consists of initializations followed by a jump +to the conditional. We assign `0` to `i` and to `sum`, using +:c:func:`gcc_jit_block_add_assignment` to add +an assignment statement, and using :c:func:`gcc_jit_context_zero` to get +the constant value `0` for the relevant type for the right-hand side of +the assignment: + +.. code-block:: c + + /* 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)); + +We can then terminate the entry block by jumping to the conditional: + +.. code-block:: c + + gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond); + +The conditional block is equivalent to the line `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 +:c:type:`gcc_jit_rvalue *`, in this case the comparison of `i` and `n`. +We build the comparison using :c:func:`gcc_jit_context_new_comparison`: + +.. code-block:: c + + 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)); + +and can then use this to add `b_loop_cond`'s sole statement, via +:c:func:`gcc_jit_block_end_with_conditional`: + +.. code-block:: c + + gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard); + +Next, we populate the body of the loop. + +The C statement `sum += i * i;` is an assignment operation, where an +lvalue is modified "in-place". We use +:c:func:`gcc_jit_block_add_assignment_op` to handle these operations: + +.. code-block:: c + + /* 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))); + +The `i++` can be thought of as `i += 1`, and can thus be handled in +a similar way. We use :c:func:`gcc_jit_context_one` to get the constant +value `1` (for the relevant type) for the right-hand side +of the assignment. + +.. code-block:: c + + /* i++ */ + gcc_jit_block_add_assignment_op ( + b_loop_body, NULL, + i, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, the_type)); + +.. note:: + + For numeric constants other than 0 or 1, we could use + :c:func:`gcc_jit_context_new_rvalue_from_int` and + :c:func:`gcc_jit_context_new_rvalue_from_double`. + +The loop body completes by jumping back to the conditional: + +.. code-block:: c + + gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond); + +Finally, we populate the `b_after_loop` block, reached when the loop +conditional is false. We want to generate the equivalent of: + +.. code-block:: c + + return sum; + +so the block is just one statement: + +.. code-block:: c + + /* return sum */ + gcc_jit_block_end_with_return ( + b_after_loop, + NULL, + gcc_jit_lvalue_as_rvalue (sum)); + +.. 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, + *then* all the statements. + +We've finished populating the function. As before, we can now compile it +to machine code: + +.. code-block:: c + + 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)); + +.. code-block:: bash + + result: 285 + + +Visualizing the control flow graph +********************************** + +You can see the control flow graph of a function using +:c:func:`gcc_jit_function_dump_to_dot`: + +.. code-block:: c + + gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot"); + +giving a .dot file in GraphViz format. + +You can convert this to an image using `dot`: + +.. code-block:: bash + + $ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png + +or use a viewer (my preferred one is xdot.py; see +https://github.com/jrfonseca/xdot.py; on Fedora you can +install it with `yum install python-xdot`): + + .. figure:: sum-of-squares.png + :alt: image of a control flow graph + +Full example +************ + + .. literalinclude:: ../examples/tut03-sum-of-squares.c + :lines: 1- + :language: c + +Building and running it: + +.. code-block:: console + + $ gcc \ + tut03-sum-of-squares.c \ + -o tut03-sum-of-squares \ + -lgccjit + + # Run the built program: + $ ./tut03-sum-of-squares + loop_test returned: 285 diff --git a/gcc/jit/docs/intro/tutorial04.rst b/gcc/jit/docs/intro/tutorial04.rst new file mode 100644 index 00000000000..cafdddb2aef --- /dev/null +++ b/gcc/jit/docs/intro/tutorial04.rst @@ -0,0 +1,1108 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +Tutorial part 4: Adding JIT-compilation to a toy interpreter +------------------------------------------------------------ +In this example we construct a "toy" interpreter, and add JIT-compilation +to it. + +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: + + * The only data type is `int` + + * It can only work on one function at a time (so that the only + function call that can be made is to recurse). + + * Functions can only take one parameter. + + * Functions have a stack of `int` values. + + * We'll implement function call within the interpreter by calling a + function in our implementation, rather than implementing our own + frame stack. + + * The parser is only good enough to get the examples to work. + +Naturally, a real interpreter would be much more complicated that this. + +The following operations are supported: + +====================== ======================== =============== ============== +Operation Meaning Old Stack New Stack +====================== ======================== =============== ============== +DUP Duplicate top of stack. ``[..., x]`` ``[..., x, x]`` +ROT Swap top two elements ``[..., x, y]`` ``[..., y, x]`` + of stack. +BINARY_ADD Add the top two elements ``[..., x, y]`` ``[..., (x+y)]`` + on the stack. +BINARY_SUBTRACT Likewise, but subtract. ``[..., x, y]`` ``[..., (x-y)]`` +BINARY_MULT Likewise, but multiply. ``[..., x, y]`` ``[..., (x*y)]`` +BINARY_COMPARE_LT Compare the top two ``[..., x, y]`` ``[..., (x<y)]`` + elements on the stack + and push a nonzero/zero + if (x<y). +RECURSE Recurse, passing the top ``[..., x]`` ``[..., fn(x)]`` + of the stack, and + popping the result. +RETURN Return the top of the ``[x]`` ``[]`` + stack. +PUSH_CONST `arg` Push an int const. ``[...]`` ``[..., arg]`` +JUMP_ABS_IF_TRUE `arg` Pop; if top of stack was ``[..., x]`` ``[...]`` + nonzero, jump to + ``arg``. +====================== ======================== =============== ============== + +Programs can be interpreted, disassembled, and compiled to machine code. + +The interpreter reads ``.toy`` scripts. Here's what a simple recursive +factorial program looks like, the script ``factorial.toy``. +The parser ignores lines beginning with a `#`. + + .. literalinclude:: ../examples/tut04-toyvm/factorial.toy + :lines: 1- + :language: c + +The interpreter is a simple infinite loop with a big ``switch`` statement +based on what the next opcode is: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Execute the given function. */ + :end-before: /* JIT compilation. */ + :language: c + +Compiling to machine code +************************* +We want to generate machine code that can be cast to this type and +then directly executed in-process: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Functions are compiled to this function ptr type. */ + :end-before: enum opcode + :language: c + +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 ``stack`` array and ``stack_depth`` +variables, local within the generated function, equivalent to this C code: + +.. code-block:: c + + int stack_depth; + int stack[MAX_STACK_DEPTH]; + +We'll also have local variables ``x`` and ``y`` for use when implementing +the opcodes, equivalent to this: + +.. code-block:: c + + int x; + int y; + +This means our compiler has the following state: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* JIT compilation. */ + :end-before: /* Stack manipulation. */ + :language: c + +Setting things up +***************** + +First we create our types: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Create types. */ + :end-before: /* The constant value 1. */ + :language: c + +along with extracting a useful `int` constant: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* The constant value 1. */ + :end-before: /* Create locations. */ + :language: c + +We'll implement push and pop in terms of the ``stack`` array and +``stack_depth``. Here are helper functions for adding statements to +a block, implementing pushing and popping values: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Stack manipulation. */ + :end-before: /* The main compilation hook. */ + :language: c + +We will support single-stepping through the generated code in the +debugger, so we need to create :c:type:`gcc_jit_location` instances, one +per operation in the source code. These will reference the lines of +e.g. ``factorial.toy``. + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Create locations. */ + :end-before: /* Creating the function. */ + :language: c + +Let's create the function itself. As usual, we create its parameter +first, then use the parameter to create the function: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Creating the function. */ + :end-before: /* Create stack lvalues. */ + :language: c + +We create the locals within the function. + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Create stack lvalues. */ + :end-before: /* 1st pass: create blocks, one per opcode. + :language: c + +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: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: first. */ + :end-before: /* Create a block per operation. */ + :language: c + +We can now create blocks for each of the operations. Most of these will +be consolidated into larger blocks when the optimizer runs. + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Create a block per operation. */ + :end-before: /* Populate the initial block. */ + :language: c + +Now that we have a block it can jump to when it's done, we can populate +the initial block: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Populate the initial block. */ + :end-before: /* 2nd pass: fill in instructions. */ + :language: c + +We can now populate the blocks for the individual operations. We loop +through them, adding instructions to their blocks: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* 2nd pass: fill in instructions. */ + :end-before: /* Helper macros. */ + :language: c + +We're going to have another big ``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 ``switch`` statement that's coming up look as much as +possible like the one above within the interpreter: + +.. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Helper macros. */ + :end-before: gcc_jit_block_add_comment + :language: c + +.. note:: + + A particularly clever implementation would have an *identical* + ``switch`` statement shared by the interpreter and the compiler, with + some preprocessor "magic". We're not doing that here, for the sake + of simplicity. + +When I first implemented this compiler, I accidentally missed an edit +when copying and pasting the ``Y_EQUALS_POP`` macro, so that popping the +stack into ``y`` instead erroneously assigned it to ``x``, leaving ``y`` +uninitialized. + +To track this kind of thing down, we can use +:c:func:`gcc_jit_block_add_comment` to add descriptive comments +to the internal representation. This is invaluable when looking through +the generated IR for, say ``factorial``: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y)) + :end-before: /* Handle the individual opcodes. */ + :language: c + +We can now write the big ``switch`` statement that implements the +individual opcodes, populating the relevant block with statements: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Handle the individual opcodes. */ + :end-before: /* Go to the next block. */ + :language: c + +Every block must be terminated, via a call to one of the +``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. + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* Go to the next block. */ + :end-before: /* end of loop on PC locations. */ + :language: c + +This is analogous to simply incrementing the program counter. + +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 :c:func:`gcc_jit_function_dump_to_dot`: + +.. code-block:: c + + gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot"); + +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. + + .. figure:: factorial.png + :alt: image of a control flow graph + +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: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* We've now finished populating the context. Compile it. */ + :end-before: /* (this leaks "result" and "funcname") */ + :language: c + +We can now run the result: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* JIT-compilation. */ + :end-before: return 0; + :language: c + +Single-stepping through the generated code +****************************************** + +It's possible to debug the generated code. To do this we need to both: + + * Set up source code locations for our statements, so that we can + meaningfully step through the code. We did this above by + calling :c:func:`gcc_jit_context_new_location` and using the + results. + + * Enable the generation of debugging information, by setting + :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the + :c:type:`gcc_jit_context` via + :c:func:`gcc_jit_context_set_bool_option`: + + .. code-block:: c + + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DEBUGINFO, + 1); + +Having done this, we can put a breakpoint on the generated function: + +.. code-block:: console + + $ 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 + +We've set up location information, which references ``factorial.toy``. +This allows us to use e.g. ``list`` to see where we are in the script: + +.. code-block:: console + + (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 + +and to step through the function, examining the data: + +.. code-block:: console + + (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 + +You'll see that the parts of the ``stack`` array that haven't been +touched yet are uninitialized. + +.. 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. + +Examining the generated code +**************************** + +How good is the optimized code? + +We can turn up optimizations, by calling +:c:func:`gcc_jit_context_set_int_option` with +:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`: + +.. code-block:: c + + gcc_jit_context_set_int_option ( + ctxt, + GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, + 3); + +One of GCC's internal representations is called "gimple". A dump of the +initial gimple representation of the code can be seen by setting: + +.. code-block:: c + + gcc_jit_context_set_bool_option (ctxt, + GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, + 1); + +With optimization on and source locations displayed, this gives: + +.. We'll use "c" for gimple dumps + +.. code-block:: c + + 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 */ + +You can see the generated machine code in assembly form via: + +.. code-block:: c + + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, + 1); + result = gcc_jit_context_compile (ctxt); + +which shows that (on this x86_64 box) the compiler has unrolled the loop +and is using MMX instructions to perform several multiplications +simultaneously: + +.. code-block:: gas + + .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 + +This is clearly overkill for a function that will likely overflow the +``int`` type before the vectorization is worthwhile - but then again, this +is a toy example. + +Turning down the optimization level to 2: + +.. code-block:: c + + gcc_jit_context_set_int_option ( + ctxt, + GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, + 3); + +yields this code, which is simple enough to quote in its entirety: + +.. code-block:: gas + + .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 + +Note that the stack pushing and popping have been eliminated, as has the +recursive call (in favor of an iteration). + +Putting it all together +*********************** + +The complete example can be seen in the source tree at +``gcc/jit/docs/examples/tut04-toyvm/toyvm.c`` + +along with a Makefile and a couple of sample .toy scripts: + +.. code-block:: console + + $ 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 + +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: + +.. code-block:: c + + 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); + +This will dump detailed information about the compiler's state to a +directory under ``/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): + +.. code-block:: console + + 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 + +The gimple code is converted into Static Single Assignment form, +with annotations for use when generating the debuginfo: + +.. code-block:: console + + $ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa + +.. code-block:: c + + ;; 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 */ + +We can perhaps better see the code by turning off +:c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to suppress all those ``DEBUG`` +statements, giving: + +.. code-block:: console + + $ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa + +.. code-block:: c + + ;; 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; + + } + +Note in the above how all the :c:type:`gcc_jit_block` instances we +created have been consolidated into just 3 blocks in GCC's internal +representation: ``initial``, ``instr4`` and ``instr9``. + +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: + +.. code-block:: console + + $ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1 + +.. code-block:: c + + ;; 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; + + } + +Note how, in the above, all those ``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: + +.. code-block:: console + + $ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra + +.. code-block:: c + + ;; 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; + + } + +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: + +.. code-block:: console + + $ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1 + +.. code-block:: c + + ;; 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; + + } + +Later on, another pass finally eliminated ``stack_depth`` local and the +unused parts of the `stack`` array altogether: + +.. code-block:: console + + $ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa + +.. code-block:: c + + ;; 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; + + } + + +Elimination of tail recursion +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Another significant optimization is the detection that the call to +``factorial`` is tail recursion, which can be eliminated in favor of +an iteration: + +.. code-block:: console + + $ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1 + +.. code-block:: c + + ;; 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; + + } diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst new file mode 100644 index 00000000000..d8dd4f8df71 --- /dev/null +++ b/gcc/jit/docs/topics/contexts.rst @@ -0,0 +1,315 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Compilation contexts +==================== + +.. type:: gcc_jit_context + +The top-level of the API is the :c:type:`gcc_jit_context` type. + +A :c:type:`gcc_jit_context` instance encapsulates the state of a +compilation. + +You can set up options on it, and add types, functions and code. +Invoking :c:func:`gcc_jit_context_compile` on it gives you a +:c:type:`gcc_jit_result`. + +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. + +.. function:: gcc_jit_context *gcc_jit_context_acquire (void) + + This function acquires a new :c:type:`gcc_jit_object *` instance, + which is independent of any others that may be present within this + process. + +.. function:: void gcc_jit_context_release (gcc_jit_context *ctxt) + + This function releases all resources associated with the given context. + Both the context itself and all of its :c:type:`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. + + .. code-block:: c + + gcc_jit_context_release (ctxt); + +.. function:: gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context *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. + + +Thread-safety +------------- +Instances of :c:type:`gcc_jit_object *` created via +:c:func:`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 :c:func:`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. + + +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 +:c:func:`gcc_jit_context_get_first_error`. + +.. function:: const char *\ + gcc_jit_context_get_first_error (gcc_jit_context *ctxt) + + Returns the first error message that occurred on the context. + + The returned string is valid for the rest of the lifetime of the + context. + + If no errors occurred, this will be NULL. + +Debugging +--------- + +.. function:: void\ + gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,\ + const char *path,\ + int update_locations) + + To help with debugging: dump a C-like representation to the given path, + describing what's been set up on the context. + + If "update_locations" is true, then also set up :type:`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 + :macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to allow stepping through the + code in a debugger. + + +Options +------- + +String Options +************** + +.. function:: void gcc_jit_context_set_str_option(gcc_jit_context *ctxt, \ + enum gcc_jit_str_option opt, \ + const char *value) + + Set a string option of the context. + + .. type:: enum gcc_jit_str_option + + There is currently just one string option: + + .. macro:: GCC_JIT_STR_OPTION_PROGNAME + + The name of the program, for use as a prefix when printing error + messages to stderr. If `NULL`, or default, "libgccjit.so" is used. + +Boolean options +*************** + +.. function:: void gcc_jit_context_set_bool_option(gcc_jit_context *ctxt, \ + enum gcc_jit_bool_option opt, \ + int value) + + Set a boolean option of the context. + Zero is "false" (the default), non-zero is "true". + + .. type:: enum gcc_jit_bool_option + + .. macro:: GCC_JIT_BOOL_OPTION_DEBUGINFO + + If true, :func:`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 + :type:`gcc_jit_location` instances). + + .. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE + + If true, :func:`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 `square` 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>>>>> + + .. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE + + If true, :func:`gcc_jit_context_compile` will dump the "gimple" + representation of your code to stderr, before any optimizations + are performed. The dump resembles C code: + + .. code-block:: c + + square (signed int i) + { + signed int D.56; + + entry: + D.56 = i * i; + return D.56; + } + + .. macro:: GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE + + If true, :func:`gcc_jit_context_compile` will dump the final + generated code to stderr, in the form of assembly language: + + .. code-block:: gas + + .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 + + + .. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY + + If true, :func:`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. + + .. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING + + If true, :func:`gcc_jit_context_compile` will dump copious + amount of information on what it's doing to various + files within a temporary directory. Use + :macro:`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. + + .. 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 *of* the library. It is + used when running the selftest suite. + + .. macro:: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES + + If true, the :type:`gcc_jit_context` will not clean up intermediate files + written to the filesystem, and will display their location on stderr. + +Integer options +*************** + +.. function:: void gcc_jit_context_set_int_option (gcc_jit_context *ctxt, \ + enum gcc_jit_int_option opt, \ + int value) + + Set an integer option of the context. + + .. type:: enum gcc_jit_int_option + + There is currently just one integer option: + + .. 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). diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst new file mode 100644 index 00000000000..1cf9641aaf1 --- /dev/null +++ b/gcc/jit/docs/topics/expressions.rst @@ -0,0 +1,525 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Expressions +=========== + +Rvalues +------- +.. type:: gcc_jit_rvalue + +A :c:type:`gcc_jit_rvalue *` is an expression that can be computed. + +It can be simple, e.g.: + + * an integer value e.g. `0` or `42` + * a string literal e.g. `"Hello world"` + * a variable e.g. `i`. These are also lvalues (see below). + +or compound e.g.: + + * a unary expression e.g. `!cond` + * a binary expression e.g. `(a + b)` + * a function call e.g. `get_distance (&player_ship, &target)` + * etc. + +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). + +.. function:: gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue) + + Get the type of this rvalue. + +.. function:: gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue) + + Upcast the given rvalue to be an object. + + +Simple expressions +****************** + +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + int value) + + Given a numeric type (integer or floating point), build an rvalue for + the given constant value. + +.. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type) + + Given a numeric type (integer or floating point), get the rvalue for + zero. Essentially this is just a shortcut for: + + .. code-block:: c + + gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0) + +.. function:: gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type) + + Given a numeric type (integer or floating point), get the rvalue for + zero. Essentially this is just a shortcut for: + + .. code-block:: c + + gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1) + +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + double value) + + Given a numeric type (integer or floating point), build an rvalue for + the given constant value. + +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \ + gcc_jit_type *pointer_type, \ + void *value) + + Given a pointer type, build an rvalue for the given address. + +.. function:: gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context *ctxt, \ + gcc_jit_type *pointer_type) + + Given a pointer type, build an rvalue for ``NULL``. Essentially this + is just a shortcut for: + + .. code-block:: c + + gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL) + +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, \ + const char *value) + + Generate an rvalue for the given NIL-terminated string, of type + :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`. + + +Unary Operations +**************** + +.. function:: gcc_jit_rvalue * \ + gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, \ + gcc_jit_location *loc, \ + enum gcc_jit_unary_op op, \ + gcc_jit_type *result_type, \ + gcc_jit_rvalue *rvalue) + + Build a unary operation out of an input rvalue. + +.. type:: enum gcc_jit_unary_op + +The available unary operations are: + +========================================== ============ +Unary Operation C equivalent +========================================== ============ +:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)` +:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)` +:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)` +========================================== ============ + +.. c:macro:: GCC_JIT_UNARY_OP_MINUS + + Negate an arithmetic value; analogous to: + + .. code-block:: c + + -(EXPR) + + in C. + +.. c:macro:: GCC_JIT_UNARY_OP_BITWISE_NEGATE + + Bitwise negation of an integer value (one's complement); analogous + to: + + .. code-block:: c + + ~(EXPR) + + in C. + +.. c:macro:: GCC_JIT_UNARY_OP_LOGICAL_NEGATE + + Logical negation of an arithmetic or pointer value; analogous to: + + .. code-block:: c + + !(EXPR) + + in C. + +Binary Operations +***************** + +.. function:: gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, \ + gcc_jit_location *loc, \ + enum gcc_jit_binary_op op, \ + gcc_jit_type *result_type, \ + gcc_jit_rvalue *a, gcc_jit_rvalue *b) + + Build a binary operation out of two constituent rvalues. + +.. type:: enum gcc_jit_binary_op + +The available binary operations are: + +======================================== ============ +Binary Operation C equivalent +======================================== ============ +:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y` +:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y` +:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y` +:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y` +:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y` +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y` +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y` +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y` +:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y` +:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y` +:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y` +:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y` +======================================== ============ + +.. c:macro:: GCC_JIT_BINARY_OP_PLUS + + Addition of arithmetic values; analogous to: + + .. code-block:: c + + (EXPR_A) + (EXPR_B) + + in C. + + For pointer addition, use :c:func:`gcc_jit_context_new_array_access`. + +.. c:macro:: GCC_JIT_BINARY_OP_MINUS` + + Subtraction of arithmetic values; analogous to: + + .. code-block:: c + + (EXPR_A) - (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_MULT + + Multiplication of a pair of arithmetic values; analogous to: + + .. code-block:: c + + (EXPR_A) * (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_DIVIDE + + Quotient of division of arithmetic values; analogous to: + + .. code-block:: c + + (EXPR_A) / (EXPR_B) + + 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. + +.. c:macro:: GCC_JIT_BINARY_OP_MODULO + + Remainder of division of arithmetic values; analogous to: + + .. code-block:: c + + (EXPR_A) % (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_AND + + Bitwise AND; analogous to: + + .. code-block:: c + + (EXPR_A) & (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_XOR + + Bitwise exclusive OR; analogous to: + + .. code-block:: c + + (EXPR_A) ^ (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_OR + + Bitwise inclusive OR; analogous to: + + .. code-block:: c + + (EXPR_A) | (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_AND + + Logical AND; analogous to: + + .. code-block:: c + + (EXPR_A) && (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_OR + + Logical OR; analogous to: + + .. code-block:: c + + (EXPR_A) || (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_LSHIFT + + Left shift; analogous to: + + .. code-block:: c + + (EXPR_A) << (EXPR_B) + + in C. + +.. c:macro:: GCC_JIT_BINARY_OP_RSHIFT + + Right shift; analogous to: + + .. code-block:: c + + (EXPR_A) >> (EXPR_B) + + in C. + +Comparisons +*********** + +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_comparison (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + enum gcc_jit_comparison op,\ + gcc_jit_rvalue *a, gcc_jit_rvalue *b) + + Build a boolean rvalue out of the comparison of two other rvalues. + +.. type:: enum gcc_jit_comparison + +======================================= ============ +Comparison C equivalent +======================================= ============ +:c:macro:`GCC_JIT_COMPARISON_EQ` `x == y` +:c:macro:`GCC_JIT_COMPARISON_NE` `x != y` +:c:macro:`GCC_JIT_COMPARISON_LT` `x < y` +:c:macro:`GCC_JIT_COMPARISON_LE` `x <= y` +:c:macro:`GCC_JIT_COMPARISON_GT` `x > y` +:c:macro:`GCC_JIT_COMPARISON_GE` `x >= y` +======================================= ============ + + +Function calls +************** +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_call (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + gcc_jit_function *func,\ + int numargs , gcc_jit_rvalue **args) + + Given a function and the given table of argument rvalues, construct a + call to the function, with the result as an rvalue. + + .. note:: + + :c:func:`gcc_jit_context_new_call` merely builds a + :c:type:`gcc_jit_rvalue` i.e. an expression that can be evaluated, + perhaps as part of a more complicated expression. + The call *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 ``void`` return type), use + :c:func:`gcc_jit_block_add_eval`: + + .. code-block:: c + + /* Add "(void)printf (arg0, arg1);". */ + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call ( + ctxt, + NULL, + printf_func, + 2, args)); + +Type-coercion +************* + +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_cast (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + gcc_jit_rvalue *rvalue,\ + gcc_jit_type *type) + + Given an rvalue of T, construct another rvalue of another type. + + Currently only a limited set of conversions are possible: + + * int <-> float + * int <-> bool + * P* <-> Q*, for pointer types P and Q + +Lvalues +------- + +.. type:: gcc_jit_lvalue + +An lvalue is something that can of the *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. + +.. function:: gcc_jit_object *\ + gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue) + + Upcast an lvalue to be an object. + +.. function:: gcc_jit_rvalue *\ + gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue) + + Upcast an lvalue to be an rvalue. + +.. function:: gcc_jit_rvalue *\ + gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,\ + gcc_jit_location *loc) + + Take the address of an lvalue; analogous to: + + .. code-block:: c + + &(EXPR) + + in C. + +Global variables +**************** + +.. function:: gcc_jit_lvalue *\ + gcc_jit_context_new_global (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + gcc_jit_type *type,\ + const char *name) + + Add a new global variable of the given type and name to the context. + + +Working with pointers, structs and unions +----------------------------------------- + +.. function:: gcc_jit_lvalue *\ + gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,\ + gcc_jit_location *loc) + + Given an rvalue of pointer type ``T *``, dereferencing the pointer, + getting an lvalue of type ``T``. Analogous to: + + .. code-block:: c + + *(EXPR) + + in C. + +Field access is provided separately for both lvalues and rvalues. + +.. function:: gcc_jit_lvalue *\ + gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,\ + gcc_jit_location *loc,\ + gcc_jit_field *field) + + Given an lvalue of struct or union type, access the given field, + getting an lvalue of the field's type. Analogous to: + + .. code-block:: c + + (EXPR).field = ...; + + in C. + +.. function:: gcc_jit_rvalue *\ + gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,\ + gcc_jit_location *loc,\ + gcc_jit_field *field) + + Given an rvalue of struct or union type, access the given field + as an rvalue. Analogous to: + + .. code-block:: c + + (EXPR).field + + in C. + +.. function:: gcc_jit_lvalue *\ + gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,\ + gcc_jit_location *loc,\ + gcc_jit_field *field) + + Given an rvalue of pointer type ``T *`` where T is of struct or union + type, access the given field as an lvalue. Analogous to: + + .. code-block:: c + + (EXPR)->field + + in C, itself equivalent to ``(*EXPR).FIELD``. + +.. function:: gcc_jit_lvalue *\ + gcc_jit_context_new_array_access (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + gcc_jit_rvalue *ptr,\ + gcc_jit_rvalue *index) + + Given an rvalue of pointer type ``T *``, get at the element `T` at + the given index, using standard C array indexing rules i.e. each + increment of ``index`` corresponds to ``sizeof(T)`` bytes. + Analogous to: + + .. code-block:: c + + PTR[INDEX] + + in C (or, indeed, to ``PTR + INDEX``). diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst new file mode 100644 index 00000000000..aa0c0694182 --- /dev/null +++ b/gcc/jit/docs/topics/functions.rst @@ -0,0 +1,311 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Creating and using functions +============================ + +Params +------ +.. type:: gcc_jit_param + + A `gcc_jit_param` represents a parameter to a function. + +.. function:: gcc_jit_param *\ + gcc_jit_context_new_param (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + gcc_jit_type *type,\ + const char *name) + + In preparation for creating a function, create a new parameter of the + given type and name. + +Parameters are lvalues, and thus are also rvalues (and objects), so the +following upcasts are available: + +.. function:: gcc_jit_lvalue *\ + gcc_jit_param_as_lvalue (gcc_jit_param *param) + + Upcasting from param to lvalue. + +.. function:: gcc_jit_rvalue *\ + gcc_jit_param_as_rvalue (gcc_jit_param *param) + + Upcasting from param to rvalue. + +.. function:: gcc_jit_object *\ + gcc_jit_param_as_object (gcc_jit_param *param) + + Upcasting from param to object. + + +Functions +--------- + +.. type:: gcc_jit_function + + A `gcc_jit_function` represents a function - either one that we're + creating ourselves, or one that we're referencing. + +.. function:: gcc_jit_function *\ + gcc_jit_context_new_function (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + enum gcc_jit_function_kind kind,\ + gcc_jit_type *return_type,\ + const char *name,\ + int num_params,\ + gcc_jit_param **params,\ + int is_variadic) + + Create a gcc_jit_function with the given name and parameters. + + .. type:: enum gcc_jit_function_kind + + This enum controls the kind of function created, and has the following + values: + + .. macro:: GCC_JIT_FUNCTION_EXPORTED + + Function is defined by the client code and visible + by name outside of the JIT. + + .. macro:: GCC_JIT_FUNCTION_INTERNAL + + Function is defined by the client code, but is invisible + outside of the JIT. Analogous to a "static" function. + + .. 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. + + .. 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 ``inline`` and adding + ``__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. + +.. function:: gcc_jit_function *\ + gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,\ + const char *name) + +.. function:: gcc_jit_object *\ + gcc_jit_function_as_object (gcc_jit_function *func) + + Upcasting from function to object. + +.. function:: gcc_jit_param *\ + gcc_jit_function_get_param (gcc_jit_function *func, int index) + + Get the param of the given index (0-based). + +.. function:: void \ + gcc_jit_function_dump_to_dot (gcc_jit_function *func,\ + const char *path) + + Emit the function in graphviz format to the given path. + +.. function:: gcc_jit_lvalue *\ + gcc_jit_function_new_local (gcc_jit_function *func,\ + gcc_jit_location *loc,\ + gcc_jit_type *type,\ + const char *name) + + Create a new local variable within the function, of the given type and + name. + + +Blocks +------ +.. type:: gcc_jit_block + + A `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. + +.. function:: gcc_jit_block *\ + gcc_jit_function_new_block (gcc_jit_function *func,\ + const char *name) + + Create a basic block of the given name. The name may be NULL, but + providing meaningful names is often helpful when debugging: it may + show up in dumps of the internal representation, and in error + messages. + +.. function:: gcc_jit_object *\ + gcc_jit_block_as_object (gcc_jit_block *block) + + Upcast from block to object. + +.. function:: gcc_jit_function *\ + gcc_jit_block_get_function (gcc_jit_block *block) + + Which function is this block within? + + +Statements +---------- + +.. function:: void\ + gcc_jit_block_add_eval (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + gcc_jit_rvalue *rvalue) + + Add evaluation of an rvalue, discarding the result + (e.g. a function call that "returns" void). + + This is equivalent to this C code: + + .. code-block:: c + + (void)expression; + +.. function:: void\ + gcc_jit_block_add_assignment (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + gcc_jit_lvalue *lvalue,\ + gcc_jit_rvalue *rvalue) + + Add evaluation of an rvalue, assigning the result to the given + lvalue. + + This is roughly equivalent to this C code: + + .. code-block:: c + + lvalue = rvalue; + +.. function:: void\ + gcc_jit_block_add_assignment_op (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + gcc_jit_lvalue *lvalue,\ + enum gcc_jit_binary_op op,\ + gcc_jit_rvalue *rvalue) + + Add evaluation of an rvalue, using the result to modify an + lvalue. + + This is analogous to "+=" and friends: + + .. code-block:: c + + lvalue += rvalue; + lvalue *= rvalue; + lvalue /= rvalue; + + etc. For example: + + .. code-block:: c + + /* "i++" */ + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + i, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + +.. function:: void\ + gcc_jit_block_add_comment (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + const char *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 :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` + and :macro:`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. + +.. function:: void\ + gcc_jit_block_end_with_conditional (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + gcc_jit_rvalue *boolval,\ + gcc_jit_block *on_true,\ + gcc_jit_block *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: + + .. code-block:: c + + if (boolval) + goto on_true; + else + goto on_false; + + block, boolval, on_true, and on_false must be non-NULL. + +.. function:: void\ + gcc_jit_block_end_with_jump (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + gcc_jit_block *target) + + + Terminate a block by adding a jump to the given target block. + + This is roughly equivalent to this C code: + + .. code-block:: c + + goto target; + +.. function:: void\ + gcc_jit_block_end_with_return (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + gcc_jit_rvalue *rvalue) + + + Terminate a block by adding evaluation of an rvalue, returning the value. + + This is roughly equivalent to this C code: + + .. code-block:: c + + return expression; + +.. function:: void\ + gcc_jit_block_end_with_void_return (gcc_jit_block *block,\ + gcc_jit_location *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: + + .. code-block:: c + + return; diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst new file mode 100644 index 00000000000..a1291375153 --- /dev/null +++ b/gcc/jit/docs/topics/index.rst @@ -0,0 +1,30 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +Topic Reference +=============== + +.. toctree:: + :maxdepth: 2 + + contexts.rst + objects.rst + types.rst + expressions.rst + functions.rst + locations.rst + results.rst diff --git a/gcc/jit/docs/topics/locations.rst b/gcc/jit/docs/topics/locations.rst new file mode 100644 index 00000000000..d1db9743622 --- /dev/null +++ b/gcc/jit/docs/topics/locations.rst @@ -0,0 +1,69 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Source Locations +================ + +.. type:: gcc_jit_location + + A `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. + + `gcc_jit_location` instances are optional: you can always pass NULL to + any API entrypoint accepting one. + + You can construct them using :c:func:`gcc_jit_context_new_location`. + + You need to enable :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the + :c:type:`gcc_jit_context` for these locations to actually be usable by + the debugger: + + .. code-block:: c + + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DEBUGINFO, + 1); + +.. function:: gcc_jit_location *\ + gcc_jit_context_new_location (gcc_jit_context *ctxt,\ + const char *filename,\ + int line,\ + int column) + + Create a `gcc_jit_location` instance representing the given source + location. + +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 :c:func:`gcc_jit_context_dump_to_file()`: + +.. code-block:: c + + gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c", + 1 /* update_locations */); + +This will dump C-like code to the given path. If the `update_locations` +argument is true, this will also set up `gcc_jit_location` information +throughout the context, pointing at the dump file as if it were a source +file, giving you *something* you can step through in the debugger. diff --git a/gcc/jit/docs/topics/objects.rst b/gcc/jit/docs/topics/objects.rst new file mode 100644 index 00000000000..b05888d4ff3 --- /dev/null +++ b/gcc/jit/docs/topics/objects.rst @@ -0,0 +1,86 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Objects +======= + +.. type:: gcc_jit_object + +Almost every entity in the API (with the exception of +:c:type:`gcc_jit_context *` and :c:type:`gcc_jit_result *`) is a +"contextual" object, a :c:type:`gcc_jit_object *` + +A JIT object: + + * is associated with a :c:type:`gcc_jit_context *`. + + * 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. + +Although the API is C-based, there is a form of class hierarchy, which +looks like this:: + + +- gcc_jit_object + +- gcc_jit_location + +- gcc_jit_type + +- gcc_jit_struct + +- gcc_jit_field + +- gcc_jit_function + +- gcc_jit_block + +- gcc_jit_rvalue + +- gcc_jit_lvalue + +- gcc_jit_param + +There are casting methods for upcasting from subclasses to parent classes. +For example, :c:func:`gcc_jit_type_as_object`: + +.. code-block:: c + + gcc_jit_object *obj = gcc_jit_type_as_object (int_type); + +The object "base class" has the following operations: + +.. function:: gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object *obj) + + Which context is "obj" within? + + +.. function:: const char *gcc_jit_object_get_debug_string (gcc_jit_object *obj) + + Generate a human-readable description for the given object. + + For example, + + .. code-block:: c + + printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj)); + + might give this text on stdout: + + .. code-block:: bash + + obj: 4.0 * (float)i + + .. note:: + + If you call this on an object, the `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. diff --git a/gcc/jit/docs/topics/results.rst b/gcc/jit/docs/topics/results.rst new file mode 100644 index 00000000000..10dc94f2cec --- /dev/null +++ b/gcc/jit/docs/topics/results.rst @@ -0,0 +1,48 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Compilation results +=================== + +.. type:: gcc_jit_result + + A `gcc_jit_result` encapsulates the result of compiling a context. + +.. function:: gcc_jit_result *\ + gcc_jit_context_compile (gcc_jit_context *ctxt) + + This calls into GCC and builds the code, returning a + `gcc_jit_result *`. + + +.. function:: void *\ + gcc_jit_result_get_code (gcc_jit_result *result,\ + const char *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. + + +.. function:: void\ + gcc_jit_result_release (gcc_jit_result *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. diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst new file mode 100644 index 00000000000..6770eca6099 --- /dev/null +++ b/gcc/jit/docs/topics/types.rst @@ -0,0 +1,217 @@ +.. Copyright (C) 2014 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalcolm@redhat.com> + + This 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 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +.. default-domain:: c + +Types +===== + +.. c:type:: gcc_jit_type + + gcc_jit_type represents a type within the library. + +.. function:: gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type *type) + + Upcast a type to an object. + +Types can be created in several ways: + +* fundamental types can be accessed using + :func:`gcc_jit_context_get_type`: + + .. code-block:: c + + gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT); + + See :func:`gcc_jit_context_get_type` for the available types. + +* derived types can be accessed by using functions such as + :func:`gcc_jit_type_get_pointer` and :func:`gcc_jit_type_get_const`: + + .. code-block:: c + + 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)); + +* by creating structures (see below). + +Standard types +-------------- + +.. function:: gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context *ctxt, \ + enum gcc_jit_types type_) + + Access a specific type. The available types are: + + ========================================= ================================ + `enum gcc_jit_types` value Meaning + ========================================= ================================ + :c:data:`GCC_JIT_TYPE_VOID` C's ``void`` type. + :c:data:`GCC_JIT_TYPE_VOID_PTR` C's ``void *``. + :c:data:`GCC_JIT_TYPE_BOOL` C++'s ``bool`` type; also C99's + ``_Bool`` type, aka ``bool`` if + using stdbool.h. + :c:data:`GCC_JIT_TYPE_CHAR` C's ``char`` (of some signedness) + :c:data:`GCC_JIT_TYPE_SIGNED_CHAR` C's ``signed char`` + :c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR` C's ``unsigned char`` + :c:data:`GCC_JIT_TYPE_SHORT` C's ``short`` (signed) + :c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT` C's ``unsigned short`` + :c:data:`GCC_JIT_TYPE_INT` C's ``int`` (signed) + :c:data:`GCC_JIT_TYPE_UNSIGNED_INT` C's ``unsigned int`` + :c:data:`GCC_JIT_TYPE_LONG` C's ``long`` (signed) + :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG` C's ``unsigned long`` + :c:data:`GCC_JIT_TYPE_LONG_LONG` C99's ``long long`` (signed) + :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG` C99's ``unsigned long long`` + :c:data:`GCC_JIT_TYPE_FLOAT` + :c:data:`GCC_JIT_TYPE_DOUBLE` + :c:data:`GCC_JIT_TYPE_LONG_DOUBLE` + :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR` C type: ``(const char *)`` + :c:data:`GCC_JIT_TYPE_SIZE_T` C's ``size_t`` type + :c:data:`GCC_JIT_TYPE_FILE_PTR` C type: ``(FILE *)`` + ========================================= ================================ + +.. function:: gcc_jit_type *\ + gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \ + int num_bytes, int is_signed) + + Access the integer type of the given size. + + +Pointers, `const`, and `volatile` +--------------------------------- + +.. function:: gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type *type) + + Given type "T", get type "T*". + +.. function:: gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type *type) + + Given type "T", get type "const T". + +.. function:: gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type *type) + + Given type "T", get type "volatile T". + +.. function:: gcc_jit_type *\ + gcc_jit_context_new_array_type (gcc_jit_context *ctxt, \ + gcc_jit_location *loc, \ + gcc_jit_type *element_type, \ + int num_elements) + + Given type "T", get type "T[N]" (for a constant N). + + +Structures and unions +--------------------- + +.. c:type:: gcc_jit_struct + +A compound type analagous to a C `struct`. + +.. c:type:: gcc_jit_field + +A field within a :c:type:`gcc_jit_struct`. + +You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and +:c:type:`gcc_jit_field` instances, in either order: + +* by creating the fields, then the structure. For example, to model: + + .. code-block:: c + + struct coord {double x; double y; }; + + you could call: + + .. code-block:: c + + 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); + +* by creating the structure, then populating it with fields, typically + to allow modelling self-referential structs such as: + + .. code-block:: c + + struct node { int m_hash; struct node *m_next; }; + + like this: + + .. code-block:: c + + 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); + +.. function:: gcc_jit_field *\ + gcc_jit_context_new_field (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + gcc_jit_type *type,\ + const char *name) + + Construct a new field, with the given type and name. + +.. function:: gcc_jit_object *\ + gcc_jit_field_as_object (gcc_jit_field *field) + + Upcast from field to object. + +.. function:: gcc_jit_struct *\ + gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + const char *name,\ + int num_fields,\ + gcc_jit_field **fields) + + Construct a new struct type, with the given name and fields. + +.. function:: gcc_jit_struct *\ + gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + const char *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 + :c:func:`gcc_jit_struct_set_fields`. + +.. function:: gcc_jit_type *\ + gcc_jit_struct_as_type (gcc_jit_struct *struct_type) + + Upcast from struct to type. + +.. function:: void\ + gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,\ + gcc_jit_location *loc,\ + int num_fields,\ + gcc_jit_field **fields) + + Populate the fields of a formerly-opaque struct type. + + This can only be called once on a given struct type. |