diff options
author | Maksim Levental <maksim.levental@gmail.com> | 2025-09-20 14:47:32 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-20 18:47:32 +0000 |
commit | efd96afedf2c0f6f2cc34cf5a9a7e3e78f592255 (patch) | |
tree | 24a53e26b8dcd4bb72d311e55cc71e7021fb2a9c /mlir/lib/Bindings/Python/IRModule.h | |
parent | 8693ef16f6f828275c6f9b65b855504019bea27a (diff) | |
download | llvm-efd96afedf2c0f6f2cc34cf5a9a7e3e78f592255.zip llvm-efd96afedf2c0f6f2cc34cf5a9a7e3e78f592255.tar.gz llvm-efd96afedf2c0f6f2cc34cf5a9a7e3e78f592255.tar.bz2 |
[MLIR][Python] reland (narrower) type stub generation (#157930)
This a reland of https://github.com/llvm/llvm-project/pull/155741 which
was reverted at https://github.com/llvm/llvm-project/pull/157831. This
version is narrower in scope - it only turns on automatic stub
generation for `MLIRPythonExtension.Core._mlir` and **does not do
anything automatically**. Specifically, the only CMake code added to
`AddMLIRPython.cmake` is the `mlir_generate_type_stubs` function which
is then used only in a manual way. The API for
`mlir_generate_type_stubs` is:
```
Arguments:
MODULE_NAME: The fully-qualified name of the extension module (used for importing in python).
DEPENDS_TARGETS: List of targets these type stubs depend on being built; usually corresponding to the
specific extension module (e.g., something like StandalonePythonModules.extension._standaloneDialectsNanobind.dso)
and the core bindings extension module (e.g., something like StandalonePythonModules.extension._mlir.dso).
OUTPUT_DIR: The root output directory to emit the type stubs into.
OUTPUTS: List of expected outputs.
DEPENDS_TARGET_SRC_DEPS: List of cpp sources for extension library (for generating a DEPFILE).
IMPORT_PATHS: List of paths to add to PYTHONPATH for stubgen.
PATTERN_FILE: (Optional) Pattern file (see https://nanobind.readthedocs.io/en/latest/typing.html#pattern-files).
Outputs:
NB_STUBGEN_CUSTOM_TARGET: The target corresponding to generation which other targets can depend on.
```
Downstream users should use `mlir_generate_type_stubs` in coordination
with `declare_mlir_python_sources` to turn on stub generation for their
own downstream dialect extensions and upstream dialect extensions if
they so choose. Standalone example shows an example.
Note, downstream will also need to set
`-DMLIR_PYTHON_PACKAGE_PREFIX=...` correctly for their bindings.
Diffstat (limited to 'mlir/lib/Bindings/Python/IRModule.h')
-rw-r--r-- | mlir/lib/Bindings/Python/IRModule.h | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/mlir/lib/Bindings/Python/IRModule.h b/mlir/lib/Bindings/Python/IRModule.h index 28b885f..414f37c 100644 --- a/mlir/lib/Bindings/Python/IRModule.h +++ b/mlir/lib/Bindings/Python/IRModule.h @@ -19,6 +19,7 @@ #include "NanobindUtils.h" #include "mlir-c/AffineExpr.h" #include "mlir-c/AffineMap.h" +#include "mlir-c/BuiltinAttributes.h" #include "mlir-c/Diagnostics.h" #include "mlir-c/IR.h" #include "mlir-c/IntegerSet.h" @@ -75,7 +76,7 @@ public: /// Releases the object held by this instance, returning it. /// This is the proper thing to return from a function that wants to return /// the reference. Note that this does not work from initializers. - nanobind::object releaseObject() { + nanobind::typed<nanobind::object, T> releaseObject() { assert(referrent && object); referrent = nullptr; auto stolen = std::move(object); @@ -87,7 +88,7 @@ public: assert(referrent && object); return referrent; } - nanobind::object getObject() { + nanobind::typed<nanobind::object, T> getObject() { assert(referrent && object); return object; } @@ -235,6 +236,7 @@ public: /// Controls whether error diagnostics should be propagated to diagnostic /// handlers, instead of being captured by `ErrorCapture`. void setEmitErrorDiagnostics(bool value) { emitErrorDiagnostics = value; } + bool getEmitErrorDiagnostics() { return emitErrorDiagnostics; } struct ErrorCapture; private: @@ -269,7 +271,8 @@ class DefaultingPyMlirContext : public Defaulting<DefaultingPyMlirContext, PyMlirContext> { public: using Defaulting::Defaulting; - static constexpr const char kTypeDescription[] = "mlir.ir.Context"; + static constexpr const char kTypeDescription[] = + MAKE_MLIR_PYTHON_QUALNAME("ir.Context"); static PyMlirContext &resolve(); }; @@ -495,7 +498,8 @@ class DefaultingPyLocation : public Defaulting<DefaultingPyLocation, PyLocation> { public: using Defaulting::Defaulting; - static constexpr const char kTypeDescription[] = "mlir.ir.Location"; + static constexpr const char kTypeDescription[] = + MAKE_MLIR_PYTHON_QUALNAME("ir.Location"); static PyLocation &resolve(); operator MlirLocation() const { return *get(); } @@ -596,6 +600,7 @@ public: /// drops to zero or it is attached to a parent, at which point its lifetime /// is bounded by its top-level parent reference. class PyOperation; +class PyOpView; using PyOperationRef = PyObjectRef<PyOperation>; class PyOperation : public PyOperationBase, public BaseContextObject { public: @@ -675,7 +680,7 @@ public: PyLocation &location, const nanobind::object &ip, bool inferType); /// Creates an OpView suitable for this operation. - nanobind::object createOpView(); + nanobind::typed<nanobind::object, PyOpView> createOpView(); /// Erases the underlying MlirOperation, removes its pointer from the /// parent context's live operations map, and sets the valid bit false. @@ -685,7 +690,7 @@ public: void setInvalid() { valid = false; } /// Clones this operation. - nanobind::object clone(const nanobind::object &ip); + nanobind::typed<nanobind::object, PyOpView> clone(const nanobind::object &ip); PyOperation(PyMlirContextRef contextRef, MlirOperation operation); @@ -885,6 +890,8 @@ public: /// is taken by calling this function. static PyType createFromCapsule(nanobind::object capsule); + nanobind::typed<nanobind::object, PyType> maybeDownCast(); + private: MlirType type; }; @@ -958,16 +965,18 @@ public: }, nanobind::arg("other")); cls.def_prop_ro_static( - "static_typeid", [](nanobind::object & /*class*/) -> MlirTypeID { + "static_typeid", + [](nanobind::object & /*class*/) { if (DerivedTy::getTypeIdFunction) - return DerivedTy::getTypeIdFunction(); + return PyTypeID(DerivedTy::getTypeIdFunction()); throw nanobind::attribute_error( (DerivedTy::pyClassName + llvm::Twine(" has no typeid.")) .str() .c_str()); - }); + }, + nanobind::sig("def static_typeid(/) -> TypeID")); cls.def_prop_ro("typeid", [](PyType &self) { - return nanobind::cast<MlirTypeID>(nanobind::cast(self).attr("typeid")); + return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid")); }); cls.def("__repr__", [](DerivedTy &self) { PyPrintAccumulator printAccum; @@ -1011,6 +1020,8 @@ public: /// is taken by calling this function. static PyAttribute createFromCapsule(nanobind::object capsule); + nanobind::typed<nanobind::object, PyAttribute> maybeDownCast(); + private: MlirAttribute attr; }; @@ -1088,19 +1099,23 @@ public: return DerivedTy::isaFunction(otherAttr); }, nanobind::arg("other")); - cls.def_prop_ro( - "type", [](PyAttribute &attr) { return mlirAttributeGetType(attr); }); + cls.def_prop_ro("type", [](PyAttribute &attr) { + return PyType(attr.getContext(), mlirAttributeGetType(attr)) + .maybeDownCast(); + }); cls.def_prop_ro_static( - "static_typeid", [](nanobind::object & /*class*/) -> MlirTypeID { + "static_typeid", + [](nanobind::object & /*class*/) -> PyTypeID { if (DerivedTy::getTypeIdFunction) - return DerivedTy::getTypeIdFunction(); + return PyTypeID(DerivedTy::getTypeIdFunction()); throw nanobind::attribute_error( (DerivedTy::pyClassName + llvm::Twine(" has no typeid.")) .str() .c_str()); - }); + }, + nanobind::sig("def static_typeid(/) -> TypeID")); cls.def_prop_ro("typeid", [](PyAttribute &self) { - return nanobind::cast<MlirTypeID>(nanobind::cast(self).attr("typeid")); + return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid")); }); cls.def("__repr__", [](DerivedTy &self) { PyPrintAccumulator printAccum; @@ -1128,6 +1143,17 @@ public: static void bindDerived(ClassTy &m) {} }; +class PyStringAttribute : public PyConcreteAttribute<PyStringAttribute> { +public: + static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAString; + static constexpr const char *pyClassName = "StringAttr"; + using PyConcreteAttribute::PyConcreteAttribute; + static constexpr GetTypeIDFunctionTy getTypeIdFunction = + mlirStringAttrGetTypeID; + + static void bindDerived(ClassTy &c); +}; + /// Wrapper around the generic MlirValue. /// Values are managed completely by the operation that resulted in their /// definition. For op result value, this is the operation that defines the @@ -1152,7 +1178,7 @@ public: /// Gets a capsule wrapping the void* within the MlirValue. nanobind::object getCapsule(); - nanobind::object maybeDownCast(); + nanobind::typed<nanobind::object, PyValue> maybeDownCast(); /// Creates a PyValue from the MlirValue wrapped by a capsule. Ownership of /// the underlying MlirValue is still tied to the owning operation. @@ -1243,7 +1269,8 @@ public: /// Returns the symbol (opview) with the given name, throws if there is no /// such symbol in the table. - nanobind::object dunderGetItem(const std::string &name); + nanobind::typed<nanobind::object, PyOpView> + dunderGetItem(const std::string &name); /// Removes the given operation from the symbol table and erases it. void erase(PyOperationBase &symbol); @@ -1254,14 +1281,14 @@ public: /// Inserts the given operation into the symbol table. The operation must have /// the symbol trait. - MlirAttribute insert(PyOperationBase &symbol); + PyStringAttribute insert(PyOperationBase &symbol); /// Gets and sets the name of a symbol op. - static MlirAttribute getSymbolName(PyOperationBase &symbol); + static PyStringAttribute getSymbolName(PyOperationBase &symbol); static void setSymbolName(PyOperationBase &symbol, const std::string &name); /// Gets and sets the visibility of a symbol op. - static MlirAttribute getVisibility(PyOperationBase &symbol); + static PyStringAttribute getVisibility(PyOperationBase &symbol); static void setVisibility(PyOperationBase &symbol, const std::string &visibility); |