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 **********************************************************************/ 12static void 13create_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, ¶m_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 79static void 80create_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 92static void 93verify_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 118static void 119create_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 170static char *trig_sincos_dump; 171static char *trig_statistics_dump; 172 173static void 174create_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, ¶m_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 239static void 240create_use_of_builtins (gcc_jit_context *ctxt) 241{ 242 create_test_of_builtin_strcmp (ctxt); 243 create_test_of_builtin_trig (ctxt); 244} 245 246static void 247verify_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 262static void 263verify_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 298static void 299verify_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 309static void 310create_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, ¶m_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 349static void 350verify_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 368void 369create_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 377void 378verify_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} 384