Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpp: export id #18

Open
wants to merge 1 commit into
base: continious-integration
Choose a base branch
from
Open

cpp: export id #18

wants to merge 1 commit into from

Conversation

ftynse
Copy link
Member

@ftynse ftynse commented Sep 1, 2017

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.

Closes #8

This was referenced Sep 1, 2017
@ftynse ftynse changed the base branch from master to continious-integration September 1, 2017 16:49
@ftynse
Copy link
Member Author

ftynse commented Sep 1, 2017

@TobiG I don't understand how CI works here...

@tobiasgrosser
Copy link
Member

It does not. I should probably just disable it again.

Copy link
Member

@tobiasgrosser tobiasgrosser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Alex,

thanks for this patch. It looks really great and the functions generated make a lot of sense.

Some high-level questions:

What does "disallow unnamed ids by construction, ensure that ids remain value comparable mean"? It seems your third constructor allows to construct an unnamed id?

Just pretty printing the right bindings is a good idea for a first draft of the patch. However, this will prevent these function to exist on the python side of things. Also, I feel it would be slightly more in-style to just generate this stuff instead of pattern matching on the types. For this we should likely ask Sven for feedback. He has strong concerns about this.

*static_cast<int *>(user) = 0;
}

/* Test that user pointers of the ids are not freed as long as the exists at
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theRE exists

* 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

went OUT of scope

" void (*deleter)(void *) = nullptr);\n"
" inline id(isl::ctx ctx, void *usr,\n"
" void (*deleter)(void *) = nullptr);\n"
" inline bool has_name() const;\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also just add an __isl_bool isl_id_has_name() method and export it.

isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set);
__isl_export
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel these could be a separate commit. But let's worry about this when upstreaming.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used for tests.

" void *usr,\n"
" void (*deleter)(void *) = nullptr);\n"
" inline id(isl::ctx ctx, void *usr,\n"
" void (*deleter)(void *) = nullptr);\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions you choose look good. I am slightly afraid that pretty printing them like this won't fly. At the very least, the first one could be declared as C function and normally exposed. This would make sure that isl ids are also available in python.

Not sure about the other two. Do they make any sense in python? I mean, do we want to pass references to other python objects as user point? (A deleter certainly does not make sense)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather maintain a dict id->object separately. My recommendation would be to do so in C++, too. The only place where I need the user pointer is interacting with PPCG-generated schedule trees.

As a radical solution, we can hide the user pointer from C++ and python completely. If the user needs it, they can do access it by extracting a C isl_id and be thus "warned" that the underlying data is a C object.


static void reset_flag(void *user) {
*static_cast<int *>(user) = 0;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add this as a lambda function into the test function below?

@ftynse
Copy link
Member Author

ftynse commented Sep 1, 2017

What does "disallow unnamed ids by construction, ensure that ids remain value comparable mean"? It seems your third constructor allows to construct an unnamed id?

Yes, actually there should be an assert.

Just pretty printing the right bindings is a good idea for a first draft of the patch. However, this will prevent these function to exist on the python side of things. Also, I feel it would be slightly more in-style to just generate this stuff instead of pattern matching on the types. For this we should likely ask Sven for feedback. He has strong concerns about this.

I'd like to avoid modifying the existing public API. Changing something like id allocation seems to be a pretty large change. We could just export isl_id_alloc, but the resulting constructor does is not fully make sense in C++. Also, setting up a deleter along with the object looks cleaner.

User-pointers for python do not make sense. I'm not aware of any address guarantees for python objects, which are necessary to ensure uniqueness. So I would suggest to pretty-print the python class only with a name-based constructor. With these arguments, pattern-matching seems a worthy solution.

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 <git@ozinenko.com>
@ftynse
Copy link
Member Author

ftynse commented Sep 2, 2017

@TobiG
okay, I figured out how to make the CI run the tests: merge master to continuous-integration, then base PRs on that branch rather than master and request merging to it.
Anyway master is only updated from upstream and PRs are never merged here directly.

Would be nice to automate the process of pulling from the main repo and merging it into the continuous-integration branch.

@tobiasgrosser
Copy link
Member

Great. We should just commit the CI file to the main isl repo. That would make this work here out-of-the-box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants