| /* 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.c, 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 the C++ bindings. |
| */ |
| |
| /**************************************************************************** |
| 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); |
| |
| block.add_assignment ( |
| /* q->discriminant =... */ |
| param_q.dereference_field (testcase.discriminant), |
| /* (q->b * q->b) - (4 * q->a * q->c) */ |
| testcase.ctxt.new_minus ( |
| testcase.numeric_type, |
| |
| /* (q->b * q->b) */ |
| testcase.ctxt.new_mult ( |
| testcase.numeric_type, |
| q_b, q_b), |
| |
| /* (4 * (q->a * q->c)) */ |
| testcase.ctxt.new_mult ( |
| testcase.numeric_type, |
| /* 4.0 */ |
| testcase.ctxt.new_rvalue ( |
| testcase.numeric_type, |
| 4), |
| /* (q->a * q->c) */ |
| testcase.ctxt.new_mult ( |
| testcase.numeric_type, |
| q_a, q_c)))); /* end of add_assignment call. */ |
| 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_call (testcase.calc_discriminant, address_of_q); |
| |
| initial.add_comment ("if (q.discriminant > 0)"); |
| initial.end_with_conditional ( |
| testcase.ctxt.new_gt ( |
| 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.ctxt.new_call (testcase.sqrt, discriminant_of_q)); |
| |
| gccjit::rvalue minus_b = |
| testcase.ctxt.new_minus ( |
| testcase.numeric_type, |
| b); |
| gccjit::rvalue two_a = |
| testcase.ctxt.new_mult ( |
| testcase.numeric_type, |
| testcase.ctxt.new_rvalue (testcase.numeric_type, 2), |
| 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 = ..." */ |
| r1.dereference (), |
| |
| /* (-b + s) / (2 * a) */ |
| testcase.ctxt.new_divide ( |
| testcase.numeric_type, |
| testcase.ctxt.new_plus ( |
| testcase.numeric_type, |
| minus_b, |
| s), |
| two_a)); |
| |
| on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)"); |
| on_positive_discriminant.add_assignment ( |
| /* "*r2 = ..." */ |
| r2.dereference (), |
| |
| /* (-b - s) / (2 * a) */ |
| testcase.ctxt.new_divide ( |
| testcase.numeric_type, |
| testcase.ctxt.new_minus ( |
| testcase.numeric_type, |
| 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" */ |
| on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)"); |
| on_nonpositive_discriminant.end_with_conditional ( |
| testcase.ctxt.new_eq ( |
| 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 = ..." */ |
| r1.dereference (), |
| |
| /* -b / (2 * a) */ |
| testcase.ctxt.new_divide ( |
| testcase.numeric_type, |
| minus_b, |
| two_a)); |
| |
| /* "return 1;" */ |
| on_zero_discriminant.end_with_return ( |
| testcase.ctxt.one (testcase.int_type)); |
| |
| /* Block: "on_negative_discriminant" */ |
| /* else return 0; */ |
| on_negative_discriminant.end_with_return ( |
| testcase.ctxt.zero (testcase.int_type)); |
| |
| /* 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 = {}; |
| 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); |
| } |