617 lines
18 KiB
ReStructuredText
617 lines
18 KiB
ReStructuredText
.. Copyright (C) 2014-2016 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 :c:type:`int` value.
|
|
|
|
.. function:: gcc_jit_rvalue *\
|
|
gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt, \
|
|
gcc_jit_type *numeric_type, \
|
|
long value)
|
|
|
|
Given a numeric type (integer or floating point), build an rvalue for
|
|
the given constant :c:type:`long` 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
|
|
one. 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 :c:type:`double` 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`.
|
|
|
|
The parameter ``value`` must be non-NULL. The call takes a copy of the
|
|
underlying string, so it is valid to pass in a pointer to an on-stack
|
|
buffer.
|
|
|
|
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_ABS` `abs (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.
|
|
|
|
.. c:macro:: GCC_JIT_UNARY_OP_ABS
|
|
|
|
Absolute value of an arithmetic expression; analogous to:
|
|
|
|
.. code-block:: c
|
|
|
|
abs (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));
|
|
|
|
.. function:: gcc_jit_rvalue *\
|
|
gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,\
|
|
gcc_jit_location *loc,\
|
|
gcc_jit_rvalue *fn_ptr,\
|
|
int numargs, \
|
|
gcc_jit_rvalue **args)
|
|
|
|
Given an rvalue of function pointer type, and the given table of
|
|
argument rvalues, construct a call to the function pointer, with the
|
|
result as an rvalue.
|
|
|
|
.. note::
|
|
|
|
The same caveat as for :c:func:`gcc_jit_context_new_call` applies.
|
|
|
|
.. function:: void\
|
|
gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *call,\
|
|
int require_tail_call)
|
|
|
|
Given an :c:type:`gcc_jit_rvalue *` for a call created through
|
|
:c:func:`gcc_jit_context_new_call` or
|
|
:c:func:`gcc_jit_context_new_call_through_ptr`, mark/clear the
|
|
call as needing tail-call optimization. The optimizer will
|
|
attempt to optimize the call into a jump instruction; if it is
|
|
unable to do do, an error will be emitted.
|
|
|
|
This may be useful when implementing functions that use the
|
|
continuation-passing style (e.g. for functional programming
|
|
languages), in which every function "returns" by calling a
|
|
"continuation" function pointer. This call must be
|
|
guaranteed to be implemented as a jump, otherwise the program
|
|
could consume an arbitrary amount of stack space as it executed.
|
|
|
|
This entrypoint was added in :ref:`LIBGCCJIT_ABI_6`; you can test for
|
|
its presence using
|
|
|
|
.. code-block:: c
|
|
|
|
#ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
|
|
|
|
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,\
|
|
enum gcc_jit_global_kind kind,\
|
|
gcc_jit_type *type,\
|
|
const char *name)
|
|
|
|
Add a new global variable of the given type and name to the context.
|
|
|
|
The parameter ``name`` must be non-NULL. The call takes a copy of the
|
|
underlying string, so it is valid to pass in a pointer to an on-stack
|
|
buffer.
|
|
|
|
The "kind" parameter determines the visibility of the "global" outside
|
|
of the :c:type:`gcc_jit_result`:
|
|
|
|
.. type:: enum gcc_jit_global_kind
|
|
|
|
.. c:macro:: GCC_JIT_GLOBAL_EXPORTED
|
|
|
|
Global is defined by the client code and is visible
|
|
by name outside of this JIT context via
|
|
:c:func:`gcc_jit_result_get_global` (and this value is required for
|
|
the global to be accessible via that entrypoint).
|
|
|
|
.. c:macro:: GCC_JIT_GLOBAL_INTERNAL
|
|
|
|
Global is defined by the client code, but is invisible
|
|
outside of it. Analogous to a "static" global within a .c file.
|
|
Specifically, the variable will only be visible within this
|
|
context and within child contexts.
|
|
|
|
.. c:macro:: GCC_JIT_GLOBAL_IMPORTED
|
|
|
|
Global is not defined by the client code; we're merely
|
|
referring to it. Analogous to using an "extern" global from a
|
|
header file.
|
|
|
|
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``).
|