llvm-project/mlir/test/python/live_operations.py
Oleksandr "Alex" Zinenko 67897d77ed
[mlir][py] invalidate nested operations when parent is deleted (#93339)
When an operation is erased in Python, its children may still be in the
"live" list inside Python bindings. After this, if some of the newly
allocated operations happen to reuse the same pointer address, this will
trigger an assertion in the bindings. This assertion would be incorrect
because the operations aren't actually live. Make sure we remove the
children operations from the "live" list when erasing the parent.

This also concentrates responsibility over the removal from the "live"
list and invalidation in a single place.

Note that this requires the IR to be sufficiently structurally valid so
a walk through it can succeed. If this invariant was broken by, e.g, C++
pass called from Python, there isn't much we can do.
2024-05-30 10:06:02 +02:00

47 lines
1.9 KiB
Python

# RUN: %PYTHON %s
# It is sufficient that this doesn't assert.
from mlir.ir import *
def createDetachedModule():
module = Module.create()
with InsertionPoint(module.body):
# TODO: Python bindings are currently unaware that modules are also
# operations, so having a module erased won't trigger the cascading
# removal of live operations (#93337). Use a non-module operation
# instead.
nested = Operation.create("test.some_operation", regions=1)
# When the operation is detached from parent, it is considered to be
# owned by Python. It will therefore be erased when the Python object
# is destroyed.
nested.detach_from_parent()
# However, we create and maintain references to operations within
# `nested`. These references keep the corresponding operations in the
# "live" list even if they have been erased in C++, making them
# "zombie". If the C++ allocator reuses one of the address previously
# used for a now-"zombie" operation, this used to result in an
# assertion "cannot create detached operation that already exists" from
# the bindings code. Erasing the detached operation should result in
# removing all nested operations from the live list.
#
# Note that the assertion is not guaranteed since it depends on the
# behavior of the allocator on the C++ side, so this test mail fail
# intermittently.
with InsertionPoint(nested.regions[0].blocks.append()):
a = [Operation.create("test.some_other_operation") for i in range(100)]
return a
def createManyDetachedModules():
with Context() as ctx, Location.unknown():
ctx.allow_unregistered_dialects = True
for j in range(100):
a = createDetachedModule()
if __name__ == "__main__":
createManyDetachedModules()