(root)/
gcc-13.2.0/
gcc/
testsuite/
jit.dg/
test-functions.c
       1  #include <math.h>
       2  #include <stdlib.h>
       3  #include <stdio.h>
       4  
       5  #include "libgccjit.h"
       6  
       7  #include "harness.h"
       8  
       9  /**********************************************************************
      10   GCC_JIT_FUNCTION_ALWAYS_INLINE and GCC_JIT_FUNCTION_INTERNAL
      11   **********************************************************************/
      12  static void
      13  create_test_of_hidden_function (gcc_jit_context *ctxt,
      14  				enum gcc_jit_function_kind hidden_kind,
      15  				const char *hidden_func_name,
      16  				const char *visible_func_name)
      17  {
      18    /* Let's try to inject the equivalent of:
      19       static double hidden_mult (double a, double b)
      20       {
      21         return x * x;
      22       }
      23       double my_square (double x)
      24       {
      25         return my_mult (x, x);
      26       }
      27  
      28       where hidden_mult can potentially be
      29         inline  __attribute__((always_inline)).  */
      30    gcc_jit_type *double_type =
      31      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
      32  
      33    /* Create "my_mult" */
      34    gcc_jit_param *param_a =
      35      gcc_jit_context_new_param (ctxt, NULL, double_type, "a");
      36    gcc_jit_param *param_b =
      37      gcc_jit_context_new_param (ctxt, NULL, double_type, "b");
      38    gcc_jit_param *params[2] = {param_a, param_b};
      39    gcc_jit_function *my_mult =
      40      gcc_jit_context_new_function (ctxt, NULL,
      41  				  hidden_kind,
      42                                    double_type,
      43                                    hidden_func_name,
      44                                    2, params,
      45                                    0);
      46    gcc_jit_block *body_of_my_mult =
      47      gcc_jit_function_new_block (my_mult, NULL);
      48    gcc_jit_block_end_with_return (
      49      body_of_my_mult, NULL,
      50      gcc_jit_context_new_binary_op (
      51        ctxt, NULL,
      52        GCC_JIT_BINARY_OP_MULT,
      53        double_type,
      54        gcc_jit_param_as_rvalue (param_a),
      55        gcc_jit_param_as_rvalue (param_b)));
      56  
      57    /* Create "my_square" */
      58    gcc_jit_param *param_x =
      59      gcc_jit_context_new_param (ctxt, NULL, double_type, "x");
      60    gcc_jit_function *my_square =
      61      gcc_jit_context_new_function (ctxt, NULL,
      62                                    GCC_JIT_FUNCTION_EXPORTED,
      63                                    double_type,
      64                                    visible_func_name,
      65                                    1, &param_x,
      66                                    0);
      67    gcc_jit_block *body_of_my_square =
      68      gcc_jit_function_new_block (my_square, NULL);
      69    gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_x),
      70  			     gcc_jit_param_as_rvalue (param_x)};
      71    gcc_jit_block_end_with_return (
      72      body_of_my_square, NULL,
      73      gcc_jit_context_new_call (
      74        ctxt, NULL,
      75        my_mult,
      76        2, args));
      77  }
      78  
      79  static void
      80  create_tests_of_hidden_functions (gcc_jit_context *ctxt)
      81  {
      82    create_test_of_hidden_function (ctxt,
      83  				  GCC_JIT_FUNCTION_INTERNAL,
      84  				  "my_internal_mult",
      85  				  "my_square_with_internal");
      86    create_test_of_hidden_function (ctxt,
      87  				  GCC_JIT_FUNCTION_ALWAYS_INLINE,
      88  				  "my_always_inline_mult",
      89  				  "my_square_with_always_inline");
      90  }
      91  
      92  static void
      93  verify_hidden_functions (gcc_jit_context *ctxt, gcc_jit_result *result)
      94  {
      95    CHECK_NON_NULL (result);
      96  
      97    /* GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE
      98       functions should not be accessible in the result.  */
      99    CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_internal_mult"));
     100    CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_always_inline_mult"));
     101  
     102    typedef double (*fn_type) (double);
     103    fn_type my_square_with_internal =
     104      (fn_type)gcc_jit_result_get_code (result, "my_square_with_internal");
     105    CHECK_NON_NULL (my_square_with_internal);
     106    CHECK_VALUE (my_square_with_internal (5.0), 25.0);
     107  
     108    fn_type my_square_with_always_inline =
     109      (fn_type)gcc_jit_result_get_code (result, "my_square_with_always_inline");
     110    CHECK_NON_NULL (my_square_with_always_inline);
     111    CHECK_VALUE (my_square_with_always_inline (5.0), 25.0);
     112  }
     113  
     114  /**********************************************************************
     115   Builtin functions
     116   **********************************************************************/
     117  
     118  static void
     119  create_test_of_builtin_strcmp (gcc_jit_context *ctxt)
     120  {
     121    /* Let's try to inject the equivalent of:
     122         int
     123         test_of_builtin_strcmp (const char *a, const char *b)
     124         {
     125           return __builtin_strcmp (a, b);
     126         }
     127    */
     128    gcc_jit_type *int_type =
     129      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
     130    gcc_jit_type *const_char_ptr_type =
     131      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
     132  
     133    /* Get the built-in function.  */
     134    gcc_jit_function *builtin_fn =
     135      gcc_jit_context_get_builtin_function (ctxt, "strcmp");
     136  
     137    CHECK_STRING_VALUE (
     138      gcc_jit_object_get_debug_string (gcc_jit_function_as_object (builtin_fn)),
     139      "strcmp");
     140  
     141    /* Build the test_fn.  */
     142    gcc_jit_param *param_a =
     143      gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "a");
     144    gcc_jit_param *param_b =
     145      gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "b");
     146    gcc_jit_param *params[2] = {param_a, param_b};
     147    gcc_jit_function *test_fn =
     148      gcc_jit_context_new_function (ctxt, NULL,
     149                                    GCC_JIT_FUNCTION_EXPORTED,
     150                                    int_type,
     151                                    "test_of_builtin_strcmp",
     152                                    2, params,
     153                                    0);
     154    gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_a),
     155  			     gcc_jit_param_as_rvalue (param_b)};
     156    gcc_jit_rvalue *call =
     157      gcc_jit_context_new_call (ctxt,
     158                                NULL,
     159                                builtin_fn,
     160                                2, args);
     161    CHECK_STRING_VALUE (
     162      gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (call)),
     163      "strcmp (a, b)");
     164  
     165    gcc_jit_block *initial =
     166      gcc_jit_function_new_block (test_fn, "initial");
     167    gcc_jit_block_end_with_return (initial, NULL, call);
     168  }
     169  
     170  static char *trig_sincos_dump;
     171  static char *trig_statistics_dump;
     172  
     173  static void
     174  create_test_of_builtin_trig (gcc_jit_context *ctxt)
     175  {
     176    /* Let's try to inject the equivalent of:
     177         int
     178         test_of_builtin_trig (double theta)
     179         {
     180           return 2 * sin (theta) * cos (theta);
     181         }
     182         (in theory, optimizable to sin (2 * theta))
     183    */
     184  
     185    gcc_jit_context_enable_dump (ctxt,
     186  			       "tree-sincos",
     187  			       &trig_sincos_dump);
     188    gcc_jit_context_enable_dump (ctxt,
     189  			       "statistics",
     190  			       &trig_statistics_dump);
     191  
     192    gcc_jit_type *double_t =
     193      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
     194  
     195    /* Get the built-in functions.  */
     196    gcc_jit_function *builtin_sin =
     197      gcc_jit_context_get_builtin_function (ctxt, "sin");
     198    gcc_jit_function *builtin_cos =
     199      gcc_jit_context_get_builtin_function (ctxt, "cos");
     200  
     201    /* Build the test_fn.  */
     202    gcc_jit_param *param_theta =
     203      gcc_jit_context_new_param (ctxt, NULL, double_t, "theta");
     204    gcc_jit_function *test_fn =
     205      gcc_jit_context_new_function (ctxt, NULL,
     206                                    GCC_JIT_FUNCTION_EXPORTED,
     207                                    double_t,
     208                                    "test_of_builtin_trig",
     209                                    1, &param_theta,
     210                                    0);
     211    gcc_jit_rvalue *args[1] = {gcc_jit_param_as_rvalue (param_theta)};
     212    gcc_jit_rvalue *two =
     213      gcc_jit_context_new_rvalue_from_int (ctxt, double_t, 2);
     214    gcc_jit_rvalue *ret =
     215      gcc_jit_context_new_binary_op (
     216        ctxt, NULL,
     217        GCC_JIT_BINARY_OP_MULT,
     218        double_t,
     219        two,
     220        gcc_jit_context_new_binary_op (
     221          ctxt, NULL,
     222  	GCC_JIT_BINARY_OP_MULT,
     223  	double_t,
     224  	gcc_jit_context_new_call (ctxt, NULL,
     225  				  builtin_sin,
     226  				  1, args),
     227  	gcc_jit_context_new_call (ctxt, NULL,
     228  				  builtin_cos,
     229  				  1, args)));
     230    CHECK_STRING_VALUE (
     231      gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (ret)),
     232      "(double)2 * sin (theta) * cos (theta)");
     233  
     234    gcc_jit_block *initial =
     235      gcc_jit_function_new_block (test_fn, "initial");
     236    gcc_jit_block_end_with_return (initial, NULL, ret);
     237  }
     238  
     239  static void
     240  create_use_of_builtins (gcc_jit_context *ctxt)
     241  {
     242    create_test_of_builtin_strcmp (ctxt);
     243    create_test_of_builtin_trig (ctxt);
     244  }
     245  
     246  static void
     247  verify_test_of_builtin_strcmp (gcc_jit_context *ctxt, gcc_jit_result *result)
     248  {
     249    typedef int (*fn_type) (const char *, const char *);
     250    CHECK_NON_NULL (result);
     251  
     252    fn_type test_of_builtin_strcmp =
     253      (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_strcmp");
     254    CHECK_NON_NULL (test_of_builtin_strcmp);
     255  
     256    /* Verify that it correctly called strcmp.  */
     257    CHECK_VALUE (test_of_builtin_strcmp ("foo", "foo"), 0);
     258    CHECK (test_of_builtin_strcmp ("foo", "bar") > 0);
     259    CHECK (test_of_builtin_strcmp ("bar", "foo") < 0);
     260  }
     261  
     262  static void
     263  verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result)
     264  {
     265    typedef double (*fn_type) (double);
     266    CHECK_NON_NULL (result);
     267  
     268    fn_type test_of_builtin_trig =
     269      (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_trig");
     270    CHECK_NON_NULL (test_of_builtin_trig);
     271  
     272    /* Verify that it correctly computes
     273          sin (2 * theta)
     274       (perhaps calling sin and cos). */
     275    CHECK_DOUBLE_VALUE (test_of_builtin_trig (0.0         ),  0.0);
     276    CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4      ),  1.0);
     277    CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2      ),  0.0);
     278    CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0);
     279    CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI        ),  0.0);
     280  
     281    /* PR jit/64020:
     282       The "sincos" pass merges sin/cos calls into the cexpi builtin.
     283       Verify that a dump of the "sincos" pass was provided, and that it
     284       shows a call to the cexpi builtin on a SSA name of "theta".  */
     285    CHECK_NON_NULL (trig_sincos_dump);
     286    CHECK_STRING_CONTAINS (trig_sincos_dump, " = __builtin_cexpi (theta_");
     287    free (trig_sincos_dump);
     288  
     289    /* Similarly, verify that the statistics dump was provided, and that
     290       it shows the sincos optimization.  */
     291    CHECK_NON_NULL (trig_statistics_dump);
     292    CHECK_STRING_CONTAINS (
     293      trig_statistics_dump,
     294      "sincos \"sincos statements inserted\" \"test_of_builtin_trig\" 1");
     295    free (trig_statistics_dump);
     296  }
     297  
     298  static void
     299  verify_use_of_builtins (gcc_jit_context *ctxt, gcc_jit_result *result)
     300  {
     301    verify_test_of_builtin_strcmp (ctxt, result);
     302    verify_test_of_builtin_trig (ctxt, result);
     303  }
     304  
     305  /**********************************************************************
     306   "void" return
     307   **********************************************************************/
     308  
     309  static void
     310  create_use_of_void_return (gcc_jit_context *ctxt)
     311  {
     312    /* Let's try to inject the equivalent of:
     313         void
     314         test_of_void_return (int *out)
     315         {
     316           *out = 1;
     317  	 return;
     318         }
     319    */
     320    gcc_jit_type *void_t =
     321      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
     322    gcc_jit_type *int_t =
     323      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
     324    gcc_jit_type *int_ptr_t =
     325      gcc_jit_type_get_pointer (int_t);
     326  
     327    /* Build the test_fn.  */
     328    gcc_jit_param *param_out =
     329      gcc_jit_context_new_param (ctxt, NULL, int_ptr_t, "out");
     330    gcc_jit_function *test_fn =
     331      gcc_jit_context_new_function (ctxt, NULL,
     332                                    GCC_JIT_FUNCTION_EXPORTED,
     333                                    void_t,
     334                                    "test_of_void_return",
     335                                    1, &param_out,
     336                                    0);
     337    gcc_jit_block *initial =
     338      gcc_jit_function_new_block (test_fn, "initial");
     339  
     340    gcc_jit_block_add_assignment (
     341      initial, NULL,
     342      /* "*out = ..." */
     343      gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (param_out),
     344  				NULL),
     345      gcc_jit_context_one (ctxt, int_t));
     346    gcc_jit_block_end_with_void_return (initial, NULL);
     347  }
     348  
     349  static void
     350  verify_void_return (gcc_jit_context *ctxt, gcc_jit_result *result)
     351  {
     352    typedef void (*fn_type) (int *);
     353    CHECK_NON_NULL (result);
     354  
     355    fn_type test_of_void_return =
     356      (fn_type)gcc_jit_result_get_code (result, "test_of_void_return");
     357    CHECK_NON_NULL (test_of_void_return);
     358  
     359    int i;
     360    test_of_void_return (&i);
     361    CHECK_VALUE (i, 1); /* ensure correct value was written back */
     362  }
     363  
     364  /**********************************************************************
     365   Code for harness
     366   **********************************************************************/
     367  
     368  void
     369  create_code (gcc_jit_context *ctxt, void *user_data)
     370  {
     371    create_tests_of_hidden_functions (ctxt);
     372    create_use_of_builtins (ctxt);
     373    create_use_of_void_return (ctxt);
     374  }
     375  
     376  
     377  void
     378  verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
     379  {
     380    verify_hidden_functions (ctxt, result);
     381    verify_use_of_builtins (ctxt, result);
     382    verify_void_return (ctxt, result);
     383  }