in mlir/lib/Bindings/Python/IRCore.cpp [2149:3100]
void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// Enums.
//----------------------------------------------------------------------------
py::enum_<MlirDiagnosticSeverity>(m, "DiagnosticSeverity", py::module_local())
.value("ERROR", MlirDiagnosticError)
.value("WARNING", MlirDiagnosticWarning)
.value("NOTE", MlirDiagnosticNote)
.value("REMARK", MlirDiagnosticRemark);
//----------------------------------------------------------------------------
// Mapping of Diagnostics.
//----------------------------------------------------------------------------
py::class_<PyDiagnostic>(m, "Diagnostic", py::module_local())
.def_property_readonly("severity", &PyDiagnostic::getSeverity)
.def_property_readonly("location", &PyDiagnostic::getLocation)
.def_property_readonly("message", &PyDiagnostic::getMessage)
.def_property_readonly("notes", &PyDiagnostic::getNotes)
.def("__str__", [](PyDiagnostic &self) -> py::str {
if (!self.isValid())
return "<Invalid Diagnostic>";
return self.getMessage();
});
py::class_<PyDiagnosticHandler>(m, "DiagnosticHandler", py::module_local())
.def("detach", &PyDiagnosticHandler::detach)
.def_property_readonly("attached", &PyDiagnosticHandler::isAttached)
.def_property_readonly("had_error", &PyDiagnosticHandler::getHadError)
.def("__enter__", &PyDiagnosticHandler::contextEnter)
.def("__exit__", &PyDiagnosticHandler::contextExit);
//----------------------------------------------------------------------------
// Mapping of MlirContext.
//----------------------------------------------------------------------------
py::class_<PyMlirContext>(m, "Context", py::module_local())
.def(py::init<>(&PyMlirContext::createNewContextForInit))
.def_static("_get_live_count", &PyMlirContext::getLiveCount)
.def("_get_context_again",
[](PyMlirContext &self) {
PyMlirContextRef ref = PyMlirContext::forContext(self.get());
return ref.releaseObject();
})
.def("_get_live_operation_count", &PyMlirContext::getLiveOperationCount)
.def("_get_live_module_count", &PyMlirContext::getLiveModuleCount)
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
&PyMlirContext::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyMlirContext::createFromCapsule)
.def("__enter__", &PyMlirContext::contextEnter)
.def("__exit__", &PyMlirContext::contextExit)
.def_property_readonly_static(
"current",
[](py::object & /*class*/) {
auto *context = PyThreadContextEntry::getDefaultContext();
if (!context)
throw SetPyError(PyExc_ValueError, "No current Context");
return context;
},
"Gets the Context bound to the current thread or raises ValueError")
.def_property_readonly(
"dialects",
[](PyMlirContext &self) { return PyDialects(self.getRef()); },
"Gets a container for accessing dialects by name")
.def_property_readonly(
"d", [](PyMlirContext &self) { return PyDialects(self.getRef()); },
"Alias for 'dialect'")
.def(
"get_dialect_descriptor",
[=](PyMlirContext &self, std::string &name) {
MlirDialect dialect = mlirContextGetOrLoadDialect(
self.get(), {name.data(), name.size()});
if (mlirDialectIsNull(dialect)) {
throw SetPyError(PyExc_ValueError,
Twine("Dialect '") + name + "' not found");
}
return PyDialectDescriptor(self.getRef(), dialect);
},
py::arg("dialect_name"),
"Gets or loads a dialect by name, returning its descriptor object")
.def_property(
"allow_unregistered_dialects",
[](PyMlirContext &self) -> bool {
return mlirContextGetAllowUnregisteredDialects(self.get());
},
[](PyMlirContext &self, bool value) {
mlirContextSetAllowUnregisteredDialects(self.get(), value);
})
.def("attach_diagnostic_handler", &PyMlirContext::attachDiagnosticHandler,
py::arg("callback"),
"Attaches a diagnostic handler that will receive callbacks")
.def(
"enable_multithreading",
[](PyMlirContext &self, bool enable) {
mlirContextEnableMultithreading(self.get(), enable);
},
py::arg("enable"))
.def(
"is_registered_operation",
[](PyMlirContext &self, std::string &name) {
return mlirContextIsRegisteredOperation(
self.get(), MlirStringRef{name.data(), name.size()});
},
py::arg("operation_name"));
//----------------------------------------------------------------------------
// Mapping of PyDialectDescriptor
//----------------------------------------------------------------------------
py::class_<PyDialectDescriptor>(m, "DialectDescriptor", py::module_local())
.def_property_readonly("namespace",
[](PyDialectDescriptor &self) {
MlirStringRef ns =
mlirDialectGetNamespace(self.get());
return py::str(ns.data, ns.length);
})
.def("__repr__", [](PyDialectDescriptor &self) {
MlirStringRef ns = mlirDialectGetNamespace(self.get());
std::string repr("<DialectDescriptor ");
repr.append(ns.data, ns.length);
repr.append(">");
return repr;
});
//----------------------------------------------------------------------------
// Mapping of PyDialects
//----------------------------------------------------------------------------
py::class_<PyDialects>(m, "Dialects", py::module_local())
.def("__getitem__",
[=](PyDialects &self, std::string keyName) {
MlirDialect dialect =
self.getDialectForKey(keyName, /*attrError=*/false);
py::object descriptor =
py::cast(PyDialectDescriptor{self.getContext(), dialect});
return createCustomDialectWrapper(keyName, std::move(descriptor));
})
.def("__getattr__", [=](PyDialects &self, std::string attrName) {
MlirDialect dialect =
self.getDialectForKey(attrName, /*attrError=*/true);
py::object descriptor =
py::cast(PyDialectDescriptor{self.getContext(), dialect});
return createCustomDialectWrapper(attrName, std::move(descriptor));
});
//----------------------------------------------------------------------------
// Mapping of PyDialect
//----------------------------------------------------------------------------
py::class_<PyDialect>(m, "Dialect", py::module_local())
.def(py::init<py::object>(), py::arg("descriptor"))
.def_property_readonly(
"descriptor", [](PyDialect &self) { return self.getDescriptor(); })
.def("__repr__", [](py::object self) {
auto clazz = self.attr("__class__");
return py::str("<Dialect ") +
self.attr("descriptor").attr("namespace") + py::str(" (class ") +
clazz.attr("__module__") + py::str(".") +
clazz.attr("__name__") + py::str(")>");
});
//----------------------------------------------------------------------------
// Mapping of Location
//----------------------------------------------------------------------------
py::class_<PyLocation>(m, "Location", py::module_local())
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyLocation::createFromCapsule)
.def("__enter__", &PyLocation::contextEnter)
.def("__exit__", &PyLocation::contextExit)
.def("__eq__",
[](PyLocation &self, PyLocation &other) -> bool {
return mlirLocationEqual(self, other);
})
.def("__eq__", [](PyLocation &self, py::object other) { return false; })
.def_property_readonly_static(
"current",
[](py::object & /*class*/) {
auto *loc = PyThreadContextEntry::getDefaultLocation();
if (!loc)
throw SetPyError(PyExc_ValueError, "No current Location");
return loc;
},
"Gets the Location bound to the current thread or raises ValueError")
.def_static(
"unknown",
[](DefaultingPyMlirContext context) {
return PyLocation(context->getRef(),
mlirLocationUnknownGet(context->get()));
},
py::arg("context") = py::none(),
"Gets a Location representing an unknown location")
.def_static(
"callsite",
[](PyLocation callee, const std::vector<PyLocation> &frames,
DefaultingPyMlirContext context) {
if (frames.empty())
throw py::value_error("No caller frames provided");
MlirLocation caller = frames.back().get();
for (const PyLocation &frame :
llvm::reverse(llvm::makeArrayRef(frames).drop_back()))
caller = mlirLocationCallSiteGet(frame.get(), caller);
return PyLocation(context->getRef(),
mlirLocationCallSiteGet(callee.get(), caller));
},
py::arg("callee"), py::arg("frames"), py::arg("context") = py::none(),
kContextGetCallSiteLocationDocstring)
.def_static(
"file",
[](std::string filename, int line, int col,
DefaultingPyMlirContext context) {
return PyLocation(
context->getRef(),
mlirLocationFileLineColGet(
context->get(), toMlirStringRef(filename), line, col));
},
py::arg("filename"), py::arg("line"), py::arg("col"),
py::arg("context") = py::none(), kContextGetFileLocationDocstring)
.def_static(
"fused",
[](const std::vector<PyLocation> &pyLocations,
llvm::Optional<PyAttribute> metadata,
DefaultingPyMlirContext context) {
llvm::SmallVector<MlirLocation, 4> locations;
locations.reserve(pyLocations.size());
for (auto &pyLocation : pyLocations)
locations.push_back(pyLocation.get());
MlirLocation location = mlirLocationFusedGet(
context->get(), locations.size(), locations.data(),
metadata ? metadata->get() : MlirAttribute{0});
return PyLocation(context->getRef(), location);
},
py::arg("locations"), py::arg("metadata") = py::none(),
py::arg("context") = py::none(), kContextGetFusedLocationDocstring)
.def_static(
"name",
[](std::string name, llvm::Optional<PyLocation> childLoc,
DefaultingPyMlirContext context) {
return PyLocation(
context->getRef(),
mlirLocationNameGet(
context->get(), toMlirStringRef(name),
childLoc ? childLoc->get()
: mlirLocationUnknownGet(context->get())));
},
py::arg("name"), py::arg("childLoc") = py::none(),
py::arg("context") = py::none(), kContextGetNameLocationDocString)
.def_property_readonly(
"context",
[](PyLocation &self) { return self.getContext().getObject(); },
"Context that owns the Location")
.def(
"emit_error",
[](PyLocation &self, std::string message) {
mlirEmitError(self, message.c_str());
},
py::arg("message"), "Emits an error at this location")
.def("__repr__", [](PyLocation &self) {
PyPrintAccumulator printAccum;
mlirLocationPrint(self, printAccum.getCallback(),
printAccum.getUserData());
return printAccum.join();
});
//----------------------------------------------------------------------------
// Mapping of Module
//----------------------------------------------------------------------------
py::class_<PyModule>(m, "Module", py::module_local())
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyModule::createFromCapsule)
.def_static(
"parse",
[](const std::string moduleAsm, DefaultingPyMlirContext context) {
MlirModule module = mlirModuleCreateParse(
context->get(), toMlirStringRef(moduleAsm));
// TODO: Rework error reporting once diagnostic engine is exposed
// in C API.
if (mlirModuleIsNull(module)) {
throw SetPyError(
PyExc_ValueError,
"Unable to parse module assembly (see diagnostics)");
}
return PyModule::forModule(module).releaseObject();
},
py::arg("asm"), py::arg("context") = py::none(),
kModuleParseDocstring)
.def_static(
"create",
[](DefaultingPyLocation loc) {
MlirModule module = mlirModuleCreateEmpty(loc);
return PyModule::forModule(module).releaseObject();
},
py::arg("loc") = py::none(), "Creates an empty module")
.def_property_readonly(
"context",
[](PyModule &self) { return self.getContext().getObject(); },
"Context that created the Module")
.def_property_readonly(
"operation",
[](PyModule &self) {
return PyOperation::forOperation(self.getContext(),
mlirModuleGetOperation(self.get()),
self.getRef().releaseObject())
.releaseObject();
},
"Accesses the module as an operation")
.def_property_readonly(
"body",
[](PyModule &self) {
PyOperationRef moduleOp = PyOperation::forOperation(
self.getContext(), mlirModuleGetOperation(self.get()),
self.getRef().releaseObject());
PyBlock returnBlock(moduleOp, mlirModuleGetBody(self.get()));
return returnBlock;
},
"Return the block for this module")
.def(
"dump",
[](PyModule &self) {
mlirOperationDump(mlirModuleGetOperation(self.get()));
},
kDumpDocstring)
.def(
"__str__",
[](py::object self) {
// Defer to the operation's __str__.
return self.attr("operation").attr("__str__")();
},
kOperationStrDunderDocstring);
//----------------------------------------------------------------------------
// Mapping of Operation.
//----------------------------------------------------------------------------
py::class_<PyOperationBase>(m, "_OperationBase", py::module_local())
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
[](PyOperationBase &self) {
return self.getOperation().getCapsule();
})
.def("__eq__",
[](PyOperationBase &self, PyOperationBase &other) {
return &self.getOperation() == &other.getOperation();
})
.def("__eq__",
[](PyOperationBase &self, py::object other) { return false; })
.def("__hash__",
[](PyOperationBase &self) {
return static_cast<size_t>(llvm::hash_value(&self.getOperation()));
})
.def_property_readonly("attributes",
[](PyOperationBase &self) {
return PyOpAttributeMap(
self.getOperation().getRef());
})
.def_property_readonly("operands",
[](PyOperationBase &self) {
return PyOpOperandList(
self.getOperation().getRef());
})
.def_property_readonly("regions",
[](PyOperationBase &self) {
return PyRegionList(
self.getOperation().getRef());
})
.def_property_readonly(
"results",
[](PyOperationBase &self) {
return PyOpResultList(self.getOperation().getRef());
},
"Returns the list of Operation results.")
.def_property_readonly(
"result",
[](PyOperationBase &self) {
auto &operation = self.getOperation();
auto numResults = mlirOperationGetNumResults(operation);
if (numResults != 1) {
auto name = mlirIdentifierStr(mlirOperationGetName(operation));
throw SetPyError(
PyExc_ValueError,
Twine("Cannot call .result on operation ") +
StringRef(name.data, name.length) + " which has " +
Twine(numResults) +
" results (it is only valid for operations with a "
"single result)");
}
return PyOpResult(operation.getRef(),
mlirOperationGetResult(operation, 0));
},
"Shortcut to get an op result if it has only one (throws an error "
"otherwise).")
.def_property_readonly(
"location",
[](PyOperationBase &self) {
PyOperation &operation = self.getOperation();
return PyLocation(operation.getContext(),
mlirOperationGetLocation(operation.get()));
},
"Returns the source location the operation was defined or derived "
"from.")
.def(
"__str__",
[](PyOperationBase &self) {
return self.getAsm(/*binary=*/false,
/*largeElementsLimit=*/llvm::None,
/*enableDebugInfo=*/false,
/*prettyDebugInfo=*/false,
/*printGenericOpForm=*/false,
/*useLocalScope=*/false,
/*assumeVerified=*/false);
},
"Returns the assembly form of the operation.")
.def("print", &PyOperationBase::print,
// Careful: Lots of arguments must match up with print method.
py::arg("file") = py::none(), py::arg("binary") = false,
py::arg("large_elements_limit") = py::none(),
py::arg("enable_debug_info") = false,
py::arg("pretty_debug_info") = false,
py::arg("print_generic_op_form") = false,
py::arg("use_local_scope") = false,
py::arg("assume_verified") = false, kOperationPrintDocstring)
.def("get_asm", &PyOperationBase::getAsm,
// Careful: Lots of arguments must match up with get_asm method.
py::arg("binary") = false,
py::arg("large_elements_limit") = py::none(),
py::arg("enable_debug_info") = false,
py::arg("pretty_debug_info") = false,
py::arg("print_generic_op_form") = false,
py::arg("use_local_scope") = false,
py::arg("assume_verified") = false, kOperationGetAsmDocstring)
.def(
"verify",
[](PyOperationBase &self) {
return mlirOperationVerify(self.getOperation());
},
"Verify the operation and return true if it passes, false if it "
"fails.")
.def("move_after", &PyOperationBase::moveAfter, py::arg("other"),
"Puts self immediately after the other operation in its parent "
"block.")
.def("move_before", &PyOperationBase::moveBefore, py::arg("other"),
"Puts self immediately before the other operation in its parent "
"block.")
.def(
"detach_from_parent",
[](PyOperationBase &self) {
PyOperation &operation = self.getOperation();
operation.checkValid();
if (!operation.isAttached())
throw py::value_error("Detached operation has no parent.");
operation.detachFromParent();
return operation.createOpView();
},
"Detaches the operation from its parent block.");
py::class_<PyOperation, PyOperationBase>(m, "Operation", py::module_local())
.def_static("create", &PyOperation::create, py::arg("name"),
py::arg("results") = py::none(),
py::arg("operands") = py::none(),
py::arg("attributes") = py::none(),
py::arg("successors") = py::none(), py::arg("regions") = 0,
py::arg("loc") = py::none(), py::arg("ip") = py::none(),
kOperationCreateDocstring)
.def_property_readonly("parent",
[](PyOperation &self) -> py::object {
auto parent = self.getParentOperation();
if (parent)
return parent->getObject();
return py::none();
})
.def("erase", &PyOperation::erase)
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
&PyOperation::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyOperation::createFromCapsule)
.def_property_readonly("name",
[](PyOperation &self) {
self.checkValid();
MlirOperation operation = self.get();
MlirStringRef name = mlirIdentifierStr(
mlirOperationGetName(operation));
return py::str(name.data, name.length);
})
.def_property_readonly(
"context",
[](PyOperation &self) {
self.checkValid();
return self.getContext().getObject();
},
"Context that owns the Operation")
.def_property_readonly("opview", &PyOperation::createOpView);
auto opViewClass =
py::class_<PyOpView, PyOperationBase>(m, "OpView", py::module_local())
.def(py::init<py::object>(), py::arg("operation"))
.def_property_readonly("operation", &PyOpView::getOperationObject)
.def_property_readonly(
"context",
[](PyOpView &self) {
return self.getOperation().getContext().getObject();
},
"Context that owns the Operation")
.def("__str__", [](PyOpView &self) {
return py::str(self.getOperationObject());
});
opViewClass.attr("_ODS_REGIONS") = py::make_tuple(0, true);
opViewClass.attr("_ODS_OPERAND_SEGMENTS") = py::none();
opViewClass.attr("_ODS_RESULT_SEGMENTS") = py::none();
opViewClass.attr("build_generic") = classmethod(
&PyOpView::buildGeneric, py::arg("cls"), py::arg("results") = py::none(),
py::arg("operands") = py::none(), py::arg("attributes") = py::none(),
py::arg("successors") = py::none(), py::arg("regions") = py::none(),
py::arg("loc") = py::none(), py::arg("ip") = py::none(),
"Builds a specific, generated OpView based on class level attributes.");
//----------------------------------------------------------------------------
// Mapping of PyRegion.
//----------------------------------------------------------------------------
py::class_<PyRegion>(m, "Region", py::module_local())
.def_property_readonly(
"blocks",
[](PyRegion &self) {
return PyBlockList(self.getParentOperation(), self.get());
},
"Returns a forward-optimized sequence of blocks.")
.def_property_readonly(
"owner",
[](PyRegion &self) {
return self.getParentOperation()->createOpView();
},
"Returns the operation owning this region.")
.def(
"__iter__",
[](PyRegion &self) {
self.checkValid();
MlirBlock firstBlock = mlirRegionGetFirstBlock(self.get());
return PyBlockIterator(self.getParentOperation(), firstBlock);
},
"Iterates over blocks in the region.")
.def("__eq__",
[](PyRegion &self, PyRegion &other) {
return self.get().ptr == other.get().ptr;
})
.def("__eq__", [](PyRegion &self, py::object &other) { return false; });
//----------------------------------------------------------------------------
// Mapping of PyBlock.
//----------------------------------------------------------------------------
py::class_<PyBlock>(m, "Block", py::module_local())
.def_property_readonly(
"owner",
[](PyBlock &self) {
return self.getParentOperation()->createOpView();
},
"Returns the owning operation of this block.")
.def_property_readonly(
"region",
[](PyBlock &self) {
MlirRegion region = mlirBlockGetParentRegion(self.get());
return PyRegion(self.getParentOperation(), region);
},
"Returns the owning region of this block.")
.def_property_readonly(
"arguments",
[](PyBlock &self) {
return PyBlockArgumentList(self.getParentOperation(), self.get());
},
"Returns a list of block arguments.")
.def_property_readonly(
"operations",
[](PyBlock &self) {
return PyOperationList(self.getParentOperation(), self.get());
},
"Returns a forward-optimized sequence of operations.")
.def_static(
"create_at_start",
[](PyRegion &parent, py::list pyArgTypes) {
parent.checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
argTypes.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
}
MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
mlirRegionInsertOwnedBlock(parent, 0, block);
return PyBlock(parent.getParentOperation(), block);
},
py::arg("parent"), py::arg("arg_types") = py::list(),
"Creates and returns a new Block at the beginning of the given "
"region (with given argument types).")
.def(
"create_before",
[](PyBlock &self, py::args pyArgTypes) {
self.checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
argTypes.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
}
MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
MlirRegion region = mlirBlockGetParentRegion(self.get());
mlirRegionInsertOwnedBlockBefore(region, self.get(), block);
return PyBlock(self.getParentOperation(), block);
},
"Creates and returns a new Block before this block "
"(with given argument types).")
.def(
"create_after",
[](PyBlock &self, py::args pyArgTypes) {
self.checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
argTypes.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
}
MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
MlirRegion region = mlirBlockGetParentRegion(self.get());
mlirRegionInsertOwnedBlockAfter(region, self.get(), block);
return PyBlock(self.getParentOperation(), block);
},
"Creates and returns a new Block after this block "
"(with given argument types).")
.def(
"__iter__",
[](PyBlock &self) {
self.checkValid();
MlirOperation firstOperation =
mlirBlockGetFirstOperation(self.get());
return PyOperationIterator(self.getParentOperation(),
firstOperation);
},
"Iterates over operations in the block.")
.def("__eq__",
[](PyBlock &self, PyBlock &other) {
return self.get().ptr == other.get().ptr;
})
.def("__eq__", [](PyBlock &self, py::object &other) { return false; })
.def(
"__str__",
[](PyBlock &self) {
self.checkValid();
PyPrintAccumulator printAccum;
mlirBlockPrint(self.get(), printAccum.getCallback(),
printAccum.getUserData());
return printAccum.join();
},
"Returns the assembly form of the block.")
.def(
"append",
[](PyBlock &self, PyOperationBase &operation) {
if (operation.getOperation().isAttached())
operation.getOperation().detachFromParent();
MlirOperation mlirOperation = operation.getOperation().get();
mlirBlockAppendOwnedOperation(self.get(), mlirOperation);
operation.getOperation().setAttached(
self.getParentOperation().getObject());
},
py::arg("operation"),
"Appends an operation to this block. If the operation is currently "
"in another block, it will be moved.");
//----------------------------------------------------------------------------
// Mapping of PyInsertionPoint.
//----------------------------------------------------------------------------
py::class_<PyInsertionPoint>(m, "InsertionPoint", py::module_local())
.def(py::init<PyBlock &>(), py::arg("block"),
"Inserts after the last operation but still inside the block.")
.def("__enter__", &PyInsertionPoint::contextEnter)
.def("__exit__", &PyInsertionPoint::contextExit)
.def_property_readonly_static(
"current",
[](py::object & /*class*/) {
auto *ip = PyThreadContextEntry::getDefaultInsertionPoint();
if (!ip)
throw SetPyError(PyExc_ValueError, "No current InsertionPoint");
return ip;
},
"Gets the InsertionPoint bound to the current thread or raises "
"ValueError if none has been set")
.def(py::init<PyOperationBase &>(), py::arg("beforeOperation"),
"Inserts before a referenced operation.")
.def_static("at_block_begin", &PyInsertionPoint::atBlockBegin,
py::arg("block"), "Inserts at the beginning of the block.")
.def_static("at_block_terminator", &PyInsertionPoint::atBlockTerminator,
py::arg("block"), "Inserts before the block terminator.")
.def("insert", &PyInsertionPoint::insert, py::arg("operation"),
"Inserts an operation.")
.def_property_readonly(
"block", [](PyInsertionPoint &self) { return self.getBlock(); },
"Returns the block that this InsertionPoint points to.");
//----------------------------------------------------------------------------
// Mapping of PyAttribute.
//----------------------------------------------------------------------------
py::class_<PyAttribute>(m, "Attribute", py::module_local())
// Delegate to the PyAttribute copy constructor, which will also lifetime
// extend the backing context which owns the MlirAttribute.
.def(py::init<PyAttribute &>(), py::arg("cast_from_type"),
"Casts the passed attribute to the generic Attribute")
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
&PyAttribute::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAttribute::createFromCapsule)
.def_static(
"parse",
[](std::string attrSpec, DefaultingPyMlirContext context) {
MlirAttribute type = mlirAttributeParseGet(
context->get(), toMlirStringRef(attrSpec));
// TODO: Rework error reporting once diagnostic engine is exposed
// in C API.
if (mlirAttributeIsNull(type)) {
throw SetPyError(PyExc_ValueError,
Twine("Unable to parse attribute: '") +
attrSpec + "'");
}
return PyAttribute(context->getRef(), type);
},
py::arg("asm"), py::arg("context") = py::none(),
"Parses an attribute from an assembly form")
.def_property_readonly(
"context",
[](PyAttribute &self) { return self.getContext().getObject(); },
"Context that owns the Attribute")
.def_property_readonly("type",
[](PyAttribute &self) {
return PyType(self.getContext()->getRef(),
mlirAttributeGetType(self));
})
.def(
"get_named",
[](PyAttribute &self, std::string name) {
return PyNamedAttribute(self, std::move(name));
},
py::keep_alive<0, 1>(), "Binds a name to the attribute")
.def("__eq__",
[](PyAttribute &self, PyAttribute &other) { return self == other; })
.def("__eq__", [](PyAttribute &self, py::object &other) { return false; })
.def("__hash__",
[](PyAttribute &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
})
.def(
"dump", [](PyAttribute &self) { mlirAttributeDump(self); },
kDumpDocstring)
.def(
"__str__",
[](PyAttribute &self) {
PyPrintAccumulator printAccum;
mlirAttributePrint(self, printAccum.getCallback(),
printAccum.getUserData());
return printAccum.join();
},
"Returns the assembly form of the Attribute.")
.def("__repr__", [](PyAttribute &self) {
// Generally, assembly formats are not printed for __repr__ because
// this can cause exceptionally long debug output and exceptions.
// However, attribute values are generally considered useful and are
// printed. This may need to be re-evaluated if debug dumps end up
// being excessive.
PyPrintAccumulator printAccum;
printAccum.parts.append("Attribute(");
mlirAttributePrint(self, printAccum.getCallback(),
printAccum.getUserData());
printAccum.parts.append(")");
return printAccum.join();
});
//----------------------------------------------------------------------------
// Mapping of PyNamedAttribute
//----------------------------------------------------------------------------
py::class_<PyNamedAttribute>(m, "NamedAttribute", py::module_local())
.def("__repr__",
[](PyNamedAttribute &self) {
PyPrintAccumulator printAccum;
printAccum.parts.append("NamedAttribute(");
printAccum.parts.append(
py::str(mlirIdentifierStr(self.namedAttr.name).data,
mlirIdentifierStr(self.namedAttr.name).length));
printAccum.parts.append("=");
mlirAttributePrint(self.namedAttr.attribute,
printAccum.getCallback(),
printAccum.getUserData());
printAccum.parts.append(")");
return printAccum.join();
})
.def_property_readonly(
"name",
[](PyNamedAttribute &self) {
return py::str(mlirIdentifierStr(self.namedAttr.name).data,
mlirIdentifierStr(self.namedAttr.name).length);
},
"The name of the NamedAttribute binding")
.def_property_readonly(
"attr",
[](PyNamedAttribute &self) {
// TODO: When named attribute is removed/refactored, also remove
// this constructor (it does an inefficient table lookup).
auto contextRef = PyMlirContext::forContext(
mlirAttributeGetContext(self.namedAttr.attribute));
return PyAttribute(std::move(contextRef), self.namedAttr.attribute);
},
py::keep_alive<0, 1>(),
"The underlying generic attribute of the NamedAttribute binding");
//----------------------------------------------------------------------------
// Mapping of PyType.
//----------------------------------------------------------------------------
py::class_<PyType>(m, "Type", py::module_local())
// Delegate to the PyType copy constructor, which will also lifetime
// extend the backing context which owns the MlirType.
.def(py::init<PyType &>(), py::arg("cast_from_type"),
"Casts the passed type to the generic Type")
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyType::createFromCapsule)
.def_static(
"parse",
[](std::string typeSpec, DefaultingPyMlirContext context) {
MlirType type =
mlirTypeParseGet(context->get(), toMlirStringRef(typeSpec));
// TODO: Rework error reporting once diagnostic engine is exposed
// in C API.
if (mlirTypeIsNull(type)) {
throw SetPyError(PyExc_ValueError,
Twine("Unable to parse type: '") + typeSpec +
"'");
}
return PyType(context->getRef(), type);
},
py::arg("asm"), py::arg("context") = py::none(),
kContextParseTypeDocstring)
.def_property_readonly(
"context", [](PyType &self) { return self.getContext().getObject(); },
"Context that owns the Type")
.def("__eq__", [](PyType &self, PyType &other) { return self == other; })
.def("__eq__", [](PyType &self, py::object &other) { return false; })
.def("__hash__",
[](PyType &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
})
.def(
"dump", [](PyType &self) { mlirTypeDump(self); }, kDumpDocstring)
.def(
"__str__",
[](PyType &self) {
PyPrintAccumulator printAccum;
mlirTypePrint(self, printAccum.getCallback(),
printAccum.getUserData());
return printAccum.join();
},
"Returns the assembly form of the type.")
.def("__repr__", [](PyType &self) {
// Generally, assembly formats are not printed for __repr__ because
// this can cause exceptionally long debug output and exceptions.
// However, types are an exception as they typically have compact
// assembly forms and printing them is useful.
PyPrintAccumulator printAccum;
printAccum.parts.append("Type(");
mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
printAccum.parts.append(")");
return printAccum.join();
});
//----------------------------------------------------------------------------
// Mapping of Value.
//----------------------------------------------------------------------------
py::class_<PyValue>(m, "Value", py::module_local())
.def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyValue::createFromCapsule)
.def_property_readonly(
"context",
[](PyValue &self) { return self.getParentOperation()->getContext(); },
"Context in which the value lives.")
.def(
"dump", [](PyValue &self) { mlirValueDump(self.get()); },
kDumpDocstring)
.def_property_readonly(
"owner",
[](PyValue &self) {
assert(mlirOperationEqual(self.getParentOperation()->get(),
mlirOpResultGetOwner(self.get())) &&
"expected the owner of the value in Python to match that in "
"the IR");
return self.getParentOperation().getObject();
})
.def("__eq__",
[](PyValue &self, PyValue &other) {
return self.get().ptr == other.get().ptr;
})
.def("__eq__", [](PyValue &self, py::object other) { return false; })
.def("__hash__",
[](PyValue &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
})
.def(
"__str__",
[](PyValue &self) {
PyPrintAccumulator printAccum;
printAccum.parts.append("Value(");
mlirValuePrint(self.get(), printAccum.getCallback(),
printAccum.getUserData());
printAccum.parts.append(")");
return printAccum.join();
},
kValueDunderStrDocstring)
.def_property_readonly("type", [](PyValue &self) {
return PyType(self.getParentOperation()->getContext(),
mlirValueGetType(self.get()));
});
PyBlockArgument::bind(m);
PyOpResult::bind(m);
//----------------------------------------------------------------------------
// Mapping of SymbolTable.
//----------------------------------------------------------------------------
py::class_<PySymbolTable>(m, "SymbolTable", py::module_local())
.def(py::init<PyOperationBase &>())
.def("__getitem__", &PySymbolTable::dunderGetItem)
.def("insert", &PySymbolTable::insert, py::arg("operation"))
.def("erase", &PySymbolTable::erase, py::arg("operation"))
.def("__delitem__", &PySymbolTable::dunderDel)
.def("__contains__",
[](PySymbolTable &table, const std::string &name) {
return !mlirOperationIsNull(mlirSymbolTableLookup(
table, mlirStringRefCreate(name.data(), name.length())));
})
// Static helpers.
.def_static("set_symbol_name", &PySymbolTable::setSymbolName,
py::arg("symbol"), py::arg("name"))
.def_static("get_symbol_name", &PySymbolTable::getSymbolName,
py::arg("symbol"))
.def_static("get_visibility", &PySymbolTable::getVisibility,
py::arg("symbol"))
.def_static("set_visibility", &PySymbolTable::setVisibility,
py::arg("symbol"), py::arg("visibility"))
.def_static("replace_all_symbol_uses",
&PySymbolTable::replaceAllSymbolUses, py::arg("old_symbol"),
py::arg("new_symbol"), py::arg("from_op"))
.def_static("walk_symbol_tables", &PySymbolTable::walkSymbolTables,
py::arg("from_op"), py::arg("all_sym_uses_visible"),
py::arg("callback"));
// Container bindings.
PyBlockArgumentList::bind(m);
PyBlockIterator::bind(m);
PyBlockList::bind(m);
PyOperationIterator::bind(m);
PyOperationList::bind(m);
PyOpAttributeMap::bind(m);
PyOpOperandList::bind(m);
PyOpResultList::bind(m);
PyRegionIterator::bind(m);
PyRegionList::bind(m);
// Debug bindings.
PyGlobalDebugFlag::bind(m);
}