Skip to content

Commit

Permalink
[mlir][Python] Add a simple PyOpOperand iterator for PyValue uses.
Browse files Browse the repository at this point in the history
This adds a simple PyOpOperand based on MlirOpOperand, which can has
properties for the owner op and operation number.

This also adds a PyOpOperandIterator that defines methods for __iter__
and __next__ so PyOpOperands can be iterated over using the the
MlirOpOperand C API.

Finally, a uses psuedo-container is added to PyValue so the uses can
generically be iterated.

Depends on D139596

Reviewed By: stellaraccident, jdd

Differential Revision: https://reviews.llvm.org/D139597
  • Loading branch information
mikeurbach committed Dec 14, 2022
1 parent b49d3e5 commit afb2ed8
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
56 changes: 56 additions & 0 deletions mlir/lib/Bindings/Python/IRCore.cpp
Expand Up @@ -447,6 +447,55 @@ class PyOperationList {
MlirBlock block;
};

class PyOpOperand {
public:
PyOpOperand(MlirOpOperand opOperand) : opOperand(opOperand) {}

py::object getOwner() {
MlirOperation owner = mlirOpOperandGetOwner(opOperand);
PyMlirContextRef context =
PyMlirContext::forContext(mlirOperationGetContext(owner));
return PyOperation::forOperation(context, owner)->createOpView();
}

size_t getOperandNumber() { return mlirOpOperandGetOperandNumber(opOperand); }

static void bind(py::module &m) {
py::class_<PyOpOperand>(m, "OpOperand", py::module_local())
.def_property_readonly("owner", &PyOpOperand::getOwner)
.def_property_readonly("operand_number",
&PyOpOperand::getOperandNumber);
}

private:
MlirOpOperand opOperand;
};

class PyOpOperandIterator {
public:
PyOpOperandIterator(MlirOpOperand opOperand) : opOperand(opOperand) {}

PyOpOperandIterator &dunderIter() { return *this; }

PyOpOperand dunderNext() {
if (mlirOpOperandIsNull(opOperand))
throw py::stop_iteration();

PyOpOperand returnOpOperand(opOperand);
opOperand = mlirOpOperandGetNextUse(opOperand);
return returnOpOperand;
}

static void bind(py::module &m) {
py::class_<PyOpOperandIterator>(m, "OpOperandIterator", py::module_local())
.def("__iter__", &PyOpOperandIterator::dunderIter)
.def("__next__", &PyOpOperandIterator::dunderNext);
}

private:
MlirOpOperand opOperand;
};

} // namespace

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -3156,6 +3205,11 @@ void mlir::python::populateIRCore(py::module &m) {
assert(false && "Value must be a block argument or an op result");
return py::none();
})
.def_property_readonly("uses",
[](PyValue &self) {
return PyOpOperandIterator(
mlirValueGetFirstUse(self.get()));
})
.def("__eq__",
[](PyValue &self, PyValue &other) {
return self.get().ptr == other.get().ptr;
Expand All @@ -3182,6 +3236,7 @@ void mlir::python::populateIRCore(py::module &m) {
});
PyBlockArgument::bind(m);
PyOpResult::bind(m);
PyOpOperand::bind(m);

//----------------------------------------------------------------------------
// Mapping of SymbolTable.
Expand Down Expand Up @@ -3220,6 +3275,7 @@ void mlir::python::populateIRCore(py::module &m) {
PyOperationIterator::bind(m);
PyOperationList::bind(m);
PyOpAttributeMap::bind(m);
PyOpOperandIterator::bind(m);
PyOpOperandList::bind(m);
PyOpResultList::bind(m);
PyRegionIterator::bind(m);
Expand Down
22 changes: 22 additions & 0 deletions mlir/test/python/ir/value.py
Expand Up @@ -89,3 +89,25 @@ def testValueHash():
op, ret = block.operations
assert hash(block.arguments[0]) == hash(op.operands[0])
assert hash(op.result) == hash(ret.operands[0])

# CHECK-LABEL: TEST: testValueUses
@run
def testValueUses():
ctx = Context()
ctx.allow_unregistered_dialects = True
with Location.unknown(ctx):
i32 = IntegerType.get_signless(32)
module = Module.create()
with InsertionPoint(module.body):
value = Operation.create("custom.op1", results=[i32]).results[0]
op1 = Operation.create("custom.op2", operands=[value])
op2 = Operation.create("custom.op2", operands=[value])

# CHECK: Use owner: "custom.op2"
# CHECK: Use operand_number: 0
# CHECK: Use owner: "custom.op2"
# CHECK: Use operand_number: 0
for use in value.uses:
assert use.owner in [op1, op2]
print(f"Use owner: {use.owner}")
print(f"Use operand_number: {use.operand_number}")

0 comments on commit afb2ed8

Please sign in to comment.