Committed to branch dmalcolm/jit: gcc/jit/ * libgccjit++.h (gccjit::object::get_context): New method. (gccjit::function): Add overloaded operator () for various numbers of arguments as a very terse way of creating function calls. (gccjit::rvalue::get_type): New method.
(operator-): New overloaded unary op for rvalues. (operator~): Likewise. (operator!): Likewise. (operator+): New overloaded binary op for rvalues. (operator-): Likewise. (operator*): Likewise. (operator/): Likewise. (operator%): Likewise. (operator&): Likewise. (operator^): Likewise. (operator|): Likewise. (operator&&): Likewise. (operator||): Likewise. (operator==): New overloaded comparison for rvalues. (operator!=): Likewise. (operator<): Likewise. (operator<=): Likewise. (operator>): Likewise. (operator>=): Likewise. (operator*): New overloaded operator for dereferencing an rvalue representing a pointer. * libgccjit.c (gcc_jit_rvalue_get_type): New. * libgccjit.h (gcc_jit_rvalue_get_type): New. * libgccjit.map (gcc_jit_rvalue_get_type): New. gcc/testsuite/ * jit.dg/test-operator-overloading.cc: New testcase, a rewrite of test-quadratic.cc to use operator overloading. --- gcc/jit/ChangeLog.jit | 36 +++ gcc/jit/libgccjit++.h | 173 ++++++++++++ gcc/jit/libgccjit.c | 8 + gcc/jit/libgccjit.h | 3 + gcc/jit/libgccjit.map | 1 + gcc/testsuite/ChangeLog.jit | 5 + gcc/testsuite/jit.dg/test-operator-overloading.cc | 306 ++++++++++++++++++++++ 7 files changed, 532 insertions(+) create mode 100644 gcc/testsuite/jit.dg/test-operator-overloading.cc diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit index bd209ed..9b44728 100644 --- a/gcc/jit/ChangeLog.jit +++ b/gcc/jit/ChangeLog.jit @@ -1,5 +1,41 @@ 2014-02-10 David Malcolm <dmalc...@redhat.com> + * libgccjit++.h (gccjit::object::get_context): New method. + (gccjit::function): Add overloaded operator () for various + numbers of arguments as a very terse way of creating function calls. + (gccjit::rvalue::get_type): New method. + + (operator-): New overloaded unary op for rvalues. + (operator~): Likewise. + (operator!): Likewise. + + (operator+): New overloaded binary op for rvalues. + (operator-): Likewise. + (operator*): Likewise. + (operator/): Likewise. + (operator%): Likewise. + (operator&): Likewise. + (operator^): Likewise. + (operator|): Likewise. + (operator&&): Likewise. + (operator||): Likewise. + + (operator==): New overloaded comparison for rvalues. + (operator!=): Likewise. + (operator<): Likewise. + (operator<=): Likewise. + (operator>): Likewise. + (operator>=): Likewise. + + (operator*): New overloaded operator for dereferencing an + rvalue representing a pointer. + + * libgccjit.c (gcc_jit_rvalue_get_type): New. + * libgccjit.h (gcc_jit_rvalue_get_type): New. + * libgccjit.map (gcc_jit_rvalue_get_type): New. + +2014-02-10 David Malcolm <dmalc...@redhat.com> + * libgccjit++.h (gccjit::context::new_minus): New method, providing a way to do a specific unary op with less typing. (gccjit::context::new_bitwise_negate): Likewise. diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index ff22d1e..fab1a74 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -27,6 +27,8 @@ namespace gccjit class object { public: + context get_context () const; + std::string get_debug_string () const; protected: @@ -296,6 +298,16 @@ namespace gccjit void add_return (rvalue rvalue, location loc = location ()); + + /* A series of overloaded operator () with various numbers of arguments + for a very terse way of creating a call to this function. The call + is created within the same context as the function itself, which may + not be what you want. */ + rvalue operator() (location loc = location ()); + rvalue operator() (rvalue arg0, + location loc = location ()); + rvalue operator() (rvalue arg0, rvalue arg1, + location loc = location ()); }; class label : public object @@ -314,6 +326,8 @@ namespace gccjit rvalue (gcc_jit_rvalue *inner); gcc_jit_rvalue *get_inner_rvalue (); + type get_type (); + rvalue access_field (field field, location loc = location ()); @@ -345,6 +359,42 @@ namespace gccjit gcc_jit_param *get_inner_param (); }; + + + /* Overloaded operators, for those who want the most terse API + (at the possible risk of being a little too magical). + + In each case, the first parameter is used to determine which context + owns the resulting expression, and, where appropriate, what the + latter's type is. */ + + /* Unary operators. */ + rvalue operator- (rvalue a); // unary minus + rvalue operator~ (rvalue a); // unary bitwise negate + rvalue operator! (rvalue a); // unary logical negate + + /* Binary operators. */ + rvalue operator+ (rvalue a, rvalue b); + rvalue operator- (rvalue a, rvalue b); + rvalue operator* (rvalue a, rvalue b); + rvalue operator/ (rvalue a, rvalue b); + rvalue operator% (rvalue a, rvalue b); + rvalue operator& (rvalue a, rvalue b); // bitwise and + rvalue operator^ (rvalue a, rvalue b); // bitwise_xor + rvalue operator| (rvalue a, rvalue b); // bitwise_or + rvalue operator&& (rvalue a, rvalue b); // logical_and + rvalue operator|| (rvalue a, rvalue b); // logical_or + + /* Comparisons. */ + rvalue operator== (rvalue a, rvalue b); + rvalue operator!= (rvalue a, rvalue b); + rvalue operator< (rvalue a, rvalue b); + rvalue operator<= (rvalue a, rvalue b); + rvalue operator> (rvalue a, rvalue b); + rvalue operator>= (rvalue a, rvalue b); + + /* Dereferencing. */ + lvalue operator* (rvalue ptr); } /**************************************************************************** @@ -835,6 +885,12 @@ context::new_array_access (rvalue ptr, } // class object +inline context +object::get_context () const +{ + return context (gcc_jit_object_get_context (m_inner_obj)); +} + inline std::string object::get_debug_string () const { @@ -1038,6 +1094,28 @@ function::add_return (rvalue rvalue, rvalue.get_inner_rvalue ()); } +inline rvalue +function::operator() (location loc) +{ + return get_context ().new_call (*this, loc); +} +inline rvalue +function::operator() (rvalue arg0, + location loc) +{ + return get_context ().new_call (*this, + arg0, + loc); +} +inline rvalue +function::operator() (rvalue arg0, rvalue arg1, + location loc) +{ + return get_context ().new_call (*this, + arg0, arg1, + loc); +} + // class label inline label::label () : object (NULL) {} inline label::label (gcc_jit_label *inner) @@ -1064,6 +1142,12 @@ rvalue::get_inner_rvalue () return reinterpret_cast<gcc_jit_rvalue *> (get_inner_object ()); } +inline type +rvalue::get_type () +{ + return type (gcc_jit_rvalue_get_type (get_inner_rvalue ())); +} + inline rvalue rvalue::access_field (field field, location loc) @@ -1123,6 +1207,95 @@ inline param::param (gcc_jit_param *inner) : lvalue (gcc_jit_param_as_lvalue (inner)) {} +/* Overloaded operators. */ +// Unary operators +inline rvalue operator- (rvalue a) +{ + return a.get_context ().new_minus (a.get_type (), a); +} +inline rvalue operator~ (rvalue a) +{ + return a.get_context ().new_bitwise_negate (a.get_type (), a); +} +inline rvalue operator! (rvalue a) +{ + return a.get_context ().new_logical_negate (a.get_type (), a); +} + +// Binary operators +inline rvalue operator+ (rvalue a, rvalue b) +{ + return a.get_context ().new_plus (a.get_type (), a, b); +} +inline rvalue operator- (rvalue a, rvalue b) +{ + return a.get_context ().new_minus (a.get_type (), a, b); +} +inline rvalue operator* (rvalue a, rvalue b) +{ + return a.get_context ().new_mult (a.get_type (), a, b); +} +inline rvalue operator/ (rvalue a, rvalue b) +{ + return a.get_context ().new_divide (a.get_type (), a, b); +} +inline rvalue operator% (rvalue a, rvalue b) +{ + return a.get_context ().new_modulo (a.get_type (), a, b); +} +inline rvalue operator& (rvalue a, rvalue b) +{ + return a.get_context ().new_bitwise_and (a.get_type (), a, b); +} +inline rvalue operator^ (rvalue a, rvalue b) +{ + return a.get_context ().new_bitwise_xor (a.get_type (), a, b); +} +inline rvalue operator| (rvalue a, rvalue b) +{ + return a.get_context ().new_bitwise_or (a.get_type (), a, b); +} +inline rvalue operator&& (rvalue a, rvalue b) +{ + return a.get_context ().new_logical_and (a.get_type (), a, b); +} +inline rvalue operator|| (rvalue a, rvalue b) +{ + return a.get_context ().new_logical_or (a.get_type (), a, b); +} + +/* Comparisons. */ +inline rvalue operator== (rvalue a, rvalue b) +{ + return a.get_context ().new_eq (a, b); +} +inline rvalue operator!= (rvalue a, rvalue b) +{ + return a.get_context ().new_ne (a, b); +} +inline rvalue operator< (rvalue a, rvalue b) +{ + return a.get_context ().new_lt (a, b); +} +inline rvalue operator<= (rvalue a, rvalue b) +{ + return a.get_context ().new_le (a, b); +} +inline rvalue operator> (rvalue a, rvalue b) +{ + return a.get_context ().new_gt (a, b); +} +inline rvalue operator>= (rvalue a, rvalue b) +{ + return a.get_context ().new_ge (a, b); +} + +/* Dereferencing. */ +inline lvalue operator* (rvalue ptr) +{ + return ptr.dereference (); +} + } // namespace gccjit #endif /* #ifndef LIBGCCJIT_PLUS_PLUS_H */ diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 181954d..3f39984 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -452,6 +452,14 @@ gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue) return static_cast <gcc_jit_object *> (rvalue->as_object ()); } +gcc_jit_type * +gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue) +{ + RETURN_NULL_IF_FAIL (rvalue, NULL, "NULL rvalue"); + + return static_cast <gcc_jit_type *> (rvalue->get_type ()); +} + gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 1ef55d0..e0161ba 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -467,6 +467,9 @@ gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue); extern gcc_jit_object * gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue); +extern gcc_jit_type * +gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue); + /* Integer constants. */ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index cbf9b33..6dc700d 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -63,6 +63,7 @@ gcc_jit_rvalue_as_object; gcc_jit_rvalue_dereference; gcc_jit_rvalue_dereference_field; + gcc_jit_rvalue_get_type; gcc_jit_type_as_object; gcc_jit_type_get_const; gcc_jit_type_get_pointer; diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit index ee2dc40..11987e0 100644 --- a/gcc/testsuite/ChangeLog.jit +++ b/gcc/testsuite/ChangeLog.jit @@ -1,5 +1,10 @@ 2014-02-10 David Malcolm <dmalc...@redhat.com> + * jit.dg/test-operator-overloading.cc: New testcase, a + rewrite of test-quadratic.cc to use operator overloading. + +2014-02-10 David Malcolm <dmalc...@redhat.com> + * jit.dg/test-quadratic.cc (make_calc_discriminant): Make use of new methods of the C++ wrapper API to shorten the example code. (make_test_quadratic): Likewise. diff --git a/gcc/testsuite/jit.dg/test-operator-overloading.cc b/gcc/testsuite/jit.dg/test-operator-overloading.cc new file mode 100644 index 0000000..313b3e6 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-operator-overloading.cc @@ -0,0 +1,306 @@ +/* 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; + + /* "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_type (GCC_JIT_TYPE_INT); + + 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.numeric_type, + "calc_discriminant", + params, + 0); + testcase.calc_discriminant.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); + + testcase.calc_discriminant.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)); +} + +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"); + /* q.a = a; */ + test_quadratic.add_assignment (q.access_field (testcase.a), a); + /* q.b = b; */ + test_quadratic.add_assignment (q.access_field (testcase.b), b); + /* q.c = c; */ + test_quadratic.add_assignment (q.access_field (testcase.c), c); + /* calc_discriminant (&q); */ + gccjit::rvalue address_of_q = q.get_address (); + test_quadratic.add_eval (testcase.calc_discriminant (address_of_q)); + + gccjit::label on_positive_discriminant + = test_quadratic.new_forward_label ("positive_discriminant"); + + gccjit::label on_nonpositive_discriminant + = test_quadratic.new_forward_label ("nonpositive_discriminant"); + + gccjit::label on_zero_discriminant + = test_quadratic.new_forward_label ("zero_discriminant"); + + gccjit::label on_negative_discriminant + = test_quadratic.new_forward_label ("negative_discriminant"); + CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (), + "zero_discriminant"); + + test_quadratic.add_comment ("if (q.discriminant > 0)"); + test_quadratic.add_conditional ( + q.access_field (testcase.discriminant) > testcase.zero, + on_positive_discriminant, + on_nonpositive_discriminant); + + test_quadratic.place_forward_label (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); + test_quadratic.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"); + + test_quadratic.add_comment ("*r1 = (-b + s) / (2 * a);"); + test_quadratic.add_assignment (*r1, (minus_b + s) / two_a); + + test_quadratic.add_comment ("*r2 = (-b - s) / (2 * a)"); + test_quadratic.add_assignment (*r2, (minus_b - s) / two_a); + + /* "return 2;" */ + test_quadratic.add_return (testcase.ctxt.new_rvalue (testcase.int_type, 2)); + + /* "else if (q.discriminant == 0)" */ + test_quadratic.place_forward_label (on_nonpositive_discriminant); + test_quadratic.add_comment ("else if (q.discriminant == 0)"); + test_quadratic.add_conditional ( + q.access_field (testcase.discriminant) == testcase.zero, + on_zero_discriminant, + on_negative_discriminant); + + /* if (q.discriminant == 0) */ + test_quadratic.place_forward_label (on_zero_discriminant); + + test_quadratic.add_comment ("*r1 = -b / (2 * a);"); + test_quadratic.add_assignment (*r1, minus_b / two_a); + + /* "return 1;" */ + test_quadratic.add_return (testcase.ctxt.one (testcase.int_type)); + + /* else return 0; */ + test_quadratic.place_forward_label (on_negative_discriminant); + test_quadratic.add_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; + 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); +} -- 1.7.11.7