Expressions

Rvalues

gcc_jit_rvalue

A 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).

gcc_jit_type *gcc_jit_rvalue_get_type(gcc_jit_rvalue *rvalue)

Get the type of this rvalue.

gcc_jit_object *gcc_jit_rvalue_as_object(gcc_jit_rvalue *rvalue)

Upcast the given rvalue to be an object.

Simple expressions

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 int value.

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 long value.

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:

gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
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:

gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
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 double value.

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.

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:

gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
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 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.

Vector expressions

gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_vector(gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_type *vec_type, size_t num_elements, gcc_jit_rvalue **elements)

Build a vector rvalue from an array of elements.

“vec_type” should be a vector type, created using gcc_jit_type_get_vector().

“num_elements” should match that of the vector type.

This entrypoint was added in LIBGCCJIT_ABI_10; you can test for its presence using

#ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector

Unary Operations

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.

The parameter result_type must be a numeric type.

enum gcc_jit_unary_op

The available unary operations are:

Unary Operation C equivalent
GCC_JIT_UNARY_OP_MINUS -(EXPR)
GCC_JIT_UNARY_OP_BITWISE_NEGATE ~(EXPR)
GCC_JIT_UNARY_OP_LOGICAL_NEGATE !(EXPR)
GCC_JIT_UNARY_OP_ABS abs (EXPR)
GCC_JIT_UNARY_OP_MINUS

Negate an arithmetic value; analogous to:

-(EXPR)

in C.

GCC_JIT_UNARY_OP_BITWISE_NEGATE

Bitwise negation of an integer value (one’s complement); analogous to:

~(EXPR)

in C.

GCC_JIT_UNARY_OP_LOGICAL_NEGATE

Logical negation of an arithmetic or pointer value; analogous to:

!(EXPR)

in C.

GCC_JIT_UNARY_OP_ABS

Absolute value of an arithmetic expression; analogous to:

abs (EXPR)

in C.

Binary Operations

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.

The parameter result_type must be a numeric type.

enum gcc_jit_binary_op

The available binary operations are:

Binary Operation C equivalent
GCC_JIT_BINARY_OP_PLUS x + y
GCC_JIT_BINARY_OP_MINUS x - y
GCC_JIT_BINARY_OP_MULT x * y
GCC_JIT_BINARY_OP_DIVIDE x / y
GCC_JIT_BINARY_OP_MODULO x % y
GCC_JIT_BINARY_OP_BITWISE_AND x & y
GCC_JIT_BINARY_OP_BITWISE_XOR x ^ y
GCC_JIT_BINARY_OP_BITWISE_OR x | y
GCC_JIT_BINARY_OP_LOGICAL_AND x && y
GCC_JIT_BINARY_OP_LOGICAL_OR x || y
GCC_JIT_BINARY_OP_LSHIFT x << y
GCC_JIT_BINARY_OP_RSHIFT x >> y
GCC_JIT_BINARY_OP_PLUS

Addition of arithmetic values; analogous to:

(EXPR_A) + (EXPR_B)

in C.

For pointer addition, use gcc_jit_context_new_array_access().

GCC_JIT_BINARY_OP_MINUS

Subtraction of arithmetic values; analogous to:

(EXPR_A) - (EXPR_B)

in C.

GCC_JIT_BINARY_OP_MULT

Multiplication of a pair of arithmetic values; analogous to:

(EXPR_A) * (EXPR_B)

in C.

GCC_JIT_BINARY_OP_DIVIDE

Quotient of division of arithmetic values; analogous to:

(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.

GCC_JIT_BINARY_OP_MODULO

Remainder of division of arithmetic values; analogous to:

(EXPR_A) % (EXPR_B)

in C.

GCC_JIT_BINARY_OP_BITWISE_AND

Bitwise AND; analogous to:

(EXPR_A) & (EXPR_B)

in C.

GCC_JIT_BINARY_OP_BITWISE_XOR

Bitwise exclusive OR; analogous to:

(EXPR_A) ^ (EXPR_B)

in C.

GCC_JIT_BINARY_OP_BITWISE_OR

Bitwise inclusive OR; analogous to:

(EXPR_A) | (EXPR_B)

in C.

GCC_JIT_BINARY_OP_LOGICAL_AND

Logical AND; analogous to:

(EXPR_A) && (EXPR_B)

in C.

GCC_JIT_BINARY_OP_LOGICAL_OR

Logical OR; analogous to:

(EXPR_A) || (EXPR_B)

in C.

GCC_JIT_BINARY_OP_LSHIFT

Left shift; analogous to:

(EXPR_A) << (EXPR_B)

in C.

GCC_JIT_BINARY_OP_RSHIFT

Right shift; analogous to:

(EXPR_A) >> (EXPR_B)

in C.

Comparisons

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.

enum gcc_jit_comparison
Comparison C equivalent
GCC_JIT_COMPARISON_EQ x == y
GCC_JIT_COMPARISON_NE x != y
GCC_JIT_COMPARISON_LT x < y
GCC_JIT_COMPARISON_LE x <= y
GCC_JIT_COMPARISON_GT x > y
GCC_JIT_COMPARISON_GE x >= y

Function calls

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

gcc_jit_context_new_call() merely builds a 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 gcc_jit_block_add_eval():

/* Add "(void)printf (arg0, arg1);".  */
gcc_jit_block_add_eval (
  block, NULL,
  gcc_jit_context_new_call (
    ctxt,
    NULL,
    printf_func,
    2, args));
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 (e.g. from gcc_jit_context_new_function_ptr_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 gcc_jit_context_new_call() applies.

void gcc_jit_rvalue_set_bool_require_tail_call(gcc_jit_rvalue *call, int require_tail_call)

Given an gcc_jit_rvalue * for a call created through gcc_jit_context_new_call() or 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 LIBGCCJIT_ABI_6; you can test for its presence using

#ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call

Function pointers

Function pointers can be obtained:

Type-coercion

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

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.

gcc_jit_object * gcc_jit_lvalue_as_object(gcc_jit_lvalue *lvalue)

Upcast an lvalue to be an object.

gcc_jit_rvalue * gcc_jit_lvalue_as_rvalue(gcc_jit_lvalue *lvalue)

Upcast an lvalue to be an rvalue.

gcc_jit_rvalue * gcc_jit_lvalue_get_address(gcc_jit_lvalue *lvalue, gcc_jit_location *loc)

Take the address of an lvalue; analogous to:

&(EXPR)

in C.

Global variables

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 type must be non-void.

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 gcc_jit_result:

enum gcc_jit_global_kind
GCC_JIT_GLOBAL_EXPORTED

Global is defined by the client code and is visible by name outside of this JIT context via gcc_jit_result_get_global() (and this value is required for the global to be accessible via that entrypoint).

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.

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.

gcc_jit_lvalue * gcc_jit_global_set_initializer(gcc_jit_lvalue *global, const void *blob, size_t num_bytes)

Set an initializer for global using the memory content pointed by blob for num_bytes. global must be an array of an integral type. Return the global itself.

The parameter blob must be non-NULL. The call copies the memory pointed by blob for num_bytes bytes, so it is valid to pass in a pointer to an on-stack buffer. The content will be stored in the compilation unit and used as initialization value of the array.

This entrypoint was added in LIBGCCJIT_ABI_14; you can test for its presence using

#ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer

Working with pointers, structs and unions

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:

*(EXPR)

in C.

Field access is provided separately for both lvalues and rvalues.

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:

(EXPR).field = ...;

in C.

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:

(EXPR).field

in C.

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:

(EXPR)->field

in C, itself equivalent to (*EXPR).FIELD.

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:

PTR[INDEX]

in C (or, indeed, to PTR + INDEX).