1 #include <stdlib.h>
2 #include <stdio.h>
3 
4 #include "libgccjit.h"
5 
6 #include "harness.h"
7 
8 struct quadratic
9 {
10   double a;
11   double b;
12   double c;
13   double discriminant;
14 };
15 
16 /* Let's try to inject the equivalent of:
17 
18      extern double sqrt (double);
19 
20      static void
21      calc_discriminant (struct quadratic *q)
22      {
23        // (b^2 - 4ac)
24        q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
25      }
26 
27      int
28      test_quadratic (double a, double b, double c, double *r1, double *r2)
29      {
30        struct quadratic q;
31        q.a = a;
32        q.b = b;
33        q.c = c;
34        calc_discriminant (&q);
35        if (q.discriminant > 0)
36 	 {
37 	    double s = sqrt (q.discriminant);
38 	    *r1 = (-b + s) / (2 * a);
39 	    *r2 = (-b - s) / (2 * a);
40 	    return 2;
41 	 }
42        else if (q.discriminant == 0)
43 	 {
44 	    *r1 = -b / (2 * a);
45 	    return 1;
46 	 }
47 	 else return 0;
48      }
49 */
50 
51 struct quadratic_test
52 {
53   gcc_jit_context *ctxt;
54 
55   /* "double" and "(double *)".  */
56   gcc_jit_type *numeric_type;
57   gcc_jit_type *numeric_type_ptr;
58 
59   /* The value (double)0.  */
60   gcc_jit_rvalue *zero;
61 
62   gcc_jit_type *int_type;
63   gcc_jit_type *void_type;
64 
65   /* "struct quadratic" */
66   gcc_jit_type *quadratic;
67   gcc_jit_field *a;
68   gcc_jit_field *b;
69   gcc_jit_field *c;
70   gcc_jit_field *discriminant;
71 
72   /* "(struct quadratic *)" */
73   gcc_jit_type *quadratic_ptr;
74 
75   gcc_jit_function *calc_discriminant;
76 
77   gcc_jit_function *sqrt;
78 
79 };
80 
81 static void
make_types(struct quadratic_test * testcase)82 make_types (struct quadratic_test *testcase)
83 {
84   testcase->numeric_type =
85     gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE);
86   testcase->numeric_type_ptr =
87     gcc_jit_type_get_pointer (testcase->numeric_type);
88   testcase->zero =
89     gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
90 
91   testcase->int_type =
92     gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
93 
94   testcase->void_type =
95     gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
96 
97   testcase->a =
98     gcc_jit_context_new_field (testcase->ctxt,
99 			       NULL,
100 			       testcase->numeric_type,
101 			       "a");
102   testcase->b =
103     gcc_jit_context_new_field (testcase->ctxt,
104 			       NULL,
105 			       testcase->numeric_type,
106 			       "b");
107   testcase->c =
108     gcc_jit_context_new_field (testcase->ctxt,
109 			       NULL,
110 			       testcase->numeric_type,
111 			       "c");
112   testcase->discriminant =
113     gcc_jit_context_new_field (testcase->ctxt,
114 			       NULL,
115 			       testcase->numeric_type,
116 			       "discriminant");
117   gcc_jit_field *fields[] = {testcase->a,
118 			     testcase->b,
119 			     testcase->c,
120 			     testcase->discriminant};
121   testcase->quadratic =
122     gcc_jit_struct_as_type (
123       gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
124 				       "quadratic", 4, fields));
125   testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
126 }
127 
128 static void
make_sqrt(struct quadratic_test * testcase)129 make_sqrt (struct quadratic_test *testcase)
130 {
131   gcc_jit_param *param_x =
132     gcc_jit_context_new_param (testcase->ctxt, NULL,
133 			       testcase->numeric_type, "x");
134   testcase->sqrt =
135     gcc_jit_context_new_function (testcase->ctxt, NULL,
136 				  GCC_JIT_FUNCTION_IMPORTED,
137 				  testcase->numeric_type,
138 				  "sqrt",
139 				  1, &param_x,
140 				  0);
141 }
142 
143 static void
make_calc_discriminant(struct quadratic_test * testcase)144 make_calc_discriminant (struct quadratic_test *testcase)
145 {
146   /* Build "calc_discriminant".  */
147   gcc_jit_param *param_q =
148     gcc_jit_context_new_param (testcase->ctxt, NULL,
149 			       testcase->quadratic_ptr, "q");
150   testcase->calc_discriminant =
151     gcc_jit_context_new_function (testcase->ctxt, NULL,
152 				  GCC_JIT_FUNCTION_INTERNAL,
153 				  testcase->void_type,
154 				  "calc_discriminant",
155 				  1, &param_q,
156 				  0);
157   gcc_jit_block *blk =
158     gcc_jit_function_new_block (testcase->calc_discriminant, NULL);
159   gcc_jit_block_add_comment (
160     blk, NULL,
161     "(b^2 - 4ac)");
162 
163   gcc_jit_rvalue *q_a =
164     gcc_jit_lvalue_as_rvalue (
165 	gcc_jit_rvalue_dereference_field (
166 	  gcc_jit_param_as_rvalue (param_q),
167 	  NULL, testcase->a));
168   gcc_jit_rvalue *q_b =
169     gcc_jit_lvalue_as_rvalue (
170 	gcc_jit_rvalue_dereference_field (
171 	  gcc_jit_param_as_rvalue (param_q),
172 	  NULL, testcase->b));
173   gcc_jit_rvalue *q_c =
174     gcc_jit_lvalue_as_rvalue (
175 	gcc_jit_rvalue_dereference_field (
176 	  gcc_jit_param_as_rvalue (param_q),
177 	  NULL, testcase->c));
178 
179   /* (q->b * q->b) - (4 * q->a * q->c) */
180   gcc_jit_rvalue *rhs =
181     gcc_jit_context_new_binary_op (
182       testcase->ctxt, NULL,
183       GCC_JIT_BINARY_OP_MINUS,
184       testcase->numeric_type,
185 
186       /* (q->b * q->b) */
187       gcc_jit_context_new_binary_op (
188 	testcase->ctxt, NULL,
189 	GCC_JIT_BINARY_OP_MULT,
190 	testcase->numeric_type,
191 	q_b, q_b),
192 
193       /* (4 * (q->a * q->c)) */
194       gcc_jit_context_new_binary_op (
195 	testcase->ctxt, NULL,
196 	GCC_JIT_BINARY_OP_MULT,
197 	testcase->numeric_type,
198 	/* 4.0 */
199 	gcc_jit_context_new_rvalue_from_int (
200 	  testcase->ctxt,
201 	  testcase->numeric_type,
202 	  4),
203 	/* (q->a * q->c) */
204 	gcc_jit_context_new_binary_op (
205 	  testcase->ctxt, NULL,
206 	  GCC_JIT_BINARY_OP_MULT,
207 	  testcase->numeric_type,
208 	  q_a, q_c)));
209 
210   CHECK_STRING_VALUE (
211      gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (rhs)),
212      "q->b * q->b - (double)4 * q->a * q->c");
213 
214   gcc_jit_block_add_assignment (
215     blk, NULL,
216 
217     /* q->discriminant =...  */
218     gcc_jit_rvalue_dereference_field (
219       gcc_jit_param_as_rvalue (param_q),
220       NULL,
221       testcase->discriminant),
222     rhs);
223 
224   gcc_jit_block_end_with_void_return (blk, NULL);
225 }
226 
227 static void
make_test_quadratic(struct quadratic_test * testcase)228 make_test_quadratic (struct quadratic_test *testcase)
229 {
230   gcc_jit_param *a =
231     gcc_jit_context_new_param (testcase->ctxt, NULL,
232 			       testcase->numeric_type, "a");
233   gcc_jit_param *b =
234     gcc_jit_context_new_param (testcase->ctxt, NULL,
235 			       testcase->numeric_type, "b");
236   gcc_jit_param *c =
237     gcc_jit_context_new_param (testcase->ctxt, NULL,
238 			       testcase->numeric_type, "c");
239   gcc_jit_param *r1 =
240     gcc_jit_context_new_param (testcase->ctxt, NULL,
241 			       testcase->numeric_type_ptr, "r1");
242   gcc_jit_param *r2 =
243     gcc_jit_context_new_param (testcase->ctxt, NULL,
244 			       testcase->numeric_type_ptr, "r2");
245   gcc_jit_param *params[] = {a, b, c, r1, r2};
246   gcc_jit_function *test_quadratic =
247     gcc_jit_context_new_function (testcase->ctxt, NULL,
248 				  GCC_JIT_FUNCTION_EXPORTED,
249 				  testcase->int_type,
250 				  "test_quadratic",
251 				  5, params,
252 				  0);
253   /* struct quadratic q; */
254   gcc_jit_lvalue *q =
255     gcc_jit_function_new_local (
256       test_quadratic, NULL,
257       testcase->quadratic,
258       "q");
259 
260   gcc_jit_block *initial =
261     gcc_jit_function_new_block (test_quadratic,
262 				"initial");
263   gcc_jit_block *on_positive_discriminant
264     = gcc_jit_function_new_block (test_quadratic,
265 				  "positive_discriminant");
266 
267   gcc_jit_block *on_nonpositive_discriminant
268     = gcc_jit_function_new_block (test_quadratic,
269 				  "nonpositive_discriminant");
270 
271   gcc_jit_block *on_zero_discriminant
272     = gcc_jit_function_new_block (test_quadratic,
273 				  "zero_discriminant");
274 
275   gcc_jit_block *on_negative_discriminant
276     = gcc_jit_function_new_block (test_quadratic,
277 				  "negative_discriminant");
278 
279   /* Initial block.  */
280   /* q.a = a; */
281   gcc_jit_block_add_assignment (
282     initial, NULL,
283     gcc_jit_lvalue_access_field (q, NULL, testcase->a),
284     gcc_jit_param_as_rvalue (a));
285   /* q.b = b; */
286   gcc_jit_block_add_assignment (
287     initial, NULL,
288     gcc_jit_lvalue_access_field (q, NULL, testcase->b),
289     gcc_jit_param_as_rvalue (b));
290   /* q.c = c; */
291   gcc_jit_block_add_assignment (
292     initial, NULL,
293     gcc_jit_lvalue_access_field (q, NULL, testcase->c),
294     gcc_jit_param_as_rvalue (c));
295   /* calc_discriminant (&q); */
296   gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
297   gcc_jit_block_add_eval (
298     initial, NULL,
299     gcc_jit_context_new_call (
300       testcase->ctxt, NULL,
301       testcase->calc_discriminant,
302       1, &address_of_q));
303 
304   gcc_jit_block_add_comment (
305     initial, NULL,
306     "if (q.discriminant > 0)");
307   gcc_jit_block_end_with_conditional (
308     initial, NULL,
309     gcc_jit_context_new_comparison (
310       testcase->ctxt, NULL,
311       GCC_JIT_COMPARISON_GT,
312       gcc_jit_rvalue_access_field (
313 	gcc_jit_lvalue_as_rvalue (q),
314 	NULL,
315 	testcase->discriminant),
316       testcase->zero),
317     on_positive_discriminant,
318     on_nonpositive_discriminant);
319 
320   /* Block: "on_positive_discriminant" */
321   /* double s = sqrt (q.discriminant); */
322   gcc_jit_lvalue *s = gcc_jit_function_new_local (
323     test_quadratic, NULL,
324     testcase->numeric_type,
325     "s");
326   gcc_jit_rvalue *discriminant_of_q =
327     gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
328 				 NULL,
329 				 testcase->discriminant);
330   gcc_jit_block_add_assignment (
331     on_positive_discriminant, NULL,
332     s,
333     gcc_jit_context_new_call (
334       testcase->ctxt, NULL,
335       testcase->sqrt,
336       1, &discriminant_of_q));
337 
338   gcc_jit_rvalue *minus_b =
339     gcc_jit_context_new_unary_op (
340       testcase->ctxt, NULL,
341       GCC_JIT_UNARY_OP_MINUS,
342       testcase->numeric_type,
343       gcc_jit_param_as_rvalue (b));
344   gcc_jit_rvalue *two_a =
345     gcc_jit_context_new_binary_op (
346       testcase->ctxt, NULL,
347       GCC_JIT_BINARY_OP_MULT,
348       testcase->numeric_type,
349       gcc_jit_context_new_rvalue_from_int (
350 	testcase->ctxt,
351 	testcase->numeric_type,
352 	2),
353       gcc_jit_param_as_rvalue (a));
354 
355   gcc_jit_block_add_comment (
356     on_positive_discriminant, NULL,
357     "*r1 = (-b + s) / (2 * a);");
358   gcc_jit_block_add_assignment (
359     on_positive_discriminant, NULL,
360 
361     /* "*r1 = ..." */
362     gcc_jit_rvalue_dereference (
363       gcc_jit_param_as_rvalue (r1), NULL),
364 
365     /* (-b + s) / (2 * a) */
366     gcc_jit_context_new_binary_op (
367       testcase->ctxt, NULL,
368       GCC_JIT_BINARY_OP_DIVIDE,
369       testcase->numeric_type,
370       gcc_jit_context_new_binary_op (
371 	testcase->ctxt, NULL,
372 	GCC_JIT_BINARY_OP_PLUS,
373 	testcase->numeric_type,
374 	minus_b,
375 	gcc_jit_lvalue_as_rvalue (s)),
376       two_a));
377 
378   gcc_jit_block_add_comment (
379     on_positive_discriminant, NULL,
380     "*r2 = (-b - s) / (2 * a)");
381   gcc_jit_block_add_assignment (
382     on_positive_discriminant, NULL,
383 
384     /* "*r2 = ..." */
385     gcc_jit_rvalue_dereference (
386       gcc_jit_param_as_rvalue (r2), NULL),
387 
388     /* (-b - s) / (2 * a) */
389     gcc_jit_context_new_binary_op (
390       testcase->ctxt, NULL,
391       GCC_JIT_BINARY_OP_DIVIDE,
392       testcase->numeric_type,
393       gcc_jit_context_new_binary_op (
394 	testcase->ctxt, NULL,
395 	GCC_JIT_BINARY_OP_MINUS,
396 	testcase->numeric_type,
397 	minus_b,
398 	gcc_jit_lvalue_as_rvalue (s)),
399       two_a));
400 
401   /* "return 2;" */
402   gcc_jit_block_end_with_return (
403     on_positive_discriminant, NULL,
404     gcc_jit_context_new_rvalue_from_int (
405       testcase->ctxt,
406       testcase->int_type,
407       2));
408 
409   /* Block: "on_nonpositive_discriminant" */
410   gcc_jit_block_add_comment (
411     on_nonpositive_discriminant, NULL,
412     "else if (q.discriminant == 0)");
413   gcc_jit_block_end_with_conditional (
414     on_nonpositive_discriminant, NULL,
415     gcc_jit_context_new_comparison (
416       testcase->ctxt, NULL,
417       GCC_JIT_COMPARISON_EQ,
418       gcc_jit_rvalue_access_field (
419 	gcc_jit_lvalue_as_rvalue (q),
420 	NULL,
421 	testcase->discriminant),
422       testcase->zero),
423     on_zero_discriminant,
424     on_negative_discriminant);
425 
426   /* Block: "on_zero_discriminant" */
427   gcc_jit_block_add_comment (
428     on_zero_discriminant, NULL,
429     "*r1 = -b / (2 * a);");
430   gcc_jit_block_add_assignment (
431     on_zero_discriminant, NULL,
432 
433     /* "*r1 = ..." */
434     gcc_jit_rvalue_dereference (
435       gcc_jit_param_as_rvalue (r1), NULL),
436 
437     /* -b / (2 * a) */
438     gcc_jit_context_new_binary_op (
439       testcase->ctxt, NULL,
440       GCC_JIT_BINARY_OP_DIVIDE,
441       testcase->numeric_type,
442       minus_b,
443       two_a));
444   gcc_jit_block_end_with_return (
445     /* "return 1;" */
446     on_zero_discriminant, NULL,
447       gcc_jit_context_one (testcase->ctxt, testcase->int_type));
448 
449   /* Block: "on_negative_discriminant" */
450   gcc_jit_block_end_with_return (
451     /* "else return 0;" */
452     on_negative_discriminant, NULL,
453     gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
454 }
455 
456 void
create_code(gcc_jit_context * ctxt,void * user_data)457 create_code (gcc_jit_context *ctxt, void *user_data)
458 {
459   struct quadratic_test testcase;
460   memset (&testcase, 0, sizeof (testcase));
461   testcase.ctxt = ctxt;
462   make_types (&testcase);
463   make_sqrt (&testcase);
464   make_calc_discriminant (&testcase);
465   make_test_quadratic (&testcase);
466 }
467 
468 void
verify_code(gcc_jit_context * ctxt,gcc_jit_result * result)469 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
470 {
471   typedef int (*fn_type) (double a, double b, double c,
472 			  double *r1, double *r2);
473 
474   CHECK_NON_NULL (result);
475 
476   fn_type test_quadratic =
477     (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
478   CHECK_NON_NULL (test_quadratic);
479 
480   /* Verify that the code correctly solves quadratic equations.  */
481   double r1, r2;
482 
483   /* This one has two solutions: */
484   CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
485   CHECK_VALUE (r1, 1);
486   CHECK_VALUE (r2, -4);
487 
488   /* This one has one solution: */
489   CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
490   CHECK_VALUE (r1, -0.5);
491 
492   /* This one has no real solutions: */
493   CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
494 }
495