123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- #include <stdlib.h>
- #include <stdio.h>
- #include "libgccjit.h"
- #define TEST_ESCHEWS_TEST_JIT
- #define TEST_PROVIDES_MAIN
- #include "harness.h"
- struct quadratic
- {
- double a;
- double b;
- double c;
- double discriminant;
- };
- /* This is an adapted version of test-quadratic.c
- Like that test, we'll try to inject the following code, but we'll
- split it up into some nested contexts, in 3 levels, to test
- how nested contexts work.
- ***** In top-level context: *****
- (shared type declarations, for int, double, struct quadratic);
- extern double sqrt (double);
- ***** In mid-level context: *****
- void
- calc_discriminant (struct quadratic *q)
- {
- // (b^2 - 4ac)
- q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
- }
- ***** In bottom context: *****
- int
- test_quadratic (double a, double b, double c, double *r1, double *r2)
- {
- struct quadratic q;
- q.a = a;
- q.b = b;
- q.c = c;
- calc_discriminant (&q);
- if (q.discriminant > 0)
- {
- double s = sqrt (q.discriminant);
- *r1 = (-b + s) / (2 * a);
- *r2 = (-b - s) / (2 * a);
- return 2;
- }
- else if (q.discriminant == 0)
- {
- *r1 = -b / (2 * a);
- return 1;
- }
- else return 0;
- }
- */
- struct top_level
- {
- gcc_jit_context *ctxt;
- /* "double" and "(double *)". */
- gcc_jit_type *numeric_type;
- gcc_jit_type *numeric_type_ptr;
- /* The value (double)0. */
- gcc_jit_rvalue *zero;
- gcc_jit_type *int_type;
- gcc_jit_type *void_type;
- /* "struct quadratic" */
- gcc_jit_type *struct_quadratic;
- gcc_jit_field *a;
- gcc_jit_field *b;
- gcc_jit_field *c;
- gcc_jit_field *discriminant;
- /* "(struct quadratic *)" */
- gcc_jit_type *quadratic_ptr;
- gcc_jit_function *sqrt;
- };
- struct middle_level
- {
- gcc_jit_context *ctxt;
- gcc_jit_function *calc_discriminant;
- };
- struct bottom_level
- {
- gcc_jit_context *ctxt;
- };
- static void
- make_types (struct top_level *top_level)
- {
- top_level->numeric_type =
- gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_DOUBLE);
- top_level->numeric_type_ptr =
- gcc_jit_type_get_pointer (top_level->numeric_type);
- top_level->zero =
- gcc_jit_context_zero (top_level->ctxt, top_level->numeric_type);
- top_level->int_type =
- gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_INT);
- top_level->void_type =
- gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_VOID);
- top_level->a =
- gcc_jit_context_new_field (top_level->ctxt,
- NULL,
- top_level->numeric_type,
- "a");
- top_level->b =
- gcc_jit_context_new_field (top_level->ctxt,
- NULL,
- top_level->numeric_type,
- "b");
- top_level->c =
- gcc_jit_context_new_field (top_level->ctxt,
- NULL,
- top_level->numeric_type,
- "c");
- top_level->discriminant =
- gcc_jit_context_new_field (top_level->ctxt,
- NULL,
- top_level->numeric_type,
- "discriminant");
- gcc_jit_field *fields[] = {top_level->a,
- top_level->b,
- top_level->c,
- top_level->discriminant};
- top_level->struct_quadratic =
- gcc_jit_struct_as_type (
- gcc_jit_context_new_struct_type (top_level->ctxt, NULL,
- "quadratic", 4, fields));
- top_level->quadratic_ptr =
- gcc_jit_type_get_pointer (top_level->struct_quadratic);
- }
- static void
- make_sqrt (struct top_level *top_level)
- {
- gcc_jit_param *param_x =
- gcc_jit_context_new_param (top_level->ctxt, NULL,
- top_level->numeric_type, "x");
- top_level->sqrt =
- gcc_jit_context_new_function (top_level->ctxt, NULL,
- GCC_JIT_FUNCTION_IMPORTED,
- top_level->numeric_type,
- "sqrt",
- 1, ¶m_x,
- 0);
- }
- static void
- make_calc_discriminant (struct top_level *top_level,
- struct middle_level *middle_level)
- {
- /* Build "calc_discriminant". */
- gcc_jit_param *param_q =
- gcc_jit_context_new_param (middle_level->ctxt, NULL,
- top_level->quadratic_ptr, "q");
- middle_level->calc_discriminant =
- gcc_jit_context_new_function (middle_level->ctxt, NULL,
- GCC_JIT_FUNCTION_EXPORTED,
- top_level->void_type,
- "calc_discriminant",
- 1, ¶m_q,
- 0);
- gcc_jit_block *blk =
- gcc_jit_function_new_block (middle_level->calc_discriminant, NULL);
- gcc_jit_block_add_comment (
- blk, NULL,
- "(b^2 - 4ac)");
- gcc_jit_rvalue *q_a =
- gcc_jit_lvalue_as_rvalue (
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL, top_level->a));
- gcc_jit_rvalue *q_b =
- gcc_jit_lvalue_as_rvalue (
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL, top_level->b));
- gcc_jit_rvalue *q_c =
- gcc_jit_lvalue_as_rvalue (
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL, top_level->c));
- gcc_jit_block_add_assignment (
- blk, NULL,
- /* q->discriminant =... */
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL,
- top_level->discriminant),
- /* (q->b * q->b) - (4 * q->a * q->c) */
- gcc_jit_context_new_binary_op (
- middle_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_MINUS,
- top_level->numeric_type,
- /* (q->b * q->b) */
- gcc_jit_context_new_binary_op (
- middle_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- top_level->numeric_type,
- q_b, q_b),
- /* (4 * (q->a * q->c)) */
- gcc_jit_context_new_binary_op (
- middle_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- top_level->numeric_type,
- /* 4.0 */
- gcc_jit_context_new_rvalue_from_int (
- middle_level->ctxt,
- top_level->numeric_type,
- 4),
- /* (q->a * q->c) */
- gcc_jit_context_new_binary_op (
- middle_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- top_level->numeric_type,
- q_a, q_c)))); /* end of gcc_jit_function_add_assignment call. */
- gcc_jit_block_end_with_void_return (blk, NULL);
- }
- static void
- make_test_quadratic (struct top_level *top_level,
- struct middle_level *middle_level,
- struct bottom_level *bottom_level)
- {
- gcc_jit_param *a =
- gcc_jit_context_new_param (bottom_level->ctxt, NULL,
- top_level->numeric_type, "a");
- gcc_jit_param *b =
- gcc_jit_context_new_param (bottom_level->ctxt, NULL,
- top_level->numeric_type, "b");
- gcc_jit_param *c =
- gcc_jit_context_new_param (bottom_level->ctxt, NULL,
- top_level->numeric_type, "c");
- gcc_jit_param *r1 =
- gcc_jit_context_new_param (bottom_level->ctxt, NULL,
- top_level->numeric_type_ptr, "r1");
- gcc_jit_param *r2 =
- gcc_jit_context_new_param (bottom_level->ctxt, NULL,
- top_level->numeric_type_ptr, "r2");
- gcc_jit_param *params[] = {a, b, c, r1, r2};
- gcc_jit_function *test_quadratic =
- gcc_jit_context_new_function (bottom_level->ctxt, NULL,
- GCC_JIT_FUNCTION_EXPORTED,
- top_level->int_type,
- "test_quadratic",
- 5, params,
- 0);
- /* struct quadratic q; */
- gcc_jit_lvalue *q =
- gcc_jit_function_new_local (
- test_quadratic, NULL,
- top_level->struct_quadratic,
- "q");
- gcc_jit_block *initial =
- gcc_jit_function_new_block (test_quadratic,
- "initial");
- gcc_jit_block *on_positive_discriminant
- = gcc_jit_function_new_block (test_quadratic,
- "positive_discriminant");
- gcc_jit_block *on_nonpositive_discriminant
- = gcc_jit_function_new_block (test_quadratic,
- "nonpositive_discriminant");
- gcc_jit_block *on_zero_discriminant
- = gcc_jit_function_new_block (test_quadratic,
- "zero_discriminant");
- gcc_jit_block *on_negative_discriminant
- = gcc_jit_function_new_block (test_quadratic,
- "negative_discriminant");
- /* Initial block. */
- /* q.a = a; */
- gcc_jit_block_add_assignment (
- initial, NULL,
- gcc_jit_lvalue_access_field (q, NULL, top_level->a),
- gcc_jit_param_as_rvalue (a));
- /* q.b = b; */
- gcc_jit_block_add_assignment (
- initial, NULL,
- gcc_jit_lvalue_access_field (q, NULL, top_level->b),
- gcc_jit_param_as_rvalue (b));
- /* q.c = c; */
- gcc_jit_block_add_assignment (
- initial, NULL,
- gcc_jit_lvalue_access_field (q, NULL, top_level->c),
- gcc_jit_param_as_rvalue (c));
- /* calc_discriminant (&q); */
- gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
- gcc_jit_block_add_eval (
- initial, NULL,
- gcc_jit_context_new_call (
- bottom_level->ctxt, NULL,
- middle_level->calc_discriminant,
- 1, &address_of_q));
- gcc_jit_block_add_comment (
- initial, NULL,
- "if (q.discriminant > 0)");
- gcc_jit_block_end_with_conditional (
- initial, NULL,
- gcc_jit_context_new_comparison (
- bottom_level->ctxt, NULL,
- GCC_JIT_COMPARISON_GT,
- gcc_jit_rvalue_access_field (
- gcc_jit_lvalue_as_rvalue (q),
- NULL,
- top_level->discriminant),
- top_level->zero),
- on_positive_discriminant,
- on_nonpositive_discriminant);
- /* Block: "on_positive_discriminant" */
- /* double s = sqrt (q.discriminant); */
- gcc_jit_lvalue *s = gcc_jit_function_new_local (
- test_quadratic, NULL,
- top_level->numeric_type,
- "s");
- gcc_jit_rvalue *discriminant_of_q =
- gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
- NULL,
- top_level->discriminant);
- gcc_jit_block_add_assignment (
- on_positive_discriminant, NULL,
- s,
- gcc_jit_context_new_call (
- bottom_level->ctxt, NULL,
- top_level->sqrt,
- 1, &discriminant_of_q));
- gcc_jit_rvalue *minus_b =
- gcc_jit_context_new_unary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_UNARY_OP_MINUS,
- top_level->numeric_type,
- gcc_jit_param_as_rvalue (b));
- gcc_jit_rvalue *two_a =
- gcc_jit_context_new_binary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- top_level->numeric_type,
- gcc_jit_context_new_rvalue_from_int (
- bottom_level->ctxt,
- top_level->numeric_type,
- 2),
- gcc_jit_param_as_rvalue (a));
- gcc_jit_block_add_comment (
- on_positive_discriminant, NULL,
- "*r1 = (-b + s) / (2 * a);");
- gcc_jit_block_add_assignment (
- on_positive_discriminant, NULL,
- /* "*r1 = ..." */
- gcc_jit_rvalue_dereference (
- gcc_jit_param_as_rvalue (r1), NULL),
- /* (-b + s) / (2 * a) */
- gcc_jit_context_new_binary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_DIVIDE,
- top_level->numeric_type,
- gcc_jit_context_new_binary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_PLUS,
- top_level->numeric_type,
- minus_b,
- gcc_jit_lvalue_as_rvalue (s)),
- two_a));
- gcc_jit_block_add_comment (
- on_positive_discriminant, NULL,
- "*r2 = (-b - s) / (2 * a)");
- gcc_jit_block_add_assignment (
- on_positive_discriminant, NULL,
- /* "*r2 = ..." */
- gcc_jit_rvalue_dereference (
- gcc_jit_param_as_rvalue (r2), NULL),
- /* (-b - s) / (2 * a) */
- gcc_jit_context_new_binary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_DIVIDE,
- top_level->numeric_type,
- gcc_jit_context_new_binary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_MINUS,
- top_level->numeric_type,
- minus_b,
- gcc_jit_lvalue_as_rvalue (s)),
- two_a));
- /* "return 2;" */
- gcc_jit_block_end_with_return (
- on_positive_discriminant, NULL,
- gcc_jit_context_new_rvalue_from_int (
- bottom_level->ctxt,
- top_level->int_type,
- 2));
- /* Block: "on_nonpositive_discriminant" */
- gcc_jit_block_add_comment (
- on_nonpositive_discriminant, NULL,
- "else if (q.discriminant == 0)");
- gcc_jit_block_end_with_conditional (
- on_nonpositive_discriminant, NULL,
- gcc_jit_context_new_comparison (
- bottom_level->ctxt, NULL,
- GCC_JIT_COMPARISON_EQ,
- gcc_jit_rvalue_access_field (
- gcc_jit_lvalue_as_rvalue (q),
- NULL,
- top_level->discriminant),
- top_level->zero),
- on_zero_discriminant,
- on_negative_discriminant);
- /* Block: "on_zero_discriminant" */
- gcc_jit_block_add_comment (
- on_zero_discriminant, NULL,
- "*r1 = -b / (2 * a);");
- gcc_jit_block_add_assignment (
- on_zero_discriminant, NULL,
- /* "*r1 = ..." */
- gcc_jit_rvalue_dereference (
- gcc_jit_param_as_rvalue (r1), NULL),
- /* -b / (2 * a) */
- gcc_jit_context_new_binary_op (
- bottom_level->ctxt, NULL,
- GCC_JIT_BINARY_OP_DIVIDE,
- top_level->numeric_type,
- minus_b,
- two_a));
- /* "return 1;" */
- gcc_jit_block_end_with_return (
- on_zero_discriminant, NULL,
- gcc_jit_context_one (bottom_level->ctxt, top_level->int_type));
- /* Block: "on_negative_discriminant" */
- gcc_jit_block_end_with_return (
- /* else return 0; */
- on_negative_discriminant, NULL,
- gcc_jit_context_zero (bottom_level->ctxt, top_level->int_type));
- }
- void
- verify_middle_code (gcc_jit_context *ctxt, gcc_jit_result *result)
- {
- struct quadratic q;
- typedef void (*fn_type) (struct quadratic *q);
- fn_type calc_discriminant =
- (fn_type)gcc_jit_result_get_code (result,
- "calc_discriminant");
- CHECK_NON_NULL (calc_discriminant);
- q.a = 3;
- q.b = 5;
- q.c = 7;
- q.discriminant = 0;
- calc_discriminant (&q);
- CHECK_VALUE (q.discriminant, -59);
- }
- void
- verify_bottom_code (gcc_jit_context *ctxt, gcc_jit_result *result)
- {
- typedef int (*fn_type) (double a, double b, double c,
- double *r1, double *r2);
- CHECK_NON_NULL (result);
- fn_type test_quadratic =
- (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
- CHECK_NON_NULL (test_quadratic);
- /* Verify that the code correctly solves quadratic equations. */
- double r1, r2;
- /* This one has two solutions: */
- CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
- CHECK_VALUE (r1, 1);
- CHECK_VALUE (r2, -4);
- /* This one has one solution: */
- CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
- CHECK_VALUE (r1, -0.5);
- /* This one has no real solutions: */
- CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
- }
- int
- main (int argc, char **argv)
- {
- int i, j, k;
- const int NUM_TOP_ITERATIONS = 2;
- const int NUM_MIDDLE_ITERATIONS = 2;
- const int NUM_BOTTOM_ITERATIONS = 2;
- /* We do the whole thing multiple times to shake out state-management
- issues in the underlying code. */
- FILE *logfile = fopen ("test-nested-contexts.c.exe.log.txt", "w");
- if (!logfile)
- fail ("error opening logfile");
- for (i = 1; i <= NUM_TOP_ITERATIONS; i++)
- {
- /* Create the top-level context. */
- snprintf (test, sizeof (test),
- "%s iteration %d of %d of top level",
- extract_progname (argv[0]),
- i, NUM_TOP_ITERATIONS);
- struct top_level top_level;
- memset (&top_level, 0, sizeof (top_level));
- top_level.ctxt = gcc_jit_context_acquire ();
- gcc_jit_context_set_logfile (top_level.ctxt,
- logfile,
- 0, 0);
- set_options (top_level.ctxt, argv[0]);
- make_types (&top_level);
- make_sqrt (&top_level);
- /* No errors should have occurred. */
- CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL);
- gcc_jit_context_dump_to_file (top_level.ctxt,
- "dump-of-test-nested-contexts-top.c",
- 1);
- for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++)
- {
- /* Create and populate the middle-level context, using
- objects from the top-level context. */
- snprintf (test, sizeof (test),
- ("%s iteration %d of %d of top level;"
- " %d of %d of middle level"),
- extract_progname (argv[0]),
- i, NUM_TOP_ITERATIONS,
- j, NUM_MIDDLE_ITERATIONS);
- struct middle_level middle_level;
- memset (&middle_level, 0, sizeof (middle_level));
- middle_level.ctxt =
- gcc_jit_context_new_child_context (top_level.ctxt);
- make_calc_discriminant (&top_level,
- &middle_level);
- /* No errors should have occurred. */
- CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt),
- NULL);
- gcc_jit_context_dump_to_file (middle_level.ctxt,
- "dump-of-test-nested-contexts-middle.c",
- 1);
- gcc_jit_result *middle_result =
- gcc_jit_context_compile (middle_level.ctxt);
- CHECK_NON_NULL (middle_result);
- verify_middle_code (middle_level.ctxt, middle_result);
- for (k = 1; k <= NUM_BOTTOM_ITERATIONS; k++)
- {
- /* Create and populate the innermost context, using
- objects from the top-level and middle-level contexts. */
- snprintf (test, sizeof (test),
- ("%s iteration %d of %d of top level;"
- " %d of %d of middle level;"
- " %d of %d of bottom level"),
- extract_progname (argv[0]),
- i, NUM_TOP_ITERATIONS,
- j, NUM_MIDDLE_ITERATIONS,
- k, NUM_BOTTOM_ITERATIONS);
- struct bottom_level bottom_level;
- memset (&bottom_level, 0, sizeof (bottom_level));
- bottom_level.ctxt =
- gcc_jit_context_new_child_context (middle_level.ctxt);
- make_test_quadratic (&top_level,
- &middle_level,
- &bottom_level);
- /* No errors should have occurred. */
- CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt),
- NULL);
- gcc_jit_context_dump_to_file (bottom_level.ctxt,
- "dump-of-test-nested-contexts-bottom.c",
- 1);
- /* Dump a reproducer for the bottom context.
- The generated reproducer needs to also regenerate the
- parent contexts, so this gives us test coverage for
- that case. */
- gcc_jit_context_dump_reproducer_to_file (
- bottom_level.ctxt,
- "test-nested-contexts.c.exe.reproducer.c");
- gcc_jit_result *bottom_result =
- gcc_jit_context_compile (bottom_level.ctxt);
- verify_bottom_code (bottom_level.ctxt, bottom_result);
- gcc_jit_result_release (bottom_result);
- gcc_jit_context_release (bottom_level.ctxt);
- }
- gcc_jit_result_release (middle_result);
- gcc_jit_context_release (middle_level.ctxt);
- }
- gcc_jit_context_release (top_level.ctxt);
- }
- if (logfile)
- fclose (logfile);
- totals ();
- return 0;
- }
|