123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- #include <math.h>
- #include <stdlib.h>
- #include <stdio.h>
- #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);
- }
|