int main (int argc, char **argv) { gcc_jit_context *ctxt = NULL; gcc_jit_result *result = NULL; /* Get a "context" object for working with the library. */ ctxt = gcc_jit_context_acquire (); if (!ctxt) { fprintf (stderr, "NULL ctxt"); goto error; } /* Set some options on the context. Let's see the code being generated, in assembler form. */ gcc_jit_context_set_bool_option ( ctxt, GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 0); /* Populate the context. */ create_code (ctxt); /* Compile the code. */ result = gcc_jit_context_compile (ctxt); if (!result) { fprintf (stderr, "NULL result"); goto error; } /* We're done with the context; we can release it: */ gcc_jit_context_release (ctxt); ctxt = NULL; /* Extract the generated code from "result". */ void *fn_ptr = gcc_jit_result_get_code (result, "square"); if (!fn_ptr) { fprintf (stderr, "NULL fn_ptr"); goto error; } typedef int (*fn_type) (int); fn_type square = (fn_type)fn_ptr; printf ("result: %d\n", square (5)); error: if (ctxt) gcc_jit_context_release (ctxt); if (result) gcc_jit_result_release (result); return 0; }
int main (int argc, char **argv) { gcc_jit_context *ctxt = NULL; gcc_jit_result *result = NULL; /* Get a "context" object for working with the library. */ ctxt = gcc_jit_context_acquire (); if (!ctxt) { fprintf (stderr, "NULL ctxt"); goto error; } /* Set some options on the context. Let's see the code being generated, in assembler form. */ gcc_jit_context_set_bool_option ( ctxt, GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 0); /* Populate the context. */ create_code (ctxt); /* Compile the code. */ result = gcc_jit_context_compile (ctxt); if (!result) { fprintf (stderr, "NULL result"); goto error; } /* Extract the generated code from "result". */ 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"); goto error; } /* Run the generated code. */ int val = loop_test (10); printf("loop_test returned: %d\n", val); error: gcc_jit_context_release (ctxt); gcc_jit_result_release (result); return 0; }
int main (int argc, char **argv) { gcc_jit_context *ctxt; gcc_jit_result *result; /* Get a "context" object for working with the library. */ ctxt = gcc_jit_context_acquire (); if (!ctxt) { fprintf (stderr, "NULL ctxt"); exit (1); } /* Set some options on the context. Let's see the code being generated, in assembler form. */ gcc_jit_context_set_bool_option ( ctxt, GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 0); /* Populate the context. */ create_code (ctxt); /* Compile the code. */ result = gcc_jit_context_compile (ctxt); if (!result) { fprintf (stderr, "NULL result"); exit (1); } /* Extract the generated code from "result". */ typedef void (*fn_type) (const char *); fn_type greet = (fn_type)gcc_jit_result_get_code (result, "greet"); if (!greet) { fprintf (stderr, "NULL greet"); exit (1); } /* Now call the generated function: */ greet ("world"); fflush (stdout); gcc_jit_context_release (ctxt); gcc_jit_result_release (result); return 0; }
void ravi_jit_context_free(ravi_gcc_context_t *ravi) { if (ravi == NULL) return; if (ravi->parent_result_) { gcc_jit_result_release(ravi->parent_result_); ravi->parent_result_ = NULL; } if (ravi->context) { gcc_jit_context_release(ravi->context); ravi->context = NULL; } if (ravi->types) { free(ravi->types); ravi->types = NULL; } free(ravi); }
ravi_gcc_context_t *ravi_jit_new_context(void) { ravi_gcc_context_t *ravi = NULL; gcc_jit_context *gcc_ctx = gcc_jit_context_acquire(); if (!gcc_ctx) { fprintf(stderr, "failed to allocate a GCC JIT context\n"); goto on_error; } ravi = (ravi_gcc_context_t *)calloc(1, sizeof(ravi_gcc_context_t)); if (!ravi) { fprintf(stderr, "failed to allocate a Ravi JIT context\n"); goto on_error; } ravi->context = gcc_ctx; ravi->auto_ = false; ravi->enabled_ = true; ravi->min_code_size_ = 150; ravi->min_exec_count_ = 50; ravi->opt_level_ = 3; ravi->size_level_ = 0; if (!ravi_setup_lua_types(ravi)) { fprintf(stderr, "failed to setup types\n"); goto on_error; } ravi->parent_result_ = gcc_jit_context_compile(ravi->context); if (gcc_jit_context_get_first_error(ravi->context)) { fprintf(stderr, "aborting due to JIT error: %s\n", gcc_jit_context_get_first_error(ravi->context)); abort(); } return ravi; on_error: if (ravi) { ravi_jit_context_free(ravi); } else if (gcc_ctx) { gcc_jit_context_release(gcc_ctx); } return NULL; }
static toyvm_compiled_function * toyvm_function_compile (toyvm_function *fn) { compilation_state state; int pc; char *funcname; memset (&state, 0, sizeof (state)); funcname = get_function_name (fn->fn_filename); state.ctxt = gcc_jit_context_acquire (); gcc_jit_context_set_bool_option (state.ctxt, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 0); gcc_jit_context_set_bool_option (state.ctxt, GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 0); gcc_jit_context_set_int_option (state.ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); gcc_jit_context_set_bool_option (state.ctxt, GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES, 0); gcc_jit_context_set_bool_option (state.ctxt, GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING, 0); gcc_jit_context_set_bool_option (state.ctxt, GCC_JIT_BOOL_OPTION_DEBUGINFO, 1); /* Create types. */ state.int_type = gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT); state.bool_type = gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL); state.stack_type = gcc_jit_context_new_array_type (state.ctxt, NULL, state.int_type, MAX_STACK_DEPTH); /* The constant value 1. */ state.const_one = gcc_jit_context_one (state.ctxt, state.int_type); /* Create locations. */ for (pc = 0; pc < fn->fn_num_ops; pc++) { toyvm_op *op = &fn->fn_ops[pc]; state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt, fn->fn_filename, op->op_linenum, 0); /* column */ } /* Creating the function. */ state.param_arg = gcc_jit_context_new_param (state.ctxt, state.op_locs[0], state.int_type, "arg"); state.fn = gcc_jit_context_new_function (state.ctxt, state.op_locs[0], GCC_JIT_FUNCTION_EXPORTED, state.int_type, funcname, 1, &state.param_arg, 0); /* Create stack lvalues. */ state.stack = gcc_jit_function_new_local (state.fn, NULL, state.stack_type, "stack"); state.stack_depth = gcc_jit_function_new_local (state.fn, NULL, state.int_type, "stack_depth"); state.x = gcc_jit_function_new_local (state.fn, NULL, state.int_type, "x"); state.y = gcc_jit_function_new_local (state.fn, NULL, state.int_type, "y"); /* 1st pass: create blocks, one per opcode. */ /* We need an entry block to do one-time initialization, so create that first. */ state.initial_block = gcc_jit_function_new_block (state.fn, "initial"); /* Create a block per operation. */ for (pc = 0; pc < fn->fn_num_ops; pc++) { char buf[16]; sprintf (buf, "instr%i", pc); state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf); } /* Populate the initial block. */ /* "stack_depth = 0;". */ gcc_jit_block_add_assignment ( state.initial_block, state.op_locs[0], state.stack_depth, gcc_jit_context_zero (state.ctxt, state.int_type)); /* "PUSH (arg);". */ add_push (&state, state.initial_block, gcc_jit_param_as_rvalue (state.param_arg), state.op_locs[0]); /* ...and jump to insn 0. */ gcc_jit_block_end_with_jump (state.initial_block, state.op_locs[0], state.op_blocks[0]); /* 2nd pass: fill in instructions. */ for (pc = 0; pc < fn->fn_num_ops; pc++) { gcc_jit_location *loc = state.op_locs[pc]; gcc_jit_block *block = state.op_blocks[pc]; gcc_jit_block *next_block = (pc < fn->fn_num_ops ? state.op_blocks[pc + 1] : NULL); toyvm_op *op; op = &fn->fn_ops[pc]; /* Helper macros. */ #define X_EQUALS_POP()\ add_pop (&state, block, state.x, loc) #define Y_EQUALS_POP()\ add_pop (&state, block, state.y, loc) #define PUSH_RVALUE(RVALUE)\ add_push (&state, block, (RVALUE), loc) #define PUSH_X()\ PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x)) #define PUSH_Y() \ PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y)) gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]); /* Handle the individual opcodes. */ switch (op->op_opcode) { case DUP: X_EQUALS_POP (); PUSH_X (); PUSH_X (); break; case ROT: Y_EQUALS_POP (); X_EQUALS_POP (); PUSH_Y (); PUSH_X (); break; case BINARY_ADD: Y_EQUALS_POP (); X_EQUALS_POP (); PUSH_RVALUE ( gcc_jit_context_new_binary_op ( state.ctxt, loc, GCC_JIT_BINARY_OP_PLUS, state.int_type, gcc_jit_lvalue_as_rvalue (state.x), gcc_jit_lvalue_as_rvalue (state.y))); break; case BINARY_SUBTRACT: Y_EQUALS_POP (); X_EQUALS_POP (); PUSH_RVALUE ( gcc_jit_context_new_binary_op ( state.ctxt, loc, GCC_JIT_BINARY_OP_MINUS, state.int_type, gcc_jit_lvalue_as_rvalue (state.x), gcc_jit_lvalue_as_rvalue (state.y))); break; case BINARY_MULT: Y_EQUALS_POP (); X_EQUALS_POP (); PUSH_RVALUE ( gcc_jit_context_new_binary_op ( state.ctxt, loc, GCC_JIT_BINARY_OP_MULT, state.int_type, gcc_jit_lvalue_as_rvalue (state.x), gcc_jit_lvalue_as_rvalue (state.y))); break; case BINARY_COMPARE_LT: Y_EQUALS_POP (); X_EQUALS_POP (); PUSH_RVALUE ( /* cast of bool to int */ gcc_jit_context_new_cast ( state.ctxt, loc, /* (x < y) as a bool */ gcc_jit_context_new_comparison ( state.ctxt, loc, GCC_JIT_COMPARISON_LT, gcc_jit_lvalue_as_rvalue (state.x), gcc_jit_lvalue_as_rvalue (state.y)), state.int_type)); break; case RECURSE: { X_EQUALS_POP (); gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x); PUSH_RVALUE ( gcc_jit_context_new_call ( state.ctxt, loc, state.fn, 1, &arg)); break; } case RETURN: X_EQUALS_POP (); gcc_jit_block_end_with_return ( block, loc, gcc_jit_lvalue_as_rvalue (state.x)); break; /* Ops taking an operand. */ case PUSH_CONST: PUSH_RVALUE ( gcc_jit_context_new_rvalue_from_int ( state.ctxt, state.int_type, op->op_operand)); break; case JUMP_ABS_IF_TRUE: X_EQUALS_POP (); gcc_jit_block_end_with_conditional ( block, loc, /* "(bool)x". */ gcc_jit_context_new_cast ( state.ctxt, loc, gcc_jit_lvalue_as_rvalue (state.x), state.bool_type), state.op_blocks[op->op_operand], /* on_true */ next_block); /* on_false */ break; default: assert(0); } /* end of switch on opcode */ /* Go to the next block. */ if (op->op_opcode != JUMP_ABS_IF_TRUE && op->op_opcode != RETURN) gcc_jit_block_end_with_jump ( block, loc, next_block); } /* end of loop on PC locations. */ /* We've now finished populating the context. Compile it. */ gcc_jit_result *jit_result = gcc_jit_context_compile (state.ctxt); gcc_jit_context_release (state.ctxt); toyvm_compiled_function *toyvm_result = (toyvm_compiled_function *)calloc (1, sizeof (toyvm_compiled_function)); if (!toyvm_result) { fprintf (stderr, "out of memory allocating toyvm_compiled_function\n"); gcc_jit_result_release (jit_result); return NULL; } toyvm_result->cf_jit_result = jit_result; toyvm_result->cf_code = (toyvm_compiled_code)gcc_jit_result_get_code (jit_result, funcname); free (funcname); return toyvm_result; }
int main (int argc, char **argv) { int i, j, k; const int NUM_TOP_ITERATIONS = 2; const int NUM_MIDDLE_ITERATIONS = 2; const int NUM_BOTTOM_ITERATIONS = 2; /* We do the whole thing multiple times to shake out state-management issues in the underlying code. */ for (i = 1; i <= NUM_TOP_ITERATIONS; i++) { /* Create the top-level context. */ snprintf (test, sizeof (test), "%s iteration %d of %d of top level", extract_progname (argv[0]), i, NUM_TOP_ITERATIONS); struct top_level top_level; memset (&top_level, 0, sizeof (top_level)); top_level.ctxt = gcc_jit_context_acquire (); set_options (top_level.ctxt, argv[0]); make_types (&top_level); make_sqrt (&top_level); /* No errors should have occurred. */ CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL); gcc_jit_context_dump_to_file (top_level.ctxt, "dump-of-test-nested-contexts-top.c", 1); for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++) { /* Create and populate the middle-level context, using objects from the top-level context. */ snprintf (test, sizeof (test), ("%s iteration %d of %d of top level;" " %d of %d of middle level"), extract_progname (argv[0]), i, NUM_TOP_ITERATIONS, j, NUM_MIDDLE_ITERATIONS); struct middle_level middle_level; memset (&middle_level, 0, sizeof (middle_level)); middle_level.ctxt = gcc_jit_context_new_child_context (top_level.ctxt); make_calc_discriminant (&top_level, &middle_level); /* No errors should have occurred. */ CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt), NULL); gcc_jit_context_dump_to_file (middle_level.ctxt, "dump-of-test-nested-contexts-middle.c", 1); gcc_jit_result *middle_result = gcc_jit_context_compile (middle_level.ctxt); CHECK_NON_NULL (middle_result); verify_middle_code (middle_level.ctxt, middle_result); for (k = 1; k <= NUM_BOTTOM_ITERATIONS; k++) { /* Create and populate the innermost context, using objects from the top-level and middle-level contexts. */ snprintf (test, sizeof (test), ("%s iteration %d of %d of top level;" " %d of %d of middle level;" " %d of %d of bottom level"), extract_progname (argv[0]), i, NUM_TOP_ITERATIONS, j, NUM_MIDDLE_ITERATIONS, k, NUM_BOTTOM_ITERATIONS); struct bottom_level bottom_level; memset (&bottom_level, 0, sizeof (bottom_level)); bottom_level.ctxt = gcc_jit_context_new_child_context (middle_level.ctxt); make_test_quadratic (&top_level, &middle_level, &bottom_level); /* No errors should have occurred. */ CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt), NULL); gcc_jit_context_dump_to_file (bottom_level.ctxt, "dump-of-test-nested-contexts-bottom.c", 1); gcc_jit_result *bottom_result = gcc_jit_context_compile (bottom_level.ctxt); verify_bottom_code (bottom_level.ctxt, bottom_result); gcc_jit_result_release (bottom_result); gcc_jit_context_release (bottom_level.ctxt); } gcc_jit_result_release (middle_result); gcc_jit_context_release (middle_level.ctxt); } gcc_jit_context_release (top_level.ctxt); } totals (); return 0; }