Commit 29df5715 by David Malcolm Committed by David Malcolm

Document libgccjit++.h

gcc/jit/ChangeLog:
	* docs/cp/index.rst: New file.
	* docs/cp/intro/index.rst: New file.
	* docs/cp/intro/tutorial01.rst: New file.
	* docs/cp/intro/tutorial02.rst: New file.
	* docs/cp/intro/tutorial03.rst: New file.
	* docs/cp/intro/tutorial04.rst: New file.
	* docs/cp/topics/contexts.rst: New file.
	* docs/cp/topics/expressions.rst: New file.
	* docs/cp/topics/functions.rst: New file.
	* docs/cp/topics/index.rst: New file.
	* docs/cp/topics/locations.rst: New file.
	* docs/cp/topics/objects.rst: New file.
	* docs/cp/topics/results.rst: New file.
	* docs/cp/topics/types.rst: New file.
	* docs/examples/tut01-hello-world.cc: New file.
	* docs/examples/tut02-square.c: Fix missing newline in output.
	* docs/examples/tut02-square.cc: New file.
	* docs/examples/tut03-sum-of-squares.cc: New file.
	* docs/examples/tut04-toyvm/toyvm.cc: New file.
	* docs/index.rst: Move summary to above the table of contents.
	Add text about the C vs C++ APIs.
	* docs/topics/contexts.rst: Fix a typo.

	* docs/_build/texinfo/libgccjit.texi: Regenerate.
	* docs/_build/texinfo/factorial1.png: New file.
	* docs/_build/texinfo/sum-of-squares1.png: New file.

From-SVN: r218588
parent e56e603b
2014-12-10 David Malcolm <dmalcolm@redhat.com>
* docs/cp/index.rst: New file.
* docs/cp/intro/index.rst: New file.
* docs/cp/intro/tutorial01.rst: New file.
* docs/cp/intro/tutorial02.rst: New file.
* docs/cp/intro/tutorial03.rst: New file.
* docs/cp/intro/tutorial04.rst: New file.
* docs/cp/topics/contexts.rst: New file.
* docs/cp/topics/expressions.rst: New file.
* docs/cp/topics/functions.rst: New file.
* docs/cp/topics/index.rst: New file.
* docs/cp/topics/locations.rst: New file.
* docs/cp/topics/objects.rst: New file.
* docs/cp/topics/results.rst: New file.
* docs/cp/topics/types.rst: New file.
* docs/examples/tut01-hello-world.cc: New file.
* docs/examples/tut02-square.c: Fix missing newline in output.
* docs/examples/tut02-square.cc: New file.
* docs/examples/tut03-sum-of-squares.cc: New file.
* docs/examples/tut04-toyvm/toyvm.cc: New file.
* docs/index.rst: Move summary to above the table of contents.
Add text about the C vs C++ APIs.
* docs/topics/contexts.rst: Fix a typo.
* docs/_build/texinfo/libgccjit.texi: Regenerate.
* docs/_build/texinfo/factorial1.png: New file.
* docs/_build/texinfo/sum-of-squares1.png: New file.
2014-12-09 David Malcolm <dmalcolm@redhat.com>
* docs/examples/tut04-toyvm/toyvm.c (toyvm_function_compile): Move
......
This source diff could not be displayed because it is too large. You can view the blob instead.
.. 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/>.
C++ bindings for libgccjit
==========================
This document describes the C++ bindings to
`libgccjit <http://gcc.gnu.org/wiki/JIT>`_, an API for embedding GCC
inside programs and libraries.
The C++ bindings consist of a single header file ``libgccjit++.h``.
This is a collection of "thin" wrapper classes around the C API.
Everything is an inline function, implemented in terms of the C API,
so there is nothing extra to link against.
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.
Contents:
.. toctree::
:maxdepth: 2
intro/index.rst
topics/index.rst
.. 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
.. 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:: cpp
Tutorial part 1: "Hello world"
==============================
Before we look at the details of the API, let's look at building and
running programs that use the library.
Here's a toy "hello world" program that uses the library's C++ API to
synthesize a call to `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.cc
:language: c++
Copy the above to `tut01-hello-world.cc`.
Assuming you have the jit library installed, build the test program
using:
.. code-block:: console
$ gcc \
tut01-hello-world.cc \
-o tut01-hello-world \
-lgccjit
You should then be able to run the built program:
.. code-block:: console
$ ./tut01-hello-world
hello world
.. 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:: cpp
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's C++ API?
First we need to include the relevant header:
.. code-block:: c++
#include <libgccjit++.h>
All state associated with compilation is associated with a
:type:`gccjit::context`, which is a thin C++ wrapper around the C API's
:c:type:`gcc_jit_context *`.
Create one using :func:`gccjit::context::acquire`:
.. code-block:: c++
gccjit::context ctxt;
ctxt = gccjit::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 :type:`gccjit::type`, using
:func:`gccjit::context::get_type`:
.. code-block:: c++
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
:type:`gccjit::type` is an example of a "contextual" object: every
entity in the API is associated with a :type:`gccjit::context`.
Memory management is easy: all such "contextual" objects are automatically
cleaned up for you when the context is released, using
:func:`gccjit::context::release`:
.. code-block:: c++
ctxt.release ();
so you don't need to manually track and cleanup all objects, just the
contexts.
All of the C++ classes in the API are thin wrappers around pointers to
types in the C API.
The C++ class hierarchy within the ``gccjit`` namespace looks like this::
+- object
+- location
+- type
+- struct
+- field
+- function
+- block
+- rvalue
+- lvalue
+- param
One thing you can do with a :type:`gccjit::object` is
to ask it for a human-readable description as a :type:`std::string`, using
:func:`gccjit::object::get_debug_string`:
.. code-block:: c++
printf ("obj: %s\n", obj.get_debug_string ().c_str ());
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 :func:`gccjit::context::new_param`:
.. code-block:: c++
gccjit::param param_i = ctxt.new_param (int_type, "i");
and we can then make a vector of all of the params of the function,
in this case just one:
.. code-block:: c++
std::vector<gccjit::param> params;
params.push_back (param_i);
Now we can create the function, using
:c:func:`gccjit::context::new_function`:
.. code-block:: c++
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
params,
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++
gccjit::block block = func.new_block ();
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
We can build the expression using :func:`gccjit::context::new_binary_op`:
.. code-block:: c++
gccjit::rvalue expr =
ctxt.new_binary_op (
GCC_JIT_BINARY_OP_MULT, int_type,
param_i, param_i);
A :type:`gccjit::rvalue` is another example of a
:type:`gccjit::object` subclass. As before, we can print it with
:func:`gccjit::object::get_debug_string`.
.. code-block:: c++
printf ("expr: %s\n", expr.get_debug_string ().c_str ());
giving this output:
.. code-block:: bash
expr: i * i
Note that :type:`gccjit::rvalue` provides numerous overloaded operators
which can be used to dramatically reduce the amount of typing needed.
We can build the above binary operation more directly with this one-liner:
.. code-block:: c++
gccjit::rvalue expr = param_i * param_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++
block.end_with_return (expr);
OK, we've populated the context. We can now compile it using
:func:`gccjit::context::compile`:
.. code-block:: c++
gcc_jit_result *result;
result = ctxt.compile ();
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 :func:`gccjit::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++
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
result = ctxt.compile ();
.. 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++
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 1);
result = ctxt.compile ();
.. 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
:func:`gccjit::context::set_int_option` with
:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
.. code-block:: c++
ctxt.set_int_option (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.cc
:lines: 1-
:language: c++
Building and running it:
.. code-block:: console
$ gcc \
tut02-square.cc \
-o tut02-square \
-lgccjit
# Run the built program:
$ ./tut02-square
result: 25
.. 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:: cpp
Compilation contexts
====================
.. class:: gccjit::context
The top-level of the C++ API is the :class:`gccjit::context` type.
A :class:`gccjit::context` instance encapsulates the state of a
compilation.
You can set up options on it, and add types, functions and code.
Invoking :func:`gccjit::context::compile` on it gives you a
:c:type:`gcc_jit_result *`.
It is a thin wrapper around the C API's :c:type:`gcc_jit_context *`.
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:: gccjit::context gccjit::context::acquire ()
This function acquires a new :class:`gccjit::context` instance,
which is independent of any others that may be present within this
process.
.. function:: void gccjit::context::release ()
This function releases all resources associated with the given context.
Both the context itself and all of its :c:type:`gccjit::object *`
instances are cleaned up. It should be called exactly once on a given
context.
It is invalid to use the context or any of its "contextual" objects
after calling this.
.. code-block:: c++
ctxt.release ();
.. function:: gccjit::context \
gccjit::context::new_child_context ()
Given an existing JIT context, create a child context.
The child inherits a copy of all option-settings from the parent.
The child can reference objects created within the parent, but not
vice-versa.
The lifetime of the child context must be bounded by that of the
parent: you should release a child context before releasing the parent
context.
If you use a function from a parent context within a child context,
you have to compile the parent context before you can compile the
child context, and the gccjit::result of the parent context must
outlive the gccjit::result of the child context.
This allows caching of shared initializations. For example, you could
create types and declarations of global functions in a parent context
once within a process, and then create child contexts whenever a
function or loop becomes hot. Each such child context can be used for
JIT-compiling just one function or loop, but can reference types
and helper functions created within the parent context.
Contexts can be arbitrarily nested, provided the above rules are
followed, but it's probably not worth going above 2 or 3 levels, and
there will likely be a performance hit for such nesting.
Thread-safety
-------------
Instances of :class:`gccjit::context` created via
:func:`gccjit::context::acquire` are independent from each other:
only one thread may use a given context at once, but multiple threads
could each have their own contexts without needing locks.
Contexts created via :func:`gccjit::context::new_child_context` are
related to their parent context. They can be partitioned by their
ultimate ancestor into independent "family trees". Only one thread
within a process may use a given "family tree" of such contexts at once,
and if you're using multiple threads you should provide your own locking
around entire such context partitions.
Error-handling
--------------
.. FIXME: How does error-handling work for C++ API?
You can only compile and get code from a context if no errors occur.
In general, if an error occurs when using an API entrypoint, it returns
NULL. You don't have to check everywhere for NULL results, since the
API gracefully handles a NULL being passed in for any argument.
Errors are printed on stderr and can be queried using
:func:`gccjit::context::get_first_error`.
.. function:: const char *\
gccjit::context::get_first_error (gccjit::context *ctxt)
Returns the first error message that occurred on the context.
The returned string is valid for the rest of the lifetime of the
context.
If no errors occurred, this will be NULL.
Debugging
---------
.. function:: void\
gccjit::context::dump_to_file (const std::string &path, \
int update_locations)
To help with debugging: dump a C-like representation to the given path,
describing what's been set up on the context.
If "update_locations" is true, then also set up :class:`gccjit::location`
information throughout the context, pointing at the dump file as if it
were a source file. This may be of use in conjunction with
:c:macro:`GCCJIT::BOOL_OPTION_DEBUGINFO` to allow stepping through the
code in a debugger.
Options
-------
..
FIXME: gccjit::context::set_str_option doesn't seem to exist yet in the
C++ API
Boolean options
***************
.. function:: void \
gccjit::context::set_bool_option(enum gcc_jit_bool_option, \
int value)
Set a boolean option of the context.
This is a thin wrapper around the C API
:c:func:`gcc_jit_context_set_bool_option`; the options have the same
meaning.
Integer options
***************
.. function:: void \
gccjit::context::set_int_option (enum gcc_jit_int_option, \
int value)
Set an integer option of the context.
This is a thin wrapper around the C API
:c:func:`gcc_jit_context_set_int_option`; the options have the same
meaning.
.. 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:: cpp
Creating and using functions
============================
Params
------
.. class:: gccjit::param
A `gccjit::param` represents a parameter to a function.
.. function:: gccjit::param \
gccjit::context::new_param (gccjit::type type,\
const char *name, \
gccjit::location loc)
In preparation for creating a function, create a new parameter of the
given type and name.
:class:`gccjit::param` is a subclass of :class:`gccjit::lvalue` (and thus
of :class:`gccjit::rvalue` and :class:`gccjit::object`). It is a thin
wrapper around the C API's :c:type:`gcc_jit_param *`.
Functions
---------
.. class:: gccjit::function
A `gccjit::function` represents a function - either one that we're
creating ourselves, or one that we're referencing.
.. function:: gccjit::function \
gccjit::context::new_function (enum gcc_jit_function_kind,\
gccjit::type return_type, \
const char *name, \
std::vector<param> &params, \
int is_variadic, \
gccjit::location loc) \
Create a gcc_jit_function with the given name and parameters.
Parameters "is_variadic" and "loc" are optional.
This is a wrapper around the C API's :c:func:`gcc_jit_context_new_function`.
.. function:: gccjit::function \
gccjit::context::get_builtin_function (const char *name)
This is a wrapper around the C API's
:c:func:`gcc_jit_context_get_builtin_function`.
.. function:: gccjit::param \
gccjit::function::get_param (int index) const
Get the param of the given index (0-based).
.. function:: void \
gccjit::function::dump_to_dot (const char *path)
Emit the function in graphviz format to the given path.
.. function:: gccjit::lvalue \
gccjit::function::new_local (gccjit::type type,\
const char *name, \
gccjit::location loc)
Create a new local variable within the function, of the given type and
name.
Blocks
------
.. class:: gccjit::block
A `gccjit::block` represents a basic block within a function i.e. a
sequence of statements with a single entry point and a single exit
point.
:class:`gccjit::block` is a subclass of :class:`gccjit::object`.
The first basic block that you create within a function will
be the entrypoint.
Each basic block that you create within a function must be
terminated, either with a conditional, a jump, or a return.
It's legal to have multiple basic blocks that return within
one function.
.. function:: gccjit::block \
gccjit::function::new_block (const char *name)
Create a basic block of the given name. The name may be NULL, but
providing meaningful names is often helpful when debugging: it may
show up in dumps of the internal representation, and in error
messages.
Statements
----------
.. function:: void\
gccjit::block::add_eval (gccjit::rvalue rvalue, \
gccjit::location loc)
Add evaluation of an rvalue, discarding the result
(e.g. a function call that "returns" void).
This is equivalent to this C code:
.. code-block:: c
(void)expression;
.. function:: void\
gccjit::block::add_assignment (gccjit::lvalue lvalue, \
gccjit::rvalue rvalue, \
gccjit::location loc)
Add evaluation of an rvalue, assigning the result to the given
lvalue.
This is roughly equivalent to this C code:
.. code-block:: c
lvalue = rvalue;
.. function:: void\
gccjit::block::add_assignment_op (gccjit::lvalue lvalue, \
enum gcc_jit_binary_op, \
gccjit::rvalue rvalue, \
gccjit::location loc)
Add evaluation of an rvalue, using the result to modify an
lvalue.
This is analogous to "+=" and friends:
.. code-block:: c
lvalue += rvalue;
lvalue *= rvalue;
lvalue /= rvalue;
etc. For example:
.. code-block:: c
/* "i++" */
loop_body.add_assignment_op (
i,
GCC_JIT_BINARY_OP_PLUS,
ctxt.one (int_type));
.. function:: void\
gccjit::block::add_comment (const char *text, \
gccjit::location loc)
Add a no-op textual comment to the internal representation of the
code. It will be optimized away, but will be visible in the dumps
seen via :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE`
and :c: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.
Parameter "loc" is optional.
.. function:: void\
gccjit::block::end_with_conditional (gccjit::rvalue boolval,\
gccjit::block on_true,\
gccjit::block on_false, \
gccjit::location loc)
Terminate a block by adding evaluation of an rvalue, branching on the
result to the appropriate successor block.
This is roughly equivalent to this C code:
.. 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\
gccjit::block::end_with_jump (gccjit::block target, \
gccjit::location loc)
Terminate a block by adding a jump to the given target block.
This is roughly equivalent to this C code:
.. code-block:: c
goto target;
.. function:: void\
gccjit::block::end_with_return (gccjit::rvalue rvalue, \
gccjit::location loc)
Terminate a block.
Both params are optional.
An rvalue must be provided for a function returning non-void, and
must not be provided by a function "returning" `void`.
If an rvalue is provided, the block is terminated by evaluating the
rvalue and returning the value.
This is roughly equivalent to this C code:
.. code-block:: c
return expression;
If an rvalue is not provided, the block is terminated by adding a
valueless return, for use within a function with "void" return type.
This is equivalent to this C code:
.. code-block:: c
return;
.. 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
.. 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:: cpp
Source Locations
================
.. class:: gccjit::location
A `gccjit::location` encapsulates a source code location, so that
you can (optionally) associate locations in your language with
statements in the JIT-compiled code, allowing the debugger to
single-step through your language.
`gccjit::location` instances are optional: you can always omit them
from any C++ API entrypoint accepting one.
You can construct them using :func:`gccjit::context::new_location`.
You need to enable :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
:class:`gccjit::context` for these locations to actually be usable by
the debugger:
.. code-block:: cpp
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
.. function:: gccjit::location \
gccjit::context::new_location (const char *filename, \
int line, \
int column)
Create a `gccjit::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 :func:`gccjit::context::dump_to_file()`:
.. code-block:: cpp
ctxt.dump_to_file ("/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 `gccjit::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.
.. 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:: cpp
Objects
=======
.. class:: gccjit::object
Almost every entity in the API (with the exception of
:class:`gccjit::context` and :c:type:`gcc_jit_result *`) is a
"contextual" object, a :class:`gccjit::object`.
A JIT object:
* is associated with a :class:`gccjit::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.
The C++ class hierarchy within the ``gccjit`` namespace looks like this::
+- object
+- location
+- type
+- struct
+- field
+- function
+- block
+- rvalue
+- lvalue
+- param
The :class:`gccjit::object` base class has the following operations:
.. function:: gccjit::context gccjit::object::get_context () const
Which context is the obj within?
.. function:: std::string gccjit::object::get_debug_string () const
Generate a human-readable description for the given object.
For example,
.. code-block:: c++
printf ("obj: %s\n", obj.get_debug_string ().c_str ());
might give this text on stdout:
.. code-block:: bash
obj: 4.0 * (float)i
.. 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:: cpp
Compilation results
===================
.. type:: gcc_jit_result
A `gcc_jit_result` encapsulates the result of compiling a context.
.. function:: gcc_jit_result *\
gccjit::context::compile ()
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.
.. 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:: cpp
Types
=====
.. class:: gccjit::type
gccjit::type represents a type within the library. It is a subclass
of :class:`gccjit::object`.
Types can be created in several ways:
* fundamental types can be accessed using
:func:`gccjit::context::get_type`:
.. code-block:: c++
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
or using the :func:`gccjit::context::get_int_type<T>` template:
.. code-block:: c++
gccjit::type t = ctxt.get_int_type <unsigned short> ();
See :c:func:`gcc_jit_context_get_type` for the available types.
* derived types can be accessed by using functions such as
:func:`gccjit::type::get_pointer` and :func:`gccjit::type::get_const`:
.. code-block:: c++
gccjit::type const_int_star = int_type.get_const ().get_pointer ();
gccjit::type int_const_star = int_type.get_pointer ().get_const ();
* by creating structures (see below).
Standard types
--------------
.. function:: gccjit::type gccjit::context::get_type (enum gcc_jit_types)
Access a specific type. This is a thin wrapper around
:c:func:`gcc_jit_context_get_type`; the parameter has the same meaning.
.. function:: gccjit::type \
gccjit::context::get_int_type (size_t num_bytes, int is_signed)
Access the integer type of the given size.
.. function:: gccjit::type \
gccjit::context::get_int_type <T> ()
Access the given integer type. For example, you could map the
``unsigned short`` type into a gccjit::type via:
.. code-block:: c++
gccjit::type t = ctxt.get_int_type <unsigned short> ();
Pointers, `const`, and `volatile`
---------------------------------
.. function:: gccjit::type gccjit::type::get_pointer ()
Given type "T", get type "T*".
.. FIXME: get_const doesn't seem to exist
.. function:: gccjit::type gccjit::type::get_const ()
Given type "T", get type "const T".
.. function:: gccjit::type gccjit::type::get_volatile ()
Given type "T", get type "volatile T".
.. function:: gccjit::type \
gccjit::context::new_array_type (gccjit::type element_type, \
int num_elements, \
gccjit::location loc)
Given type "T", get type "T[N]" (for a constant N).
Param "loc" is optional.
Structures and unions
---------------------
.. class:: gccjit::struct_
A compound type analagous to a C `struct`.
:class:`gccjit::struct_` is a subclass of :class:`gccjit::type` (and thus
of :class:`gccjit::object` in turn).
.. class:: gccjit::field
A field within a :class:`gccjit::struct_`.
:class:`gccjit::field` is a subclass of :class:`gccjit::object`.
You can model C `struct` types by creating :class:`gccjit::struct_` and
:class:`gccjit::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++
gccjit::field field_x = ctxt.new_field (double_type, "x");
gccjit::field field_y = ctxt.new_field (double_type, "y");
std::vector fields;
fields.push_back (field_x);
fields.push_back (field_y);
gccjit::struct_ coord = ctxt.new_struct_type ("coord", fields);
* 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++
gccjit::struct_ node = ctxt.new_opaque_struct_type ("node");
gccjit::type node_ptr = node.get_pointer ();
gccjit::field field_hash = ctxt.new_field (int_type, "m_hash");
gccjit::field field_next = ctxt.new_field (node_ptr, "m_next");
std::vector fields;
fields.push_back (field_hash);
fields.push_back (field_next);
node.set_fields (fields);
.. FIXME: the above API doesn't seem to exist yet
.. function:: gccjit::field \
gccjit::context::new_field (gccjit::type type,\
const char *name, \
gccjit::location loc)
Construct a new field, with the given type and name.
.. function:: gccjit::struct_ \
gccjit::context::new_struct_type (const std::string &name,\
std::vector<field> &fields,\
gccjit::location loc)
Construct a new struct type, with the given name and fields.
.. function:: gccjit::struct_ \
gccjit::context::new_opaque_struct (const std::string &name, \
gccjit::location loc)
Construct a new struct type, with the given name, but without
specifying the fields. The fields can be omitted (in which case the
size of the struct is not known), or later specified using
:c:func:`gcc_jit_struct_set_fields`.
/* Smoketest example for libgccjit.so C++ API
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 (gccjit::context ctxt)
{
/* Let's try to inject the equivalent of this C code:
void
greet (const char *name)
{
printf ("hello %s\n", name);
}
*/
gccjit::type void_type = ctxt.get_type (GCC_JIT_TYPE_VOID);
gccjit::type const_char_ptr_type =
ctxt.get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
gccjit::param param_name =
ctxt.new_param (const_char_ptr_type, "name");
std::vector<gccjit::param> func_params;
func_params.push_back (param_name);
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
void_type,
"greet",
func_params, 0);
gccjit::param param_format =
ctxt.new_param (const_char_ptr_type, "format");
std::vector<gccjit::param> printf_params;
printf_params.push_back (param_format);
gccjit::function printf_func =
ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
ctxt.get_type (GCC_JIT_TYPE_INT),
"printf",
printf_params, 1);
gccjit::block block = func.new_block ();
block.add_eval (ctxt.new_call (printf_func,
ctxt.new_rvalue ("hello %s\n"),
param_name));
block.end_with_return ();
}
int
main (int argc, char **argv)
{
gccjit::context ctxt;
gcc_jit_result *result;
/* Get a "context" object for working with the library. */
ctxt = gccjit::context::acquire ();
/* Set some options on the context.
Turn this on to see the code being generated, in assembler form. */
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = ctxt.compile ();
if (!result)
{
fprintf (stderr, "NULL result");
exit (1);
}
ctxt.release ();
/* Extract the generated code from "result". */
typedef void (*fn_type) (const char *);
fn_type greet =
(fn_type)gcc_jit_result_get_code (result, "greet");
if (!greet)
{
fprintf (stderr, "NULL greet");
exit (1);
}
/* Now call the generated function: */
greet ("world");
fflush (stdout);
gcc_jit_result_release (result);
return 0;
}
......@@ -102,7 +102,7 @@ main (int argc, char **argv)
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d", square (5));
printf ("result: %d\n", square (5));
error:
if (ctxt)
......
/* Usage example for libgccjit.so's C++ API
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 (gccjit::context ctxt)
{
/* Let's try to inject the equivalent of this C code:
int square (int i)
{
return i * i;
}
*/
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
gccjit::param param_i = ctxt.new_param (int_type, "i");
std::vector<gccjit::param> params;
params.push_back (param_i);
gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
params, 0);
gccjit::block block = func.new_block ();
gccjit::rvalue expr =
ctxt.new_binary_op (GCC_JIT_BINARY_OP_MULT, int_type,
param_i, param_i);
block.end_with_return (expr);
}
int
main (int argc, char **argv)
{
/* Get a "context" object for working with the library. */
gccjit::context ctxt = gccjit::context::acquire ();
/* Set some options on the context.
Turn this on to see the code being generated, in assembler form. */
ctxt.set_bool_option (
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
gcc_jit_result *result = ctxt.compile ();
/* We're done with the context; we can release it: */
ctxt.release ();
if (!result)
{
fprintf (stderr, "NULL result");
return 1;
}
/* Extract the generated code from "result". */
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
{
fprintf (stderr, "NULL fn_ptr");
gcc_jit_result_release (result);
return 1;
}
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d\n", square (5));
gcc_jit_result_release (result);
return 0;
}
/* Usage example for libgccjit.so's C++ API
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 (gccjit::context ctxt)
{
/*
Simple sum-of-squares, to test conditionals and looping
int loop_test (int n)
{
int i;
int sum = 0;
for (i = 0; i < n ; i ++)
{
sum += i * i;
}
return sum;
*/
gccjit::type the_type = ctxt.get_int_type <int> ();
gccjit::type return_type = the_type;
gccjit::param n = ctxt.new_param (the_type, "n");
std::vector<gccjit::param> params;
params.push_back (n);
gccjit::function func =
ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
params, 0);
/* Build locals: */
gccjit::lvalue i = func.new_local (the_type, "i");
gccjit::lvalue sum = func.new_local (the_type, "sum");
gccjit::block b_initial = func.new_block ("initial");
gccjit::block b_loop_cond = func.new_block ("loop_cond");
gccjit::block b_loop_body = func.new_block ("loop_body");
gccjit::block b_after_loop = func.new_block ("after_loop");
/* sum = 0; */
b_initial.add_assignment (sum, ctxt.zero (the_type));
/* i = 0; */
b_initial.add_assignment (i, ctxt.zero (the_type));
b_initial.end_with_jump (b_loop_cond);
/* if (i >= n) */
b_loop_cond.end_with_conditional (
i >= n,
b_after_loop,
b_loop_body);
/* sum += i * i */
b_loop_body.add_assignment_op (sum,
GCC_JIT_BINARY_OP_PLUS,
i * i);
/* i++ */
b_loop_body.add_assignment_op (i,
GCC_JIT_BINARY_OP_PLUS,
ctxt.one (the_type));
b_loop_body.end_with_jump (b_loop_cond);
/* return sum */
b_after_loop.end_with_return (sum);
}
int
main (int argc, char **argv)
{
gccjit::context ctxt;
gcc_jit_result *result = NULL;
/* Get a "context" object for working with the library. */
ctxt = gccjit::context::acquire ();
/* Set some options on the context.
Turn this on to see the code being generated, in assembler form. */
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = ctxt.compile ();
ctxt.release ();
if (!result)
{
fprintf (stderr, "NULL result");
return 1;
}
/* Extract the generated code from "result". */
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
{
fprintf (stderr, "NULL loop_test");
gcc_jit_result_release (result);
return 1;
}
/* Run the generated code. */
int val = loop_test (10);
printf("loop_test returned: %d\n", val);
gcc_jit_result_release (result);
return 0;
}
......@@ -18,6 +18,20 @@
libgccjit
=========
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.
There are actually two APIs for the library:
* a pure C API: ``libgccjit.h``
* a C++ wrapper API: ``libgccjit++.h``. This is a collection of "thin"
wrapper classes around the C API, to save typing.
Contents:
.. toctree::
......@@ -25,15 +39,9 @@ Contents:
intro/index.rst
topics/index.rst
cp/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
==================
......
......@@ -89,7 +89,7 @@ cleanup of such objects is done for you when the context is released.
Thread-safety
-------------
Instances of :c:type:`gcc_jit_object *` created via
Instances of :c:type:`gcc_jit_context *` 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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment