1 #include <stdlib.h>
2 #include <stdio.h>
3
4 #include "libgccjit.h"
5
6 #define TEST_ESCHEWS_TEST_JIT
7 #define TEST_PROVIDES_MAIN
8 #include "harness.h"
9
10 struct quadratic
11 {
12 double a;
13 double b;
14 double c;
15 double discriminant;
16 };
17
18 /* This is an adapted version of test-quadratic.c
19
20 Like that test, we'll try to inject the following code, but we'll
21 split it up into some nested contexts, in 3 levels, to test
22 how nested contexts work.
23
24 ***** In top-level context: *****
25
26 (shared type declarations, for int, double, struct quadratic);
27 extern double sqrt (double);
28
29 ***** In mid-level context: *****
30
31 void
32 calc_discriminant (struct quadratic *q)
33 {
34 // (b^2 - 4ac)
35 q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
36 }
37
38 ***** In bottom context: *****
39
40 int
41 test_quadratic (double a, double b, double c, double *r1, double *r2)
42 {
43 struct quadratic q;
44 q.a = a;
45 q.b = b;
46 q.c = c;
47 calc_discriminant (&q);
48 if (q.discriminant > 0)
49 {
50 double s = sqrt (q.discriminant);
51 *r1 = (-b + s) / (2 * a);
52 *r2 = (-b - s) / (2 * a);
53 return 2;
54 }
55 else if (q.discriminant == 0)
56 {
57 *r1 = -b / (2 * a);
58 return 1;
59 }
60 else return 0;
61 }
62 */
63
64 struct top_level
65 {
66 gcc_jit_context *ctxt;
67
68 /* "double" and "(double *)". */
69 gcc_jit_type *numeric_type;
70 gcc_jit_type *numeric_type_ptr;
71
72 /* The value (double)0. */
73 gcc_jit_rvalue *zero;
74
75 gcc_jit_type *int_type;
76 gcc_jit_type *void_type;
77
78 /* "struct quadratic" */
79 gcc_jit_type *struct_quadratic;
80 gcc_jit_field *a;
81 gcc_jit_field *b;
82 gcc_jit_field *c;
83 gcc_jit_field *discriminant;
84
85 /* "(struct quadratic *)" */
86 gcc_jit_type *quadratic_ptr;
87
88 gcc_jit_function *sqrt;
89 };
90
91 struct middle_level
92 {
93 gcc_jit_context *ctxt;
94 gcc_jit_function *calc_discriminant;
95 };
96
97 struct bottom_level
98 {
99 gcc_jit_context *ctxt;
100 };
101
102 static void
make_types(struct top_level * top_level)103 make_types (struct top_level *top_level)
104 {
105 top_level->numeric_type =
106 gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_DOUBLE);
107 top_level->numeric_type_ptr =
108 gcc_jit_type_get_pointer (top_level->numeric_type);
109 top_level->zero =
110 gcc_jit_context_zero (top_level->ctxt, top_level->numeric_type);
111
112 top_level->int_type =
113 gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_INT);
114 top_level->void_type =
115 gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_VOID);
116
117 top_level->a =
118 gcc_jit_context_new_field (top_level->ctxt,
119 NULL,
120 top_level->numeric_type,
121 "a");
122 top_level->b =
123 gcc_jit_context_new_field (top_level->ctxt,
124 NULL,
125 top_level->numeric_type,
126 "b");
127 top_level->c =
128 gcc_jit_context_new_field (top_level->ctxt,
129 NULL,
130 top_level->numeric_type,
131 "c");
132 top_level->discriminant =
133 gcc_jit_context_new_field (top_level->ctxt,
134 NULL,
135 top_level->numeric_type,
136 "discriminant");
137 gcc_jit_field *fields[] = {top_level->a,
138 top_level->b,
139 top_level->c,
140 top_level->discriminant};
141 top_level->struct_quadratic =
142 gcc_jit_struct_as_type (
143 gcc_jit_context_new_struct_type (top_level->ctxt, NULL,
144 "quadratic", 4, fields));
145 top_level->quadratic_ptr =
146 gcc_jit_type_get_pointer (top_level->struct_quadratic);
147 }
148
149 static void
make_sqrt(struct top_level * top_level)150 make_sqrt (struct top_level *top_level)
151 {
152 gcc_jit_param *param_x =
153 gcc_jit_context_new_param (top_level->ctxt, NULL,
154 top_level->numeric_type, "x");
155 top_level->sqrt =
156 gcc_jit_context_new_function (top_level->ctxt, NULL,
157 GCC_JIT_FUNCTION_IMPORTED,
158 top_level->numeric_type,
159 "sqrt",
160 1, ¶m_x,
161 0);
162 }
163
164 static void
make_calc_discriminant(struct top_level * top_level,struct middle_level * middle_level)165 make_calc_discriminant (struct top_level *top_level,
166 struct middle_level *middle_level)
167 {
168 /* Build "calc_discriminant". */
169 gcc_jit_param *param_q =
170 gcc_jit_context_new_param (middle_level->ctxt, NULL,
171 top_level->quadratic_ptr, "q");
172 middle_level->calc_discriminant =
173 gcc_jit_context_new_function (middle_level->ctxt, NULL,
174 GCC_JIT_FUNCTION_EXPORTED,
175 top_level->void_type,
176 "calc_discriminant",
177 1, ¶m_q,
178 0);
179 gcc_jit_block *blk =
180 gcc_jit_function_new_block (middle_level->calc_discriminant, NULL);
181 gcc_jit_block_add_comment (
182 blk, NULL,
183 "(b^2 - 4ac)");
184
185 gcc_jit_rvalue *q_a =
186 gcc_jit_lvalue_as_rvalue (
187 gcc_jit_rvalue_dereference_field (
188 gcc_jit_param_as_rvalue (param_q),
189 NULL, top_level->a));
190 gcc_jit_rvalue *q_b =
191 gcc_jit_lvalue_as_rvalue (
192 gcc_jit_rvalue_dereference_field (
193 gcc_jit_param_as_rvalue (param_q),
194 NULL, top_level->b));
195 gcc_jit_rvalue *q_c =
196 gcc_jit_lvalue_as_rvalue (
197 gcc_jit_rvalue_dereference_field (
198 gcc_jit_param_as_rvalue (param_q),
199 NULL, top_level->c));
200
201 gcc_jit_block_add_assignment (
202 blk, NULL,
203
204 /* q->discriminant =... */
205 gcc_jit_rvalue_dereference_field (
206 gcc_jit_param_as_rvalue (param_q),
207 NULL,
208 top_level->discriminant),
209
210 /* (q->b * q->b) - (4 * q->a * q->c) */
211 gcc_jit_context_new_binary_op (
212 middle_level->ctxt, NULL,
213 GCC_JIT_BINARY_OP_MINUS,
214 top_level->numeric_type,
215
216 /* (q->b * q->b) */
217 gcc_jit_context_new_binary_op (
218 middle_level->ctxt, NULL,
219 GCC_JIT_BINARY_OP_MULT,
220 top_level->numeric_type,
221 q_b, q_b),
222
223 /* (4 * (q->a * q->c)) */
224 gcc_jit_context_new_binary_op (
225 middle_level->ctxt, NULL,
226 GCC_JIT_BINARY_OP_MULT,
227 top_level->numeric_type,
228 /* 4.0 */
229 gcc_jit_context_new_rvalue_from_int (
230 middle_level->ctxt,
231 top_level->numeric_type,
232 4),
233 /* (q->a * q->c) */
234 gcc_jit_context_new_binary_op (
235 middle_level->ctxt, NULL,
236 GCC_JIT_BINARY_OP_MULT,
237 top_level->numeric_type,
238 q_a, q_c)))); /* end of gcc_jit_function_add_assignment call. */
239
240 gcc_jit_block_end_with_void_return (blk, NULL);
241 }
242
243 static void
make_test_quadratic(struct top_level * top_level,struct middle_level * middle_level,struct bottom_level * bottom_level)244 make_test_quadratic (struct top_level *top_level,
245 struct middle_level *middle_level,
246 struct bottom_level *bottom_level)
247 {
248 gcc_jit_param *a =
249 gcc_jit_context_new_param (bottom_level->ctxt, NULL,
250 top_level->numeric_type, "a");
251 gcc_jit_param *b =
252 gcc_jit_context_new_param (bottom_level->ctxt, NULL,
253 top_level->numeric_type, "b");
254 gcc_jit_param *c =
255 gcc_jit_context_new_param (bottom_level->ctxt, NULL,
256 top_level->numeric_type, "c");
257 gcc_jit_param *r1 =
258 gcc_jit_context_new_param (bottom_level->ctxt, NULL,
259 top_level->numeric_type_ptr, "r1");
260 gcc_jit_param *r2 =
261 gcc_jit_context_new_param (bottom_level->ctxt, NULL,
262 top_level->numeric_type_ptr, "r2");
263 gcc_jit_param *params[] = {a, b, c, r1, r2};
264 gcc_jit_function *test_quadratic =
265 gcc_jit_context_new_function (bottom_level->ctxt, NULL,
266 GCC_JIT_FUNCTION_EXPORTED,
267 top_level->int_type,
268 "test_quadratic",
269 5, params,
270 0);
271
272 /* struct quadratic q; */
273 gcc_jit_lvalue *q =
274 gcc_jit_function_new_local (
275 test_quadratic, NULL,
276 top_level->struct_quadratic,
277 "q");
278
279 gcc_jit_block *initial =
280 gcc_jit_function_new_block (test_quadratic,
281 "initial");
282 gcc_jit_block *on_positive_discriminant
283 = gcc_jit_function_new_block (test_quadratic,
284 "positive_discriminant");
285
286 gcc_jit_block *on_nonpositive_discriminant
287 = gcc_jit_function_new_block (test_quadratic,
288 "nonpositive_discriminant");
289
290 gcc_jit_block *on_zero_discriminant
291 = gcc_jit_function_new_block (test_quadratic,
292 "zero_discriminant");
293
294 gcc_jit_block *on_negative_discriminant
295 = gcc_jit_function_new_block (test_quadratic,
296 "negative_discriminant");
297
298 /* Initial block. */
299 /* q.a = a; */
300 gcc_jit_block_add_assignment (
301 initial, NULL,
302 gcc_jit_lvalue_access_field (q, NULL, top_level->a),
303 gcc_jit_param_as_rvalue (a));
304 /* q.b = b; */
305 gcc_jit_block_add_assignment (
306 initial, NULL,
307 gcc_jit_lvalue_access_field (q, NULL, top_level->b),
308 gcc_jit_param_as_rvalue (b));
309 /* q.c = c; */
310 gcc_jit_block_add_assignment (
311 initial, NULL,
312 gcc_jit_lvalue_access_field (q, NULL, top_level->c),
313 gcc_jit_param_as_rvalue (c));
314 /* calc_discriminant (&q); */
315 gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
316 gcc_jit_block_add_eval (
317 initial, NULL,
318 gcc_jit_context_new_call (
319 bottom_level->ctxt, NULL,
320 middle_level->calc_discriminant,
321 1, &address_of_q));
322
323 gcc_jit_block_add_comment (
324 initial, NULL,
325 "if (q.discriminant > 0)");
326 gcc_jit_block_end_with_conditional (
327 initial, NULL,
328 gcc_jit_context_new_comparison (
329 bottom_level->ctxt, NULL,
330 GCC_JIT_COMPARISON_GT,
331 gcc_jit_rvalue_access_field (
332 gcc_jit_lvalue_as_rvalue (q),
333 NULL,
334 top_level->discriminant),
335 top_level->zero),
336 on_positive_discriminant,
337 on_nonpositive_discriminant);
338
339 /* Block: "on_positive_discriminant" */
340 /* double s = sqrt (q.discriminant); */
341 gcc_jit_lvalue *s = gcc_jit_function_new_local (
342 test_quadratic, NULL,
343 top_level->numeric_type,
344 "s");
345 gcc_jit_rvalue *discriminant_of_q =
346 gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
347 NULL,
348 top_level->discriminant);
349 gcc_jit_block_add_assignment (
350 on_positive_discriminant, NULL,
351 s,
352 gcc_jit_context_new_call (
353 bottom_level->ctxt, NULL,
354 top_level->sqrt,
355 1, &discriminant_of_q));
356
357 gcc_jit_rvalue *minus_b =
358 gcc_jit_context_new_unary_op (
359 bottom_level->ctxt, NULL,
360 GCC_JIT_UNARY_OP_MINUS,
361 top_level->numeric_type,
362 gcc_jit_param_as_rvalue (b));
363 gcc_jit_rvalue *two_a =
364 gcc_jit_context_new_binary_op (
365 bottom_level->ctxt, NULL,
366 GCC_JIT_BINARY_OP_MULT,
367 top_level->numeric_type,
368 gcc_jit_context_new_rvalue_from_int (
369 bottom_level->ctxt,
370 top_level->numeric_type,
371 2),
372 gcc_jit_param_as_rvalue (a));
373
374 gcc_jit_block_add_comment (
375 on_positive_discriminant, NULL,
376 "*r1 = (-b + s) / (2 * a);");
377 gcc_jit_block_add_assignment (
378 on_positive_discriminant, NULL,
379
380 /* "*r1 = ..." */
381 gcc_jit_rvalue_dereference (
382 gcc_jit_param_as_rvalue (r1), NULL),
383
384 /* (-b + s) / (2 * a) */
385 gcc_jit_context_new_binary_op (
386 bottom_level->ctxt, NULL,
387 GCC_JIT_BINARY_OP_DIVIDE,
388 top_level->numeric_type,
389 gcc_jit_context_new_binary_op (
390 bottom_level->ctxt, NULL,
391 GCC_JIT_BINARY_OP_PLUS,
392 top_level->numeric_type,
393 minus_b,
394 gcc_jit_lvalue_as_rvalue (s)),
395 two_a));
396
397 gcc_jit_block_add_comment (
398 on_positive_discriminant, NULL,
399 "*r2 = (-b - s) / (2 * a)");
400 gcc_jit_block_add_assignment (
401 on_positive_discriminant, NULL,
402
403 /* "*r2 = ..." */
404 gcc_jit_rvalue_dereference (
405 gcc_jit_param_as_rvalue (r2), NULL),
406
407 /* (-b - s) / (2 * a) */
408 gcc_jit_context_new_binary_op (
409 bottom_level->ctxt, NULL,
410 GCC_JIT_BINARY_OP_DIVIDE,
411 top_level->numeric_type,
412 gcc_jit_context_new_binary_op (
413 bottom_level->ctxt, NULL,
414 GCC_JIT_BINARY_OP_MINUS,
415 top_level->numeric_type,
416 minus_b,
417 gcc_jit_lvalue_as_rvalue (s)),
418 two_a));
419
420 /* "return 2;" */
421 gcc_jit_block_end_with_return (
422 on_positive_discriminant, NULL,
423 gcc_jit_context_new_rvalue_from_int (
424 bottom_level->ctxt,
425 top_level->int_type,
426 2));
427
428 /* Block: "on_nonpositive_discriminant" */
429 gcc_jit_block_add_comment (
430 on_nonpositive_discriminant, NULL,
431 "else if (q.discriminant == 0)");
432 gcc_jit_block_end_with_conditional (
433 on_nonpositive_discriminant, NULL,
434 gcc_jit_context_new_comparison (
435 bottom_level->ctxt, NULL,
436 GCC_JIT_COMPARISON_EQ,
437 gcc_jit_rvalue_access_field (
438 gcc_jit_lvalue_as_rvalue (q),
439 NULL,
440 top_level->discriminant),
441 top_level->zero),
442 on_zero_discriminant,
443 on_negative_discriminant);
444
445 /* Block: "on_zero_discriminant" */
446 gcc_jit_block_add_comment (
447 on_zero_discriminant, NULL,
448 "*r1 = -b / (2 * a);");
449 gcc_jit_block_add_assignment (
450 on_zero_discriminant, NULL,
451
452 /* "*r1 = ..." */
453 gcc_jit_rvalue_dereference (
454 gcc_jit_param_as_rvalue (r1), NULL),
455
456 /* -b / (2 * a) */
457 gcc_jit_context_new_binary_op (
458 bottom_level->ctxt, NULL,
459 GCC_JIT_BINARY_OP_DIVIDE,
460 top_level->numeric_type,
461 minus_b,
462 two_a));
463
464 /* "return 1;" */
465 gcc_jit_block_end_with_return (
466 on_zero_discriminant, NULL,
467 gcc_jit_context_one (bottom_level->ctxt, top_level->int_type));
468
469 /* Block: "on_negative_discriminant" */
470 gcc_jit_block_end_with_return (
471 /* else return 0; */
472 on_negative_discriminant, NULL,
473 gcc_jit_context_zero (bottom_level->ctxt, top_level->int_type));
474 }
475
476 void
verify_middle_code(gcc_jit_context * ctxt,gcc_jit_result * result)477 verify_middle_code (gcc_jit_context *ctxt, gcc_jit_result *result)
478 {
479 struct quadratic q;
480
481 typedef void (*fn_type) (struct quadratic *q);
482 fn_type calc_discriminant =
483 (fn_type)gcc_jit_result_get_code (result,
484 "calc_discriminant");
485 CHECK_NON_NULL (calc_discriminant);
486
487 q.a = 3;
488 q.b = 5;
489 q.c = 7;
490 q.discriminant = 0;
491 calc_discriminant (&q);
492
493 CHECK_VALUE (q.discriminant, -59);
494 }
495
496 void
verify_bottom_code(gcc_jit_context * ctxt,gcc_jit_result * result)497 verify_bottom_code (gcc_jit_context *ctxt, gcc_jit_result *result)
498 {
499 typedef int (*fn_type) (double a, double b, double c,
500 double *r1, double *r2);
501
502 CHECK_NON_NULL (result);
503
504 fn_type test_quadratic =
505 (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
506 CHECK_NON_NULL (test_quadratic);
507
508 /* Verify that the code correctly solves quadratic equations. */
509 double r1, r2;
510
511 /* This one has two solutions: */
512 CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
513 CHECK_VALUE (r1, 1);
514 CHECK_VALUE (r2, -4);
515
516 /* This one has one solution: */
517 CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
518 CHECK_VALUE (r1, -0.5);
519
520 /* This one has no real solutions: */
521 CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
522 }
523
524 int
main(int argc,char ** argv)525 main (int argc, char **argv)
526 {
527 int i, j, k;
528 const int NUM_TOP_ITERATIONS = 2;
529 const int NUM_MIDDLE_ITERATIONS = 2;
530 const int NUM_BOTTOM_ITERATIONS = 2;
531
532 /* We do the whole thing multiple times to shake out state-management
533 issues in the underlying code. */
534
535 FILE *logfile = fopen ("test-nested-contexts.c.exe.log.txt", "w");
536 if (!logfile)
537 fail ("error opening logfile");
538
539 for (i = 1; i <= NUM_TOP_ITERATIONS; i++)
540 {
541 /* Create the top-level context. */
542 snprintf (test, sizeof (test),
543 "%s iteration %d of %d of top level",
544 extract_progname (argv[0]),
545 i, NUM_TOP_ITERATIONS);
546
547 struct top_level top_level;
548 memset (&top_level, 0, sizeof (top_level));
549
550 top_level.ctxt = gcc_jit_context_acquire ();
551 gcc_jit_context_set_logfile (top_level.ctxt,
552 logfile,
553 0, 0);
554 set_options (top_level.ctxt, argv[0]);
555
556 make_types (&top_level);
557 make_sqrt (&top_level);
558
559 /* No errors should have occurred. */
560 CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL);
561
562 gcc_jit_context_dump_to_file (top_level.ctxt,
563 "dump-of-test-nested-contexts-top.c",
564 1);
565
566 for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++)
567 {
568 /* Create and populate the middle-level context, using
569 objects from the top-level context. */
570 snprintf (test, sizeof (test),
571 ("%s iteration %d of %d of top level;"
572 " %d of %d of middle level"),
573 extract_progname (argv[0]),
574 i, NUM_TOP_ITERATIONS,
575 j, NUM_MIDDLE_ITERATIONS);
576
577 struct middle_level middle_level;
578 memset (&middle_level, 0, sizeof (middle_level));
579
580 middle_level.ctxt =
581 gcc_jit_context_new_child_context (top_level.ctxt);
582 make_calc_discriminant (&top_level,
583 &middle_level);
584
585 /* No errors should have occurred. */
586 CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt),
587 NULL);
588
589 gcc_jit_context_dump_to_file (middle_level.ctxt,
590 "dump-of-test-nested-contexts-middle.c",
591 1);
592
593 gcc_jit_result *middle_result =
594 gcc_jit_context_compile (middle_level.ctxt);
595 CHECK_NON_NULL (middle_result);
596
597 verify_middle_code (middle_level.ctxt, middle_result);
598
599 for (k = 1; k <= NUM_BOTTOM_ITERATIONS; k++)
600 {
601 /* Create and populate the innermost context, using
602 objects from the top-level and middle-level contexts. */
603 snprintf (test, sizeof (test),
604 ("%s iteration %d of %d of top level;"
605 " %d of %d of middle level;"
606 " %d of %d of bottom level"),
607 extract_progname (argv[0]),
608 i, NUM_TOP_ITERATIONS,
609 j, NUM_MIDDLE_ITERATIONS,
610 k, NUM_BOTTOM_ITERATIONS);
611
612 struct bottom_level bottom_level;
613 memset (&bottom_level, 0, sizeof (bottom_level));
614
615 bottom_level.ctxt =
616 gcc_jit_context_new_child_context (middle_level.ctxt);
617 make_test_quadratic (&top_level,
618 &middle_level,
619 &bottom_level);
620
621 /* No errors should have occurred. */
622 CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt),
623 NULL);
624
625 gcc_jit_context_dump_to_file (bottom_level.ctxt,
626 "dump-of-test-nested-contexts-bottom.c",
627 1);
628
629 /* Dump a reproducer for the bottom context.
630 The generated reproducer needs to also regenerate the
631 parent contexts, so this gives us test coverage for
632 that case. */
633 gcc_jit_context_dump_reproducer_to_file (
634 bottom_level.ctxt,
635 "test-nested-contexts.c.exe.reproducer.c");
636
637 gcc_jit_result *bottom_result =
638 gcc_jit_context_compile (bottom_level.ctxt);
639 verify_bottom_code (bottom_level.ctxt, bottom_result);
640 gcc_jit_result_release (bottom_result);
641 gcc_jit_context_release (bottom_level.ctxt);
642
643 }
644
645 gcc_jit_result_release (middle_result);
646 gcc_jit_context_release (middle_level.ctxt);
647
648 }
649
650 gcc_jit_context_release (top_level.ctxt);
651 }
652
653 if (logfile)
654 fclose (logfile);
655
656 totals ();
657
658 return 0;
659 }
660