123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- #include <stdlib.h>
- #include <stdio.h>
- #include "libgccjit.h"
- #include "harness.h"
- struct quadratic
- {
- double a;
- double b;
- double c;
- double discriminant;
- };
- /* Let's try to inject the equivalent of:
- extern double sqrt (double);
- static void
- calc_discriminant (struct quadratic *q)
- {
- // (b^2 - 4ac)
- q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
- }
- 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 quadratic_test
- {
- 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 *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 *calc_discriminant;
- gcc_jit_function *sqrt;
- };
- static void
- make_types (struct quadratic_test *testcase)
- {
- testcase->numeric_type =
- gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE);
- testcase->numeric_type_ptr =
- gcc_jit_type_get_pointer (testcase->numeric_type);
- testcase->zero =
- gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
- testcase->int_type =
- gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
- testcase->void_type =
- gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
- testcase->a =
- gcc_jit_context_new_field (testcase->ctxt,
- NULL,
- testcase->numeric_type,
- "a");
- testcase->b =
- gcc_jit_context_new_field (testcase->ctxt,
- NULL,
- testcase->numeric_type,
- "b");
- testcase->c =
- gcc_jit_context_new_field (testcase->ctxt,
- NULL,
- testcase->numeric_type,
- "c");
- testcase->discriminant =
- gcc_jit_context_new_field (testcase->ctxt,
- NULL,
- testcase->numeric_type,
- "discriminant");
- gcc_jit_field *fields[] = {testcase->a,
- testcase->b,
- testcase->c,
- testcase->discriminant};
- testcase->quadratic =
- gcc_jit_struct_as_type (
- gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
- "quadratic", 4, fields));
- testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
- }
- static void
- make_sqrt (struct quadratic_test *testcase)
- {
- gcc_jit_param *param_x =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->numeric_type, "x");
- testcase->sqrt =
- gcc_jit_context_new_function (testcase->ctxt, NULL,
- GCC_JIT_FUNCTION_IMPORTED,
- testcase->numeric_type,
- "sqrt",
- 1, ¶m_x,
- 0);
- }
- static void
- make_calc_discriminant (struct quadratic_test *testcase)
- {
- /* Build "calc_discriminant". */
- gcc_jit_param *param_q =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->quadratic_ptr, "q");
- testcase->calc_discriminant =
- gcc_jit_context_new_function (testcase->ctxt, NULL,
- GCC_JIT_FUNCTION_INTERNAL,
- testcase->void_type,
- "calc_discriminant",
- 1, ¶m_q,
- 0);
- gcc_jit_block *blk =
- gcc_jit_function_new_block (testcase->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, testcase->a));
- gcc_jit_rvalue *q_b =
- gcc_jit_lvalue_as_rvalue (
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL, testcase->b));
- gcc_jit_rvalue *q_c =
- gcc_jit_lvalue_as_rvalue (
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL, testcase->c));
- /* (q->b * q->b) - (4 * q->a * q->c) */
- gcc_jit_rvalue *rhs =
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_MINUS,
- testcase->numeric_type,
- /* (q->b * q->b) */
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- testcase->numeric_type,
- q_b, q_b),
- /* (4 * (q->a * q->c)) */
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- testcase->numeric_type,
- /* 4.0 */
- gcc_jit_context_new_rvalue_from_int (
- testcase->ctxt,
- testcase->numeric_type,
- 4),
- /* (q->a * q->c) */
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- testcase->numeric_type,
- q_a, q_c)));
- CHECK_STRING_VALUE (
- gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (rhs)),
- "q->b * q->b - (double)4 * q->a * q->c");
- gcc_jit_block_add_assignment (
- blk, NULL,
- /* q->discriminant =... */
- gcc_jit_rvalue_dereference_field (
- gcc_jit_param_as_rvalue (param_q),
- NULL,
- testcase->discriminant),
- rhs);
- gcc_jit_block_end_with_void_return (blk, NULL);
- }
- static void
- make_test_quadratic (struct quadratic_test *testcase)
- {
- gcc_jit_param *a =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->numeric_type, "a");
- gcc_jit_param *b =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->numeric_type, "b");
- gcc_jit_param *c =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->numeric_type, "c");
- gcc_jit_param *r1 =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->numeric_type_ptr, "r1");
- gcc_jit_param *r2 =
- gcc_jit_context_new_param (testcase->ctxt, NULL,
- testcase->numeric_type_ptr, "r2");
- gcc_jit_param *params[] = {a, b, c, r1, r2};
- gcc_jit_function *test_quadratic =
- gcc_jit_context_new_function (testcase->ctxt, NULL,
- GCC_JIT_FUNCTION_EXPORTED,
- testcase->int_type,
- "test_quadratic",
- 5, params,
- 0);
- /* struct quadratic q; */
- gcc_jit_lvalue *q =
- gcc_jit_function_new_local (
- test_quadratic, NULL,
- testcase->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, testcase->a),
- gcc_jit_param_as_rvalue (a));
- /* q.b = b; */
- gcc_jit_block_add_assignment (
- initial, NULL,
- gcc_jit_lvalue_access_field (q, NULL, testcase->b),
- gcc_jit_param_as_rvalue (b));
- /* q.c = c; */
- gcc_jit_block_add_assignment (
- initial, NULL,
- gcc_jit_lvalue_access_field (q, NULL, testcase->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 (
- testcase->ctxt, NULL,
- testcase->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 (
- testcase->ctxt, NULL,
- GCC_JIT_COMPARISON_GT,
- gcc_jit_rvalue_access_field (
- gcc_jit_lvalue_as_rvalue (q),
- NULL,
- testcase->discriminant),
- testcase->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,
- testcase->numeric_type,
- "s");
- gcc_jit_rvalue *discriminant_of_q =
- gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
- NULL,
- testcase->discriminant);
- gcc_jit_block_add_assignment (
- on_positive_discriminant, NULL,
- s,
- gcc_jit_context_new_call (
- testcase->ctxt, NULL,
- testcase->sqrt,
- 1, &discriminant_of_q));
- gcc_jit_rvalue *minus_b =
- gcc_jit_context_new_unary_op (
- testcase->ctxt, NULL,
- GCC_JIT_UNARY_OP_MINUS,
- testcase->numeric_type,
- gcc_jit_param_as_rvalue (b));
- gcc_jit_rvalue *two_a =
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_MULT,
- testcase->numeric_type,
- gcc_jit_context_new_rvalue_from_int (
- testcase->ctxt,
- testcase->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 (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_DIVIDE,
- testcase->numeric_type,
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_PLUS,
- testcase->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 (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_DIVIDE,
- testcase->numeric_type,
- gcc_jit_context_new_binary_op (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_MINUS,
- testcase->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 (
- testcase->ctxt,
- testcase->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 (
- testcase->ctxt, NULL,
- GCC_JIT_COMPARISON_EQ,
- gcc_jit_rvalue_access_field (
- gcc_jit_lvalue_as_rvalue (q),
- NULL,
- testcase->discriminant),
- testcase->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 (
- testcase->ctxt, NULL,
- GCC_JIT_BINARY_OP_DIVIDE,
- testcase->numeric_type,
- minus_b,
- two_a));
- gcc_jit_block_end_with_return (
- /* "return 1;" */
- on_zero_discriminant, NULL,
- gcc_jit_context_one (testcase->ctxt, testcase->int_type));
- /* Block: "on_negative_discriminant" */
- gcc_jit_block_end_with_return (
- /* "else return 0;" */
- on_negative_discriminant, NULL,
- gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
- }
- void
- create_code (gcc_jit_context *ctxt, void *user_data)
- {
- struct quadratic_test testcase;
- memset (&testcase, 0, sizeof (testcase));
- testcase.ctxt = ctxt;
- make_types (&testcase);
- make_sqrt (&testcase);
- make_calc_discriminant (&testcase);
- make_test_quadratic (&testcase);
- }
- void
- verify_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);
- }
|