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
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)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
create_tests_of_hidden_functions(gcc_jit_context * ctxt)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
verify_hidden_functions(gcc_jit_context * ctxt,gcc_jit_result * result)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
create_test_of_builtin_strcmp(gcc_jit_context * ctxt)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
create_test_of_builtin_trig(gcc_jit_context * ctxt)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
create_use_of_builtins(gcc_jit_context * ctxt)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
verify_test_of_builtin_strcmp(gcc_jit_context * ctxt,gcc_jit_result * result)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
verify_test_of_builtin_trig(gcc_jit_context * ctxt,gcc_jit_result * result)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
verify_use_of_builtins(gcc_jit_context * ctxt,gcc_jit_result * result)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
create_use_of_void_return(gcc_jit_context * ctxt)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
verify_void_return(gcc_jit_context * ctxt,gcc_jit_result * result)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
create_code(gcc_jit_context * ctxt,void * user_data)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
verify_code(gcc_jit_context * ctxt,gcc_jit_result * result)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 }
384