diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..7b971f3b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: c + +compiler: + - clang + - gcc + +os: + - linux +# - osx + +osx_image: xcode9 + +dist: trusty + +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gmp ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install --with-clang --with-lld --with-python llvm ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libgmp-dev libedit-dev ; fi + - export PATH=/usr/local/opt/llvm/bin:$PATH + - git submodule init + - git submodule update +env: + - INT=gmp + - INT=imath + - INT=imath-32 + +script: + - ./autogen.sh && ./configure --with-int=$INT --with-clang=system && make && make check diff --git a/include/isl/aff.h b/include/isl/aff.h index dc67819a..03262ec2 100644 --- a/include/isl/aff.h +++ b/include/isl/aff.h @@ -73,6 +73,7 @@ __isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff, int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type, const char *name); +__isl_export isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2); isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff); @@ -80,7 +81,7 @@ isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff); __isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos); -__isl_export +__isl_operator __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff); __isl_export __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff); @@ -90,16 +91,16 @@ __isl_overload __isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff, __isl_take isl_val *mod); -__isl_export +__isl_operator __isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1, __isl_take isl_aff *aff2); -__isl_export +__isl_operator __isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1, __isl_take isl_aff *aff2); -__isl_export +__isl_operator __isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1, __isl_take isl_aff *aff2); -__isl_export +__isl_operator __isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1, __isl_take isl_aff *aff2); @@ -201,6 +202,7 @@ isl_bool isl_pw_aff_is_empty(__isl_keep isl_pw_aff *pwaff); isl_bool isl_pw_aff_involves_nan(__isl_keep isl_pw_aff *pa); int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1, __isl_keep isl_pw_aff *pa2); +__isl_export isl_bool isl_pw_aff_plain_is_equal(__isl_keep isl_pw_aff *pwaff1, __isl_keep isl_pw_aff *pwaff2); isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1, @@ -249,19 +251,19 @@ __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, __isl_export __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); -__isl_export +__isl_operator __isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); -__isl_export +__isl_operator __isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2); -__isl_export +__isl_operator __isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); -__isl_export +__isl_operator __isl_give isl_pw_aff *isl_pw_aff_sub(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2); -__isl_export +__isl_operator __isl_give isl_pw_aff *isl_pw_aff_neg(__isl_take isl_pw_aff *pwaff); __isl_export __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff); diff --git a/include/isl/ctx.h b/include/isl/ctx.h index 7c925233..d2b19c33 100644 --- a/include/isl/ctx.h +++ b/include/isl/ctx.h @@ -33,6 +33,9 @@ #ifndef __isl_overload #define __isl_overload #endif +#ifndef __isl_operator +#define __isl_operator +#endif #ifndef __isl_constructor #define __isl_constructor #endif diff --git a/include/isl/val.h b/include/isl/val.h index fb50eaa4..45082e17 100644 --- a/include/isl/val.h +++ b/include/isl/val.h @@ -58,7 +58,7 @@ __isl_give isl_val *isl_val_set_si(__isl_take isl_val *v, long i); __isl_export __isl_give isl_val *isl_val_abs(__isl_take isl_val *v); -__isl_export +__isl_operator __isl_give isl_val *isl_val_neg(__isl_take isl_val *v); __isl_export __isl_give isl_val *isl_val_inv(__isl_take isl_val *v); @@ -73,16 +73,16 @@ __isl_export __isl_give isl_val *isl_val_min(__isl_take isl_val *v1, __isl_take isl_val *v2); __isl_export __isl_give isl_val *isl_val_max(__isl_take isl_val *v1, __isl_take isl_val *v2); -__isl_export +__isl_operator __isl_give isl_val *isl_val_add(__isl_take isl_val *v1, __isl_take isl_val *v2); __isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1, unsigned long v2); -__isl_export +__isl_operator __isl_give isl_val *isl_val_sub(__isl_take isl_val *v1, __isl_take isl_val *v2); __isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1, unsigned long v2); -__isl_export +__isl_operator __isl_give isl_val *isl_val_mul(__isl_take isl_val *v1, __isl_take isl_val *v2); __isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1, unsigned long v2); -__isl_export +__isl_operator __isl_give isl_val *isl_val_div(__isl_take isl_val *v1, __isl_take isl_val *v2); __isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1, unsigned long v2); __isl_export @@ -122,17 +122,17 @@ isl_bool isl_val_is_neginfty(__isl_keep isl_val *v); __isl_export int isl_val_cmp_si(__isl_keep isl_val *v, long i); -__isl_export +__isl_operator isl_bool isl_val_lt(__isl_keep isl_val *v1, __isl_keep isl_val *v2); -__isl_export +__isl_operator isl_bool isl_val_le(__isl_keep isl_val *v1, __isl_keep isl_val *v2); -__isl_export +__isl_operator isl_bool isl_val_gt(__isl_keep isl_val *v1, __isl_keep isl_val *v2); -__isl_export +__isl_operator isl_bool isl_val_ge(__isl_keep isl_val *v1, __isl_keep isl_val *v2); -__isl_export +__isl_operator isl_bool isl_val_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2); -__isl_export +__isl_operator isl_bool isl_val_ne(__isl_keep isl_val *v1, __isl_keep isl_val *v2); __isl_export isl_bool isl_val_abs_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2); diff --git a/interface/cpp.cc b/interface/cpp.cc index 569c4d7d..9ffe4626 100644 --- a/interface/cpp.cc +++ b/interface/cpp.cc @@ -553,6 +553,32 @@ void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) } } +/* Map isl function names to C++ operators. + */ +static const char *op_map[][2] = { + { "neg", "-" }, + { "add", "+" }, + { "sub", "-" }, + { "mul", "*" }, + { "div", "/" }, + { "lt", "<" }, + { "le", "<=" }, + { "gt", ">" }, + { "ge", ">=" }, + { "eq", "==" }, + { "ne", "!=" }, +}; + +/* Translate a function name "name" into the corresponding C++ operator. + */ +std::string cpp_generator::get_op_name(std::string name) { + for (size_t i = 0; i < sizeof(op_map) / sizeof(op_map[0]); i++) + if (name.compare(op_map[i][0]) == 0) + return op_map[i][1]; + + die("No operator name found"); +}; + /* Print definitions for methods "methods" of name "fullname" in class "clazz" * to "os". * @@ -560,6 +586,9 @@ void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) * to the isl name, with the object type prefix dropped. * In case of overloaded methods, the result type suffix has also been removed. * + * In case the function is marked as operator function, an additional variant + * as C++ operator is printed. + * * "kind" specifies the kind of method that should be generated. */ void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz, @@ -576,6 +605,13 @@ void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz, osprintf(os, "\n"); kind = get_method_kind(clazz, *it); print_method_impl(os, clazz, fullname, *it, kind); + + if (is_operator(*it)) { + osprintf(os, "\n"); + print_method_impl(os, clazz, fullname, *it, + function_kind_operator); + } + } } @@ -658,6 +694,9 @@ void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param, * do not return a value, but instead update the pointer stored inside the * newly created object. * + * When printing a method as C++ operator, the function name is replaced by + * the corresponding C++ operator as defined by "get_op_name". + * * If the method has a callback argument, we reduce the number of parameters * that are exposed by one to hide the user pointer from the interface. On * the C++ side no user pointer is needed, as arguments can be forwarded @@ -673,6 +712,9 @@ void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz, string rettype_str = type2cpp(return_type); bool has_callback = false; + if (kind == function_kind_operator) + cname = get_op_name(cname); + print_method_header(os, clazz, method, fullname, false, kind); for (int i = 0; i < num_params; ++i) { @@ -754,6 +796,9 @@ void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz, * as const reference, which allows the compiler to optimize the parameter * transfer. * + * When printing a method as C++ operator, the function name is replaced by + * the corresponding C++ operator as defined by "get_op_name". + * * Constructors are marked as explicit using the C++ keyword 'explicit' or as * implicit using a comment in place of the explicit keyword. By annotating * implicit constructors with a comment, users of the interface are made @@ -771,6 +816,9 @@ void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, int num_params = method->getNumParams(); int first_param = 0; + if (kind == function_kind_operator) + cname = "operator" + get_op_name(cname); + cname = rename_method(cname); if (kind == function_kind_member_method) first_param = 1; @@ -794,7 +842,7 @@ void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, if (kind != function_kind_constructor) osprintf(os, "%s ", rettype_str.c_str()); - if (!is_declaration) + if (!is_declaration && kind != function_kind_operator) osprintf(os, "%s::", classname.c_str()); if (kind != function_kind_constructor) diff --git a/interface/cpp.h b/interface/cpp.h index fcff26e3..4c30e3d8 100644 --- a/interface/cpp.h +++ b/interface/cpp.h @@ -14,6 +14,7 @@ class cpp_generator : public generator { function_kind_static_method, function_kind_member_method, function_kind_constructor, + function_kind_operator, }; virtual void generate(); @@ -71,4 +72,5 @@ class cpp_generator : public generator { bool is_subclass(QualType subclass_type, const isl_class &class_type); function_kind get_method_kind(const isl_class &clazz, FunctionDecl *method); + std::string get_op_name(std::string name); }; diff --git a/interface/extract_interface.cc b/interface/extract_interface.cc index 1275b345..ff3e17a9 100644 --- a/interface/extract_interface.cc +++ b/interface/extract_interface.cc @@ -426,6 +426,9 @@ int main(int argc, char *argv[]) PO.addMacroDef("__isl_overload=" "__attribute__((annotate(\"isl_overload\"))) " "__attribute__((annotate(\"isl_export\")))"); + PO.addMacroDef("__isl_operator=" + "__attribute__((annotate(\"isl_operator\"))) " + "__attribute__((annotate(\"isl_export\")))"); PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))"); PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))"); diff --git a/interface/generator.cc b/interface/generator.cc index 15bc34df..b18d556c 100644 --- a/interface/generator.cc +++ b/interface/generator.cc @@ -160,6 +160,13 @@ std::vector generator::find_superclasses(RecordDecl *decl) return super; } +/* Is decl marked as operator? + */ +bool generator::is_operator(Decl *decl) +{ + return has_annotation(decl, "isl_operator"); +} + /* Is decl marked as being part of an overloaded method? */ bool generator::is_overload(Decl *decl) diff --git a/interface/generator.h b/interface/generator.h index b235add6..f4f8b0ea 100644 --- a/interface/generator.h +++ b/interface/generator.h @@ -51,6 +51,7 @@ class generator { void die(string msg) __attribute__((noreturn)); vector find_superclasses(RecordDecl *decl); bool is_overload(Decl *decl); + bool is_operator(Decl *decl); bool is_constructor(Decl *decl); bool takes(Decl *decl); bool keeps(Decl *decl); diff --git a/interface/isl_test_cpp.cpp b/interface/isl_test_cpp.cpp index 6059208d..95295357 100644 --- a/interface/isl_test_cpp.cpp +++ b/interface/isl_test_cpp.cpp @@ -307,6 +307,102 @@ void test_foreach(isl::ctx ctx) assert(ret2 == isl::stat::error); } +/* Test C++ operators for isl_val + * + * This includes: + * + * # Arithmetic + * - negation + * - addition / subtraction + * - multiplication / division + * + * # Comparison + * - Inequality + * - Equality + */ +void test_operators_val(isl::ctx ctx) +{ + isl::val half(ctx, "1/2"); + isl::val one(ctx, "1"); + isl::val neg_one(ctx, "-1"); + isl::val two(ctx, "2"); + isl::val four(ctx, "4"); + + assert(-one == neg_one); + assert(one + one == two); + assert(two - one == one); + assert(two * two == four); + assert(one / two == half); + assert(one < two); + assert(one <= two); + assert(two > one); + assert(two >= one); + assert(one == one); + assert(one != two); +} + +/* Test C++ operators for isl_aff + * + * This includes: + * + * # Arithmetic + * - negation + * - addition / subtraction + * - multiplication / division + */ +void test_operators_aff(isl::ctx ctx) +{ + isl::aff i(ctx, "{ [i] -> [i] }"); + isl::aff zero(ctx, "{ [i] -> [0] }"); + isl::aff one(ctx, "{ [i] -> [1] }"); + isl::aff neg_one(ctx, "{ [i] -> [-1] }"); + isl::aff two(ctx, "{ [i] -> [2] }"); + isl::aff four(ctx, "{ [i] -> [4] }"); + + assert((-one).plain_is_equal(neg_one)); + assert((zero + one).plain_is_equal(one)); + assert((zero - one).plain_is_equal(neg_one)); + assert((zero * one).plain_is_equal(zero)); + assert((four / two).plain_is_equal(two)); +} + +/* Test C++ operators for isl_pw_aff + * + * This includes: + * + * # Arithmetic + * - negation + * - addition / subtraction + * - multiplication / division + */ +void test_operators_pw_aff(isl::ctx ctx) +{ + isl::pw_aff i(ctx, "{ [i] -> [i] }"); + isl::pw_aff zero(ctx, "{ [i] -> [0] }"); + isl::pw_aff one(ctx, "{ [i] -> [1] }"); + isl::pw_aff neg_one(ctx, "{ [i] -> [-1] }"); + isl::pw_aff two(ctx, "{ [i] -> [2] }"); + isl::pw_aff four(ctx, "{ [i] -> [4] }"); + + assert((-one).plain_is_equal(neg_one)); + assert((zero + one).plain_is_equal(one)); + assert((zero - one).plain_is_equal(neg_one)); + assert((zero * one).plain_is_equal(zero)); + assert((four / two).plain_is_equal(two)); +} + +/* Test C++ operators for: + * + * - isl_val + * - isl_aff + */ +void test_operators(isl::ctx ctx) +{ + test_operators_val(ctx); + test_operators_aff(ctx); + test_operators_pw_aff(ctx); +} + /* Test the isl C++ interface * * This includes: @@ -315,6 +411,7 @@ void test_foreach(isl::ctx ctx) * - Different parameter types * - Different return types * - Foreach functions + * - C++ operators */ int main() { @@ -325,6 +422,7 @@ int main() test_parameters(ctx); test_return(ctx); test_foreach(ctx); + test_operators(ctx); isl_ctx_free(ctx); }