This is an archive of the discontinued LLVM Phabricator instance.

Add Operation to python bindings.
ClosedPublic

Authored by stellaraccident on Sep 18 2020, 6:48 PM.

Details

Summary
  • Fixes a rather egregious bug with respect to the inability to return arbitrary objects from py::init (was causing aliasing of multiple py::object -> native instance).
  • Makes Modules and Operations referencable types so that they can be reliably depended on.
  • Uniques python operation instances within a context. Opens the door for further accounting.
  • Next I will retrofit region and block to be dependent on the operation, and I will attempt to model the API to avoid detached regions/blocks, which will simplify things a lot (in that world, only operations can be detached).
  • Added quite a bit of test coverage to check for leaks and reference issues.
  • Supercedes: https://reviews.llvm.org/D87213

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald Transcript
stellaraccident requested review of this revision.Sep 18 2020, 6:48 PM
bondhugula added inline comments.
mlir/lib/Bindings/Python/IRModules.cpp
283

Can drop the else.

295–299

There's too much use of auto at the expense of readability - hard to tell the types. If not too long, please spell out the types.

296

Assert message please.

stellaraccident marked 3 inline comments as done.

Comments and rebase.

zhanghb97 added inline comments.Sep 20 2020, 7:54 PM
mlir/lib/Bindings/Python/IRModules.h
132

Why only living operations is recorded here, not others (like modules, attributes, types, etc.)? Should this way be used to record living objects in blocks and regions?

mlir/lib/Bindings/Python/IRModules.h
132

I'm being pretty explicit to only add accounting where there is an ownership complexity that requires it. The question comes down to which entities in the hierarchy must not alias to (potentially) multiple objects on the python side. For those where such aliasing is benign, I opted to not maintain a strict correlation, instead implementing __eq__ so that == reports them as equal, which I believe, is good enough for most.

Examples: IntegerType.get(ctx, 32) == IntegerType.get(ctx, 32)

This does mean that strict reference equality like IntegerType(ctx, 32) is IntegerType(ctx, 32) will return False. This is likely ok. We may also want to implement __hash__ on them all so that they work correctly in dicts, etc.

See D87982 and D87982 for where I took the Operation implementation. In short, PyOperation is the owner for regions and blocks and needs to be a top-level "ref" type that we can count on not aliasing. This will let us do things like selectively invalidate instances when mutations occur without worrying that there is some alias to the same operation in the hierarchy. Operations are also the only entity that I allow to be in a detached state. The C/C++ API allows this for Region/Block, but it simplified the ownership model a lot to eliminate that possibility in this API, and then it allows us to make the Region/Block completely dependent on its owning operation for accounting. Again, the aliasing is benign so I didn't worry about it.

If we ever want to re-introduce detached regions/blocks, we could do so with new "DetachedRegion" class or similar and also avoid the complexity of accounting. With the way I have it now, I think we can avoid having a global live list for regions and blocks. We may end up needing an op-local one at some point TBD, depending on how hard it is to guarantee how mutations interact with their Python peer objects. We can cross that bridge easily when we get there, imo.

Module, when used purely from the Python API, can't alias anyway, so we can use it as a unique ref type without worry. If the API ever changes such that this cannot be guaranteed (i.e. by letting you marshal a native-defined Module in), then there would need to be a live table for it too.

zhanghb97 accepted this revision.Sep 21 2020, 2:03 AM

LGTM, thanks!

This revision is now accepted and ready to land.Sep 21 2020, 2:03 AM
ftynse accepted this revision.Sep 23 2020, 3:58 AM
ftynse added inline comments.
mlir/lib/Bindings/Python/IRModules.h
29–48

Is this default constructor necessary?

56

return std::move makes me tick, and clang-tidy will complain about it preventing copy elision. I understand it is intentional here so that we always steal the underlying PyObject without changing its reference count, but it is likely worth a comment.

132

We may also want to implement hash on them all so that they work correctly in dicts, etc.

It should be possible to just forward this to LLVM's hashing for all context-owned types.

See D87982 and D87982 for where I took the Operation implementation. In short, PyOperation is the owner for regions and blocks and needs to be a top-level "ref" type that we can count on not aliasing. This will let us do things like selectively invalidate instances when mutations occur without worrying that there is some alias to the same operation in the hierarchy.

Starting from this line, it's a great rationale. Could you move it to the documentation?

200

I'm confused here about what is a parent to what else.

stellaraccident marked 5 inline comments as done.Sep 23 2020, 7:36 AM
stellaraccident added inline comments.
mlir/lib/Bindings/Python/IRModules.h
29–48

Good catch - not anymore. Leftover from some dinking with it.

56

Changed to:

auto stolen = std::move(object);
return stolen;

I think clang-tidy doesn't complain about moving an instance variable, but better to be explicit since this is so often flagged as an anti-pattern.

132

Added a section to the bindings doc and expanded on this explanation regarding ownership and the operation hierarchy. Feel free to comment and I'll update post-submit.

200

I've chopped this down and also added a todo on the parentKeepAlive member. I need to address this part in a followup to fully generalize the detached->attached transition. The docs I added do outline the intended design - this implementation just isn't there yet.

stellaraccident marked 4 inline comments as done.

Address comments

This revision was landed with ongoing or failed builds.Sep 23 2020, 7:59 AM
This revision was automatically updated to reflect the committed changes.