Skip to content

Commit 7e2a999

Browse files
committed
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 <[email protected]>
1 parent 02fa3b9 commit 7e2a999

File tree

5 files changed

+150
-2
lines changed

5 files changed

+150
-2
lines changed

include/isl/id.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
extern "C" {
1111
#endif
1212

13-
struct isl_id;
13+
struct __isl_export isl_id;
1414
typedef struct isl_id isl_id;
1515

1616
ISL_DECLARE_LIST(id)
@@ -23,7 +23,9 @@ __isl_give isl_id *isl_id_alloc(isl_ctx *ctx,
2323
__isl_give isl_id *isl_id_copy(isl_id *id);
2424
__isl_null isl_id *isl_id_free(__isl_take isl_id *id);
2525

26+
__isl_export
2627
void *isl_id_get_user(__isl_keep isl_id *id);
28+
__isl_export
2729
__isl_keep const char *isl_id_get_name(__isl_keep isl_id *id);
2830

2931
__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id,

include/isl/set.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,13 @@ isl_bool isl_set_has_dim_id(__isl_keep isl_set *set,
7575
enum isl_dim_type type, unsigned pos);
7676
__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set,
7777
enum isl_dim_type type, unsigned pos);
78+
__isl_export
7879
__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set,
7980
__isl_take isl_id *id);
8081
__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set);
82+
__isl_export
8183
isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set);
84+
__isl_export
8285
__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set);
8386
__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set);
8487

interface/cpp.cc

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz)
171171
print_ptr_decl(os, clazz);
172172
osprintf(os, "\n");
173173
print_methods_decl(os, clazz);
174+
print_custom_public_decl(os, clazz);
174175

175176
osprintf(os, "};\n");
176177
}
@@ -371,6 +372,31 @@ void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
371372
print_method_group_decl(os, clazz, it->first, it->second);
372373
}
373374

375+
/* Print declarations for custom members of a class "clazz" to "os", based on
376+
* the class name.
377+
*/
378+
void cpp_generator::print_custom_public_decl(ostream &os,
379+
const isl_class &clazz)
380+
{
381+
string cppname = type2cpp(clazz);
382+
383+
if ("id" == cppname) {
384+
const char *declarations =
385+
" inline id(isl::ctx ctx, const std::string &name);\n"
386+
" inline id(isl::ctx ctx, const std::string &name,\n"
387+
" void *usr,\n"
388+
" void (*deleter)(void *) = nullptr);\n"
389+
" inline id(isl::ctx ctx, void *usr,\n"
390+
" void (*deleter)(void *) = nullptr);\n"
391+
" inline bool has_name() const;\n"
392+
" inline id set_free_user("
393+
"void (*deleter)(void *)) const;\n"
394+
" bool operator==(const id &other) const;\n"
395+
" bool operator!=(const id &other) const;\n";
396+
osprintf(os, "%s", declarations);
397+
}
398+
}
399+
374400
/* Print declarations for methods "methods" of name "fullname" in class "clazz"
375401
* to "os".
376402
*
@@ -427,6 +453,8 @@ void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
427453
print_ptr_impl(os, clazz);
428454
osprintf(os, "\n");
429455
print_methods_impl(os, clazz);
456+
osprintf(os, "\n");
457+
print_custom_methods_impl(os, clazz);
430458
}
431459

432460
/* Print implementation of global factory function to "os".
@@ -563,6 +591,49 @@ void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
563591
}
564592
}
565593

594+
/* Print definitions for custom methods of class "clazz" to "os", based on the
595+
* class name.
596+
*/
597+
void cpp_generator::print_custom_methods_impl(ostream &os,
598+
const isl_class &clazz)
599+
{
600+
string name = type2cpp(clazz);
601+
if ("id" == name) {
602+
const char *definitions =
603+
"id::id(isl::ctx ctx, const std::string &name) {\n"
604+
" ptr = isl_id_alloc(ctx.get(), name.c_str(),\n"
605+
" nullptr);\n"
606+
"}\n\n"
607+
"id::id(isl::ctx ctx, const std::string &name,\n"
608+
" void *user, void (*deleter)(void *)) {\n"
609+
" ptr = isl_id_alloc(ctx.get(), name.c_str(), user);\n"
610+
" if (deleter)\n"
611+
" ptr = isl_id_set_free_user(ptr, deleter);\n"
612+
"}\n\n"
613+
"id::id(isl::ctx ctx, void *user,\n"
614+
" void (*deleter)(void *)) {\n"
615+
" ptr = isl_id_alloc(ctx.get(), nullptr, user);\n"
616+
" if (deleter)\n"
617+
" ptr = isl_id_set_free_user(ptr, deleter);\n"
618+
"}\n\n"
619+
"bool id::has_name() const {\n"
620+
" return isl_id_get_name(ptr) != nullptr;\n"
621+
"}\n\n"
622+
"id id::set_free_user("
623+
"void (*deleter)(void *)) const {\n"
624+
" auto res = isl_id_set_free_user(copy(), deleter);\n"
625+
" return manage(res);\n"
626+
"}\n\n"
627+
"bool id::operator==(const isl::id &other) const {\n"
628+
" return ptr == other.ptr;\n"
629+
"}\n\n"
630+
"bool id::operator!=(const isl::id &other) const {\n"
631+
" return !operator==(other);\n"
632+
"}\n\n";
633+
osprintf(os, "%s", definitions);
634+
}
635+
}
636+
566637
/* Print definitions for methods "methods" of name "fullname" in class "clazz"
567638
* to "os".
568639
*
@@ -1023,7 +1094,8 @@ string cpp_generator::type2cpp(QualType type)
10231094
if (is_isl_stat(type))
10241095
return "isl::stat";
10251096

1026-
if (type->isIntegerType())
1097+
if (type->isIntegerType() || type->isVoidType() ||
1098+
type->isVoidPointerType())
10271099
return type.getAsString();
10281100

10291101
if (is_string(type))

interface/cpp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class cpp_generator : public generator {
3434
void print_destructor_decl(ostream &os, const isl_class &clazz);
3535
void print_ptr_decl(ostream &os, const isl_class &clazz);
3636
void print_methods_decl(ostream &os, const isl_class &clazz);
37+
void print_custom_public_decl(ostream &os, const isl_class &clazz);
3738
void print_method_group_decl(ostream &os, const isl_class &clazz,
3839
const string &fullname, const set<FunctionDecl *> &methods);
3940
void print_method_decl(ostream &os, const isl_class &clazz,
@@ -51,6 +52,7 @@ class cpp_generator : public generator {
5152
void print_destructor_impl(ostream &os, const isl_class &clazz);
5253
void print_ptr_impl(ostream &os, const isl_class &clazz);
5354
void print_methods_impl(ostream &os, const isl_class &clazz);
55+
void print_custom_methods_impl(ostream &os, const isl_class &clazz);
5456
void print_method_group_impl(ostream &os, const isl_class &clazz,
5557
const string &fullname, const set<FunctionDecl *> &methods);
5658
void print_method_impl(ostream &os, const isl_class &clazz,

interface/isl_test_cpp.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,71 @@ void test_foreach(isl::ctx ctx)
314314
assert(ret2 == isl::stat::error);
315315
}
316316

317+
/* Test that ids are handled correctly and remain unique.
318+
*
319+
* Verify that id names are stored and returned correctly. Check that ids with
320+
* identical names are equal and those with different names are different.
321+
* Check that ids with identical names and different user pointers are
322+
* different. Verify that equality holds across ids constructed from C and C++
323+
* interfaces.
324+
*/
325+
void test_id(isl::ctx ctx)
326+
{
327+
isl::id id_whatever(ctx, std::string("whatever"));
328+
assert(id_whatever.has_name());
329+
assert(std::string("whatever") == id_whatever.get_name());
330+
331+
isl::id id_other(ctx, std::string("whatever"));
332+
assert(id_whatever == id_other);
333+
334+
int fourtytwo = 42;
335+
isl::id id_whatever_42(ctx, std::string("whatever"), &fourtytwo);
336+
assert(id_whatever != id_whatever_42);
337+
338+
isl::id id_whatever_42_copy(id_whatever_42);
339+
assert(id_whatever_42 == id_whatever_42_copy);
340+
341+
isl::id id_whatever_42_other(ctx, std::string("whatever"), &fourtytwo);
342+
assert(id_whatever_42 == id_whatever_42_other);
343+
344+
isl_id *cid = isl_id_alloc(ctx.get(), "whatever", &fourtytwo);
345+
assert(cid == id_whatever_42.get());
346+
isl_id_free(cid);
347+
}
348+
349+
static void reset_flag(void *user) {
350+
*static_cast<int *>(user) = 0;
351+
}
352+
353+
/* Test that user pointers of the ids are not freed as long as the exists at
354+
* least one id pointing to them, either in C or C++.
355+
*
356+
* In a scope, create an id with a flag as a user object and a user_free that
357+
* resets the flag. Use the id in a set object that lives outside the given
358+
* scope. Check that flag is still set after the id object went out of the
359+
* scope. Check that flag is reset after the set object went of of scope.
360+
*/
361+
void test_id_lifetime(isl::ctx ctx)
362+
{
363+
int *flag = new int(1);
364+
365+
{
366+
isl::set set(ctx, "{:}");
367+
{
368+
isl::id id(ctx, std::string("whatever"), flag,
369+
&reset_flag);
370+
set = set.set_tuple_id(id);
371+
}
372+
assert(1 == *flag);
373+
assert(set.has_tuple_id());
374+
375+
isl::id same_id(ctx, std::string("whatever"), flag);
376+
assert(set.get_tuple_id() == same_id);
377+
}
378+
assert(0 == *flag);
379+
delete flag;
380+
}
381+
317382
/* Test the isl C++ interface
318383
*
319384
* This includes:
@@ -322,6 +387,8 @@ void test_foreach(isl::ctx ctx)
322387
* - Different parameter types
323388
* - Different return types
324389
* - Foreach functions
390+
* - isl::id uniqueness
391+
* - isl::id lifetime
325392
*/
326393
int main()
327394
{
@@ -332,6 +399,8 @@ int main()
332399
test_parameters(ctx);
333400
test_return(ctx);
334401
test_foreach(ctx);
402+
test_id(ctx);
403+
test_id_lifetime(ctx);
335404

336405
isl_ctx_free(ctx);
337406
}

0 commit comments

Comments
 (0)