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 gcc_jit_block * instances within the gcc_jit_function *:
gcc_jit_block *b_initial = gcc_jit_function_new_block (func, "initial"); gcc_jit_block *b_loop_cond = gcc_jit_function_new_block (func, "loop_cond"); gcc_jit_block *b_loop_body = gcc_jit_function_new_block (func, "loop_body"); gcc_jit_block *b_after_loop = gcc_jit_function_new_block (func, "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 gcc_jit_block_add_assignment() to add an assignment statement, and using gcc_jit_context_zero() to get the constant value 0 for the relevant type for the right-hand side of the assignment:
/* sum = 0; */ gcc_jit_block_add_assignment ( b_initial, NULL, sum, gcc_jit_context_zero (ctxt, the_type)); /* i = 0; */ gcc_jit_block_add_assignment ( b_initial, NULL, i, gcc_jit_context_zero (ctxt, the_type));
We can then terminate the entry block by jumping to the conditional:
gcc_jit_block_end_with_jump (b_initial, NULL, 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 gcc_jit_rvalue *, in this case the comparison of i and n. We build the comparison using gcc_jit_context_new_comparison():
/* (i >= n) */ gcc_jit_rvalue *guard = gcc_jit_context_new_comparison ( ctxt, NULL, GCC_JIT_COMPARISON_GE, gcc_jit_lvalue_as_rvalue (i), gcc_jit_param_as_rvalue (n));
and can then use this to add b_loop_cond’s sole statement, via gcc_jit_block_end_with_conditional():
/* Equivalent to: if (guard) goto after_loop; else goto loop_body; */ gcc_jit_block_end_with_conditional ( b_loop_cond, NULL, guard, 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 gcc_jit_block_add_assignment_op() to handle these operations:
/* sum += i * i */ gcc_jit_block_add_assignment_op ( b_loop_body, NULL, sum, GCC_JIT_BINARY_OP_PLUS, gcc_jit_context_new_binary_op ( ctxt, NULL, GCC_JIT_BINARY_OP_MULT, the_type, gcc_jit_lvalue_as_rvalue (i), gcc_jit_lvalue_as_rvalue (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++ */ gcc_jit_block_add_assignment_op ( b_loop_body, NULL, i, GCC_JIT_BINARY_OP_PLUS, gcc_jit_context_one (ctxt, the_type));
|
The loop body completes by jumping back to the conditional:
gcc_jit_block_end_with_jump (b_loop_body, NULL, 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 */ gcc_jit_block_end_with_return ( b_after_loop, NULL, gcc_jit_lvalue_as_rvalue (sum));
|
We’ve finished populating the function. As before, we can now compile it to machine code:
gcc_jit_result *result; result = gcc_jit_context_compile (ctxt); 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) goto error; printf ("result: %d", loop_test (10));
result: 285