Creating and using functions¶
Params¶
-
class
gccjit
::
param
¶ A gccjit::param represents a parameter to a 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.
gccjit::param
is a subclass of gccjit::lvalue
(and thus
of gccjit::rvalue
and gccjit::object
). It is a thin
wrapper around the C API’s 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.
-
gccjit::function
gccjit::context
::
new_function
(enum gcc_jit_function_kind, gccjit::type return_type, const char *name, std::vector<param> ¶ms, 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
gcc_jit_context_new_function()
.
-
gccjit::function
gccjit::context
::
get_builtin_function
(const char *name)¶ This is a wrapper around the C API’s
gcc_jit_context_get_builtin_function()
.
-
gccjit::param
gccjit::function
::
get_param
(int index) const¶ Get the param of the given index (0-based).
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.
gccjit::block
is a subclass ofgccjit::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, a return, or a switch.
It’s legal to have multiple basic blocks that return within one function.
Statements¶
-
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:
(void)expression;
-
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:
lvalue = rvalue;
-
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:
lvalue += rvalue; lvalue *= rvalue; lvalue /= rvalue;
etc. For example:
/* "i++" */ loop_body.add_assignment_op ( i, GCC_JIT_BINARY_OP_PLUS, ctxt.one (int_type));
-
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
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
andGCC_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.
-
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:
if (boolval) goto on_true; else goto on_false;
block, boolval, on_true, and on_false must be non-NULL.
-
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:
goto target;
-
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:
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:
return;
-
void
gccjit::block
::
end_with_switch
(gccjit::rvalue expr, gccjit::block default_block, std::vector<gccjit::case_> cases, gccjit::location loc)¶ 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; }
expr
must be of the same integer type as all of themin_value
andmax_value
within the cases.The ranges of the cases must not overlap (or have duplicate values).
The API entrypoints relating to switch statements and cases:
gccjit::context::new_case()
were added in LIBGCCJIT_ABI_3; you can test for their presence using
#ifdef LIBGCCJIT_HAVE_SWITCH_STATEMENTS
A gccjit::case_ represents a case within a switch statement, and is created within a particular
gccjit::context
usinggccjit::context::new_case()
. It is a subclass ofgccjit::object
.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.
Here’s an example of creating a switch statement:
void create_code (gcc_jit_context *c_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; } } */ gccjit::context ctxt (c_ctxt); gccjit::type t_int = ctxt.get_type (GCC_JIT_TYPE_INT); gccjit::type return_type = t_int; gccjit::param x = ctxt.new_param (t_int, "x"); std::vector <gccjit::param> params; params.push_back (x); gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, return_type, "test_switch", params, 0); gccjit::block b_initial = func.new_block ("initial"); gccjit::block b_default = func.new_block ("default"); gccjit::block b_case_0_5 = func.new_block ("case_0_5"); gccjit::block b_case_25_27 = func.new_block ("case_25_27"); gccjit::block b_case_m42_m17 = func.new_block ("case_m42_m17"); gccjit::block b_case_40 = func.new_block ("case_40"); std::vector <gccjit::case_> cases; cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, 0), ctxt.new_rvalue (t_int, 5), b_case_0_5)); cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, 25), ctxt.new_rvalue (t_int, 27), b_case_25_27)); cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, -42), ctxt.new_rvalue (t_int, -17), b_case_m42_m17)); cases.push_back (ctxt.new_case (ctxt.new_rvalue (t_int, 40), ctxt.new_rvalue (t_int, 40), b_case_40)); b_initial.end_with_switch (x, b_default, cases); b_case_0_5.end_with_return (ctxt.new_rvalue (t_int, 3)); b_case_25_27.end_with_return (ctxt.new_rvalue (t_int, 4)); b_case_m42_m17.end_with_return (ctxt.new_rvalue (t_int, 83)); b_case_40.end_with_return (ctxt.new_rvalue (t_int, 8)); b_default.end_with_return (ctxt.new_rvalue (t_int, 10)); }