-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[MLIR][Python][NO MERGE] Support Python-defined passes in MLIR #157369
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
[MLIR][Python][NO MERGE] Support Python-defined passes in MLIR #157369
Conversation
5289c12
to
4b1213f
Compare
786c2ee
to
1e0d2d2
Compare
mlir/lib/Bindings/Python/Pass.cpp
Outdated
auto src = nb::handle(static_cast<PyObject *>(obj)); | ||
nb::callable dst; | ||
nb::inst_copy(dst, src); | ||
return static_cast<void *>(dst.ptr()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the only part i'm not 100% on: i'm not sure if inst_copy
copies the ref count or what (and whether construct
is called before or after). need to find a way to test this path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah clone
is quite tricky since in the python side I'm not sure how to call it : )
From the code, it seems that we first call callback.clone
, and then call callback.construct
in constructing an ExternalPass
, so maybe here the pointer dst.ptr()
will be dangling since the nb::callable
is destructed (callable::~callable
is called) and the ref_count become 0?
I think it is related to whether we inc_ref
in the callback.construct
. Maybe we can have such a design:
- in
callback.construct
we do not callinc_ref
, it leaves to who pass the object into theExternalPass
; - in
callback.clone
, we first callinc_ref
and then pass the object (call.release()
to prevent thenb::object::~object
from decreasing the ref count), so that the ref count of this object can be 1, and incallback.destruct
it is decreased to 0 and destructed; - before the call to
mlirCreateExternalPass
, we first callinc_ref
for the object to increase the ref count so that it should be valid at least beforecallback.destruct
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so maybe here the pointer dst.ptr() will be dangling since the nb::callable is destructed
Seems not possible since the tests pass? Are you sure that clone is called for our use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The patch sounds good to me and definitely much cleaner and simpler than mine! I'll try to merge it into my PR. Just left a few minor comments to discuss some details.
mlir/lib/Bindings/Python/Pass.cpp
Outdated
[](PyPassManager &passManager, const std::string &name, | ||
const std::string &argument, const std::string &description, | ||
const std::string &opName, const nb::callable &run) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible maybe we can make argument
, description
and opName
keyword arguments? So that we can use it like pm.add_python_pass(name, run)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya 100% that's a good idea (like you have in your PR). But I don't think you actually need to make them kw - you just have to make them have default args. Anyway either form is good with me.
mlir/lib/Bindings/Python/Pass.cpp
Outdated
auto src = nb::handle(static_cast<PyObject *>(obj)); | ||
nb::callable dst; | ||
nb::inst_copy(dst, src); | ||
return static_cast<void *>(dst.ptr()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah clone
is quite tricky since in the python side I'm not sure how to call it : )
From the code, it seems that we first call callback.clone
, and then call callback.construct
in constructing an ExternalPass
, so maybe here the pointer dst.ptr()
will be dangling since the nb::callable
is destructed (callable::~callable
is called) and the ref_count become 0?
I think it is related to whether we inc_ref
in the callback.construct
. Maybe we can have such a design:
- in
callback.construct
we do not callinc_ref
, it leaves to who pass the object into theExternalPass
; - in
callback.clone
, we first callinc_ref
and then pass the object (call.release()
to prevent thenb::object::~object
from decreasing the ref count), so that the ref count of this object can be 1, and incallback.destruct
it is decreased to 0 and destructed; - before the call to
mlirCreateExternalPass
, we first callinc_ref
for the object to increase the ref count so that it should be valid at least beforecallback.destruct
.
e7034be
to
982a52f
Compare
based heavily on llvm#156000
982a52f
to
968b50b
Compare
Co-authored-by: Maksim Levental <[email protected]>
based heavily on #156000