Add evaluation of an rvalue, discarding the result (e.g. a function call that “returns” void).
This is equivalent to this C code:
(void)expression;
Add evaluation of an rvalue, assigning the result to the given lvalue.
This is roughly equivalent to this C code:
lvalue = rvalue;
Add evaluation of an rvalue, using the result to modify an lvalue.
This is analogous to “+=” and friends:
lvalue += rvalue; lvalue *= rvalue; lvalue /= rvalue;
etc. For example:
/* "i++" */ gcc_jit_block_add_assignment_op ( loop_body, NULL, i, GCC_JIT_BINARY_OP_PLUS, gcc_jit_context_one (ctxt, int_type));
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 GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE and 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.
The parameter text
must be non-NULL. It is copied, so the input
buffer does not need to outlive the call. For example:
char buf[100]; snprintf (buf, sizeof (buf), "op%i: %s", pc, opcode_names[op->op_opcode]); gcc_jit_block_add_comment (block, loc, buf);
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:
if (boolval) goto on_true; else goto on_false;
block, boolval, on_true, and on_false must be non-NULL.
Terminate a block by adding a jump to the given target block.
This is roughly equivalent to this C code:
goto target;
Terminate a block by adding evaluation of an rvalue, returning the value.
This is roughly equivalent to this C code:
return expression;
Terminate a block by adding a valueless return, for use within a function with “void” return type.
This is equivalent to this C code:
return;
Terminate a block by adding evalation of an rvalue, then performing a multiway branch.
This is roughly equivalent to this C code:
switch (expr) { default: goto default_block; case C0.min_value ... C0.max_value: goto C0.dest_block; case C1.min_value ... C1.max_value: goto C1.dest_block; ...etc... case C[N - 1].min_value ... C[N - 1].max_value: goto C[N - 1].dest_block; }
block
, expr
, default_block
and cases
must all be
non-NULL.
expr
must be of the same integer type as all of the min_value
and max_value
within the cases.
num_cases
must be >= 0.
The ranges of the cases must not overlap (or have duplicate values).
The API entrypoints relating to switch statements and cases:
were added in LIBGCCJIT_ABI_3; you can test for their presence using
#ifdef LIBGCCJIT_HAVE_SWITCH_STATEMENTS
A gcc_jit_case represents a case within a switch statement, and is created within a particular gcc_jit_context using gcc_jit_context_new_case().
Each case expresses a multivalued range of integer values. You can express single-valued cases by passing in the same value for both min_value and max_value.
Create a new gcc_jit_case instance for use in a switch statement. min_value and max_value must be constants of an integer type, which must match that of the expression of the switch statement.
dest_block must be within the same function as the switch statement.
Upcast from a case to an object.
Here’s an example of creating a switch statement:
void create_code (gcc_jit_context *ctxt, void *user_data) { /* Let's try to inject the equivalent of: int test_switch (int x) { switch (x) { case 0 ... 5: return 3; case 25 ... 27: return 4; case -42 ... -17: return 83; case 40: return 8; default: return 10; } } */ gcc_jit_type *t_int = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); gcc_jit_type *return_type = t_int; gcc_jit_param *x = gcc_jit_context_new_param (ctxt, NULL, t_int, "x"); gcc_jit_param *params[1] = {x}; gcc_jit_function *func = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, return_type, "test_switch", 1, params, 0); gcc_jit_block *b_initial = gcc_jit_function_new_block (func, "initial"); gcc_jit_block *b_default = gcc_jit_function_new_block (func, "default"); gcc_jit_block *b_case_0_5 = gcc_jit_function_new_block (func, "case_0_5"); gcc_jit_block *b_case_25_27 = gcc_jit_function_new_block (func, "case_25_27"); gcc_jit_block *b_case_m42_m17 = gcc_jit_function_new_block (func, "case_m42_m17"); gcc_jit_block *b_case_40 = gcc_jit_function_new_block (func, "case_40"); gcc_jit_case *cases[4] = { gcc_jit_context_new_case ( ctxt, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 0), gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 5), b_case_0_5), gcc_jit_context_new_case ( ctxt, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 25), gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 27), b_case_25_27), gcc_jit_context_new_case ( ctxt, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, -42), gcc_jit_context_new_rvalue_from_int (ctxt, t_int, -17), b_case_m42_m17), gcc_jit_context_new_case ( ctxt, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 40), gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 40), b_case_40) }; gcc_jit_block_end_with_switch ( b_initial, NULL, gcc_jit_param_as_rvalue (x), b_default, 4, cases); gcc_jit_block_end_with_return ( b_case_0_5, NULL, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 3)); gcc_jit_block_end_with_return ( b_case_25_27, NULL, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 4)); gcc_jit_block_end_with_return ( b_case_m42_m17, NULL, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 83)); gcc_jit_block_end_with_return ( b_case_40, NULL, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 8)); gcc_jit_block_end_with_return ( b_default, NULL, gcc_jit_context_new_rvalue_from_int (ctxt, t_int, 10)); }
See also gcc_jit_extended_asm for entrypoints for adding inline assembler statements to a function.