From 8ec3d9c5c8f4a1dfc2202e3d51e432fda742525e Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Fri, 1 Sep 2017 13:04:04 +0200 Subject: [PATCH 1/5] cpp: export id Introduce special behavior for the id class with two features: disallow unnamed ids by construction, ensure that ids remain value-comparable. Generally, isl_id behaves like a reference-counted smart pointer to the name string and the user pointer. Additionally, it guarantees that ids with identical names and user pointers are pointer-comparable. An id object can have a "user_free" callback that is called when the reference counter reaches zero. Existing mechanism for callbacks does not apply to "user_free" callbacks as it modifies the user object passed to the callback. In particular, it creates a new object of a custom type in each call of the function that takes a callback and passes it instead of the original user pointer. Therefore, two ids constructed independently from the same user pointer would no longer be pointer-comparable. Therefore, one must pass the user pointer directly. The "user_free" callback must in turn remain a C function pointer. An alternative solution that supports std::function would require maintaining a map between user pointers and custom objects that were passed when constructing isl_ids; however, it would break direct comparability between isl_ids constructed using C and C++ interface. Support void and void * as return and argument types in the generator. Modify the generator to inject custom method declarations and definitions in the class based on the class name. Inject custom constructors, utility methods and comparison operators for isl::id. Custom constructors take either a name or a user pointer, or both. The "user_free" callback can be optionally provided in constructors or set up separately. This callback must be a C function pointer because it will be called from the C code. The user pointer is passed as void *, which can be replaced by template methods in the future, except in the "user_free" callback. The "set_user_free" function is injected so as to avoid handling a special case in callback generation. Signed-off-by: Oleksandr Zinenko --- include/isl/id.h | 4 ++- include/isl/set.h | 3 ++ interface/cpp.cc | 74 +++++++++++++++++++++++++++++++++++++- interface/cpp.h | 2 ++ interface/isl_test_cpp.cpp | 69 +++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 2 deletions(-) diff --git a/include/isl/id.h b/include/isl/id.h index c025d513..f6a31e7d 100644 --- a/include/isl/id.h +++ b/include/isl/id.h @@ -10,7 +10,7 @@ extern "C" { #endif -struct isl_id; +struct __isl_export isl_id; typedef struct isl_id isl_id; ISL_DECLARE_LIST(id) @@ -23,7 +23,9 @@ __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, __isl_give isl_id *isl_id_copy(isl_id *id); __isl_null isl_id *isl_id_free(__isl_take isl_id *id); +__isl_export void *isl_id_get_user(__isl_keep isl_id *id); +__isl_export __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, diff --git a/include/isl/set.h b/include/isl/set.h index 793195b0..9041774c 100644 --- a/include/isl/set.h +++ b/include/isl/set.h @@ -75,10 +75,13 @@ isl_bool isl_set_has_dim_id(__isl_keep isl_set *set, enum isl_dim_type type, unsigned pos); __isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set, enum isl_dim_type type, unsigned pos); +__isl_export __isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set, __isl_take isl_id *id); __isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set); +__isl_export isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set); +__isl_export __isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set); __isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set); diff --git a/interface/cpp.cc b/interface/cpp.cc index 5668088f..0cf9420e 100644 --- a/interface/cpp.cc +++ b/interface/cpp.cc @@ -171,6 +171,7 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz) print_ptr_decl(os, clazz); osprintf(os, "\n"); print_methods_decl(os, clazz); + print_custom_public_decl(os, clazz); osprintf(os, "};\n"); } @@ -371,6 +372,31 @@ void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz) print_method_group_decl(os, clazz, it->first, it->second); } +/* Print declarations for custom members of a class "clazz" to "os", based on + * the class name. + */ +void cpp_generator::print_custom_public_decl(ostream &os, + const isl_class &clazz) +{ + string cppname = type2cpp(clazz); + + if ("id" == cppname) { + const char *declarations = + " inline id(isl::ctx ctx, const std::string &name);\n" + " inline id(isl::ctx ctx, const std::string &name,\n" + " void *usr,\n" + " void (*deleter)(void *) = nullptr);\n" + " inline id(isl::ctx ctx, void *usr,\n" + " void (*deleter)(void *) = nullptr);\n" + " inline bool has_name() const;\n" + " inline id set_free_user(" + "void (*deleter)(void *)) const;\n" + " inline bool operator==(const id &other) const;\n" + " inline bool operator!=(const id &other) const;\n"; + osprintf(os, "%s", declarations); + } +} + /* Print declarations for methods "methods" of name "fullname" in class "clazz" * to "os". * @@ -427,6 +453,8 @@ void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) print_ptr_impl(os, clazz); osprintf(os, "\n"); print_methods_impl(os, clazz); + osprintf(os, "\n"); + print_custom_methods_impl(os, clazz); } /* Print implementation of global factory function to "os". @@ -563,6 +591,49 @@ void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) } } +/* Print definitions for custom methods of class "clazz" to "os", based on the + * class name. + */ +void cpp_generator::print_custom_methods_impl(ostream &os, + const isl_class &clazz) +{ + string name = type2cpp(clazz); + if ("id" == name) { + const char *definitions = + "id::id(isl::ctx ctx, const std::string &name) {\n" + " ptr = isl_id_alloc(ctx.get(), name.c_str(),\n" + " nullptr);\n" + "}\n\n" + "id::id(isl::ctx ctx, const std::string &name,\n" + " void *user, void (*deleter)(void *)) {\n" + " ptr = isl_id_alloc(ctx.get(), name.c_str(), user);\n" + " if (deleter)\n" + " ptr = isl_id_set_free_user(ptr, deleter);\n" + "}\n\n" + "id::id(isl::ctx ctx, void *user,\n" + " void (*deleter)(void *)) {\n" + " ptr = isl_id_alloc(ctx.get(), nullptr, user);\n" + " if (deleter)\n" + " ptr = isl_id_set_free_user(ptr, deleter);\n" + "}\n\n" + "bool id::has_name() const {\n" + " return isl_id_get_name(ptr) != nullptr;\n" + "}\n\n" + "id id::set_free_user(" + "void (*deleter)(void *)) const {\n" + " auto res = isl_id_set_free_user(copy(), deleter);\n" + " return manage(res);\n" + "}\n\n" + "bool id::operator==(const isl::id &other) const {\n" + " return ptr == other.ptr;\n" + "}\n\n" + "bool id::operator!=(const isl::id &other) const {\n" + " return !operator==(other);\n" + "}\n\n"; + osprintf(os, "%s", definitions); + } +} + /* Print definitions for methods "methods" of name "fullname" in class "clazz" * to "os". * @@ -1023,7 +1094,8 @@ string cpp_generator::type2cpp(QualType type) if (is_isl_stat(type)) return "isl::stat"; - if (type->isIntegerType()) + if (type->isIntegerType() || type->isVoidType() || + type->isVoidPointerType()) return type.getAsString(); if (is_string(type)) diff --git a/interface/cpp.h b/interface/cpp.h index 1978e261..e495034d 100644 --- a/interface/cpp.h +++ b/interface/cpp.h @@ -34,6 +34,7 @@ class cpp_generator : public generator { void print_destructor_decl(ostream &os, const isl_class &clazz); void print_ptr_decl(ostream &os, const isl_class &clazz); void print_methods_decl(ostream &os, const isl_class &clazz); + void print_custom_public_decl(ostream &os, const isl_class &clazz); void print_method_group_decl(ostream &os, const isl_class &clazz, const string &fullname, const set &methods); void print_method_decl(ostream &os, const isl_class &clazz, @@ -51,6 +52,7 @@ class cpp_generator : public generator { void print_destructor_impl(ostream &os, const isl_class &clazz); void print_ptr_impl(ostream &os, const isl_class &clazz); void print_methods_impl(ostream &os, const isl_class &clazz); + void print_custom_methods_impl(ostream &os, const isl_class &clazz); void print_method_group_impl(ostream &os, const isl_class &clazz, const string &fullname, const set &methods); void print_method_impl(ostream &os, const isl_class &clazz, diff --git a/interface/isl_test_cpp.cpp b/interface/isl_test_cpp.cpp index a6b1e631..c509f950 100644 --- a/interface/isl_test_cpp.cpp +++ b/interface/isl_test_cpp.cpp @@ -314,6 +314,71 @@ void test_foreach(isl::ctx ctx) assert(ret2 == isl::stat::error); } +/* Test that ids are handled correctly and remain unique. + * + * Verify that id names are stored and returned correctly. Check that ids with + * identical names are equal and those with different names are different. + * Check that ids with identical names and different user pointers are + * different. Verify that equality holds across ids constructed from C and C++ + * interfaces. + */ +void test_id(isl::ctx ctx) +{ + isl::id id_whatever(ctx, std::string("whatever")); + assert(id_whatever.has_name()); + assert(std::string("whatever") == id_whatever.get_name()); + + isl::id id_other(ctx, std::string("whatever")); + assert(id_whatever == id_other); + + int fourtytwo = 42; + isl::id id_whatever_42(ctx, std::string("whatever"), &fourtytwo); + assert(id_whatever != id_whatever_42); + + isl::id id_whatever_42_copy(id_whatever_42); + assert(id_whatever_42 == id_whatever_42_copy); + + isl::id id_whatever_42_other(ctx, std::string("whatever"), &fourtytwo); + assert(id_whatever_42 == id_whatever_42_other); + + isl_id *cid = isl_id_alloc(ctx.get(), "whatever", &fourtytwo); + assert(cid == id_whatever_42.get()); + isl_id_free(cid); +} + +static void reset_flag(void *user) { + *static_cast(user) = 0; +} + +/* Test that user pointers of the ids are not freed as long as the exists at + * least one id pointing to them, either in C or C++. + * + * In a scope, create an id with a flag as a user object and a user_free that + * resets the flag. Use the id in a set object that lives outside the given + * scope. Check that flag is still set after the id object went out of the + * scope. Check that flag is reset after the set object went of of scope. + */ +void test_id_lifetime(isl::ctx ctx) +{ + int *flag = new int(1); + + { + isl::set set(ctx, "{:}"); + { + isl::id id(ctx, std::string("whatever"), flag, + &reset_flag); + set = set.set_tuple_id(id); + } + assert(1 == *flag); + assert(set.has_tuple_id()); + + isl::id same_id(ctx, std::string("whatever"), flag); + assert(set.get_tuple_id() == same_id); + } + assert(0 == *flag); + delete flag; +} + /* Test the isl C++ interface * * This includes: @@ -322,6 +387,8 @@ void test_foreach(isl::ctx ctx) * - Different parameter types * - Different return types * - Foreach functions + * - isl::id uniqueness + * - isl::id lifetime */ int main() { @@ -332,6 +399,8 @@ int main() test_parameters(ctx); test_return(ctx); test_foreach(ctx); + test_id(ctx); + test_id_lifetime(ctx); isl_ctx_free(ctx); } From 4b97a38ab4a48fbde760f71c6d51bd0a82782ea4 Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Fri, 1 Sep 2017 15:52:27 +0200 Subject: [PATCH 2/5] boilerplate methods for lists --- include/isl/ctx.h | 3 + include/isl/val.h | 1 + interface/cpp.cc | 107 +++++++++++++++++++++++++++++---- interface/cpp.h | 13 +++- interface/extract_interface.cc | 1 + interface/generator.cc | 49 ++++++++++----- interface/generator.h | 5 ++ interface/isl.h.top | 3 + 8 files changed, 155 insertions(+), 27 deletions(-) diff --git a/include/isl/ctx.h b/include/isl/ctx.h index 7c925233..ecb04406 100644 --- a/include/isl/ctx.h +++ b/include/isl/ctx.h @@ -39,6 +39,9 @@ #ifndef __isl_subclass #define __isl_subclass(super) #endif +#ifndef __isl_list +#define __isl_list(elem) +#endif #if defined(__cplusplus) extern "C" { diff --git a/include/isl/val.h b/include/isl/val.h index fb50eaa4..225c9cb6 100644 --- a/include/isl/val.h +++ b/include/isl/val.h @@ -13,6 +13,7 @@ extern "C" { struct __isl_export isl_val; typedef struct isl_val isl_val; +struct __isl_list(isl_val) isl_val_list; ISL_DECLARE_LIST(val) struct __isl_export isl_multi_val; diff --git a/interface/cpp.cc b/interface/cpp.cc index 0cf9420e..df3caf45 100644 --- a/interface/cpp.cc +++ b/interface/cpp.cc @@ -73,6 +73,22 @@ static std::string to_string(long l) return strm.str(); } +cpp_generator::cpp_generator(set &exported_types, + set exported_functions, + set functions) : + generator(exported_types, exported_functions, functions) +{ + map::iterator ci; + + for (ci = classes.begin(); ci != classes.end(); ++ci) { + vector element_type = + get_list_element_type_name(ci->second.type); + if (element_type.empty()) + continue; + list_types[ci->second.name] = element_type[0]; + } +} + /* Generate a cpp interface based on the extracted types and functions. * * Print first a set of forward declarations for all isl wrapper @@ -123,7 +139,10 @@ void cpp_generator::print_declarations(ostream &os) else osprintf(os, "\n"); - print_class(os, ci->second); + if (is_list_type(ci->second)) + print_list_specialization(os, ci->second); + else + print_class(os, ci->second); } } @@ -144,9 +163,8 @@ void cpp_generator::print_implementations(ostream &os) } } -/* Print declarations for class "clazz" to "os". - */ -void cpp_generator::print_class(ostream &os, const isl_class &clazz) +void cpp_generator::print_common_class_body(ostream &os, const isl_class &clazz, + bool is_template_specialization) { const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); @@ -156,6 +174,8 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz) print_class_factory_decl(os, clazz); osprintf(os, "\n"); + if (is_template_specialization) + osprintf(os, "template <>\n"); osprintf(os, "class %s {\n", cppname); print_class_factory_decl(os, clazz, " friend "); osprintf(os, "\n"); @@ -172,15 +192,30 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz) osprintf(os, "\n"); print_methods_decl(os, clazz); print_custom_public_decl(os, clazz); - osprintf(os, "};\n"); } +/* Print declarations for class "clazz" to "os". + */ +void cpp_generator::print_class(ostream &os, const isl_class &clazz) +{ + print_common_class_body(os, clazz); +} + +void cpp_generator::print_list_specialization(ostream &os, + const isl_class &clazz) +{ + print_common_class_body(os, clazz, true); +} + /* Print forward declaration of class "clazz" to "os". */ void cpp_generator::print_class_forward_decl(ostream &os, const isl_class &clazz) { + if (is_list_type(clazz)) + return; + std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); @@ -235,6 +270,10 @@ void cpp_generator::print_private_constructors_decl(ostream &os, { const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); + + if (is_list_type(clazz)) + cppstring = instance_type(cppstring); + const char *cppname = cppstring.c_str(); osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname, @@ -257,11 +296,17 @@ void cpp_generator::print_public_constructors_decl(ostream &os, const isl_class &clazz) { std::string cppstring = type2cpp(clazz); + std::string constructor_string = cppstring; + + if (is_list_type(clazz)) + constructor_string = instance_type(constructor_string); + const char *cppname = cppstring.c_str(); - osprintf(os, " inline /* implicit */ %s();\n", cppname); + const char *constructor_name = constructor_string.c_str(); + osprintf(os, " inline /* implicit */ %s();\n", constructor_name); osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n", - cppname, cppname); + constructor_name, cppname); } /* Print declarations for constructors for class "class" to "os". @@ -484,9 +529,12 @@ void cpp_generator::print_private_constructors_impl(ostream &os, const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); + std::string constructor_string = + is_list_type(clazz) ? instance_type(cppstring) : cppstring; + const char *constructor_name = constructor_string.c_str(); osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n", - cppname, cppname, name); + cppname, constructor_name, name); } /* Print implementations of public constructors for class "clazz" to "os". @@ -497,10 +545,14 @@ void cpp_generator::print_public_constructors_impl(ostream &os, const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); + std::string constructor_string = + is_list_type(clazz) ? instance_type(cppstring) : cppstring; + const char *constructor_name = constructor_string.c_str(); - osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname); + osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, + constructor_name); osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n", - cppname, cppname, cppname, name); + cppname, constructor_name, cppname); } /* Print implementations of constructors for class "clazz" to "os". @@ -544,8 +596,11 @@ void cpp_generator::print_destructor_impl(ostream &os, const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); + std::string constructor_string = + is_list_type(clazz) ? instance_type(cppstring) : cppstring; + const char *constructor_name = constructor_string.c_str(); - osprintf(os, "%s::~%s() {\n", cppname, cppname); + osprintf(os, "%s::~%s() {\n", cppname, constructor_name); osprintf(os, " if (ptr)\n"); osprintf(os, " %s_free(ptr);\n", name); osprintf(os, "}\n"); @@ -1071,6 +1126,9 @@ std::string cpp_generator::rename_method(std::string name) */ string cpp_generator::type2cpp(const isl_class &clazz) { + if (is_list_type(clazz)) + return "list<" + type2cpp(list_types[clazz.name]) + ">"; + return type2cpp(clazz.name); } @@ -1085,6 +1143,10 @@ string cpp_generator::type2cpp(string type_str) */ string cpp_generator::type2cpp(QualType type) { + if (is_list_type(type)) + return "isl::list"; + if (is_isl_type(type)) return "isl::" + type2cpp(type->getPointeeType().getAsString()); @@ -1173,3 +1235,26 @@ cpp_generator::function_kind cpp_generator::get_method_kind( else return function_kind_member_method; } + +bool cpp_generator::is_list_type(QualType type) +{ + if (!type->isPointerType()) + return false; + return list_types.count(type->getPointeeType().getAsString()) != 0; +} + +bool cpp_generator::is_list_type(const isl_class &clazz) +{ + return list_types.count(clazz.name) != 0; +} + +string cpp_generator::list_element_type_name(QualType type) +{ + return list_types.at(type->getPointeeType().getAsString()); +} + +string cpp_generator::instance_type(const string &type_string) +{ + size_t pos = type_string.find('<'); + return type_string.substr(0, pos); +} diff --git a/interface/cpp.h b/interface/cpp.h index e495034d..aa25b508 100644 --- a/interface/cpp.h +++ b/interface/cpp.h @@ -4,11 +4,13 @@ using namespace std; using namespace clang; class cpp_generator : public generator { +protected: + map list_types; + public: cpp_generator(set &exported_types, set exported_functions, - set functions) : - generator(exported_types, exported_functions, functions) {} + set functions); enum function_kind { function_kind_static_method, @@ -21,7 +23,10 @@ class cpp_generator : public generator { void print_file(ostream &os, std::string filename); void print_forward_declarations(ostream &os); void print_declarations(ostream &os); + void print_common_class_body(ostream &os, const isl_class &clazz, + bool is_template_specialization = false); void print_class(ostream &os, const isl_class &clazz); + void print_list_specialization(ostream &os, const isl_class &clazz); void print_class_forward_decl(ostream &os, const isl_class &clazz); void print_class_factory_decl(ostream &os, const isl_class &clazz, const std::string &prefix = std::string()); @@ -74,4 +79,8 @@ 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); + bool is_list_type(QualType type); + bool is_list_type(const isl_class &clazz); + string list_element_type_name(QualType type); + string instance_type(const string &type_string); }; diff --git a/interface/extract_interface.cc b/interface/extract_interface.cc index 1275b345..171b2f34 100644 --- a/interface/extract_interface.cc +++ b/interface/extract_interface.cc @@ -428,6 +428,7 @@ int main(int argc, char *argv[]) "__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\")))"); + PO.addMacroDef("__isl_list(elem)=__attribute__((annotate(\"isl_list(\" #elem \")\"))) __attribute__((annotate(\"isl_export\")))"); create_preprocessor(Clang); Preprocessor &PP = Clang->getPreprocessor(); diff --git a/interface/generator.cc b/interface/generator.cc index 15bc34df..bcb57c61 100644 --- a/interface/generator.cc +++ b/interface/generator.cc @@ -129,35 +129,56 @@ void generator::die(string msg) die(msg.c_str()); } -/* Return a sequence of the types of which the given type declaration is - * marked as being a subtype. - * The order of the types is the opposite of the order in which they - * appear in the source. In particular, the first annotation - * is the one that is closest to the annotated type and the corresponding - * type is then also the first that will appear in the sequence of types. +/* Find all "decl" annotations with prefix "annotation" and return their + * arguments in a vector. More specifically, find all annotations of the form + * 'annotate("annotation(something)")' and return a vector that contains + * 'something'. */ -std::vector generator::find_superclasses(RecordDecl *decl) +vector generator::extract_annotation_arguments(RecordDecl *decl, + const string &annotation) const { - vector super; + vector arguments; if (!decl->hasAttrs()) - return super; + return arguments; - string sub = "isl_subclass"; - size_t len = sub.length(); + size_t len = annotation.length(); AttrVec attrs = decl->getAttrs(); for (AttrVec::const_iterator i = attrs.begin(); i != attrs.end(); ++i) { const AnnotateAttr *ann = dyn_cast(*i); if (!ann) continue; string s = ann->getAnnotation().str(); - if (s.substr(0, len) == sub) { + if (s.substr(0, len) == annotation) { s = s.substr(len + 1, s.length() - len - 2); - super.push_back(s); + arguments.push_back(s); } } - return super; + return arguments; +} + +/* Return a sequence of the types of which the given type declaration is + * marked as being a subtype. + * The order of the types is the opposite of the order in which they + * appear in the source. In particular, the first annotation + * is the one that is closest to the annotated type and the corresponding + * type is then also the first that will appear in the sequence of types. + */ +std::vector generator::find_superclasses(RecordDecl *decl) +{ + return extract_annotation_arguments(decl, "isl_subclass"); +} + +/* Return a type name that the given declaration is marked as being a list of. + * If the declaration is not marked as a list, return an empty vector. + */ +vector generator::get_list_element_type_name(RecordDecl *decl) +{ + vector elems = extract_annotation_arguments(decl, "isl_list"); + if (elems.size() > 1) + die("multiple element types provided for a list"); + return elems; } /* Is decl marked as being part of an overloaded method? diff --git a/interface/generator.h b/interface/generator.h index b235add6..91bdf3eb 100644 --- a/interface/generator.h +++ b/interface/generator.h @@ -50,6 +50,7 @@ class generator { void die(const char *msg) __attribute__((noreturn)); void die(string msg) __attribute__((noreturn)); vector find_superclasses(RecordDecl *decl); + vector get_list_element_type_name(RecordDecl *decl); bool is_overload(Decl *decl); bool is_constructor(Decl *decl); bool takes(Decl *decl); @@ -67,6 +68,10 @@ class generator { bool is_static(const isl_class &clazz, FunctionDecl *method); string extract_type(QualType type); FunctionDecl *find_by_name(const string &name, bool required); + +private: + vector extract_annotation_arguments(RecordDecl *decl, + const string &annotation) const; }; #endif /* ISL_INTERFACE_GENERATOR_H */ diff --git a/interface/isl.h.top b/interface/isl.h.top index 37749c29..6b0bacb0 100644 --- a/interface/isl.h.top +++ b/interface/isl.h.top @@ -91,5 +91,8 @@ enum class stat { error = isl_stat_error }; +template +class list; + } } // namespace isl From 3f992980ede3bf5fee0e4170218349b416bf6931 Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Fri, 1 Sep 2017 17:01:13 +0200 Subject: [PATCH 3/5] generate iterator-constructors and accessors --- interface/cpp.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++--- interface/cpp.h | 1 + 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/interface/cpp.cc b/interface/cpp.cc index df3caf45..33cfaac1 100644 --- a/interface/cpp.cc +++ b/interface/cpp.cc @@ -425,7 +425,20 @@ void cpp_generator::print_custom_public_decl(ostream &os, { string cppname = type2cpp(clazz); - if ("id" == cppname) { + if (is_list_type(clazz)) { + const char *declarations = + " template \n" + " inline list(isl::ctx ctx, InputIt1 from, " + "InputIt2 to);\n\n" + " inline int size() const;\n"; + string element_string = type2cpp(list_element_type_name(clazz)); + const char *element_type = element_string.c_str(); + + osprintf(os, "%s", declarations); + osprintf(os, " inline %s at(int pos) const;\n", element_type); + osprintf(os, " inline %s operator[](int pos) const;\n", + element_type); + } else if ("id" == cppname) { const char *declarations = " inline id(isl::ctx ctx, const std::string &name);\n" " inline id(isl::ctx ctx, const std::string &name,\n" @@ -542,7 +555,6 @@ void cpp_generator::print_private_constructors_impl(ostream &os, void cpp_generator::print_public_constructors_impl(ostream &os, const isl_class &clazz) { - const char *name = clazz.name.c_str(); std::string cppstring = type2cpp(clazz); const char *cppname = cppstring.c_str(); std::string constructor_string = @@ -653,7 +665,47 @@ void cpp_generator::print_custom_methods_impl(ostream &os, const isl_class &clazz) { string name = type2cpp(clazz); - if ("id" == name) { + const char *cname = name.c_str(); + if (is_list_type(clazz)) { + string element_string = list_element_type_name(clazz); + const char *element_type = element_string.c_str(); + string element_string_noprefix = element_string.substr(4); + const char *element_name = element_string_noprefix.c_str(); + string element_cppstring = type2cpp(element_string); + const char *element_cpptype = element_cppstring.c_str(); + + osprintf(os, + "template \n"); + osprintf(os, "%s::list(isl::ctx ctx, InputIt1 from, " + "InputIt2 to) {\n", cname); + osprintf(os, + " ptr = %s_list_alloc(ctx.get(), ", element_type); + osprintf(os, "std::distance(from, to));\n"); + osprintf(os, " for ( ; from != to; ++from) {\n"); + osprintf(os, " ptr = %s_list_add(ptr, from->copy());\n", + element_type); + osprintf(os, " }\n"); + osprintf(os, "}\n\n"); + + osprintf(os, "int %s::size() const {\n", cname); + osprintf(os, " return %s_list_n_%s(ptr);\n", element_type, + element_name); + osprintf(os, "}\n\n"); + + osprintf(os, "isl::%s %s::at(int pos) const {\n", element_cpptype, + cname); + osprintf(os, " ISLPP_ASSERT(pos >= 0 && pos < size(),\n"); + osprintf(os, " \"position out of range\");\n"); + osprintf(os, " return manage(%s_list_get_%s(ptr, pos));\n", + element_type, element_name); + osprintf(os, "}\n\n"); + + osprintf(os, "isl::%s %s::operator[](int pos) const {\n", + element_cpptype, cname); + osprintf(os, " return manage(%s_list_get_%s(ptr, pos));\n", + element_type, element_name); + osprintf(os, "}\n\n"); + } else if ("id" == name) { const char *definitions = "id::id(isl::ctx ctx, const std::string &name) {\n" " ptr = isl_id_alloc(ctx.get(), name.c_str(),\n" @@ -1253,6 +1305,11 @@ string cpp_generator::list_element_type_name(QualType type) return list_types.at(type->getPointeeType().getAsString()); } +string cpp_generator::list_element_type_name(const isl_class &clazz) +{ + return list_types.at(clazz.name); +} + string cpp_generator::instance_type(const string &type_string) { size_t pos = type_string.find('<'); diff --git a/interface/cpp.h b/interface/cpp.h index aa25b508..a6e94837 100644 --- a/interface/cpp.h +++ b/interface/cpp.h @@ -82,5 +82,6 @@ class cpp_generator : public generator { bool is_list_type(QualType type); bool is_list_type(const isl_class &clazz); string list_element_type_name(QualType type); + string list_element_type_name(const isl_class &clazz); string instance_type(const string &type_string); }; From 26d23acb71d92e1beb42afc19d9095159ed59480 Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Fri, 1 Sep 2017 17:21:00 +0200 Subject: [PATCH 4/5] test for isl::list --- interface/isl_test_cpp.cpp | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/interface/isl_test_cpp.cpp b/interface/isl_test_cpp.cpp index c509f950..5d7cb3da 100644 --- a/interface/isl_test_cpp.cpp +++ b/interface/isl_test_cpp.cpp @@ -379,6 +379,51 @@ void test_id_lifetime(isl::ctx ctx) delete flag; } +/* Test that read-only list of vals are modeled correctly. + * + * Construct an std::vector of isl::vals and use its iterators to construct a + * C++ isl list of vals. Compare these containers. Extract the C isl list from + * the C++ one, verify that is has expected size and content. Modify the C isl + * list and convert it back to C++. Verify that the new managed list has + * expected content. + */ +void test_val_list(isl::ctx ctx) +{ + std::vector val_vector; + for (int i = 0; i < 42; ++i) { + isl::val val(ctx, i); + val_vector.push_back(val); + } + isl::list val_list(ctx, val_vector.begin(), + val_vector.end()); + + assert(42 == val_list.size()); + for (int i = 0; i < 42; ++i) { + isl::val val_at = val_list.at(i); + isl::val val_op = val_list[i]; + isl::val expected(ctx, i); + assert(val_at.eq(expected)); + assert(val_op.eq(expected)); + } + + isl_val_list *c_val_list = val_list.release(); + assert(42 == isl_val_list_n_val(c_val_list)); + for (int i = 0; i < 42; ++i) { + isl_val *val = isl_val_list_get_val(c_val_list, i); + assert(i == isl_val_get_num_si(val)); + isl_val_free(val); + } + + c_val_list = isl_val_list_drop(c_val_list, 0, 32); + val_list = isl::manage(c_val_list); + assert(10 == val_list.size()); + for (int i = 0; i < 10; ++i) { + isl::val expected(ctx, 32 + i); + isl::val val_op = val_list[i]; + assert(val_op.eq(expected)); + } +} + /* Test the isl C++ interface * * This includes: @@ -389,6 +434,7 @@ void test_id_lifetime(isl::ctx ctx) * - Foreach functions * - isl::id uniqueness * - isl::id lifetime + * - List of isl::val */ int main() { @@ -401,6 +447,7 @@ int main() test_foreach(ctx); test_id(ctx); test_id_lifetime(ctx); + test_val_list(ctx); isl_ctx_free(ctx); } From 47f8c4abfaac6082c56b9951999dea95723cec5c Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Fri, 1 Sep 2017 17:43:05 +0200 Subject: [PATCH 5/5] export and test list of basic_maps --- include/isl/map.h | 1 + include/isl/map_type.h | 1 + interface/isl_test_cpp.cpp | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/include/isl/map.h b/include/isl/map.h index 0ff17fe5..8c5fb4ab 100644 --- a/include/isl/map.h +++ b/include/isl/map.h @@ -146,6 +146,7 @@ __isl_export __isl_give isl_basic_map *isl_basic_map_intersect( __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2); +__isl_export __isl_give isl_basic_map *isl_basic_map_list_intersect( __isl_take isl_basic_map_list *list); __isl_export diff --git a/include/isl/map_type.h b/include/isl/map_type.h index 7c30056f..d09a937c 100644 --- a/include/isl/map_type.h +++ b/include/isl/map_type.h @@ -10,6 +10,7 @@ extern "C" { struct __isl_subclass(isl_map) isl_basic_map; typedef struct isl_basic_map isl_basic_map; +struct __isl_list(isl_basic_map) isl_basic_map_list; ISL_DECLARE_LIST_TYPE(basic_map) struct __isl_subclass(isl_union_map) isl_map; typedef struct isl_map isl_map; diff --git a/interface/isl_test_cpp.cpp b/interface/isl_test_cpp.cpp index 5d7cb3da..aa269d62 100644 --- a/interface/isl_test_cpp.cpp +++ b/interface/isl_test_cpp.cpp @@ -424,6 +424,23 @@ void test_val_list(isl::ctx ctx) } } +/* Test that supplementary functions on lists are handled properly. + * + * Construct a list of basic_maps from an array thereof. Compute the + * interaction of all basic_map in the list. + */ +void test_basic_map_list(isl::ctx ctx) +{ + isl::basic_map bmap1(ctx, "{[]->[a]: 0 <= a <= 42}"); + isl::basic_map bmap2(ctx, "{[]->[a]: 21 <= a <= 63}"); + isl::basic_map bmap3(ctx, "{[]->[a]: 21 <= a <= 42}"); + + isl::basic_map bmap_array[] = { bmap1, bmap2, bmap3 }; + isl::list bmap_list(ctx, bmap_array, bmap_array + 3); + isl::basic_map result = bmap_list.intersect(); + assert(result.is_equal(bmap3)); +} + /* Test the isl C++ interface * * This includes: @@ -435,6 +452,7 @@ void test_val_list(isl::ctx ctx) * - isl::id uniqueness * - isl::id lifetime * - List of isl::val + * - Custom function of the list of isl::basic_map */ int main() { @@ -448,6 +466,7 @@ int main() test_id(ctx); test_id_lifetime(ctx); test_val_list(ctx); + test_basic_map_list(ctx); isl_ctx_free(ctx); }