test-functions.c 12 KB

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