aboutsummaryrefslogtreecommitdiff
path: root/mlir/lib/Bindings/Python/IRModule.h
diff options
context:
space:
mode:
authorMaksim Levental <maksim.levental@gmail.com>2025-09-20 14:47:32 -0400
committerGitHub <noreply@github.com>2025-09-20 18:47:32 +0000
commitefd96afedf2c0f6f2cc34cf5a9a7e3e78f592255 (patch)
tree24a53e26b8dcd4bb72d311e55cc71e7021fb2a9c /mlir/lib/Bindings/Python/IRModule.h
parent8693ef16f6f828275c6f9b65b855504019bea27a (diff)
downloadllvm-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.h69
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);