6 #define TEST_ESCHEWS_TEST_JIT
7 #define TEST_PROVIDES_MAIN
18 /* This is an adapted version of test-quadratic.c
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.
24 ***** In top-level context: *****
26 (shared type declarations, for int, double, struct quadratic);
27 extern double sqrt (double);
29 ***** In mid-level context: *****
32 calc_discriminant (struct quadratic *q)
35 q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
38 ***** In bottom context: *****
41 test_quadratic (double a, double b, double c, double *r1, double *r2)
47 calc_discriminant (&q);
48 if (q.discriminant > 0)
50 double s = sqrt (q.discriminant);
51 *r1 = (-b + s) / (2 * a);
52 *r2 = (-b - s) / (2 * a);
55 else if (q.discriminant == 0)
66 gcc_jit_context
*ctxt
;
68 /* "double" and "(double *)". */
69 gcc_jit_type
*numeric_type
;
70 gcc_jit_type
*numeric_type_ptr
;
72 /* The value (double)0. */
75 gcc_jit_type
*int_type
;
76 gcc_jit_type
*void_type
;
78 /* "struct quadratic" */
79 gcc_jit_type
*struct_quadratic
;
83 gcc_jit_field
*discriminant
;
85 /* "(struct quadratic *)" */
86 gcc_jit_type
*quadratic_ptr
;
88 gcc_jit_function
*sqrt
;
93 gcc_jit_context
*ctxt
;
94 gcc_jit_function
*calc_discriminant
;
99 gcc_jit_context
*ctxt
;
103 make_types (struct top_level
*top_level
)
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
);
110 gcc_jit_context_zero (top_level
->ctxt
, top_level
->numeric_type
);
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
);
118 gcc_jit_context_new_field (top_level
->ctxt
,
120 top_level
->numeric_type
,
123 gcc_jit_context_new_field (top_level
->ctxt
,
125 top_level
->numeric_type
,
128 gcc_jit_context_new_field (top_level
->ctxt
,
130 top_level
->numeric_type
,
132 top_level
->discriminant
=
133 gcc_jit_context_new_field (top_level
->ctxt
,
135 top_level
->numeric_type
,
137 gcc_jit_field
*fields
[] = {top_level
->a
,
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
);
150 make_sqrt (struct top_level
*top_level
)
152 gcc_jit_param
*param_x
=
153 gcc_jit_context_new_param (top_level
->ctxt
, NULL
,
154 top_level
->numeric_type
, "x");
156 gcc_jit_context_new_function (top_level
->ctxt
, NULL
,
157 GCC_JIT_FUNCTION_IMPORTED
,
158 top_level
->numeric_type
,
165 make_calc_discriminant (struct top_level
*top_level
,
166 struct middle_level
*middle_level
)
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
,
180 gcc_jit_function_new_block (middle_level
->calc_discriminant
, NULL
);
181 gcc_jit_block_add_comment (
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
));
201 gcc_jit_block_add_assignment (
204 /* q->discriminant =... */
205 gcc_jit_rvalue_dereference_field (
206 gcc_jit_param_as_rvalue (param_q
),
208 top_level
->discriminant
),
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
,
217 gcc_jit_context_new_binary_op (
218 middle_level
->ctxt
, NULL
,
219 GCC_JIT_BINARY_OP_MULT
,
220 top_level
->numeric_type
,
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
,
229 gcc_jit_context_new_rvalue_from_int (
231 top_level
->numeric_type
,
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. */
240 gcc_jit_block_end_with_void_return (blk
, NULL
);
244 make_test_quadratic (struct top_level
*top_level
,
245 struct middle_level
*middle_level
,
246 struct bottom_level
*bottom_level
)
249 gcc_jit_context_new_param (bottom_level
->ctxt
, NULL
,
250 top_level
->numeric_type
, "a");
252 gcc_jit_context_new_param (bottom_level
->ctxt
, NULL
,
253 top_level
->numeric_type
, "b");
255 gcc_jit_context_new_param (bottom_level
->ctxt
, NULL
,
256 top_level
->numeric_type
, "c");
258 gcc_jit_context_new_param (bottom_level
->ctxt
, NULL
,
259 top_level
->numeric_type_ptr
, "r1");
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
,
272 /* struct quadratic q; */
274 gcc_jit_function_new_local (
275 test_quadratic
, NULL
,
276 top_level
->struct_quadratic
,
279 gcc_jit_block
*initial
=
280 gcc_jit_function_new_block (test_quadratic
,
282 gcc_jit_block
*on_positive_discriminant
283 = gcc_jit_function_new_block (test_quadratic
,
284 "positive_discriminant");
286 gcc_jit_block
*on_nonpositive_discriminant
287 = gcc_jit_function_new_block (test_quadratic
,
288 "nonpositive_discriminant");
290 gcc_jit_block
*on_zero_discriminant
291 = gcc_jit_function_new_block (test_quadratic
,
292 "zero_discriminant");
294 gcc_jit_block
*on_negative_discriminant
295 = gcc_jit_function_new_block (test_quadratic
,
296 "negative_discriminant");
300 gcc_jit_block_add_assignment (
302 gcc_jit_lvalue_access_field (q
, NULL
, top_level
->a
),
303 gcc_jit_param_as_rvalue (a
));
305 gcc_jit_block_add_assignment (
307 gcc_jit_lvalue_access_field (q
, NULL
, top_level
->b
),
308 gcc_jit_param_as_rvalue (b
));
310 gcc_jit_block_add_assignment (
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 (
318 gcc_jit_context_new_call (
319 bottom_level
->ctxt
, NULL
,
320 middle_level
->calc_discriminant
,
323 gcc_jit_block_add_comment (
325 "if (q.discriminant > 0)");
326 gcc_jit_block_end_with_conditional (
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
),
334 top_level
->discriminant
),
336 on_positive_discriminant
,
337 on_nonpositive_discriminant
);
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
,
345 gcc_jit_rvalue
*discriminant_of_q
=
346 gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q
),
348 top_level
->discriminant
);
349 gcc_jit_block_add_assignment (
350 on_positive_discriminant
, NULL
,
352 gcc_jit_context_new_call (
353 bottom_level
->ctxt
, NULL
,
355 1, &discriminant_of_q
));
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 (
370 top_level
->numeric_type
,
372 gcc_jit_param_as_rvalue (a
));
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
,
381 gcc_jit_rvalue_dereference (
382 gcc_jit_param_as_rvalue (r1
), NULL
),
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
,
394 gcc_jit_lvalue_as_rvalue (s
)),
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
,
404 gcc_jit_rvalue_dereference (
405 gcc_jit_param_as_rvalue (r2
), NULL
),
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
,
417 gcc_jit_lvalue_as_rvalue (s
)),
421 gcc_jit_block_end_with_return (
422 on_positive_discriminant
, NULL
,
423 gcc_jit_context_new_rvalue_from_int (
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
),
440 top_level
->discriminant
),
442 on_zero_discriminant
,
443 on_negative_discriminant
);
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
,
453 gcc_jit_rvalue_dereference (
454 gcc_jit_param_as_rvalue (r1
), NULL
),
457 gcc_jit_context_new_binary_op (
458 bottom_level
->ctxt
, NULL
,
459 GCC_JIT_BINARY_OP_DIVIDE
,
460 top_level
->numeric_type
,
465 gcc_jit_block_end_with_return (
466 on_zero_discriminant
, NULL
,
467 gcc_jit_context_one (bottom_level
->ctxt
, top_level
->int_type
));
469 /* Block: "on_negative_discriminant" */
470 gcc_jit_block_end_with_return (
472 on_negative_discriminant
, NULL
,
473 gcc_jit_context_zero (bottom_level
->ctxt
, top_level
->int_type
));
477 verify_middle_code (gcc_jit_context
*ctxt
, gcc_jit_result
*result
)
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
);
491 calc_discriminant (&q
);
493 CHECK_VALUE (q
.discriminant
, -59);
497 verify_bottom_code (gcc_jit_context
*ctxt
, gcc_jit_result
*result
)
499 typedef int (*fn_type
) (double a
, double b
, double c
,
500 double *r1
, double *r2
);
502 CHECK_NON_NULL (result
);
504 fn_type test_quadratic
=
505 (fn_type
)gcc_jit_result_get_code (result
, "test_quadratic");
506 CHECK_NON_NULL (test_quadratic
);
508 /* Verify that the code correctly solves quadratic equations. */
511 /* This one has two solutions: */
512 CHECK_VALUE (test_quadratic (1, 3, -4, &r1
, &r2
), 2);
514 CHECK_VALUE (r2
, -4);
516 /* This one has one solution: */
517 CHECK_VALUE (test_quadratic (4, 4, 1, &r1
, &r2
), 1);
518 CHECK_VALUE (r1
, -0.5);
520 /* This one has no real solutions: */
521 CHECK_VALUE (test_quadratic (4, 1, 1, &r1
, &r2
), 0);
525 main (int argc
, char **argv
)
528 const int NUM_TOP_ITERATIONS
= 2;
529 const int NUM_MIDDLE_ITERATIONS
= 2;
530 const int NUM_BOTTOM_ITERATIONS
= 2;
532 /* We do the whole thing multiple times to shake out state-management
533 issues in the underlying code. */
535 FILE *logfile
= fopen ("test-nested-contexts.c.exe.log.txt", "w");
537 fail ("error opening logfile");
539 for (i
= 1; i
<= NUM_TOP_ITERATIONS
; i
++)
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
);
547 struct top_level top_level
;
548 memset (&top_level
, 0, sizeof (top_level
));
550 top_level
.ctxt
= gcc_jit_context_acquire ();
551 gcc_jit_context_set_logfile (top_level
.ctxt
,
554 set_options (top_level
.ctxt
, argv
[0]);
556 make_types (&top_level
);
557 make_sqrt (&top_level
);
559 /* No errors should have occurred. */
560 CHECK_VALUE (gcc_jit_context_get_first_error (top_level
.ctxt
), NULL
);
562 gcc_jit_context_dump_to_file (top_level
.ctxt
,
563 "dump-of-test-nested-contexts-top.c",
566 for (j
= 1; j
<= NUM_MIDDLE_ITERATIONS
; j
++)
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
);
577 struct middle_level middle_level
;
578 memset (&middle_level
, 0, sizeof (middle_level
));
581 gcc_jit_context_new_child_context (top_level
.ctxt
);
582 make_calc_discriminant (&top_level
,
585 /* No errors should have occurred. */
586 CHECK_VALUE (gcc_jit_context_get_first_error (middle_level
.ctxt
),
589 gcc_jit_context_dump_to_file (middle_level
.ctxt
,
590 "dump-of-test-nested-contexts-middle.c",
593 gcc_jit_result
*middle_result
=
594 gcc_jit_context_compile (middle_level
.ctxt
);
595 CHECK_NON_NULL (middle_result
);
597 verify_middle_code (middle_level
.ctxt
, middle_result
);
599 for (k
= 1; k
<= NUM_BOTTOM_ITERATIONS
; k
++)
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
);
612 struct bottom_level bottom_level
;
613 memset (&bottom_level
, 0, sizeof (bottom_level
));
616 gcc_jit_context_new_child_context (middle_level
.ctxt
);
617 make_test_quadratic (&top_level
,
621 /* No errors should have occurred. */
622 CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level
.ctxt
),
625 gcc_jit_context_dump_to_file (bottom_level
.ctxt
,
626 "dump-of-test-nested-contexts-bottom.c",
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
633 gcc_jit_context_dump_reproducer_to_file (
635 "test-nested-contexts.c.exe.reproducer.c");
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
);
645 gcc_jit_result_release (middle_result
);
646 gcc_jit_context_release (middle_level
.ctxt
);
650 gcc_jit_context_release (top_level
.ctxt
);