[Mlir-commits] [llvm] [mlir] [mlir python] Port Python core code to nanobind. (PR #118583)
Peter Hawkins
llvmlistbot at llvm.org
Tue Dec 3 19:16:11 PST 2024
https://github.com/hawkinsp updated https://github.com/llvm/llvm-project/pull/118583
>From 5d8eabc4e2fd55a8ea3731c5ba31d39c16a7d7f9 Mon Sep 17 00:00:00 2001
From: Peter Hawkins <phawkins at google.com>
Date: Wed, 27 Nov 2024 20:17:40 +0000
Subject: [PATCH 1/2] [mlir python] Add nanobind support for standalone
dialects.
This PR allows out-of-tree dialects to write Python dialect modules using nanobind
instead of pybind11.
It may make sense to migrate in-tree dialects and some of the ODS Python
infrastructure to nanobind, but that is a topic for a future change.
This PR makes the following changes:
* adds nanobind to the CMake and Bazel build systems. We also add
robin_map to the Bazel build, which is a dependency of nanobind.
* adds a PYTHON_BINDING_LIBRARY option to various CMake functions, such
as declare_mlir_python_extension, allowing users to select a
Python binding library.
* creates a fork of mlir/include/mlir/Bindings/Python/PybindAdaptors.h
named NanobindAdaptors.h. This plays the same role, using nanobind
instead of pybind11.
* splits CollectDiagnosticsToStringScope out of PybindAdaptors.h and
into a new header mlir/include/mlir/Bindings/Python/Diagnostics.h, since
it is code that is no way related to pybind11 or for that matter,
Python.
* changed the standalone Python extension example to have both pybind11
and nanobind variants.
* changed mlir/python/mlir/dialects/python_test.py to have both pybind11
and nanobind variants.
Notes:
* A slightly unfortunate thing that I needed to do in the CMake
integration was to use FindPython in addition to FindPython3, since nanobind's CMake
integration expects the Python_ names for variables. Perhaps there's a
better way to do this.
---
mlir/cmake/modules/AddMLIRPython.cmake | 27 +-
mlir/cmake/modules/MLIRDetectPythonEnv.cmake | 39 +
mlir/docs/Bindings/Python.md | 20 +-
.../examples/standalone/python/CMakeLists.txt | 22 +-
.../python/StandaloneExtensionNanobind.cpp | 35 +
...on.cpp => StandaloneExtensionPybind11.cpp} | 7 +-
.../{standalone.py => standalone_nanobind.py} | 2 +-
.../dialects/standalone_pybind11.py | 6 +
.../standalone/test/python/smoketest.py | 14 +-
.../mlir/Bindings/Python/Diagnostics.h | 59 ++
.../mlir/Bindings/Python/NanobindAdaptors.h | 671 ++++++++++++++++++
.../mlir/Bindings/Python/PybindAdaptors.h | 43 +-
mlir/lib/Bindings/Python/DialectLLVM.cpp | 4 +-
.../Bindings/Python/TransformInterpreter.cpp | 7 +-
mlir/python/CMakeLists.txt | 23 +-
mlir/python/mlir/dialects/python_test.py | 17 +-
mlir/python/requirements.txt | 1 +
mlir/test/python/dialects/python_test.py | 59 +-
mlir/test/python/lib/CMakeLists.txt | 3 +-
.../python/lib/PythonTestModuleNanobind.cpp | 121 ++++
...odule.cpp => PythonTestModulePybind11.cpp} | 4 +-
utils/bazel/WORKSPACE | 18 +
.../llvm-project-overlay/mlir/BUILD.bazel | 50 +-
utils/bazel/third_party_build/nanobind.BUILD | 25 +
utils/bazel/third_party_build/robin_map.BUILD | 12 +
25 files changed, 1184 insertions(+), 105 deletions(-)
create mode 100644 mlir/examples/standalone/python/StandaloneExtensionNanobind.cpp
rename mlir/examples/standalone/python/{StandaloneExtension.cpp => StandaloneExtensionPybind11.cpp} (81%)
rename mlir/examples/standalone/python/mlir_standalone/dialects/{standalone.py => standalone_nanobind.py} (78%)
create mode 100644 mlir/examples/standalone/python/mlir_standalone/dialects/standalone_pybind11.py
create mode 100644 mlir/include/mlir/Bindings/Python/Diagnostics.h
create mode 100644 mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
create mode 100644 mlir/test/python/lib/PythonTestModuleNanobind.cpp
rename mlir/test/python/lib/{PythonTestModule.cpp => PythonTestModulePybind11.cpp} (96%)
create mode 100644 utils/bazel/third_party_build/nanobind.BUILD
create mode 100644 utils/bazel/third_party_build/robin_map.BUILD
diff --git a/mlir/cmake/modules/AddMLIRPython.cmake b/mlir/cmake/modules/AddMLIRPython.cmake
index 7b91f43e2d57fd..67619a90c90be9 100644
--- a/mlir/cmake/modules/AddMLIRPython.cmake
+++ b/mlir/cmake/modules/AddMLIRPython.cmake
@@ -114,10 +114,11 @@ endfunction()
# EMBED_CAPI_LINK_LIBS: Dependent CAPI libraries that this extension depends
# on. These will be collected for all extensions and put into an
# aggregate dylib that is linked against.
+# PYTHON_BINDINGS_LIBRARY: Either pybind11 or nanobind.
function(declare_mlir_python_extension name)
cmake_parse_arguments(ARG
""
- "ROOT_DIR;MODULE_NAME;ADD_TO_PARENT"
+ "ROOT_DIR;MODULE_NAME;ADD_TO_PARENT;PYTHON_BINDINGS_LIBRARY"
"SOURCES;PRIVATE_LINK_LIBS;EMBED_CAPI_LINK_LIBS"
${ARGN})
@@ -126,15 +127,20 @@ function(declare_mlir_python_extension name)
endif()
set(_install_destination "src/python/${name}")
+ if(NOT ARG_PYTHON_BINDINGS_LIBRARY)
+ set(ARG_PYTHON_BINDINGS_LIBRARY "pybind11")
+ endif()
+
add_library(${name} INTERFACE)
set_target_properties(${name} PROPERTIES
# Yes: Leading-lowercase property names are load bearing and the recommended
# way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
- EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS"
+ EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS;mlir_python_BINDINGS_LIBRARY"
mlir_python_SOURCES_TYPE extension
mlir_python_EXTENSION_MODULE_NAME "${ARG_MODULE_NAME}"
mlir_python_EMBED_CAPI_LINK_LIBS "${ARG_EMBED_CAPI_LINK_LIBS}"
mlir_python_DEPENDS ""
+ mlir_python_BINDINGS_LIBRARY "${ARG_PYTHON_BINDINGS_LIBRARY}"
)
# Set the interface source and link_libs properties of the target
@@ -223,12 +229,14 @@ function(add_mlir_python_modules name)
elseif(_source_type STREQUAL "extension")
# Native CPP extension.
get_target_property(_module_name ${sources_target} mlir_python_EXTENSION_MODULE_NAME)
+ get_target_property(_bindings_library ${sources_target} mlir_python_BINDINGS_LIBRARY)
# Transform relative source to based on root dir.
set(_extension_target "${modules_target}.extension.${_module_name}.dso")
add_mlir_python_extension(${_extension_target} "${_module_name}"
INSTALL_COMPONENT ${modules_target}
INSTALL_DIR "${ARG_INSTALL_PREFIX}/_mlir_libs"
OUTPUT_DIRECTORY "${ARG_ROOT_PREFIX}/_mlir_libs"
+ PYTHON_BINDINGS_LIBRARY ${_bindings_library}
LINK_LIBS PRIVATE
${sources_target}
${ARG_COMMON_CAPI_LINK_LIBS}
@@ -634,7 +642,7 @@ endfunction()
function(add_mlir_python_extension libname extname)
cmake_parse_arguments(ARG
""
- "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY"
+ "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY;PYTHON_BINDINGS_LIBRARY"
"SOURCES;LINK_LIBS"
${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
@@ -644,9 +652,16 @@ function(add_mlir_python_extension libname extname)
# The actual extension library produces a shared-object or DLL and has
# sources that must be compiled in accordance with pybind11 needs (RTTI and
# exceptions).
- pybind11_add_module(${libname}
- ${ARG_SOURCES}
- )
+ if(NOT DEFINED ARG_PYTHON_BINDINGS_LIBRARY OR ARG_PYTHON_BINDINGS_LIBRARY STREQUAL "pybind11")
+ pybind11_add_module(${libname}
+ ${ARG_SOURCES}
+ )
+ elseif(ARG_PYTHON_BINDINGS_LIBRARY STREQUAL "nanobind")
+ nanobind_add_module(${libname}
+ NB_DOMAIN mlir
+ ${ARG_SOURCES}
+ )
+ endif()
# The extension itself must be compiled with RTTI and exceptions enabled.
# Also, some warning classes triggered by pybind11 are disabled.
diff --git a/mlir/cmake/modules/MLIRDetectPythonEnv.cmake b/mlir/cmake/modules/MLIRDetectPythonEnv.cmake
index 05397b7a1e1c75..c62ac7fa615ea6 100644
--- a/mlir/cmake/modules/MLIRDetectPythonEnv.cmake
+++ b/mlir/cmake/modules/MLIRDetectPythonEnv.cmake
@@ -21,6 +21,12 @@ macro(mlir_configure_python_dev_packages)
find_package(Python3 ${LLVM_MINIMUM_PYTHON_VERSION}
COMPONENTS Interpreter ${_python_development_component} REQUIRED)
+
+ # It's a little silly to detect Python a second time, but nanobind's cmake
+ # code looks for Python_ not Python3_.
+ find_package(Python ${LLVM_MINIMUM_PYTHON_VERSION}
+ COMPONENTS Interpreter ${_python_development_component} REQUIRED)
+
unset(_python_development_component)
message(STATUS "Found python include dirs: ${Python3_INCLUDE_DIRS}")
message(STATUS "Found python libraries: ${Python3_LIBRARIES}")
@@ -31,6 +37,13 @@ macro(mlir_configure_python_dev_packages)
message(STATUS "Python prefix = '${PYTHON_MODULE_PREFIX}', "
"suffix = '${PYTHON_MODULE_SUFFIX}', "
"extension = '${PYTHON_MODULE_EXTENSION}")
+
+ mlir_detect_nanobind_install()
+ find_package(nanobind 2.2 CONFIG REQUIRED)
+ message(STATUS "Found nanobind v${nanobind_VERSION}: ${nanobind_INCLUDE_DIR}")
+ message(STATUS "Python prefix = '${PYTHON_MODULE_PREFIX}', "
+ "suffix = '${PYTHON_MODULE_SUFFIX}', "
+ "extension = '${PYTHON_MODULE_EXTENSION}")
endif()
endmacro()
@@ -58,3 +71,29 @@ function(mlir_detect_pybind11_install)
set(pybind11_DIR "${PACKAGE_DIR}" PARENT_SCOPE)
endif()
endfunction()
+
+
+# Detects a nanobind package installed in the current python environment
+# and sets variables to allow it to be found. This allows nanobind to be
+# installed via pip, which typically yields a much more recent version than
+# the OS install, which will be available otherwise.
+function(mlir_detect_nanobind_install)
+ if(nanobind_DIR)
+ message(STATUS "Using explicit nanobind cmake directory: ${nanobind_DIR} (-Dnanobind_DIR to change)")
+ else()
+ message(STATUS "Checking for nanobind in python path...")
+ execute_process(
+ COMMAND "${Python3_EXECUTABLE}"
+ -c "import nanobind;print(nanobind.cmake_dir(), end='')"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ RESULT_VARIABLE STATUS
+ OUTPUT_VARIABLE PACKAGE_DIR
+ ERROR_QUIET)
+ if(NOT STATUS EQUAL "0")
+ message(STATUS "not found (install via 'pip install nanobind' or set nanobind_DIR)")
+ return()
+ endif()
+ message(STATUS "found (${PACKAGE_DIR})")
+ set(nanobind_DIR "${PACKAGE_DIR}" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/mlir/docs/Bindings/Python.md b/mlir/docs/Bindings/Python.md
index 6e52c4deaad9aa..a0bd1cac118bad 100644
--- a/mlir/docs/Bindings/Python.md
+++ b/mlir/docs/Bindings/Python.md
@@ -1138,12 +1138,14 @@ attributes and types must connect to the relevant C APIs for building and
inspection, which must be provided first. Bindings for `Attribute` and `Type`
subclasses can be defined using
[`include/mlir/Bindings/Python/PybindAdaptors.h`](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Bindings/Python/PybindAdaptors.h)
-utilities that mimic pybind11 API for defining functions and properties. These
-bindings are to be included in a separate pybind11 module. The utilities also
-provide automatic casting between C API handles `MlirAttribute` and `MlirType`
-and their Python counterparts so that the C API handles can be used directly in
-binding implementations. The methods and properties provided by the bindings
-should follow the principles discussed above.
+or
+[`include/mlir/Bindings/Python/NanobindAdaptors.h`](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h)
+utilities that mimic pybind11/nanobind API for defining functions and
+properties. These bindings are to be included in a separate module. The
+utilities also provide automatic casting between C API handles `MlirAttribute`
+and `MlirType` and their Python counterparts so that the C API handles can be
+used directly in binding implementations. The methods and properties provided by
+the bindings should follow the principles discussed above.
The attribute and type bindings for a dialect can be located in
`lib/Bindings/Python/Dialect<Name>.cpp` and should be compiled into a separate
@@ -1179,7 +1181,9 @@ make the passes available along with the dialect.
Dialect functionality other than IR objects or passes, such as helper functions,
can be exposed to Python similarly to attributes and types. C API is expected to
exist for this functionality, which can then be wrapped using pybind11 and
-`[include/mlir/Bindings/Python/PybindAdaptors.h](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Bindings/Python/PybindAdaptors.h)`
+`[include/mlir/Bindings/Python/PybindAdaptors.h](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Bindings/Python/PybindAdaptors.h)`,
+or nanobind and
+`[include/mlir/Bindings/Python/NanobindAdaptors.h](https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h)`
utilities to connect to the rest of Python API. The bindings can be located in a
-separate pybind11 module or in the same module as attributes and types, and
+separate module or in the same module as attributes and types, and
loaded along with the dialect.
diff --git a/mlir/examples/standalone/python/CMakeLists.txt b/mlir/examples/standalone/python/CMakeLists.txt
index a8c43827a5a375..69c82fd9135798 100644
--- a/mlir/examples/standalone/python/CMakeLists.txt
+++ b/mlir/examples/standalone/python/CMakeLists.txt
@@ -17,18 +17,32 @@ declare_mlir_dialect_python_bindings(
ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mlir_standalone"
TD_FILE dialects/StandaloneOps.td
SOURCES
- dialects/standalone.py
+ dialects/standalone_pybind11.py
+ dialects/standalone_nanobind.py
DIALECT_NAME standalone)
-declare_mlir_python_extension(StandalonePythonSources.Extension
- MODULE_NAME _standaloneDialects
+
+declare_mlir_python_extension(StandalonePythonSources.Pybind11Extension
+ MODULE_NAME _standaloneDialectsPybind11
+ ADD_TO_PARENT StandalonePythonSources
+ SOURCES
+ StandaloneExtensionPybind11.cpp
+ EMBED_CAPI_LINK_LIBS
+ StandaloneCAPI
+ PYTHON_BINDINGS_LIBRARY pybind11
+)
+
+declare_mlir_python_extension(StandalonePythonSources.NanobindExtension
+ MODULE_NAME _standaloneDialectsNanobind
ADD_TO_PARENT StandalonePythonSources
SOURCES
- StandaloneExtension.cpp
+ StandaloneExtensionNanobind.cpp
EMBED_CAPI_LINK_LIBS
StandaloneCAPI
+ PYTHON_BINDINGS_LIBRARY nanobind
)
+
################################################################################
# Common CAPI
################################################################################
diff --git a/mlir/examples/standalone/python/StandaloneExtensionNanobind.cpp b/mlir/examples/standalone/python/StandaloneExtensionNanobind.cpp
new file mode 100644
index 00000000000000..6d83dc585dcd1d
--- /dev/null
+++ b/mlir/examples/standalone/python/StandaloneExtensionNanobind.cpp
@@ -0,0 +1,35 @@
+//===- StandaloneExtension.cpp - Extension module -------------------------===//
+//
+// This is the nanobind version of the example module. There is also a pybind11
+// example in StandaloneExtensionPybind11.cpp.
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <nanobind/nanobind.h>
+
+#include "Standalone-c/Dialects.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
+
+namespace nb = nanobind;
+
+NB_MODULE(_standaloneDialectsNanobind, m) {
+ //===--------------------------------------------------------------------===//
+ // standalone dialect
+ //===--------------------------------------------------------------------===//
+ auto standaloneM = m.def_submodule("standalone");
+
+ standaloneM.def(
+ "register_dialect",
+ [](MlirContext context, bool load) {
+ MlirDialectHandle handle = mlirGetDialectHandle__standalone__();
+ mlirDialectHandleRegisterDialect(handle, context);
+ if (load) {
+ mlirDialectHandleLoadDialect(handle, context);
+ }
+ },
+ nb::arg("context").none() = nb::none(), nb::arg("load") = true);
+}
diff --git a/mlir/examples/standalone/python/StandaloneExtension.cpp b/mlir/examples/standalone/python/StandaloneExtensionPybind11.cpp
similarity index 81%
rename from mlir/examples/standalone/python/StandaloneExtension.cpp
rename to mlir/examples/standalone/python/StandaloneExtensionPybind11.cpp
index 5e83060cd48d82..397db4c20e7432 100644
--- a/mlir/examples/standalone/python/StandaloneExtension.cpp
+++ b/mlir/examples/standalone/python/StandaloneExtensionPybind11.cpp
@@ -1,4 +1,7 @@
-//===- StandaloneExtension.cpp - Extension module -------------------------===//
+//===- StandaloneExtensionPybind11.cpp - Extension module -----------------===//
+//
+// This is the pybind11 version of the example module. There is also a nanobind
+// example in StandaloneExtensionNanobind.cpp.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,7 +14,7 @@
using namespace mlir::python::adaptors;
-PYBIND11_MODULE(_standaloneDialects, m) {
+PYBIND11_MODULE(_standaloneDialectsPybind11, m) {
//===--------------------------------------------------------------------===//
// standalone dialect
//===--------------------------------------------------------------------===//
diff --git a/mlir/examples/standalone/python/mlir_standalone/dialects/standalone.py b/mlir/examples/standalone/python/mlir_standalone/dialects/standalone_nanobind.py
similarity index 78%
rename from mlir/examples/standalone/python/mlir_standalone/dialects/standalone.py
rename to mlir/examples/standalone/python/mlir_standalone/dialects/standalone_nanobind.py
index c958b2ac193682..6218720951c82a 100644
--- a/mlir/examples/standalone/python/mlir_standalone/dialects/standalone.py
+++ b/mlir/examples/standalone/python/mlir_standalone/dialects/standalone_nanobind.py
@@ -3,4 +3,4 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
from ._standalone_ops_gen import *
-from .._mlir_libs._standaloneDialects.standalone import *
+from .._mlir_libs._standaloneDialectsNanobind.standalone import *
diff --git a/mlir/examples/standalone/python/mlir_standalone/dialects/standalone_pybind11.py b/mlir/examples/standalone/python/mlir_standalone/dialects/standalone_pybind11.py
new file mode 100644
index 00000000000000..bfb98e404e13f2
--- /dev/null
+++ b/mlir/examples/standalone/python/mlir_standalone/dialects/standalone_pybind11.py
@@ -0,0 +1,6 @@
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+from ._standalone_ops_gen import *
+from .._mlir_libs._standaloneDialectsPybind11.standalone import *
diff --git a/mlir/examples/standalone/test/python/smoketest.py b/mlir/examples/standalone/test/python/smoketest.py
index 08e08cbd2fe24c..bd40c65d161645 100644
--- a/mlir/examples/standalone/test/python/smoketest.py
+++ b/mlir/examples/standalone/test/python/smoketest.py
@@ -1,7 +1,17 @@
-# RUN: %python %s | FileCheck %s
+# RUN: %python %s pybind11 | FileCheck %s
+# RUN: %python %s nanobind | FileCheck %s
+import sys
from mlir_standalone.ir import *
-from mlir_standalone.dialects import builtin as builtin_d, standalone as standalone_d
+from mlir_standalone.dialects import builtin as builtin_d
+
+if sys.argv[1] == "pybind11":
+ from mlir_standalone.dialects import standalone_pybind11 as standalone_d
+elif sys.argv[1] == "nanobind":
+ from mlir_standalone.dialects import standalone_nanobind as standalone_d
+else:
+ raise ValueError("Expected either pybind11 or nanobind as arguments")
+
with Context():
standalone_d.register_dialect()
diff --git a/mlir/include/mlir/Bindings/Python/Diagnostics.h b/mlir/include/mlir/Bindings/Python/Diagnostics.h
new file mode 100644
index 00000000000000..ea80e14dde0f3a
--- /dev/null
+++ b/mlir/include/mlir/Bindings/Python/Diagnostics.h
@@ -0,0 +1,59 @@
+//===- Diagnostics.h - Helpers for diagnostics in Python bindings ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_BINDINGS_PYTHON_DIAGNOSTICS_H
+#define MLIR_BINDINGS_PYTHON_DIAGNOSTICS_H
+
+#include <cassert>
+#include <string>
+
+#include "mlir-c/Diagnostics.h"
+#include "mlir-c/IR.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace mlir {
+namespace python {
+
+/// RAII scope intercepting all diagnostics into a string. The message must be
+/// checked before this goes out of scope.
+class CollectDiagnosticsToStringScope {
+public:
+ explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
+ handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
+ /*deleteUserData=*/nullptr);
+ }
+ ~CollectDiagnosticsToStringScope() {
+ assert(errorMessage.empty() && "unchecked error message");
+ mlirContextDetachDiagnosticHandler(context, handlerID);
+ }
+
+ [[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
+
+private:
+ static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
+ auto printer = +[](MlirStringRef message, void *data) {
+ *static_cast<std::string *>(data) +=
+ llvm::StringRef(message.data, message.length);
+ };
+ MlirLocation loc = mlirDiagnosticGetLocation(diag);
+ *static_cast<std::string *>(data) += "at ";
+ mlirLocationPrint(loc, printer, data);
+ *static_cast<std::string *>(data) += ": ";
+ mlirDiagnosticPrint(diag, printer, data);
+ return mlirLogicalResultSuccess();
+ }
+
+ MlirContext context;
+ MlirDiagnosticHandlerID handlerID;
+ std::string errorMessage = "";
+};
+
+} // namespace python
+} // namespace mlir
+
+#endif // MLIR_BINDINGS_PYTHON_DIAGNOSTICS_H
diff --git a/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h b/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
new file mode 100644
index 00000000000000..5e01cebcb09c91
--- /dev/null
+++ b/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
@@ -0,0 +1,671 @@
+//===- NanobindAdaptors.h - Interop with MLIR APIs via nanobind -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This file contains adaptors for clients of the core MLIR Python APIs to
+// interop via MLIR CAPI types, using nanobind. The facilities here do not
+// depend on implementation details of the MLIR Python API and do not introduce
+// C++-level dependencies with it (requiring only Python and CAPI-level
+// dependencies).
+//
+// It is encouraged to be used both in-tree and out-of-tree. For in-tree use
+// cases, it should be used for dialect implementations (versus relying on
+// Pybind-based internals of the core libraries).
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
+#define MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
+
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/string.h>
+
+#include <cstdint>
+
+#include "mlir-c/Bindings/Python/Interop.h"
+#include "mlir-c/Diagnostics.h"
+#include "mlir-c/IR.h"
+#include "llvm/ADT/Twine.h"
+
+// Raw CAPI type casters need to be declared before use, so always include them
+// first.
+namespace nanobind {
+namespace detail {
+
+/// Helper to convert a presumed MLIR API object to a capsule, accepting either
+/// an explicit Capsule (which can happen when two C APIs are communicating
+/// directly via Python) or indirectly by querying the MLIR_PYTHON_CAPI_PTR_ATTR
+/// attribute (through which supported MLIR Python API objects export their
+/// contained API pointer as a capsule). Throws a type error if the object is
+/// neither. This is intended to be used from type casters, which are invoked
+/// with a raw handle (unowned). The returned object's lifetime may not extend
+/// beyond the apiObject handle without explicitly having its refcount increased
+/// (i.e. on return).
+static nanobind::object mlirApiObjectToCapsule(nanobind::handle apiObject) {
+ if (PyCapsule_CheckExact(apiObject.ptr()))
+ return nanobind::borrow<nanobind::object>(apiObject);
+ if (!nanobind::hasattr(apiObject, MLIR_PYTHON_CAPI_PTR_ATTR)) {
+ std::string repr = nanobind::cast<std::string>(nanobind::repr(apiObject));
+ throw nanobind::type_error(
+ (llvm::Twine("Expected an MLIR object (got ") + repr + ").")
+ .str()
+ .c_str());
+ }
+ return apiObject.attr(MLIR_PYTHON_CAPI_PTR_ATTR);
+}
+
+// Note: Currently all of the following support cast from nanobind::object to
+// the Mlir* C-API type, but only a few light-weight, context-bound ones
+// implicitly cast the other way because the use case has not yet emerged and
+// ownership is unclear.
+
+/// Casts object <-> MlirAffineMap.
+template <>
+struct type_caster<MlirAffineMap> {
+ NB_TYPE_CASTER(MlirAffineMap, const_name("MlirAffineMap"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToAffineMap(capsule.ptr());
+ if (mlirAffineMapIsNull(value)) {
+ return false;
+ }
+ return !mlirAffineMapIsNull(value);
+ }
+ static handle from_cpp(MlirAffineMap v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonAffineMapToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("AffineMap")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ }
+};
+
+/// Casts object <-> MlirAttribute.
+template <>
+struct type_caster<MlirAttribute> {
+ NB_TYPE_CASTER(MlirAttribute, const_name("MlirAttribute"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToAttribute(capsule.ptr());
+ return !mlirAttributeIsNull(value);
+ }
+ static handle from_cpp(MlirAttribute v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonAttributeToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Attribute")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .attr(MLIR_PYTHON_MAYBE_DOWNCAST_ATTR)()
+ .release();
+ }
+};
+
+/// Casts object -> MlirBlock.
+template <>
+struct type_caster<MlirBlock> {
+ NB_TYPE_CASTER(MlirBlock, const_name("MlirBlock"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToBlock(capsule.ptr());
+ return !mlirBlockIsNull(value);
+ }
+};
+
+/// Casts object -> MlirContext.
+template <>
+struct type_caster<MlirContext> {
+ NB_TYPE_CASTER(MlirContext, const_name("MlirContext"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ if (src.is_none()) {
+ // Gets the current thread-bound context.
+ // TODO: This raises an error of "No current context" currently.
+ // Update the implementation to pretty-print the helpful error that the
+ // core implementations print in this case.
+ src = nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Context")
+ .attr("current");
+ }
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToContext(capsule.ptr());
+ return !mlirContextIsNull(value);
+ }
+};
+
+/// Casts object <-> MlirDialectRegistry.
+template <>
+struct type_caster<MlirDialectRegistry> {
+ NB_TYPE_CASTER(MlirDialectRegistry, const_name("MlirDialectRegistry"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToDialectRegistry(capsule.ptr());
+ return !mlirDialectRegistryIsNull(value);
+ }
+ static handle from_cpp(MlirDialectRegistry v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ nanobind::object capsule = nanobind::steal<nanobind::object>(
+ mlirPythonDialectRegistryToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("DialectRegistry")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ }
+};
+
+/// Casts object <-> MlirLocation.
+template <>
+struct type_caster<MlirLocation> {
+ NB_TYPE_CASTER(MlirLocation, const_name("MlirLocation"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ if (src.is_none()) {
+ // Gets the current thread-bound context.
+ src = nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Location")
+ .attr("current");
+ }
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToLocation(capsule.ptr());
+ return !mlirLocationIsNull(value);
+ }
+ static handle from_cpp(MlirLocation v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonLocationToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Location")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ }
+};
+
+/// Casts object <-> MlirModule.
+template <>
+struct type_caster<MlirModule> {
+ NB_TYPE_CASTER(MlirModule, const_name("MlirModule"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToModule(capsule.ptr());
+ return !mlirModuleIsNull(value);
+ }
+ static handle from_cpp(MlirModule v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonModuleToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Module")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ };
+};
+
+/// Casts object <-> MlirFrozenRewritePatternSet.
+template <>
+struct type_caster<MlirFrozenRewritePatternSet> {
+ NB_TYPE_CASTER(MlirFrozenRewritePatternSet,
+ const_name("MlirFrozenRewritePatternSet"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToFrozenRewritePatternSet(capsule.ptr());
+ return value.ptr != nullptr;
+ }
+ static handle from_cpp(MlirFrozenRewritePatternSet v, rv_policy, handle) {
+ nanobind::object capsule = nanobind::steal<nanobind::object>(
+ mlirPythonFrozenRewritePatternSetToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("rewrite"))
+ .attr("FrozenRewritePatternSet")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ };
+};
+
+/// Casts object <-> MlirOperation.
+template <>
+struct type_caster<MlirOperation> {
+ NB_TYPE_CASTER(MlirOperation, const_name("MlirOperation"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToOperation(capsule.ptr());
+ return !mlirOperationIsNull(value);
+ }
+ static handle from_cpp(MlirOperation v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ if (v.ptr == nullptr)
+ return nanobind::none();
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonOperationToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Operation")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ };
+};
+
+/// Casts object <-> MlirValue.
+template <>
+struct type_caster<MlirValue> {
+ NB_TYPE_CASTER(MlirValue, const_name("MlirValue"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToValue(capsule.ptr());
+ return !mlirValueIsNull(value);
+ }
+ static handle from_cpp(MlirValue v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ if (v.ptr == nullptr)
+ return nanobind::none();
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonValueToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Value")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .attr(MLIR_PYTHON_MAYBE_DOWNCAST_ATTR)()
+ .release();
+ };
+};
+
+/// Casts object -> MlirPassManager.
+template <>
+struct type_caster<MlirPassManager> {
+ NB_TYPE_CASTER(MlirPassManager, const_name("MlirPassManager"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToPassManager(capsule.ptr());
+ return !mlirPassManagerIsNull(value);
+ }
+};
+
+/// Casts object <-> MlirTypeID.
+template <>
+struct type_caster<MlirTypeID> {
+ NB_TYPE_CASTER(MlirTypeID, const_name("MlirTypeID"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToTypeID(capsule.ptr());
+ return !mlirTypeIDIsNull(value);
+ }
+ static handle from_cpp(MlirTypeID v, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ if (v.ptr == nullptr)
+ return nanobind::none();
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonTypeIDToCapsule(v));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("TypeID")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .release();
+ };
+};
+
+/// Casts object <-> MlirType.
+template <>
+struct type_caster<MlirType> {
+ NB_TYPE_CASTER(MlirType, const_name("MlirType"));
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
+ nanobind::object capsule = mlirApiObjectToCapsule(src);
+ value = mlirPythonCapsuleToType(capsule.ptr());
+ return !mlirTypeIsNull(value);
+ }
+ static handle from_cpp(MlirType t, rv_policy,
+ cleanup_list *cleanup) noexcept {
+ nanobind::object capsule =
+ nanobind::steal<nanobind::object>(mlirPythonTypeToCapsule(t));
+ return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Type")
+ .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
+ .attr(MLIR_PYTHON_MAYBE_DOWNCAST_ATTR)()
+ .release();
+ }
+};
+
+} // namespace detail
+} // namespace nanobind
+
+namespace mlir {
+namespace python {
+namespace nanobind_adaptors {
+
+/// Provides a facility like nanobind::class_ for defining a new class in a
+/// scope, but this allows extension of an arbitrary Python class, defining
+/// methods on it is a similar way. Classes defined in this way are very similar
+/// to if defined in Python in the usual way but use nanobind machinery to
+/// do it. These are not "real" nanobind classes but pure Python classes
+/// with no relation to a concrete C++ class.
+///
+/// Derived from a discussion upstream:
+/// https://github.com/pybind/pybind11/issues/1193
+/// (plus a fair amount of extra curricular poking)
+/// TODO: If this proves useful, see about including it in nanobind.
+class pure_subclass {
+public:
+ pure_subclass(nanobind::handle scope, const char *derivedClassName,
+ const nanobind::object &superClass) {
+ nanobind::object pyType =
+ nanobind::borrow<nanobind::object>((PyObject *)&PyType_Type);
+ nanobind::object metaclass = pyType(superClass);
+ nanobind::dict attributes;
+
+ thisClass = metaclass(derivedClassName, nanobind::make_tuple(superClass),
+ attributes);
+ scope.attr(derivedClassName) = thisClass;
+ }
+
+ template <typename Func, typename... Extra>
+ pure_subclass &def(const char *name, Func &&f, const Extra &...extra) {
+ nanobind::object cf = nanobind::cpp_function(
+ std::forward<Func>(f), nanobind::name(name), nanobind::is_method(),
+ nanobind::scope(thisClass), extra...);
+ thisClass.attr(name) = cf;
+ return *this;
+ }
+
+ template <typename Func, typename... Extra>
+ pure_subclass &def_property_readonly(const char *name, Func &&f,
+ const Extra &...extra) {
+ nanobind::object cf = nanobind::cpp_function(
+ std::forward<Func>(f), nanobind::name(name), nanobind::is_method(),
+ nanobind::scope(thisClass), extra...);
+ auto builtinProperty =
+ nanobind::borrow<nanobind::object>((PyObject *)&PyProperty_Type);
+ thisClass.attr(name) = builtinProperty(cf);
+ return *this;
+ }
+
+ template <typename Func, typename... Extra>
+ pure_subclass &def_staticmethod(const char *name, Func &&f,
+ const Extra &...extra) {
+ static_assert(!std::is_member_function_pointer<Func>::value,
+ "def_staticmethod(...) called with a non-static member "
+ "function pointer");
+ nanobind::object cf = nanobind::cpp_function(
+ std::forward<Func>(f),
+ nanobind::name(name), // nanobind::scope(thisClass),
+ extra...);
+ thisClass.attr(name) = cf;
+ return *this;
+ }
+
+ template <typename Func, typename... Extra>
+ pure_subclass &def_classmethod(const char *name, Func &&f,
+ const Extra &...extra) {
+ static_assert(!std::is_member_function_pointer<Func>::value,
+ "def_classmethod(...) called with a non-static member "
+ "function pointer");
+ nanobind::object cf = nanobind::cpp_function(
+ std::forward<Func>(f),
+ nanobind::name(name), // nanobind::scope(thisClass),
+ extra...);
+ thisClass.attr(name) =
+ nanobind::borrow<nanobind::object>(PyClassMethod_New(cf.ptr()));
+ return *this;
+ }
+
+ nanobind::object get_class() const { return thisClass; }
+
+protected:
+ nanobind::object superClass;
+ nanobind::object thisClass;
+};
+
+/// Creates a custom subclass of mlir.ir.Attribute, implementing a casting
+/// constructor and type checking methods.
+class mlir_attribute_subclass : public pure_subclass {
+public:
+ using IsAFunctionTy = bool (*)(MlirAttribute);
+ using GetTypeIDFunctionTy = MlirTypeID (*)();
+
+ /// Subclasses by looking up the super-class dynamically.
+ mlir_attribute_subclass(nanobind::handle scope, const char *attrClassName,
+ IsAFunctionTy isaFunction,
+ GetTypeIDFunctionTy getTypeIDFunction = nullptr)
+ : mlir_attribute_subclass(
+ scope, attrClassName, isaFunction,
+ nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Attribute"),
+ getTypeIDFunction) {}
+
+ /// Subclasses with a provided mlir.ir.Attribute super-class. This must
+ /// be used if the subclass is being defined in the same extension module
+ /// as the mlir.ir class (otherwise, it will trigger a recursive
+ /// initialization).
+ mlir_attribute_subclass(nanobind::handle scope, const char *typeClassName,
+ IsAFunctionTy isaFunction,
+ const nanobind::object &superCls,
+ GetTypeIDFunctionTy getTypeIDFunction = nullptr)
+ : pure_subclass(scope, typeClassName, superCls) {
+ // Casting constructor. Note that it hard, if not impossible, to properly
+ // call chain to parent `__init__` in nanobind due to its special handling
+ // for init functions that don't have a fully constructed self-reference,
+ // which makes it impossible to forward it to `__init__` of a superclass.
+ // Instead, provide a custom `__new__` and call that of a superclass, which
+ // eventually calls `__init__` of the superclass. Since attribute subclasses
+ // have no additional members, we can just return the instance thus created
+ // without amending it.
+ std::string captureTypeName(
+ typeClassName); // As string in case if typeClassName is not static.
+ nanobind::object newCf = nanobind::cpp_function(
+ [superCls, isaFunction, captureTypeName](
+ nanobind::object cls, nanobind::object otherAttribute) {
+ MlirAttribute rawAttribute =
+ nanobind::cast<MlirAttribute>(otherAttribute);
+ if (!isaFunction(rawAttribute)) {
+ auto origRepr =
+ nanobind::cast<std::string>(nanobind::repr(otherAttribute));
+ throw std::invalid_argument(
+ (llvm::Twine("Cannot cast attribute to ") + captureTypeName +
+ " (from " + origRepr + ")")
+ .str());
+ }
+ nanobind::object self = superCls.attr("__new__")(cls, otherAttribute);
+ return self;
+ },
+ nanobind::name("__new__"), nanobind::arg("cls"),
+ nanobind::arg("cast_from_attr"));
+ thisClass.attr("__new__") = newCf;
+
+ // 'isinstance' method.
+ def_staticmethod(
+ "isinstance",
+ [isaFunction](MlirAttribute other) { return isaFunction(other); },
+ nanobind::arg("other_attribute"));
+ def("__repr__", [superCls, captureTypeName](nanobind::object self) {
+ return nanobind::repr(superCls(self))
+ .attr("replace")(superCls.attr("__name__"), captureTypeName);
+ });
+ if (getTypeIDFunction) {
+ def_staticmethod("get_static_typeid",
+ [getTypeIDFunction]() { return getTypeIDFunction(); });
+ nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr(MLIR_PYTHON_CAPI_TYPE_CASTER_REGISTER_ATTR)(
+ getTypeIDFunction())(nanobind::cpp_function(
+ [thisClass = thisClass](const nanobind::object &mlirAttribute) {
+ return thisClass(mlirAttribute);
+ }));
+ }
+ }
+};
+
+/// Creates a custom subclass of mlir.ir.Type, implementing a casting
+/// constructor and type checking methods.
+class mlir_type_subclass : public pure_subclass {
+public:
+ using IsAFunctionTy = bool (*)(MlirType);
+ using GetTypeIDFunctionTy = MlirTypeID (*)();
+
+ /// Subclasses by looking up the super-class dynamically.
+ mlir_type_subclass(nanobind::handle scope, const char *typeClassName,
+ IsAFunctionTy isaFunction,
+ GetTypeIDFunctionTy getTypeIDFunction = nullptr)
+ : mlir_type_subclass(
+ scope, typeClassName, isaFunction,
+ nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Type"),
+ getTypeIDFunction) {}
+
+ /// Subclasses with a provided mlir.ir.Type super-class. This must
+ /// be used if the subclass is being defined in the same extension module
+ /// as the mlir.ir class (otherwise, it will trigger a recursive
+ /// initialization).
+ mlir_type_subclass(nanobind::handle scope, const char *typeClassName,
+ IsAFunctionTy isaFunction,
+ const nanobind::object &superCls,
+ GetTypeIDFunctionTy getTypeIDFunction = nullptr)
+ : pure_subclass(scope, typeClassName, superCls) {
+ // Casting constructor. Note that it hard, if not impossible, to properly
+ // call chain to parent `__init__` in nanobind due to its special handling
+ // for init functions that don't have a fully constructed self-reference,
+ // which makes it impossible to forward it to `__init__` of a superclass.
+ // Instead, provide a custom `__new__` and call that of a superclass, which
+ // eventually calls `__init__` of the superclass. Since attribute subclasses
+ // have no additional members, we can just return the instance thus created
+ // without amending it.
+ std::string captureTypeName(
+ typeClassName); // As string in case if typeClassName is not static.
+ nanobind::object newCf = nanobind::cpp_function(
+ [superCls, isaFunction, captureTypeName](nanobind::object cls,
+ nanobind::object otherType) {
+ MlirType rawType = nanobind::cast<MlirType>(otherType);
+ if (!isaFunction(rawType)) {
+ auto origRepr =
+ nanobind::cast<std::string>(nanobind::repr(otherType));
+ throw std::invalid_argument((llvm::Twine("Cannot cast type to ") +
+ captureTypeName + " (from " +
+ origRepr + ")")
+ .str());
+ }
+ nanobind::object self = superCls.attr("__new__")(cls, otherType);
+ return self;
+ },
+ nanobind::name("__new__"), nanobind::arg("cls"),
+ nanobind::arg("cast_from_type"));
+ thisClass.attr("__new__") = newCf;
+
+ // 'isinstance' method.
+ def_staticmethod(
+ "isinstance",
+ [isaFunction](MlirType other) { return isaFunction(other); },
+ nanobind::arg("other_type"));
+ def("__repr__", [superCls, captureTypeName](nanobind::object self) {
+ return nanobind::repr(superCls(self))
+ .attr("replace")(superCls.attr("__name__"), captureTypeName);
+ });
+ if (getTypeIDFunction) {
+ // 'get_static_typeid' method.
+ // This is modeled as a static method instead of a static property because
+ // `def_property_readonly_static` is not available in `pure_subclass` and
+ // we do not want to introduce the complexity that pybind uses to
+ // implement it.
+ def_staticmethod("get_static_typeid",
+ [getTypeIDFunction]() { return getTypeIDFunction(); });
+ nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr(MLIR_PYTHON_CAPI_TYPE_CASTER_REGISTER_ATTR)(
+ getTypeIDFunction())(nanobind::cpp_function(
+ [thisClass = thisClass](const nanobind::object &mlirType) {
+ return thisClass(mlirType);
+ }));
+ }
+ }
+};
+
+/// Creates a custom subclass of mlir.ir.Value, implementing a casting
+/// constructor and type checking methods.
+class mlir_value_subclass : public pure_subclass {
+public:
+ using IsAFunctionTy = bool (*)(MlirValue);
+
+ /// Subclasses by looking up the super-class dynamically.
+ mlir_value_subclass(nanobind::handle scope, const char *valueClassName,
+ IsAFunctionTy isaFunction)
+ : mlir_value_subclass(
+ scope, valueClassName, isaFunction,
+ nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("Value")) {}
+
+ /// Subclasses with a provided mlir.ir.Value super-class. This must
+ /// be used if the subclass is being defined in the same extension module
+ /// as the mlir.ir class (otherwise, it will trigger a recursive
+ /// initialization).
+ mlir_value_subclass(nanobind::handle scope, const char *valueClassName,
+ IsAFunctionTy isaFunction,
+ const nanobind::object &superCls)
+ : pure_subclass(scope, valueClassName, superCls) {
+ // Casting constructor. Note that it hard, if not impossible, to properly
+ // call chain to parent `__init__` in nanobind due to its special handling
+ // for init functions that don't have a fully constructed self-reference,
+ // which makes it impossible to forward it to `__init__` of a superclass.
+ // Instead, provide a custom `__new__` and call that of a superclass, which
+ // eventually calls `__init__` of the superclass. Since attribute subclasses
+ // have no additional members, we can just return the instance thus created
+ // without amending it.
+ std::string captureValueName(
+ valueClassName); // As string in case if valueClassName is not static.
+ nanobind::object newCf = nanobind::cpp_function(
+ [superCls, isaFunction, captureValueName](nanobind::object cls,
+ nanobind::object otherValue) {
+ MlirValue rawValue = nanobind::cast<MlirValue>(otherValue);
+ if (!isaFunction(rawValue)) {
+ auto origRepr =
+ nanobind::cast<std::string>(nanobind::repr(otherValue));
+ throw std::invalid_argument((llvm::Twine("Cannot cast value to ") +
+ captureValueName + " (from " +
+ origRepr + ")")
+ .str());
+ }
+ nanobind::object self = superCls.attr("__new__")(cls, otherValue);
+ return self;
+ },
+ nanobind::name("__new__"), nanobind::arg("cls"),
+ nanobind::arg("cast_from_value"));
+ thisClass.attr("__new__") = newCf;
+
+ // 'isinstance' method.
+ def_staticmethod(
+ "isinstance",
+ [isaFunction](MlirValue other) { return isaFunction(other); },
+ nanobind::arg("other_value"));
+ }
+};
+
+} // namespace nanobind_adaptors
+
+/// RAII scope intercepting all diagnostics into a string. The message must be
+/// checked before this goes out of scope.
+class CollectDiagnosticsToStringScope {
+public:
+ explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
+ handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
+ /*deleteUserData=*/nullptr);
+ }
+ ~CollectDiagnosticsToStringScope() {
+ assert(errorMessage.empty() && "unchecked error message");
+ mlirContextDetachDiagnosticHandler(context, handlerID);
+ }
+
+ [[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
+
+private:
+ static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
+ auto printer = +[](MlirStringRef message, void *data) {
+ *static_cast<std::string *>(data) +=
+ llvm::StringRef(message.data, message.length);
+ };
+ MlirLocation loc = mlirDiagnosticGetLocation(diag);
+ *static_cast<std::string *>(data) += "at ";
+ mlirLocationPrint(loc, printer, data);
+ *static_cast<std::string *>(data) += ": ";
+ mlirDiagnosticPrint(diag, printer, data);
+ return mlirLogicalResultSuccess();
+ }
+
+ MlirContext context;
+ MlirDiagnosticHandlerID handlerID;
+ std::string errorMessage = "";
+};
+
+} // namespace python
+} // namespace mlir
+
+#endif // MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
diff --git a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h
index df4b9bf713592d..c8233355d1d67b 100644
--- a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h
+++ b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h
@@ -1,4 +1,4 @@
-//===- PybindAdaptors.h - Adaptors for interop with MLIR APIs -------------===//
+//===- PybindAdaptors.h - Interop with MLIR APIs via pybind11 -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,9 +6,10 @@
//
//===----------------------------------------------------------------------===//
// This file contains adaptors for clients of the core MLIR Python APIs to
-// interop via MLIR CAPI types. The facilities here do not depend on
-// implementation details of the MLIR Python API and do not introduce C++-level
-// dependencies with it (requiring only Python and CAPI-level dependencies).
+// interop via MLIR CAPI types, using pybind11. The facilities here do not
+// depend on implementation details of the MLIR Python API and do not introduce
+// C++-level dependencies with it (requiring only Python and CAPI-level
+// dependencies).
//
// It is encouraged to be used both in-tree and out-of-tree. For in-tree use
// cases, it should be used for dialect implementations (versus relying on
@@ -611,40 +612,6 @@ class mlir_value_subclass : public pure_subclass {
} // namespace adaptors
-/// RAII scope intercepting all diagnostics into a string. The message must be
-/// checked before this goes out of scope.
-class CollectDiagnosticsToStringScope {
-public:
- explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
- handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
- /*deleteUserData=*/nullptr);
- }
- ~CollectDiagnosticsToStringScope() {
- assert(errorMessage.empty() && "unchecked error message");
- mlirContextDetachDiagnosticHandler(context, handlerID);
- }
-
- [[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
-
-private:
- static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
- auto printer = +[](MlirStringRef message, void *data) {
- *static_cast<std::string *>(data) +=
- llvm::StringRef(message.data, message.length);
- };
- MlirLocation loc = mlirDiagnosticGetLocation(diag);
- *static_cast<std::string *>(data) += "at ";
- mlirLocationPrint(loc, printer, data);
- *static_cast<std::string *>(data) += ": ";
- mlirDiagnosticPrint(diag, printer, data);
- return mlirLogicalResultSuccess();
- }
-
- MlirContext context;
- MlirDiagnosticHandlerID handlerID;
- std::string errorMessage = "";
-};
-
} // namespace python
} // namespace mlir
diff --git a/mlir/lib/Bindings/Python/DialectLLVM.cpp b/mlir/lib/Bindings/Python/DialectLLVM.cpp
index 42a4c8c0793ba8..cccf1370b8cc87 100644
--- a/mlir/lib/Bindings/Python/DialectLLVM.cpp
+++ b/mlir/lib/Bindings/Python/DialectLLVM.cpp
@@ -6,11 +6,13 @@
//
//===----------------------------------------------------------------------===//
+#include <string>
+
#include "mlir-c/Dialect/LLVM.h"
#include "mlir-c/IR.h"
#include "mlir-c/Support.h"
+#include "mlir/Bindings/Python/Diagnostics.h"
#include "mlir/Bindings/Python/PybindAdaptors.h"
-#include <string>
namespace py = pybind11;
using namespace llvm;
diff --git a/mlir/lib/Bindings/Python/TransformInterpreter.cpp b/mlir/lib/Bindings/Python/TransformInterpreter.cpp
index f6b4532b1b6be4..0c8c0e0a965aa7 100644
--- a/mlir/lib/Bindings/Python/TransformInterpreter.cpp
+++ b/mlir/lib/Bindings/Python/TransformInterpreter.cpp
@@ -10,14 +10,15 @@
//
//===----------------------------------------------------------------------===//
+#include <pybind11/detail/common.h>
+#include <pybind11/pybind11.h>
+
#include "mlir-c/Dialect/Transform/Interpreter.h"
#include "mlir-c/IR.h"
#include "mlir-c/Support.h"
+#include "mlir/Bindings/Python/Diagnostics.h"
#include "mlir/Bindings/Python/PybindAdaptors.h"
-#include <pybind11/detail/common.h>
-#include <pybind11/pybind11.h>
-
namespace py = pybind11;
namespace {
diff --git a/mlir/python/CMakeLists.txt b/mlir/python/CMakeLists.txt
index 23187f256455bb..e1b870b53ad25c 100644
--- a/mlir/python/CMakeLists.txt
+++ b/mlir/python/CMakeLists.txt
@@ -683,7 +683,9 @@ if(MLIR_INCLUDE_TESTS)
MLIRPythonTestSources.Dialects.PythonTest
ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mlir"
ADD_TO_PARENT MLIRPythonTestSources.Dialects
- SOURCES dialects/python_test.py)
+ SOURCES
+ dialects/python_test.py
+ )
set(LLVM_TARGET_DEFINITIONS
"${MLIR_MAIN_SRC_DIR}/test/python/python_test_ops.td")
mlir_tablegen(
@@ -697,12 +699,25 @@ if(MLIR_INCLUDE_TESTS)
ADD_TO_PARENT MLIRPythonTestSources.Dialects.PythonTest
SOURCES "dialects/_python_test_ops_gen.py")
- declare_mlir_python_extension(MLIRPythonTestSources.PythonTestExtension
- MODULE_NAME _mlirPythonTest
+ declare_mlir_python_extension(MLIRPythonTestSources.PythonTestExtensionPybind11
+ MODULE_NAME _mlirPythonTestPybind11
+ ADD_TO_PARENT MLIRPythonTestSources.Dialects
+ ROOT_DIR "${MLIR_SOURCE_DIR}/test/python/lib"
+ PYTHON_BINDINGS_LIBRARY pybind11
+ SOURCES
+ PythonTestModulePybind11.cpp
+ PRIVATE_LINK_LIBS
+ LLVMSupport
+ EMBED_CAPI_LINK_LIBS
+ MLIRCAPIPythonTestDialect
+ )
+ declare_mlir_python_extension(MLIRPythonTestSources.PythonTestExtensionNanobind
+ MODULE_NAME _mlirPythonTestNanobind
ADD_TO_PARENT MLIRPythonTestSources.Dialects
ROOT_DIR "${MLIR_SOURCE_DIR}/test/python/lib"
+ PYTHON_BINDINGS_LIBRARY nanobind
SOURCES
- PythonTestModule.cpp
+ PythonTestModuleNanobind.cpp
PRIVATE_LINK_LIBS
LLVMSupport
EMBED_CAPI_LINK_LIBS
diff --git a/mlir/python/mlir/dialects/python_test.py b/mlir/python/mlir/dialects/python_test.py
index b5baa80bc767fb..9380896c8c06e8 100644
--- a/mlir/python/mlir/dialects/python_test.py
+++ b/mlir/python/mlir/dialects/python_test.py
@@ -3,15 +3,14 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
from ._python_test_ops_gen import *
-from .._mlir_libs._mlirPythonTest import (
- TestAttr,
- TestType,
- TestTensorValue,
- TestIntegerRankedTensorType,
-)
-def register_python_test_dialect(registry):
- from .._mlir_libs import _mlirPythonTest
+def register_python_test_dialect(registry, use_nanobind):
+ if use_nanobind:
+ from .._mlir_libs import _mlirPythonTestNanobind
- _mlirPythonTest.register_dialect(registry)
+ _mlirPythonTestNanobind.register_dialect(registry)
+ else:
+ from .._mlir_libs import _mlirPythonTestPybind11
+
+ _mlirPythonTestPybind11.register_dialect(registry)
diff --git a/mlir/python/requirements.txt b/mlir/python/requirements.txt
index 272d066831f927..ab8a9122919e19 100644
--- a/mlir/python/requirements.txt
+++ b/mlir/python/requirements.txt
@@ -1,3 +1,4 @@
+nanobind>=2.0, <3.0
numpy>=1.19.5, <=2.1.2
pybind11>=2.10.0, <=2.13.6
PyYAML>=5.4.0, <=6.0.1
diff --git a/mlir/test/python/dialects/python_test.py b/mlir/test/python/dialects/python_test.py
index 948d1225ea489c..fd678f8321fd93 100644
--- a/mlir/test/python/dialects/python_test.py
+++ b/mlir/test/python/dialects/python_test.py
@@ -1,12 +1,33 @@
-# RUN: %PYTHON %s | FileCheck %s
+# RUN: %PYTHON %s pybind11 | FileCheck %s
+# RUN: %PYTHON %s nanobind | FileCheck %s
+import sys
from mlir.ir import *
import mlir.dialects.func as func
import mlir.dialects.python_test as test
import mlir.dialects.tensor as tensor
import mlir.dialects.arith as arith
-test.register_python_test_dialect(get_dialect_registry())
+if sys.argv[1] == "pybind11":
+ from mlir._mlir_libs._mlirPythonTestPybind11 import (
+ TestAttr,
+ TestType,
+ TestTensorValue,
+ TestIntegerRankedTensorType,
+ )
+
+ test.register_python_test_dialect(get_dialect_registry(), use_nanobind=False)
+elif sys.argv[1] == "nanobind":
+ from mlir._mlir_libs._mlirPythonTestNanobind import (
+ TestAttr,
+ TestType,
+ TestTensorValue,
+ TestIntegerRankedTensorType,
+ )
+
+ test.register_python_test_dialect(get_dialect_registry(), use_nanobind=True)
+else:
+ raise ValueError("Expected pybind11 or nanobind as argument")
def run(f):
@@ -308,7 +329,7 @@ def testOptionalOperandOp():
@run
def testCustomAttribute():
with Context() as ctx, Location.unknown():
- a = test.TestAttr.get()
+ a = TestAttr.get()
# CHECK: #python_test.test_attr
print(a)
@@ -325,11 +346,11 @@ def testCustomAttribute():
print(repr(op2.test_attr))
# The following cast must not assert.
- b = test.TestAttr(a)
+ b = TestAttr(a)
unit = UnitAttr.get()
try:
- test.TestAttr(unit)
+ TestAttr(unit)
except ValueError as e:
assert "Cannot cast attribute to TestAttr" in str(e)
else:
@@ -338,7 +359,7 @@ def testCustomAttribute():
# The following must trigger a TypeError from our adaptors and must not
# crash.
try:
- test.TestAttr(42)
+ TestAttr(42)
except TypeError as e:
assert "Expected an MLIR object" in str(e)
else:
@@ -347,7 +368,7 @@ def testCustomAttribute():
# The following must trigger a TypeError from pybind (therefore, not
# checking its message) and must not crash.
try:
- test.TestAttr(42, 56)
+ TestAttr(42, 56)
except TypeError:
pass
else:
@@ -357,12 +378,12 @@ def testCustomAttribute():
@run
def testCustomType():
with Context() as ctx:
- a = test.TestType.get()
+ a = TestType.get()
# CHECK: !python_test.test_type
print(a)
# The following cast must not assert.
- b = test.TestType(a)
+ b = TestType(a)
# Instance custom types should have typeids
assert isinstance(b.typeid, TypeID)
# Subclasses of ir.Type should not have a static_typeid
@@ -374,7 +395,7 @@ def testCustomType():
i8 = IntegerType.get_signless(8)
try:
- test.TestType(i8)
+ TestType(i8)
except ValueError as e:
assert "Cannot cast type to TestType" in str(e)
else:
@@ -383,7 +404,7 @@ def testCustomType():
# The following must trigger a TypeError from our adaptors and must not
# crash.
try:
- test.TestType(42)
+ TestType(42)
except TypeError as e:
assert "Expected an MLIR object" in str(e)
else:
@@ -392,7 +413,7 @@ def testCustomType():
# The following must trigger a TypeError from pybind (therefore, not
# checking its message) and must not crash.
try:
- test.TestType(42, 56)
+ TestType(42, 56)
except TypeError:
pass
else:
@@ -405,7 +426,7 @@ def testTensorValue():
with Context() as ctx, Location.unknown():
i8 = IntegerType.get_signless(8)
- class Tensor(test.TestTensorValue):
+ class Tensor(TestTensorValue):
def __str__(self):
return super().__str__().replace("Value", "Tensor")
@@ -425,9 +446,9 @@ def __str__(self):
# Classes of custom types that inherit from concrete types should have
# static_typeid
- assert isinstance(test.TestIntegerRankedTensorType.static_typeid, TypeID)
+ assert isinstance(TestIntegerRankedTensorType.static_typeid, TypeID)
# And it should be equal to the in-tree concrete type
- assert test.TestIntegerRankedTensorType.static_typeid == t.type.typeid
+ assert TestIntegerRankedTensorType.static_typeid == t.type.typeid
d = tensor.EmptyOp([1, 2, 3], IntegerType.get_signless(5)).result
# CHECK: Value(%{{.*}} = tensor.empty() : tensor<1x2x3xi5>)
@@ -491,7 +512,7 @@ def inferReturnTypeComponents():
@run
def testCustomTypeTypeCaster():
with Context() as ctx, Location.unknown():
- a = test.TestType.get()
+ a = TestType.get()
assert a.typeid is not None
b = Type.parse("!python_test.test_type")
@@ -500,7 +521,7 @@ def testCustomTypeTypeCaster():
# CHECK: TestType(!python_test.test_type)
print(repr(b))
- c = test.TestIntegerRankedTensorType.get([10, 10], 5)
+ c = TestIntegerRankedTensorType.get([10, 10], 5)
# CHECK: tensor<10x10xi5>
print(c)
# CHECK: TestIntegerRankedTensorType(tensor<10x10xi5>)
@@ -511,7 +532,7 @@ def testCustomTypeTypeCaster():
@register_type_caster(c.typeid)
def type_caster(pytype):
- return test.TestIntegerRankedTensorType(pytype)
+ return TestIntegerRankedTensorType(pytype)
except RuntimeError as e:
print(e)
@@ -530,7 +551,7 @@ def type_caster(pytype):
@register_type_caster(c.typeid, replace=True)
def type_caster(pytype):
- return test.TestIntegerRankedTensorType(pytype)
+ return TestIntegerRankedTensorType(pytype)
d = tensor.EmptyOp([10, 10], IntegerType.get_signless(5)).result
# CHECK: tensor<10x10xi5>
diff --git a/mlir/test/python/lib/CMakeLists.txt b/mlir/test/python/lib/CMakeLists.txt
index d7cbbfbc214772..198ed8211e773f 100644
--- a/mlir/test/python/lib/CMakeLists.txt
+++ b/mlir/test/python/lib/CMakeLists.txt
@@ -1,7 +1,8 @@
set(LLVM_OPTIONAL_SOURCES
PythonTestCAPI.cpp
PythonTestDialect.cpp
- PythonTestModule.cpp
+ PythonTestModulePybind11.cpp
+ PythonTestModuleNanobind.cpp
)
add_mlir_library(MLIRPythonTestDialect
diff --git a/mlir/test/python/lib/PythonTestModuleNanobind.cpp b/mlir/test/python/lib/PythonTestModuleNanobind.cpp
new file mode 100644
index 00000000000000..7c504d04be0d13
--- /dev/null
+++ b/mlir/test/python/lib/PythonTestModuleNanobind.cpp
@@ -0,0 +1,121 @@
+//===- PythonTestModuleNanobind.cpp - PythonTest dialect extension --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This is the nanobind edition of the PythonTest dialect module.
+//===----------------------------------------------------------------------===//
+
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/vector.h>
+
+#include "PythonTestCAPI.h"
+#include "mlir-c/BuiltinAttributes.h"
+#include "mlir-c/BuiltinTypes.h"
+#include "mlir-c/IR.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
+
+namespace nb = nanobind;
+using namespace mlir::python::nanobind_adaptors;
+
+static bool mlirTypeIsARankedIntegerTensor(MlirType t) {
+ return mlirTypeIsARankedTensor(t) &&
+ mlirTypeIsAInteger(mlirShapedTypeGetElementType(t));
+}
+
+NB_MODULE(_mlirPythonTestNanobind, m) {
+ m.def(
+ "register_python_test_dialect",
+ [](MlirContext context, bool load) {
+ MlirDialectHandle pythonTestDialect =
+ mlirGetDialectHandle__python_test__();
+ mlirDialectHandleRegisterDialect(pythonTestDialect, context);
+ if (load) {
+ mlirDialectHandleLoadDialect(pythonTestDialect, context);
+ }
+ },
+ nb::arg("context"), nb::arg("load") = true);
+
+ m.def(
+ "register_dialect",
+ [](MlirDialectRegistry registry) {
+ MlirDialectHandle pythonTestDialect =
+ mlirGetDialectHandle__python_test__();
+ mlirDialectHandleInsertDialect(pythonTestDialect, registry);
+ },
+ nb::arg("registry"));
+
+ mlir_attribute_subclass(m, "TestAttr",
+ mlirAttributeIsAPythonTestTestAttribute,
+ mlirPythonTestTestAttributeGetTypeID)
+ .def_classmethod(
+ "get",
+ [](const nb::object &cls, MlirContext ctx) {
+ return cls(mlirPythonTestTestAttributeGet(ctx));
+ },
+ nb::arg("cls"), nb::arg("context").none() = nb::none());
+
+ mlir_type_subclass(m, "TestType", mlirTypeIsAPythonTestTestType,
+ mlirPythonTestTestTypeGetTypeID)
+ .def_classmethod(
+ "get",
+ [](const nb::object &cls, MlirContext ctx) {
+ return cls(mlirPythonTestTestTypeGet(ctx));
+ },
+ nb::arg("cls"), nb::arg("context").none() = nb::none());
+
+ auto typeCls =
+ mlir_type_subclass(m, "TestIntegerRankedTensorType",
+ mlirTypeIsARankedIntegerTensor,
+ nb::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr("RankedTensorType"))
+ .def_classmethod(
+ "get",
+ [](const nb::object &cls, std::vector<int64_t> shape,
+ unsigned width, MlirContext ctx) {
+ MlirAttribute encoding = mlirAttributeGetNull();
+ return cls(mlirRankedTensorTypeGet(
+ shape.size(), shape.data(), mlirIntegerTypeGet(ctx, width),
+ encoding));
+ },
+ nb::arg("cls"), nb::arg("shape"), nb::arg("width"),
+ nb::arg("context").none() = nb::none());
+
+ assert(nb::hasattr(typeCls.get_class(), "static_typeid") &&
+ "TestIntegerRankedTensorType has no static_typeid");
+
+ MlirTypeID mlirRankedTensorTypeID = mlirRankedTensorTypeGetTypeID();
+
+ nb::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr(MLIR_PYTHON_CAPI_TYPE_CASTER_REGISTER_ATTR)(
+ mlirRankedTensorTypeID, nb::arg("replace") = true)(
+ nanobind::cpp_function([typeCls](const nb::object &mlirType) {
+ return typeCls.get_class()(mlirType);
+ }));
+
+ auto valueCls = mlir_value_subclass(m, "TestTensorValue",
+ mlirTypeIsAPythonTestTestTensorValue)
+ .def("is_null", [](MlirValue &self) {
+ return mlirValueIsNull(self);
+ });
+
+ nb::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ .attr(MLIR_PYTHON_CAPI_VALUE_CASTER_REGISTER_ATTR)(
+ mlirRankedTensorTypeID)(
+ nanobind::cpp_function([valueCls](const nb::object &valueObj) {
+ nb::object capsule = mlirApiObjectToCapsule(valueObj);
+ MlirValue v = mlirPythonCapsuleToValue(capsule.ptr());
+ MlirType t = mlirValueGetType(v);
+ // This is hyper-specific in order to exercise/test registering a
+ // value caster from cpp (but only for a single test case; see
+ // testTensorValue python_test.py).
+ if (mlirShapedTypeHasStaticShape(t) &&
+ mlirShapedTypeGetDimSize(t, 0) == 1 &&
+ mlirShapedTypeGetDimSize(t, 1) == 2 &&
+ mlirShapedTypeGetDimSize(t, 2) == 3)
+ return valueCls.get_class()(valueObj);
+ return valueObj;
+ }));
+}
diff --git a/mlir/test/python/lib/PythonTestModule.cpp b/mlir/test/python/lib/PythonTestModulePybind11.cpp
similarity index 96%
rename from mlir/test/python/lib/PythonTestModule.cpp
rename to mlir/test/python/lib/PythonTestModulePybind11.cpp
index a4f538dcb55944..94a5f5178d16e8 100644
--- a/mlir/test/python/lib/PythonTestModule.cpp
+++ b/mlir/test/python/lib/PythonTestModulePybind11.cpp
@@ -5,6 +5,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+// This is the pybind11 edition of the PythonTest dialect module.
+//===----------------------------------------------------------------------===//
#include "PythonTestCAPI.h"
#include "mlir-c/BuiltinAttributes.h"
@@ -21,7 +23,7 @@ static bool mlirTypeIsARankedIntegerTensor(MlirType t) {
mlirTypeIsAInteger(mlirShapedTypeGetElementType(t));
}
-PYBIND11_MODULE(_mlirPythonTest, m) {
+PYBIND11_MODULE(_mlirPythonTestPybind11, m) {
m.def(
"register_python_test_dialect",
[](MlirContext context, bool load) {
diff --git a/utils/bazel/WORKSPACE b/utils/bazel/WORKSPACE
index 7baca11eed3d39..66ba1ac1b17e1e 100644
--- a/utils/bazel/WORKSPACE
+++ b/utils/bazel/WORKSPACE
@@ -148,6 +148,24 @@ maybe(
url = "https://github.com/pybind/pybind11/archive/v2.10.3.zip",
)
+maybe(
+ http_archive,
+ name = "robin_map",
+ strip_prefix = "robin-map-1.3.0",
+ sha256 = "a8424ad3b0affd4c57ed26f0f3d8a29604f0e1f2ef2089f497f614b1c94c7236",
+ build_file = "@llvm-raw//utils/bazel/third_party_build:robin_map.BUILD",
+ url = "https://github.com/Tessil/robin-map/archive/refs/tags/v1.3.0.tar.gz",
+)
+
+maybe(
+ http_archive,
+ name = "nanobind",
+ build_file = "@llvm-raw//utils/bazel/third_party_build:nanobind.BUILD",
+ sha256 = "bfbfc7e5759f1669e4ddb48752b1ddc5647d1430e94614d6f8626df1d508e65a",
+ strip_prefix = "nanobind-2.2.0",
+ url = "https://github.com/wjakob/nanobind/archive/refs/tags/v2.2.0.tar.gz",
+)
+
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
py_repositories()
diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
index 179fed2f5e9a00..544becfa30b40f 100644
--- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
@@ -932,7 +932,6 @@ exports_files(
filegroup(
name = "MLIRBindingsPythonHeaderFiles",
srcs = glob([
- "lib/Bindings/Python/*.h",
"include/mlir-c/Bindings/Python/*.h",
"include/mlir/Bindings/Python/*.h",
]),
@@ -942,12 +941,10 @@ cc_library(
name = "MLIRBindingsPythonHeaders",
includes = [
"include",
- "lib/Bindings/Python",
],
textual_hdrs = [":MLIRBindingsPythonHeaderFiles"],
deps = [
":CAPIIRHeaders",
- ":CAPITransformsHeaders",
"@pybind11",
"@rules_python//python/cc:current_py_cc_headers",
],
@@ -957,17 +954,41 @@ cc_library(
name = "MLIRBindingsPythonHeadersAndDeps",
includes = [
"include",
- "lib/Bindings/Python",
],
textual_hdrs = [":MLIRBindingsPythonHeaderFiles"],
deps = [
":CAPIIR",
- ":CAPITransforms",
"@pybind11",
"@rules_python//python/cc:current_py_cc_headers",
],
)
+cc_library(
+ name = "MLIRBindingsPythonNanobindHeaders",
+ includes = [
+ "include",
+ ],
+ textual_hdrs = [":MLIRBindingsPythonHeaderFiles"],
+ deps = [
+ ":CAPIIRHeaders",
+ "@nanobind",
+ "@rules_python//python/cc:current_py_cc_headers",
+ ],
+)
+
+cc_library(
+ name = "MLIRBindingsPythonNanobindHeadersAndDeps",
+ includes = [
+ "include",
+ ],
+ textual_hdrs = [":MLIRBindingsPythonHeaderFiles"],
+ deps = [
+ ":CAPIIR",
+ "@nanobind",
+ "@rules_python//python/cc:current_py_cc_headers",
+ ],
+)
+
# These flags are needed for pybind11 to work.
PYBIND11_COPTS = [
"-fexceptions",
@@ -993,16 +1014,25 @@ filegroup(
],
)
+filegroup(
+ name = "MLIRBindingsPythonCoreHeaders",
+ srcs = glob([
+ "lib/Bindings/Python/*.h",
+ ]),
+)
+
cc_library(
name = "MLIRBindingsPythonCore",
srcs = [":MLIRBindingsPythonSourceFiles"],
copts = PYBIND11_COPTS,
features = PYBIND11_FEATURES,
+ textual_hdrs = [":MLIRBindingsPythonCoreHeaders"],
deps = [
":CAPIAsync",
":CAPIDebug",
":CAPIIR",
":CAPIInterfaces",
+ ":CAPITransforms",
":MLIRBindingsPythonHeadersAndDeps",
":Support",
":config",
@@ -1017,10 +1047,12 @@ cc_library(
srcs = [":MLIRBindingsPythonSourceFiles"],
copts = PYBIND11_COPTS,
features = PYBIND11_FEATURES,
+ textual_hdrs = [":MLIRBindingsPythonCoreHeaders"],
deps = [
":CAPIAsyncHeaders",
":CAPIDebugHeaders",
":CAPIIRHeaders",
+ ":CAPITransformsHeaders",
":MLIRBindingsPythonHeaders",
":Support",
":config",
@@ -1050,6 +1082,9 @@ cc_binary(
# These flags are needed for pybind11 to work.
copts = PYBIND11_COPTS,
features = PYBIND11_FEATURES,
+ includes = [
+ "lib/Bindings/Python",
+ ],
linkshared = 1,
linkstatic = 0,
deps = [
@@ -1063,6 +1098,9 @@ cc_binary(
srcs = ["lib/Bindings/Python/DialectLinalg.cpp"],
copts = PYBIND11_COPTS,
features = PYBIND11_FEATURES,
+ includes = [
+ "lib/Bindings/Python",
+ ],
linkshared = 1,
linkstatic = 0,
deps = [
@@ -8448,9 +8486,9 @@ cc_library(
hdrs = ["include/mlir/Conversion/ConvertToLLVM/ToLLVMPass.h"],
includes = ["include"],
deps = [
+ ":Analysis",
":ConversionPassIncGen",
":ConvertToLLVMInterface",
- ":Analysis",
":IR",
":LLVMCommonConversion",
":LLVMDialect",
diff --git a/utils/bazel/third_party_build/nanobind.BUILD b/utils/bazel/third_party_build/nanobind.BUILD
new file mode 100644
index 00000000000000..262d14a040b87e
--- /dev/null
+++ b/utils/bazel/third_party_build/nanobind.BUILD
@@ -0,0 +1,25 @@
+cc_library(
+ name = "nanobind",
+ srcs = glob(
+ [
+ "src/*.cpp",
+ ],
+ exclude = ["src/nb_combined.cpp"],
+ ),
+ defines = [
+ "NB_BUILD=1",
+ "NB_SHARED=1",
+ ],
+ includes = ["include"],
+ textual_hdrs = glob(
+ [
+ "include/**/*.h",
+ "src/*.h",
+ ],
+ ),
+ visibility = ["//visibility:public"],
+ deps = [
+ "@robin_map",
+ "@rules_python//python/cc:current_py_cc_headers",
+ ],
+)
diff --git a/utils/bazel/third_party_build/robin_map.BUILD b/utils/bazel/third_party_build/robin_map.BUILD
new file mode 100644
index 00000000000000..b8d04beaed81f9
--- /dev/null
+++ b/utils/bazel/third_party_build/robin_map.BUILD
@@ -0,0 +1,12 @@
+cc_library(
+ name = "robin_map",
+ hdrs = [
+ "include/tsl/robin_growth_policy.h",
+ "include/tsl/robin_hash.h",
+ "include/tsl/robin_map.h",
+ "include/tsl/robin_set.h",
+ ],
+ includes = ["."],
+ strip_include_prefix = "include",
+ visibility = ["//visibility:public"],
+)
>From 7942d3372e2fa16a703fbf42d09478295bac4d4c Mon Sep 17 00:00:00 2001
From: Peter Hawkins <phawkins at google.com>
Date: Wed, 4 Dec 2024 02:44:33 +0000
Subject: [PATCH 2/2] [mlir python] Port Python core code to nanobind.
Why? https://nanobind.readthedocs.io/en/latest/why.html says it better
than I can, but my primary motivation for this change is to improve MLIR
IR construction time from JAX.
For a complicated Google-internal LLM model in JAX, this change improves the MLIR
lowering time by around 5s (out of around 30s), which is a significant
speedup for simply switching binding frameworks.
To a large extent, this is a mechanical change, for instance changing pybind11::
to nanobind::.
Notes:
* this PR needs https://github.com/wjakob/nanobind/pull/806 to land in
nanobind first. Without that fix, importing the MLIR modules will
fail.
* this PR does not port the in-tree dialect extension modules. They can
be ported in a future PR.
* I removed the py::sibling() annotations from def_static and def_class
in PybindAdapters.h. These ask pybind11 to try to form an overload
with an existing method, but it's not possible to form mixed
pybind11/nanobind overloads this ways and the parent class is now defined in
nanobind. Better solutions may be possible here.
* nanobind does not contain an exact equivalent of pybind11's buffer
protocol support. It was not hard to add a nanobind implementation of
a similar API.
* nanobind is pickier about casting to std::vector<bool>, expecting that
the input is a sequence of bool types, not truthy values. In a couple
of places I added code to support truthy values during casting.
* nanobind distinguishes bytes (nb::bytes) from strings (e.g.,
std::string). This required nb::bytes overloads in a few places.
---
.../mlir/Bindings/Python/Diagnostics.h | 12 +-
mlir/include/mlir/Bindings/Python/IRTypes.h | 2 +-
.../mlir/Bindings/Python/NanobindAdaptors.h | 47 +-
.../mlir/Bindings/Python/PybindAdaptors.h | 10 +-
mlir/lib/Bindings/Python/Globals.h | 51 +-
mlir/lib/Bindings/Python/IRAffine.cpp | 322 ++--
mlir/lib/Bindings/Python/IRAttributes.cpp | 703 +++++---
mlir/lib/Bindings/Python/IRCore.cpp | 1456 +++++++++--------
mlir/lib/Bindings/Python/IRInterfaces.cpp | 258 +--
mlir/lib/Bindings/Python/IRModule.cpp | 63 +-
mlir/lib/Bindings/Python/IRModule.h | 602 +++----
mlir/lib/Bindings/Python/IRTypes.cpp | 262 +--
mlir/lib/Bindings/Python/MainModule.cpp | 56 +-
.../Python/{PybindUtils.h => NanobindUtils.h} | 124 +-
mlir/lib/Bindings/Python/Pass.cpp | 55 +-
mlir/lib/Bindings/Python/Pass.h | 4 +-
mlir/lib/Bindings/Python/Rewrite.cpp | 44 +-
mlir/lib/Bindings/Python/Rewrite.h | 4 +-
mlir/python/CMakeLists.txt | 3 +-
mlir/test/python/ir/symbol_table.py | 3 +-
20 files changed, 2165 insertions(+), 1916 deletions(-)
rename mlir/lib/Bindings/Python/{PybindUtils.h => NanobindUtils.h} (82%)
diff --git a/mlir/include/mlir/Bindings/Python/Diagnostics.h b/mlir/include/mlir/Bindings/Python/Diagnostics.h
index ea80e14dde0f3a..ecda96e5243b99 100644
--- a/mlir/include/mlir/Bindings/Python/Diagnostics.h
+++ b/mlir/include/mlir/Bindings/Python/Diagnostics.h
@@ -12,9 +12,9 @@
#include <cassert>
#include <string>
+#include "llvm/ADT/StringRef.h"
#include "mlir-c/Diagnostics.h"
#include "mlir-c/IR.h"
-#include "llvm/ADT/StringRef.h"
namespace mlir {
namespace python {
@@ -22,7 +22,7 @@ namespace python {
/// RAII scope intercepting all diagnostics into a string. The message must be
/// checked before this goes out of scope.
class CollectDiagnosticsToStringScope {
-public:
+ public:
explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
/*deleteUserData=*/nullptr);
@@ -34,7 +34,7 @@ class CollectDiagnosticsToStringScope {
[[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
-private:
+ private:
static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
auto printer = +[](MlirStringRef message, void *data) {
*static_cast<std::string *>(data) +=
@@ -53,7 +53,7 @@ class CollectDiagnosticsToStringScope {
std::string errorMessage = "";
};
-} // namespace python
-} // namespace mlir
+} // namespace python
+} // namespace mlir
-#endif // MLIR_BINDINGS_PYTHON_DIAGNOSTICS_H
+#endif // MLIR_BINDINGS_PYTHON_DIAGNOSTICS_H
diff --git a/mlir/include/mlir/Bindings/Python/IRTypes.h b/mlir/include/mlir/Bindings/Python/IRTypes.h
index 9afad4c23b3f35..ba9642cf2c6a2d 100644
--- a/mlir/include/mlir/Bindings/Python/IRTypes.h
+++ b/mlir/include/mlir/Bindings/Python/IRTypes.h
@@ -9,7 +9,7 @@
#ifndef MLIR_BINDINGS_PYTHON_IRTYPES_H
#define MLIR_BINDINGS_PYTHON_IRTYPES_H
-#include "mlir/Bindings/Python/PybindAdaptors.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
namespace mlir {
diff --git a/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h b/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
index 5e01cebcb09c91..e62ea19f0f00eb 100644
--- a/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
+++ b/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
@@ -24,10 +24,10 @@
#include <cstdint>
+#include "llvm/ADT/Twine.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir-c/Diagnostics.h"
#include "mlir-c/IR.h"
-#include "llvm/ADT/Twine.h"
// Raw CAPI type casters need to be declared before use, so always include them
// first.
@@ -233,8 +233,7 @@ struct type_caster<MlirOperation> {
}
static handle from_cpp(MlirOperation v, rv_policy,
cleanup_list *cleanup) noexcept {
- if (v.ptr == nullptr)
- return nanobind::none();
+ if (v.ptr == nullptr) return nanobind::none();
nanobind::object capsule =
nanobind::steal<nanobind::object>(mlirPythonOperationToCapsule(v));
return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
@@ -255,8 +254,7 @@ struct type_caster<MlirValue> {
}
static handle from_cpp(MlirValue v, rv_policy,
cleanup_list *cleanup) noexcept {
- if (v.ptr == nullptr)
- return nanobind::none();
+ if (v.ptr == nullptr) return nanobind::none();
nanobind::object capsule =
nanobind::steal<nanobind::object>(mlirPythonValueToCapsule(v));
return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
@@ -289,8 +287,7 @@ struct type_caster<MlirTypeID> {
}
static handle from_cpp(MlirTypeID v, rv_policy,
cleanup_list *cleanup) noexcept {
- if (v.ptr == nullptr)
- return nanobind::none();
+ if (v.ptr == nullptr) return nanobind::none();
nanobind::object capsule =
nanobind::steal<nanobind::object>(mlirPythonTypeIDToCapsule(v));
return nanobind::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
@@ -321,8 +318,8 @@ struct type_caster<MlirType> {
}
};
-} // namespace detail
-} // namespace nanobind
+} // namespace detail
+} // namespace nanobind
namespace mlir {
namespace python {
@@ -340,7 +337,7 @@ namespace nanobind_adaptors {
/// (plus a fair amount of extra curricular poking)
/// TODO: If this proves useful, see about including it in nanobind.
class pure_subclass {
-public:
+ public:
pure_subclass(nanobind::handle scope, const char *derivedClassName,
const nanobind::object &superClass) {
nanobind::object pyType =
@@ -382,7 +379,7 @@ class pure_subclass {
"function pointer");
nanobind::object cf = nanobind::cpp_function(
std::forward<Func>(f),
- nanobind::name(name), // nanobind::scope(thisClass),
+ nanobind::name(name), // nanobind::scope(thisClass),
extra...);
thisClass.attr(name) = cf;
return *this;
@@ -396,7 +393,7 @@ class pure_subclass {
"function pointer");
nanobind::object cf = nanobind::cpp_function(
std::forward<Func>(f),
- nanobind::name(name), // nanobind::scope(thisClass),
+ nanobind::name(name), // nanobind::scope(thisClass),
extra...);
thisClass.attr(name) =
nanobind::borrow<nanobind::object>(PyClassMethod_New(cf.ptr()));
@@ -405,7 +402,7 @@ class pure_subclass {
nanobind::object get_class() const { return thisClass; }
-protected:
+ protected:
nanobind::object superClass;
nanobind::object thisClass;
};
@@ -413,7 +410,7 @@ class pure_subclass {
/// Creates a custom subclass of mlir.ir.Attribute, implementing a casting
/// constructor and type checking methods.
class mlir_attribute_subclass : public pure_subclass {
-public:
+ public:
using IsAFunctionTy = bool (*)(MlirAttribute);
using GetTypeIDFunctionTy = MlirTypeID (*)();
@@ -445,7 +442,7 @@ class mlir_attribute_subclass : public pure_subclass {
// have no additional members, we can just return the instance thus created
// without amending it.
std::string captureTypeName(
- typeClassName); // As string in case if typeClassName is not static.
+ typeClassName); // As string in case if typeClassName is not static.
nanobind::object newCf = nanobind::cpp_function(
[superCls, isaFunction, captureTypeName](
nanobind::object cls, nanobind::object otherAttribute) {
@@ -491,7 +488,7 @@ class mlir_attribute_subclass : public pure_subclass {
/// Creates a custom subclass of mlir.ir.Type, implementing a casting
/// constructor and type checking methods.
class mlir_type_subclass : public pure_subclass {
-public:
+ public:
using IsAFunctionTy = bool (*)(MlirType);
using GetTypeIDFunctionTy = MlirTypeID (*)();
@@ -523,7 +520,7 @@ class mlir_type_subclass : public pure_subclass {
// have no additional members, we can just return the instance thus created
// without amending it.
std::string captureTypeName(
- typeClassName); // As string in case if typeClassName is not static.
+ typeClassName); // As string in case if typeClassName is not static.
nanobind::object newCf = nanobind::cpp_function(
[superCls, isaFunction, captureTypeName](nanobind::object cls,
nanobind::object otherType) {
@@ -573,7 +570,7 @@ class mlir_type_subclass : public pure_subclass {
/// Creates a custom subclass of mlir.ir.Value, implementing a casting
/// constructor and type checking methods.
class mlir_value_subclass : public pure_subclass {
-public:
+ public:
using IsAFunctionTy = bool (*)(MlirValue);
/// Subclasses by looking up the super-class dynamically.
@@ -601,7 +598,7 @@ class mlir_value_subclass : public pure_subclass {
// have no additional members, we can just return the instance thus created
// without amending it.
std::string captureValueName(
- valueClassName); // As string in case if valueClassName is not static.
+ valueClassName); // As string in case if valueClassName is not static.
nanobind::object newCf = nanobind::cpp_function(
[superCls, isaFunction, captureValueName](nanobind::object cls,
nanobind::object otherValue) {
@@ -629,12 +626,12 @@ class mlir_value_subclass : public pure_subclass {
}
};
-} // namespace nanobind_adaptors
+} // namespace nanobind_adaptors
/// RAII scope intercepting all diagnostics into a string. The message must be
/// checked before this goes out of scope.
class CollectDiagnosticsToStringScope {
-public:
+ public:
explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
/*deleteUserData=*/nullptr);
@@ -646,7 +643,7 @@ class CollectDiagnosticsToStringScope {
[[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
-private:
+ private:
static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
auto printer = +[](MlirStringRef message, void *data) {
*static_cast<std::string *>(data) +=
@@ -665,7 +662,7 @@ class CollectDiagnosticsToStringScope {
std::string errorMessage = "";
};
-} // namespace python
-} // namespace mlir
+} // namespace python
+} // namespace mlir
-#endif // MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
+#endif // MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
diff --git a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h
index c8233355d1d67b..edc69774be9227 100644
--- a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h
+++ b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h
@@ -374,9 +374,8 @@ class pure_subclass {
static_assert(!std::is_member_function_pointer<Func>::value,
"def_staticmethod(...) called with a non-static member "
"function pointer");
- py::cpp_function cf(
- std::forward<Func>(f), py::name(name), py::scope(thisClass),
- py::sibling(py::getattr(thisClass, name, py::none())), extra...);
+ py::cpp_function cf(std::forward<Func>(f), py::name(name),
+ py::scope(thisClass), extra...);
thisClass.attr(cf.name()) = py::staticmethod(cf);
return *this;
}
@@ -387,9 +386,8 @@ class pure_subclass {
static_assert(!std::is_member_function_pointer<Func>::value,
"def_classmethod(...) called with a non-static member "
"function pointer");
- py::cpp_function cf(
- std::forward<Func>(f), py::name(name), py::scope(thisClass),
- py::sibling(py::getattr(thisClass, name, py::none())), extra...);
+ py::cpp_function cf(std::forward<Func>(f), py::name(name),
+ py::scope(thisClass), extra...);
thisClass.attr(cf.name()) =
py::reinterpret_borrow<py::object>(PyClassMethod_New(cf.ptr()));
return *this;
diff --git a/mlir/lib/Bindings/Python/Globals.h b/mlir/lib/Bindings/Python/Globals.h
index a022067f5c7e57..ecbbb4ea1e7f90 100644
--- a/mlir/lib/Bindings/Python/Globals.h
+++ b/mlir/lib/Bindings/Python/Globals.h
@@ -9,17 +9,16 @@
#ifndef MLIR_BINDINGS_PYTHON_GLOBALS_H
#define MLIR_BINDINGS_PYTHON_GLOBALS_H
-#include "PybindUtils.h"
+#include <optional>
+#include <string>
+#include <vector>
-#include "mlir-c/IR.h"
-#include "mlir/CAPI/Support.h"
+#include "NanobindUtils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
-
-#include <optional>
-#include <string>
-#include <vector>
+#include "mlir-c/IR.h"
+#include "mlir/CAPI/Support.h"
namespace mlir {
namespace python {
@@ -57,71 +56,71 @@ class PyGlobals {
/// Raises an exception if the mapping already exists and replace == false.
/// This is intended to be called by implementation code.
void registerAttributeBuilder(const std::string &attributeKind,
- pybind11::function pyFunc,
+ nanobind::callable pyFunc,
bool replace = false);
/// Adds a user-friendly type caster. Raises an exception if the mapping
/// already exists and replace == false. This is intended to be called by
/// implementation code.
- void registerTypeCaster(MlirTypeID mlirTypeID, pybind11::function typeCaster,
+ void registerTypeCaster(MlirTypeID mlirTypeID, nanobind::callable typeCaster,
bool replace = false);
/// Adds a user-friendly value caster. Raises an exception if the mapping
/// already exists and replace == false. This is intended to be called by
/// implementation code.
void registerValueCaster(MlirTypeID mlirTypeID,
- pybind11::function valueCaster,
+ nanobind::callable valueCaster,
bool replace = false);
/// Adds a concrete implementation dialect class.
/// Raises an exception if the mapping already exists.
/// This is intended to be called by implementation code.
void registerDialectImpl(const std::string &dialectNamespace,
- pybind11::object pyClass);
+ nanobind::object pyClass);
/// Adds a concrete implementation operation class.
/// Raises an exception if the mapping already exists and replace == false.
/// This is intended to be called by implementation code.
void registerOperationImpl(const std::string &operationName,
- pybind11::object pyClass, bool replace = false);
+ nanobind::object pyClass, bool replace = false);
/// Returns the custom Attribute builder for Attribute kind.
- std::optional<pybind11::function>
- lookupAttributeBuilder(const std::string &attributeKind);
+ std::optional<nanobind::callable> lookupAttributeBuilder(
+ const std::string &attributeKind);
/// Returns the custom type caster for MlirTypeID mlirTypeID.
- std::optional<pybind11::function> lookupTypeCaster(MlirTypeID mlirTypeID,
+ std::optional<nanobind::callable> lookupTypeCaster(MlirTypeID mlirTypeID,
MlirDialect dialect);
/// Returns the custom value caster for MlirTypeID mlirTypeID.
- std::optional<pybind11::function> lookupValueCaster(MlirTypeID mlirTypeID,
+ std::optional<nanobind::callable> lookupValueCaster(MlirTypeID mlirTypeID,
MlirDialect dialect);
/// Looks up a registered dialect class by namespace. Note that this may
/// trigger loading of the defining module and can arbitrarily re-enter.
- std::optional<pybind11::object>
- lookupDialectClass(const std::string &dialectNamespace);
+ std::optional<nanobind::object> lookupDialectClass(
+ const std::string &dialectNamespace);
/// Looks up a registered operation class (deriving from OpView) by operation
/// name. Note that this may trigger a load of the dialect, which can
/// arbitrarily re-enter.
- std::optional<pybind11::object>
- lookupOperationClass(llvm::StringRef operationName);
+ std::optional<nanobind::object> lookupOperationClass(
+ llvm::StringRef operationName);
-private:
+ private:
static PyGlobals *instance;
/// Module name prefixes to search under for dialect implementation modules.
std::vector<std::string> dialectSearchPrefixes;
/// Map of dialect namespace to external dialect class object.
- llvm::StringMap<pybind11::object> dialectClassMap;
+ llvm::StringMap<nanobind::object> dialectClassMap;
/// Map of full operation name to external operation class object.
- llvm::StringMap<pybind11::object> operationClassMap;
+ llvm::StringMap<nanobind::object> operationClassMap;
/// Map of attribute ODS name to custom builder.
- llvm::StringMap<pybind11::object> attributeBuilderMap;
+ llvm::StringMap<nanobind::callable> attributeBuilderMap;
/// Map of MlirTypeID to custom type caster.
- llvm::DenseMap<MlirTypeID, pybind11::object> typeCasterMap;
+ llvm::DenseMap<MlirTypeID, nanobind::callable> typeCasterMap;
/// Map of MlirTypeID to custom value caster.
- llvm::DenseMap<MlirTypeID, pybind11::object> valueCasterMap;
+ llvm::DenseMap<MlirTypeID, nanobind::callable> valueCasterMap;
/// Set of dialect namespaces that we have attempted to import implementation
/// modules for.
llvm::StringSet<> loadedDialectModules;
diff --git a/mlir/lib/Bindings/Python/IRAffine.cpp b/mlir/lib/Bindings/Python/IRAffine.cpp
index b138e131e851ea..577aa5e5504348 100644
--- a/mlir/lib/Bindings/Python/IRAffine.cpp
+++ b/mlir/lib/Bindings/Python/IRAffine.cpp
@@ -6,31 +6,30 @@
//
//===----------------------------------------------------------------------===//
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/string.h>
+#include <nanobind/stl/vector.h>
+
#include <cstddef>
#include <cstdint>
-#include <pybind11/cast.h>
-#include <pybind11/detail/common.h>
-#include <pybind11/pybind11.h>
-#include <pybind11/pytypes.h>
+#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "IRModule.h"
-
-#include "PybindUtils.h"
-
+#include "NanobindUtils.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
#include "mlir-c/AffineExpr.h"
#include "mlir-c/AffineMap.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir-c/IntegerSet.h"
#include "mlir/Support/LLVM.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-namespace py = pybind11;
+namespace nb = nanobind;
using namespace mlir;
using namespace mlir::python;
@@ -46,23 +45,23 @@ static const char kDumpDocstring[] =
/// Throws errors in case of failure, using "action" to describe what the caller
/// was attempting to do.
template <typename PyType, typename CType>
-static void pyListToVector(const py::list &list,
+static void pyListToVector(const nb::list &list,
llvm::SmallVectorImpl<CType> &result,
StringRef action) {
- result.reserve(py::len(list));
- for (py::handle item : list) {
+ result.reserve(nb::len(list));
+ for (nb::handle item : list) {
try {
- result.push_back(item.cast<PyType>());
- } catch (py::cast_error &err) {
+ result.push_back(nb::cast<PyType>(item));
+ } catch (nb::cast_error &err) {
std::string msg = (llvm::Twine("Invalid expression when ") + action +
" (" + err.what() + ")")
.str();
- throw py::cast_error(msg);
- } catch (py::reference_cast_error &err) {
+ throw std::runtime_error(msg.c_str());
+ } catch (std::runtime_error &err) {
std::string msg = (llvm::Twine("Invalid expression (None?) when ") +
action + " (" + err.what() + ")")
.str();
- throw py::cast_error(msg);
+ throw std::runtime_error(msg.c_str());
}
}
}
@@ -94,37 +93,37 @@ class PyConcreteAffineExpr : public BaseTy {
// IsAFunctionTy isaFunction
// const char *pyClassName
// and redefine bindDerived.
- using ClassTy = py::class_<DerivedTy, BaseTy>;
- using IsAFunctionTy = bool (*)(MlirAffineExpr);
-
- PyConcreteAffineExpr() = default;
- PyConcreteAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
- : BaseTy(std::move(contextRef), affineExpr) {}
- PyConcreteAffineExpr(PyAffineExpr &orig)
- : PyConcreteAffineExpr(orig.getContext(), castFrom(orig)) {}
-
- static MlirAffineExpr castFrom(PyAffineExpr &orig) {
- if (!DerivedTy::isaFunction(orig)) {
- auto origRepr = py::repr(py::cast(orig)).cast<std::string>();
- throw py::value_error((Twine("Cannot cast affine expression to ") +
- DerivedTy::pyClassName + " (from " + origRepr +
- ")")
- .str());
- }
- return orig;
- }
-
- static void bind(py::module &m) {
- auto cls = ClassTy(m, DerivedTy::pyClassName, py::module_local());
- cls.def(py::init<PyAffineExpr &>(), py::arg("expr"));
- cls.def_static(
- "isinstance",
- [](PyAffineExpr &otherAffineExpr) -> bool {
- return DerivedTy::isaFunction(otherAffineExpr);
- },
- py::arg("other"));
- DerivedTy::bindDerived(cls);
- }
+ using ClassTy = nb::class_<DerivedTy, BaseTy>;
+ using IsAFunctionTy = bool (*)(MlirAffineExpr);
+
+ PyConcreteAffineExpr() = default;
+ PyConcreteAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
+ : BaseTy(std::move(contextRef), affineExpr) {}
+ PyConcreteAffineExpr(PyAffineExpr &orig)
+ : PyConcreteAffineExpr(orig.getContext(), castFrom(orig)) {}
+
+ static MlirAffineExpr castFrom(PyAffineExpr &orig) {
+ if (!DerivedTy::isaFunction(orig)) {
+ auto origRepr = nb::cast<std::string>(nb::repr(nb::cast(orig)));
+ throw nb::value_error((Twine("Cannot cast affine expression to ") +
+ DerivedTy::pyClassName + " (from " + origRepr + ")")
+ .str()
+ .c_str());
+ }
+ return orig;
+ }
+
+ static void bind(nb::module_ &m) {
+ auto cls = ClassTy(m, DerivedTy::pyClassName);
+ cls.def(nb::init<PyAffineExpr &>(), nb::arg("expr"));
+ cls.def_static(
+ "isinstance",
+ [](PyAffineExpr &otherAffineExpr) -> bool {
+ return DerivedTy::isaFunction(otherAffineExpr);
+ },
+ nb::arg("other"));
+ DerivedTy::bindDerived(cls);
+ }
/// Implemented by derived classes to add methods to the Python subclass.
static void bindDerived(ClassTy &m) {}
@@ -144,9 +143,9 @@ class PyAffineConstantExpr : public PyConcreteAffineExpr<PyAffineConstantExpr> {
}
static void bindDerived(ClassTy &c) {
- c.def_static("get", &PyAffineConstantExpr::get, py::arg("value"),
- py::arg("context") = py::none());
- c.def_property_readonly("value", [](PyAffineConstantExpr &self) {
+ c.def_static("get", &PyAffineConstantExpr::get, nb::arg("value"),
+ nb::arg("context").none() = nb::none());
+ c.def_prop_ro("value", [](PyAffineConstantExpr &self) {
return mlirAffineConstantExprGetValue(self);
});
}
@@ -164,9 +163,9 @@ class PyAffineDimExpr : public PyConcreteAffineExpr<PyAffineDimExpr> {
}
static void bindDerived(ClassTy &c) {
- c.def_static("get", &PyAffineDimExpr::get, py::arg("position"),
- py::arg("context") = py::none());
- c.def_property_readonly("position", [](PyAffineDimExpr &self) {
+ c.def_static("get", &PyAffineDimExpr::get, nb::arg("position"),
+ nb::arg("context").none() = nb::none());
+ c.def_prop_ro("position", [](PyAffineDimExpr &self) {
return mlirAffineDimExprGetPosition(self);
});
}
@@ -184,9 +183,9 @@ class PyAffineSymbolExpr : public PyConcreteAffineExpr<PyAffineSymbolExpr> {
}
static void bindDerived(ClassTy &c) {
- c.def_static("get", &PyAffineSymbolExpr::get, py::arg("position"),
- py::arg("context") = py::none());
- c.def_property_readonly("position", [](PyAffineSymbolExpr &self) {
+ c.def_static("get", &PyAffineSymbolExpr::get, nb::arg("position"),
+ nb::arg("context").none() = nb::none());
+ c.def_prop_ro("position", [](PyAffineSymbolExpr &self) {
return mlirAffineSymbolExprGetPosition(self);
});
}
@@ -209,8 +208,8 @@ class PyAffineBinaryExpr : public PyConcreteAffineExpr<PyAffineBinaryExpr> {
}
static void bindDerived(ClassTy &c) {
- c.def_property_readonly("lhs", &PyAffineBinaryExpr::lhs);
- c.def_property_readonly("rhs", &PyAffineBinaryExpr::rhs);
+ c.def_prop_ro("lhs", &PyAffineBinaryExpr::lhs);
+ c.def_prop_ro("rhs", &PyAffineBinaryExpr::rhs);
}
};
@@ -365,15 +364,13 @@ bool PyAffineExpr::operator==(const PyAffineExpr &other) const {
return mlirAffineExprEqual(affineExpr, other.affineExpr);
}
-py::object PyAffineExpr::getCapsule() {
- return py::reinterpret_steal<py::object>(
- mlirPythonAffineExprToCapsule(*this));
+nb::object PyAffineExpr::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonAffineExprToCapsule(*this));
}
-PyAffineExpr PyAffineExpr::createFromCapsule(py::object capsule) {
+PyAffineExpr PyAffineExpr::createFromCapsule(nb::object capsule) {
MlirAffineExpr rawAffineExpr = mlirPythonCapsuleToAffineExpr(capsule.ptr());
- if (mlirAffineExprIsNull(rawAffineExpr))
- throw py::error_already_set();
+ if (mlirAffineExprIsNull(rawAffineExpr)) throw nb::python_error();
return PyAffineExpr(
PyMlirContext::forContext(mlirAffineExprGetContext(rawAffineExpr)),
rawAffineExpr);
@@ -424,14 +421,13 @@ bool PyAffineMap::operator==(const PyAffineMap &other) const {
return mlirAffineMapEqual(affineMap, other.affineMap);
}
-py::object PyAffineMap::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonAffineMapToCapsule(*this));
+nb::object PyAffineMap::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonAffineMapToCapsule(*this));
}
-PyAffineMap PyAffineMap::createFromCapsule(py::object capsule) {
+PyAffineMap PyAffineMap::createFromCapsule(nb::object capsule) {
MlirAffineMap rawAffineMap = mlirPythonCapsuleToAffineMap(capsule.ptr());
- if (mlirAffineMapIsNull(rawAffineMap))
- throw py::error_already_set();
+ if (mlirAffineMapIsNull(rawAffineMap)) throw nb::python_error();
return PyAffineMap(
PyMlirContext::forContext(mlirAffineMapGetContext(rawAffineMap)),
rawAffineMap);
@@ -454,11 +450,10 @@ class PyIntegerSetConstraint {
bool isEq() { return mlirIntegerSetIsConstraintEq(set, pos); }
- static void bind(py::module &m) {
- py::class_<PyIntegerSetConstraint>(m, "IntegerSetConstraint",
- py::module_local())
- .def_property_readonly("expr", &PyIntegerSetConstraint::getExpr)
- .def_property_readonly("is_eq", &PyIntegerSetConstraint::isEq);
+ static void bind(nb::module_ &m) {
+ nb::class_<PyIntegerSetConstraint>(m, "IntegerSetConstraint")
+ .def_prop_ro("expr", &PyIntegerSetConstraint::getExpr)
+ .def_prop_ro("is_eq", &PyIntegerSetConstraint::isEq);
}
private:
@@ -501,27 +496,24 @@ bool PyIntegerSet::operator==(const PyIntegerSet &other) const {
return mlirIntegerSetEqual(integerSet, other.integerSet);
}
-py::object PyIntegerSet::getCapsule() {
- return py::reinterpret_steal<py::object>(
- mlirPythonIntegerSetToCapsule(*this));
+nb::object PyIntegerSet::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonIntegerSetToCapsule(*this));
}
-PyIntegerSet PyIntegerSet::createFromCapsule(py::object capsule) {
+PyIntegerSet PyIntegerSet::createFromCapsule(nb::object capsule) {
MlirIntegerSet rawIntegerSet = mlirPythonCapsuleToIntegerSet(capsule.ptr());
- if (mlirIntegerSetIsNull(rawIntegerSet))
- throw py::error_already_set();
+ if (mlirIntegerSetIsNull(rawIntegerSet)) throw nb::python_error();
return PyIntegerSet(
PyMlirContext::forContext(mlirIntegerSetGetContext(rawIntegerSet)),
rawIntegerSet);
}
-void mlir::python::populateIRAffine(py::module &m) {
+void mlir::python::populateIRAffine(nb::module_ &m) {
//----------------------------------------------------------------------------
// Mapping of PyAffineExpr and derived classes.
//----------------------------------------------------------------------------
- py::class_<PyAffineExpr>(m, "AffineExpr", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyAffineExpr::getCapsule)
+ nb::class_<PyAffineExpr>(m, "AffineExpr")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyAffineExpr::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAffineExpr::createFromCapsule)
.def("__add__", &PyAffineAddExpr::get)
.def("__add__", &PyAffineAddExpr::getRHSConstant)
@@ -558,7 +550,7 @@ void mlir::python::populateIRAffine(py::module &m) {
.def("__eq__", [](PyAffineExpr &self,
PyAffineExpr &other) { return self == other; })
.def("__eq__",
- [](PyAffineExpr &self, py::object &other) { return false; })
+ [](PyAffineExpr &self, nb::object &other) { return false; })
.def("__str__",
[](PyAffineExpr &self) {
PyPrintAccumulator printAccum;
@@ -579,7 +571,7 @@ void mlir::python::populateIRAffine(py::module &m) {
[](PyAffineExpr &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
})
- .def_property_readonly(
+ .def_prop_ro(
"context",
[](PyAffineExpr &self) { return self.getContext().getObject(); })
.def("compose",
@@ -632,16 +624,16 @@ void mlir::python::populateIRAffine(py::module &m) {
.def_static("get_ceil_div", &PyAffineCeilDivExpr::getRHSConstant,
"Gets an affine expression containing the rounded-up result "
"of dividing an expression by a constant.")
- .def_static("get_constant", &PyAffineConstantExpr::get, py::arg("value"),
- py::arg("context") = py::none(),
+ .def_static("get_constant", &PyAffineConstantExpr::get, nb::arg("value"),
+ nb::arg("context").none() = nb::none(),
"Gets a constant affine expression with the given value.")
.def_static(
- "get_dim", &PyAffineDimExpr::get, py::arg("position"),
- py::arg("context") = py::none(),
+ "get_dim", &PyAffineDimExpr::get, nb::arg("position"),
+ nb::arg("context").none() = nb::none(),
"Gets an affine expression of a dimension at the given position.")
.def_static(
- "get_symbol", &PyAffineSymbolExpr::get, py::arg("position"),
- py::arg("context") = py::none(),
+ "get_symbol", &PyAffineSymbolExpr::get, nb::arg("position"),
+ nb::arg("context").none() = nb::none(),
"Gets an affine expression of a symbol at the given position.")
.def(
"dump", [](PyAffineExpr &self) { mlirAffineExprDump(self); },
@@ -659,13 +651,12 @@ void mlir::python::populateIRAffine(py::module &m) {
//----------------------------------------------------------------------------
// Mapping of PyAffineMap.
//----------------------------------------------------------------------------
- py::class_<PyAffineMap>(m, "AffineMap", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyAffineMap::getCapsule)
+ nb::class_<PyAffineMap>(m, "AffineMap")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyAffineMap::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAffineMap::createFromCapsule)
.def("__eq__",
[](PyAffineMap &self, PyAffineMap &other) { return self == other; })
- .def("__eq__", [](PyAffineMap &self, py::object &other) { return false; })
+ .def("__eq__", [](PyAffineMap &self, nb::object &other) { return false; })
.def("__str__",
[](PyAffineMap &self) {
PyPrintAccumulator printAccum;
@@ -687,7 +678,7 @@ void mlir::python::populateIRAffine(py::module &m) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
})
.def_static("compress_unused_symbols",
- [](py::list affineMaps, DefaultingPyMlirContext context) {
+ [](nb::list affineMaps, DefaultingPyMlirContext context) {
SmallVector<MlirAffineMap> maps;
pyListToVector<PyAffineMap, MlirAffineMap>(
affineMaps, maps, "attempting to create an AffineMap");
@@ -704,7 +695,7 @@ void mlir::python::populateIRAffine(py::module &m) {
res.emplace_back(context->getRef(), m);
return res;
})
- .def_property_readonly(
+ .def_prop_ro(
"context",
[](PyAffineMap &self) { return self.getContext().getObject(); },
"Context that owns the Affine Map")
@@ -713,7 +704,7 @@ void mlir::python::populateIRAffine(py::module &m) {
kDumpDocstring)
.def_static(
"get",
- [](intptr_t dimCount, intptr_t symbolCount, py::list exprs,
+ [](intptr_t dimCount, intptr_t symbolCount, nb::list exprs,
DefaultingPyMlirContext context) {
SmallVector<MlirAffineExpr> affineExprs;
pyListToVector<PyAffineExpr, MlirAffineExpr>(
@@ -723,8 +714,8 @@ void mlir::python::populateIRAffine(py::module &m) {
affineExprs.size(), affineExprs.data());
return PyAffineMap(context->getRef(), map);
},
- py::arg("dim_count"), py::arg("symbol_count"), py::arg("exprs"),
- py::arg("context") = py::none(),
+ nb::arg("dim_count"), nb::arg("symbol_count"), nb::arg("exprs"),
+ nb::arg("context").none() = nb::none(),
"Gets a map with the given expressions as results.")
.def_static(
"get_constant",
@@ -733,7 +724,7 @@ void mlir::python::populateIRAffine(py::module &m) {
mlirAffineMapConstantGet(context->get(), value);
return PyAffineMap(context->getRef(), affineMap);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets an affine map with a single constant result")
.def_static(
"get_empty",
@@ -741,7 +732,7 @@ void mlir::python::populateIRAffine(py::module &m) {
MlirAffineMap affineMap = mlirAffineMapEmptyGet(context->get());
return PyAffineMap(context->getRef(), affineMap);
},
- py::arg("context") = py::none(), "Gets an empty affine map.")
+ nb::arg("context").none() = nb::none(), "Gets an empty affine map.")
.def_static(
"get_identity",
[](intptr_t nDims, DefaultingPyMlirContext context) {
@@ -749,7 +740,7 @@ void mlir::python::populateIRAffine(py::module &m) {
mlirAffineMapMultiDimIdentityGet(context->get(), nDims);
return PyAffineMap(context->getRef(), affineMap);
},
- py::arg("n_dims"), py::arg("context") = py::none(),
+ nb::arg("n_dims"), nb::arg("context").none() = nb::none(),
"Gets an identity map with the given number of dimensions.")
.def_static(
"get_minor_identity",
@@ -759,8 +750,8 @@ void mlir::python::populateIRAffine(py::module &m) {
mlirAffineMapMinorIdentityGet(context->get(), nDims, nResults);
return PyAffineMap(context->getRef(), affineMap);
},
- py::arg("n_dims"), py::arg("n_results"),
- py::arg("context") = py::none(),
+ nb::arg("n_dims"), nb::arg("n_results"),
+ nb::arg("context").none() = nb::none(),
"Gets a minor identity map with the given number of dimensions and "
"results.")
.def_static(
@@ -768,13 +759,14 @@ void mlir::python::populateIRAffine(py::module &m) {
[](std::vector<unsigned> permutation,
DefaultingPyMlirContext context) {
if (!isPermutation(permutation))
- throw py::cast_error("Invalid permutation when attempting to "
- "create an AffineMap");
+ throw std::runtime_error(
+ "Invalid permutation when attempting to "
+ "create an AffineMap");
MlirAffineMap affineMap = mlirAffineMapPermutationGet(
context->get(), permutation.size(), permutation.data());
return PyAffineMap(context->getRef(), affineMap);
},
- py::arg("permutation"), py::arg("context") = py::none(),
+ nb::arg("permutation"), nb::arg("context").none() = nb::none(),
"Gets an affine map that permutes its inputs.")
.def(
"get_submap",
@@ -782,33 +774,33 @@ void mlir::python::populateIRAffine(py::module &m) {
intptr_t numResults = mlirAffineMapGetNumResults(self);
for (intptr_t pos : resultPos) {
if (pos < 0 || pos >= numResults)
- throw py::value_error("result position out of bounds");
+ throw nb::value_error("result position out of bounds");
}
MlirAffineMap affineMap = mlirAffineMapGetSubMap(
self, resultPos.size(), resultPos.data());
return PyAffineMap(self.getContext(), affineMap);
},
- py::arg("result_positions"))
+ nb::arg("result_positions"))
.def(
"get_major_submap",
[](PyAffineMap &self, intptr_t nResults) {
if (nResults >= mlirAffineMapGetNumResults(self))
- throw py::value_error("number of results out of bounds");
+ throw nb::value_error("number of results out of bounds");
MlirAffineMap affineMap =
mlirAffineMapGetMajorSubMap(self, nResults);
return PyAffineMap(self.getContext(), affineMap);
},
- py::arg("n_results"))
+ nb::arg("n_results"))
.def(
"get_minor_submap",
[](PyAffineMap &self, intptr_t nResults) {
if (nResults >= mlirAffineMapGetNumResults(self))
- throw py::value_error("number of results out of bounds");
+ throw nb::value_error("number of results out of bounds");
MlirAffineMap affineMap =
mlirAffineMapGetMinorSubMap(self, nResults);
return PyAffineMap(self.getContext(), affineMap);
},
- py::arg("n_results"))
+ nb::arg("n_results"))
.def(
"replace",
[](PyAffineMap &self, PyAffineExpr &expression,
@@ -818,39 +810,37 @@ void mlir::python::populateIRAffine(py::module &m) {
self, expression, replacement, numResultDims, numResultSyms);
return PyAffineMap(self.getContext(), affineMap);
},
- py::arg("expr"), py::arg("replacement"), py::arg("n_result_dims"),
- py::arg("n_result_syms"))
- .def_property_readonly(
+ nb::arg("expr"), nb::arg("replacement"), nb::arg("n_result_dims"),
+ nb::arg("n_result_syms"))
+ .def_prop_ro(
"is_permutation",
[](PyAffineMap &self) { return mlirAffineMapIsPermutation(self); })
- .def_property_readonly("is_projected_permutation",
- [](PyAffineMap &self) {
- return mlirAffineMapIsProjectedPermutation(self);
- })
- .def_property_readonly(
+ .def_prop_ro("is_projected_permutation",
+ [](PyAffineMap &self) {
+ return mlirAffineMapIsProjectedPermutation(self);
+ })
+ .def_prop_ro(
"n_dims",
[](PyAffineMap &self) { return mlirAffineMapGetNumDims(self); })
- .def_property_readonly(
+ .def_prop_ro(
"n_inputs",
[](PyAffineMap &self) { return mlirAffineMapGetNumInputs(self); })
- .def_property_readonly(
+ .def_prop_ro(
"n_symbols",
[](PyAffineMap &self) { return mlirAffineMapGetNumSymbols(self); })
- .def_property_readonly("results", [](PyAffineMap &self) {
- return PyAffineMapExprList(self);
- });
+ .def_prop_ro("results",
+ [](PyAffineMap &self) { return PyAffineMapExprList(self); });
PyAffineMapExprList::bind(m);
//----------------------------------------------------------------------------
// Mapping of PyIntegerSet.
//----------------------------------------------------------------------------
- py::class_<PyIntegerSet>(m, "IntegerSet", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyIntegerSet::getCapsule)
+ nb::class_<PyIntegerSet>(m, "IntegerSet")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyIntegerSet::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyIntegerSet::createFromCapsule)
.def("__eq__", [](PyIntegerSet &self,
PyIntegerSet &other) { return self == other; })
- .def("__eq__", [](PyIntegerSet &self, py::object other) { return false; })
+ .def("__eq__", [](PyIntegerSet &self, nb::object other) { return false; })
.def("__str__",
[](PyIntegerSet &self) {
PyPrintAccumulator printAccum;
@@ -871,7 +861,7 @@ void mlir::python::populateIRAffine(py::module &m) {
[](PyIntegerSet &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
})
- .def_property_readonly(
+ .def_prop_ro(
"context",
[](PyIntegerSet &self) { return self.getContext().getObject(); })
.def(
@@ -879,14 +869,14 @@ void mlir::python::populateIRAffine(py::module &m) {
kDumpDocstring)
.def_static(
"get",
- [](intptr_t numDims, intptr_t numSymbols, py::list exprs,
+ [](intptr_t numDims, intptr_t numSymbols, nb::list exprs,
std::vector<bool> eqFlags, DefaultingPyMlirContext context) {
if (exprs.size() != eqFlags.size())
- throw py::value_error(
+ throw nb::value_error(
"Expected the number of constraints to match "
"that of equality flags");
- if (exprs.empty())
- throw py::value_error("Expected non-empty list of constraints");
+ if (exprs.size() == 0)
+ throw nb::value_error("Expected non-empty list of constraints");
// Copy over to a SmallVector because std::vector has a
// specialization for booleans that packs data and does not
@@ -901,8 +891,8 @@ void mlir::python::populateIRAffine(py::module &m) {
affineExprs.data(), flags.data());
return PyIntegerSet(context->getRef(), set);
},
- py::arg("num_dims"), py::arg("num_symbols"), py::arg("exprs"),
- py::arg("eq_flags"), py::arg("context") = py::none())
+ nb::arg("num_dims"), nb::arg("num_symbols"), nb::arg("exprs"),
+ nb::arg("eq_flags"), nb::arg("context").none() = nb::none())
.def_static(
"get_empty",
[](intptr_t numDims, intptr_t numSymbols,
@@ -911,20 +901,20 @@ void mlir::python::populateIRAffine(py::module &m) {
mlirIntegerSetEmptyGet(context->get(), numDims, numSymbols);
return PyIntegerSet(context->getRef(), set);
},
- py::arg("num_dims"), py::arg("num_symbols"),
- py::arg("context") = py::none())
+ nb::arg("num_dims"), nb::arg("num_symbols"),
+ nb::arg("context").none() = nb::none())
.def(
"get_replaced",
- [](PyIntegerSet &self, py::list dimExprs, py::list symbolExprs,
+ [](PyIntegerSet &self, nb::list dimExprs, nb::list symbolExprs,
intptr_t numResultDims, intptr_t numResultSymbols) {
if (static_cast<intptr_t>(dimExprs.size()) !=
mlirIntegerSetGetNumDims(self))
- throw py::value_error(
+ throw nb::value_error(
"Expected the number of dimension replacement expressions "
"to match that of dimensions");
if (static_cast<intptr_t>(symbolExprs.size()) !=
mlirIntegerSetGetNumSymbols(self))
- throw py::value_error(
+ throw nb::value_error(
"Expected the number of symbol replacement expressions "
"to match that of symbols");
@@ -940,30 +930,30 @@ void mlir::python::populateIRAffine(py::module &m) {
numResultDims, numResultSymbols);
return PyIntegerSet(self.getContext(), set);
},
- py::arg("dim_exprs"), py::arg("symbol_exprs"),
- py::arg("num_result_dims"), py::arg("num_result_symbols"))
- .def_property_readonly("is_canonical_empty",
- [](PyIntegerSet &self) {
- return mlirIntegerSetIsCanonicalEmpty(self);
- })
- .def_property_readonly(
+ nb::arg("dim_exprs"), nb::arg("symbol_exprs"),
+ nb::arg("num_result_dims"), nb::arg("num_result_symbols"))
+ .def_prop_ro("is_canonical_empty",
+ [](PyIntegerSet &self) {
+ return mlirIntegerSetIsCanonicalEmpty(self);
+ })
+ .def_prop_ro(
"n_dims",
[](PyIntegerSet &self) { return mlirIntegerSetGetNumDims(self); })
- .def_property_readonly(
+ .def_prop_ro(
"n_symbols",
[](PyIntegerSet &self) { return mlirIntegerSetGetNumSymbols(self); })
- .def_property_readonly(
+ .def_prop_ro(
"n_inputs",
[](PyIntegerSet &self) { return mlirIntegerSetGetNumInputs(self); })
- .def_property_readonly("n_equalities",
- [](PyIntegerSet &self) {
- return mlirIntegerSetGetNumEqualities(self);
- })
- .def_property_readonly("n_inequalities",
- [](PyIntegerSet &self) {
- return mlirIntegerSetGetNumInequalities(self);
- })
- .def_property_readonly("constraints", [](PyIntegerSet &self) {
+ .def_prop_ro("n_equalities",
+ [](PyIntegerSet &self) {
+ return mlirIntegerSetGetNumEqualities(self);
+ })
+ .def_prop_ro("n_inequalities",
+ [](PyIntegerSet &self) {
+ return mlirIntegerSetGetNumInequalities(self);
+ })
+ .def_prop_ro("constraints", [](PyIntegerSet &self) {
return PyIntegerSetConstraintList(self);
});
PyIntegerSetConstraint::bind(m);
diff --git a/mlir/lib/Bindings/Python/IRAttributes.cpp b/mlir/lib/Bindings/Python/IRAttributes.cpp
index cc9532f4e33b2c..7ec220053701f2 100644
--- a/mlir/lib/Bindings/Python/IRAttributes.cpp
+++ b/mlir/lib/Bindings/Python/IRAttributes.cpp
@@ -6,23 +6,29 @@
//
//===----------------------------------------------------------------------===//
+#include <nanobind/nanobind.h>
+#include <nanobind/ndarray.h>
+#include <nanobind/stl/optional.h>
+#include <nanobind/stl/string.h>
+#include <nanobind/stl/string_view.h>
+#include <nanobind/stl/vector.h>
+
+#include <cstdint>
#include <optional>
+#include <string>
#include <string_view>
#include <utility>
#include "IRModule.h"
-
-#include "PybindUtils.h"
-#include <pybind11/numpy.h>
-
+#include "NanobindUtils.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/raw_ostream.h"
-
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/BuiltinTypes.h"
-#include "mlir/Bindings/Python/PybindAdaptors.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
-namespace py = pybind11;
+namespace nb = nanobind;
+using namespace nanobind::literals;
using namespace mlir;
using namespace mlir::python;
@@ -123,10 +129,112 @@ subsequent processing.
namespace {
+struct nb_buffer_info {
+ void *ptr = nullptr;
+ ssize_t itemsize = 0;
+ ssize_t size = 0;
+ const char *format = nullptr;
+ ssize_t ndim = 0;
+ SmallVector<ssize_t, 4> shape;
+ SmallVector<ssize_t, 4> strides;
+ bool readonly = false;
+
+ nb_buffer_info() = default;
+
+ nb_buffer_info(void *ptr, ssize_t itemsize, const char *format, ssize_t ndim,
+ SmallVector<ssize_t, 4> shape_in,
+ SmallVector<ssize_t, 4> strides_in, bool readonly = false)
+ : ptr(ptr),
+ itemsize(itemsize),
+ format(format),
+ ndim(ndim),
+ shape(std::move(shape_in)),
+ strides(std::move(strides_in)),
+ readonly(readonly) {
+ size = 1;
+ for (ssize_t i = 0; i < ndim; ++i) {
+ size *= shape[i];
+ }
+ }
+
+ explicit nb_buffer_info(Py_buffer *view)
+ : nb_buffer_info(view->buf, view->itemsize, view->format, view->ndim,
+ {view->shape, view->shape + view->ndim},
+ // TODO(phawkins): check for null strides
+ {view->strides, view->strides + view->ndim},
+ view->readonly != 0) {}
+};
+
+class nb_buffer : public nb::object {
+ NB_OBJECT_DEFAULT(nb_buffer, object, "buffer", PyObject_CheckBuffer);
+
+ nb_buffer_info request() const {
+ int flags = PyBUF_STRIDES | PyBUF_FORMAT;
+ auto *view = new Py_buffer();
+ if (PyObject_GetBuffer(ptr(), view, flags) != 0) {
+ delete view;
+ throw nb::python_error();
+ }
+ return nb_buffer_info(view);
+ }
+};
+
+template <typename T>
+struct nb_format_descriptor {};
+
+template <>
+struct nb_format_descriptor<bool> {
+ static const char *format() { return "?"; }
+};
+template <>
+struct nb_format_descriptor<signed char> {
+ static const char *format() { return "b"; }
+};
+template <>
+struct nb_format_descriptor<unsigned char> {
+ static const char *format() { return "B"; }
+};
+template <>
+struct nb_format_descriptor<short> {
+ static const char *format() { return "h"; }
+};
+template <>
+struct nb_format_descriptor<unsigned short> {
+ static const char *format() { return "H"; }
+};
+template <>
+struct nb_format_descriptor<int> {
+ static const char *format() { return "i"; }
+};
+template <>
+struct nb_format_descriptor<unsigned int> {
+ static const char *format() { return "I"; }
+};
+template <>
+struct nb_format_descriptor<long> {
+ static const char *format() { return "l"; }
+};
+template <>
+struct nb_format_descriptor<unsigned long> {
+ static const char *format() { return "L"; }
+};
+template <>
+struct nb_format_descriptor<float> {
+ static const char *format() { return "f"; }
+};
+template <>
+struct nb_format_descriptor<double> {
+ static const char *format() { return "d"; }
+};
+
static MlirStringRef toMlirStringRef(const std::string &s) {
return mlirStringRefCreate(s.data(), s.size());
}
+static MlirStringRef toMlirStringRef(const nb::bytes &s) {
+ return mlirStringRefCreate(static_cast<const char *>(s.data()), s.size());
+}
+
class PyAffineMapAttribute : public PyConcreteAttribute<PyAffineMapAttribute> {
public:
static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAAffineMap;
@@ -142,9 +250,9 @@ class PyAffineMapAttribute : public PyConcreteAttribute<PyAffineMapAttribute> {
MlirAttribute attr = mlirAffineMapAttrGet(affineMap.get());
return PyAffineMapAttribute(affineMap.getContext(), attr);
},
- py::arg("affine_map"), "Gets an attribute wrapping an AffineMap.");
- c.def_property_readonly("value", mlirAffineMapAttrGetValue,
- "Returns the value of the AffineMap attribute");
+ nb::arg("affine_map"), "Gets an attribute wrapping an AffineMap.");
+ c.def_prop_ro("value", mlirAffineMapAttrGetValue,
+ "Returns the value of the AffineMap attribute");
}
};
@@ -164,25 +272,25 @@ class PyIntegerSetAttribute
MlirAttribute attr = mlirIntegerSetAttrGet(integerSet.get());
return PyIntegerSetAttribute(integerSet.getContext(), attr);
},
- py::arg("integer_set"), "Gets an attribute wrapping an IntegerSet.");
+ nb::arg("integer_set"), "Gets an attribute wrapping an IntegerSet.");
}
};
template <typename T>
-static T pyTryCast(py::handle object) {
+static T pyTryCast(nb::handle object) {
try {
- return object.cast<T>();
- } catch (py::cast_error &err) {
- std::string msg =
- std::string(
- "Invalid attribute when attempting to create an ArrayAttribute (") +
- err.what() + ")";
- throw py::cast_error(msg);
- } catch (py::reference_cast_error &err) {
+ return nb::cast<T>(object);
+ } catch (nb::cast_error &err) {
+ std::string msg = std::string(
+ "Invalid attribute when attempting to "
+ "create an ArrayAttribute (") +
+ err.what() + ")";
+ throw std::runtime_error(msg.c_str());
+ } catch (std::runtime_error &err) {
std::string msg = std::string("Invalid attribute (None?) when attempting "
"to create an ArrayAttribute (") +
err.what() + ")";
- throw py::cast_error(msg);
+ throw std::runtime_error(msg.c_str());
}
}
@@ -205,14 +313,13 @@ class PyDenseArrayAttribute : public PyConcreteAttribute<DerivedT> {
EltTy dunderNext() {
// Throw if the index has reached the end.
if (nextIndex >= mlirDenseArrayGetNumElements(attr.get()))
- throw py::stop_iteration();
+ throw nb::stop_iteration();
return DerivedT::getElement(attr.get(), nextIndex++);
}
/// Bind the iterator class.
- static void bind(py::module &m) {
- py::class_<PyDenseArrayIterator>(m, DerivedT::pyIteratorName,
- py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyDenseArrayIterator>(m, DerivedT::pyIteratorName)
.def("__iter__", &PyDenseArrayIterator::dunderIter)
.def("__next__", &PyDenseArrayIterator::dunderNext);
}
@@ -230,17 +337,35 @@ class PyDenseArrayAttribute : public PyConcreteAttribute<DerivedT> {
/// Bind the attribute class.
static void bindDerived(typename PyConcreteAttribute<DerivedT>::ClassTy &c) {
// Bind the constructor.
- c.def_static(
- "get",
- [](const std::vector<EltTy> &values, DefaultingPyMlirContext ctx) {
- return getAttribute(values, ctx->getRef());
- },
- py::arg("values"), py::arg("context") = py::none(),
- "Gets a uniqued dense array attribute");
+ if constexpr (std::is_same_v<EltTy, bool>) {
+ c.def_static(
+ "get",
+ [](const nb::sequence &py_values, DefaultingPyMlirContext ctx) {
+ std::vector<bool> values;
+ for (nb::handle py_value : py_values) {
+ int is_true = PyObject_IsTrue(py_value.ptr());
+ if (is_true < 0) {
+ throw nb::python_error();
+ }
+ values.push_back(is_true);
+ }
+ return getAttribute(values, ctx->getRef());
+ },
+ nb::arg("values"), nb::arg("context").none() = nb::none(),
+ "Gets a uniqued dense array attribute");
+ } else {
+ c.def_static(
+ "get",
+ [](const std::vector<EltTy> &values, DefaultingPyMlirContext ctx) {
+ return getAttribute(values, ctx->getRef());
+ },
+ nb::arg("values"), nb::arg("context").none() = nb::none(),
+ "Gets a uniqued dense array attribute");
+ }
// Bind the array methods.
c.def("__getitem__", [](DerivedT &arr, intptr_t i) {
if (i >= mlirDenseArrayGetNumElements(arr))
- throw py::index_error("DenseArray index out of range");
+ throw nb::index_error("DenseArray index out of range");
return arr.getItem(i);
});
c.def("__len__", [](const DerivedT &arr) {
@@ -248,14 +373,13 @@ class PyDenseArrayAttribute : public PyConcreteAttribute<DerivedT> {
});
c.def("__iter__",
[](const DerivedT &arr) { return PyDenseArrayIterator(arr); });
- c.def("__add__", [](DerivedT &arr, const py::list &extras) {
+ c.def("__add__", [](DerivedT &arr, const nb::list &extras) {
std::vector<EltTy> values;
intptr_t numOldElements = mlirDenseArrayGetNumElements(arr);
- values.reserve(numOldElements + py::len(extras));
+ values.reserve(numOldElements + nb::len(extras));
for (intptr_t i = 0; i < numOldElements; ++i)
values.push_back(arr.getItem(i));
- for (py::handle attr : extras)
- values.push_back(pyTryCast<EltTy>(attr));
+ for (nb::handle attr : extras) values.push_back(pyTryCast<EltTy>(attr));
return getAttribute(values, arr.getContext());
});
}
@@ -358,13 +482,12 @@ class PyArrayAttribute : public PyConcreteAttribute<PyArrayAttribute> {
MlirAttribute dunderNext() {
// TODO: Throw is an inefficient way to stop iteration.
if (nextIndex >= mlirArrayAttrGetNumElements(attr.get()))
- throw py::stop_iteration();
+ throw nb::stop_iteration();
return mlirArrayAttrGetElement(attr.get(), nextIndex++);
}
- static void bind(py::module &m) {
- py::class_<PyArrayAttributeIterator>(m, "ArrayAttributeIterator",
- py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyArrayAttributeIterator>(m, "ArrayAttributeIterator")
.def("__iter__", &PyArrayAttributeIterator::dunderIter)
.def("__next__", &PyArrayAttributeIterator::dunderNext);
}
@@ -381,9 +504,9 @@ class PyArrayAttribute : public PyConcreteAttribute<PyArrayAttribute> {
static void bindDerived(ClassTy &c) {
c.def_static(
"get",
- [](py::list attributes, DefaultingPyMlirContext context) {
+ [](nb::list attributes, DefaultingPyMlirContext context) {
SmallVector<MlirAttribute> mlirAttributes;
- mlirAttributes.reserve(py::len(attributes));
+ mlirAttributes.reserve(nb::len(attributes));
for (auto attribute : attributes) {
mlirAttributes.push_back(pyTryCast<PyAttribute>(attribute));
}
@@ -391,12 +514,12 @@ class PyArrayAttribute : public PyConcreteAttribute<PyArrayAttribute> {
context->get(), mlirAttributes.size(), mlirAttributes.data());
return PyArrayAttribute(context->getRef(), attr);
},
- py::arg("attributes"), py::arg("context") = py::none(),
+ nb::arg("attributes"), nb::arg("context").none() = nb::none(),
"Gets a uniqued Array attribute");
c.def("__getitem__",
[](PyArrayAttribute &arr, intptr_t i) {
if (i >= mlirArrayAttrGetNumElements(arr))
- throw py::index_error("ArrayAttribute index out of range");
+ throw nb::index_error("ArrayAttribute index out of range");
return arr.getItem(i);
})
.def("__len__",
@@ -406,13 +529,13 @@ class PyArrayAttribute : public PyConcreteAttribute<PyArrayAttribute> {
.def("__iter__", [](const PyArrayAttribute &arr) {
return PyArrayAttributeIterator(arr);
});
- c.def("__add__", [](PyArrayAttribute arr, py::list extras) {
+ c.def("__add__", [](PyArrayAttribute arr, nb::list extras) {
std::vector<MlirAttribute> attributes;
intptr_t numOldElements = mlirArrayAttrGetNumElements(arr);
- attributes.reserve(numOldElements + py::len(extras));
+ attributes.reserve(numOldElements + nb::len(extras));
for (intptr_t i = 0; i < numOldElements; ++i)
attributes.push_back(arr.getItem(i));
- for (py::handle attr : extras)
+ for (nb::handle attr : extras)
attributes.push_back(pyTryCast<PyAttribute>(attr));
MlirAttribute arrayAttr = mlirArrayAttrGet(
arr.getContext()->get(), attributes.size(), attributes.data());
@@ -440,7 +563,7 @@ class PyFloatAttribute : public PyConcreteAttribute<PyFloatAttribute> {
throw MLIRError("Invalid attribute", errors.take());
return PyFloatAttribute(type.getContext(), attr);
},
- py::arg("type"), py::arg("value"), py::arg("loc") = py::none(),
+ nb::arg("type"), nb::arg("value"), nb::arg("loc").none() = nb::none(),
"Gets an uniqued float point attribute associated to a type");
c.def_static(
"get_f32",
@@ -449,7 +572,7 @@ class PyFloatAttribute : public PyConcreteAttribute<PyFloatAttribute> {
context->get(), mlirF32TypeGet(context->get()), value);
return PyFloatAttribute(context->getRef(), attr);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets an uniqued float point attribute associated to a f32 type");
c.def_static(
"get_f64",
@@ -458,10 +581,10 @@ class PyFloatAttribute : public PyConcreteAttribute<PyFloatAttribute> {
context->get(), mlirF64TypeGet(context->get()), value);
return PyFloatAttribute(context->getRef(), attr);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets an uniqued float point attribute associated to a f64 type");
- c.def_property_readonly("value", mlirFloatAttrGetValueDouble,
- "Returns the value of the float attribute");
+ c.def_prop_ro("value", mlirFloatAttrGetValueDouble,
+ "Returns the value of the float attribute");
c.def("__float__", mlirFloatAttrGetValueDouble,
"Converts the value of the float attribute to a Python float");
}
@@ -481,27 +604,26 @@ class PyIntegerAttribute : public PyConcreteAttribute<PyIntegerAttribute> {
MlirAttribute attr = mlirIntegerAttrGet(type, value);
return PyIntegerAttribute(type.getContext(), attr);
},
- py::arg("type"), py::arg("value"),
+ nb::arg("type"), nb::arg("value"),
"Gets an uniqued integer attribute associated to a type");
- c.def_property_readonly("value", toPyInt,
- "Returns the value of the integer attribute");
+ c.def_prop_ro("value", toPyInt,
+ "Returns the value of the integer attribute");
c.def("__int__", toPyInt,
"Converts the value of the integer attribute to a Python int");
- c.def_property_readonly_static("static_typeid",
- [](py::object & /*class*/) -> MlirTypeID {
- return mlirIntegerAttrGetTypeID();
- });
+ c.def_prop_ro_static("static_typeid",
+ [](nb::object & /*class*/) -> MlirTypeID {
+ return mlirIntegerAttrGetTypeID();
+ });
}
private:
- static py::int_ toPyInt(PyIntegerAttribute &self) {
- MlirType type = mlirAttributeGetType(self);
- if (mlirTypeIsAIndex(type) || mlirIntegerTypeIsSignless(type))
- return mlirIntegerAttrGetValueInt(self);
- if (mlirIntegerTypeIsSigned(type))
- return mlirIntegerAttrGetValueSInt(self);
- return mlirIntegerAttrGetValueUInt(self);
- }
+ static int64_t toPyInt(PyIntegerAttribute &self) {
+ MlirType type = mlirAttributeGetType(self);
+ if (mlirTypeIsAIndex(type) || mlirIntegerTypeIsSignless(type))
+ return mlirIntegerAttrGetValueInt(self);
+ if (mlirIntegerTypeIsSigned(type)) return mlirIntegerAttrGetValueSInt(self);
+ return mlirIntegerAttrGetValueUInt(self);
+ }
};
/// Bool Attribute subclass - BoolAttr.
@@ -518,10 +640,10 @@ class PyBoolAttribute : public PyConcreteAttribute<PyBoolAttribute> {
MlirAttribute attr = mlirBoolAttrGet(context->get(), value);
return PyBoolAttribute(context->getRef(), attr);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets an uniqued bool attribute");
- c.def_property_readonly("value", mlirBoolAttrGetValue,
- "Returns the value of the bool attribute");
+ c.def_prop_ro("value", mlirBoolAttrGetValue,
+ "Returns the value of the bool attribute");
c.def("__bool__", mlirBoolAttrGetValue,
"Converts the value of the bool attribute to a Python bool");
}
@@ -555,9 +677,9 @@ class PySymbolRefAttribute : public PyConcreteAttribute<PySymbolRefAttribute> {
DefaultingPyMlirContext context) {
return PySymbolRefAttribute::fromList(symbols, context.resolve());
},
- py::arg("symbols"), py::arg("context") = py::none(),
+ nb::arg("symbols"), nb::arg("context").none() = nb::none(),
"Gets a uniqued SymbolRef attribute from a list of symbol names");
- c.def_property_readonly(
+ c.def_prop_ro(
"value",
[](PySymbolRefAttribute &self) {
std::vector<std::string> symbols = {
@@ -589,13 +711,13 @@ class PyFlatSymbolRefAttribute
mlirFlatSymbolRefAttrGet(context->get(), toMlirStringRef(value));
return PyFlatSymbolRefAttribute(context->getRef(), attr);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets a uniqued FlatSymbolRef attribute");
- c.def_property_readonly(
+ c.def_prop_ro(
"value",
[](PyFlatSymbolRefAttribute &self) {
MlirStringRef stringRef = mlirFlatSymbolRefAttrGetValue(self);
- return py::str(stringRef.data, stringRef.length);
+ return nb::str(stringRef.data, stringRef.length);
},
"Returns the value of the FlatSymbolRef attribute as a string");
}
@@ -612,29 +734,29 @@ class PyOpaqueAttribute : public PyConcreteAttribute<PyOpaqueAttribute> {
static void bindDerived(ClassTy &c) {
c.def_static(
"get",
- [](std::string dialectNamespace, py::buffer buffer, PyType &type,
+ [](std::string dialectNamespace, nb_buffer buffer, PyType &type,
DefaultingPyMlirContext context) {
- const py::buffer_info bufferInfo = buffer.request();
+ const nb_buffer_info bufferInfo = buffer.request();
intptr_t bufferSize = bufferInfo.size;
MlirAttribute attr = mlirOpaqueAttrGet(
context->get(), toMlirStringRef(dialectNamespace), bufferSize,
static_cast<char *>(bufferInfo.ptr), type);
return PyOpaqueAttribute(context->getRef(), attr);
},
- py::arg("dialect_namespace"), py::arg("buffer"), py::arg("type"),
- py::arg("context") = py::none(), "Gets an Opaque attribute.");
- c.def_property_readonly(
+ nb::arg("dialect_namespace"), nb::arg("buffer"), nb::arg("type"),
+ nb::arg("context").none() = nb::none(), "Gets an Opaque attribute.");
+ c.def_prop_ro(
"dialect_namespace",
[](PyOpaqueAttribute &self) {
MlirStringRef stringRef = mlirOpaqueAttrGetDialectNamespace(self);
- return py::str(stringRef.data, stringRef.length);
+ return nb::str(stringRef.data, stringRef.length);
},
"Returns the dialect namespace for the Opaque attribute as a string");
- c.def_property_readonly(
+ c.def_prop_ro(
"data",
[](PyOpaqueAttribute &self) {
MlirStringRef stringRef = mlirOpaqueAttrGetData(self);
- return py::bytes(stringRef.data, stringRef.length);
+ return nb::bytes(stringRef.data, stringRef.length);
},
"Returns the data for the Opaqued attributes as `bytes`");
}
@@ -656,7 +778,16 @@ class PyStringAttribute : public PyConcreteAttribute<PyStringAttribute> {
mlirStringAttrGet(context->get(), toMlirStringRef(value));
return PyStringAttribute(context->getRef(), attr);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
+ "Gets a uniqued string attribute");
+ c.def_static(
+ "get",
+ [](nb::bytes value, DefaultingPyMlirContext context) {
+ MlirAttribute attr =
+ mlirStringAttrGet(context->get(), toMlirStringRef(value));
+ return PyStringAttribute(context->getRef(), attr);
+ },
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets a uniqued string attribute");
c.def_static(
"get_typed",
@@ -665,20 +796,20 @@ class PyStringAttribute : public PyConcreteAttribute<PyStringAttribute> {
mlirStringAttrTypedGet(type, toMlirStringRef(value));
return PyStringAttribute(type.getContext(), attr);
},
- py::arg("type"), py::arg("value"),
+ nb::arg("type"), nb::arg("value"),
"Gets a uniqued string attribute associated to a type");
- c.def_property_readonly(
+ c.def_prop_ro(
"value",
[](PyStringAttribute &self) {
MlirStringRef stringRef = mlirStringAttrGetValue(self);
- return py::str(stringRef.data, stringRef.length);
+ return nb::str(stringRef.data, stringRef.length);
},
"Returns the value of the string attribute");
- c.def_property_readonly(
+ c.def_prop_ro(
"value_bytes",
[](PyStringAttribute &self) {
MlirStringRef stringRef = mlirStringAttrGetValue(self);
- return py::bytes(stringRef.data, stringRef.length);
+ return nb::bytes(stringRef.data, stringRef.length);
},
"Returns the value of the string attribute as `bytes`");
}
@@ -692,13 +823,12 @@ class PyDenseElementsAttribute
static constexpr const char *pyClassName = "DenseElementsAttr";
using PyConcreteAttribute::PyConcreteAttribute;
- static PyDenseElementsAttribute
- getFromList(py::list attributes, std::optional<PyType> explicitType,
- DefaultingPyMlirContext contextWrapper) {
-
- const size_t numAttributes = py::len(attributes);
+ static PyDenseElementsAttribute getFromList(
+ nb::list attributes, std::optional<PyType> explicitType,
+ DefaultingPyMlirContext contextWrapper) {
+ const size_t numAttributes = nb::len(attributes);
if (numAttributes == 0)
- throw py::value_error("Attributes list must be non-empty.");
+ throw nb::value_error("Attributes list must be non-empty.");
MlirType shapedType;
if (explicitType) {
@@ -708,8 +838,8 @@ class PyDenseElementsAttribute
std::string message;
llvm::raw_string_ostream os(message);
os << "Expected a static ShapedType for the shaped_type parameter: "
- << py::repr(py::cast(*explicitType));
- throw py::value_error(message);
+ << nb::cast<std::string_view>(nb::repr(nb::cast(*explicitType)));
+ throw nb::value_error(message.c_str());
}
shapedType = *explicitType;
} else {
@@ -722,7 +852,7 @@ class PyDenseElementsAttribute
SmallVector<MlirAttribute> mlirAttributes;
mlirAttributes.reserve(numAttributes);
- for (const py::handle &attribute : attributes) {
+ for (const nb::handle &attribute : attributes) {
MlirAttribute mlirAttribute = pyTryCast<PyAttribute>(attribute);
MlirType attrType = mlirAttributeGetType(mlirAttribute);
mlirAttributes.push_back(mlirAttribute);
@@ -731,9 +861,11 @@ class PyDenseElementsAttribute
std::string message;
llvm::raw_string_ostream os(message);
os << "All attributes must be of the same type and match "
- << "the type parameter: expected=" << py::repr(py::cast(shapedType))
- << ", but got=" << py::repr(py::cast(attrType));
- throw py::value_error(message);
+ << "the type parameter: expected="
+ << nb::cast<std::string_view>(nb::repr(nb::cast(shapedType)))
+ << ", but got="
+ << nb::cast<std::string_view>(nb::repr(nb::cast(attrType)));
+ throw nb::value_error(message.c_str());
}
}
@@ -743,11 +875,10 @@ class PyDenseElementsAttribute
return PyDenseElementsAttribute(contextWrapper->getRef(), elements);
}
- static PyDenseElementsAttribute
- getFromBuffer(py::buffer array, bool signless,
- std::optional<PyType> explicitType,
- std::optional<std::vector<int64_t>> explicitShape,
- DefaultingPyMlirContext contextWrapper) {
+ static PyDenseElementsAttribute getFromBuffer(
+ nb_buffer array, bool signless, std::optional<PyType> explicitType,
+ std::optional<std::vector<int64_t>> explicitShape,
+ DefaultingPyMlirContext contextWrapper) {
// Request a contiguous view. In exotic cases, this will cause a copy.
int flags = PyBUF_ND;
if (!explicitType) {
@@ -755,7 +886,7 @@ class PyDenseElementsAttribute
}
Py_buffer view;
if (PyObject_GetBuffer(array.ptr(), &view, flags) != 0) {
- throw py::error_already_set();
+ throw nb::python_error();
}
auto freeBuffer = llvm::make_scope_exit([&]() { PyBuffer_Release(&view); });
@@ -778,25 +909,29 @@ class PyDenseElementsAttribute
if (!mlirAttributeIsAInteger(elementAttr) &&
!mlirAttributeIsAFloat(elementAttr)) {
std::string message = "Illegal element type for DenseElementsAttr: ";
- message.append(py::repr(py::cast(elementAttr)));
- throw py::value_error(message);
+ message.append(
+ nb::cast<std::string_view>(nb::repr(nb::cast(elementAttr))));
+ throw nb::value_error(message.c_str());
}
if (!mlirTypeIsAShaped(shapedType) ||
!mlirShapedTypeHasStaticShape(shapedType)) {
std::string message =
"Expected a static ShapedType for the shaped_type parameter: ";
- message.append(py::repr(py::cast(shapedType)));
- throw py::value_error(message);
+ message.append(
+ nb::cast<std::string_view>(nb::repr(nb::cast(shapedType))));
+ throw nb::value_error(message.c_str());
}
MlirType shapedElementType = mlirShapedTypeGetElementType(shapedType);
MlirType attrType = mlirAttributeGetType(elementAttr);
if (!mlirTypeEqual(shapedElementType, attrType)) {
std::string message =
"Shaped element type and attribute type must be equal: shaped=";
- message.append(py::repr(py::cast(shapedType)));
+ message.append(
+ nb::cast<std::string_view>(nb::repr(nb::cast(shapedType))));
message.append(", element=");
- message.append(py::repr(py::cast(elementAttr)));
- throw py::value_error(message);
+ message.append(
+ nb::cast<std::string_view>(nb::repr(nb::cast(elementAttr))));
+ throw nb::value_error(message.c_str());
}
MlirAttribute elements =
@@ -806,7 +941,7 @@ class PyDenseElementsAttribute
intptr_t dunderLen() { return mlirElementsAttrGetNumElements(*this); }
- py::buffer_info accessBuffer() {
+ nb_buffer_info accessBuffer() {
MlirType shapedType = mlirAttributeGetType(*this);
MlirType elementType = mlirShapedTypeGetElementType(shapedType);
std::string format;
@@ -889,32 +1024,36 @@ class PyDenseElementsAttribute
static void bindDerived(ClassTy &c) {
c.def("__len__", &PyDenseElementsAttribute::dunderLen)
.def_static("get", PyDenseElementsAttribute::getFromBuffer,
- py::arg("array"), py::arg("signless") = true,
- py::arg("type") = py::none(), py::arg("shape") = py::none(),
- py::arg("context") = py::none(),
+ nb::arg("array"), nb::arg("signless") = true,
+ nb::arg("type").none() = nb::none(),
+ nb::arg("shape").none() = nb::none(),
+ nb::arg("context").none() = nb::none(),
kDenseElementsAttrGetDocstring)
.def_static("get", PyDenseElementsAttribute::getFromList,
- py::arg("attrs"), py::arg("type") = py::none(),
- py::arg("context") = py::none(),
+ nb::arg("attrs"), nb::arg("type").none() = nb::none(),
+ nb::arg("context").none() = nb::none(),
kDenseElementsAttrGetFromListDocstring)
.def_static("get_splat", PyDenseElementsAttribute::getSplat,
- py::arg("shaped_type"), py::arg("element_attr"),
+ nb::arg("shaped_type"), nb::arg("element_attr"),
"Gets a DenseElementsAttr where all values are the same")
- .def_property_readonly("is_splat",
- [](PyDenseElementsAttribute &self) -> bool {
- return mlirDenseElementsAttrIsSplat(self);
- })
- .def("get_splat_value",
- [](PyDenseElementsAttribute &self) {
- if (!mlirDenseElementsAttrIsSplat(self))
- throw py::value_error(
- "get_splat_value called on a non-splat attribute");
- return mlirDenseElementsAttrGetSplatValue(self);
- })
- .def_buffer(&PyDenseElementsAttribute::accessBuffer);
+ .def_prop_ro("is_splat",
+ [](PyDenseElementsAttribute &self) -> bool {
+ return mlirDenseElementsAttrIsSplat(self);
+ })
+ .def("get_splat_value", [](PyDenseElementsAttribute &self) {
+ if (!mlirDenseElementsAttrIsSplat(self))
+ throw nb::value_error(
+ "get_splat_value called on a non-splat attribute");
+ return mlirDenseElementsAttrGetSplatValue(self);
+ });
}
-private:
+ static PyType_Slot slots[];
+
+ private:
+ static int bf_getbuffer(PyObject *exporter, Py_buffer *view, int flags);
+ static void bf_releasebuffer(PyObject *, Py_buffer *buffer);
+
static bool isUnsignedIntegerFormat(std::string_view format) {
if (format.empty())
return false;
@@ -1039,27 +1178,28 @@ class PyDenseElementsAttribute
return mlirDenseElementsAttrRawBufferGet(type, view.len, view.buf);
}
- // There is a complication for boolean numpy arrays, as numpy represents them
- // as 8 bits (1 byte) per boolean, whereas MLIR bitpacks them into 8 booleans
- // per byte.
+ // There is a complication for boolean numpy arrays, as numpy represents
+ // them as 8 bits (1 byte) per boolean, whereas MLIR bitpacks them into 8
+ // booleans per byte.
static MlirAttribute getBitpackedAttributeFromBooleanBuffer(
Py_buffer &view, std::optional<std::vector<int64_t>> explicitShape,
MlirContext &context) {
if (llvm::endianness::native != llvm::endianness::little) {
- // Given we have no good way of testing the behavior on big-endian systems
- // we will throw
- throw py::type_error("Constructing a bit-packed MLIR attribute is "
- "unsupported on big-endian systems");
+ // Given we have no good way of testing the behavior on big-endian
+ // systems we will throw
+ throw nb::type_error(
+ "Constructing a bit-packed MLIR attribute is "
+ "unsupported on big-endian systems");
}
+ nb::ndarray<uint8_t, nb::numpy, nb::ndim<1>, nb::c_contig> unpackedArray(
+ /*data=*/static_cast<uint8_t *>(view.buf),
+ /*shape=*/{static_cast<size_t>(view.len)});
- py::array_t<uint8_t> unpackedArray(view.len,
- static_cast<uint8_t *>(view.buf));
-
- py::module numpy = py::module::import("numpy");
- py::object packbitsFunc = numpy.attr("packbits");
- py::object packedBooleans =
- packbitsFunc(unpackedArray, "bitorder"_a = "little");
- py::buffer_info pythonBuffer = packedBooleans.cast<py::buffer>().request();
+ nb::module_ numpy = nb::module_::import_("numpy");
+ nb::object packbitsFunc = numpy.attr("packbits");
+ nb::object packedBooleans =
+ packbitsFunc(nb::cast(unpackedArray), "bitorder"_a = "little");
+ nb_buffer_info pythonBuffer = nb::cast<nb_buffer>(packedBooleans).request();
MlirType bitpackedType =
getShapedType(mlirIntegerTypeGet(context, 1), explicitShape, view);
@@ -1073,33 +1213,37 @@ class PyDenseElementsAttribute
// This does the opposite transformation of
// `getBitpackedAttributeFromBooleanBuffer`
- py::buffer_info getBooleanBufferFromBitpackedAttribute() {
+ nb_buffer_info getBooleanBufferFromBitpackedAttribute() {
if (llvm::endianness::native != llvm::endianness::little) {
- // Given we have no good way of testing the behavior on big-endian systems
- // we will throw
- throw py::type_error("Constructing a numpy array from a MLIR attribute "
- "is unsupported on big-endian systems");
+ // Given we have no good way of testing the behavior on big-endian
+ // systems we will throw
+ throw nb::type_error(
+ "Constructing a numpy array from a MLIR attribute "
+ "is unsupported on big-endian systems");
}
int64_t numBooleans = mlirElementsAttrGetNumElements(*this);
int64_t numBitpackedBytes = llvm::divideCeil(numBooleans, 8);
uint8_t *bitpackedData = static_cast<uint8_t *>(
const_cast<void *>(mlirDenseElementsAttrGetRawData(*this)));
- py::array_t<uint8_t> packedArray(numBitpackedBytes, bitpackedData);
+ nb::ndarray<uint8_t, nb::numpy, nb::ndim<1>, nb::c_contig> packedArray(
+ /*data=*/bitpackedData,
+ /*shape=*/{static_cast<size_t>(numBitpackedBytes)});
- py::module numpy = py::module::import("numpy");
- py::object unpackbitsFunc = numpy.attr("unpackbits");
- py::object equalFunc = numpy.attr("equal");
- py::object reshapeFunc = numpy.attr("reshape");
- py::array unpackedBooleans =
- unpackbitsFunc(packedArray, "bitorder"_a = "little");
+ nb::module_ numpy = nb::module_::import_("numpy");
+ nb::object unpackbitsFunc = numpy.attr("unpackbits");
+ nb::object equalFunc = numpy.attr("equal");
+ nb::object reshapeFunc = numpy.attr("reshape");
+ nb::object unpackedBooleans =
+ unpackbitsFunc(nb::cast(packedArray), "bitorder"_a = "little");
// Unpackbits operates on bytes and gives back a flat 0 / 1 integer array.
// We need to:
// 1. Slice away the padded bits
// 2. Make the boolean array have the correct shape
// 3. Convert the array to a boolean array
- unpackedBooleans = unpackedBooleans[py::slice(0, numBooleans, 1)];
+ unpackedBooleans = unpackedBooleans[nb::slice(
+ nb::int_(0), nb::int_(numBooleans), nb::int_(1))];
unpackedBooleans = equalFunc(unpackedBooleans, 1);
MlirType shapedType = mlirAttributeGetType(*this);
@@ -1110,15 +1254,15 @@ class PyDenseElementsAttribute
}
unpackedBooleans = reshapeFunc(unpackedBooleans, shape);
- // Make sure the returned py::buffer_view claims ownership of the data in
+ // Make sure the returned nb::buffer_view claims ownership of the data in
// `pythonBuffer` so it remains valid when Python reads it
- py::buffer pythonBuffer = unpackedBooleans.cast<py::buffer>();
+ nb_buffer pythonBuffer = nb::cast<nb_buffer>(unpackedBooleans);
return pythonBuffer.request();
}
template <typename Type>
- py::buffer_info bufferInfo(MlirType shapedType,
- const char *explicitFormat = nullptr) {
+ nb_buffer_info bufferInfo(MlirType shapedType,
+ const char *explicitFormat = nullptr) {
intptr_t rank = mlirShapedTypeGetRank(shapedType);
// Prepare the data for the buffer_info.
// Buffer is configured for read-only access below.
@@ -1142,19 +1286,69 @@ class PyDenseElementsAttribute
}
strides.push_back(sizeof(Type));
}
- std::string format;
+ const char *format;
if (explicitFormat) {
format = explicitFormat;
} else {
- format = py::format_descriptor<Type>::format();
+ format = nb_format_descriptor<Type>::format();
}
- return py::buffer_info(data, sizeof(Type), format, rank, shape, strides,
- /*readonly=*/true);
+ return nb_buffer_info(data, sizeof(Type), format, rank, std::move(shape),
+ std::move(strides),
+ /*readonly=*/true);
}
}; // namespace
-/// Refinement of the PyDenseElementsAttribute for attributes containing integer
-/// (and boolean) values. Supports element access.
+PyType_Slot PyDenseElementsAttribute::slots[] = {
+ {Py_bf_getbuffer,
+ reinterpret_cast<void *>(PyDenseElementsAttribute::bf_getbuffer)},
+ {Py_bf_releasebuffer,
+ reinterpret_cast<void *>(PyDenseElementsAttribute::bf_releasebuffer)},
+ {0, nullptr},
+};
+
+/*static*/ int PyDenseElementsAttribute::bf_getbuffer(PyObject *obj,
+ Py_buffer *view,
+ int flags) {
+ view->obj = nullptr;
+ nb_buffer_info info;
+ try {
+ auto *attr = nb::cast<PyDenseElementsAttribute *>(nb::handle(obj));
+ info = attr->accessBuffer();
+ } catch (nb::python_error &e) {
+ e.restore();
+ nb::chain_error(PyExc_BufferError, "Error converting attribute to buffer");
+ return -1;
+ }
+ view->obj = obj;
+ view->ndim = 1;
+ view->buf = info.ptr;
+ view->itemsize = info.itemsize;
+ view->len = info.itemsize;
+ for (auto s : info.shape) {
+ view->len *= s;
+ }
+ view->readonly = info.readonly;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+ view->format = const_cast<char *>(info.format);
+ }
+ if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+ view->ndim = static_cast<int>(info.ndim);
+ view->strides = info.strides.data();
+ view->shape = info.shape.data();
+ }
+ view->suboffsets = nullptr;
+ view->internal = new nb_buffer_info(std::move(info));
+ Py_INCREF(obj);
+ return 0;
+}
+
+/*static*/ void PyDenseElementsAttribute::bf_releasebuffer(PyObject *,
+ Py_buffer *view) {
+ delete reinterpret_cast<nb_buffer_info *>(view->internal);
+}
+
+/// Refinement of the PyDenseElementsAttribute for attributes containing
+/// integer (and boolean) values. Supports element access.
class PyDenseIntElementsAttribute
: public PyConcreteAttribute<PyDenseIntElementsAttribute,
PyDenseElementsAttribute> {
@@ -1163,11 +1357,11 @@ class PyDenseIntElementsAttribute
static constexpr const char *pyClassName = "DenseIntElementsAttr";
using PyConcreteAttribute::PyConcreteAttribute;
- /// Returns the element at the given linear position. Asserts if the index is
- /// out of range.
- py::int_ dunderGetItem(intptr_t pos) {
+ /// Returns the element at the given linear position. Asserts if the index
+ /// is out of range.
+ nb::object dunderGetItem(intptr_t pos) {
if (pos < 0 || pos >= dunderLen()) {
- throw py::index_error("attempt to access out of bounds element");
+ throw nb::index_error("attempt to access out of bounds element");
}
MlirType type = mlirAttributeGetType(*this);
@@ -1175,7 +1369,7 @@ class PyDenseIntElementsAttribute
assert(mlirTypeIsAInteger(type) &&
"expected integer element type in dense int elements attribute");
// Dispatch element extraction to an appropriate C function based on the
- // elemental type of the attribute. py::int_ is implicitly constructible
+ // elemental type of the attribute. nb::int_ is implicitly constructible
// from any C++ integral type and handles bitwidth correctly.
// TODO: consider caching the type properties in the constructor to avoid
// querying them on each element access.
@@ -1183,38 +1377,38 @@ class PyDenseIntElementsAttribute
bool isUnsigned = mlirIntegerTypeIsUnsigned(type);
if (isUnsigned) {
if (width == 1) {
- return mlirDenseElementsAttrGetBoolValue(*this, pos);
+ return nb::int_(int(mlirDenseElementsAttrGetBoolValue(*this, pos)));
}
if (width == 8) {
- return mlirDenseElementsAttrGetUInt8Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetUInt8Value(*this, pos));
}
if (width == 16) {
- return mlirDenseElementsAttrGetUInt16Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetUInt16Value(*this, pos));
}
if (width == 32) {
- return mlirDenseElementsAttrGetUInt32Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetUInt32Value(*this, pos));
}
if (width == 64) {
- return mlirDenseElementsAttrGetUInt64Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetUInt64Value(*this, pos));
}
} else {
if (width == 1) {
- return mlirDenseElementsAttrGetBoolValue(*this, pos);
+ return nb::int_(int(mlirDenseElementsAttrGetBoolValue(*this, pos)));
}
if (width == 8) {
- return mlirDenseElementsAttrGetInt8Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetInt8Value(*this, pos));
}
if (width == 16) {
- return mlirDenseElementsAttrGetInt16Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetInt16Value(*this, pos));
}
if (width == 32) {
- return mlirDenseElementsAttrGetInt32Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetInt32Value(*this, pos));
}
if (width == 64) {
- return mlirDenseElementsAttrGetInt64Value(*this, pos);
+ return nb::int_(mlirDenseElementsAttrGetInt64Value(*this, pos));
}
}
- throw py::type_error("Unsupported integer type");
+ throw nb::type_error("Unsupported integer type");
}
static void bindDerived(ClassTy &c) {
@@ -1230,10 +1424,10 @@ class PyDenseResourceElementsAttribute
static constexpr const char *pyClassName = "DenseResourceElementsAttr";
using PyConcreteAttribute::PyConcreteAttribute;
- static PyDenseResourceElementsAttribute
- getFromBuffer(py::buffer buffer, const std::string &name, const PyType &type,
- std::optional<size_t> alignment, bool isMutable,
- DefaultingPyMlirContext contextWrapper) {
+ static PyDenseResourceElementsAttribute getFromBuffer(
+ nb_buffer buffer, const std::string &name, const PyType &type,
+ std::optional<size_t> alignment, bool isMutable,
+ DefaultingPyMlirContext contextWrapper) {
if (!mlirTypeIsAShaped(type)) {
throw std::invalid_argument(
"Constructing a DenseResourceElementsAttr requires a ShapedType.");
@@ -1244,7 +1438,7 @@ class PyDenseResourceElementsAttribute
int flags = PyBUF_STRIDES;
std::unique_ptr<Py_buffer> view = std::make_unique<Py_buffer>();
if (PyObject_GetBuffer(buffer.ptr(), view.get(), flags) != 0) {
- throw py::error_already_set();
+ throw nb::python_error();
}
// This scope releaser will only release if we haven't yet transferred
@@ -1289,12 +1483,12 @@ class PyDenseResourceElementsAttribute
}
static void bindDerived(ClassTy &c) {
- c.def_static("get_from_buffer",
- PyDenseResourceElementsAttribute::getFromBuffer,
- py::arg("array"), py::arg("name"), py::arg("type"),
- py::arg("alignment") = py::none(),
- py::arg("is_mutable") = false, py::arg("context") = py::none(),
- kDenseResourceElementsAttrGetFromBufferDocstring);
+ c.def_static(
+ "get_from_buffer", PyDenseResourceElementsAttribute::getFromBuffer,
+ nb::arg("array"), nb::arg("name"), nb::arg("type"),
+ nb::arg("alignment").none() = nb::none(), nb::arg("is_mutable") = false,
+ nb::arg("context").none() = nb::none(),
+ kDenseResourceElementsAttrGetFromBufferDocstring);
}
};
@@ -1318,12 +1512,12 @@ class PyDictAttribute : public PyConcreteAttribute<PyDictAttribute> {
c.def("__len__", &PyDictAttribute::dunderLen);
c.def_static(
"get",
- [](py::dict attributes, DefaultingPyMlirContext context) {
+ [](nb::dict attributes, DefaultingPyMlirContext context) {
SmallVector<MlirNamedAttribute> mlirNamedAttributes;
mlirNamedAttributes.reserve(attributes.size());
- for (auto &it : attributes) {
- auto &mlirAttr = it.second.cast<PyAttribute &>();
- auto name = it.first.cast<std::string>();
+ for (std::pair<nb::handle, nb::handle> it : attributes) {
+ auto &mlirAttr = nb::cast<PyAttribute &>(it.second);
+ auto name = nb::cast<std::string>(it.first);
mlirNamedAttributes.push_back(mlirNamedAttributeGet(
mlirIdentifierGet(mlirAttributeGetContext(mlirAttr),
toMlirStringRef(name)),
@@ -1334,18 +1528,18 @@ class PyDictAttribute : public PyConcreteAttribute<PyDictAttribute> {
mlirNamedAttributes.data());
return PyDictAttribute(context->getRef(), attr);
},
- py::arg("value") = py::dict(), py::arg("context") = py::none(),
+ nb::arg("value") = nb::dict(), nb::arg("context").none() = nb::none(),
"Gets an uniqued dict attribute");
c.def("__getitem__", [](PyDictAttribute &self, const std::string &name) {
MlirAttribute attr =
mlirDictionaryAttrGetElementByName(self, toMlirStringRef(name));
if (mlirAttributeIsNull(attr))
- throw py::key_error("attempt to access a non-existent attribute");
+ throw nb::key_error("attempt to access a non-existent attribute");
return attr;
});
c.def("__getitem__", [](PyDictAttribute &self, intptr_t index) {
if (index < 0 || index >= self.dunderLen()) {
- throw py::index_error("attempt to access out of bounds attribute");
+ throw nb::index_error("attempt to access out of bounds attribute");
}
MlirNamedAttribute namedAttr = mlirDictionaryAttrGetElement(self, index);
return PyNamedAttribute(
@@ -1365,25 +1559,25 @@ class PyDenseFPElementsAttribute
static constexpr const char *pyClassName = "DenseFPElementsAttr";
using PyConcreteAttribute::PyConcreteAttribute;
- py::float_ dunderGetItem(intptr_t pos) {
+ nb::float_ dunderGetItem(intptr_t pos) {
if (pos < 0 || pos >= dunderLen()) {
- throw py::index_error("attempt to access out of bounds element");
+ throw nb::index_error("attempt to access out of bounds element");
}
MlirType type = mlirAttributeGetType(*this);
type = mlirShapedTypeGetElementType(type);
// Dispatch element extraction to an appropriate C function based on the
- // elemental type of the attribute. py::float_ is implicitly constructible
+ // elemental type of the attribute. nb::float_ is implicitly constructible
// from float and double.
// TODO: consider caching the type properties in the constructor to avoid
// querying them on each element access.
if (mlirTypeIsAF32(type)) {
- return mlirDenseElementsAttrGetFloatValue(*this, pos);
+ return nb::float_(mlirDenseElementsAttrGetFloatValue(*this, pos));
}
if (mlirTypeIsAF64(type)) {
- return mlirDenseElementsAttrGetDoubleValue(*this, pos);
+ return nb::float_(mlirDenseElementsAttrGetDoubleValue(*this, pos));
}
- throw py::type_error("Unsupported floating-point type");
+ throw nb::type_error("Unsupported floating-point type");
}
static void bindDerived(ClassTy &c) {
@@ -1406,9 +1600,9 @@ class PyTypeAttribute : public PyConcreteAttribute<PyTypeAttribute> {
MlirAttribute attr = mlirTypeAttrGet(value.get());
return PyTypeAttribute(context->getRef(), attr);
},
- py::arg("value"), py::arg("context") = py::none(),
+ nb::arg("value"), nb::arg("context").none() = nb::none(),
"Gets a uniqued Type attribute");
- c.def_property_readonly("value", [](PyTypeAttribute &self) {
+ c.def_prop_ro("value", [](PyTypeAttribute &self) {
return mlirTypeAttrGetValue(self.get());
});
}
@@ -1430,7 +1624,7 @@ class PyUnitAttribute : public PyConcreteAttribute<PyUnitAttribute> {
return PyUnitAttribute(context->getRef(),
mlirUnitAttrGet(context->get()));
},
- py::arg("context") = py::none(), "Create a Unit attribute.");
+ nb::arg("context").none() = nb::none(), "Create a Unit attribute.");
}
};
@@ -1453,7 +1647,8 @@ class PyStridedLayoutAttribute
ctx->get(), offset, strides.size(), strides.data());
return PyStridedLayoutAttribute(ctx->getRef(), attr);
},
- py::arg("offset"), py::arg("strides"), py::arg("context") = py::none(),
+ nb::arg("offset"), nb::arg("strides"),
+ nb::arg("context").none() = nb::none(),
"Gets a strided layout attribute.");
c.def_static(
"get_fully_dynamic",
@@ -1465,16 +1660,17 @@ class PyStridedLayoutAttribute
ctx->get(), dynamic, strides.size(), strides.data());
return PyStridedLayoutAttribute(ctx->getRef(), attr);
},
- py::arg("rank"), py::arg("context") = py::none(),
- "Gets a strided layout attribute with dynamic offset and strides of a "
+ nb::arg("rank"), nb::arg("context").none() = nb::none(),
+ "Gets a strided layout attribute with dynamic offset and strides of "
+ "a "
"given rank.");
- c.def_property_readonly(
+ c.def_prop_ro(
"offset",
[](PyStridedLayoutAttribute &self) {
return mlirStridedLayoutAttrGetOffset(self);
},
"Returns the value of the float point attribute");
- c.def_property_readonly(
+ c.def_prop_ro(
"strides",
[](PyStridedLayoutAttribute &self) {
intptr_t size = mlirStridedLayoutAttrGetNumStrides(self);
@@ -1488,63 +1684,64 @@ class PyStridedLayoutAttribute
}
};
-py::object denseArrayAttributeCaster(PyAttribute &pyAttribute) {
+nb::object denseArrayAttributeCaster(PyAttribute &pyAttribute) {
if (PyDenseBoolArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseBoolArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseBoolArrayAttribute(pyAttribute));
if (PyDenseI8ArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseI8ArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseI8ArrayAttribute(pyAttribute));
if (PyDenseI16ArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseI16ArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseI16ArrayAttribute(pyAttribute));
if (PyDenseI32ArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseI32ArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseI32ArrayAttribute(pyAttribute));
if (PyDenseI64ArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseI64ArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseI64ArrayAttribute(pyAttribute));
if (PyDenseF32ArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseF32ArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseF32ArrayAttribute(pyAttribute));
if (PyDenseF64ArrayAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseF64ArrayAttribute(pyAttribute));
+ return nb::cast(PyDenseF64ArrayAttribute(pyAttribute));
std::string msg =
std::string("Can't cast unknown element type DenseArrayAttr (") +
- std::string(py::repr(py::cast(pyAttribute))) + ")";
- throw py::cast_error(msg);
+ nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
+ throw nb::type_error(msg.c_str());
}
-py::object denseIntOrFPElementsAttributeCaster(PyAttribute &pyAttribute) {
+nb::object denseIntOrFPElementsAttributeCaster(PyAttribute &pyAttribute) {
if (PyDenseFPElementsAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseFPElementsAttribute(pyAttribute));
+ return nb::cast(PyDenseFPElementsAttribute(pyAttribute));
if (PyDenseIntElementsAttribute::isaFunction(pyAttribute))
- return py::cast(PyDenseIntElementsAttribute(pyAttribute));
+ return nb::cast(PyDenseIntElementsAttribute(pyAttribute));
std::string msg =
std::string(
"Can't cast unknown element type DenseIntOrFPElementsAttr (") +
- std::string(py::repr(py::cast(pyAttribute))) + ")";
- throw py::cast_error(msg);
+ nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
+ throw nb::type_error(msg.c_str());
}
-py::object integerOrBoolAttributeCaster(PyAttribute &pyAttribute) {
+nb::object integerOrBoolAttributeCaster(PyAttribute &pyAttribute) {
if (PyBoolAttribute::isaFunction(pyAttribute))
- return py::cast(PyBoolAttribute(pyAttribute));
+ return nb::cast(PyBoolAttribute(pyAttribute));
if (PyIntegerAttribute::isaFunction(pyAttribute))
- return py::cast(PyIntegerAttribute(pyAttribute));
+ return nb::cast(PyIntegerAttribute(pyAttribute));
std::string msg =
std::string("Can't cast unknown element type DenseArrayAttr (") +
- std::string(py::repr(py::cast(pyAttribute))) + ")";
- throw py::cast_error(msg);
+ nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
+ throw nb::type_error(msg.c_str());
}
-py::object symbolRefOrFlatSymbolRefAttributeCaster(PyAttribute &pyAttribute) {
+nb::object symbolRefOrFlatSymbolRefAttributeCaster(PyAttribute &pyAttribute) {
if (PyFlatSymbolRefAttribute::isaFunction(pyAttribute))
- return py::cast(PyFlatSymbolRefAttribute(pyAttribute));
+ return nb::cast(PyFlatSymbolRefAttribute(pyAttribute));
if (PySymbolRefAttribute::isaFunction(pyAttribute))
- return py::cast(PySymbolRefAttribute(pyAttribute));
+ return nb::cast(PySymbolRefAttribute(pyAttribute));
std::string msg = std::string("Can't cast unknown SymbolRef attribute (") +
- std::string(py::repr(py::cast(pyAttribute))) + ")";
- throw py::cast_error(msg);
+ nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) +
+ ")";
+ throw nb::type_error(msg.c_str());
}
} // namespace
-void mlir::python::populateIRAttributes(py::module &m) {
+void mlir::python::populateIRAttributes(nb::module_ &m) {
PyAffineMapAttribute::bind(m);
PyDenseBoolArrayAttribute::bind(m);
PyDenseBoolArrayAttribute::PyDenseArrayIterator::bind(m);
@@ -1562,24 +1759,26 @@ void mlir::python::populateIRAttributes(py::module &m) {
PyDenseF64ArrayAttribute::PyDenseArrayIterator::bind(m);
PyGlobals::get().registerTypeCaster(
mlirDenseArrayAttrGetTypeID(),
- pybind11::cpp_function(denseArrayAttributeCaster));
+ nb::cast<nb::callable>(nb::cpp_function(denseArrayAttributeCaster)));
PyArrayAttribute::bind(m);
PyArrayAttribute::PyArrayAttributeIterator::bind(m);
PyBoolAttribute::bind(m);
- PyDenseElementsAttribute::bind(m);
+ PyDenseElementsAttribute::bind(m, PyDenseElementsAttribute::slots);
PyDenseFPElementsAttribute::bind(m);
PyDenseIntElementsAttribute::bind(m);
PyGlobals::get().registerTypeCaster(
mlirDenseIntOrFPElementsAttrGetTypeID(),
- pybind11::cpp_function(denseIntOrFPElementsAttributeCaster));
+ nb::cast<nb::callable>(
+ nb::cpp_function(denseIntOrFPElementsAttributeCaster)));
PyDenseResourceElementsAttribute::bind(m);
PyDictAttribute::bind(m);
PySymbolRefAttribute::bind(m);
PyGlobals::get().registerTypeCaster(
mlirSymbolRefAttrGetTypeID(),
- pybind11::cpp_function(symbolRefOrFlatSymbolRefAttributeCaster));
+ nb::cast<nb::callable>(
+ nb::cpp_function(symbolRefOrFlatSymbolRefAttributeCaster)));
PyFlatSymbolRefAttribute::bind(m);
PyOpaqueAttribute::bind(m);
@@ -1590,7 +1789,7 @@ void mlir::python::populateIRAttributes(py::module &m) {
PyTypeAttribute::bind(m);
PyGlobals::get().registerTypeCaster(
mlirIntegerAttrGetTypeID(),
- pybind11::cpp_function(integerOrBoolAttributeCaster));
+ nb::cast<nb::callable>(nb::cpp_function(integerOrBoolAttributeCaster)));
PyUnitAttribute::bind(m);
PyStridedLayoutAttribute::bind(m);
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 3e96f8c60ba7cd..e9b436b50dbeaa 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -6,26 +6,31 @@
//
//===----------------------------------------------------------------------===//
-#include "IRModule.h"
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/function.h>
+#include <nanobind/stl/optional.h>
+#include <nanobind/stl/string.h>
+#include <nanobind/stl/tuple.h>
+#include <nanobind/stl/vector.h>
-#include "Globals.h"
-#include "PybindUtils.h"
+#include <optional>
+#include <utility>
+#include "Globals.h"
+#include "IRModule.h"
+#include "NanobindUtils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/Debug.h"
#include "mlir-c/Diagnostics.h"
#include "mlir-c/IR.h"
#include "mlir-c/Support.h"
-#include "mlir/Bindings/Python/PybindAdaptors.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
-#include <optional>
-#include <utility>
-
-namespace py = pybind11;
-using namespace py::literals;
+namespace nb = nanobind;
+using namespace nb::literals;
using namespace mlir;
using namespace mlir::python;
@@ -190,18 +195,17 @@ operations.
/// Helper for creating an @classmethod.
template <class Func, typename... Args>
-py::object classmethod(Func f, Args... args) {
- py::object cf = py::cpp_function(f, args...);
- return py::reinterpret_borrow<py::object>((PyClassMethod_New(cf.ptr())));
+nb::object classmethod(Func f, Args... args) {
+ nb::object cf = nb::cpp_function(f, args...);
+ return nb::borrow<nb::object>((PyClassMethod_New(cf.ptr())));
}
-static py::object
-createCustomDialectWrapper(const std::string &dialectNamespace,
- py::object dialectDescriptor) {
+static nb::object createCustomDialectWrapper(
+ const std::string &dialectNamespace, nb::object dialectDescriptor) {
auto dialectClass = PyGlobals::get().lookupDialectClass(dialectNamespace);
if (!dialectClass) {
// Use the base class.
- return py::cast(PyDialect(std::move(dialectDescriptor)));
+ return nb::cast(PyDialect(std::move(dialectDescriptor)));
}
// Create the custom implementation.
@@ -212,42 +216,47 @@ static MlirStringRef toMlirStringRef(const std::string &s) {
return mlirStringRefCreate(s.data(), s.size());
}
+static MlirStringRef toMlirStringRef(const nb::bytes &s) {
+ return mlirStringRefCreate(static_cast<const char *>(s.data()), s.size());
+}
+
/// Create a block, using the current location context if no locations are
/// specified.
-static MlirBlock createBlock(const py::sequence &pyArgTypes,
- const std::optional<py::sequence> &pyArgLocs) {
+static MlirBlock createBlock(const nb::sequence &pyArgTypes,
+ const std::optional<nb::sequence> &pyArgLocs) {
SmallVector<MlirType> argTypes;
- argTypes.reserve(pyArgTypes.size());
+ argTypes.reserve(nb::len(pyArgTypes));
for (const auto &pyType : pyArgTypes)
- argTypes.push_back(pyType.cast<PyType &>());
+ argTypes.push_back(nb::cast<PyType &>(pyType));
SmallVector<MlirLocation> argLocs;
if (pyArgLocs) {
- argLocs.reserve(pyArgLocs->size());
+ argLocs.reserve(nb::len(*pyArgLocs));
for (const auto &pyLoc : *pyArgLocs)
- argLocs.push_back(pyLoc.cast<PyLocation &>());
+ argLocs.push_back(nb::cast<PyLocation &>(pyLoc));
} else if (!argTypes.empty()) {
argLocs.assign(argTypes.size(), DefaultingPyLocation::resolve());
}
if (argTypes.size() != argLocs.size())
- throw py::value_error(("Expected " + Twine(argTypes.size()) +
+ throw nb::value_error(("Expected " + Twine(argTypes.size()) +
" locations, got: " + Twine(argLocs.size()))
- .str());
+ .str()
+ .c_str());
return mlirBlockCreate(argTypes.size(), argTypes.data(), argLocs.data());
}
/// Wrapper for the global LLVM debugging flag.
struct PyGlobalDebugFlag {
- static void set(py::object &o, bool enable) { mlirEnableGlobalDebug(enable); }
+ static void set(nb::object &o, bool enable) { mlirEnableGlobalDebug(enable); }
- static bool get(const py::object &) { return mlirIsGlobalDebugEnabled(); }
+ static bool get(const nb::object &) { return mlirIsGlobalDebugEnabled(); }
- static void bind(py::module &m) {
+ static void bind(nb::module_ &m) {
// Debug flags.
- py::class_<PyGlobalDebugFlag>(m, "_GlobalDebug", py::module_local())
- .def_property_static("flag", &PyGlobalDebugFlag::get,
- &PyGlobalDebugFlag::set, "LLVM-wide debug flag")
+ nb::class_<PyGlobalDebugFlag>(m, "_GlobalDebug")
+ .def_prop_rw_static("flag", &PyGlobalDebugFlag::get,
+ &PyGlobalDebugFlag::set, "LLVM-wide debug flag")
.def_static(
"set_types",
[](const std::string &type) {
@@ -268,20 +277,19 @@ struct PyAttrBuilderMap {
static bool dunderContains(const std::string &attributeKind) {
return PyGlobals::get().lookupAttributeBuilder(attributeKind).has_value();
}
- static py::function dundeGetItemNamed(const std::string &attributeKind) {
+ static nb::callable dundeGetItemNamed(const std::string &attributeKind) {
auto builder = PyGlobals::get().lookupAttributeBuilder(attributeKind);
- if (!builder)
- throw py::key_error(attributeKind);
+ if (!builder) throw nb::key_error(attributeKind.c_str());
return *builder;
}
static void dundeSetItemNamed(const std::string &attributeKind,
- py::function func, bool replace) {
+ nb::callable func, bool replace) {
PyGlobals::get().registerAttributeBuilder(attributeKind, std::move(func),
replace);
}
- static void bind(py::module &m) {
- py::class_<PyAttrBuilderMap>(m, "AttrBuilder", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyAttrBuilderMap>(m, "AttrBuilder")
.def_static("contains", &PyAttrBuilderMap::dunderContains)
.def_static("get", &PyAttrBuilderMap::dundeGetItemNamed)
.def_static("insert", &PyAttrBuilderMap::dundeSetItemNamed,
@@ -295,8 +303,8 @@ struct PyAttrBuilderMap {
// PyBlock
//------------------------------------------------------------------------------
-py::object PyBlock::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonBlockToCapsule(get()));
+nb::object PyBlock::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonBlockToCapsule(get()));
}
//------------------------------------------------------------------------------
@@ -315,14 +323,14 @@ class PyRegionIterator {
PyRegion dunderNext() {
operation->checkValid();
if (nextIndex >= mlirOperationGetNumRegions(operation->get())) {
- throw py::stop_iteration();
+ throw nb::stop_iteration();
}
MlirRegion region = mlirOperationGetRegion(operation->get(), nextIndex++);
return PyRegion(operation, region);
}
- static void bind(py::module &m) {
- py::class_<PyRegionIterator>(m, "RegionIterator", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyRegionIterator>(m, "RegionIterator")
.def("__iter__", &PyRegionIterator::dunderIter)
.def("__next__", &PyRegionIterator::dunderNext);
}
@@ -351,14 +359,14 @@ class PyRegionList {
PyRegion dunderGetItem(intptr_t index) {
// dunderLen checks validity.
if (index < 0 || index >= dunderLen()) {
- throw py::index_error("attempt to access out of bounds region");
+ throw nb::index_error("attempt to access out of bounds region");
}
MlirRegion region = mlirOperationGetRegion(operation->get(), index);
return PyRegion(operation, region);
}
- static void bind(py::module &m) {
- py::class_<PyRegionList>(m, "RegionSequence", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyRegionList>(m, "RegionSequence")
.def("__len__", &PyRegionList::dunderLen)
.def("__iter__", &PyRegionList::dunderIter)
.def("__getitem__", &PyRegionList::dunderGetItem);
@@ -378,7 +386,7 @@ class PyBlockIterator {
PyBlock dunderNext() {
operation->checkValid();
if (mlirBlockIsNull(next)) {
- throw py::stop_iteration();
+ throw nb::stop_iteration();
}
PyBlock returnBlock(operation, next);
@@ -386,8 +394,8 @@ class PyBlockIterator {
return returnBlock;
}
- static void bind(py::module &m) {
- py::class_<PyBlockIterator>(m, "BlockIterator", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyBlockIterator>(m, "BlockIterator")
.def("__iter__", &PyBlockIterator::dunderIter)
.def("__next__", &PyBlockIterator::dunderNext);
}
@@ -424,7 +432,7 @@ class PyBlockList {
PyBlock dunderGetItem(intptr_t index) {
operation->checkValid();
if (index < 0) {
- throw py::index_error("attempt to access out of bounds block");
+ throw nb::index_error("attempt to access out of bounds block");
}
MlirBlock block = mlirRegionGetFirstBlock(region);
while (!mlirBlockIsNull(block)) {
@@ -434,24 +442,26 @@ class PyBlockList {
block = mlirBlockGetNextInRegion(block);
index -= 1;
}
- throw py::index_error("attempt to access out of bounds block");
+ throw nb::index_error("attempt to access out of bounds block");
}
- PyBlock appendBlock(const py::args &pyArgTypes,
- const std::optional<py::sequence> &pyArgLocs) {
+ PyBlock appendBlock(const nb::args &pyArgTypes,
+ const std::optional<nb::sequence> &pyArgLocs) {
operation->checkValid();
- MlirBlock block = createBlock(pyArgTypes, pyArgLocs);
+ MlirBlock block =
+ createBlock(nb::cast<nb::sequence>(pyArgTypes), pyArgLocs);
mlirRegionAppendOwnedBlock(region, block);
return PyBlock(operation, block);
}
- static void bind(py::module &m) {
- py::class_<PyBlockList>(m, "BlockList", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyBlockList>(m, "BlockList")
.def("__getitem__", &PyBlockList::dunderGetItem)
.def("__iter__", &PyBlockList::dunderIter)
.def("__len__", &PyBlockList::dunderLen)
.def("append", &PyBlockList::appendBlock, kAppendBlockDocstring,
- py::arg("arg_locs") = std::nullopt);
+ nb::arg("args"), nb::kw_only(),
+ nb::arg("arg_locs") = std::nullopt);
}
private:
@@ -466,10 +476,10 @@ class PyOperationIterator {
PyOperationIterator &dunderIter() { return *this; }
- py::object dunderNext() {
+ nb::object dunderNext() {
parentOperation->checkValid();
if (mlirOperationIsNull(next)) {
- throw py::stop_iteration();
+ throw nb::stop_iteration();
}
PyOperationRef returnOperation =
@@ -478,8 +488,8 @@ class PyOperationIterator {
return returnOperation->createOpView();
}
- static void bind(py::module &m) {
- py::class_<PyOperationIterator>(m, "OperationIterator", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyOperationIterator>(m, "OperationIterator")
.def("__iter__", &PyOperationIterator::dunderIter)
.def("__next__", &PyOperationIterator::dunderNext);
}
@@ -515,10 +525,10 @@ class PyOperationList {
return count;
}
- py::object dunderGetItem(intptr_t index) {
+ nb::object dunderGetItem(intptr_t index) {
parentOperation->checkValid();
if (index < 0) {
- throw py::index_error("attempt to access out of bounds operation");
+ throw nb::index_error("attempt to access out of bounds operation");
}
MlirOperation childOp = mlirBlockGetFirstOperation(block);
while (!mlirOperationIsNull(childOp)) {
@@ -529,11 +539,11 @@ class PyOperationList {
childOp = mlirOperationGetNextInBlock(childOp);
index -= 1;
}
- throw py::index_error("attempt to access out of bounds operation");
+ throw nb::index_error("attempt to access out of bounds operation");
}
- static void bind(py::module &m) {
- py::class_<PyOperationList>(m, "OperationList", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyOperationList>(m, "OperationList")
.def("__getitem__", &PyOperationList::dunderGetItem)
.def("__iter__", &PyOperationList::dunderIter)
.def("__len__", &PyOperationList::dunderLen);
@@ -548,7 +558,7 @@ class PyOpOperand {
public:
PyOpOperand(MlirOpOperand opOperand) : opOperand(opOperand) {}
- py::object getOwner() {
+ nb::object getOwner() {
MlirOperation owner = mlirOpOperandGetOwner(opOperand);
PyMlirContextRef context =
PyMlirContext::forContext(mlirOperationGetContext(owner));
@@ -557,11 +567,10 @@ class PyOpOperand {
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);
+ static void bind(nb::module_ &m) {
+ nb::class_<PyOpOperand>(m, "OpOperand")
+ .def_prop_ro("owner", &PyOpOperand::getOwner)
+ .def_prop_ro("operand_number", &PyOpOperand::getOperandNumber);
}
private:
@@ -575,16 +584,15 @@ class PyOpOperandIterator {
PyOpOperandIterator &dunderIter() { return *this; }
PyOpOperand dunderNext() {
- if (mlirOpOperandIsNull(opOperand))
- throw py::stop_iteration();
+ if (mlirOpOperandIsNull(opOperand)) throw nb::stop_iteration();
PyOpOperand returnOpOperand(opOperand);
opOperand = mlirOpOperandGetNextUse(opOperand);
return returnOpOperand;
}
- static void bind(py::module &m) {
- py::class_<PyOpOperandIterator>(m, "OpOperandIterator", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyOpOperandIterator>(m, "OpOperandIterator")
.def("__iter__", &PyOpOperandIterator::dunderIter)
.def("__next__", &PyOpOperandIterator::dunderNext);
}
@@ -600,7 +608,7 @@ class PyOpOperandIterator {
//------------------------------------------------------------------------------
PyMlirContext::PyMlirContext(MlirContext context) : context(context) {
- py::gil_scoped_acquire acquire;
+ nb::gil_scoped_acquire acquire;
auto &liveContexts = getLiveContexts();
liveContexts[context.ptr] = this;
}
@@ -609,41 +617,35 @@ PyMlirContext::~PyMlirContext() {
// Note that the only public way to construct an instance is via the
// forContext method, which always puts the associated handle into
// liveContexts.
- py::gil_scoped_acquire acquire;
+ nb::gil_scoped_acquire acquire;
getLiveContexts().erase(context.ptr);
mlirContextDestroy(context);
}
-py::object PyMlirContext::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonContextToCapsule(get()));
+nb::object PyMlirContext::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonContextToCapsule(get()));
}
-py::object PyMlirContext::createFromCapsule(py::object capsule) {
+nb::object PyMlirContext::createFromCapsule(nb::object capsule) {
MlirContext rawContext = mlirPythonCapsuleToContext(capsule.ptr());
- if (mlirContextIsNull(rawContext))
- throw py::error_already_set();
+ if (mlirContextIsNull(rawContext)) throw nb::python_error();
return forContext(rawContext).releaseObject();
}
-PyMlirContext *PyMlirContext::createNewContextForInit() {
- MlirContext context = mlirContextCreateWithThreading(false);
- return new PyMlirContext(context);
-}
-
PyMlirContextRef PyMlirContext::forContext(MlirContext context) {
- py::gil_scoped_acquire acquire;
+ nb::gil_scoped_acquire acquire;
auto &liveContexts = getLiveContexts();
auto it = liveContexts.find(context.ptr);
if (it == liveContexts.end()) {
// Create.
PyMlirContext *unownedContextWrapper = new PyMlirContext(context);
- py::object pyRef = py::cast(unownedContextWrapper);
- assert(pyRef && "cast to py::object failed");
+ nb::object pyRef = nb::cast(unownedContextWrapper);
+ assert(pyRef && "cast to nb::object failed");
liveContexts[context.ptr] = unownedContextWrapper;
return PyMlirContextRef(unownedContextWrapper, std::move(pyRef));
}
// Use existing.
- py::object pyRef = py::cast(it->second);
+ nb::object pyRef = nb::cast(it->second);
return PyMlirContextRef(it->second, std::move(pyRef));
}
@@ -717,23 +719,23 @@ void PyMlirContext::clearOperationAndInside(PyOperationBase &op) {
size_t PyMlirContext::getLiveModuleCount() { return liveModules.size(); }
-pybind11::object PyMlirContext::contextEnter() {
- return PyThreadContextEntry::pushContext(*this);
+nb::object PyMlirContext::contextEnter(nb::object context) {
+ return PyThreadContextEntry::pushContext(context);
}
-void PyMlirContext::contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb) {
+void PyMlirContext::contextExit(const nb::object &excType,
+ const nb::object &excVal,
+ const nb::object &excTb) {
PyThreadContextEntry::popContext(*this);
}
-py::object PyMlirContext::attachDiagnosticHandler(py::object callback) {
+nb::object PyMlirContext::attachDiagnosticHandler(nb::object callback) {
// Note that ownership is transferred to the delete callback below by way of
// an explicit inc_ref (borrow).
PyDiagnosticHandler *pyHandler =
new PyDiagnosticHandler(get(), std::move(callback));
- py::object pyHandlerObject =
- py::cast(pyHandler, py::return_value_policy::take_ownership);
+ nb::object pyHandlerObject =
+ nb::cast(pyHandler, nb::rv_policy::take_ownership);
pyHandlerObject.inc_ref();
// In these C callbacks, the userData is a PyDiagnosticHandler* that is
@@ -741,17 +743,17 @@ py::object PyMlirContext::attachDiagnosticHandler(py::object callback) {
auto handlerCallback =
+[](MlirDiagnostic diagnostic, void *userData) -> MlirLogicalResult {
PyDiagnostic *pyDiagnostic = new PyDiagnostic(diagnostic);
- py::object pyDiagnosticObject =
- py::cast(pyDiagnostic, py::return_value_policy::take_ownership);
+ nb::object pyDiagnosticObject =
+ nb::cast(pyDiagnostic, nb::rv_policy::take_ownership);
auto *pyHandler = static_cast<PyDiagnosticHandler *>(userData);
bool result = false;
{
// Since this can be called from arbitrary C++ contexts, always get the
// gil.
- py::gil_scoped_acquire gil;
+ nb::gil_scoped_acquire gil;
try {
- result = py::cast<bool>(pyHandler->callback(pyDiagnostic));
+ result = nb::cast<bool>(pyHandler->callback(pyDiagnostic));
} catch (std::exception &e) {
fprintf(stderr, "MLIR Python Diagnostic handler raised exception: %s\n",
e.what());
@@ -768,8 +770,7 @@ py::object PyMlirContext::attachDiagnosticHandler(py::object callback) {
pyHandler->registeredID.reset();
// Decrement reference, balancing the inc_ref() above.
- py::object pyHandlerObject =
- py::cast(pyHandler, py::return_value_policy::reference);
+ nb::object pyHandlerObject = nb::cast(pyHandler, nb::rv_policy::reference);
pyHandlerObject.dec_ref();
};
@@ -819,9 +820,9 @@ PyThreadContextEntry *PyThreadContextEntry::getTopOfStack() {
return &stack.back();
}
-void PyThreadContextEntry::push(FrameKind frameKind, py::object context,
- py::object insertionPoint,
- py::object location) {
+void PyThreadContextEntry::push(FrameKind frameKind, nb::object context,
+ nb::object insertionPoint,
+ nb::object location) {
auto &stack = getStack();
stack.emplace_back(frameKind, std::move(context), std::move(insertionPoint),
std::move(location));
@@ -844,19 +845,19 @@ void PyThreadContextEntry::push(FrameKind frameKind, py::object context,
PyMlirContext *PyThreadContextEntry::getContext() {
if (!context)
return nullptr;
- return py::cast<PyMlirContext *>(context);
+ return nb::cast<PyMlirContext *>(context);
}
PyInsertionPoint *PyThreadContextEntry::getInsertionPoint() {
if (!insertionPoint)
return nullptr;
- return py::cast<PyInsertionPoint *>(insertionPoint);
+ return nb::cast<PyInsertionPoint *>(insertionPoint);
}
PyLocation *PyThreadContextEntry::getLocation() {
if (!location)
return nullptr;
- return py::cast<PyLocation *>(location);
+ return nb::cast<PyLocation *>(location);
}
PyMlirContext *PyThreadContextEntry::getDefaultContext() {
@@ -874,12 +875,11 @@ PyLocation *PyThreadContextEntry::getDefaultLocation() {
return tos ? tos->getLocation() : nullptr;
}
-py::object PyThreadContextEntry::pushContext(PyMlirContext &context) {
- py::object contextObj = py::cast(context);
- push(FrameKind::Context, /*context=*/contextObj,
- /*insertionPoint=*/py::object(),
- /*location=*/py::object());
- return contextObj;
+nb::object PyThreadContextEntry::pushContext(nb::object context) {
+ push(FrameKind::Context, /*context=*/context,
+ /*insertionPoint=*/nb::object(),
+ /*location=*/nb::object());
+ return context;
}
void PyThreadContextEntry::popContext(PyMlirContext &context) {
@@ -892,15 +892,16 @@ void PyThreadContextEntry::popContext(PyMlirContext &context) {
stack.pop_back();
}
-py::object
-PyThreadContextEntry::pushInsertionPoint(PyInsertionPoint &insertionPoint) {
- py::object contextObj =
+nb::object PyThreadContextEntry::pushInsertionPoint(
+ nb::object insertionPointObj) {
+ PyInsertionPoint &insertionPoint =
+ nb::cast<PyInsertionPoint &>(insertionPointObj);
+ nb::object contextObj =
insertionPoint.getBlock().getParentOperation()->getContext().getObject();
- py::object insertionPointObj = py::cast(insertionPoint);
push(FrameKind::InsertionPoint,
/*context=*/contextObj,
/*insertionPoint=*/insertionPointObj,
- /*location=*/py::object());
+ /*location=*/nb::object());
return insertionPointObj;
}
@@ -915,11 +916,11 @@ void PyThreadContextEntry::popInsertionPoint(PyInsertionPoint &insertionPoint) {
stack.pop_back();
}
-py::object PyThreadContextEntry::pushLocation(PyLocation &location) {
- py::object contextObj = location.getContext().getObject();
- py::object locationObj = py::cast(location);
+nb::object PyThreadContextEntry::pushLocation(nb::object locationObj) {
+ PyLocation &location = nb::cast<PyLocation &>(locationObj);
+ nb::object contextObj = location.getContext().getObject();
push(FrameKind::Location, /*context=*/contextObj,
- /*insertionPoint=*/py::object(),
+ /*insertionPoint=*/nb::object(),
/*location=*/locationObj);
return locationObj;
}
@@ -941,15 +942,15 @@ void PyThreadContextEntry::popLocation(PyLocation &location) {
void PyDiagnostic::invalidate() {
valid = false;
if (materializedNotes) {
- for (auto ¬eObject : *materializedNotes) {
- PyDiagnostic *note = py::cast<PyDiagnostic *>(noteObject);
+ for (nb::handle noteObject : *materializedNotes) {
+ PyDiagnostic *note = nb::cast<PyDiagnostic *>(noteObject);
note->invalidate();
}
}
}
PyDiagnosticHandler::PyDiagnosticHandler(MlirContext context,
- py::object callback)
+ nb::object callback)
: context(context), callback(std::move(callback)) {}
PyDiagnosticHandler::~PyDiagnosticHandler() = default;
@@ -984,32 +985,36 @@ PyLocation PyDiagnostic::getLocation() {
return PyLocation(PyMlirContext::forContext(context), loc);
}
-py::str PyDiagnostic::getMessage() {
+nb::str PyDiagnostic::getMessage() {
checkValid();
- py::object fileObject = py::module::import("io").attr("StringIO")();
+ nb::object fileObject = nb::module_::import_("io").attr("StringIO")();
PyFileAccumulator accum(fileObject, /*binary=*/false);
mlirDiagnosticPrint(diagnostic, accum.getCallback(), accum.getUserData());
- return fileObject.attr("getvalue")();
+ return nb::cast<nb::str>(fileObject.attr("getvalue")());
}
-py::tuple PyDiagnostic::getNotes() {
+nb::tuple PyDiagnostic::getNotes() {
checkValid();
if (materializedNotes)
return *materializedNotes;
intptr_t numNotes = mlirDiagnosticGetNumNotes(diagnostic);
- materializedNotes = py::tuple(numNotes);
+ nb::tuple notes = nb::steal<nb::tuple>(PyTuple_New(numNotes));
for (intptr_t i = 0; i < numNotes; ++i) {
MlirDiagnostic noteDiag = mlirDiagnosticGetNote(diagnostic, i);
- (*materializedNotes)[i] = PyDiagnostic(noteDiag);
+ nb::object diagnostic = nb::cast(PyDiagnostic(noteDiag));
+ PyTuple_SET_ITEM(notes.ptr(), i, diagnostic.release().ptr());
}
+ materializedNotes = std::move(notes);
+
return *materializedNotes;
}
PyDiagnostic::DiagnosticInfo PyDiagnostic::getInfo() {
std::vector<DiagnosticInfo> notes;
- for (py::handle n : getNotes())
- notes.emplace_back(n.cast<PyDiagnostic>().getInfo());
- return {getSeverity(), getLocation(), getMessage(), std::move(notes)};
+ for (nb::handle n : getNotes())
+ notes.emplace_back(nb::cast<PyDiagnostic>(n).getInfo());
+ return {getSeverity(), getLocation(), nb::cast<std::string>(getMessage()),
+ std::move(notes)};
}
//------------------------------------------------------------------------------
@@ -1022,23 +1027,20 @@ MlirDialect PyDialects::getDialectForKey(const std::string &key,
{key.data(), key.size()});
if (mlirDialectIsNull(dialect)) {
std::string msg = (Twine("Dialect '") + key + "' not found").str();
- if (attrError)
- throw py::attribute_error(msg);
- throw py::index_error(msg);
+ if (attrError) throw nb::attribute_error(msg.c_str());
+ throw nb::index_error(msg.c_str());
}
return dialect;
}
-py::object PyDialectRegistry::getCapsule() {
- return py::reinterpret_steal<py::object>(
- mlirPythonDialectRegistryToCapsule(*this));
+nb::object PyDialectRegistry::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonDialectRegistryToCapsule(*this));
}
-PyDialectRegistry PyDialectRegistry::createFromCapsule(py::object capsule) {
+PyDialectRegistry PyDialectRegistry::createFromCapsule(nb::object capsule) {
MlirDialectRegistry rawRegistry =
mlirPythonCapsuleToDialectRegistry(capsule.ptr());
- if (mlirDialectRegistryIsNull(rawRegistry))
- throw py::error_already_set();
+ if (mlirDialectRegistryIsNull(rawRegistry)) throw nb::python_error();
return PyDialectRegistry(rawRegistry);
}
@@ -1046,25 +1048,24 @@ PyDialectRegistry PyDialectRegistry::createFromCapsule(py::object capsule) {
// PyLocation
//------------------------------------------------------------------------------
-py::object PyLocation::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonLocationToCapsule(*this));
+nb::object PyLocation::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonLocationToCapsule(*this));
}
-PyLocation PyLocation::createFromCapsule(py::object capsule) {
+PyLocation PyLocation::createFromCapsule(nb::object capsule) {
MlirLocation rawLoc = mlirPythonCapsuleToLocation(capsule.ptr());
- if (mlirLocationIsNull(rawLoc))
- throw py::error_already_set();
+ if (mlirLocationIsNull(rawLoc)) throw nb::python_error();
return PyLocation(PyMlirContext::forContext(mlirLocationGetContext(rawLoc)),
rawLoc);
}
-py::object PyLocation::contextEnter() {
- return PyThreadContextEntry::pushLocation(*this);
+nb::object PyLocation::contextEnter(nb::object locationObj) {
+ return PyThreadContextEntry::pushLocation(locationObj);
}
-void PyLocation::contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb) {
+void PyLocation::contextExit(const nb::object &excType,
+ const nb::object &excVal,
+ const nb::object &excTb) {
PyThreadContextEntry::popLocation(*this);
}
@@ -1087,7 +1088,7 @@ PyModule::PyModule(PyMlirContextRef contextRef, MlirModule module)
: BaseContextObject(std::move(contextRef)), module(module) {}
PyModule::~PyModule() {
- py::gil_scoped_acquire acquire;
+ nb::gil_scoped_acquire acquire;
auto &liveModules = getContext()->liveModules;
assert(liveModules.count(module.ptr) == 1 &&
"destroying module not in live map");
@@ -1099,7 +1100,7 @@ PyModuleRef PyModule::forModule(MlirModule module) {
MlirContext context = mlirModuleGetContext(module);
PyMlirContextRef contextRef = PyMlirContext::forContext(context);
- py::gil_scoped_acquire acquire;
+ nb::gil_scoped_acquire acquire;
auto &liveModules = contextRef->liveModules;
auto it = liveModules.find(module.ptr);
if (it == liveModules.end()) {
@@ -1108,8 +1109,7 @@ PyModuleRef PyModule::forModule(MlirModule module) {
// Note that the default return value policy on cast is automatic_reference,
// which does not take ownership (delete will not be called).
// Just be explicit.
- py::object pyRef =
- py::cast(unownedModule, py::return_value_policy::take_ownership);
+ nb::object pyRef = nb::cast(unownedModule, nb::rv_policy::take_ownership);
unownedModule->handle = pyRef;
liveModules[module.ptr] =
std::make_pair(unownedModule->handle, unownedModule);
@@ -1117,19 +1117,18 @@ PyModuleRef PyModule::forModule(MlirModule module) {
}
// Use existing.
PyModule *existing = it->second.second;
- py::object pyRef = py::reinterpret_borrow<py::object>(it->second.first);
+ nb::object pyRef = nb::borrow<nb::object>(it->second.first);
return PyModuleRef(existing, std::move(pyRef));
}
-py::object PyModule::createFromCapsule(py::object capsule) {
+nb::object PyModule::createFromCapsule(nb::object capsule) {
MlirModule rawModule = mlirPythonCapsuleToModule(capsule.ptr());
- if (mlirModuleIsNull(rawModule))
- throw py::error_already_set();
+ if (mlirModuleIsNull(rawModule)) throw nb::python_error();
return forModule(rawModule).releaseObject();
}
-py::object PyModule::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonModuleToCapsule(get()));
+nb::object PyModule::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonModuleToCapsule(get()));
}
//------------------------------------------------------------------------------
@@ -1158,7 +1157,7 @@ PyOperation::~PyOperation() {
PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
MlirOperation operation,
- py::object parentKeepAlive) {
+ nb::object parentKeepAlive) {
auto &liveOperations = contextRef->liveOperations;
// Create.
PyOperation *unownedOperation =
@@ -1166,8 +1165,7 @@ PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
// Note that the default return value policy on cast is automatic_reference,
// which does not take ownership (delete will not be called).
// Just be explicit.
- py::object pyRef =
- py::cast(unownedOperation, py::return_value_policy::take_ownership);
+ nb::object pyRef = nb::cast(unownedOperation, nb::rv_policy::take_ownership);
unownedOperation->handle = pyRef;
if (parentKeepAlive) {
unownedOperation->parentKeepAlive = std::move(parentKeepAlive);
@@ -1178,7 +1176,7 @@ PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
PyOperationRef PyOperation::forOperation(PyMlirContextRef contextRef,
MlirOperation operation,
- py::object parentKeepAlive) {
+ nb::object parentKeepAlive) {
auto &liveOperations = contextRef->liveOperations;
auto it = liveOperations.find(operation.ptr);
if (it == liveOperations.end()) {
@@ -1188,13 +1186,13 @@ PyOperationRef PyOperation::forOperation(PyMlirContextRef contextRef,
}
// Use existing.
PyOperation *existing = it->second.second;
- py::object pyRef = py::reinterpret_borrow<py::object>(it->second.first);
+ nb::object pyRef = nb::borrow<nb::object>(it->second.first);
return PyOperationRef(existing, std::move(pyRef));
}
PyOperationRef PyOperation::createDetached(PyMlirContextRef contextRef,
MlirOperation operation,
- py::object parentKeepAlive) {
+ nb::object parentKeepAlive) {
auto &liveOperations = contextRef->liveOperations;
assert(liveOperations.count(operation.ptr) == 0 &&
"cannot create detached operation that already exists");
@@ -1227,12 +1225,12 @@ void PyOperation::checkValid() const {
void PyOperationBase::print(std::optional<int64_t> largeElementsLimit,
bool enableDebugInfo, bool prettyDebugInfo,
bool printGenericOpForm, bool useLocalScope,
- bool assumeVerified, py::object fileObject,
+ bool assumeVerified, nb::object fileObject,
bool binary, bool skipRegions) {
PyOperation &operation = getOperation();
operation.checkValid();
if (fileObject.is_none())
- fileObject = py::module::import("sys").attr("stdout");
+ fileObject = nb::module_::import_("sys").attr("stdout");
MlirOpPrintingFlags flags = mlirOpPrintingFlagsCreate();
if (largeElementsLimit)
@@ -1255,18 +1253,18 @@ void PyOperationBase::print(std::optional<int64_t> largeElementsLimit,
mlirOpPrintingFlagsDestroy(flags);
}
-void PyOperationBase::print(PyAsmState &state, py::object fileObject,
+void PyOperationBase::print(PyAsmState &state, nb::object fileObject,
bool binary) {
PyOperation &operation = getOperation();
operation.checkValid();
if (fileObject.is_none())
- fileObject = py::module::import("sys").attr("stdout");
+ fileObject = nb::module_::import_("sys").attr("stdout");
PyFileAccumulator accum(fileObject, binary);
mlirOperationPrintWithState(operation, state.get(), accum.getCallback(),
accum.getUserData());
}
-void PyOperationBase::writeBytecode(const py::object &fileObject,
+void PyOperationBase::writeBytecode(const nb::object &fileObject,
std::optional<int64_t> bytecodeVersion) {
PyOperation &operation = getOperation();
operation.checkValid();
@@ -1282,9 +1280,10 @@ void PyOperationBase::writeBytecode(const py::object &fileObject,
operation, config, accum.getCallback(), accum.getUserData());
mlirBytecodeWriterConfigDestroy(config);
if (mlirLogicalResultIsFailure(res))
- throw py::value_error((Twine("Unable to honor desired bytecode version ") +
+ throw nb::value_error((Twine("Unable to honor desired bytecode version ") +
Twine(*bytecodeVersion))
- .str());
+ .str()
+ .c_str());
}
void PyOperationBase::walk(
@@ -1296,7 +1295,7 @@ void PyOperationBase::walk(
std::function<MlirWalkResult(MlirOperation)> callback;
bool gotException;
std::string exceptionWhat;
- py::object exceptionType;
+ nb::object exceptionType;
};
UserData userData{callback, false, {}, {}};
MlirOperationWalkCallback walkCallback = [](MlirOperation op,
@@ -1304,10 +1303,10 @@ void PyOperationBase::walk(
UserData *calleeUserData = static_cast<UserData *>(userData);
try {
return (calleeUserData->callback)(op);
- } catch (py::error_already_set &e) {
+ } catch (nb::python_error &e) {
calleeUserData->gotException = true;
- calleeUserData->exceptionWhat = e.what();
- calleeUserData->exceptionType = e.type();
+ calleeUserData->exceptionWhat = std::string(e.what());
+ calleeUserData->exceptionType = nb::borrow(e.type());
return MlirWalkResult::MlirWalkResultInterrupt;
}
};
@@ -1319,16 +1318,16 @@ void PyOperationBase::walk(
}
}
-py::object PyOperationBase::getAsm(bool binary,
+nb::object PyOperationBase::getAsm(bool binary,
std::optional<int64_t> largeElementsLimit,
bool enableDebugInfo, bool prettyDebugInfo,
bool printGenericOpForm, bool useLocalScope,
bool assumeVerified, bool skipRegions) {
- py::object fileObject;
+ nb::object fileObject;
if (binary) {
- fileObject = py::module::import("io").attr("BytesIO")();
+ fileObject = nb::module_::import_("io").attr("BytesIO")();
} else {
- fileObject = py::module::import("io").attr("StringIO")();
+ fileObject = nb::module_::import_("io").attr("StringIO")();
}
print(/*largeElementsLimit=*/largeElementsLimit,
/*enableDebugInfo=*/enableDebugInfo,
@@ -1372,7 +1371,7 @@ bool PyOperationBase::verify() {
std::optional<PyOperationRef> PyOperation::getParentOperation() {
checkValid();
if (!isAttached())
- throw py::value_error("Detached operations have no parent");
+ throw nb::value_error("Detached operations have no parent");
MlirOperation operation = mlirOperationGetParentOperation(get());
if (mlirOperationIsNull(operation))
return {};
@@ -1388,57 +1387,54 @@ PyBlock PyOperation::getBlock() {
return PyBlock{std::move(*parentOperation), block};
}
-py::object PyOperation::getCapsule() {
+nb::object PyOperation::getCapsule() {
checkValid();
- return py::reinterpret_steal<py::object>(mlirPythonOperationToCapsule(get()));
+ return nb::steal<nb::object>(mlirPythonOperationToCapsule(get()));
}
-py::object PyOperation::createFromCapsule(py::object capsule) {
+nb::object PyOperation::createFromCapsule(nb::object capsule) {
MlirOperation rawOperation = mlirPythonCapsuleToOperation(capsule.ptr());
- if (mlirOperationIsNull(rawOperation))
- throw py::error_already_set();
+ if (mlirOperationIsNull(rawOperation)) throw nb::python_error();
MlirContext rawCtxt = mlirOperationGetContext(rawOperation);
return forOperation(PyMlirContext::forContext(rawCtxt), rawOperation)
.releaseObject();
}
static void maybeInsertOperation(PyOperationRef &op,
- const py::object &maybeIp) {
+ const nb::object &maybeIp) {
// InsertPoint active?
- if (!maybeIp.is(py::cast(false))) {
+ if (!maybeIp.is(nb::cast(false))) {
PyInsertionPoint *ip;
if (maybeIp.is_none()) {
ip = PyThreadContextEntry::getDefaultInsertionPoint();
} else {
- ip = py::cast<PyInsertionPoint *>(maybeIp);
+ ip = nb::cast<PyInsertionPoint *>(maybeIp);
}
if (ip)
ip->insert(*op.get());
}
}
-py::object PyOperation::create(const std::string &name,
+nb::object PyOperation::create(const std::string &name,
std::optional<std::vector<PyType *>> results,
std::optional<std::vector<PyValue *>> operands,
- std::optional<py::dict> attributes,
+ std::optional<nb::dict> attributes,
std::optional<std::vector<PyBlock *>> successors,
int regions, DefaultingPyLocation location,
- const py::object &maybeIp, bool inferType) {
+ const nb::object &maybeIp, bool inferType) {
llvm::SmallVector<MlirValue, 4> mlirOperands;
llvm::SmallVector<MlirType, 4> mlirResults;
llvm::SmallVector<MlirBlock, 4> mlirSuccessors;
llvm::SmallVector<std::pair<std::string, MlirAttribute>, 4> mlirAttributes;
// General parameter validation.
- if (regions < 0)
- throw py::value_error("number of regions must be >= 0");
+ if (regions < 0) throw nb::value_error("number of regions must be >= 0");
// Unpack/validate operands.
if (operands) {
mlirOperands.reserve(operands->size());
for (PyValue *operand : *operands) {
- if (!operand)
- throw py::value_error("operand value cannot be None");
+ if (!operand) throw nb::value_error("operand value cannot be None");
mlirOperands.push_back(operand->get());
}
}
@@ -1448,39 +1444,38 @@ py::object PyOperation::create(const std::string &name,
mlirResults.reserve(results->size());
for (PyType *result : *results) {
// TODO: Verify result type originate from the same context.
- if (!result)
- throw py::value_error("result type cannot be None");
+ if (!result) throw nb::value_error("result type cannot be None");
mlirResults.push_back(*result);
}
}
// Unpack/validate attributes.
if (attributes) {
mlirAttributes.reserve(attributes->size());
- for (auto &it : *attributes) {
+ for (std::pair<nb::handle, nb::handle> it : *attributes) {
std::string key;
try {
- key = it.first.cast<std::string>();
- } catch (py::cast_error &err) {
+ key = nb::cast<std::string>(it.first);
+ } catch (nb::cast_error &err) {
std::string msg = "Invalid attribute key (not a string) when "
"attempting to create the operation \"" +
name + "\" (" + err.what() + ")";
- throw py::cast_error(msg);
+ throw nb::type_error(msg.c_str());
}
try {
- auto &attribute = it.second.cast<PyAttribute &>();
+ auto &attribute = nb::cast<PyAttribute &>(it.second);
// TODO: Verify attribute originates from the same context.
mlirAttributes.emplace_back(std::move(key), attribute);
- } catch (py::reference_cast_error &) {
+ } catch (nb::cast_error &err) {
+ std::string msg = "Invalid attribute value for the key \"" + key +
+ "\" when attempting to create the operation \"" +
+ name + "\" (" + err.what() + ")";
+ throw nb::type_error(msg.c_str());
+ } catch (std::runtime_error &err) {
// This exception seems thrown when the value is "None".
std::string msg =
"Found an invalid (`None`?) attribute value for the key \"" + key +
"\" when attempting to create the operation \"" + name + "\"";
- throw py::cast_error(msg);
- } catch (py::cast_error &err) {
- std::string msg = "Invalid attribute value for the key \"" + key +
- "\" when attempting to create the operation \"" +
- name + "\" (" + err.what() + ")";
- throw py::cast_error(msg);
+ throw std::runtime_error(msg);
}
}
}
@@ -1489,8 +1484,7 @@ py::object PyOperation::create(const std::string &name,
mlirSuccessors.reserve(successors->size());
for (auto *successor : *successors) {
// TODO: Verify successor originate from the same context.
- if (!successor)
- throw py::value_error("successor block cannot be None");
+ if (!successor) throw nb::value_error("successor block cannot be None");
mlirSuccessors.push_back(successor->get());
}
}
@@ -1534,8 +1528,7 @@ py::object PyOperation::create(const std::string &name,
// Construct the operation.
MlirOperation operation = mlirOperationCreate(&state);
- if (!operation.ptr)
- throw py::value_error("Operation creation failed");
+ if (!operation.ptr) throw nb::value_error("Operation creation failed");
PyOperationRef created =
PyOperation::createDetached(location->getContext(), operation);
maybeInsertOperation(created, maybeIp);
@@ -1543,7 +1536,7 @@ py::object PyOperation::create(const std::string &name,
return created.getObject();
}
-py::object PyOperation::clone(const py::object &maybeIp) {
+nb::object PyOperation::clone(const nb::object &maybeIp) {
MlirOperation clonedOperation = mlirOperationClone(operation);
PyOperationRef cloned =
PyOperation::createDetached(getContext(), clonedOperation);
@@ -1552,15 +1545,15 @@ py::object PyOperation::clone(const py::object &maybeIp) {
return cloned->createOpView();
}
-py::object PyOperation::createOpView() {
+nb::object PyOperation::createOpView() {
checkValid();
MlirIdentifier ident = mlirOperationGetName(get());
MlirStringRef identStr = mlirIdentifierStr(ident);
auto operationCls = PyGlobals::get().lookupOperationClass(
StringRef(identStr.data, identStr.length));
if (operationCls)
- return PyOpView::constructDerived(*operationCls, *getRef().get());
- return py::cast(PyOpView(getRef().getObject()));
+ return PyOpView::constructDerived(*operationCls, getRef().getObject());
+ return nb::cast(PyOpView(getRef().getObject()));
}
void PyOperation::erase() {
@@ -1573,8 +1566,8 @@ void PyOperation::erase() {
// PyOpView
//------------------------------------------------------------------------------
-static void populateResultTypes(StringRef name, py::list resultTypeList,
- const py::object &resultSegmentSpecObj,
+static void populateResultTypes(StringRef name, nb::list resultTypeList,
+ const nb::object &resultSegmentSpecObj,
std::vector<int32_t> &resultSegmentLengths,
std::vector<PyType *> &resultTypes) {
resultTypes.reserve(resultTypeList.size());
@@ -1582,26 +1575,27 @@ static void populateResultTypes(StringRef name, py::list resultTypeList,
// Non-variadic result unpacking.
for (const auto &it : llvm::enumerate(resultTypeList)) {
try {
- resultTypes.push_back(py::cast<PyType *>(it.value()));
- if (!resultTypes.back())
- throw py::cast_error();
- } catch (py::cast_error &err) {
- throw py::value_error((llvm::Twine("Result ") +
+ resultTypes.push_back(nb::cast<PyType *>(it.value()));
+ if (!resultTypes.back()) throw nb::cast_error();
+ } catch (nb::cast_error &err) {
+ throw nb::value_error((llvm::Twine("Result ") +
llvm::Twine(it.index()) + " of operation \"" +
name + "\" must be a Type (" + err.what() + ")")
- .str());
+ .str()
+ .c_str());
}
}
} else {
// Sized result unpacking.
- auto resultSegmentSpec = py::cast<std::vector<int>>(resultSegmentSpecObj);
+ auto resultSegmentSpec = nb::cast<std::vector<int>>(resultSegmentSpecObj);
if (resultSegmentSpec.size() != resultTypeList.size()) {
- throw py::value_error((llvm::Twine("Operation \"") + name +
+ throw nb::value_error((llvm::Twine("Operation \"") + name +
"\" requires " +
llvm::Twine(resultSegmentSpec.size()) +
" result segments but was provided " +
llvm::Twine(resultTypeList.size()))
- .str());
+ .str()
+ .c_str());
}
resultSegmentLengths.reserve(resultTypeList.size());
for (const auto &it :
@@ -1610,7 +1604,7 @@ static void populateResultTypes(StringRef name, py::list resultTypeList,
if (segmentSpec == 1 || segmentSpec == 0) {
// Unpack unary element.
try {
- auto *resultType = py::cast<PyType *>(std::get<0>(it.value()));
+ auto *resultType = nb::cast<PyType *>(std::get<0>(it.value()));
if (resultType) {
resultTypes.push_back(resultType);
resultSegmentLengths.push_back(1);
@@ -1618,14 +1612,20 @@ static void populateResultTypes(StringRef name, py::list resultTypeList,
// Allowed to be optional.
resultSegmentLengths.push_back(0);
} else {
- throw py::cast_error("was None and result is not optional");
+ throw nb::value_error(
+ (llvm::Twine("Result ") + llvm::Twine(it.index()) +
+ " of operation \"" + name +
+ "\" must be a Type (was None and result is not optional)")
+ .str()
+ .c_str());
}
- } catch (py::cast_error &err) {
- throw py::value_error((llvm::Twine("Result ") +
+ } catch (nb::cast_error &err) {
+ throw nb::value_error((llvm::Twine("Result ") +
llvm::Twine(it.index()) + " of operation \"" +
name + "\" must be a Type (" + err.what() +
")")
- .str());
+ .str()
+ .c_str());
}
} else if (segmentSpec == -1) {
// Unpack sequence by appending.
@@ -1635,72 +1635,75 @@ static void populateResultTypes(StringRef name, py::list resultTypeList,
resultSegmentLengths.push_back(0);
} else {
// Unpack the list.
- auto segment = py::cast<py::sequence>(std::get<0>(it.value()));
- for (py::object segmentItem : segment) {
- resultTypes.push_back(py::cast<PyType *>(segmentItem));
+ auto segment = nb::cast<nb::sequence>(std::get<0>(it.value()));
+ for (nb::handle segmentItem : segment) {
+ resultTypes.push_back(nb::cast<PyType *>(segmentItem));
if (!resultTypes.back()) {
- throw py::cast_error("contained a None item");
+ throw nb::type_error("contained a None item");
}
}
- resultSegmentLengths.push_back(segment.size());
+ resultSegmentLengths.push_back(nb::len(segment));
}
} catch (std::exception &err) {
// NOTE: Sloppy to be using a catch-all here, but there are at least
// three different unrelated exceptions that can be thrown in the
// above "casts". Just keep the scope above small and catch them all.
- throw py::value_error((llvm::Twine("Result ") +
+ throw nb::value_error((llvm::Twine("Result ") +
llvm::Twine(it.index()) + " of operation \"" +
name + "\" must be a Sequence of Types (" +
err.what() + ")")
- .str());
+ .str()
+ .c_str());
}
} else {
- throw py::value_error("Unexpected segment spec");
+ throw nb::value_error("Unexpected segment spec");
}
}
}
}
-py::object PyOpView::buildGeneric(
- const py::object &cls, std::optional<py::list> resultTypeList,
- py::list operandList, std::optional<py::dict> attributes,
+nb::object PyOpView::buildGeneric(
+ const nb::object &cls, std::optional<nb::list> resultTypeList,
+ nb::list operandList, std::optional<nb::dict> attributes,
std::optional<std::vector<PyBlock *>> successors,
std::optional<int> regions, DefaultingPyLocation location,
- const py::object &maybeIp) {
+ const nb::object &maybeIp) {
PyMlirContextRef context = location->getContext();
// Class level operation construction metadata.
- std::string name = py::cast<std::string>(cls.attr("OPERATION_NAME"));
+ std::string name = nb::cast<std::string>(cls.attr("OPERATION_NAME"));
// Operand and result segment specs are either none, which does no
// variadic unpacking, or a list of ints with segment sizes, where each
// element is either a positive number (typically 1 for a scalar) or -1 to
// indicate that it is derived from the length of the same-indexed operand
// or result (implying that it is a list at that position).
- py::object operandSegmentSpecObj = cls.attr("_ODS_OPERAND_SEGMENTS");
- py::object resultSegmentSpecObj = cls.attr("_ODS_RESULT_SEGMENTS");
+ nb::object operandSegmentSpecObj = cls.attr("_ODS_OPERAND_SEGMENTS");
+ nb::object resultSegmentSpecObj = cls.attr("_ODS_RESULT_SEGMENTS");
std::vector<int32_t> operandSegmentLengths;
std::vector<int32_t> resultSegmentLengths;
// Validate/determine region count.
- auto opRegionSpec = py::cast<std::tuple<int, bool>>(cls.attr("_ODS_REGIONS"));
+ auto opRegionSpec = nb::cast<std::tuple<int, bool>>(cls.attr("_ODS_REGIONS"));
int opMinRegionCount = std::get<0>(opRegionSpec);
bool opHasNoVariadicRegions = std::get<1>(opRegionSpec);
if (!regions) {
regions = opMinRegionCount;
}
if (*regions < opMinRegionCount) {
- throw py::value_error(
+ throw nb::value_error(
(llvm::Twine("Operation \"") + name + "\" requires a minimum of " +
llvm::Twine(opMinRegionCount) +
" regions but was built with regions=" + llvm::Twine(*regions))
- .str());
+ .str()
+ .c_str());
}
if (opHasNoVariadicRegions && *regions > opMinRegionCount) {
- throw py::value_error(
+ throw nb::value_error(
(llvm::Twine("Operation \"") + name + "\" requires a maximum of " +
llvm::Twine(opMinRegionCount) +
" regions but was built with regions=" + llvm::Twine(*regions))
- .str());
+ .str()
+ .c_str());
}
// Unpack results.
@@ -1717,26 +1720,27 @@ py::object PyOpView::buildGeneric(
// Non-sized operand unpacking.
for (const auto &it : llvm::enumerate(operandList)) {
try {
- operands.push_back(py::cast<PyValue *>(it.value()));
- if (!operands.back())
- throw py::cast_error();
- } catch (py::cast_error &err) {
- throw py::value_error((llvm::Twine("Operand ") +
+ operands.push_back(nb::cast<PyValue *>(it.value()));
+ if (!operands.back()) throw nb::cast_error();
+ } catch (nb::cast_error &err) {
+ throw nb::value_error((llvm::Twine("Operand ") +
llvm::Twine(it.index()) + " of operation \"" +
name + "\" must be a Value (" + err.what() + ")")
- .str());
+ .str()
+ .c_str());
}
}
} else {
// Sized operand unpacking.
- auto operandSegmentSpec = py::cast<std::vector<int>>(operandSegmentSpecObj);
+ auto operandSegmentSpec = nb::cast<std::vector<int>>(operandSegmentSpecObj);
if (operandSegmentSpec.size() != operandList.size()) {
- throw py::value_error((llvm::Twine("Operation \"") + name +
+ throw nb::value_error((llvm::Twine("Operation \"") + name +
"\" requires " +
llvm::Twine(operandSegmentSpec.size()) +
"operand segments but was provided " +
llvm::Twine(operandList.size()))
- .str());
+ .str()
+ .c_str());
}
operandSegmentLengths.reserve(operandList.size());
for (const auto &it :
@@ -1745,7 +1749,7 @@ py::object PyOpView::buildGeneric(
if (segmentSpec == 1 || segmentSpec == 0) {
// Unpack unary element.
try {
- auto *operandValue = py::cast<PyValue *>(std::get<0>(it.value()));
+ auto *operandValue = nb::cast<PyValue *>(std::get<0>(it.value()));
if (operandValue) {
operands.push_back(operandValue);
operandSegmentLengths.push_back(1);
@@ -1753,14 +1757,20 @@ py::object PyOpView::buildGeneric(
// Allowed to be optional.
operandSegmentLengths.push_back(0);
} else {
- throw py::cast_error("was None and operand is not optional");
+ throw nb::value_error(
+ (llvm::Twine("Operand ") + llvm::Twine(it.index()) +
+ " of operation \"" + name +
+ "\" must be a Value (was None and operand is not optional)")
+ .str()
+ .c_str());
}
- } catch (py::cast_error &err) {
- throw py::value_error((llvm::Twine("Operand ") +
+ } catch (nb::cast_error &err) {
+ throw nb::value_error((llvm::Twine("Operand ") +
llvm::Twine(it.index()) + " of operation \"" +
name + "\" must be a Value (" + err.what() +
")")
- .str());
+ .str()
+ .c_str());
}
} else if (segmentSpec == -1) {
// Unpack sequence by appending.
@@ -1770,27 +1780,28 @@ py::object PyOpView::buildGeneric(
operandSegmentLengths.push_back(0);
} else {
// Unpack the list.
- auto segment = py::cast<py::sequence>(std::get<0>(it.value()));
- for (py::object segmentItem : segment) {
- operands.push_back(py::cast<PyValue *>(segmentItem));
+ auto segment = nb::cast<nb::sequence>(std::get<0>(it.value()));
+ for (nb::handle segmentItem : segment) {
+ operands.push_back(nb::cast<PyValue *>(segmentItem));
if (!operands.back()) {
- throw py::cast_error("contained a None item");
+ throw nb::type_error("contained a None item");
}
}
- operandSegmentLengths.push_back(segment.size());
+ operandSegmentLengths.push_back(nb::len(segment));
}
} catch (std::exception &err) {
// NOTE: Sloppy to be using a catch-all here, but there are at least
// three different unrelated exceptions that can be thrown in the
// above "casts". Just keep the scope above small and catch them all.
- throw py::value_error((llvm::Twine("Operand ") +
+ throw nb::value_error((llvm::Twine("Operand ") +
llvm::Twine(it.index()) + " of operation \"" +
name + "\" must be a Sequence of Values (" +
err.what() + ")")
- .str());
+ .str()
+ .c_str());
}
} else {
- throw py::value_error("Unexpected segment spec");
+ throw nb::value_error("Unexpected segment spec");
}
}
}
@@ -1799,15 +1810,16 @@ py::object PyOpView::buildGeneric(
if (!operandSegmentLengths.empty() || !resultSegmentLengths.empty()) {
// Dup.
if (attributes) {
- attributes = py::dict(*attributes);
+ attributes = nb::dict(*attributes);
} else {
- attributes = py::dict();
+ attributes = nb::dict();
}
if (attributes->contains("resultSegmentSizes") ||
attributes->contains("operandSegmentSizes")) {
- throw py::value_error("Manually setting a 'resultSegmentSizes' or "
- "'operandSegmentSizes' attribute is unsupported. "
- "Use Operation.create for such low-level access.");
+ throw nb::value_error(
+ "Manually setting a 'resultSegmentSizes' or "
+ "'operandSegmentSizes' attribute is unsupported. "
+ "Use Operation.create for such low-level access.");
}
// Add resultSegmentSizes attribute.
@@ -1839,21 +1851,18 @@ py::object PyOpView::buildGeneric(
!resultTypeList);
}
-pybind11::object PyOpView::constructDerived(const pybind11::object &cls,
- const PyOperation &operation) {
- // TODO: pybind11 2.6 supports a more direct form.
- // Upgrade many years from now.
- // auto opViewType = py::type::of<PyOpView>();
- py::handle opViewType = py::detail::get_type_handle(typeid(PyOpView), true);
- py::object instance = cls.attr("__new__")(cls);
+nb::object PyOpView::constructDerived(const nb::object &cls,
+ const nb::object &operation) {
+ nb::handle opViewType = nb::type<PyOpView>();
+ nb::object instance = cls.attr("__new__")(cls);
opViewType.attr("__init__")(instance, operation);
return instance;
}
-PyOpView::PyOpView(const py::object &operationObject)
+PyOpView::PyOpView(const nb::object &operationObject)
// Casting through the PyOperationBase base-class and then back to the
// Operation lets us accept any PyOperationBase subclass.
- : operation(py::cast<PyOperationBase &>(operationObject).getOperation()),
+ : operation(nb::cast<PyOperationBase &>(operationObject).getOperation()),
operationObject(operation.getRef().getObject()) {}
//------------------------------------------------------------------------------
@@ -1869,7 +1878,7 @@ PyInsertionPoint::PyInsertionPoint(PyOperationBase &beforeOperationBase)
void PyInsertionPoint::insert(PyOperationBase &operationBase) {
PyOperation &operation = operationBase.getOperation();
if (operation.isAttached())
- throw py::value_error(
+ throw nb::value_error(
"Attempt to insert operation that is already attached");
block.getParentOperation()->checkValid();
MlirOperation beforeOp = {nullptr};
@@ -1882,10 +1891,11 @@ void PyInsertionPoint::insert(PyOperationBase &operationBase) {
// already end in a known terminator (violating this will cause assertion
// failures later).
if (!mlirOperationIsNull(mlirBlockGetTerminator(block.get()))) {
- throw py::index_error("Cannot insert operation at the end of a block "
- "that already has a terminator. Did you mean to "
- "use 'InsertionPoint.at_block_terminator(block)' "
- "versus 'InsertionPoint(block)'?");
+ throw nb::index_error(
+ "Cannot insert operation at the end of a block "
+ "that already has a terminator. Did you mean to "
+ "use 'InsertionPoint.at_block_terminator(block)' "
+ "versus 'InsertionPoint(block)'?");
}
}
mlirBlockInsertOwnedOperationBefore(block.get(), beforeOp, operation);
@@ -1908,19 +1918,19 @@ PyInsertionPoint PyInsertionPoint::atBlockBegin(PyBlock &block) {
PyInsertionPoint PyInsertionPoint::atBlockTerminator(PyBlock &block) {
MlirOperation terminator = mlirBlockGetTerminator(block.get());
if (mlirOperationIsNull(terminator))
- throw py::value_error("Block has no terminator");
+ throw nb::value_error("Block has no terminator");
PyOperationRef terminatorOpRef = PyOperation::forOperation(
block.getParentOperation()->getContext(), terminator);
return PyInsertionPoint{block, std::move(terminatorOpRef)};
}
-py::object PyInsertionPoint::contextEnter() {
- return PyThreadContextEntry::pushInsertionPoint(*this);
+nb::object PyInsertionPoint::contextEnter(nb::object insertPoint) {
+ return PyThreadContextEntry::pushInsertionPoint(insertPoint);
}
-void PyInsertionPoint::contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb) {
+void PyInsertionPoint::contextExit(const nb::object &excType,
+ const nb::object &excVal,
+ const nb::object &excTb) {
PyThreadContextEntry::popInsertionPoint(*this);
}
@@ -1932,14 +1942,13 @@ bool PyAttribute::operator==(const PyAttribute &other) const {
return mlirAttributeEqual(attr, other.attr);
}
-py::object PyAttribute::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonAttributeToCapsule(*this));
+nb::object PyAttribute::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonAttributeToCapsule(*this));
}
-PyAttribute PyAttribute::createFromCapsule(py::object capsule) {
+PyAttribute PyAttribute::createFromCapsule(nb::object capsule) {
MlirAttribute rawAttr = mlirPythonCapsuleToAttribute(capsule.ptr());
- if (mlirAttributeIsNull(rawAttr))
- throw py::error_already_set();
+ if (mlirAttributeIsNull(rawAttr)) throw nb::python_error();
return PyAttribute(
PyMlirContext::forContext(mlirAttributeGetContext(rawAttr)), rawAttr);
}
@@ -1964,14 +1973,13 @@ bool PyType::operator==(const PyType &other) const {
return mlirTypeEqual(type, other.type);
}
-py::object PyType::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(*this));
+nb::object PyType::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonTypeToCapsule(*this));
}
-PyType PyType::createFromCapsule(py::object capsule) {
+PyType PyType::createFromCapsule(nb::object capsule) {
MlirType rawType = mlirPythonCapsuleToType(capsule.ptr());
- if (mlirTypeIsNull(rawType))
- throw py::error_already_set();
+ if (mlirTypeIsNull(rawType)) throw nb::python_error();
return PyType(PyMlirContext::forContext(mlirTypeGetContext(rawType)),
rawType);
}
@@ -1980,14 +1988,13 @@ PyType PyType::createFromCapsule(py::object capsule) {
// PyTypeID.
//------------------------------------------------------------------------------
-py::object PyTypeID::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonTypeIDToCapsule(*this));
+nb::object PyTypeID::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonTypeIDToCapsule(*this));
}
-PyTypeID PyTypeID::createFromCapsule(py::object capsule) {
+PyTypeID PyTypeID::createFromCapsule(nb::object capsule) {
MlirTypeID mlirTypeID = mlirPythonCapsuleToTypeID(capsule.ptr());
- if (mlirTypeIDIsNull(mlirTypeID))
- throw py::error_already_set();
+ if (mlirTypeIDIsNull(mlirTypeID)) throw nb::python_error();
return PyTypeID(mlirTypeID);
}
bool PyTypeID::operator==(const PyTypeID &other) const {
@@ -1998,36 +2005,34 @@ bool PyTypeID::operator==(const PyTypeID &other) const {
// PyValue and subclasses.
//------------------------------------------------------------------------------
-pybind11::object PyValue::getCapsule() {
- return py::reinterpret_steal<py::object>(mlirPythonValueToCapsule(get()));
+nb::object PyValue::getCapsule() {
+ return nb::steal<nb::object>(mlirPythonValueToCapsule(get()));
}
-pybind11::object PyValue::maybeDownCast() {
+nb::object PyValue::maybeDownCast() {
MlirType type = mlirValueGetType(get());
MlirTypeID mlirTypeID = mlirTypeGetTypeID(type);
assert(!mlirTypeIDIsNull(mlirTypeID) &&
"mlirTypeID was expected to be non-null.");
- std::optional<pybind11::function> valueCaster =
+ std::optional<nb::callable> valueCaster =
PyGlobals::get().lookupValueCaster(mlirTypeID, mlirTypeGetDialect(type));
- // py::return_value_policy::move means use std::move to move the return value
+ // nb::rv_policy::move means use std::move to move the return value
// contents into a new instance that will be owned by Python.
- py::object thisObj = py::cast(this, py::return_value_policy::move);
+ nb::object thisObj = nb::cast(this, nb::rv_policy::move);
if (!valueCaster)
return thisObj;
return valueCaster.value()(thisObj);
}
-PyValue PyValue::createFromCapsule(pybind11::object capsule) {
+PyValue PyValue::createFromCapsule(nb::object capsule) {
MlirValue value = mlirPythonCapsuleToValue(capsule.ptr());
- if (mlirValueIsNull(value))
- throw py::error_already_set();
+ if (mlirValueIsNull(value)) throw nb::python_error();
MlirOperation owner;
if (mlirValueIsAOpResult(value))
owner = mlirOpResultGetOwner(value);
if (mlirValueIsABlockArgument(value))
owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(value));
- if (mlirOperationIsNull(owner))
- throw py::error_already_set();
+ if (mlirOperationIsNull(owner)) throw nb::python_error();
MlirContext ctx = mlirOperationGetContext(owner);
PyOperationRef ownerRef =
PyOperation::forOperation(PyMlirContext::forContext(ctx), owner);
@@ -2042,16 +2047,17 @@ PySymbolTable::PySymbolTable(PyOperationBase &operation)
: operation(operation.getOperation().getRef()) {
symbolTable = mlirSymbolTableCreate(operation.getOperation().get());
if (mlirSymbolTableIsNull(symbolTable)) {
- throw py::cast_error("Operation is not a Symbol Table.");
+ throw nb::type_error("Operation is not a Symbol Table.");
}
}
-py::object PySymbolTable::dunderGetItem(const std::string &name) {
+nb::object PySymbolTable::dunderGetItem(const std::string &name) {
operation->checkValid();
MlirOperation symbol = mlirSymbolTableLookup(
symbolTable, mlirStringRefCreate(name.data(), name.length()));
if (mlirOperationIsNull(symbol))
- throw py::key_error("Symbol '" + name + "' not in the symbol table.");
+ throw nb::key_error(
+ ("Symbol '" + name + "' not in the symbol table.").c_str());
return PyOperation::forOperation(operation->getContext(), symbol,
operation.getObject())
@@ -2069,8 +2075,8 @@ void PySymbolTable::erase(PyOperationBase &symbol) {
}
void PySymbolTable::dunderDel(const std::string &name) {
- py::object operation = dunderGetItem(name);
- erase(py::cast<PyOperationBase &>(operation));
+ nb::object operation = dunderGetItem(name);
+ erase(nb::cast<PyOperationBase &>(operation));
}
MlirAttribute PySymbolTable::insert(PyOperationBase &symbol) {
@@ -2079,7 +2085,7 @@ MlirAttribute PySymbolTable::insert(PyOperationBase &symbol) {
MlirAttribute symbolAttr = mlirOperationGetAttributeByName(
symbol.getOperation().get(), mlirSymbolTableGetSymbolAttributeName());
if (mlirAttributeIsNull(symbolAttr))
- throw py::value_error("Expected operation to have a symbol name.");
+ throw nb::value_error("Expected operation to have a symbol name.");
return mlirSymbolTableInsert(symbolTable, symbol.getOperation().get());
}
@@ -2091,7 +2097,7 @@ MlirAttribute PySymbolTable::getSymbolName(PyOperationBase &symbol) {
MlirAttribute existingNameAttr =
mlirOperationGetAttributeByName(operation.get(), attrName);
if (mlirAttributeIsNull(existingNameAttr))
- throw py::value_error("Expected operation to have a symbol name.");
+ throw nb::value_error("Expected operation to have a symbol name.");
return existingNameAttr;
}
@@ -2104,7 +2110,7 @@ void PySymbolTable::setSymbolName(PyOperationBase &symbol,
MlirAttribute existingNameAttr =
mlirOperationGetAttributeByName(operation.get(), attrName);
if (mlirAttributeIsNull(existingNameAttr))
- throw py::value_error("Expected operation to have a symbol name.");
+ throw nb::value_error("Expected operation to have a symbol name.");
MlirAttribute newNameAttr =
mlirStringAttrGet(operation.getContext()->get(), toMlirStringRef(name));
mlirOperationSetAttributeByName(operation.get(), attrName, newNameAttr);
@@ -2117,7 +2123,7 @@ MlirAttribute PySymbolTable::getVisibility(PyOperationBase &symbol) {
MlirAttribute existingVisAttr =
mlirOperationGetAttributeByName(operation.get(), attrName);
if (mlirAttributeIsNull(existingVisAttr))
- throw py::value_error("Expected operation to have a symbol visibility.");
+ throw nb::value_error("Expected operation to have a symbol visibility.");
return existingVisAttr;
}
@@ -2125,7 +2131,7 @@ void PySymbolTable::setVisibility(PyOperationBase &symbol,
const std::string &visibility) {
if (visibility != "public" && visibility != "private" &&
visibility != "nested")
- throw py::value_error(
+ throw nb::value_error(
"Expected visibility to be 'public', 'private' or 'nested'");
PyOperation &operation = symbol.getOperation();
operation.checkValid();
@@ -2133,7 +2139,7 @@ void PySymbolTable::setVisibility(PyOperationBase &symbol,
MlirAttribute existingVisAttr =
mlirOperationGetAttributeByName(operation.get(), attrName);
if (mlirAttributeIsNull(existingVisAttr))
- throw py::value_error("Expected operation to have a symbol visibility.");
+ throw nb::value_error("Expected operation to have a symbol visibility.");
MlirAttribute newVisAttr = mlirStringAttrGet(operation.getContext()->get(),
toMlirStringRef(visibility));
mlirOperationSetAttributeByName(operation.get(), attrName, newVisAttr);
@@ -2148,20 +2154,20 @@ void PySymbolTable::replaceAllSymbolUses(const std::string &oldSymbol,
toMlirStringRef(oldSymbol), toMlirStringRef(newSymbol),
from.getOperation())))
- throw py::value_error("Symbol rename failed");
+ throw nb::value_error("Symbol rename failed");
}
void PySymbolTable::walkSymbolTables(PyOperationBase &from,
bool allSymUsesVisible,
- py::object callback) {
+ nb::object callback) {
PyOperation &fromOperation = from.getOperation();
fromOperation.checkValid();
struct UserData {
PyMlirContextRef context;
- py::object callback;
+ nb::object callback;
bool gotException;
std::string exceptionWhat;
- py::object exceptionType;
+ nb::object exceptionType;
};
UserData userData{
fromOperation.getContext(), std::move(callback), false, {}, {}};
@@ -2175,10 +2181,10 @@ void PySymbolTable::walkSymbolTables(PyOperationBase &from,
return;
try {
calleeUserData->callback(pyFoundOp.getObject(), isVisible);
- } catch (py::error_already_set &e) {
+ } catch (nb::python_error &e) {
calleeUserData->gotException = true;
calleeUserData->exceptionWhat = e.what();
- calleeUserData->exceptionType = e.type();
+ calleeUserData->exceptionType = nb::borrow(e.type());
}
},
static_cast<void *>(&userData));
@@ -2195,12 +2201,12 @@ namespace {
/// to accommodate other levels unless core MLIR changes.
template <typename DerivedTy>
class PyConcreteValue : public PyValue {
-public:
+ public:
// Derived classes must define statics for:
// IsAFunctionTy isaFunction
// const char *pyClassName
// and redefine bindDerived.
- using ClassTy = py::class_<DerivedTy, PyValue>;
+ using ClassTy = nb::class_<DerivedTy, PyValue>;
using IsAFunctionTy = bool (*)(MlirValue);
PyConcreteValue() = default;
@@ -2213,25 +2219,26 @@ class PyConcreteValue : public PyValue {
/// type mismatches.
static MlirValue castFrom(PyValue &orig) {
if (!DerivedTy::isaFunction(orig.get())) {
- auto origRepr = py::repr(py::cast(orig)).cast<std::string>();
- throw py::value_error((Twine("Cannot cast value to ") +
+ auto origRepr = nb::cast<std::string>(nb::repr(nb::cast(orig)));
+ throw nb::value_error((Twine("Cannot cast value to ") +
DerivedTy::pyClassName + " (from " + origRepr +
")")
- .str());
+ .str()
+ .c_str());
}
return orig.get();
}
/// Binds the Python module objects to functions of this class.
- static void bind(py::module &m) {
- auto cls = ClassTy(m, DerivedTy::pyClassName, py::module_local());
- cls.def(py::init<PyValue &>(), py::keep_alive<0, 1>(), py::arg("value"));
+ static void bind(nb::module_ &m) {
+ auto cls = ClassTy(m, DerivedTy::pyClassName);
+ cls.def(nb::init<PyValue &>(), nb::keep_alive<0, 1>(), nb::arg("value"));
cls.def_static(
"isinstance",
[](PyValue &otherValue) -> bool {
return DerivedTy::isaFunction(otherValue);
},
- py::arg("other_value"));
+ nb::arg("other_value"));
cls.def(MLIR_PYTHON_MAYBE_DOWNCAST_ATTR,
[](DerivedTy &self) { return self.maybeDownCast(); });
DerivedTy::bindDerived(cls);
@@ -2249,11 +2256,11 @@ class PyBlockArgument : public PyConcreteValue<PyBlockArgument> {
using PyConcreteValue::PyConcreteValue;
static void bindDerived(ClassTy &c) {
- c.def_property_readonly("owner", [](PyBlockArgument &self) {
+ c.def_prop_ro("owner", [](PyBlockArgument &self) {
return PyBlock(self.getParentOperation(),
mlirBlockArgumentGetOwner(self.get()));
});
- c.def_property_readonly("arg_number", [](PyBlockArgument &self) {
+ c.def_prop_ro("arg_number", [](PyBlockArgument &self) {
return mlirBlockArgumentGetArgNumber(self.get());
});
c.def(
@@ -2261,7 +2268,7 @@ class PyBlockArgument : public PyConcreteValue<PyBlockArgument> {
[](PyBlockArgument &self, PyType type) {
return mlirBlockArgumentSetType(self.get(), type);
},
- py::arg("type"));
+ nb::arg("type"));
}
};
@@ -2273,14 +2280,14 @@ class PyOpResult : public PyConcreteValue<PyOpResult> {
using PyConcreteValue::PyConcreteValue;
static void bindDerived(ClassTy &c) {
- c.def_property_readonly("owner", [](PyOpResult &self) {
+ c.def_prop_ro("owner", [](PyOpResult &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();
});
- c.def_property_readonly("result_number", [](PyOpResult &self) {
+ c.def_prop_ro("result_number", [](PyOpResult &self) {
return mlirOpResultGetResultNumber(self.get());
});
}
@@ -2317,7 +2324,7 @@ class PyBlockArgumentList
operation(std::move(operation)), block(block) {}
static void bindDerived(ClassTy &c) {
- c.def_property_readonly("types", [](PyBlockArgumentList &self) {
+ c.def_prop_ro("types", [](PyBlockArgumentList &self) {
return getValueTypes(self, self.operation->getContext());
});
}
@@ -2422,10 +2429,10 @@ class PyOpResultList : public Sliceable<PyOpResultList, PyOpResult> {
operation(std::move(operation)) {}
static void bindDerived(ClassTy &c) {
- c.def_property_readonly("types", [](PyOpResultList &self) {
+ c.def_prop_ro("types", [](PyOpResultList &self) {
return getValueTypes(self, self.operation->getContext());
});
- c.def_property_readonly("owner", [](PyOpResultList &self) {
+ c.def_prop_ro("owner", [](PyOpResultList &self) {
return self.operation->createOpView();
});
}
@@ -2508,14 +2515,14 @@ class PyOpAttributeMap {
MlirAttribute attr = mlirOperationGetAttributeByName(operation->get(),
toMlirStringRef(name));
if (mlirAttributeIsNull(attr)) {
- throw py::key_error("attempt to access a non-existent attribute");
+ throw nb::key_error("attempt to access a non-existent attribute");
}
return attr;
}
PyNamedAttribute dunderGetItemIndexed(intptr_t index) {
if (index < 0 || index >= dunderLen()) {
- throw py::index_error("attempt to access out of bounds attribute");
+ throw nb::index_error("attempt to access out of bounds attribute");
}
MlirNamedAttribute namedAttr =
mlirOperationGetAttribute(operation->get(), index);
@@ -2534,7 +2541,7 @@ class PyOpAttributeMap {
int removed = mlirOperationRemoveAttributeByName(operation->get(),
toMlirStringRef(name));
if (!removed)
- throw py::key_error("attempt to delete a non-existent attribute");
+ throw nb::key_error("attempt to delete a non-existent attribute");
}
intptr_t dunderLen() {
@@ -2546,8 +2553,8 @@ class PyOpAttributeMap {
operation->get(), toMlirStringRef(name)));
}
- static void bind(py::module &m) {
- py::class_<PyOpAttributeMap>(m, "OpAttributeMap", py::module_local())
+ static void bind(nb::module_ &m) {
+ nb::class_<PyOpAttributeMap>(m, "OpAttributeMap")
.def("__contains__", &PyOpAttributeMap::dunderContains)
.def("__len__", &PyOpAttributeMap::dunderLen)
.def("__getitem__", &PyOpAttributeMap::dunderGetItemNamed)
@@ -2566,21 +2573,21 @@ class PyOpAttributeMap {
// Populates the core exports of the 'ir' submodule.
//------------------------------------------------------------------------------
-void mlir::python::populateIRCore(py::module &m) {
+void mlir::python::populateIRCore(nb::module_ &m) {
//----------------------------------------------------------------------------
// Enums.
//----------------------------------------------------------------------------
- py::enum_<MlirDiagnosticSeverity>(m, "DiagnosticSeverity", py::module_local())
+ nb::enum_<MlirDiagnosticSeverity>(m, "DiagnosticSeverity")
.value("ERROR", MlirDiagnosticError)
.value("WARNING", MlirDiagnosticWarning)
.value("NOTE", MlirDiagnosticNote)
.value("REMARK", MlirDiagnosticRemark);
- py::enum_<MlirWalkOrder>(m, "WalkOrder", py::module_local())
+ nb::enum_<MlirWalkOrder>(m, "WalkOrder")
.value("PRE_ORDER", MlirWalkPreOrder)
.value("POST_ORDER", MlirWalkPostOrder);
- py::enum_<MlirWalkResult>(m, "WalkResult", py::module_local())
+ nb::enum_<MlirWalkResult>(m, "WalkResult")
.value("ADVANCE", MlirWalkResultAdvance)
.value("INTERRUPT", MlirWalkResultInterrupt)
.value("SKIP", MlirWalkResultSkip);
@@ -2588,33 +2595,36 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// 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>";
+ nb::class_<PyDiagnostic>(m, "Diagnostic")
+ .def_prop_ro("severity", &PyDiagnostic::getSeverity)
+ .def_prop_ro("location", &PyDiagnostic::getLocation)
+ .def_prop_ro("message", &PyDiagnostic::getMessage)
+ .def_prop_ro("notes", &PyDiagnostic::getNotes)
+ .def("__str__", [](PyDiagnostic &self) -> nb::str {
+ if (!self.isValid()) return nb::str("<Invalid Diagnostic>");
return self.getMessage();
});
- py::class_<PyDiagnostic::DiagnosticInfo>(m, "DiagnosticInfo",
- py::module_local())
- .def(py::init<>([](PyDiagnostic diag) { return diag.getInfo(); }))
- .def_readonly("severity", &PyDiagnostic::DiagnosticInfo::severity)
- .def_readonly("location", &PyDiagnostic::DiagnosticInfo::location)
- .def_readonly("message", &PyDiagnostic::DiagnosticInfo::message)
- .def_readonly("notes", &PyDiagnostic::DiagnosticInfo::notes)
+ nb::class_<PyDiagnostic::DiagnosticInfo>(m, "DiagnosticInfo")
+ .def("__init__",
+ [](PyDiagnostic::DiagnosticInfo &self, PyDiagnostic diag) {
+ new (&self) PyDiagnostic::DiagnosticInfo(diag.getInfo());
+ })
+ .def_ro("severity", &PyDiagnostic::DiagnosticInfo::severity)
+ .def_ro("location", &PyDiagnostic::DiagnosticInfo::location)
+ .def_ro("message", &PyDiagnostic::DiagnosticInfo::message)
+ .def_ro("notes", &PyDiagnostic::DiagnosticInfo::notes)
.def("__str__",
[](PyDiagnostic::DiagnosticInfo &self) { return self.message; });
- py::class_<PyDiagnosticHandler>(m, "DiagnosticHandler", py::module_local())
+ nb::class_<PyDiagnosticHandler>(m, "DiagnosticHandler")
.def("detach", &PyDiagnosticHandler::detach)
- .def_property_readonly("attached", &PyDiagnosticHandler::isAttached)
- .def_property_readonly("had_error", &PyDiagnosticHandler::getHadError)
+ .def_prop_ro("attached", &PyDiagnosticHandler::isAttached)
+ .def_prop_ro("had_error", &PyDiagnosticHandler::getHadError)
.def("__enter__", &PyDiagnosticHandler::contextEnter)
- .def("__exit__", &PyDiagnosticHandler::contextExit);
+ .def("__exit__", &PyDiagnosticHandler::contextExit,
+ nb::arg("exc_type").none(), nb::arg("exc_value").none(),
+ nb::arg("traceback").none());
//----------------------------------------------------------------------------
// Mapping of MlirContext.
@@ -2622,8 +2632,12 @@ void mlir::python::populateIRCore(py::module &m) {
// __init__.py will subclass it with site-specific functionality and set a
// "Context" attribute on this module.
//----------------------------------------------------------------------------
- py::class_<PyMlirContext>(m, "_BaseContext", py::module_local())
- .def(py::init<>(&PyMlirContext::createNewContextForInit))
+ nb::class_<PyMlirContext>(m, "_BaseContext")
+ .def("__init__",
+ [](PyMlirContext &self) {
+ MlirContext context = mlirContextCreateWithThreading(false);
+ new (&self) PyMlirContext(context);
+ })
.def_static("_get_live_count", &PyMlirContext::getLiveCount)
.def("_get_context_again",
[](PyMlirContext &self) {
@@ -2635,28 +2649,27 @@ void mlir::python::populateIRCore(py::module &m) {
&PyMlirContext::getLiveOperationObjects)
.def("_clear_live_operations", &PyMlirContext::clearLiveOperations)
.def("_clear_live_operations_inside",
- py::overload_cast<MlirOperation>(
+ nb::overload_cast<MlirOperation>(
&PyMlirContext::clearOperationsInside))
.def("_get_live_module_count", &PyMlirContext::getLiveModuleCount)
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyMlirContext::getCapsule)
+ .def_prop_ro(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(
+ .def("__exit__", &PyMlirContext::contextExit, nb::arg("exc_type").none(),
+ nb::arg("exc_value").none(), nb::arg("traceback").none())
+ .def_prop_ro_static(
"current",
- [](py::object & /*class*/) {
+ [](nb::object & /*class*/) {
auto *context = PyThreadContextEntry::getDefaultContext();
- if (!context)
- return py::none().cast<py::object>();
- return py::cast(context);
+ if (!context) return nb::none();
+ return nb::cast(context);
},
"Gets the Context bound to the current thread or raises ValueError")
- .def_property_readonly(
+ .def_prop_ro(
"dialects",
[](PyMlirContext &self) { return PyDialects(self.getRef()); },
"Gets a container for accessing dialects by name")
- .def_property_readonly(
+ .def_prop_ro(
"d", [](PyMlirContext &self) { return PyDialects(self.getRef()); },
"Alias for 'dialect'")
.def(
@@ -2665,14 +2678,14 @@ void mlir::python::populateIRCore(py::module &m) {
MlirDialect dialect = mlirContextGetOrLoadDialect(
self.get(), {name.data(), name.size()});
if (mlirDialectIsNull(dialect)) {
- throw py::value_error(
- (Twine("Dialect '") + name + "' not found").str());
+ throw nb::value_error(
+ (Twine("Dialect '") + name + "' not found").str().c_str());
}
return PyDialectDescriptor(self.getRef(), dialect);
},
- py::arg("dialect_name"),
+ nb::arg("dialect_name"),
"Gets or loads a dialect by name, returning its descriptor object")
- .def_property(
+ .def_prop_rw(
"allow_unregistered_dialects",
[](PyMlirContext &self) -> bool {
return mlirContextGetAllowUnregisteredDialects(self.get());
@@ -2681,32 +2694,32 @@ void mlir::python::populateIRCore(py::module &m) {
mlirContextSetAllowUnregisteredDialects(self.get(), value);
})
.def("attach_diagnostic_handler", &PyMlirContext::attachDiagnosticHandler,
- py::arg("callback"),
+ nb::arg("callback"),
"Attaches a diagnostic handler that will receive callbacks")
.def(
"enable_multithreading",
[](PyMlirContext &self, bool enable) {
mlirContextEnableMultithreading(self.get(), enable);
},
- py::arg("enable"))
+ nb::arg("enable"))
.def(
"is_registered_operation",
[](PyMlirContext &self, std::string &name) {
return mlirContextIsRegisteredOperation(
self.get(), MlirStringRef{name.data(), name.size()});
},
- py::arg("operation_name"))
+ nb::arg("operation_name"))
.def(
"append_dialect_registry",
[](PyMlirContext &self, PyDialectRegistry ®istry) {
mlirContextAppendDialectRegistry(self.get(), registry);
},
- py::arg("registry"))
- .def_property("emit_error_diagnostics", nullptr,
- &PyMlirContext::setEmitErrorDiagnostics,
- "Emit error diagnostics to diagnostic handlers. By default "
- "error diagnostics are captured and reported through "
- "MLIRError exceptions.")
+ nb::arg("registry"))
+ .def_prop_rw("emit_error_diagnostics", nullptr,
+ &PyMlirContext::setEmitErrorDiagnostics,
+ "Emit error diagnostics to diagnostic handlers. By default "
+ "error diagnostics are captured and reported through "
+ "MLIRError exceptions.")
.def("load_all_available_dialects", [](PyMlirContext &self) {
mlirContextLoadAllAvailableDialects(self.get());
});
@@ -2714,13 +2727,12 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// 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);
- })
+ nb::class_<PyDialectDescriptor>(m, "DialectDescriptor")
+ .def_prop_ro("namespace",
+ [](PyDialectDescriptor &self) {
+ MlirStringRef ns = mlirDialectGetNamespace(self.get());
+ return nb::str(ns.data, ns.length);
+ })
.def("__repr__", [](PyDialectDescriptor &self) {
MlirStringRef ns = mlirDialectGetNamespace(self.get());
std::string repr("<DialectDescriptor ");
@@ -2732,66 +2744,65 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// Mapping of PyDialects
//----------------------------------------------------------------------------
- py::class_<PyDialects>(m, "Dialects", py::module_local())
+ nb::class_<PyDialects>(m, "Dialects")
.def("__getitem__",
[=](PyDialects &self, std::string keyName) {
MlirDialect dialect =
self.getDialectForKey(keyName, /*attrError=*/false);
- py::object descriptor =
- py::cast(PyDialectDescriptor{self.getContext(), dialect});
+ nb::object descriptor =
+ nb::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});
+ nb::object descriptor =
+ nb::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) {
+ nb::class_<PyDialect>(m, "Dialect")
+ .def(nb::init<nb::object>(), nb::arg("descriptor"))
+ .def_prop_ro("descriptor",
+ [](PyDialect &self) { return self.getDescriptor(); })
+ .def("__repr__", [](nb::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(")>");
+ return nb::str("<Dialect ") +
+ self.attr("descriptor").attr("namespace") + nb::str(" (class ") +
+ clazz.attr("__module__") + nb::str(".") +
+ clazz.attr("__name__") + nb::str(")>");
});
//----------------------------------------------------------------------------
// Mapping of PyDialectRegistry
//----------------------------------------------------------------------------
- py::class_<PyDialectRegistry>(m, "DialectRegistry", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyDialectRegistry::getCapsule)
+ nb::class_<PyDialectRegistry>(m, "DialectRegistry")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyDialectRegistry::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyDialectRegistry::createFromCapsule)
- .def(py::init<>());
+ .def(nb::init<>());
//----------------------------------------------------------------------------
// Mapping of Location
//----------------------------------------------------------------------------
- py::class_<PyLocation>(m, "Location", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule)
+ nb::class_<PyLocation>(m, "Location")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyLocation::createFromCapsule)
.def("__enter__", &PyLocation::contextEnter)
- .def("__exit__", &PyLocation::contextExit)
+ .def("__exit__", &PyLocation::contextExit, nb::arg("exc_type").none(),
+ nb::arg("exc_value").none(), nb::arg("traceback").none())
.def("__eq__",
[](PyLocation &self, PyLocation &other) -> bool {
return mlirLocationEqual(self, other);
})
- .def("__eq__", [](PyLocation &self, py::object other) { return false; })
- .def_property_readonly_static(
+ .def("__eq__", [](PyLocation &self, nb::object other) { return false; })
+ .def_prop_ro_static(
"current",
- [](py::object & /*class*/) {
+ [](nb::object & /*class*/) {
auto *loc = PyThreadContextEntry::getDefaultLocation();
- if (!loc)
- throw py::value_error("No current Location");
+ if (!loc) throw nb::value_error("No current Location");
return loc;
},
"Gets the Location bound to the current thread or raises ValueError")
@@ -2801,14 +2812,14 @@ void mlir::python::populateIRCore(py::module &m) {
return PyLocation(context->getRef(),
mlirLocationUnknownGet(context->get()));
},
- py::arg("context") = py::none(),
+ nb::arg("context").none() = nb::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");
+ throw nb::value_error("No caller frames provided");
MlirLocation caller = frames.back().get();
for (const PyLocation &frame :
llvm::reverse(llvm::ArrayRef(frames).drop_back()))
@@ -2816,7 +2827,8 @@ void mlir::python::populateIRCore(py::module &m) {
return PyLocation(context->getRef(),
mlirLocationCallSiteGet(callee.get(), caller));
},
- py::arg("callee"), py::arg("frames"), py::arg("context") = py::none(),
+ nb::arg("callee"), nb::arg("frames"),
+ nb::arg("context").none() = nb::none(),
kContextGetCallSiteLocationDocstring)
.def_static(
"file",
@@ -2827,8 +2839,9 @@ void mlir::python::populateIRCore(py::module &m) {
mlirLocationFileLineColGet(
context->get(), toMlirStringRef(filename), line, col));
},
- py::arg("filename"), py::arg("line"), py::arg("col"),
- py::arg("context") = py::none(), kContextGetFileLocationDocstring)
+ nb::arg("filename"), nb::arg("line"), nb::arg("col"),
+ nb::arg("context").none() = nb::none(),
+ kContextGetFileLocationDocstring)
.def_static(
"fused",
[](const std::vector<PyLocation> &pyLocations,
@@ -2843,8 +2856,9 @@ void mlir::python::populateIRCore(py::module &m) {
metadata ? metadata->get() : MlirAttribute{0});
return PyLocation(context->getRef(), location);
},
- py::arg("locations"), py::arg("metadata") = py::none(),
- py::arg("context") = py::none(), kContextGetFusedLocationDocstring)
+ nb::arg("locations"), nb::arg("metadata").none() = nb::none(),
+ nb::arg("context").none() = nb::none(),
+ kContextGetFusedLocationDocstring)
.def_static(
"name",
[](std::string name, std::optional<PyLocation> childLoc,
@@ -2856,21 +2870,22 @@ void mlir::python::populateIRCore(py::module &m) {
childLoc ? childLoc->get()
: mlirLocationUnknownGet(context->get())));
},
- py::arg("name"), py::arg("childLoc") = py::none(),
- py::arg("context") = py::none(), kContextGetNameLocationDocString)
+ nb::arg("name"), nb::arg("childLoc").none() = nb::none(),
+ nb::arg("context").none() = nb::none(),
+ kContextGetNameLocationDocString)
.def_static(
"from_attr",
[](PyAttribute &attribute, DefaultingPyMlirContext context) {
return PyLocation(context->getRef(),
mlirLocationFromAttribute(attribute));
},
- py::arg("attribute"), py::arg("context") = py::none(),
+ nb::arg("attribute"), nb::arg("context").none() = nb::none(),
"Gets a Location from a LocationAttr")
- .def_property_readonly(
+ .def_prop_ro(
"context",
[](PyLocation &self) { return self.getContext().getObject(); },
"Context that owns the Location")
- .def_property_readonly(
+ .def_prop_ro(
"attr",
[](PyLocation &self) { return mlirLocationGetAttribute(self); },
"Get the underlying LocationAttr")
@@ -2879,7 +2894,7 @@ void mlir::python::populateIRCore(py::module &m) {
[](PyLocation &self, std::string message) {
mlirEmitError(self, message.c_str());
},
- py::arg("message"), "Emits an error at this location")
+ nb::arg("message"), "Emits an error at this location")
.def("__repr__", [](PyLocation &self) {
PyPrintAccumulator printAccum;
mlirLocationPrint(self, printAccum.getCallback(),
@@ -2890,8 +2905,8 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// Mapping of Module
//----------------------------------------------------------------------------
- py::class_<PyModule>(m, "Module", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule)
+ nb::class_<PyModule>(m, "Module", nb::is_weak_referenceable())
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyModule::createFromCapsule)
.def_static(
"parse",
@@ -2903,7 +2918,19 @@ void mlir::python::populateIRCore(py::module &m) {
throw MLIRError("Unable to parse module assembly", errors.take());
return PyModule::forModule(module).releaseObject();
},
- py::arg("asm"), py::arg("context") = py::none(),
+ nb::arg("asm"), nb::arg("context").none() = nb::none(),
+ kModuleParseDocstring)
+ .def_static(
+ "parse",
+ [](nb::bytes moduleAsm, DefaultingPyMlirContext context) {
+ PyMlirContext::ErrorCapture errors(context->getRef());
+ MlirModule module = mlirModuleCreateParse(
+ context->get(), toMlirStringRef(moduleAsm));
+ if (mlirModuleIsNull(module))
+ throw MLIRError("Unable to parse module assembly", errors.take());
+ return PyModule::forModule(module).releaseObject();
+ },
+ nb::arg("asm"), nb::arg("context").none() = nb::none(),
kModuleParseDocstring)
.def_static(
"create",
@@ -2911,12 +2938,12 @@ void mlir::python::populateIRCore(py::module &m) {
MlirModule module = mlirModuleCreateEmpty(loc);
return PyModule::forModule(module).releaseObject();
},
- py::arg("loc") = py::none(), "Creates an empty module")
- .def_property_readonly(
+ nb::arg("loc").none() = nb::none(), "Creates an empty module")
+ .def_prop_ro(
"context",
[](PyModule &self) { return self.getContext().getObject(); },
"Context that created the Module")
- .def_property_readonly(
+ .def_prop_ro(
"operation",
[](PyModule &self) {
return PyOperation::forOperation(self.getContext(),
@@ -2925,7 +2952,7 @@ void mlir::python::populateIRCore(py::module &m) {
.releaseObject();
},
"Accesses the module as an operation")
- .def_property_readonly(
+ .def_prop_ro(
"body",
[](PyModule &self) {
PyOperationRef moduleOp = PyOperation::forOperation(
@@ -2943,7 +2970,7 @@ void mlir::python::populateIRCore(py::module &m) {
kDumpDocstring)
.def(
"__str__",
- [](py::object self) {
+ [](nb::object self) {
// Defer to the operation's __str__.
return self.attr("operation").attr("__str__")();
},
@@ -2952,27 +2979,26 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// 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();
- })
+ nb::class_<PyOperationBase>(m, "_OperationBase")
+ .def_prop_ro(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; })
+ [](PyOperationBase &self, nb::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(
+ .def_prop_ro("attributes",
+ [](PyOperationBase &self) {
+ return PyOpAttributeMap(self.getOperation().getRef());
+ })
+ .def_prop_ro(
"context",
[](PyOperationBase &self) {
PyOperation &concreteOperation = self.getOperation();
@@ -2980,46 +3006,44 @@ void mlir::python::populateIRCore(py::module &m) {
return concreteOperation.getContext().getObject();
},
"Context that owns the Operation")
- .def_property_readonly("name",
- [](PyOperationBase &self) {
- auto &concreteOperation = self.getOperation();
- concreteOperation.checkValid();
- MlirOperation operation =
- concreteOperation.get();
- MlirStringRef name = mlirIdentifierStr(
- mlirOperationGetName(operation));
- return py::str(name.data, name.length);
- })
- .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(
+ .def_prop_ro("name",
+ [](PyOperationBase &self) {
+ auto &concreteOperation = self.getOperation();
+ concreteOperation.checkValid();
+ MlirOperation operation = concreteOperation.get();
+ MlirStringRef name =
+ mlirIdentifierStr(mlirOperationGetName(operation));
+ return nb::str(name.data, name.length);
+ })
+ .def_prop_ro("operands",
+ [](PyOperationBase &self) {
+ return PyOpOperandList(self.getOperation().getRef());
+ })
+ .def_prop_ro("regions",
+ [](PyOperationBase &self) {
+ return PyRegionList(self.getOperation().getRef());
+ })
+ .def_prop_ro(
"results",
[](PyOperationBase &self) {
return PyOpResultList(self.getOperation().getRef());
},
"Returns the list of Operation results.")
- .def_property_readonly(
+ .def_prop_ro(
"result",
[](PyOperationBase &self) {
auto &operation = self.getOperation();
auto numResults = mlirOperationGetNumResults(operation);
if (numResults != 1) {
auto name = mlirIdentifierStr(mlirOperationGetName(operation));
- throw py::value_error(
+ throw nb::value_error(
(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)")
- .str());
+ .str()
+ .c_str());
}
return PyOpResult(operation.getRef(),
mlirOperationGetResult(operation, 0))
@@ -3027,7 +3051,7 @@ void mlir::python::populateIRCore(py::module &m) {
},
"Shortcut to get an op result if it has only one (throws an error "
"otherwise).")
- .def_property_readonly(
+ .def_prop_ro(
"location",
[](PyOperationBase &self) {
PyOperation &operation = self.getOperation();
@@ -3036,14 +3060,12 @@ void mlir::python::populateIRCore(py::module &m) {
},
"Returns the source location the operation was defined or derived "
"from.")
- .def_property_readonly("parent",
- [](PyOperationBase &self) -> py::object {
- auto parent =
- self.getOperation().getParentOperation();
- if (parent)
- return parent->getObject();
- return py::none();
- })
+ .def_prop_ro("parent",
+ [](PyOperationBase &self) -> nb::object {
+ auto parent = self.getOperation().getParentOperation();
+ if (parent) return parent->getObject();
+ return nb::none();
+ })
.def(
"__str__",
[](PyOperationBase &self) {
@@ -3058,75 +3080,76 @@ void mlir::python::populateIRCore(py::module &m) {
},
"Returns the assembly form of the operation.")
.def("print",
- py::overload_cast<PyAsmState &, pybind11::object, bool>(
+ nb::overload_cast<PyAsmState &, nb::object, bool>(
&PyOperationBase::print),
- py::arg("state"), py::arg("file") = py::none(),
- py::arg("binary") = false, kOperationPrintStateDocstring)
+ nb::arg("state"), nb::arg("file").none() = nb::none(),
+ nb::arg("binary") = false, kOperationPrintStateDocstring)
.def("print",
- py::overload_cast<std::optional<int64_t>, bool, bool, bool, bool,
- bool, py::object, bool, bool>(
+ nb::overload_cast<std::optional<int64_t>, bool, bool, bool, bool,
+ bool, nb::object, bool, bool>(
&PyOperationBase::print),
// Careful: Lots of arguments must match up with print method.
- 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, py::arg("file") = py::none(),
- py::arg("binary") = false, py::arg("skip_regions") = false,
- kOperationPrintDocstring)
- .def("write_bytecode", &PyOperationBase::writeBytecode, py::arg("file"),
- py::arg("desired_version") = py::none(),
+ nb::arg("large_elements_limit").none() = nb::none(),
+ nb::arg("enable_debug_info") = false,
+ nb::arg("pretty_debug_info") = false,
+ nb::arg("print_generic_op_form") = false,
+ nb::arg("use_local_scope") = false,
+ nb::arg("assume_verified") = false,
+ nb::arg("file").none() = nb::none(), nb::arg("binary") = false,
+ nb::arg("skip_regions") = false, kOperationPrintDocstring)
+ .def("write_bytecode", &PyOperationBase::writeBytecode, nb::arg("file"),
+ nb::arg("desired_version").none() = nb::none(),
kOperationPrintBytecodeDocstring)
.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, py::arg("skip_regions") = false,
+ nb::arg("binary") = false,
+ nb::arg("large_elements_limit").none() = nb::none(),
+ nb::arg("enable_debug_info") = false,
+ nb::arg("pretty_debug_info") = false,
+ nb::arg("print_generic_op_form") = false,
+ nb::arg("use_local_scope") = false,
+ nb::arg("assume_verified") = false, nb::arg("skip_regions") = false,
kOperationGetAsmDocstring)
.def("verify", &PyOperationBase::verify,
"Verify the operation. Raises MLIRError if verification fails, and "
"returns true otherwise.")
- .def("move_after", &PyOperationBase::moveAfter, py::arg("other"),
+ .def("move_after", &PyOperationBase::moveAfter, nb::arg("other"),
"Puts self immediately after the other operation in its parent "
"block.")
- .def("move_before", &PyOperationBase::moveBefore, py::arg("other"),
+ .def("move_before", &PyOperationBase::moveBefore, nb::arg("other"),
"Puts self immediately before the other operation in its parent "
"block.")
.def(
"clone",
- [](PyOperationBase &self, py::object ip) {
+ [](PyOperationBase &self, nb::object ip) {
return self.getOperation().clone(ip);
},
- py::arg("ip") = py::none())
+ nb::arg("ip").none() = nb::none())
.def(
"detach_from_parent",
[](PyOperationBase &self) {
PyOperation &operation = self.getOperation();
operation.checkValid();
if (!operation.isAttached())
- throw py::value_error("Detached operation has no parent.");
+ throw nb::value_error("Detached operation has no parent.");
operation.detachFromParent();
return operation.createOpView();
},
"Detaches the operation from its parent block.")
.def("erase", [](PyOperationBase &self) { self.getOperation().erase(); })
- .def("walk", &PyOperationBase::walk, py::arg("callback"),
- py::arg("walk_order") = MlirWalkPostOrder);
-
- 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(),
- py::arg("infer_type") = false, kOperationCreateDocstring)
+ .def("walk", &PyOperationBase::walk, nb::arg("callback"),
+ nb::arg("walk_order") = MlirWalkPostOrder);
+
+ nb::class_<PyOperation, PyOperationBase>(m, "Operation")
+ .def_static("create", &PyOperation::create, nb::arg("name"),
+ nb::arg("results").none() = nb::none(),
+ nb::arg("operands").none() = nb::none(),
+ nb::arg("attributes").none() = nb::none(),
+ nb::arg("successors").none() = nb::none(),
+ nb::arg("regions") = 0, nb::arg("loc").none() = nb::none(),
+ nb::arg("ip").none() = nb::none(),
+ nb::arg("infer_type") = false, kOperationCreateDocstring)
.def_static(
"parse",
[](const std::string &sourceStr, const std::string &sourceName,
@@ -3134,16 +3157,15 @@ void mlir::python::populateIRCore(py::module &m) {
return PyOperation::parse(context->getRef(), sourceStr, sourceName)
->createOpView();
},
- py::arg("source"), py::kw_only(), py::arg("source_name") = "",
- py::arg("context") = py::none(),
+ nb::arg("source"), nb::kw_only(), nb::arg("source_name") = "",
+ nb::arg("context").none() = nb::none(),
"Parses an operation. Supports both text assembly format and binary "
"bytecode format.")
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyOperation::getCapsule)
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyOperation::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyOperation::createFromCapsule)
- .def_property_readonly("operation", [](py::object self) { return self; })
- .def_property_readonly("opview", &PyOperation::createOpView)
- .def_property_readonly(
+ .def_prop_ro("operation", [](nb::object self) { return self; })
+ .def_prop_ro("opview", &PyOperation::createOpView)
+ .def_prop_ro(
"successors",
[](PyOperationBase &self) {
return PyOpSuccessors(self.getOperation().getRef());
@@ -3151,30 +3173,33 @@ void mlir::python::populateIRCore(py::module &m) {
"Returns the list of Operation successors.");
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("opview", [](py::object self) { return self; })
+ nb::class_<PyOpView, PyOperationBase>(m, "OpView")
+ .def(nb::init<nb::object>(), nb::arg("operation"))
+ .def_prop_ro("operation", &PyOpView::getOperationObject)
+ .def_prop_ro("opview", [](nb::object self) { return self; })
.def(
"__str__",
- [](PyOpView &self) { return py::str(self.getOperationObject()); })
- .def_property_readonly(
+ [](PyOpView &self) { return nb::str(self.getOperationObject()); })
+ .def_prop_ro(
"successors",
[](PyOperationBase &self) {
return PyOpSuccessors(self.getOperation().getRef());
},
"Returns the list of Operation successors.");
- 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("_ODS_REGIONS") = nb::make_tuple(0, true);
+ opViewClass.attr("_ODS_OPERAND_SEGMENTS") = nb::none();
+ opViewClass.attr("_ODS_RESULT_SEGMENTS") = nb::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(),
+ &PyOpView::buildGeneric, nb::arg("cls"),
+ nb::arg("results").none() = nb::none(),
+ nb::arg("operands").none() = nb::none(),
+ nb::arg("attributes").none() = nb::none(),
+ nb::arg("successors").none() = nb::none(),
+ nb::arg("regions").none() = nb::none(),
+ nb::arg("loc").none() = nb::none(), nb::arg("ip").none() = nb::none(),
"Builds a specific, generated OpView based on class level attributes.");
opViewClass.attr("parse") = classmethod(
- [](const py::object &cls, const std::string &sourceStr,
+ [](const nb::object &cls, const std::string &sourceStr,
const std::string &sourceName, DefaultingPyMlirContext context) {
PyOperationRef parsed =
PyOperation::parse(context->getRef(), sourceStr, sourceName);
@@ -3185,30 +3210,30 @@ void mlir::python::populateIRCore(py::module &m) {
// `OpView` subclasses, and is not intended to be used on `OpView`
// directly.
std::string clsOpName =
- py::cast<std::string>(cls.attr("OPERATION_NAME"));
+ nb::cast<std::string>(cls.attr("OPERATION_NAME"));
MlirStringRef identifier =
mlirIdentifierStr(mlirOperationGetName(*parsed.get()));
std::string_view parsedOpName(identifier.data, identifier.length);
if (clsOpName != parsedOpName)
throw MLIRError(Twine("Expected a '") + clsOpName + "' op, got: '" +
parsedOpName + "'");
- return PyOpView::constructDerived(cls, *parsed.get());
+ return PyOpView::constructDerived(cls, parsed.getObject());
},
- py::arg("cls"), py::arg("source"), py::kw_only(),
- py::arg("source_name") = "", py::arg("context") = py::none(),
+ nb::arg("cls"), nb::arg("source"), nb::kw_only(),
+ nb::arg("source_name") = "", nb::arg("context").none() = nb::none(),
"Parses a specific, generated OpView based on class level attributes");
//----------------------------------------------------------------------------
// Mapping of PyRegion.
//----------------------------------------------------------------------------
- py::class_<PyRegion>(m, "Region", py::module_local())
- .def_property_readonly(
+ nb::class_<PyRegion>(m, "Region")
+ .def_prop_ro(
"blocks",
[](PyRegion &self) {
return PyBlockList(self.getParentOperation(), self.get());
},
"Returns a forward-optimized sequence of blocks.")
- .def_property_readonly(
+ .def_prop_ro(
"owner",
[](PyRegion &self) {
return self.getParentOperation()->createOpView();
@@ -3226,27 +3251,27 @@ void mlir::python::populateIRCore(py::module &m) {
[](PyRegion &self, PyRegion &other) {
return self.get().ptr == other.get().ptr;
})
- .def("__eq__", [](PyRegion &self, py::object &other) { return false; });
+ .def("__eq__", [](PyRegion &self, nb::object &other) { return false; });
//----------------------------------------------------------------------------
// Mapping of PyBlock.
//----------------------------------------------------------------------------
- py::class_<PyBlock>(m, "Block", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyBlock::getCapsule)
- .def_property_readonly(
+ nb::class_<PyBlock>(m, "Block")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyBlock::getCapsule)
+ .def_prop_ro(
"owner",
[](PyBlock &self) {
return self.getParentOperation()->createOpView();
},
"Returns the owning operation of this block.")
- .def_property_readonly(
+ .def_prop_ro(
"region",
[](PyBlock &self) {
MlirRegion region = mlirBlockGetParentRegion(self.get());
return PyRegion(self.getParentOperation(), region);
},
"Returns the owning region of this block.")
- .def_property_readonly(
+ .def_prop_ro(
"arguments",
[](PyBlock &self) {
return PyBlockArgumentList(self.getParentOperation(), self.get());
@@ -3265,7 +3290,7 @@ void mlir::python::populateIRCore(py::module &m) {
return mlirBlockEraseArgument(self.get(), index);
},
"Erase the argument at 'index' and remove it from the argument list.")
- .def_property_readonly(
+ .def_prop_ro(
"operations",
[](PyBlock &self) {
return PyOperationList(self.getParentOperation(), self.get());
@@ -3273,15 +3298,15 @@ void mlir::python::populateIRCore(py::module &m) {
"Returns a forward-optimized sequence of operations.")
.def_static(
"create_at_start",
- [](PyRegion &parent, const py::list &pyArgTypes,
- const std::optional<py::sequence> &pyArgLocs) {
+ [](PyRegion &parent, const nb::sequence &pyArgTypes,
+ const std::optional<nb::sequence> &pyArgLocs) {
parent.checkValid();
MlirBlock block = createBlock(pyArgTypes, pyArgLocs);
mlirRegionInsertOwnedBlock(parent, 0, block);
return PyBlock(parent.getParentOperation(), block);
},
- py::arg("parent"), py::arg("arg_types") = py::list(),
- py::arg("arg_locs") = std::nullopt,
+ nb::arg("parent"), nb::arg("arg_types") = nb::list(),
+ nb::arg("arg_locs") = std::nullopt,
"Creates and returns a new Block at the beginning of the given "
"region (with given argument types and locations).")
.def(
@@ -3295,28 +3320,32 @@ void mlir::python::populateIRCore(py::module &m) {
"Append this block to a region, transferring ownership if necessary")
.def(
"create_before",
- [](PyBlock &self, const py::args &pyArgTypes,
- const std::optional<py::sequence> &pyArgLocs) {
+ [](PyBlock &self, const nb::args &pyArgTypes,
+ const std::optional<nb::sequence> &pyArgLocs) {
self.checkValid();
- MlirBlock block = createBlock(pyArgTypes, pyArgLocs);
+ MlirBlock block =
+ createBlock(nb::cast<nb::sequence>(pyArgTypes), pyArgLocs);
MlirRegion region = mlirBlockGetParentRegion(self.get());
mlirRegionInsertOwnedBlockBefore(region, self.get(), block);
return PyBlock(self.getParentOperation(), block);
},
- py::arg("arg_locs") = std::nullopt,
+ nb::arg("arg_types"), nb::kw_only(),
+ nb::arg("arg_locs") = std::nullopt,
"Creates and returns a new Block before this block "
"(with given argument types and locations).")
.def(
"create_after",
- [](PyBlock &self, const py::args &pyArgTypes,
- const std::optional<py::sequence> &pyArgLocs) {
+ [](PyBlock &self, const nb::args &pyArgTypes,
+ const std::optional<nb::sequence> &pyArgLocs) {
self.checkValid();
- MlirBlock block = createBlock(pyArgTypes, pyArgLocs);
+ MlirBlock block =
+ createBlock(nb::cast<nb::sequence>(pyArgTypes), pyArgLocs);
MlirRegion region = mlirBlockGetParentRegion(self.get());
mlirRegionInsertOwnedBlockAfter(region, self.get(), block);
return PyBlock(self.getParentOperation(), block);
},
- py::arg("arg_locs") = std::nullopt,
+ nb::arg("arg_types"), nb::kw_only(),
+ nb::arg("arg_locs") = std::nullopt,
"Creates and returns a new Block after this block "
"(with given argument types and locations).")
.def(
@@ -3333,7 +3362,7 @@ void mlir::python::populateIRCore(py::module &m) {
[](PyBlock &self, PyBlock &other) {
return self.get().ptr == other.get().ptr;
})
- .def("__eq__", [](PyBlock &self, py::object &other) { return false; })
+ .def("__eq__", [](PyBlock &self, nb::object &other) { return false; })
.def("__hash__",
[](PyBlock &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
@@ -3359,7 +3388,7 @@ void mlir::python::populateIRCore(py::module &m) {
operation.getOperation().setAttached(
self.getParentOperation().getObject());
},
- py::arg("operation"),
+ nb::arg("operation"),
"Appends an operation to this block. If the operation is currently "
"in another block, it will be moved.");
@@ -3367,39 +3396,40 @@ void mlir::python::populateIRCore(py::module &m) {
// Mapping of PyInsertionPoint.
//----------------------------------------------------------------------------
- py::class_<PyInsertionPoint>(m, "InsertionPoint", py::module_local())
- .def(py::init<PyBlock &>(), py::arg("block"),
+ nb::class_<PyInsertionPoint>(m, "InsertionPoint")
+ .def(nb::init<PyBlock &>(), nb::arg("block"),
"Inserts after the last operation but still inside the block.")
.def("__enter__", &PyInsertionPoint::contextEnter)
- .def("__exit__", &PyInsertionPoint::contextExit)
- .def_property_readonly_static(
+ .def("__exit__", &PyInsertionPoint::contextExit,
+ nb::arg("exc_type").none(), nb::arg("exc_value").none(),
+ nb::arg("traceback").none())
+ .def_prop_ro_static(
"current",
- [](py::object & /*class*/) {
+ [](nb::object & /*class*/) {
auto *ip = PyThreadContextEntry::getDefaultInsertionPoint();
- if (!ip)
- throw py::value_error("No current InsertionPoint");
+ if (!ip) throw nb::value_error("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"),
+ .def(nb::init<PyOperationBase &>(), nb::arg("beforeOperation"),
"Inserts before a referenced operation.")
.def_static("at_block_begin", &PyInsertionPoint::atBlockBegin,
- py::arg("block"), "Inserts at the beginning of the block.")
+ nb::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"),
+ nb::arg("block"), "Inserts before the block terminator.")
+ .def("insert", &PyInsertionPoint::insert, nb::arg("operation"),
"Inserts an operation.")
- .def_property_readonly(
+ .def_prop_ro(
"block", [](PyInsertionPoint &self) { return self.getBlock(); },
"Returns the block that this InsertionPoint points to.")
- .def_property_readonly(
+ .def_prop_ro(
"ref_operation",
- [](PyInsertionPoint &self) -> py::object {
+ [](PyInsertionPoint &self) -> nb::object {
auto refOperation = self.getRefOperation();
if (refOperation)
return refOperation->getObject();
- return py::none();
+ return nb::none();
},
"The reference operation before which new operations are "
"inserted, or None if the insertion point is at the end of "
@@ -3408,13 +3438,12 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// Mapping of PyAttribute.
//----------------------------------------------------------------------------
- py::class_<PyAttribute>(m, "Attribute", py::module_local())
+ nb::class_<PyAttribute>(m, "Attribute")
// 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"),
+ .def(nb::init<PyAttribute &>(), nb::arg("cast_from_type"),
"Casts the passed attribute to the generic Attribute")
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyAttribute::getCapsule)
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyAttribute::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAttribute::createFromCapsule)
.def_static(
"parse",
@@ -3426,24 +3455,24 @@ void mlir::python::populateIRCore(py::module &m) {
throw MLIRError("Unable to parse attribute", errors.take());
return attr;
},
- py::arg("asm"), py::arg("context") = py::none(),
+ nb::arg("asm"), nb::arg("context").none() = nb::none(),
"Parses an attribute from an assembly form. Raises an MLIRError on "
"failure.")
- .def_property_readonly(
+ .def_prop_ro(
"context",
[](PyAttribute &self) { return self.getContext().getObject(); },
"Context that owns the Attribute")
- .def_property_readonly(
- "type", [](PyAttribute &self) { return mlirAttributeGetType(self); })
+ .def_prop_ro("type",
+ [](PyAttribute &self) { return 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")
+ nb::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("__eq__", [](PyAttribute &self, nb::object &other) { return false; })
.def("__hash__",
[](PyAttribute &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
@@ -3474,36 +3503,34 @@ void mlir::python::populateIRCore(py::module &m) {
printAccum.parts.append(")");
return printAccum.join();
})
- .def_property_readonly(
- "typeid",
- [](PyAttribute &self) -> MlirTypeID {
- MlirTypeID mlirTypeID = mlirAttributeGetTypeID(self);
- assert(!mlirTypeIDIsNull(mlirTypeID) &&
- "mlirTypeID was expected to be non-null.");
- return mlirTypeID;
- })
+ .def_prop_ro("typeid",
+ [](PyAttribute &self) -> MlirTypeID {
+ MlirTypeID mlirTypeID = mlirAttributeGetTypeID(self);
+ assert(!mlirTypeIDIsNull(mlirTypeID) &&
+ "mlirTypeID was expected to be non-null.");
+ return mlirTypeID;
+ })
.def(MLIR_PYTHON_MAYBE_DOWNCAST_ATTR, [](PyAttribute &self) {
MlirTypeID mlirTypeID = mlirAttributeGetTypeID(self);
assert(!mlirTypeIDIsNull(mlirTypeID) &&
"mlirTypeID was expected to be non-null.");
- std::optional<pybind11::function> typeCaster =
+ std::optional<nb::callable> typeCaster =
PyGlobals::get().lookupTypeCaster(mlirTypeID,
mlirAttributeGetDialect(self));
- if (!typeCaster)
- return py::cast(self);
+ if (!typeCaster) return nb::cast(self);
return typeCaster.value()(self);
});
//----------------------------------------------------------------------------
// Mapping of PyNamedAttribute
//----------------------------------------------------------------------------
- py::class_<PyNamedAttribute>(m, "NamedAttribute", py::module_local())
+ nb::class_<PyNamedAttribute>(m, "NamedAttribute")
.def("__repr__",
[](PyNamedAttribute &self) {
PyPrintAccumulator printAccum;
printAccum.parts.append("NamedAttribute(");
printAccum.parts.append(
- py::str(mlirIdentifierStr(self.namedAttr.name).data,
+ nb::str(mlirIdentifierStr(self.namedAttr.name).data,
mlirIdentifierStr(self.namedAttr.name).length));
printAccum.parts.append("=");
mlirAttributePrint(self.namedAttr.attribute,
@@ -3512,28 +3539,28 @@ void mlir::python::populateIRCore(py::module &m) {
printAccum.parts.append(")");
return printAccum.join();
})
- .def_property_readonly(
+ .def_prop_ro(
"name",
[](PyNamedAttribute &self) {
- return py::str(mlirIdentifierStr(self.namedAttr.name).data,
+ return nb::str(mlirIdentifierStr(self.namedAttr.name).data,
mlirIdentifierStr(self.namedAttr.name).length);
},
"The name of the NamedAttribute binding")
- .def_property_readonly(
+ .def_prop_ro(
"attr",
[](PyNamedAttribute &self) { return self.namedAttr.attribute; },
- py::keep_alive<0, 1>(),
+ nb::keep_alive<0, 1>(),
"The underlying generic attribute of the NamedAttribute binding");
//----------------------------------------------------------------------------
// Mapping of PyType.
//----------------------------------------------------------------------------
- py::class_<PyType>(m, "Type", py::module_local())
+ nb::class_<PyType>(m, "Type")
// 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"),
+ .def(nb::init<PyType &>(), nb::arg("cast_from_type"),
"Casts the passed type to the generic Type")
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule)
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyType::createFromCapsule)
.def_static(
"parse",
@@ -3545,13 +3572,15 @@ void mlir::python::populateIRCore(py::module &m) {
throw MLIRError("Unable to parse type", errors.take());
return type;
},
- py::arg("asm"), py::arg("context") = py::none(),
+ nb::arg("asm"), nb::arg("context").none() = nb::none(),
kContextParseTypeDocstring)
- .def_property_readonly(
+ .def_prop_ro(
"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(
+ "__eq__", [](PyType &self, nb::object &other) { return false; },
+ nb::arg("other").none())
.def("__hash__",
[](PyType &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
@@ -3585,28 +3614,26 @@ void mlir::python::populateIRCore(py::module &m) {
MlirTypeID mlirTypeID = mlirTypeGetTypeID(self);
assert(!mlirTypeIDIsNull(mlirTypeID) &&
"mlirTypeID was expected to be non-null.");
- std::optional<pybind11::function> typeCaster =
+ std::optional<nb::callable> typeCaster =
PyGlobals::get().lookupTypeCaster(mlirTypeID,
mlirTypeGetDialect(self));
- if (!typeCaster)
- return py::cast(self);
+ if (!typeCaster) return nb::cast(self);
return typeCaster.value()(self);
})
- .def_property_readonly("typeid", [](PyType &self) -> MlirTypeID {
+ .def_prop_ro("typeid", [](PyType &self) -> MlirTypeID {
MlirTypeID mlirTypeID = mlirTypeGetTypeID(self);
if (!mlirTypeIDIsNull(mlirTypeID))
return mlirTypeID;
- auto origRepr =
- pybind11::repr(pybind11::cast(self)).cast<std::string>();
- throw py::value_error(
- (origRepr + llvm::Twine(" has no typeid.")).str());
+ auto origRepr = nb::cast<std::string>(nb::repr(nb::cast(self)));
+ throw nb::value_error(
+ (origRepr + llvm::Twine(" has no typeid.")).str().c_str());
});
//----------------------------------------------------------------------------
// Mapping of PyTypeID.
//----------------------------------------------------------------------------
- py::class_<PyTypeID>(m, "TypeID", py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyTypeID::getCapsule)
+ nb::class_<PyTypeID>(m, "TypeID")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyTypeID::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyTypeID::createFromCapsule)
// Note, this tests whether the underlying TypeIDs are the same,
// not whether the wrapper MlirTypeIDs are the same, nor whether
@@ -3614,7 +3641,7 @@ void mlir::python::populateIRCore(py::module &m) {
.def("__eq__",
[](PyTypeID &self, PyTypeID &other) { return self == other; })
.def("__eq__",
- [](PyTypeID &self, const py::object &other) { return false; })
+ [](PyTypeID &self, const nb::object &other) { return false; })
// Note, this gives the hash value of the underlying TypeID, not the
// hash value of the Python object, nor the hash value of the
// MlirTypeID wrapper.
@@ -3625,20 +3652,20 @@ void mlir::python::populateIRCore(py::module &m) {
//----------------------------------------------------------------------------
// Mapping of Value.
//----------------------------------------------------------------------------
- py::class_<PyValue>(m, "Value", py::module_local())
- .def(py::init<PyValue &>(), py::keep_alive<0, 1>(), py::arg("value"))
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule)
+ nb::class_<PyValue>(m, "Value")
+ .def(nb::init<PyValue &>(), nb::keep_alive<0, 1>(), nb::arg("value"))
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyValue::createFromCapsule)
- .def_property_readonly(
+ .def_prop_ro(
"context",
[](PyValue &self) { return self.getParentOperation()->getContext(); },
"Context in which the value lives.")
.def(
"dump", [](PyValue &self) { mlirValueDump(self.get()); },
kDumpDocstring)
- .def_property_readonly(
+ .def_prop_ro(
"owner",
- [](PyValue &self) -> py::object {
+ [](PyValue &self) -> nb::object {
MlirValue v = self.get();
if (mlirValueIsAOpResult(v)) {
assert(
@@ -3651,22 +3678,22 @@ void mlir::python::populateIRCore(py::module &m) {
if (mlirValueIsABlockArgument(v)) {
MlirBlock block = mlirBlockArgumentGetOwner(self.get());
- return py::cast(PyBlock(self.getParentOperation(), block));
+ return nb::cast(PyBlock(self.getParentOperation(), block));
}
assert(false && "Value must be a block argument or an op result");
- return py::none();
+ return nb::none();
+ })
+ .def_prop_ro(
+ "uses",
+ [](PyValue &self) {
+ return PyOpOperandIterator(mlirValueGetFirstUse(self.get()));
})
- .def_property_readonly("uses",
- [](PyValue &self) {
- return PyOpOperandIterator(
- mlirValueGetFirstUse(self.get()));
- })
.def("__eq__",
[](PyValue &self, PyValue &other) {
return self.get().ptr == other.get().ptr;
})
- .def("__eq__", [](PyValue &self, py::object other) { return false; })
+ .def("__eq__", [](PyValue &self, nb::object other) { return false; })
.def("__hash__",
[](PyValue &self) {
return static_cast<size_t>(llvm::hash_value(self.get().ptr));
@@ -3698,26 +3725,26 @@ void mlir::python::populateIRCore(py::module &m) {
mlirAsmStateDestroy(valueState);
return printAccum.join();
},
- py::arg("use_local_scope") = false)
+ nb::arg("use_local_scope") = false)
.def(
"get_name",
- [](PyValue &self, std::reference_wrapper<PyAsmState> state) {
+ [](PyValue &self, PyAsmState &state) {
PyPrintAccumulator printAccum;
- MlirAsmState valueState = state.get().get();
+ MlirAsmState valueState = state.get();
mlirValuePrintAsOperand(self.get(), valueState,
printAccum.getCallback(),
printAccum.getUserData());
return printAccum.join();
},
- py::arg("state"), kGetNameAsOperand)
- .def_property_readonly(
- "type", [](PyValue &self) { return mlirValueGetType(self.get()); })
+ nb::arg("state"), kGetNameAsOperand)
+ .def_prop_ro("type",
+ [](PyValue &self) { return mlirValueGetType(self.get()); })
.def(
"set_type",
[](PyValue &self, const PyType &type) {
return mlirValueSetType(self.get(), type);
},
- py::arg("type"))
+ nb::arg("type"))
.def(
"replace_all_uses_with",
[](PyValue &self, PyValue &with) {
@@ -3730,22 +3757,22 @@ void mlir::python::populateIRCore(py::module &m) {
MlirOperation exceptedUser = exception.get();
mlirValueReplaceAllUsesExcept(self, with, 1, &exceptedUser);
},
- py::arg("with"), py::arg("exceptions"),
+ nb::arg("with"), nb::arg("exceptions"),
kValueReplaceAllUsesExceptDocstring)
.def(
"replace_all_uses_except",
- [](MlirValue self, MlirValue with, py::list exceptions) {
+ [](MlirValue self, MlirValue with, nb::list exceptions) {
// Convert Python list to a SmallVector of MlirOperations
llvm::SmallVector<MlirOperation> exceptionOps;
- for (py::handle exception : exceptions) {
- exceptionOps.push_back(exception.cast<PyOperation &>().get());
+ for (nb::handle exception : exceptions) {
+ exceptionOps.push_back(nb::cast<PyOperation &>(exception).get());
}
mlirValueReplaceAllUsesExcept(
self, with, static_cast<intptr_t>(exceptionOps.size()),
exceptionOps.data());
},
- py::arg("with"), py::arg("exceptions"),
+ nb::arg("with"), nb::arg("exceptions"),
kValueReplaceAllUsesExceptDocstring)
.def(MLIR_PYTHON_MAYBE_DOWNCAST_ATTR,
[](PyValue &self) { return self.maybeDownCast(); });
@@ -3753,20 +3780,20 @@ void mlir::python::populateIRCore(py::module &m) {
PyOpResult::bind(m);
PyOpOperand::bind(m);
- py::class_<PyAsmState>(m, "AsmState", py::module_local())
- .def(py::init<PyValue &, bool>(), py::arg("value"),
- py::arg("use_local_scope") = false)
- .def(py::init<PyOperationBase &, bool>(), py::arg("op"),
- py::arg("use_local_scope") = false);
+ nb::class_<PyAsmState>(m, "AsmState")
+ .def(nb::init<PyValue &, bool>(), nb::arg("value"),
+ nb::arg("use_local_scope") = false)
+ .def(nb::init<PyOperationBase &, bool>(), nb::arg("op"),
+ nb::arg("use_local_scope") = false);
//----------------------------------------------------------------------------
// Mapping of SymbolTable.
//----------------------------------------------------------------------------
- py::class_<PySymbolTable>(m, "SymbolTable", py::module_local())
- .def(py::init<PyOperationBase &>())
+ nb::class_<PySymbolTable>(m, "SymbolTable")
+ .def(nb::init<PyOperationBase &>())
.def("__getitem__", &PySymbolTable::dunderGetItem)
- .def("insert", &PySymbolTable::insert, py::arg("operation"))
- .def("erase", &PySymbolTable::erase, py::arg("operation"))
+ .def("insert", &PySymbolTable::insert, nb::arg("operation"))
+ .def("erase", &PySymbolTable::erase, nb::arg("operation"))
.def("__delitem__", &PySymbolTable::dunderDel)
.def("__contains__",
[](PySymbolTable &table, const std::string &name) {
@@ -3775,19 +3802,19 @@ void mlir::python::populateIRCore(py::module &m) {
})
// Static helpers.
.def_static("set_symbol_name", &PySymbolTable::setSymbolName,
- py::arg("symbol"), py::arg("name"))
+ nb::arg("symbol"), nb::arg("name"))
.def_static("get_symbol_name", &PySymbolTable::getSymbolName,
- py::arg("symbol"))
+ nb::arg("symbol"))
.def_static("get_visibility", &PySymbolTable::getVisibility,
- py::arg("symbol"))
+ nb::arg("symbol"))
.def_static("set_visibility", &PySymbolTable::setVisibility,
- py::arg("symbol"), py::arg("visibility"))
+ nb::arg("symbol"), nb::arg("visibility"))
.def_static("replace_all_symbol_uses",
- &PySymbolTable::replaceAllSymbolUses, py::arg("old_symbol"),
- py::arg("new_symbol"), py::arg("from_op"))
+ &PySymbolTable::replaceAllSymbolUses, nb::arg("old_symbol"),
+ nb::arg("new_symbol"), nb::arg("from_op"))
.def_static("walk_symbol_tables", &PySymbolTable::walkSymbolTables,
- py::arg("from_op"), py::arg("all_sym_uses_visible"),
- py::arg("callback"));
+ nb::arg("from_op"), nb::arg("all_sym_uses_visible"),
+ nb::arg("callback"));
// Container bindings.
PyBlockArgumentList::bind(m);
@@ -3809,14 +3836,15 @@ void mlir::python::populateIRCore(py::module &m) {
// Attribute builder getter.
PyAttrBuilderMap::bind(m);
- py::register_local_exception_translator([](std::exception_ptr p) {
+ nb::register_exception_translator([](const std::exception_ptr &p,
+ void *payload) {
// We can't define exceptions with custom fields through pybind, so instead
// the exception class is defined in python and imported here.
try {
if (p)
std::rethrow_exception(p);
} catch (const MLIRError &e) {
- py::object obj = py::module_::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
+ nb::object obj = nb::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("MLIRError")(e.message, e.errorDiagnostics);
PyErr_SetObject(PyExc_Exception, obj.ptr());
}
diff --git a/mlir/lib/Bindings/Python/IRInterfaces.cpp b/mlir/lib/Bindings/Python/IRInterfaces.cpp
index 54cfa56066eb8b..815b4aba0f4666 100644
--- a/mlir/lib/Bindings/Python/IRInterfaces.cpp
+++ b/mlir/lib/Bindings/Python/IRInterfaces.cpp
@@ -6,25 +6,25 @@
//
//===----------------------------------------------------------------------===//
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/optional.h>
+#include <nanobind/stl/vector.h>
+
#include <cstdint>
#include <optional>
-#include <pybind11/cast.h>
-#include <pybind11/detail/common.h>
-#include <pybind11/pybind11.h>
-#include <pybind11/pytypes.h>
#include <string>
#include <utility>
#include <vector>
#include "IRModule.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/IR.h"
#include "mlir-c/Interfaces.h"
#include "mlir-c/Support.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
-namespace py = pybind11;
+namespace nb = nanobind;
namespace mlir {
namespace python {
@@ -53,10 +53,10 @@ namespace {
/// Takes in an optional ist of operands and converts them into a SmallVector
/// of MlirVlaues. Returns an empty SmallVector if the list is empty.
-llvm::SmallVector<MlirValue> wrapOperands(std::optional<py::list> operandList) {
+llvm::SmallVector<MlirValue> wrapOperands(std::optional<nb::list> operandList) {
llvm::SmallVector<MlirValue> mlirOperands;
- if (!operandList || operandList->empty()) {
+ if (!operandList || operandList->size() == 0) {
return mlirOperands;
}
@@ -68,40 +68,40 @@ llvm::SmallVector<MlirValue> wrapOperands(std::optional<py::list> operandList) {
PyValue *val;
try {
- val = py::cast<PyValue *>(it.value());
- if (!val)
- throw py::cast_error();
+ val = nb::cast<PyValue *>(it.value());
+ if (!val) throw nb::cast_error();
mlirOperands.push_back(val->get());
continue;
- } catch (py::cast_error &err) {
+ } catch (nb::cast_error &err) {
// Intentionally unhandled to try sequence below first.
(void)err;
}
try {
- auto vals = py::cast<py::sequence>(it.value());
- for (py::object v : vals) {
+ auto vals = nb::cast<nb::sequence>(it.value());
+ for (nb::handle v : vals) {
try {
- val = py::cast<PyValue *>(v);
- if (!val)
- throw py::cast_error();
+ val = nb::cast<PyValue *>(v);
+ if (!val) throw nb::cast_error();
mlirOperands.push_back(val->get());
- } catch (py::cast_error &err) {
- throw py::value_error(
+ } catch (nb::cast_error &err) {
+ throw nb::value_error(
(llvm::Twine("Operand ") + llvm::Twine(it.index()) +
" must be a Value or Sequence of Values (" + err.what() + ")")
- .str());
+ .str()
+ .c_str());
}
}
continue;
- } catch (py::cast_error &err) {
- throw py::value_error((llvm::Twine("Operand ") + llvm::Twine(it.index()) +
+ } catch (nb::cast_error &err) {
+ throw nb::value_error((llvm::Twine("Operand ") + llvm::Twine(it.index()) +
" must be a Value or Sequence of Values (" +
err.what() + ")")
- .str());
+ .str()
+ .c_str());
}
- throw py::cast_error();
+ throw nb::cast_error();
}
return mlirOperands;
@@ -143,68 +143,65 @@ wrapRegions(std::optional<std::vector<PyRegion>> regions) {
/// canonical name of the operation suitable for lookups.
template <typename ConcreteIface>
class PyConcreteOpInterface {
-protected:
- using ClassTy = py::class_<ConcreteIface>;
+ protected:
+ using ClassTy = nb::class_<ConcreteIface>;
using GetTypeIDFunctionTy = MlirTypeID (*)();
public:
/// Constructs an interface instance from an object that is either an
/// operation or a subclass of OpView. In the latter case, only the static
/// methods of the interface are accessible to the caller.
- PyConcreteOpInterface(py::object object, DefaultingPyMlirContext context)
- : obj(std::move(object)) {
- try {
- operation = &py::cast<PyOperation &>(obj);
- } catch (py::cast_error &) {
- // Do nothing.
- }
-
- try {
- operation = &py::cast<PyOpView &>(obj).getOperation();
- } catch (py::cast_error &) {
- // Do nothing.
- }
-
- if (operation != nullptr) {
- if (!mlirOperationImplementsInterface(*operation,
- ConcreteIface::getInterfaceID())) {
- std::string msg = "the operation does not implement ";
- throw py::value_error(msg + ConcreteIface::pyClassName);
- }
-
- MlirIdentifier identifier = mlirOperationGetName(*operation);
- MlirStringRef stringRef = mlirIdentifierStr(identifier);
- opName = std::string(stringRef.data, stringRef.length);
- } else {
- try {
- opName = obj.attr("OPERATION_NAME").template cast<std::string>();
- } catch (py::cast_error &) {
- throw py::type_error(
- "Op interface does not refer to an operation or OpView class");
- }
-
- if (!mlirOperationImplementsInterfaceStatic(
- mlirStringRefCreate(opName.data(), opName.length()),
- context.resolve().get(), ConcreteIface::getInterfaceID())) {
- std::string msg = "the operation does not implement ";
- throw py::value_error(msg + ConcreteIface::pyClassName);
- }
- }
- }
+ PyConcreteOpInterface(nb::object object, DefaultingPyMlirContext context)
+ : obj(std::move(object)) {
+ try {
+ operation = &nb::cast<PyOperation &>(obj);
+ } catch (nb::cast_error &) {
+ // Do nothing.
+ }
+
+ try {
+ operation = &nb::cast<PyOpView &>(obj).getOperation();
+ } catch (nb::cast_error &) {
+ // Do nothing.
+ }
+
+ if (operation != nullptr) {
+ if (!mlirOperationImplementsInterface(*operation,
+ ConcreteIface::getInterfaceID())) {
+ std::string msg = "the operation does not implement ";
+ throw nb::value_error((msg + ConcreteIface::pyClassName).c_str());
+ }
+
+ MlirIdentifier identifier = mlirOperationGetName(*operation);
+ MlirStringRef stringRef = mlirIdentifierStr(identifier);
+ opName = std::string(stringRef.data, stringRef.length);
+ } else {
+ try {
+ opName = nb::cast<std::string>(obj.attr("OPERATION_NAME"));
+ } catch (nb::cast_error &) {
+ throw nb::type_error(
+ "Op interface does not refer to an operation or OpView class");
+ }
+
+ if (!mlirOperationImplementsInterfaceStatic(
+ mlirStringRefCreate(opName.data(), opName.length()),
+ context.resolve().get(), ConcreteIface::getInterfaceID())) {
+ std::string msg = "the operation does not implement ";
+ throw nb::value_error((msg + ConcreteIface::pyClassName).c_str());
+ }
+ }
+ }
/// Creates the Python bindings for this class in the given module.
- static void bind(py::module &m) {
- py::class_<ConcreteIface> cls(m, ConcreteIface::pyClassName,
- py::module_local());
- cls.def(py::init<py::object, DefaultingPyMlirContext>(), py::arg("object"),
- py::arg("context") = py::none(), constructorDoc)
- .def_property_readonly("operation",
- &PyConcreteOpInterface::getOperationObject,
- operationDoc)
- .def_property_readonly("opview", &PyConcreteOpInterface::getOpView,
- opviewDoc);
- ConcreteIface::bindDerived(cls);
- }
+ static void bind(nb::module_ &m) {
+ nb::class_<ConcreteIface> cls(m, ConcreteIface::pyClassName);
+ cls.def(nb::init<nb::object, DefaultingPyMlirContext>(), nb::arg("object"),
+ nb::arg("context").none() = nb::none(), constructorDoc)
+ .def_prop_ro("operation", &PyConcreteOpInterface::getOperationObject,
+ operationDoc)
+ .def_prop_ro("opview", &PyConcreteOpInterface::getOpView, opviewDoc);
+ ConcreteIface::bindDerived(cls);
+ }
/// Hook for derived classes to add class-specific bindings.
static void bindDerived(ClassTy &cls) {}
@@ -216,9 +213,9 @@ class PyConcreteOpInterface {
/// Returns the operation instance from which this object was constructed.
/// Throws a type error if this object was constructed from a subclass of
/// OpView.
- py::object getOperationObject() {
+ nb::object getOperationObject() {
if (operation == nullptr) {
- throw py::type_error("Cannot get an operation from a static interface");
+ throw nb::type_error("Cannot get an operation from a static interface");
}
return operation->getRef().releaseObject();
@@ -227,9 +224,9 @@ class PyConcreteOpInterface {
/// Returns the opview of the operation instance from which this object was
/// constructed. Throws a type error if this object was constructed form a
/// subclass of OpView.
- py::object getOpView() {
+ nb::object getOpView() {
if (operation == nullptr) {
- throw py::type_error("Cannot get an opview from a static interface");
+ throw nb::type_error("Cannot get an opview from a static interface");
}
return operation->createOpView();
@@ -242,7 +239,7 @@ class PyConcreteOpInterface {
private:
PyOperation *operation = nullptr;
std::string opName;
- py::object obj;
+ nb::object obj;
};
/// Python wrapper for InferTypeOpInterface. This interface has only static
@@ -275,12 +272,11 @@ class PyInferTypeOpInterface
/// Given the arguments required to build an operation, attempts to infer its
/// return types. Throws value_error on failure.
- std::vector<PyType>
- inferReturnTypes(std::optional<py::list> operandList,
- std::optional<PyAttribute> attributes, void *properties,
- std::optional<std::vector<PyRegion>> regions,
- DefaultingPyMlirContext context,
- DefaultingPyLocation location) {
+ std::vector<PyType> inferReturnTypes(
+ std::optional<nb::list> operandList,
+ std::optional<PyAttribute> attributes, void *properties,
+ std::optional<std::vector<PyRegion>> regions,
+ DefaultingPyMlirContext context, DefaultingPyLocation location) {
llvm::SmallVector<MlirValue> mlirOperands =
wrapOperands(std::move(operandList));
llvm::SmallVector<MlirRegion> mlirRegions = wrapRegions(std::move(regions));
@@ -299,7 +295,7 @@ class PyInferTypeOpInterface
mlirRegions.data(), &appendResultsCallback, &data);
if (mlirLogicalResultIsFailure(result)) {
- throw py::value_error("Failed to infer result types");
+ throw nb::value_error("Failed to infer result types");
}
return inferredTypes;
@@ -307,11 +303,12 @@ class PyInferTypeOpInterface
static void bindDerived(ClassTy &cls) {
cls.def("inferReturnTypes", &PyInferTypeOpInterface::inferReturnTypes,
- py::arg("operands") = py::none(),
- py::arg("attributes") = py::none(),
- py::arg("properties") = py::none(), py::arg("regions") = py::none(),
- py::arg("context") = py::none(), py::arg("loc") = py::none(),
- inferReturnTypesDoc);
+ nb::arg("operands").none() = nb::none(),
+ nb::arg("attributes").none() = nb::none(),
+ nb::arg("properties").none() = nb::none(),
+ nb::arg("regions").none() = nb::none(),
+ nb::arg("context").none() = nb::none(),
+ nb::arg("loc").none() = nb::none(), inferReturnTypesDoc);
}
};
@@ -319,21 +316,22 @@ class PyInferTypeOpInterface
class PyShapedTypeComponents {
public:
PyShapedTypeComponents(MlirType elementType) : elementType(elementType) {}
- PyShapedTypeComponents(py::list shape, MlirType elementType)
+ PyShapedTypeComponents(nb::list shape, MlirType elementType)
: shape(std::move(shape)), elementType(elementType), ranked(true) {}
- PyShapedTypeComponents(py::list shape, MlirType elementType,
+ PyShapedTypeComponents(nb::list shape, MlirType elementType,
MlirAttribute attribute)
- : shape(std::move(shape)), elementType(elementType), attribute(attribute),
+ : shape(std::move(shape)),
+ elementType(elementType),
+ attribute(attribute),
ranked(true) {}
PyShapedTypeComponents(PyShapedTypeComponents &) = delete;
PyShapedTypeComponents(PyShapedTypeComponents &&other) noexcept
: shape(other.shape), elementType(other.elementType),
attribute(other.attribute), ranked(other.ranked) {}
- static void bind(py::module &m) {
- py::class_<PyShapedTypeComponents>(m, "ShapedTypeComponents",
- py::module_local())
- .def_property_readonly(
+ static void bind(nb::module_ &m) {
+ nb::class_<PyShapedTypeComponents>(m, "ShapedTypeComponents")
+ .def_prop_ro(
"element_type",
[](PyShapedTypeComponents &self) { return self.elementType; },
"Returns the element type of the shaped type components.")
@@ -342,57 +340,57 @@ class PyShapedTypeComponents {
[](PyType &elementType) {
return PyShapedTypeComponents(elementType);
},
- py::arg("element_type"),
+ nb::arg("element_type"),
"Create an shaped type components object with only the element "
"type.")
.def_static(
"get",
- [](py::list shape, PyType &elementType) {
+ [](nb::list shape, PyType &elementType) {
return PyShapedTypeComponents(std::move(shape), elementType);
},
- py::arg("shape"), py::arg("element_type"),
+ nb::arg("shape"), nb::arg("element_type"),
"Create a ranked shaped type components object.")
.def_static(
"get",
- [](py::list shape, PyType &elementType, PyAttribute &attribute) {
+ [](nb::list shape, PyType &elementType, PyAttribute &attribute) {
return PyShapedTypeComponents(std::move(shape), elementType,
attribute);
},
- py::arg("shape"), py::arg("element_type"), py::arg("attribute"),
+ nb::arg("shape"), nb::arg("element_type"), nb::arg("attribute"),
"Create a ranked shaped type components object with attribute.")
- .def_property_readonly(
+ .def_prop_ro(
"has_rank",
[](PyShapedTypeComponents &self) -> bool { return self.ranked; },
"Returns whether the given shaped type component is ranked.")
- .def_property_readonly(
+ .def_prop_ro(
"rank",
- [](PyShapedTypeComponents &self) -> py::object {
+ [](PyShapedTypeComponents &self) -> nb::object {
if (!self.ranked) {
- return py::none();
+ return nb::none();
}
- return py::int_(self.shape.size());
+ return nb::int_(self.shape.size());
},
"Returns the rank of the given ranked shaped type components. If "
"the shaped type components does not have a rank, None is "
"returned.")
- .def_property_readonly(
+ .def_prop_ro(
"shape",
- [](PyShapedTypeComponents &self) -> py::object {
+ [](PyShapedTypeComponents &self) -> nb::object {
if (!self.ranked) {
- return py::none();
+ return nb::none();
}
- return py::list(self.shape);
+ return nb::list(self.shape);
},
"Returns the shape of the ranked shaped type components as a list "
"of integers. Returns none if the shaped type component does not "
"have a rank.");
}
- pybind11::object getCapsule();
- static PyShapedTypeComponents createFromCapsule(pybind11::object capsule);
+ nb::object getCapsule();
+ static PyShapedTypeComponents createFromCapsule(nb::object capsule);
-private:
- py::list shape;
+ private:
+ nb::list shape;
MlirType elementType;
MlirAttribute attribute;
bool ranked{false};
@@ -424,7 +422,7 @@ class PyInferShapedTypeOpInterface
if (!hasRank) {
data->inferredShapedTypeComponents.emplace_back(elementType);
} else {
- py::list shapeList;
+ nb::list shapeList;
for (intptr_t i = 0; i < rank; ++i) {
shapeList.append(shape[i]);
}
@@ -436,7 +434,7 @@ class PyInferShapedTypeOpInterface
/// Given the arguments required to build an operation, attempts to infer the
/// shaped type components. Throws value_error on failure.
std::vector<PyShapedTypeComponents> inferReturnTypeComponents(
- std::optional<py::list> operandList,
+ std::optional<nb::list> operandList,
std::optional<PyAttribute> attributes, void *properties,
std::optional<std::vector<PyRegion>> regions,
DefaultingPyMlirContext context, DefaultingPyLocation location) {
@@ -458,7 +456,7 @@ class PyInferShapedTypeOpInterface
mlirRegions.data(), &appendResultsCallback, &data);
if (mlirLogicalResultIsFailure(result)) {
- throw py::value_error("Failed to infer result shape type components");
+ throw nb::value_error("Failed to infer result shape type components");
}
return inferredShapedTypeComponents;
@@ -467,14 +465,16 @@ class PyInferShapedTypeOpInterface
static void bindDerived(ClassTy &cls) {
cls.def("inferReturnTypeComponents",
&PyInferShapedTypeOpInterface::inferReturnTypeComponents,
- py::arg("operands") = py::none(),
- py::arg("attributes") = py::none(), py::arg("regions") = py::none(),
- py::arg("properties") = py::none(), py::arg("context") = py::none(),
- py::arg("loc") = py::none(), inferReturnTypeComponentsDoc);
+ nb::arg("operands").none() = nb::none(),
+ nb::arg("attributes").none() = nb::none(),
+ nb::arg("regions").none() = nb::none(),
+ nb::arg("properties").none() = nb::none(),
+ nb::arg("context").none() = nb::none(),
+ nb::arg("loc").none() = nb::none(), inferReturnTypeComponentsDoc);
}
};
-void populateIRInterfaces(py::module &m) {
+void populateIRInterfaces(nb::module_ &m) {
PyInferTypeOpInterface::bind(m);
PyShapedTypeComponents::bind(m);
PyInferShapedTypeOpInterface::bind(m);
diff --git a/mlir/lib/Bindings/Python/IRModule.cpp b/mlir/lib/Bindings/Python/IRModule.cpp
index 6727860c094a2a..05d0552fdfc385 100644
--- a/mlir/lib/Bindings/Python/IRModule.cpp
+++ b/mlir/lib/Bindings/Python/IRModule.cpp
@@ -7,16 +7,19 @@
//===----------------------------------------------------------------------===//
#include "IRModule.h"
-#include "Globals.h"
-#include "PybindUtils.h"
-#include "mlir-c/Bindings/Python/Interop.h"
-#include "mlir-c/Support.h"
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/string.h>
#include <optional>
#include <vector>
-namespace py = pybind11;
+#include "Globals.h"
+#include "NanobindUtils.h"
+#include "mlir-c/Bindings/Python/Interop.h"
+#include "mlir-c/Support.h"
+
+namespace nb = nanobind;
using namespace mlir;
using namespace mlir::python;
@@ -41,14 +44,14 @@ bool PyGlobals::loadDialectModule(llvm::StringRef dialectNamespace) {
return true;
// Since re-entrancy is possible, make a copy of the search prefixes.
std::vector<std::string> localSearchPrefixes = dialectSearchPrefixes;
- py::object loaded = py::none();
+ nb::object loaded = nb::none();
for (std::string moduleName : localSearchPrefixes) {
moduleName.push_back('.');
moduleName.append(dialectNamespace.data(), dialectNamespace.size());
try {
- loaded = py::module::import(moduleName.c_str());
- } catch (py::error_already_set &e) {
+ loaded = nb::module_::import_(moduleName.c_str());
+ } catch (nb::python_error &e) {
if (e.matches(PyExc_ModuleNotFoundError)) {
continue;
}
@@ -66,41 +69,39 @@ bool PyGlobals::loadDialectModule(llvm::StringRef dialectNamespace) {
}
void PyGlobals::registerAttributeBuilder(const std::string &attributeKind,
- py::function pyFunc, bool replace) {
- py::object &found = attributeBuilderMap[attributeKind];
+ nb::callable pyFunc, bool replace) {
+ nb::object &found = attributeBuilderMap[attributeKind];
if (found && !replace) {
throw std::runtime_error((llvm::Twine("Attribute builder for '") +
attributeKind +
"' is already registered with func: " +
- py::str(found).operator std::string())
+ nb::cast<std::string>(nb::str(found)))
.str());
}
found = std::move(pyFunc);
}
void PyGlobals::registerTypeCaster(MlirTypeID mlirTypeID,
- pybind11::function typeCaster,
- bool replace) {
- pybind11::object &found = typeCasterMap[mlirTypeID];
+ nb::callable typeCaster, bool replace) {
+ nb::object &found = typeCasterMap[mlirTypeID];
if (found && !replace)
throw std::runtime_error("Type caster is already registered with caster: " +
- py::str(found).operator std::string());
+ nb::cast<std::string>(nb::str(found)));
found = std::move(typeCaster);
}
void PyGlobals::registerValueCaster(MlirTypeID mlirTypeID,
- pybind11::function valueCaster,
- bool replace) {
- pybind11::object &found = valueCasterMap[mlirTypeID];
+ nb::callable valueCaster, bool replace) {
+ nb::object &found = valueCasterMap[mlirTypeID];
if (found && !replace)
throw std::runtime_error("Value caster is already registered: " +
- py::repr(found).cast<std::string>());
+ nb::cast<std::string>(nb::repr(found)));
found = std::move(valueCaster);
}
void PyGlobals::registerDialectImpl(const std::string &dialectNamespace,
- py::object pyClass) {
- py::object &found = dialectClassMap[dialectNamespace];
+ nb::object pyClass) {
+ nb::object &found = dialectClassMap[dialectNamespace];
if (found) {
throw std::runtime_error((llvm::Twine("Dialect namespace '") +
dialectNamespace + "' is already registered.")
@@ -110,8 +111,8 @@ void PyGlobals::registerDialectImpl(const std::string &dialectNamespace,
}
void PyGlobals::registerOperationImpl(const std::string &operationName,
- py::object pyClass, bool replace) {
- py::object &found = operationClassMap[operationName];
+ nb::object pyClass, bool replace) {
+ nb::object &found = operationClassMap[operationName];
if (found && !replace) {
throw std::runtime_error((llvm::Twine("Operation '") + operationName +
"' is already registered.")
@@ -120,8 +121,8 @@ void PyGlobals::registerOperationImpl(const std::string &operationName,
found = std::move(pyClass);
}
-std::optional<py::function>
-PyGlobals::lookupAttributeBuilder(const std::string &attributeKind) {
+std::optional<nb::callable> PyGlobals::lookupAttributeBuilder(
+ const std::string &attributeKind) {
const auto foundIt = attributeBuilderMap.find(attributeKind);
if (foundIt != attributeBuilderMap.end()) {
assert(foundIt->second && "attribute builder is defined");
@@ -130,7 +131,7 @@ PyGlobals::lookupAttributeBuilder(const std::string &attributeKind) {
return std::nullopt;
}
-std::optional<py::function> PyGlobals::lookupTypeCaster(MlirTypeID mlirTypeID,
+std::optional<nb::callable> PyGlobals::lookupTypeCaster(MlirTypeID mlirTypeID,
MlirDialect dialect) {
// Try to load dialect module.
(void)loadDialectModule(unwrap(mlirDialectGetNamespace(dialect)));
@@ -142,7 +143,7 @@ std::optional<py::function> PyGlobals::lookupTypeCaster(MlirTypeID mlirTypeID,
return std::nullopt;
}
-std::optional<py::function> PyGlobals::lookupValueCaster(MlirTypeID mlirTypeID,
+std::optional<nb::callable> PyGlobals::lookupValueCaster(MlirTypeID mlirTypeID,
MlirDialect dialect) {
// Try to load dialect module.
(void)loadDialectModule(unwrap(mlirDialectGetNamespace(dialect)));
@@ -154,8 +155,8 @@ std::optional<py::function> PyGlobals::lookupValueCaster(MlirTypeID mlirTypeID,
return std::nullopt;
}
-std::optional<py::object>
-PyGlobals::lookupDialectClass(const std::string &dialectNamespace) {
+std::optional<nb::object> PyGlobals::lookupDialectClass(
+ const std::string &dialectNamespace) {
// Make sure dialect module is loaded.
if (!loadDialectModule(dialectNamespace))
return std::nullopt;
@@ -168,8 +169,8 @@ PyGlobals::lookupDialectClass(const std::string &dialectNamespace) {
return std::nullopt;
}
-std::optional<pybind11::object>
-PyGlobals::lookupOperationClass(llvm::StringRef operationName) {
+std::optional<nb::object> PyGlobals::lookupOperationClass(
+ llvm::StringRef operationName) {
// Make sure dialect module is loaded.
auto split = operationName.split('.');
llvm::StringRef dialectNamespace = split.first;
diff --git a/mlir/lib/Bindings/Python/IRModule.h b/mlir/lib/Bindings/Python/IRModule.h
index 172898cfda0c52..489e2b6e82a230 100644
--- a/mlir/lib/Bindings/Python/IRModule.h
+++ b/mlir/lib/Bindings/Python/IRModule.h
@@ -10,21 +10,23 @@
#ifndef MLIR_BINDINGS_PYTHON_IRMODULES_H
#define MLIR_BINDINGS_PYTHON_IRMODULES_H
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/string.h>
+
#include <optional>
#include <utility>
#include <vector>
#include "Globals.h"
-#include "PybindUtils.h"
-
+#include "NanobindUtils.h"
+#include "llvm/ADT/DenseMap.h"
#include "mlir-c/AffineExpr.h"
#include "mlir-c/AffineMap.h"
#include "mlir-c/Diagnostics.h"
#include "mlir-c/IR.h"
#include "mlir-c/IntegerSet.h"
#include "mlir-c/Transforms.h"
-#include "mlir/Bindings/Python/PybindAdaptors.h"
-#include "llvm/ADT/DenseMap.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
namespace mlir {
namespace python {
@@ -48,8 +50,8 @@ class PyValue;
/// reference to its underlying python object.
template <typename T>
class PyObjectRef {
-public:
- PyObjectRef(T *referrent, pybind11::object object)
+ public:
+ PyObjectRef(T *referrent, nanobind::object object)
: referrent(referrent), object(std::move(object)) {
assert(this->referrent &&
"cannot construct PyObjectRef with null referrent");
@@ -67,13 +69,13 @@ class PyObjectRef {
int getRefCount() {
if (!object)
return 0;
- return object.ref_count();
+ return Py_REFCNT(object.ptr());
}
/// 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.
- pybind11::object releaseObject() {
+ nanobind::object releaseObject() {
assert(referrent && object);
referrent = nullptr;
auto stolen = std::move(object);
@@ -85,7 +87,7 @@ class PyObjectRef {
assert(referrent && object);
return referrent;
}
- pybind11::object getObject() {
+ nanobind::object getObject() {
assert(referrent && object);
return object;
}
@@ -93,7 +95,7 @@ class PyObjectRef {
private:
T *referrent;
- pybind11::object object;
+ nanobind::object object;
};
/// Tracks an entry in the thread context stack. New entries are pushed onto
@@ -112,11 +114,13 @@ class PyThreadContextEntry {
Location,
};
- PyThreadContextEntry(FrameKind frameKind, pybind11::object context,
- pybind11::object insertionPoint,
- pybind11::object location)
- : context(std::move(context)), insertionPoint(std::move(insertionPoint)),
- location(std::move(location)), frameKind(frameKind) {}
+ PyThreadContextEntry(FrameKind frameKind, nanobind::object context,
+ nanobind::object insertionPoint,
+ nanobind::object location)
+ : context(std::move(context)),
+ insertionPoint(std::move(insertionPoint)),
+ location(std::move(location)),
+ frameKind(frameKind) {}
/// Gets the top of stack context and return nullptr if not defined.
static PyMlirContext *getDefaultContext();
@@ -134,28 +138,28 @@ class PyThreadContextEntry {
/// Stack management.
static PyThreadContextEntry *getTopOfStack();
- static pybind11::object pushContext(PyMlirContext &context);
+ static nanobind::object pushContext(nanobind::object context);
static void popContext(PyMlirContext &context);
- static pybind11::object pushInsertionPoint(PyInsertionPoint &insertionPoint);
+ static nanobind::object pushInsertionPoint(nanobind::object insertionPoint);
static void popInsertionPoint(PyInsertionPoint &insertionPoint);
- static pybind11::object pushLocation(PyLocation &location);
+ static nanobind::object pushLocation(nanobind::object location);
static void popLocation(PyLocation &location);
/// Gets the thread local stack.
static std::vector<PyThreadContextEntry> &getStack();
private:
- static void push(FrameKind frameKind, pybind11::object context,
- pybind11::object insertionPoint, pybind11::object location);
-
- /// An object reference to the PyContext.
- pybind11::object context;
- /// An object reference to the current insertion point.
- pybind11::object insertionPoint;
- /// An object reference to the current location.
- pybind11::object location;
- // The kind of push that was performed.
- FrameKind frameKind;
+ static void push(FrameKind frameKind, nanobind::object context,
+ nanobind::object insertionPoint, nanobind::object location);
+
+ /// An object reference to the PyContext.
+ nanobind::object context;
+ /// An object reference to the current insertion point.
+ nanobind::object insertionPoint;
+ /// An object reference to the current location.
+ nanobind::object location;
+ // The kind of push that was performed.
+ FrameKind frameKind;
};
/// Wrapper around MlirContext.
@@ -163,14 +167,15 @@ using PyMlirContextRef = PyObjectRef<PyMlirContext>;
class PyMlirContext {
public:
PyMlirContext() = delete;
+ PyMlirContext(MlirContext context);
PyMlirContext(const PyMlirContext &) = delete;
PyMlirContext(PyMlirContext &&) = delete;
- /// For the case of a python __init__ (py::init) method, pybind11 is quite
- /// strict about needing to return a pointer that is not yet associated to
- /// an py::object. Since the forContext() method acts like a pool, possibly
- /// returning a recycled context, it does not satisfy this need. The usual
- /// way in python to accomplish such a thing is to override __new__, but
+ /// For the case of a python __init__ (nanobind::init) method, pybind11 is
+ /// quite strict about needing to return a pointer that is not yet associated
+ /// to an nanobind::object. Since the forContext() method acts like a pool,
+ /// possibly returning a recycled context, it does not satisfy this need. The
+ /// usual way in python to accomplish such a thing is to override __new__, but
/// that is also not supported by pybind11. Instead, we use this entry
/// point which always constructs a fresh context (which cannot alias an
/// existing one because it is fresh).
@@ -187,17 +192,17 @@ class PyMlirContext {
/// Gets a strong reference to this context, which will ensure it is kept
/// alive for the life of the reference.
PyMlirContextRef getRef() {
- return PyMlirContextRef(this, pybind11::cast(this));
+ return PyMlirContextRef(this, nanobind::cast(this));
}
/// Gets a capsule wrapping the void* within the MlirContext.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyMlirContext from the MlirContext wrapped by a capsule.
/// Note that PyMlirContext instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirContext
/// is taken by calling this function.
- static pybind11::object createFromCapsule(pybind11::object capsule);
+ static nanobind::object createFromCapsule(nanobind::object capsule);
/// Gets the count of live context objects. Used for testing.
static size_t getLiveCount();
@@ -237,23 +242,21 @@ class PyMlirContext {
size_t getLiveModuleCount();
/// Enter and exit the context manager.
- pybind11::object contextEnter();
- void contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb);
+ static nanobind::object contextEnter(nanobind::object context);
+ void contextExit(const nanobind::object &excType,
+ const nanobind::object &excVal,
+ const nanobind::object &excTb);
/// Attaches a Python callback as a diagnostic handler, returning a
/// registration object (internally a PyDiagnosticHandler).
- pybind11::object attachDiagnosticHandler(pybind11::object callback);
+ nanobind::object attachDiagnosticHandler(nanobind::object callback);
/// Controls whether error diagnostics should be propagated to diagnostic
/// handlers, instead of being captured by `ErrorCapture`.
void setEmitErrorDiagnostics(bool value) { emitErrorDiagnostics = value; }
struct ErrorCapture;
-private:
- PyMlirContext(MlirContext context);
-
+ private:
// Interns the mapping of live MlirContext::ptr to PyMlirContext instances,
// preserving the relationship that an MlirContext maps to a single
// PyMlirContext wrapper. This could be replaced in the future with an
@@ -268,7 +271,7 @@ class PyMlirContext {
// from this map, and while it still exists as an instance, any
// attempt to access it will raise an error.
using LiveModuleMap =
- llvm::DenseMap<const void *, std::pair<pybind11::handle, PyModule *>>;
+ llvm::DenseMap<const void *, std::pair<nanobind::handle, PyModule *>>;
LiveModuleMap liveModules;
// Interns all live operations associated with this context. Operations
@@ -276,7 +279,7 @@ class PyMlirContext {
// removed from this map, and while it still exists as an instance, any
// attempt to access it will raise an error.
using LiveOperationMap =
- llvm::DenseMap<void *, std::pair<pybind11::handle, PyOperation *>>;
+ llvm::DenseMap<void *, std::pair<nanobind::handle, PyOperation *>>;
LiveOperationMap liveOperations;
bool emitErrorDiagnostics = false;
@@ -324,21 +327,21 @@ class PyLocation : public BaseContextObject {
MlirLocation get() const { return loc; }
/// Enter and exit the context manager.
- pybind11::object contextEnter();
- void contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb);
+ static nanobind::object contextEnter(nanobind::object location);
+ void contextExit(const nanobind::object &excType,
+ const nanobind::object &excVal,
+ const nanobind::object &excTb);
/// Gets a capsule wrapping the void* within the MlirLocation.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyLocation from the MlirLocation wrapped by a capsule.
/// Note that PyLocation instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirLocation
/// is taken by calling this function.
- static PyLocation createFromCapsule(pybind11::object capsule);
+ static PyLocation createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirLocation loc;
};
@@ -353,8 +356,8 @@ class PyDiagnostic {
bool isValid() { return valid; }
MlirDiagnosticSeverity getSeverity();
PyLocation getLocation();
- pybind11::str getMessage();
- pybind11::tuple getNotes();
+ nanobind::str getMessage();
+ nanobind::tuple getNotes();
/// Materialized diagnostic information. This is safe to access outside the
/// diagnostic callback.
@@ -373,7 +376,7 @@ class PyDiagnostic {
/// If notes have been materialized from the diagnostic, then this will
/// be populated with the corresponding objects (all castable to
/// PyDiagnostic).
- std::optional<pybind11::tuple> materializedNotes;
+ std::optional<nanobind::tuple> materializedNotes;
bool valid = true;
};
@@ -398,25 +401,25 @@ class PyDiagnostic {
/// is no way to attach an existing handler object).
class PyDiagnosticHandler {
public:
- PyDiagnosticHandler(MlirContext context, pybind11::object callback);
- ~PyDiagnosticHandler();
+ PyDiagnosticHandler(MlirContext context, nanobind::object callback);
+ ~PyDiagnosticHandler();
- bool isAttached() { return registeredID.has_value(); }
- bool getHadError() { return hadError; }
+ bool isAttached() { return registeredID.has_value(); }
+ bool getHadError() { return hadError; }
- /// Detaches the handler. Does nothing if not attached.
- void detach();
+ /// Detaches the handler. Does nothing if not attached.
+ void detach();
- pybind11::object contextEnter() { return pybind11::cast(this); }
- void contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb) {
- detach();
- }
+ nanobind::object contextEnter() { return nanobind::cast(this); }
+ void contextExit(const nanobind::object &excType,
+ const nanobind::object &excVal,
+ const nanobind::object &excTb) {
+ detach();
+ }
private:
MlirContext context;
- pybind11::object callback;
+ nanobind::object callback;
std::optional<MlirDiagnosticHandlerID> registeredID;
bool hadError = false;
friend class PyMlirContext;
@@ -477,12 +480,12 @@ class PyDialects : public BaseContextObject {
/// objects of this type will be returned directly.
class PyDialect {
public:
- PyDialect(pybind11::object descriptor) : descriptor(std::move(descriptor)) {}
+ PyDialect(nanobind::object descriptor) : descriptor(std::move(descriptor)) {}
- pybind11::object getDescriptor() { return descriptor; }
+ nanobind::object getDescriptor() { return descriptor; }
private:
- pybind11::object descriptor;
+ nanobind::object descriptor;
};
/// Wrapper around an MlirDialectRegistry.
@@ -505,10 +508,10 @@ class PyDialectRegistry {
operator MlirDialectRegistry() const { return registry; }
MlirDialectRegistry get() const { return registry; }
- pybind11::object getCapsule();
- static PyDialectRegistry createFromCapsule(pybind11::object capsule);
+ nanobind::object getCapsule();
+ static PyDialectRegistry createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirDialectRegistry registry;
};
@@ -542,26 +545,25 @@ class PyModule : public BaseContextObject {
/// Gets a strong reference to this module.
PyModuleRef getRef() {
- return PyModuleRef(this,
- pybind11::reinterpret_borrow<pybind11::object>(handle));
+ return PyModuleRef(this, nanobind::borrow<nanobind::object>(handle));
}
/// Gets a capsule wrapping the void* within the MlirModule.
/// Note that the module does not (yet) provide a corresponding factory for
/// constructing from a capsule as that would require uniquing PyModule
/// instances, which is not currently done.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyModule from the MlirModule wrapped by a capsule.
/// Note that PyModule instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirModule
/// is taken by calling this function.
- static pybind11::object createFromCapsule(pybind11::object capsule);
+ static nanobind::object createFromCapsule(nanobind::object capsule);
-private:
+ private:
PyModule(PyMlirContextRef contextRef, MlirModule module);
MlirModule module;
- pybind11::handle handle;
+ nanobind::handle handle;
};
class PyAsmState;
@@ -574,18 +576,18 @@ class PyOperationBase {
/// Implements the bound 'print' method and helps with others.
void print(std::optional<int64_t> largeElementsLimit, bool enableDebugInfo,
bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
- bool assumeVerified, py::object fileObject, bool binary,
+ bool assumeVerified, nanobind::object fileObject, bool binary,
bool skipRegions);
- void print(PyAsmState &state, py::object fileObject, bool binary);
+ void print(PyAsmState &state, nanobind::object fileObject, bool binary);
- pybind11::object getAsm(bool binary,
+ nanobind::object getAsm(bool binary,
std::optional<int64_t> largeElementsLimit,
bool enableDebugInfo, bool prettyDebugInfo,
bool printGenericOpForm, bool useLocalScope,
bool assumeVerified, bool skipRegions);
// Implement the bound 'writeBytecode' method.
- void writeBytecode(const pybind11::object &fileObject,
+ void writeBytecode(const nanobind::object &fileObject,
std::optional<int64_t> bytecodeVersion);
// Implement the walk method.
@@ -619,15 +621,15 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
/// Returns a PyOperation for the given MlirOperation, optionally associating
/// it with a parentKeepAlive.
- static PyOperationRef
- forOperation(PyMlirContextRef contextRef, MlirOperation operation,
- pybind11::object parentKeepAlive = pybind11::object());
+ static PyOperationRef forOperation(
+ PyMlirContextRef contextRef, MlirOperation operation,
+ nanobind::object parentKeepAlive = nanobind::object());
/// Creates a detached operation. The operation must not be associated with
/// any existing live operation.
- static PyOperationRef
- createDetached(PyMlirContextRef contextRef, MlirOperation operation,
- pybind11::object parentKeepAlive = pybind11::object());
+ static PyOperationRef createDetached(
+ PyMlirContextRef contextRef, MlirOperation operation,
+ nanobind::object parentKeepAlive = nanobind::object());
/// Parses a source string (either text assembly or bytecode), creating a
/// detached operation.
@@ -640,7 +642,7 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
void detachFromParent() {
mlirOperationRemoveFromParent(getOperation());
setDetached();
- parentKeepAlive = pybind11::object();
+ parentKeepAlive = nanobind::object();
}
/// Gets the backing operation.
@@ -651,12 +653,11 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
}
PyOperationRef getRef() {
- return PyOperationRef(
- this, pybind11::reinterpret_borrow<pybind11::object>(handle));
+ return PyOperationRef(this, nanobind::borrow<nanobind::object>(handle));
}
bool isAttached() { return attached; }
- void setAttached(const pybind11::object &parent = pybind11::object()) {
+ void setAttached(const nanobind::object &parent = nanobind::object()) {
assert(!attached && "operation already attached");
attached = true;
}
@@ -675,24 +676,24 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
std::optional<PyOperationRef> getParentOperation();
/// Gets a capsule wrapping the void* within the MlirOperation.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyOperation from the MlirOperation wrapped by a capsule.
/// Ownership of the underlying MlirOperation is taken by calling this
/// function.
- static pybind11::object createFromCapsule(pybind11::object capsule);
+ static nanobind::object createFromCapsule(nanobind::object capsule);
/// Creates an operation. See corresponding python docstring.
- static pybind11::object
- create(const std::string &name, std::optional<std::vector<PyType *>> results,
- std::optional<std::vector<PyValue *>> operands,
- std::optional<pybind11::dict> attributes,
- std::optional<std::vector<PyBlock *>> successors, int regions,
- DefaultingPyLocation location, const pybind11::object &ip,
- bool inferType);
+ static nanobind::object create(
+ const std::string &name, std::optional<std::vector<PyType *>> results,
+ std::optional<std::vector<PyValue *>> operands,
+ std::optional<nanobind::dict> attributes,
+ std::optional<std::vector<PyBlock *>> successors, int regions,
+ DefaultingPyLocation location, const nanobind::object &ip,
+ bool inferType);
/// Creates an OpView suitable for this operation.
- pybind11::object createOpView();
+ nanobind::object createOpView();
/// Erases the underlying MlirOperation, removes its pointer from the
/// parent context's live operations map, and sets the valid bit false.
@@ -702,23 +703,23 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
void setInvalid() { valid = false; }
/// Clones this operation.
- pybind11::object clone(const pybind11::object &ip);
+ nanobind::object clone(const nanobind::object &ip);
-private:
+ private:
PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
static PyOperationRef createInstance(PyMlirContextRef contextRef,
MlirOperation operation,
- pybind11::object parentKeepAlive);
+ nanobind::object parentKeepAlive);
MlirOperation operation;
- pybind11::handle handle;
+ nanobind::handle handle;
// Keeps the parent alive, regardless of whether it is an Operation or
// Module.
// TODO: As implemented, this facility is only sufficient for modeling the
// trivial module parent back-reference. Generalize this to also account for
// transitions from detached to attached and address TODOs in the
// ir_operation.py regarding testing corresponding lifetime guarantees.
- pybind11::object parentKeepAlive;
+ nanobind::object parentKeepAlive;
bool attached = true;
bool valid = true;
@@ -733,31 +734,31 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
/// python types.
class PyOpView : public PyOperationBase {
public:
- PyOpView(const pybind11::object &operationObject);
- PyOperation &getOperation() override { return operation; }
-
- pybind11::object getOperationObject() { return operationObject; }
-
- static pybind11::object buildGeneric(
- const pybind11::object &cls, std::optional<pybind11::list> resultTypeList,
- pybind11::list operandList, std::optional<pybind11::dict> attributes,
- std::optional<std::vector<PyBlock *>> successors,
- std::optional<int> regions, DefaultingPyLocation location,
- const pybind11::object &maybeIp);
-
- /// Construct an instance of a class deriving from OpView, bypassing its
- /// `__init__` method. The derived class will typically define a constructor
- /// that provides a convenient builder, but we need to side-step this when
- /// constructing an `OpView` for an already-built operation.
- ///
- /// The caller is responsible for verifying that `operation` is a valid
- /// operation to construct `cls` with.
- static pybind11::object constructDerived(const pybind11::object &cls,
- const PyOperation &operation);
+ PyOpView(const nanobind::object &operationObject);
+ PyOperation &getOperation() override { return operation; }
+
+ nanobind::object getOperationObject() { return operationObject; }
+
+ static nanobind::object buildGeneric(
+ const nanobind::object &cls, std::optional<nanobind::list> resultTypeList,
+ nanobind::list operandList, std::optional<nanobind::dict> attributes,
+ std::optional<std::vector<PyBlock *>> successors,
+ std::optional<int> regions, DefaultingPyLocation location,
+ const nanobind::object &maybeIp);
+
+ /// Construct an instance of a class deriving from OpView, bypassing its
+ /// `__init__` method. The derived class will typically define a constructor
+ /// that provides a convenient builder, but we need to side-step this when
+ /// constructing an `OpView` for an already-built operation.
+ ///
+ /// The caller is responsible for verifying that `operation` is a valid
+ /// operation to construct `cls` with.
+ static nanobind::object constructDerived(const nanobind::object &cls,
+ const nanobind::object &operation);
private:
PyOperation &operation; // For efficient, cast-free access from C++
- pybind11::object operationObject; // Holds the reference.
+ nanobind::object operationObject; // Holds the reference.
};
/// Wrapper around an MlirRegion.
@@ -830,9 +831,9 @@ class PyBlock {
void checkValid() { return parentOperation->checkValid(); }
/// Gets a capsule wrapping the void* within the MlirBlock.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
-private:
+ private:
PyOperationRef parentOperation;
MlirBlock block;
};
@@ -858,10 +859,10 @@ class PyInsertionPoint {
void insert(PyOperationBase &operationBase);
/// Enter and exit the context manager.
- pybind11::object contextEnter();
- void contextExit(const pybind11::object &excType,
- const pybind11::object &excVal,
- const pybind11::object &excTb);
+ static nanobind::object contextEnter(nanobind::object insertionPoint);
+ void contextExit(const nanobind::object &excType,
+ const nanobind::object &excVal,
+ const nanobind::object &excTb);
PyBlock &getBlock() { return block; }
std::optional<PyOperationRef> &getRefOperation() { return refOperation; }
@@ -886,15 +887,15 @@ class PyType : public BaseContextObject {
MlirType get() const { return type; }
/// Gets a capsule wrapping the void* within the MlirType.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyType from the MlirType wrapped by a capsule.
/// Note that PyType instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirType
/// is taken by calling this function.
- static PyType createFromCapsule(pybind11::object capsule);
+ static PyType createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirType type;
};
@@ -912,12 +913,12 @@ class PyTypeID {
MlirTypeID get() { return typeID; }
/// Gets a capsule wrapping the void* within the MlirTypeID.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyTypeID from the MlirTypeID wrapped by a capsule.
- static PyTypeID createFromCapsule(pybind11::object capsule);
+ static PyTypeID createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirTypeID typeID;
};
@@ -932,66 +933,70 @@ class PyConcreteType : public BaseTy {
// Derived classes must define statics for:
// IsAFunctionTy isaFunction
// const char *pyClassName
- using ClassTy = pybind11::class_<DerivedTy, BaseTy>;
- using IsAFunctionTy = bool (*)(MlirType);
- using GetTypeIDFunctionTy = MlirTypeID (*)();
- static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
-
- PyConcreteType() = default;
- PyConcreteType(PyMlirContextRef contextRef, MlirType t)
- : BaseTy(std::move(contextRef), t) {}
- PyConcreteType(PyType &orig)
- : PyConcreteType(orig.getContext(), castFrom(orig)) {}
-
- static MlirType castFrom(PyType &orig) {
- if (!DerivedTy::isaFunction(orig)) {
- auto origRepr = pybind11::repr(pybind11::cast(orig)).cast<std::string>();
- throw py::value_error((llvm::Twine("Cannot cast type to ") +
- DerivedTy::pyClassName + " (from " + origRepr +
- ")")
- .str());
- }
- return orig;
- }
-
- static void bind(pybind11::module &m) {
- auto cls = ClassTy(m, DerivedTy::pyClassName, pybind11::module_local());
- cls.def(pybind11::init<PyType &>(), pybind11::keep_alive<0, 1>(),
- pybind11::arg("cast_from_type"));
- cls.def_static(
- "isinstance",
- [](PyType &otherType) -> bool {
- return DerivedTy::isaFunction(otherType);
- },
- pybind11::arg("other"));
- cls.def_property_readonly_static(
- "static_typeid", [](py::object & /*class*/) -> MlirTypeID {
- if (DerivedTy::getTypeIdFunction)
- return DerivedTy::getTypeIdFunction();
- throw py::attribute_error(
- (DerivedTy::pyClassName + llvm::Twine(" has no typeid.")).str());
- });
- cls.def_property_readonly("typeid", [](PyType &self) {
- return py::cast(self).attr("typeid").cast<MlirTypeID>();
- });
- cls.def("__repr__", [](DerivedTy &self) {
- PyPrintAccumulator printAccum;
- printAccum.parts.append(DerivedTy::pyClassName);
- printAccum.parts.append("(");
- mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
- printAccum.parts.append(")");
- return printAccum.join();
- });
-
- if (DerivedTy::getTypeIdFunction) {
- PyGlobals::get().registerTypeCaster(
- DerivedTy::getTypeIdFunction(),
- pybind11::cpp_function(
- [](PyType pyType) -> DerivedTy { return pyType; }));
- }
-
- DerivedTy::bindDerived(cls);
- }
+ using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
+ using IsAFunctionTy = bool (*)(MlirType);
+ using GetTypeIDFunctionTy = MlirTypeID (*)();
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
+
+ PyConcreteType() = default;
+ PyConcreteType(PyMlirContextRef contextRef, MlirType t)
+ : BaseTy(std::move(contextRef), t) {}
+ PyConcreteType(PyType &orig)
+ : PyConcreteType(orig.getContext(), castFrom(orig)) {}
+
+ static MlirType castFrom(PyType &orig) {
+ if (!DerivedTy::isaFunction(orig)) {
+ auto origRepr =
+ nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
+ throw nanobind::value_error((llvm::Twine("Cannot cast type to ") +
+ DerivedTy::pyClassName + " (from " +
+ origRepr + ")")
+ .str()
+ .c_str());
+ }
+ return orig;
+ }
+
+ static void bind(nanobind::module_ &m) {
+ auto cls = ClassTy(m, DerivedTy::pyClassName);
+ cls.def(nanobind::init<PyType &>(), nanobind::keep_alive<0, 1>(),
+ nanobind::arg("cast_from_type"));
+ cls.def_static(
+ "isinstance",
+ [](PyType &otherType) -> bool {
+ return DerivedTy::isaFunction(otherType);
+ },
+ nanobind::arg("other"));
+ cls.def_prop_ro_static(
+ "static_typeid", [](nanobind::object & /*class*/) -> MlirTypeID {
+ if (DerivedTy::getTypeIdFunction)
+ return DerivedTy::getTypeIdFunction();
+ throw nanobind::attribute_error(
+ (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
+ .str()
+ .c_str());
+ });
+ cls.def_prop_ro("typeid", [](PyType &self) {
+ return nanobind::cast<MlirTypeID>(nanobind::cast(self).attr("typeid"));
+ });
+ cls.def("__repr__", [](DerivedTy &self) {
+ PyPrintAccumulator printAccum;
+ printAccum.parts.append(DerivedTy::pyClassName);
+ printAccum.parts.append("(");
+ mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
+ printAccum.parts.append(")");
+ return printAccum.join();
+ });
+
+ if (DerivedTy::getTypeIdFunction) {
+ PyGlobals::get().registerTypeCaster(
+ DerivedTy::getTypeIdFunction(),
+ nanobind::cast<nanobind::callable>(nanobind::cpp_function(
+ [](PyType pyType) -> DerivedTy { return pyType; })));
+ }
+
+ DerivedTy::bindDerived(cls);
+ }
/// Implemented by derived classes to add methods to the Python subclass.
static void bindDerived(ClassTy &m) {}
@@ -1008,15 +1013,15 @@ class PyAttribute : public BaseContextObject {
MlirAttribute get() const { return attr; }
/// Gets a capsule wrapping the void* within the MlirAttribute.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
/// Note that PyAttribute instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirAttribute
/// is taken by calling this function.
- static PyAttribute createFromCapsule(pybind11::object capsule);
+ static PyAttribute createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirAttribute attr;
};
@@ -1054,71 +1059,80 @@ class PyConcreteAttribute : public BaseTy {
// Derived classes must define statics for:
// IsAFunctionTy isaFunction
// const char *pyClassName
- using ClassTy = pybind11::class_<DerivedTy, BaseTy>;
- using IsAFunctionTy = bool (*)(MlirAttribute);
- using GetTypeIDFunctionTy = MlirTypeID (*)();
- static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
-
- PyConcreteAttribute() = default;
- PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
- : BaseTy(std::move(contextRef), attr) {}
- PyConcreteAttribute(PyAttribute &orig)
- : PyConcreteAttribute(orig.getContext(), castFrom(orig)) {}
-
- static MlirAttribute castFrom(PyAttribute &orig) {
- if (!DerivedTy::isaFunction(orig)) {
- auto origRepr = pybind11::repr(pybind11::cast(orig)).cast<std::string>();
- throw py::value_error((llvm::Twine("Cannot cast attribute to ") +
- DerivedTy::pyClassName + " (from " + origRepr +
- ")")
- .str());
- }
- return orig;
- }
-
- static void bind(pybind11::module &m) {
- auto cls = ClassTy(m, DerivedTy::pyClassName, pybind11::buffer_protocol(),
- pybind11::module_local());
- cls.def(pybind11::init<PyAttribute &>(), pybind11::keep_alive<0, 1>(),
- pybind11::arg("cast_from_attr"));
- cls.def_static(
- "isinstance",
- [](PyAttribute &otherAttr) -> bool {
- return DerivedTy::isaFunction(otherAttr);
- },
- pybind11::arg("other"));
- cls.def_property_readonly(
- "type", [](PyAttribute &attr) { return mlirAttributeGetType(attr); });
- cls.def_property_readonly_static(
- "static_typeid", [](py::object & /*class*/) -> MlirTypeID {
- if (DerivedTy::getTypeIdFunction)
- return DerivedTy::getTypeIdFunction();
- throw py::attribute_error(
- (DerivedTy::pyClassName + llvm::Twine(" has no typeid.")).str());
- });
- cls.def_property_readonly("typeid", [](PyAttribute &self) {
- return py::cast(self).attr("typeid").cast<MlirTypeID>();
- });
- cls.def("__repr__", [](DerivedTy &self) {
- PyPrintAccumulator printAccum;
- printAccum.parts.append(DerivedTy::pyClassName);
- printAccum.parts.append("(");
- mlirAttributePrint(self, printAccum.getCallback(),
- printAccum.getUserData());
- printAccum.parts.append(")");
- return printAccum.join();
- });
-
- if (DerivedTy::getTypeIdFunction) {
- PyGlobals::get().registerTypeCaster(
- DerivedTy::getTypeIdFunction(),
- pybind11::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
- return pyAttribute;
- }));
- }
-
- DerivedTy::bindDerived(cls);
- }
+ using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
+ using IsAFunctionTy = bool (*)(MlirAttribute);
+ using GetTypeIDFunctionTy = MlirTypeID (*)();
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
+
+ PyConcreteAttribute() = default;
+ PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
+ : BaseTy(std::move(contextRef), attr) {}
+ PyConcreteAttribute(PyAttribute &orig)
+ : PyConcreteAttribute(orig.getContext(), castFrom(orig)) {}
+
+ static MlirAttribute castFrom(PyAttribute &orig) {
+ if (!DerivedTy::isaFunction(orig)) {
+ auto origRepr =
+ nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
+ throw nanobind::value_error((llvm::Twine("Cannot cast attribute to ") +
+ DerivedTy::pyClassName + " (from " +
+ origRepr + ")")
+ .str()
+ .c_str());
+ }
+ return orig;
+ }
+
+ static void bind(nanobind::module_ &m, PyType_Slot *slots = nullptr) {
+ ClassTy cls;
+ if (slots) {
+ cls = ClassTy(m, DerivedTy::pyClassName, nanobind::type_slots(slots));
+ } else {
+ cls = ClassTy(m, DerivedTy::pyClassName);
+ }
+ cls.def(nanobind::init<PyAttribute &>(), nanobind::keep_alive<0, 1>(),
+ nanobind::arg("cast_from_attr"));
+ cls.def_static(
+ "isinstance",
+ [](PyAttribute &otherAttr) -> bool {
+ return DerivedTy::isaFunction(otherAttr);
+ },
+ nanobind::arg("other"));
+ cls.def_prop_ro(
+ "type", [](PyAttribute &attr) { return mlirAttributeGetType(attr); });
+ cls.def_prop_ro_static(
+ "static_typeid", [](nanobind::object & /*class*/) -> MlirTypeID {
+ if (DerivedTy::getTypeIdFunction)
+ return DerivedTy::getTypeIdFunction();
+ throw nanobind::attribute_error(
+ (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
+ .str()
+ .c_str());
+ });
+ cls.def_prop_ro("typeid", [](PyAttribute &self) {
+ return nanobind::cast<MlirTypeID>(nanobind::cast(self).attr("typeid"));
+ });
+ cls.def("__repr__", [](DerivedTy &self) {
+ PyPrintAccumulator printAccum;
+ printAccum.parts.append(DerivedTy::pyClassName);
+ printAccum.parts.append("(");
+ mlirAttributePrint(self, printAccum.getCallback(),
+ printAccum.getUserData());
+ printAccum.parts.append(")");
+ return printAccum.join();
+ });
+
+ if (DerivedTy::getTypeIdFunction) {
+ PyGlobals::get().registerTypeCaster(
+ DerivedTy::getTypeIdFunction(),
+ nanobind::cast<nanobind::callable>(
+ nanobind::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
+ return pyAttribute;
+ })));
+ }
+
+ DerivedTy::bindDerived(cls);
+ }
/// Implemented by derived classes to add methods to the Python subclass.
static void bindDerived(ClassTy &m) {}
@@ -1146,15 +1160,15 @@ class PyValue {
void checkValid() { return parentOperation->checkValid(); }
/// Gets a capsule wrapping the void* within the MlirValue.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
- pybind11::object maybeDownCast();
+ nanobind::object maybeDownCast();
/// Creates a PyValue from the MlirValue wrapped by a capsule. Ownership of
/// the underlying MlirValue is still tied to the owning operation.
- static PyValue createFromCapsule(pybind11::object capsule);
+ static PyValue createFromCapsule(nanobind::object capsule);
-private:
+ private:
PyOperationRef parentOperation;
MlirValue value;
};
@@ -1169,13 +1183,13 @@ class PyAffineExpr : public BaseContextObject {
MlirAffineExpr get() const { return affineExpr; }
/// Gets a capsule wrapping the void* within the MlirAffineExpr.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule.
/// Note that PyAffineExpr instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirAffineExpr
/// is taken by calling this function.
- static PyAffineExpr createFromCapsule(pybind11::object capsule);
+ static PyAffineExpr createFromCapsule(nanobind::object capsule);
PyAffineExpr add(const PyAffineExpr &other) const;
PyAffineExpr mul(const PyAffineExpr &other) const;
@@ -1196,15 +1210,15 @@ class PyAffineMap : public BaseContextObject {
MlirAffineMap get() const { return affineMap; }
/// Gets a capsule wrapping the void* within the MlirAffineMap.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule.
/// Note that PyAffineMap instances are uniqued, so the returned object
/// may be a pre-existing object. Ownership of the underlying MlirAffineMap
/// is taken by calling this function.
- static PyAffineMap createFromCapsule(pybind11::object capsule);
+ static PyAffineMap createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirAffineMap affineMap;
};
@@ -1217,14 +1231,14 @@ class PyIntegerSet : public BaseContextObject {
MlirIntegerSet get() const { return integerSet; }
/// Gets a capsule wrapping the void* within the MlirIntegerSet.
- pybind11::object getCapsule();
+ nanobind::object getCapsule();
/// Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule.
/// Note that PyIntegerSet instances may be uniqued, so the returned object
/// may be a pre-existing object. Integer sets are owned by the context.
- static PyIntegerSet createFromCapsule(pybind11::object capsule);
+ static PyIntegerSet createFromCapsule(nanobind::object capsule);
-private:
+ private:
MlirIntegerSet integerSet;
};
@@ -1239,7 +1253,7 @@ class PySymbolTable {
/// Returns the symbol (opview) with the given name, throws if there is no
/// such symbol in the table.
- pybind11::object dunderGetItem(const std::string &name);
+ nanobind::object dunderGetItem(const std::string &name);
/// Removes the given operation from the symbol table and erases it.
void erase(PyOperationBase &symbol);
@@ -1269,7 +1283,7 @@ class PySymbolTable {
/// Walks all symbol tables under and including 'from'.
static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible,
- pybind11::object callback);
+ nanobind::object callback);
/// Casts the bindings class into the C API structure.
operator MlirSymbolTable() { return symbolTable; }
@@ -1289,16 +1303,16 @@ struct MLIRError {
std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
};
-void populateIRAffine(pybind11::module &m);
-void populateIRAttributes(pybind11::module &m);
-void populateIRCore(pybind11::module &m);
-void populateIRInterfaces(pybind11::module &m);
-void populateIRTypes(pybind11::module &m);
+void populateIRAffine(nanobind::module_ &m);
+void populateIRAttributes(nanobind::module_ &m);
+void populateIRCore(nanobind::module_ &m);
+void populateIRInterfaces(nanobind::module_ &m);
+void populateIRTypes(nanobind::module_ &m);
} // namespace python
} // namespace mlir
-namespace pybind11 {
+namespace nanobind {
namespace detail {
template <>
@@ -1309,6 +1323,6 @@ struct type_caster<mlir::python::DefaultingPyLocation>
: MlirDefaultingCaster<mlir::python::DefaultingPyLocation> {};
} // namespace detail
-} // namespace pybind11
+} // namespace nanobind
#endif // MLIR_BINDINGS_PYTHON_IRMODULES_H
diff --git a/mlir/lib/Bindings/Python/IRTypes.cpp b/mlir/lib/Bindings/Python/IRTypes.cpp
index 6f192bc4bffeef..40c314dc794b66 100644
--- a/mlir/lib/Bindings/Python/IRTypes.cpp
+++ b/mlir/lib/Bindings/Python/IRTypes.cpp
@@ -6,19 +6,23 @@
//
//===----------------------------------------------------------------------===//
-#include "IRModule.h"
+#include "mlir/Bindings/Python/IRTypes.h"
-#include "PybindUtils.h"
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/optional.h>
+#include <nanobind/stl/pair.h>
+#include <nanobind/stl/string.h>
+#include <nanobind/stl/vector.h>
-#include "mlir/Bindings/Python/IRTypes.h"
+#include <optional>
+#include "IRModule.h"
+#include "NanobindUtils.h"
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/BuiltinTypes.h"
#include "mlir-c/Support.h"
-#include <optional>
-
-namespace py = pybind11;
+namespace nb = nanobind;
using namespace mlir;
using namespace mlir::python;
@@ -48,7 +52,7 @@ class PyIntegerType : public PyConcreteType<PyIntegerType> {
MlirType t = mlirIntegerTypeGet(context->get(), width);
return PyIntegerType(context->getRef(), t);
},
- py::arg("width"), py::arg("context") = py::none(),
+ nb::arg("width"), nb::arg("context").none() = nb::none(),
"Create a signless integer type");
c.def_static(
"get_signed",
@@ -56,7 +60,7 @@ class PyIntegerType : public PyConcreteType<PyIntegerType> {
MlirType t = mlirIntegerTypeSignedGet(context->get(), width);
return PyIntegerType(context->getRef(), t);
},
- py::arg("width"), py::arg("context") = py::none(),
+ nb::arg("width"), nb::arg("context").none() = nb::none(),
"Create a signed integer type");
c.def_static(
"get_unsigned",
@@ -64,25 +68,25 @@ class PyIntegerType : public PyConcreteType<PyIntegerType> {
MlirType t = mlirIntegerTypeUnsignedGet(context->get(), width);
return PyIntegerType(context->getRef(), t);
},
- py::arg("width"), py::arg("context") = py::none(),
+ nb::arg("width"), nb::arg("context").none() = nb::none(),
"Create an unsigned integer type");
- c.def_property_readonly(
+ c.def_prop_ro(
"width",
[](PyIntegerType &self) { return mlirIntegerTypeGetWidth(self); },
"Returns the width of the integer type");
- c.def_property_readonly(
+ c.def_prop_ro(
"is_signless",
[](PyIntegerType &self) -> bool {
return mlirIntegerTypeIsSignless(self);
},
"Returns whether this is a signless integer");
- c.def_property_readonly(
+ c.def_prop_ro(
"is_signed",
[](PyIntegerType &self) -> bool {
return mlirIntegerTypeIsSigned(self);
},
"Returns whether this is a signed integer");
- c.def_property_readonly(
+ c.def_prop_ro(
"is_unsigned",
[](PyIntegerType &self) -> bool {
return mlirIntegerTypeIsUnsigned(self);
@@ -107,7 +111,7 @@ class PyIndexType : public PyConcreteType<PyIndexType> {
MlirType t = mlirIndexTypeGet(context->get());
return PyIndexType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a index type.");
+ nb::arg("context").none() = nb::none(), "Create a index type.");
}
};
@@ -118,7 +122,7 @@ class PyFloatType : public PyConcreteType<PyFloatType> {
using PyConcreteType::PyConcreteType;
static void bindDerived(ClassTy &c) {
- c.def_property_readonly(
+ c.def_prop_ro(
"width", [](PyFloatType &self) { return mlirFloatTypeGetWidth(self); },
"Returns the width of the floating-point type");
}
@@ -141,7 +145,7 @@ class PyFloat4E2M1FNType
MlirType t = mlirFloat4E2M1FNTypeGet(context->get());
return PyFloat4E2M1FNType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float4_e2m1fn type.");
+ nb::arg("context").none() = nb::none(), "Create a float4_e2m1fn type.");
}
};
@@ -162,7 +166,7 @@ class PyFloat6E2M3FNType
MlirType t = mlirFloat6E2M3FNTypeGet(context->get());
return PyFloat6E2M3FNType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float6_e2m3fn type.");
+ nb::arg("context").none() = nb::none(), "Create a float6_e2m3fn type.");
}
};
@@ -183,7 +187,7 @@ class PyFloat6E3M2FNType
MlirType t = mlirFloat6E3M2FNTypeGet(context->get());
return PyFloat6E3M2FNType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float6_e3m2fn type.");
+ nb::arg("context").none() = nb::none(), "Create a float6_e3m2fn type.");
}
};
@@ -204,7 +208,7 @@ class PyFloat8E4M3FNType
MlirType t = mlirFloat8E4M3FNTypeGet(context->get());
return PyFloat8E4M3FNType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e4m3fn type.");
+ nb::arg("context").none() = nb::none(), "Create a float8_e4m3fn type.");
}
};
@@ -224,7 +228,7 @@ class PyFloat8E5M2Type : public PyConcreteType<PyFloat8E5M2Type, PyFloatType> {
MlirType t = mlirFloat8E5M2TypeGet(context->get());
return PyFloat8E5M2Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e5m2 type.");
+ nb::arg("context").none() = nb::none(), "Create a float8_e5m2 type.");
}
};
@@ -244,7 +248,7 @@ class PyFloat8E4M3Type : public PyConcreteType<PyFloat8E4M3Type, PyFloatType> {
MlirType t = mlirFloat8E4M3TypeGet(context->get());
return PyFloat8E4M3Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e4m3 type.");
+ nb::arg("context").none() = nb::none(), "Create a float8_e4m3 type.");
}
};
@@ -265,7 +269,8 @@ class PyFloat8E4M3FNUZType
MlirType t = mlirFloat8E4M3FNUZTypeGet(context->get());
return PyFloat8E4M3FNUZType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e4m3fnuz type.");
+ nb::arg("context").none() = nb::none(),
+ "Create a float8_e4m3fnuz type.");
}
};
@@ -286,7 +291,8 @@ class PyFloat8E4M3B11FNUZType
MlirType t = mlirFloat8E4M3B11FNUZTypeGet(context->get());
return PyFloat8E4M3B11FNUZType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e4m3b11fnuz type.");
+ nb::arg("context").none() = nb::none(),
+ "Create a float8_e4m3b11fnuz type.");
}
};
@@ -307,7 +313,8 @@ class PyFloat8E5M2FNUZType
MlirType t = mlirFloat8E5M2FNUZTypeGet(context->get());
return PyFloat8E5M2FNUZType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e5m2fnuz type.");
+ nb::arg("context").none() = nb::none(),
+ "Create a float8_e5m2fnuz type.");
}
};
@@ -327,7 +334,7 @@ class PyFloat8E3M4Type : public PyConcreteType<PyFloat8E3M4Type, PyFloatType> {
MlirType t = mlirFloat8E3M4TypeGet(context->get());
return PyFloat8E3M4Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e3m4 type.");
+ nb::arg("context").none() = nb::none(), "Create a float8_e3m4 type.");
}
};
@@ -348,7 +355,8 @@ class PyFloat8E8M0FNUType
MlirType t = mlirFloat8E8M0FNUTypeGet(context->get());
return PyFloat8E8M0FNUType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a float8_e8m0fnu type.");
+ nb::arg("context").none() = nb::none(),
+ "Create a float8_e8m0fnu type.");
}
};
@@ -368,7 +376,7 @@ class PyBF16Type : public PyConcreteType<PyBF16Type, PyFloatType> {
MlirType t = mlirBF16TypeGet(context->get());
return PyBF16Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a bf16 type.");
+ nb::arg("context").none() = nb::none(), "Create a bf16 type.");
}
};
@@ -388,7 +396,7 @@ class PyF16Type : public PyConcreteType<PyF16Type, PyFloatType> {
MlirType t = mlirF16TypeGet(context->get());
return PyF16Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a f16 type.");
+ nb::arg("context").none() = nb::none(), "Create a f16 type.");
}
};
@@ -408,7 +416,7 @@ class PyTF32Type : public PyConcreteType<PyTF32Type, PyFloatType> {
MlirType t = mlirTF32TypeGet(context->get());
return PyTF32Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a tf32 type.");
+ nb::arg("context").none() = nb::none(), "Create a tf32 type.");
}
};
@@ -428,7 +436,7 @@ class PyF32Type : public PyConcreteType<PyF32Type, PyFloatType> {
MlirType t = mlirF32TypeGet(context->get());
return PyF32Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a f32 type.");
+ nb::arg("context").none() = nb::none(), "Create a f32 type.");
}
};
@@ -448,7 +456,7 @@ class PyF64Type : public PyConcreteType<PyF64Type, PyFloatType> {
MlirType t = mlirF64TypeGet(context->get());
return PyF64Type(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a f64 type.");
+ nb::arg("context").none() = nb::none(), "Create a f64 type.");
}
};
@@ -468,7 +476,7 @@ class PyNoneType : public PyConcreteType<PyNoneType> {
MlirType t = mlirNoneTypeGet(context->get());
return PyNoneType(context->getRef(), t);
},
- py::arg("context") = py::none(), "Create a none type.");
+ nb::arg("context").none() = nb::none(), "Create a none type.");
}
};
@@ -490,14 +498,15 @@ class PyComplexType : public PyConcreteType<PyComplexType> {
MlirType t = mlirComplexTypeGet(elementType);
return PyComplexType(elementType.getContext(), t);
}
- throw py::value_error(
+ throw nb::value_error(
(Twine("invalid '") +
- py::repr(py::cast(elementType)).cast<std::string>() +
+ nb::cast<std::string>(nb::repr(nb::cast(elementType))) +
"' and expected floating point or integer type.")
- .str());
+ .str()
+ .c_str());
},
"Create a complex type");
- c.def_property_readonly(
+ c.def_prop_ro(
"element_type",
[](PyComplexType &self) { return mlirComplexTypeGetElementType(self); },
"Returns element type.");
@@ -508,22 +517,22 @@ class PyComplexType : public PyConcreteType<PyComplexType> {
// Shaped Type Interface - ShapedType
void mlir::PyShapedType::bindDerived(ClassTy &c) {
- c.def_property_readonly(
+ c.def_prop_ro(
"element_type",
[](PyShapedType &self) { return mlirShapedTypeGetElementType(self); },
"Returns the element type of the shaped type.");
- c.def_property_readonly(
+ c.def_prop_ro(
"has_rank",
[](PyShapedType &self) -> bool { return mlirShapedTypeHasRank(self); },
"Returns whether the given shaped type is ranked.");
- c.def_property_readonly(
+ c.def_prop_ro(
"rank",
[](PyShapedType &self) {
self.requireHasRank();
return mlirShapedTypeGetRank(self);
},
"Returns the rank of the given ranked shaped type.");
- c.def_property_readonly(
+ c.def_prop_ro(
"has_static_shape",
[](PyShapedType &self) -> bool {
return mlirShapedTypeHasStaticShape(self);
@@ -535,7 +544,7 @@ void mlir::PyShapedType::bindDerived(ClassTy &c) {
self.requireHasRank();
return mlirShapedTypeIsDynamicDim(self, dim);
},
- py::arg("dim"),
+ nb::arg("dim"),
"Returns whether the dim-th dimension of the given shaped type is "
"dynamic.");
c.def(
@@ -544,12 +553,12 @@ void mlir::PyShapedType::bindDerived(ClassTy &c) {
self.requireHasRank();
return mlirShapedTypeGetDimSize(self, dim);
},
- py::arg("dim"),
+ nb::arg("dim"),
"Returns the dim-th dimension of the given ranked shaped type.");
c.def_static(
"is_dynamic_size",
[](int64_t size) -> bool { return mlirShapedTypeIsDynamicSize(size); },
- py::arg("dim_size"),
+ nb::arg("dim_size"),
"Returns whether the given dimension size indicates a dynamic "
"dimension.");
c.def(
@@ -558,10 +567,10 @@ void mlir::PyShapedType::bindDerived(ClassTy &c) {
self.requireHasRank();
return mlirShapedTypeIsDynamicStrideOrOffset(val);
},
- py::arg("dim_size"),
+ nb::arg("dim_size"),
"Returns whether the given value is used as a placeholder for dynamic "
"strides and offsets in shaped types.");
- c.def_property_readonly(
+ c.def_prop_ro(
"shape",
[](PyShapedType &self) {
self.requireHasRank();
@@ -587,7 +596,7 @@ void mlir::PyShapedType::bindDerived(ClassTy &c) {
void mlir::PyShapedType::requireHasRank() {
if (!mlirShapedTypeHasRank(*this)) {
- throw py::value_error(
+ throw nb::value_error(
"calling this method requires that the type has a rank.");
}
}
@@ -607,15 +616,15 @@ class PyVectorType : public PyConcreteType<PyVectorType, PyShapedType> {
using PyConcreteType::PyConcreteType;
static void bindDerived(ClassTy &c) {
- c.def_static("get", &PyVectorType::get, py::arg("shape"),
- py::arg("element_type"), py::kw_only(),
- py::arg("scalable") = py::none(),
- py::arg("scalable_dims") = py::none(),
- py::arg("loc") = py::none(), "Create a vector type")
- .def_property_readonly(
+ c.def_static("get", &PyVectorType::get, nb::arg("shape"),
+ nb::arg("element_type"), nb::kw_only(),
+ nb::arg("scalable").none() = nb::none(),
+ nb::arg("scalable_dims").none() = nb::none(),
+ nb::arg("loc").none() = nb::none(), "Create a vector type")
+ .def_prop_ro(
"scalable",
[](MlirType self) { return mlirVectorTypeIsScalable(self); })
- .def_property_readonly("scalable_dims", [](MlirType self) {
+ .def_prop_ro("scalable_dims", [](MlirType self) {
std::vector<bool> scalableDims;
size_t rank = static_cast<size_t>(mlirShapedTypeGetRank(self));
scalableDims.reserve(rank);
@@ -626,44 +635,42 @@ class PyVectorType : public PyConcreteType<PyVectorType, PyShapedType> {
}
private:
- static PyVectorType get(std::vector<int64_t> shape, PyType &elementType,
- std::optional<py::list> scalable,
- std::optional<std::vector<int64_t>> scalableDims,
- DefaultingPyLocation loc) {
- if (scalable && scalableDims) {
- throw py::value_error("'scalable' and 'scalable_dims' kwargs "
- "are mutually exclusive.");
- }
-
- PyMlirContext::ErrorCapture errors(loc->getContext());
- MlirType type;
- if (scalable) {
- if (scalable->size() != shape.size())
- throw py::value_error("Expected len(scalable) == len(shape).");
-
- SmallVector<bool> scalableDimFlags = llvm::to_vector(llvm::map_range(
- *scalable, [](const py::handle &h) { return h.cast<bool>(); }));
- type = mlirVectorTypeGetScalableChecked(loc, shape.size(), shape.data(),
- scalableDimFlags.data(),
- elementType);
- } else if (scalableDims) {
- SmallVector<bool> scalableDimFlags(shape.size(), false);
- for (int64_t dim : *scalableDims) {
- if (static_cast<size_t>(dim) >= scalableDimFlags.size() || dim < 0)
- throw py::value_error("Scalable dimension index out of bounds.");
- scalableDimFlags[dim] = true;
- }
- type = mlirVectorTypeGetScalableChecked(loc, shape.size(), shape.data(),
- scalableDimFlags.data(),
- elementType);
- } else {
- type = mlirVectorTypeGetChecked(loc, shape.size(), shape.data(),
- elementType);
- }
- if (mlirTypeIsNull(type))
- throw MLIRError("Invalid type", errors.take());
- return PyVectorType(elementType.getContext(), type);
- }
+ static PyVectorType get(std::vector<int64_t> shape, PyType &elementType,
+ std::optional<nb::list> scalable,
+ std::optional<std::vector<int64_t>> scalableDims,
+ DefaultingPyLocation loc) {
+ if (scalable && scalableDims) {
+ throw nb::value_error(
+ "'scalable' and 'scalable_dims' kwargs "
+ "are mutually exclusive.");
+ }
+
+ PyMlirContext::ErrorCapture errors(loc->getContext());
+ MlirType type;
+ if (scalable) {
+ if (scalable->size() != shape.size())
+ throw nb::value_error("Expected len(scalable) == len(shape).");
+
+ SmallVector<bool> scalableDimFlags = llvm::to_vector(llvm::map_range(
+ *scalable, [](const nb::handle &h) { return nb::cast<bool>(h); }));
+ type = mlirVectorTypeGetScalableChecked(
+ loc, shape.size(), shape.data(), scalableDimFlags.data(), elementType);
+ } else if (scalableDims) {
+ SmallVector<bool> scalableDimFlags(shape.size(), false);
+ for (int64_t dim : *scalableDims) {
+ if (static_cast<size_t>(dim) >= scalableDimFlags.size() || dim < 0)
+ throw nb::value_error("Scalable dimension index out of bounds.");
+ scalableDimFlags[dim] = true;
+ }
+ type = mlirVectorTypeGetScalableChecked(
+ loc, shape.size(), shape.data(), scalableDimFlags.data(), elementType);
+ } else {
+ type =
+ mlirVectorTypeGetChecked(loc, shape.size(), shape.data(), elementType);
+ }
+ if (mlirTypeIsNull(type)) throw MLIRError("Invalid type", errors.take());
+ return PyVectorType(elementType.getContext(), type);
+ }
};
/// Ranked Tensor Type subclass - RankedTensorType.
@@ -689,17 +696,16 @@ class PyRankedTensorType
throw MLIRError("Invalid type", errors.take());
return PyRankedTensorType(elementType.getContext(), t);
},
- py::arg("shape"), py::arg("element_type"),
- py::arg("encoding") = py::none(), py::arg("loc") = py::none(),
- "Create a ranked tensor type");
- c.def_property_readonly(
- "encoding",
- [](PyRankedTensorType &self) -> std::optional<MlirAttribute> {
- MlirAttribute encoding = mlirRankedTensorTypeGetEncoding(self.get());
- if (mlirAttributeIsNull(encoding))
- return std::nullopt;
- return encoding;
- });
+ nb::arg("shape"), nb::arg("element_type"),
+ nb::arg("encoding").none() = nb::none(),
+ nb::arg("loc").none() = nb::none(), "Create a ranked tensor type");
+ c.def_prop_ro("encoding",
+ [](PyRankedTensorType &self) -> std::optional<MlirAttribute> {
+ MlirAttribute encoding =
+ mlirRankedTensorTypeGetEncoding(self.get());
+ if (mlirAttributeIsNull(encoding)) return std::nullopt;
+ return encoding;
+ });
}
};
@@ -723,7 +729,7 @@ class PyUnrankedTensorType
throw MLIRError("Invalid type", errors.take());
return PyUnrankedTensorType(elementType.getContext(), t);
},
- py::arg("element_type"), py::arg("loc") = py::none(),
+ nb::arg("element_type"), nb::arg("loc").none() = nb::none(),
"Create a unranked tensor type");
}
};
@@ -754,10 +760,11 @@ class PyMemRefType : public PyConcreteType<PyMemRefType, PyShapedType> {
throw MLIRError("Invalid type", errors.take());
return PyMemRefType(elementType.getContext(), t);
},
- py::arg("shape"), py::arg("element_type"),
- py::arg("layout") = py::none(), py::arg("memory_space") = py::none(),
- py::arg("loc") = py::none(), "Create a memref type")
- .def_property_readonly(
+ nb::arg("shape"), nb::arg("element_type"),
+ nb::arg("layout").none() = nb::none(),
+ nb::arg("memory_space").none() = nb::none(),
+ nb::arg("loc").none() = nb::none(), "Create a memref type")
+ .def_prop_ro(
"layout",
[](PyMemRefType &self) -> MlirAttribute {
return mlirMemRefTypeGetLayout(self);
@@ -775,14 +782,14 @@ class PyMemRefType : public PyConcreteType<PyMemRefType, PyShapedType> {
return {strides, offset};
},
"The strides and offset of the MemRef type.")
- .def_property_readonly(
+ .def_prop_ro(
"affine_map",
[](PyMemRefType &self) -> PyAffineMap {
MlirAffineMap map = mlirMemRefTypeGetAffineMap(self);
return PyAffineMap(self.getContext(), map);
},
"The layout of the MemRef type as an affine map.")
- .def_property_readonly(
+ .def_prop_ro(
"memory_space",
[](PyMemRefType &self) -> std::optional<MlirAttribute> {
MlirAttribute a = mlirMemRefTypeGetMemorySpace(self);
@@ -820,9 +827,9 @@ class PyUnrankedMemRefType
throw MLIRError("Invalid type", errors.take());
return PyUnrankedMemRefType(elementType.getContext(), t);
},
- py::arg("element_type"), py::arg("memory_space"),
- py::arg("loc") = py::none(), "Create a unranked memref type")
- .def_property_readonly(
+ nb::arg("element_type"), nb::arg("memory_space").none(),
+ nb::arg("loc").none() = nb::none(), "Create a unranked memref type")
+ .def_prop_ro(
"memory_space",
[](PyUnrankedMemRefType &self) -> std::optional<MlirAttribute> {
MlirAttribute a = mlirUnrankedMemrefGetMemorySpace(self);
@@ -851,15 +858,15 @@ class PyTupleType : public PyConcreteType<PyTupleType> {
elements.data());
return PyTupleType(context->getRef(), t);
},
- py::arg("elements"), py::arg("context") = py::none(),
+ nb::arg("elements"), nb::arg("context").none() = nb::none(),
"Create a tuple type");
c.def(
"get_type",
[](PyTupleType &self, intptr_t pos) {
return mlirTupleTypeGetType(self, pos);
},
- py::arg("pos"), "Returns the pos-th type in the tuple type.");
- c.def_property_readonly(
+ nb::arg("pos"), "Returns the pos-th type in the tuple type.");
+ c.def_prop_ro(
"num_types",
[](PyTupleType &self) -> intptr_t {
return mlirTupleTypeGetNumTypes(self);
@@ -887,13 +894,14 @@ class PyFunctionType : public PyConcreteType<PyFunctionType> {
results.size(), results.data());
return PyFunctionType(context->getRef(), t);
},
- py::arg("inputs"), py::arg("results"), py::arg("context") = py::none(),
+ nb::arg("inputs"), nb::arg("results"),
+ nb::arg("context").none() = nb::none(),
"Gets a FunctionType from a list of input and result types");
- c.def_property_readonly(
+ c.def_prop_ro(
"inputs",
[](PyFunctionType &self) {
MlirType t = self;
- py::list types;
+ nb::list types;
for (intptr_t i = 0, e = mlirFunctionTypeGetNumInputs(self); i < e;
++i) {
types.append(mlirFunctionTypeGetInput(t, i));
@@ -901,10 +909,10 @@ class PyFunctionType : public PyConcreteType<PyFunctionType> {
return types;
},
"Returns the list of input types in the FunctionType.");
- c.def_property_readonly(
+ c.def_prop_ro(
"results",
[](PyFunctionType &self) {
- py::list types;
+ nb::list types;
for (intptr_t i = 0, e = mlirFunctionTypeGetNumResults(self); i < e;
++i) {
types.append(mlirFunctionTypeGetResult(self, i));
@@ -938,21 +946,21 @@ class PyOpaqueType : public PyConcreteType<PyOpaqueType> {
toMlirStringRef(typeData));
return PyOpaqueType(context->getRef(), type);
},
- py::arg("dialect_namespace"), py::arg("buffer"),
- py::arg("context") = py::none(),
+ nb::arg("dialect_namespace"), nb::arg("buffer"),
+ nb::arg("context").none() = nb::none(),
"Create an unregistered (opaque) dialect type.");
- c.def_property_readonly(
+ c.def_prop_ro(
"dialect_namespace",
[](PyOpaqueType &self) {
MlirStringRef stringRef = mlirOpaqueTypeGetDialectNamespace(self);
- return py::str(stringRef.data, stringRef.length);
+ return nb::str(stringRef.data, stringRef.length);
},
"Returns the dialect namespace for the Opaque type as a string.");
- c.def_property_readonly(
+ c.def_prop_ro(
"data",
[](PyOpaqueType &self) {
MlirStringRef stringRef = mlirOpaqueTypeGetData(self);
- return py::str(stringRef.data, stringRef.length);
+ return nb::str(stringRef.data, stringRef.length);
},
"Returns the data for the Opaque type as a string.");
}
@@ -960,7 +968,7 @@ class PyOpaqueType : public PyConcreteType<PyOpaqueType> {
} // namespace
-void mlir::python::populateIRTypes(py::module &m) {
+void mlir::python::populateIRTypes(nb::module_ &m) {
PyIntegerType::bind(m);
PyFloatType::bind(m);
PyIndexType::bind(m);
diff --git a/mlir/lib/Bindings/Python/MainModule.cpp b/mlir/lib/Bindings/Python/MainModule.cpp
index 7c27021902de31..e5e64a921a79ad 100644
--- a/mlir/lib/Bindings/Python/MainModule.cpp
+++ b/mlir/lib/Bindings/Python/MainModule.cpp
@@ -6,29 +6,31 @@
//
//===----------------------------------------------------------------------===//
-#include "PybindUtils.h"
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/string.h>
#include "Globals.h"
#include "IRModule.h"
+#include "NanobindUtils.h"
#include "Pass.h"
#include "Rewrite.h"
-namespace py = pybind11;
+namespace nb = nanobind;
using namespace mlir;
-using namespace py::literals;
+using namespace nb::literals;
using namespace mlir::python;
// -----------------------------------------------------------------------------
// Module initialization.
// -----------------------------------------------------------------------------
-PYBIND11_MODULE(_mlir, m) {
+NB_MODULE(_mlir, m) {
m.doc() = "MLIR Python Native Extension";
- py::class_<PyGlobals>(m, "_Globals", py::module_local())
- .def_property("dialect_search_modules",
- &PyGlobals::getDialectSearchPrefixes,
- &PyGlobals::setDialectSearchPrefixes)
+ nb::class_<PyGlobals>(m, "_Globals")
+ .def_prop_rw("dialect_search_modules",
+ &PyGlobals::getDialectSearchPrefixes,
+ &PyGlobals::setDialectSearchPrefixes)
.def(
"append_dialect_search_prefix",
[](PyGlobals &self, std::string moduleName) {
@@ -45,22 +47,21 @@ PYBIND11_MODULE(_mlir, m) {
"dialect_namespace"_a, "dialect_class"_a,
"Testing hook for directly registering a dialect")
.def("_register_operation_impl", &PyGlobals::registerOperationImpl,
- "operation_name"_a, "operation_class"_a, py::kw_only(),
+ "operation_name"_a, "operation_class"_a, nb::kw_only(),
"replace"_a = false,
"Testing hook for directly registering an operation");
// Aside from making the globals accessible to python, having python manage
// it is necessary to make sure it is destroyed (and releases its python
// resources) properly.
- m.attr("globals") =
- py::cast(new PyGlobals, py::return_value_policy::take_ownership);
+ m.attr("globals") = nb::cast(new PyGlobals, nb::rv_policy::take_ownership);
// Registration decorators.
m.def(
"register_dialect",
- [](py::type pyClass) {
+ [](nb::type_object pyClass) {
std::string dialectNamespace =
- pyClass.attr("DIALECT_NAMESPACE").cast<std::string>();
+ nanobind::cast<std::string>(pyClass.attr("DIALECT_NAMESPACE"));
PyGlobals::get().registerDialectImpl(dialectNamespace, pyClass);
return pyClass;
},
@@ -68,45 +69,46 @@ PYBIND11_MODULE(_mlir, m) {
"Class decorator for registering a custom Dialect wrapper");
m.def(
"register_operation",
- [](const py::type &dialectClass, bool replace) -> py::cpp_function {
- return py::cpp_function(
- [dialectClass, replace](py::type opClass) -> py::type {
+ [](const nb::type_object &dialectClass, bool replace) -> nb::object {
+ return nb::cpp_function(
+ [dialectClass,
+ replace](nb::type_object opClass) -> nb::type_object {
std::string operationName =
- opClass.attr("OPERATION_NAME").cast<std::string>();
+ nanobind::cast<std::string>(opClass.attr("OPERATION_NAME"));
PyGlobals::get().registerOperationImpl(operationName, opClass,
replace);
// Dict-stuff the new opClass by name onto the dialect class.
- py::object opClassName = opClass.attr("__name__");
+ nb::object opClassName = opClass.attr("__name__");
dialectClass.attr(opClassName) = opClass;
return opClass;
});
},
- "dialect_class"_a, py::kw_only(), "replace"_a = false,
+ "dialect_class"_a, nb::kw_only(), "replace"_a = false,
"Produce a class decorator for registering an Operation class as part of "
"a dialect");
m.def(
MLIR_PYTHON_CAPI_TYPE_CASTER_REGISTER_ATTR,
- [](MlirTypeID mlirTypeID, bool replace) -> py::cpp_function {
- return py::cpp_function([mlirTypeID,
- replace](py::object typeCaster) -> py::object {
+ [](MlirTypeID mlirTypeID, bool replace) -> nb::object {
+ return nb::cpp_function([mlirTypeID, replace](
+ nb::callable typeCaster) -> nb::object {
PyGlobals::get().registerTypeCaster(mlirTypeID, typeCaster, replace);
return typeCaster;
});
},
- "typeid"_a, py::kw_only(), "replace"_a = false,
+ "typeid"_a, nb::kw_only(), "replace"_a = false,
"Register a type caster for casting MLIR types to custom user types.");
m.def(
MLIR_PYTHON_CAPI_VALUE_CASTER_REGISTER_ATTR,
- [](MlirTypeID mlirTypeID, bool replace) -> py::cpp_function {
- return py::cpp_function(
- [mlirTypeID, replace](py::object valueCaster) -> py::object {
+ [](MlirTypeID mlirTypeID, bool replace) -> nb::object {
+ return nb::cpp_function(
+ [mlirTypeID, replace](nb::callable valueCaster) -> nb::object {
PyGlobals::get().registerValueCaster(mlirTypeID, valueCaster,
replace);
return valueCaster;
});
},
- "typeid"_a, py::kw_only(), "replace"_a = false,
+ "typeid"_a, nb::kw_only(), "replace"_a = false,
"Register a value caster for casting MLIR values to custom user values.");
// Define and populate IR submodule.
diff --git a/mlir/lib/Bindings/Python/PybindUtils.h b/mlir/lib/Bindings/Python/NanobindUtils.h
similarity index 82%
rename from mlir/lib/Bindings/Python/PybindUtils.h
rename to mlir/lib/Bindings/Python/NanobindUtils.h
index 38462ac8ba6db9..117151581889bf 100644
--- a/mlir/lib/Bindings/Python/PybindUtils.h
+++ b/mlir/lib/Bindings/Python/NanobindUtils.h
@@ -1,4 +1,5 @@
-//===- PybindUtils.h - Utilities for interop with pybind11 ------*- C++ -*-===//
+//===- NanobindUtils.h - Utilities for interop with nanobind ------*- C++
+//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -9,13 +10,21 @@
#ifndef MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
#define MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
-#include "mlir-c/Support.h"
+#include <nanobind/nanobind.h>
+
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/DataTypes.h"
+#include "mlir-c/Support.h"
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
+template <>
+struct std::iterator_traits<nanobind::detail::fast_iterator> {
+ using value_type = nanobind::handle;
+ using reference = const value_type;
+ using pointer = void;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::forward_iterator_tag;
+};
namespace mlir {
namespace python {
@@ -37,7 +46,7 @@ namespace python {
template <typename DerivedTy, typename T>
class Defaulting {
-public:
+ public:
using ReferrentTy = T;
/// Type casters require the type to be default constructible, but using
/// such an instance is illegal.
@@ -47,21 +56,21 @@ class Defaulting {
ReferrentTy *get() const { return referrent; }
ReferrentTy *operator->() { return referrent; }
-private:
+ private:
ReferrentTy *referrent = nullptr;
};
-} // namespace python
-} // namespace mlir
+} // namespace python
+} // namespace mlir
-namespace pybind11 {
+namespace nanobind {
namespace detail {
template <typename DefaultingTy>
struct MlirDefaultingCaster {
- PYBIND11_TYPE_CASTER(DefaultingTy, _(DefaultingTy::kTypeDescription));
+ NB_TYPE_CASTER(DefaultingTy, const_name(DefaultingTy::kTypeDescription));
- bool load(pybind11::handle src, bool) {
+ bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) {
if (src.is_none()) {
// Note that we do want an exception to propagate from here as it will be
// the most informative.
@@ -76,20 +85,20 @@ struct MlirDefaultingCaster {
// code to produce nice error messages (other than "Cannot cast...").
try {
value = DefaultingTy{
- pybind11::cast<typename DefaultingTy::ReferrentTy &>(src)};
+ nanobind::cast<typename DefaultingTy::ReferrentTy &>(src)};
return true;
} catch (std::exception &) {
return false;
}
}
- static handle cast(DefaultingTy src, return_value_policy policy,
- handle parent) {
- return pybind11::cast(src, policy);
+ static handle from_cpp(DefaultingTy src, rv_policy policy,
+ cleanup_list *cleanup) noexcept {
+ return nanobind::cast(src, policy);
}
};
-} // namespace detail
-} // namespace pybind11
+} // namespace detail
+} // namespace nanobind
//------------------------------------------------------------------------------
// Conversion utilities.
@@ -100,7 +109,7 @@ namespace mlir {
/// Accumulates into a python string from a method that accepts an
/// MlirStringCallback.
struct PyPrintAccumulator {
- pybind11::list parts;
+ nanobind::list parts;
void *getUserData() { return this; }
@@ -108,45 +117,45 @@ struct PyPrintAccumulator {
return [](MlirStringRef part, void *userData) {
PyPrintAccumulator *printAccum =
static_cast<PyPrintAccumulator *>(userData);
- pybind11::str pyPart(part.data,
- part.length); // Decodes as UTF-8 by default.
+ nanobind::str pyPart(part.data,
+ part.length); // Decodes as UTF-8 by default.
printAccum->parts.append(std::move(pyPart));
};
}
- pybind11::str join() {
- pybind11::str delim("", 0);
- return delim.attr("join")(parts);
+ nanobind::str join() {
+ nanobind::str delim("", 0);
+ return nanobind::cast<nanobind::str>(delim.attr("join")(parts));
}
};
/// Accumulates int a python file-like object, either writing text (default)
/// or binary.
class PyFileAccumulator {
-public:
- PyFileAccumulator(const pybind11::object &fileObject, bool binary)
+ public:
+ PyFileAccumulator(const nanobind::object &fileObject, bool binary)
: pyWriteFunction(fileObject.attr("write")), binary(binary) {}
void *getUserData() { return this; }
MlirStringCallback getCallback() {
return [](MlirStringRef part, void *userData) {
- pybind11::gil_scoped_acquire acquire;
+ nanobind::gil_scoped_acquire acquire;
PyFileAccumulator *accum = static_cast<PyFileAccumulator *>(userData);
if (accum->binary) {
// Note: Still has to copy and not avoidable with this API.
- pybind11::bytes pyBytes(part.data, part.length);
+ nanobind::bytes pyBytes(part.data, part.length);
accum->pyWriteFunction(pyBytes);
} else {
- pybind11::str pyStr(part.data,
- part.length); // Decodes as UTF-8 by default.
+ nanobind::str pyStr(part.data,
+ part.length); // Decodes as UTF-8 by default.
accum->pyWriteFunction(pyStr);
}
};
}
-private:
- pybind11::object pyWriteFunction;
+ private:
+ nanobind::object pyWriteFunction;
bool binary;
};
@@ -163,17 +172,17 @@ struct PySinglePartStringAccumulator {
assert(!accum->invoked &&
"PySinglePartStringAccumulator called back multiple times");
accum->invoked = true;
- accum->value = pybind11::str(part.data, part.length);
+ accum->value = nanobind::str(part.data, part.length);
};
}
- pybind11::str takeValue() {
+ nanobind::str takeValue() {
assert(invoked && "PySinglePartStringAccumulator not called back");
return std::move(value);
}
-private:
- pybind11::str value;
+ private:
+ nanobind::str value;
bool invoked = false;
};
@@ -207,16 +216,14 @@ struct PySinglePartStringAccumulator {
/// the python class.
template <typename Derived, typename ElementTy>
class Sliceable {
-protected:
- using ClassTy = pybind11::class_<Derived>;
+ protected:
+ using ClassTy = nanobind::class_<Derived>;
/// Transforms `index` into a legal value to access the underlying sequence.
/// Returns <0 on failure.
intptr_t wrapIndex(intptr_t index) {
- if (index < 0)
- index = length + index;
- if (index < 0 || index >= length)
- return -1;
+ if (index < 0) index = length + index;
+ if (index < 0 || index >= length) return -1;
return index;
}
@@ -237,7 +244,7 @@ class Sliceable {
/// Returns the element at the given slice index. Supports negative indices
/// by taking elements in inverse order. Returns a nullptr object if out
/// of bounds.
- pybind11::object getItem(intptr_t index) {
+ nanobind::object getItem(intptr_t index) {
// Negative indices mean we count from the end.
index = wrapIndex(index);
if (index < 0) {
@@ -250,24 +257,24 @@ class Sliceable {
->getRawElement(linearizeIndex(index))
.maybeDownCast();
else
- return pybind11::cast(
+ return nanobind::cast(
static_cast<Derived *>(this)->getRawElement(linearizeIndex(index)));
}
/// Returns a new instance of the pseudo-container restricted to the given
/// slice. Returns a nullptr object on failure.
- pybind11::object getItemSlice(PyObject *slice) {
+ nanobind::object getItemSlice(PyObject *slice) {
ssize_t start, stop, extraStep, sliceLength;
if (PySlice_GetIndicesEx(slice, length, &start, &stop, &extraStep,
&sliceLength) != 0) {
PyErr_SetString(PyExc_IndexError, "index out of range");
return {};
}
- return pybind11::cast(static_cast<Derived *>(this)->slice(
+ return nanobind::cast(static_cast<Derived *>(this)->slice(
startIndex + start * step, sliceLength, step * extraStep));
}
-public:
+ public:
explicit Sliceable(intptr_t startIndex, intptr_t length, intptr_t step)
: startIndex(startIndex), length(length), step(step) {
assert(length >= 0 && "expected non-negative slice length");
@@ -279,7 +286,7 @@ class Sliceable {
// Negative indices mean we count from the end.
index = wrapIndex(index);
if (index < 0) {
- throw pybind11::index_error("index out of range");
+ throw nanobind::index_error("index out of range");
}
return static_cast<Derived *>(this)->getRawElement(linearizeIndex(index));
@@ -304,39 +311,38 @@ class Sliceable {
}
/// Binds the indexing and length methods in the Python class.
- static void bind(pybind11::module &m) {
- auto clazz = pybind11::class_<Derived>(m, Derived::pyClassName,
- pybind11::module_local())
+ static void bind(nanobind::module_ &m) {
+ auto clazz = nanobind::class_<Derived>(m, Derived::pyClassName)
.def("__add__", &Sliceable::dunderAdd);
Derived::bindDerived(clazz);
// Manually implement the sequence protocol via the C API. We do this
- // because it is approx 4x faster than via pybind11, largely because that
+ // because it is approx 4x faster than via nanobind, largely because that
// formulation requires a C++ exception to be thrown to detect end of
// sequence.
// Since we are in a C-context, any C++ exception that happens here
// will terminate the program. There is nothing in this implementation
// that should throw in a non-terminal way, so we forgo further
// exception marshalling.
- // See: https://github.com/pybind/pybind11/issues/2842
+ // See: https://github.com/pybind/nanobind/issues/2842
auto heap_type = reinterpret_cast<PyHeapTypeObject *>(clazz.ptr());
assert(heap_type->ht_type.tp_flags & Py_TPFLAGS_HEAPTYPE &&
"must be heap type");
heap_type->as_sequence.sq_length = +[](PyObject *rawSelf) -> Py_ssize_t {
- auto self = pybind11::cast<Derived *>(rawSelf);
+ auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
return self->length;
};
// sq_item is called as part of the sequence protocol for iteration,
// list construction, etc.
heap_type->as_sequence.sq_item =
+[](PyObject *rawSelf, Py_ssize_t index) -> PyObject * {
- auto self = pybind11::cast<Derived *>(rawSelf);
+ auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
return self->getItem(index).release().ptr();
};
// mp_subscript is used for both slices and integer lookups.
heap_type->as_mapping.mp_subscript =
+[](PyObject *rawSelf, PyObject *rawSubscript) -> PyObject * {
- auto self = pybind11::cast<Derived *>(rawSelf);
+ auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
Py_ssize_t index = PyNumber_AsSsize_t(rawSubscript, PyExc_IndexError);
if (!PyErr_Occurred()) {
// Integer indexing.
@@ -357,13 +363,13 @@ class Sliceable {
/// Hook for derived classes willing to bind more methods.
static void bindDerived(ClassTy &) {}
-private:
+ private:
intptr_t startIndex;
intptr_t length;
intptr_t step;
};
-} // namespace mlir
+} // namespace mlir
namespace llvm {
@@ -384,6 +390,6 @@ struct DenseMapInfo<MlirTypeID> {
return mlirTypeIDEqual(lhs, rhs);
}
};
-} // namespace llvm
+} // namespace llvm
-#endif // MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
+#endif // MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
diff --git a/mlir/lib/Bindings/Python/Pass.cpp b/mlir/lib/Bindings/Python/Pass.cpp
index e8d28abe6d583a..368797f093ea0d 100644
--- a/mlir/lib/Bindings/Python/Pass.cpp
+++ b/mlir/lib/Bindings/Python/Pass.cpp
@@ -8,12 +8,16 @@
#include "Pass.h"
+#include <nanobind/nanobind.h>
+#include <nanobind/stl/optional.h>
+#include <nanobind/stl/string.h>
+
#include "IRModule.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir-c/Pass.h"
-namespace py = pybind11;
-using namespace py::literals;
+namespace nb = nanobind;
+using namespace nb::literals;
using namespace mlir;
using namespace mlir::python;
@@ -34,16 +38,14 @@ class PyPassManager {
MlirPassManager get() { return passManager; }
void release() { passManager.ptr = nullptr; }
- pybind11::object getCapsule() {
- return py::reinterpret_steal<py::object>(
- mlirPythonPassManagerToCapsule(get()));
+ nb::object getCapsule() {
+ return nb::steal<nb::object>(mlirPythonPassManagerToCapsule(get()));
}
- static pybind11::object createFromCapsule(pybind11::object capsule) {
+ static nb::object createFromCapsule(nb::object capsule) {
MlirPassManager rawPm = mlirPythonCapsuleToPassManager(capsule.ptr());
- if (mlirPassManagerIsNull(rawPm))
- throw py::error_already_set();
- return py::cast(PyPassManager(rawPm), py::return_value_policy::move);
+ if (mlirPassManagerIsNull(rawPm)) throw nb::python_error();
+ return nb::cast(PyPassManager(rawPm), nb::rv_policy::move);
}
private:
@@ -53,22 +55,23 @@ class PyPassManager {
} // namespace
/// Create the `mlir.passmanager` here.
-void mlir::python::populatePassManagerSubmodule(py::module &m) {
+void mlir::python::populatePassManagerSubmodule(nb::module_ &m) {
//----------------------------------------------------------------------------
// Mapping of the top-level PassManager
//----------------------------------------------------------------------------
- py::class_<PyPassManager>(m, "PassManager", py::module_local())
- .def(py::init<>([](const std::string &anchorOp,
- DefaultingPyMlirContext context) {
- MlirPassManager passManager = mlirPassManagerCreateOnOperation(
- context->get(),
- mlirStringRefCreate(anchorOp.data(), anchorOp.size()));
- return new PyPassManager(passManager);
- }),
- "anchor_op"_a = py::str("any"), "context"_a = py::none(),
- "Create a new PassManager for the current (or provided) Context.")
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyPassManager::getCapsule)
+ nb::class_<PyPassManager>(m, "PassManager")
+ .def(
+ "__init__",
+ [](PyPassManager &self, const std::string &anchorOp,
+ DefaultingPyMlirContext context) {
+ MlirPassManager passManager = mlirPassManagerCreateOnOperation(
+ context->get(),
+ mlirStringRefCreate(anchorOp.data(), anchorOp.size()));
+ new (&self) PyPassManager(passManager);
+ },
+ "anchor_op"_a = nb::str("any"), "context"_a = nb::none(),
+ "Create a new PassManager for the current (or provided) Context.")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyPassManager::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyPassManager::createFromCapsule)
.def("_testing_release", &PyPassManager::release,
"Releases (leaks) the backing pass manager (testing)")
@@ -90,7 +93,7 @@ void mlir::python::populatePassManagerSubmodule(py::module &m) {
"print_before_all"_a = false, "print_after_all"_a = true,
"print_module_scope"_a = false, "print_after_change"_a = false,
"print_after_failure"_a = false,
- "tree_printing_dir_path"_a = py::none(),
+ "tree_printing_dir_path"_a = nb::none(),
"Enable IR printing, default as mlir-print-ir-after-all.")
.def(
"enable_verifier",
@@ -108,10 +111,10 @@ void mlir::python::populatePassManagerSubmodule(py::module &m) {
mlirStringRefCreate(pipeline.data(), pipeline.size()),
errorMsg.getCallback(), errorMsg.getUserData());
if (mlirLogicalResultIsFailure(status))
- throw py::value_error(std::string(errorMsg.join()));
+ throw nb::value_error(errorMsg.join().c_str());
return new PyPassManager(passManager);
},
- "pipeline"_a, "context"_a = py::none(),
+ "pipeline"_a, "context"_a = nb::none(),
"Parse a textual pass-pipeline and return a top-level PassManager "
"that can be applied on a Module. Throw a ValueError if the pipeline "
"can't be parsed")
@@ -124,7 +127,7 @@ void mlir::python::populatePassManagerSubmodule(py::module &m) {
mlirStringRefCreate(pipeline.data(), pipeline.size()),
errorMsg.getCallback(), errorMsg.getUserData());
if (mlirLogicalResultIsFailure(status))
- throw py::value_error(std::string(errorMsg.join()));
+ throw nb::value_error(errorMsg.join().c_str());
},
"pipeline"_a,
"Add textual pipeline elements to the pass manager. Throws a "
diff --git a/mlir/lib/Bindings/Python/Pass.h b/mlir/lib/Bindings/Python/Pass.h
index 3a500d5e8257ac..bc409435218299 100644
--- a/mlir/lib/Bindings/Python/Pass.h
+++ b/mlir/lib/Bindings/Python/Pass.h
@@ -9,12 +9,12 @@
#ifndef MLIR_BINDINGS_PYTHON_PASS_H
#define MLIR_BINDINGS_PYTHON_PASS_H
-#include "PybindUtils.h"
+#include "NanobindUtils.h"
namespace mlir {
namespace python {
-void populatePassManagerSubmodule(pybind11::module &m);
+void populatePassManagerSubmodule(nanobind::module_ &m);
} // namespace python
} // namespace mlir
diff --git a/mlir/lib/Bindings/Python/Rewrite.cpp b/mlir/lib/Bindings/Python/Rewrite.cpp
index 1d8128be9f0826..2048b888e7398a 100644
--- a/mlir/lib/Bindings/Python/Rewrite.cpp
+++ b/mlir/lib/Bindings/Python/Rewrite.cpp
@@ -8,14 +8,16 @@
#include "Rewrite.h"
+#include <nanobind/nanobind.h>
+
#include "IRModule.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir-c/Rewrite.h"
#include "mlir/Config/mlir-config.h"
-namespace py = pybind11;
+namespace nb = nanobind;
using namespace mlir;
-using namespace py::literals;
+using namespace nb::literals;
using namespace mlir::python;
namespace {
@@ -54,18 +56,16 @@ class PyFrozenRewritePatternSet {
}
MlirFrozenRewritePatternSet get() { return set; }
- pybind11::object getCapsule() {
- return py::reinterpret_steal<py::object>(
+ nb::object getCapsule() {
+ return nb::steal<nb::object>(
mlirPythonFrozenRewritePatternSetToCapsule(get()));
}
- static pybind11::object createFromCapsule(pybind11::object capsule) {
+ static nb::object createFromCapsule(nb::object capsule) {
MlirFrozenRewritePatternSet rawPm =
mlirPythonCapsuleToFrozenRewritePatternSet(capsule.ptr());
- if (rawPm.ptr == nullptr)
- throw py::error_already_set();
- return py::cast(PyFrozenRewritePatternSet(rawPm),
- py::return_value_policy::move);
+ if (rawPm.ptr == nullptr) throw nb::python_error();
+ return nb::cast(PyFrozenRewritePatternSet(rawPm), nb::rv_policy::move);
}
private:
@@ -75,25 +75,27 @@ class PyFrozenRewritePatternSet {
} // namespace
/// Create the `mlir.rewrite` here.
-void mlir::python::populateRewriteSubmodule(py::module &m) {
+void mlir::python::populateRewriteSubmodule(nb::module_ &m) {
//----------------------------------------------------------------------------
// Mapping of the top-level PassManager
//----------------------------------------------------------------------------
#if MLIR_ENABLE_PDL_IN_PATTERNMATCH
- py::class_<PyPDLPatternModule>(m, "PDLModule", py::module_local())
- .def(py::init<>([](MlirModule module) {
- return mlirPDLPatternModuleFromModule(module);
- }),
- "module"_a, "Create a PDL module from the given module.")
+ nb::class_<PyPDLPatternModule>(m, "PDLModule")
+ .def(
+ "__init__",
+ [](PyPDLPatternModule &self, MlirModule module) {
+ new (&self)
+ PyPDLPatternModule(mlirPDLPatternModuleFromModule(module));
+ },
+ "module"_a, "Create a PDL module from the given module.")
.def("freeze", [](PyPDLPatternModule &self) {
return new PyFrozenRewritePatternSet(mlirFreezeRewritePattern(
mlirRewritePatternSetFromPDLPatternModule(self.get())));
});
-#endif // MLIR_ENABLE_PDL_IN_PATTERNMATCg
- py::class_<PyFrozenRewritePatternSet>(m, "FrozenRewritePatternSet",
- py::module_local())
- .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
- &PyFrozenRewritePatternSet::getCapsule)
+#endif // MLIR_ENABLE_PDL_IN_PATTERNMATCH
+ nb::class_<PyFrozenRewritePatternSet>(m, "FrozenRewritePatternSet")
+ .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR,
+ &PyFrozenRewritePatternSet::getCapsule)
.def(MLIR_PYTHON_CAPI_FACTORY_ATTR,
&PyFrozenRewritePatternSet::createFromCapsule);
m.def(
@@ -102,7 +104,7 @@ void mlir::python::populateRewriteSubmodule(py::module &m) {
auto status = mlirApplyPatternsAndFoldGreedily(module, set, {});
if (mlirLogicalResultIsFailure(status))
// FIXME: Not sure this is the right error to throw here.
- throw py::value_error("pattern application failed to converge");
+ throw nb::value_error("pattern application failed to converge");
},
"module"_a, "set"_a,
"Applys the given patterns to the given module greedily while folding "
diff --git a/mlir/lib/Bindings/Python/Rewrite.h b/mlir/lib/Bindings/Python/Rewrite.h
index 997b80adda3038..ae89e2b9589f13 100644
--- a/mlir/lib/Bindings/Python/Rewrite.h
+++ b/mlir/lib/Bindings/Python/Rewrite.h
@@ -9,12 +9,12 @@
#ifndef MLIR_BINDINGS_PYTHON_REWRITE_H
#define MLIR_BINDINGS_PYTHON_REWRITE_H
-#include "PybindUtils.h"
+#include "NanobindUtils.h"
namespace mlir {
namespace python {
-void populateRewriteSubmodule(pybind11::module &m);
+void populateRewriteSubmodule(nanobind::module_ &m);
} // namespace python
} // namespace mlir
diff --git a/mlir/python/CMakeLists.txt b/mlir/python/CMakeLists.txt
index e1b870b53ad25c..d3ca940b408276 100644
--- a/mlir/python/CMakeLists.txt
+++ b/mlir/python/CMakeLists.txt
@@ -440,6 +440,7 @@ declare_mlir_python_extension(MLIRPythonExtension.Core
MODULE_NAME _mlir
ADD_TO_PARENT MLIRPythonSources.Core
ROOT_DIR "${PYTHON_SOURCE_DIR}"
+ PYTHON_BINDINGS_LIBRARY nanobind
SOURCES
MainModule.cpp
IRAffine.cpp
@@ -455,7 +456,7 @@ declare_mlir_python_extension(MLIRPythonExtension.Core
Globals.h
IRModule.h
Pass.h
- PybindUtils.h
+ NanobindUtils.h
Rewrite.h
PRIVATE_LINK_LIBS
LLVMSupport
diff --git a/mlir/test/python/ir/symbol_table.py b/mlir/test/python/ir/symbol_table.py
index 577721ab2111f5..8b6d7ea5a197d7 100644
--- a/mlir/test/python/ir/symbol_table.py
+++ b/mlir/test/python/ir/symbol_table.py
@@ -176,5 +176,6 @@ def error_callback(symbol_table_op, uses_visible):
try:
SymbolTable.walk_symbol_tables(m.operation, True, error_callback)
except RuntimeError as e:
- # CHECK: GOT EXCEPTION: Exception raised in callback: AssertionError: Raised from python
+ # CHECK: GOT EXCEPTION: Exception raised in callback:
+ # CHECK: AssertionError: Raised from python
print(f"GOT EXCEPTION: {e}")
More information about the Mlir-commits
mailing list