This function has a loop, so we need to build some basic blocks to handle the control flow. In this case, we need 4 blocks:
so we create these as gccjit;;block instances within the gccjit;;function:
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");
We now populate each block with statements.
The entry block b_initial consists of initializations followed by a jump to the conditional. We assign 0 to i and to sum, using gccjit;;block;;add_assignment() to add an assignment statement, and using gccjit;;context;;zero() to get the constant value 0 for the relevant type for the right-hand side of the assignment:
/* sum = 0; */ b_initial.add_assignment (sum, ctxt.zero (the_type)); /* i = 0; */ b_initial.add_assignment (i, ctxt.zero (the_type));
We can then terminate the entry block by jumping to the conditional:
b_initial.end_with_jump (b_loop_cond);
The conditional block is equivalent to the line while (i < n) from our C example. It contains a single statement: a conditional, which jumps to one of two destination blocks depending on a boolean gccjit;;rvalue, in this case the comparison of i and n.
We could build the comparison using gccjit;;context;;new_comparison():
gccjit::rvalue guard = ctxt.new_comparison (GCC_JIT_COMPARISON_GE, i, n);
and can then use this to add b_loop_cond’s sole statement, via gccjit;;block;;end_with_conditional():
b_loop_cond.end_with_conditional (guard, b_after_loop, // on_true b_loop_body); // on_false
However gccjit;;rvalue has overloaded operators for this, so we express the conditional as
gccjit::rvalue guard = (i >= n);
and hence we can write the block more concisely as:
b_loop_cond.end_with_conditional ( i >= n, b_after_loop, // on_true b_loop_body); // on_false
Next, we populate the body of the loop.
The C statement sum += i * i; is an assignment operation, where an lvalue is modified “in-place”. We use gccjit;;block;;add_assignment_op() to handle these operations:
/* sum += i * i */ b_loop_body.add_assignment_op (sum, GCC_JIT_BINARY_OP_PLUS, i * i);
The i++ can be thought of as i += 1, and can thus be handled in a similar way. We use gcc_jit_context_one() to get the constant value 1 (for the relevant type) for the right-hand side of the assignment.
/* i++ */ b_loop_body.add_assignment_op (i, GCC_JIT_BINARY_OP_PLUS, ctxt.one (the_type));
|
The loop body completes by jumping back to the conditional:
b_loop_body.end_with_jump (b_loop_cond);
Finally, we populate the b_after_loop block, reached when the loop conditional is false. We want to generate the equivalent of:
return sum;
so the block is just one statement:
/* return sum */ b_after_loop.end_with_return (sum);
|
We’ve finished populating the function. As before, we can now compile it to machine code:
gcc_jit_result *result; result = ctxt.compile (); ctxt.release (); if (!result) { fprintf (stderr, "NULL result"); return 1; } 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; } printf ("result: %d", loop_test (10));
result: 285