First we create our types:
void compilation_state::create_types () { /* Create types. */ int_type = ctxt.get_type (GCC_JIT_TYPE_INT); bool_type = ctxt.get_type (GCC_JIT_TYPE_BOOL); stack_type = ctxt.new_array_type (int_type, MAX_STACK_DEPTH);
along with extracting a useful int constant:
const_one = ctxt.one (int_type); }
We’ll implement push and pop in terms of the stack
array and
stack_depth
. Here are helper functions for adding statements to
a block, implementing pushing and popping values:
void compilation_state::add_push (gccjit::block block, gccjit::rvalue rvalue, gccjit::location loc) { /* stack[stack_depth] = RVALUE */ block.add_assignment ( /* stack[stack_depth] */ ctxt.new_array_access ( stack, stack_depth, loc), rvalue, loc); /* "stack_depth++;". */ block.add_assignment_op ( stack_depth, GCC_JIT_BINARY_OP_PLUS, const_one, loc); } void compilation_state::add_pop (gccjit::block block, gccjit::lvalue lvalue, gccjit::location loc) { /* "--stack_depth;". */ block.add_assignment_op ( stack_depth, GCC_JIT_BINARY_OP_MINUS, const_one, loc); /* "LVALUE = stack[stack_depth];". */ block.add_assignment ( lvalue, /* stack[stack_depth] */ ctxt.new_array_access (stack, stack_depth, loc), loc); }
We will support single-stepping through the generated code in the
debugger, so we need to create gccjit;;location instances, one
per operation in the source code. These will reference the lines of
e.g. factorial.toy
.
void compilation_state::create_locations () { for (int pc = 0; pc < toyvmfn.fn_num_ops; pc++) { toyvm_op *op = &toyvmfn.fn_ops[pc]; op_locs[pc] = ctxt.new_location (toyvmfn.fn_filename, op->op_linenum, 0); /* column */ } }
Let’s create the function itself. As usual, we create its parameter first, then use the parameter to create the function:
void compilation_state::create_function (const char *funcname) { std::vector <gccjit::param> params; param_arg = ctxt.new_param (int_type, "arg", op_locs[0]); params.push_back (param_arg); fn = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, int_type, funcname, params, 0, op_locs[0]);
We create the locals within the function.
stack = fn.new_local (stack_type, "stack"); stack_depth = fn.new_local (int_type, "stack_depth"); x = fn.new_local (int_type, "x"); y = fn.new_local (int_type, "y");