123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /* Test of C++ API. */
- #include <stdlib.h>
- #include <stdio.h>
- #include "libgccjit++.h"
- #include <sstream>
- #include "harness.h"
- struct quadratic
- {
- double a;
- double b;
- double c;
- double discriminant;
- };
- /* As per test-quadratic.cc, let's try to inject the equivalent of:
- extern double sqrt (double);
- 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;
- }
- However, we'll use operator overloading for maxium brevity, at the
- risk of perhaps being too "magical".
- */
- /****************************************************************************
- Test case
- ****************************************************************************/
- struct quadratic_test
- {
- gccjit::context ctxt;
- /* "double" and "(double *)". */
- gccjit::type numeric_type;
- gccjit::type numeric_type_ptr;
- /* The value (double)0. */
- gccjit::rvalue zero;
- gccjit::type int_type;
- gccjit::type void_type;
- /* "struct quadratic" */
- gccjit::type quadratic;
- gccjit::field a;
- gccjit::field b;
- gccjit::field c;
- gccjit::field discriminant;
- /* "(struct quadratic *)" */
- gccjit::type quadratic_ptr;
- gccjit::function calc_discriminant;
- gccjit::function sqrt;
- };
- static void
- make_types (quadratic_test &testcase)
- {
- testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
- testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
- testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
- testcase.int_type = testcase.ctxt.get_int_type <int> ();
- testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID);
- testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
- testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
- testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
- testcase.discriminant =
- testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
- CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
- "discriminant");
- std::vector<gccjit::field> fields (4);
- fields[0] = testcase.a;
- fields[1] = testcase.b;
- fields[2] = testcase.c;
- fields[3] = testcase.discriminant;
- testcase.quadratic =
- testcase.ctxt.new_struct_type (
- "quadratic",
- fields);
- testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
- }
- static void
- make_sqrt (quadratic_test &testcase)
- {
- std::vector<gccjit::param> params (1);
- params[0] =
- testcase.ctxt.new_param (testcase.numeric_type, "x");
- testcase.sqrt =
- testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
- testcase.numeric_type,
- "sqrt",
- params,
- 0);
- }
- static void
- make_calc_discriminant (quadratic_test &testcase)
- {
- /* Build "calc_discriminant". */
- gccjit::param param_q =
- testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
- std::vector <gccjit::param> params (1);
- params[0] = param_q;
- testcase.calc_discriminant =
- testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
- testcase.void_type,
- "calc_discriminant",
- params,
- 0);
- gccjit::block block = testcase.calc_discriminant.new_block ();
- block.add_comment ("(b^2 - 4ac)");
- gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
- gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
- gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
- gccjit::rvalue four =
- testcase.ctxt.new_rvalue (testcase.numeric_type, 4);
- block.add_assignment (
- /* q->discriminant =... */
- param_q.dereference_field (testcase.discriminant),
- /* (q->b * q->b) - (4 * q->a * q->c) */
- (q_b * q_b) - (four * q_a * q_c));
- block.end_with_return ();
- }
- static void
- make_test_quadratic (quadratic_test &testcase)
- {
- gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
- gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
- gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
- gccjit::param r1 =
- testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
- gccjit::param r2 =
- testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
- std::vector<gccjit::param> params (5);
- params[0] = a;
- params[1] = b;
- params[2] = c;
- params[3] = r1;
- params[4] = r2;
- gccjit::function test_quadratic =
- testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
- testcase.int_type,
- "test_quadratic",
- params,
- 0);
- /* struct quadratic q; */
- gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
- gccjit::block initial = test_quadratic.new_block ("initial");
- gccjit::block on_positive_discriminant
- = test_quadratic.new_block ("positive_discriminant");
- gccjit::block on_nonpositive_discriminant
- = test_quadratic.new_block ("nonpositive_discriminant");
- gccjit::block on_zero_discriminant
- = test_quadratic.new_block ("zero_discriminant");
- gccjit::block on_negative_discriminant
- = test_quadratic.new_block ("negative_discriminant");
- CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
- "zero_discriminant");
- /* q.a = a; */
- initial.add_assignment (q.access_field (testcase.a), a);
- /* q.b = b; */
- initial.add_assignment (q.access_field (testcase.b), b);
- /* q.c = c; */
- initial.add_assignment (q.access_field (testcase.c), c);
- /* calc_discriminant (&q); */
- gccjit::rvalue address_of_q = q.get_address ();
- initial.add_eval (testcase.calc_discriminant (address_of_q));
- initial.add_comment ("if (q.discriminant > 0)");
- initial.end_with_conditional (
- q.access_field (testcase.discriminant) > testcase.zero,
- on_positive_discriminant,
- on_nonpositive_discriminant);
- /* Block: "on_positive_discriminant" */
- /* double s = sqrt (q.discriminant); */
- gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
- gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
- on_positive_discriminant.add_assignment (s, testcase.sqrt (discriminant_of_q));
- gccjit::rvalue minus_b = -b;
- gccjit::rvalue two =
- testcase.ctxt.new_rvalue (testcase.numeric_type, 2);
- gccjit::rvalue two_a = two * a;
- CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
- "(double)2 * a");
- on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);");
- on_positive_discriminant.add_assignment (*r1, (minus_b + s) / two_a);
- on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)");
- on_positive_discriminant.add_assignment (*r2, (minus_b - s) / two_a);
- /* "return 2;" */
- on_positive_discriminant.end_with_return (
- testcase.ctxt.new_rvalue (testcase.int_type, 2));
- /* Block: "on_nonpositive_discriminant" */
- /* "else if (q.discriminant == 0)" */
- on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)");
- on_nonpositive_discriminant.end_with_conditional (
- q.access_field (testcase.discriminant) == testcase.zero,
- on_zero_discriminant,
- on_negative_discriminant);
- /* Block: "on_zero_discriminant" */
- /* if (q.discriminant == 0) */
- on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);");
- on_zero_discriminant.add_assignment (*r1, minus_b / two_a);
- /* "return 1;" */
- on_zero_discriminant.end_with_return (testcase.int_type.one ());
- /* Block: "on_negative_discriminant" */
- /* else return 0; */
- on_negative_discriminant.end_with_return (testcase.int_type.zero ());
- /* Verify that output stream operator << works. */
- std::ostringstream os;
- os << "streamed output: " << address_of_q;
- CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
- }
- 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);
- }
|