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, &param_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, &param_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