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, ¶m_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, ¶m_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