void verify_bottom_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef int (*fn_type) (double a, double b, double c, double *r1, double *r2); CHECK_NON_NULL (result); fn_type test_quadratic = (fn_type)gcc_jit_result_get_code (result, "test_quadratic"); CHECK_NON_NULL (test_quadratic); /* Verify that the code correctly solves quadratic equations. */ double r1, r2; /* This one has two solutions: */ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2); CHECK_VALUE (r1, 1); CHECK_VALUE (r2, -4); /* This one has one solution: */ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1); CHECK_VALUE (r1, -0.5); /* This one has no real solutions: */ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0); }
static void verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef double (*fn_type) (double); CHECK_NON_NULL (result); fn_type test_of_builtin_trig = (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_trig"); CHECK_NON_NULL (test_of_builtin_trig); /* Verify that it correctly computes sin (2 * theta) (perhaps calling sin and cos). */ CHECK_DOUBLE_VALUE (test_of_builtin_trig (0.0 ), 0.0); CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 ), 1.0); CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2 ), 0.0); CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0); CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI ), 0.0); /* PR jit/64020: The "sincos" pass merges sin/cos calls into the cexpi builtin. Verify that a dump of the "sincos" pass was provided, and that it shows a call to the cexpi builtin on a SSA name of "theta". */ CHECK_NON_NULL (trig_sincos_dump); CHECK_STRING_CONTAINS (trig_sincos_dump, " = __builtin_cexpi (theta_"); free (trig_sincos_dump); /* Similarly, verify that the statistics dump was provided, and that it shows the sincos optimization. */ CHECK_NON_NULL (trig_statistics_dump); CHECK_STRING_CONTAINS ( trig_statistics_dump, "sincos \"sincos statements inserted\" \"test_of_builtin_trig\" 1"); free (trig_statistics_dump); }
static void* concurrent_jit_run(void *info) { gcc_jit_context *ctx; ctx = gcc_jit_context_acquire (); if (ctx == NULL) { fprintf(stderr, "acquired JIT context is NULL"); return NULL; } gcc_jit_context_set_int_option(ctx, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2); #if EXTRAE_SUPPORT Extrae_event(JIT_EVENT_TYPE, JIT_CODE_GENERATION); #endif generate_code_regexp(ctx, regexp); #if EXTRAE_SUPPORT Extrae_event(JIT_EVENT_TYPE, 0); Extrae_event(JIT_EVENT_TYPE, JIT_COMPILATION); #endif gcc_jit_result *result = gcc_jit_context_compile(ctx); #if EXTRAE_SUPPORT Extrae_event(JIT_EVENT_TYPE, 0); #endif if (result == NULL) { fprintf(stderr, "compilation failed"); return NULL; } #if EXTRAE_SUPPORT Extrae_event(JIT_EVENT_TYPE, JIT_GET_CODE); #endif match_fun_t function_addr = (match_fun_t)gcc_jit_result_get_code(result, "match"); #if EXTRAE_SUPPORT Extrae_event(JIT_EVENT_TYPE, 0); #endif #if EXTRAE_SUPPORT if (function_addr == NULL) { fprintf(stderr, "error getting 'match'"); return NULL; } #endif atomic_store(&match_fun, function_addr); return NULL; }
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; }
extern void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (const char *); CHECK_NON_NULL (result); fn_type hello_world = (fn_type)gcc_jit_result_get_code (result, "hello_world"); CHECK_NON_NULL (hello_world); hello_world ("world"); fflush (stdout); }
static void verify_hidden_functions (gcc_jit_context *ctxt, gcc_jit_result *result) { CHECK_NON_NULL (result); /* GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE functions should not be accessible in the result. */ CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_internal_mult")); CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_always_inline_mult")); typedef double (*fn_type) (double); fn_type my_square_with_internal = (fn_type)gcc_jit_result_get_code (result, "my_square_with_internal"); CHECK_NON_NULL (my_square_with_internal); CHECK_VALUE (my_square_with_internal (5.0), 25.0); fn_type my_square_with_always_inline = (fn_type)gcc_jit_result_get_code (result, "my_square_with_always_inline"); CHECK_NON_NULL (my_square_with_always_inline); CHECK_VALUE (my_square_with_always_inline (5.0), 25.0); }
void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { CHECK_NON_NULL (result); typedef int (*my_fn_type) (void); CHECK_NON_NULL (result); my_fn_type my_fn = (my_fn_type)gcc_jit_result_get_code (result, long_names.fn_name); CHECK_NON_NULL (my_fn); int val = my_fn (); CHECK_VALUE (val, 42); }
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; }
static void verify_void_return (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (int *); CHECK_NON_NULL (result); fn_type test_of_void_return = (fn_type)gcc_jit_result_get_code (result, "test_of_void_return"); CHECK_NON_NULL (test_of_void_return); int i; test_of_void_return (&i); CHECK_VALUE (i, 1); /* ensure correct value was written back */ }
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; }
static void verify_test_of_builtin_strcmp (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef int (*fn_type) (const char *, const char *); CHECK_NON_NULL (result); fn_type test_of_builtin_strcmp = (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_strcmp"); CHECK_NON_NULL (test_of_builtin_strcmp); /* Verify that it correctly called strcmp. */ CHECK_VALUE (test_of_builtin_strcmp ("foo", "foo"), 0); CHECK (test_of_builtin_strcmp ("foo", "bar") > 0); CHECK (test_of_builtin_strcmp ("bar", "foo") < 0); }
void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef double (*test_nested_loops_fn_type) (int n, double *a, double *b); CHECK_NON_NULL (result); test_nested_loops_fn_type test_nested_loops = (test_nested_loops_fn_type)gcc_jit_result_get_code (result, "test_nested_loops"); CHECK_NON_NULL (test_nested_loops); double test_a[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}; double test_b[] = {5., 6., 7., 8., 9., 10., 1., 2., 3., 4.}; double val = test_nested_loops (10, test_a, test_b); note ("test_nested_loops returned: %f", val); CHECK_VALUE (val, 3025.0); }
void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef float (*fn_type) (int i); CHECK_NON_NULL (result); fn_type test_union = (fn_type)gcc_jit_result_get_code (result, "test_union"); CHECK_NON_NULL (test_union); /* Call the JIT-generated function. */ float f_result = test_union (42); union int_or_float u; u.as_float = f_result; CHECK_VALUE (u.as_int, 42); }
void verify_middle_code (gcc_jit_context *ctxt, gcc_jit_result *result) { struct quadratic q; typedef void (*fn_type) (struct quadratic *q); fn_type calc_discriminant = (fn_type)gcc_jit_result_get_code (result, "calc_discriminant"); CHECK_NON_NULL (calc_discriminant); q.a = 3; q.b = 5; q.c = 7; q.discriminant = 0; calc_discriminant (&q); CHECK_VALUE (q.discriminant, -59); }
void verify_uint_overflow_fn (gcc_jit_result *jit_result, const char *funcname, unsigned int x, unsigned int y, unsigned int expected_result, int expected_ovf) { CHECK_NON_NULL (jit_result); typedef unsigned int (*overflow_fn_type) (unsigned int, unsigned int, int *); overflow_fn_type fn = (overflow_fn_type)gcc_jit_result_get_code (jit_result, funcname); CHECK_NON_NULL (fn); /* Call the function: */ int actual_ovf = 0; unsigned int actual_result = fn (x, y, &actual_ovf); note ("%s (%d, %d) returned: %d with ovf: %d", funcname, x, y, actual_result, actual_ovf); CHECK_VALUE (actual_result, expected_result); CHECK_VALUE (actual_ovf, expected_ovf); }
void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (int); CHECK_NON_NULL (result); fn_type test_caller = (fn_type)gcc_jit_result_get_code (result, "test_caller"); CHECK_NON_NULL (test_caller); called_with[0] = 0; called_with[1] = 0; called_with[2] = 0; /* Call the JIT-generated function. */ test_caller (5); /* Verify that it correctly called "called_function". */ CHECK_VALUE (called_with[0], 15); CHECK_VALUE (called_with[1], 20); CHECK_VALUE (called_with[2], 25); }
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; }