#include #include #include #include "libgccjit.h" #include "harness.h" /********************************************************************** GCC_JIT_FUNCTION_ALWAYS_INLINE and GCC_JIT_FUNCTION_INTERNAL **********************************************************************/ static void create_test_of_hidden_function (gcc_jit_context *ctxt, enum gcc_jit_function_kind hidden_kind, const char *hidden_func_name, const char *visible_func_name) { /* Let's try to inject the equivalent of: static double hidden_mult (double a, double b) { return x * x; } double my_square (double x) { return my_mult (x, x); } where hidden_mult can potentially be inline __attribute__((always_inline)). */ gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); /* Create "my_mult" */ gcc_jit_param *param_a = gcc_jit_context_new_param (ctxt, NULL, double_type, "a"); gcc_jit_param *param_b = gcc_jit_context_new_param (ctxt, NULL, double_type, "b"); gcc_jit_param *params[2] = {param_a, param_b}; gcc_jit_function *my_mult = gcc_jit_context_new_function (ctxt, NULL, hidden_kind, double_type, hidden_func_name, 2, params, 0); gcc_jit_block *body_of_my_mult = gcc_jit_function_new_block (my_mult, NULL); gcc_jit_block_end_with_return ( body_of_my_mult, NULL, gcc_jit_context_new_binary_op ( ctxt, NULL, GCC_JIT_BINARY_OP_MULT, double_type, gcc_jit_param_as_rvalue (param_a), gcc_jit_param_as_rvalue (param_b))); /* Create "my_square" */ gcc_jit_param *param_x = gcc_jit_context_new_param (ctxt, NULL, double_type, "x"); gcc_jit_function *my_square = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, double_type, visible_func_name, 1, ¶m_x, 0); gcc_jit_block *body_of_my_square = gcc_jit_function_new_block (my_square, NULL); gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_x), gcc_jit_param_as_rvalue (param_x)}; gcc_jit_block_end_with_return ( body_of_my_square, NULL, gcc_jit_context_new_call ( ctxt, NULL, my_mult, 2, args)); } static void create_tests_of_hidden_functions (gcc_jit_context *ctxt) { create_test_of_hidden_function (ctxt, GCC_JIT_FUNCTION_INTERNAL, "my_internal_mult", "my_square_with_internal"); create_test_of_hidden_function (ctxt, GCC_JIT_FUNCTION_ALWAYS_INLINE, "my_always_inline_mult", "my_square_with_always_inline"); } 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); } /********************************************************************** Builtin functions **********************************************************************/ static void create_test_of_builtin_strcmp (gcc_jit_context *ctxt) { /* Let's try to inject the equivalent of: int test_of_builtin_strcmp (const char *a, const char *b) { return __builtin_strcmp (a, b); } */ gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); gcc_jit_type *const_char_ptr_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); /* Get the built-in function. */ gcc_jit_function *builtin_fn = gcc_jit_context_get_builtin_function (ctxt, "strcmp"); CHECK_STRING_VALUE ( gcc_jit_object_get_debug_string (gcc_jit_function_as_object (builtin_fn)), "strcmp"); /* Build the test_fn. */ gcc_jit_param *param_a = gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "a"); gcc_jit_param *param_b = gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "b"); gcc_jit_param *params[2] = {param_a, param_b}; gcc_jit_function *test_fn = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, int_type, "test_of_builtin_strcmp", 2, params, 0); gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_a), gcc_jit_param_as_rvalue (param_b)}; gcc_jit_rvalue *call = gcc_jit_context_new_call (ctxt, NULL, builtin_fn, 2, args); CHECK_STRING_VALUE ( gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (call)), "strcmp (a, b)"); gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); gcc_jit_block_end_with_return (initial, NULL, call); } static char *trig_sincos_dump; static char *trig_statistics_dump; static void create_test_of_builtin_trig (gcc_jit_context *ctxt) { /* Let's try to inject the equivalent of: int test_of_builtin_trig (double theta) { return 2 * sin (theta) * cos (theta); } (in theory, optimizable to sin (2 * theta)) */ gcc_jit_context_enable_dump (ctxt, "tree-sincos", &trig_sincos_dump); gcc_jit_context_enable_dump (ctxt, "statistics", &trig_statistics_dump); gcc_jit_type *double_t = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); /* Get the built-in functions. */ gcc_jit_function *builtin_sin = gcc_jit_context_get_builtin_function (ctxt, "sin"); gcc_jit_function *builtin_cos = gcc_jit_context_get_builtin_function (ctxt, "cos"); /* Build the test_fn. */ gcc_jit_param *param_theta = gcc_jit_context_new_param (ctxt, NULL, double_t, "theta"); gcc_jit_function *test_fn = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, double_t, "test_of_builtin_trig", 1, ¶m_theta, 0); gcc_jit_rvalue *args[1] = {gcc_jit_param_as_rvalue (param_theta)}; gcc_jit_rvalue *two = gcc_jit_context_new_rvalue_from_int (ctxt, double_t, 2); gcc_jit_rvalue *ret = gcc_jit_context_new_binary_op ( ctxt, NULL, GCC_JIT_BINARY_OP_MULT, double_t, two, gcc_jit_context_new_binary_op ( ctxt, NULL, GCC_JIT_BINARY_OP_MULT, double_t, gcc_jit_context_new_call (ctxt, NULL, builtin_sin, 1, args), gcc_jit_context_new_call (ctxt, NULL, builtin_cos, 1, args))); CHECK_STRING_VALUE ( gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (ret)), "(double)2 * sin (theta) * cos (theta)"); gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); gcc_jit_block_end_with_return (initial, NULL, ret); } static void create_use_of_builtins (gcc_jit_context *ctxt) { create_test_of_builtin_strcmp (ctxt); create_test_of_builtin_trig (ctxt); } 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); } 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 verify_use_of_builtins (gcc_jit_context *ctxt, gcc_jit_result *result) { verify_test_of_builtin_strcmp (ctxt, result); verify_test_of_builtin_trig (ctxt, result); } /********************************************************************** "void" return **********************************************************************/ static void create_use_of_void_return (gcc_jit_context *ctxt) { /* Let's try to inject the equivalent of: void test_of_void_return (int *out) { *out = 1; return; } */ gcc_jit_type *void_t = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); gcc_jit_type *int_t = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); gcc_jit_type *int_ptr_t = gcc_jit_type_get_pointer (int_t); /* Build the test_fn. */ gcc_jit_param *param_out = gcc_jit_context_new_param (ctxt, NULL, int_ptr_t, "out"); gcc_jit_function *test_fn = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, void_t, "test_of_void_return", 1, ¶m_out, 0); gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); gcc_jit_block_add_assignment ( initial, NULL, /* "*out = ..." */ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (param_out), NULL), gcc_jit_context_one (ctxt, int_t)); gcc_jit_block_end_with_void_return (initial, NULL); } 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 */ } /********************************************************************** Code for harness **********************************************************************/ void create_code (gcc_jit_context *ctxt, void *user_data) { create_tests_of_hidden_functions (ctxt); create_use_of_builtins (ctxt); create_use_of_void_return (ctxt); } void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { verify_hidden_functions (ctxt, result); verify_use_of_builtins (ctxt, result); verify_void_return (ctxt, result); }