[Mlir-commits] [mlir] [MLIR][Python] Remove partial LLVM APIs in python bindings (3/n) (PR #178984)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Feb 2 08:26:55 PST 2026


https://github.com/RattataKing updated https://github.com/llvm/llvm-project/pull/178984

>From c464c34a1362ea0232572a33719d298bdcc536ce Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 18:57:34 +0000
Subject: [PATCH 1/9] Remove stringRef

---
 mlir/include/mlir/Bindings/Python/Globals.h |  7 ++++---
 mlir/lib/Bindings/Python/Globals.cpp        | 12 ++++++------
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Globals.h b/mlir/include/mlir/Bindings/Python/Globals.h
index 6a722575c4e48..42c38f020d7b5 100644
--- a/mlir/include/mlir/Bindings/Python/Globals.h
+++ b/mlir/include/mlir/Bindings/Python/Globals.h
@@ -12,6 +12,7 @@
 #include <optional>
 #include <regex>
 #include <string>
+#include <string_view>
 #include <unordered_set>
 #include <vector>
 
@@ -60,7 +61,7 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
   /// Note that this returns void because it is expected that the module
   /// contains calls to decorators and helpers that register the salient
   /// entities. Returns true if dialect is successfully loaded.
-  bool loadDialectModule(llvm::StringRef dialectNamespace);
+  bool loadDialectModule(std::string_view dialectNamespace);
 
   /// Adds a user-friendly Attribute builder.
   /// Raises an exception if the mapping already exists and replace == false.
@@ -121,7 +122,7 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
   /// name. Note that this may trigger a load of the dialect, which can
   /// arbitrarily re-enter.
   std::optional<nanobind::object>
-  lookupOperationClass(llvm::StringRef operationName);
+  lookupOperationClass(std::string_view operationName);
 
   /// Looks up a registered operation adaptor class by operation
   /// name. Note that this may trigger a load of the dialect, which can
@@ -143,7 +144,7 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
 
     void registerTracebackFileExclusion(const std::string &file);
 
-    bool isUserTracebackFilename(llvm::StringRef file);
+    bool isUserTracebackFilename(std::string_view file);
 
     static constexpr size_t kMaxFrames = 512;
 
diff --git a/mlir/lib/Bindings/Python/Globals.cpp b/mlir/lib/Bindings/Python/Globals.cpp
index 3d7ee3d30656e..5c1c767e95b4d 100644
--- a/mlir/lib/Bindings/Python/Globals.cpp
+++ b/mlir/lib/Bindings/Python/Globals.cpp
@@ -46,7 +46,7 @@ PyGlobals &PyGlobals::get() {
   return *instance;
 }
 
-bool PyGlobals::loadDialectModule(llvm::StringRef dialectNamespace) {
+bool PyGlobals::loadDialectModule(std::string_view dialectNamespace) {
   {
     nb::ft_lock_guard lock(mutex);
     if (loadedDialectModules.contains(dialectNamespace))
@@ -202,10 +202,10 @@ PyGlobals::lookupDialectClass(const std::string &dialectNamespace) {
 }
 
 std::optional<nb::object>
-PyGlobals::lookupOperationClass(llvm::StringRef operationName) {
+PyGlobals::lookupOperationClass(std::string_view operationName) {
   // Make sure dialect module is loaded.
-  auto split = operationName.split('.');
-  llvm::StringRef dialectNamespace = split.first;
+  size_t splitPos = operationName.find('.');
+  std::string_view dialectNamespace = operationName.substr(0, splitPos);
   if (!loadDialectModule(dialectNamespace))
     return std::nullopt;
 
@@ -282,7 +282,7 @@ void PyGlobals::TracebackLoc::registerTracebackFileExclusion(
 }
 
 bool PyGlobals::TracebackLoc::isUserTracebackFilename(
-    const llvm::StringRef file) {
+    const std::string_view file) {
   nanobind::ft_lock_guard lock(mutex);
   if (rebuildUserTracebackIncludeRegex) {
     userTracebackIncludeRegex.assign(
@@ -297,7 +297,7 @@ bool PyGlobals::TracebackLoc::isUserTracebackFilename(
     isUserTracebackFilenameCache.clear();
   }
   if (!isUserTracebackFilenameCache.contains(file)) {
-    std::string fileStr = file.str();
+    std::string fileStr(file);
     bool include = std::regex_search(fileStr, userTracebackIncludeRegex);
     bool exclude = std::regex_search(fileStr, userTracebackExcludeRegex);
     isUserTracebackFilenameCache[file] = include || !exclude;

>From fb173d0039e822a22b33771d10b43ee0ae4bb921 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 19:34:19 +0000
Subject: [PATCH 2/9] Replace raw_string_ostream

---
 mlir/include/mlir/Bindings/Python/Diagnostics.h | 15 +++++++++------
 mlir/lib/Bindings/Python/DialectLLVM.cpp        |  3 +--
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Diagnostics.h b/mlir/include/mlir/Bindings/Python/Diagnostics.h
index 167002d561931..e30bbd639aade 100644
--- a/mlir/include/mlir/Bindings/Python/Diagnostics.h
+++ b/mlir/include/mlir/Bindings/Python/Diagnostics.h
@@ -11,10 +11,10 @@
 
 #include "mlir-c/Diagnostics.h"
 #include "mlir-c/IR.h"
-#include "llvm/Support/raw_ostream.h"
 
 #include <cassert>
 #include <cstdint>
+#include <sstream>
 #include <string>
 
 namespace mlir {
@@ -35,6 +35,9 @@ class CollectDiagnosticsToStringScope {
   }
 
   [[nodiscard]] std::string takeMessage() {
+    message = messageStream.str();
+    messageStream.str("");
+    messageStream.clear();
     std::string newMessage;
     std::swap(message, newMessage);
     return newMessage;
@@ -43,16 +46,16 @@ class CollectDiagnosticsToStringScope {
 private:
   static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
     auto printer = +[](MlirStringRef message, void *data) {
-      *static_cast<llvm::raw_string_ostream *>(data)
+      *static_cast<std::ostringstream *>(data)
           << std::string_view(message.data, message.length);
     };
     MlirLocation loc = mlirDiagnosticGetLocation(diag);
-    *static_cast<llvm::raw_string_ostream *>(data) << "at ";
+    *static_cast<std::ostringstream *>(data) << "at ";
     mlirLocationPrint(loc, printer, data);
-    *static_cast<llvm::raw_string_ostream *>(data) << ": ";
+    *static_cast<std::ostringstream *>(data) << ": ";
     mlirDiagnosticPrint(diag, printer, data);
     for (intptr_t i = 0; i < mlirDiagnosticGetNumNotes(diag); i++) {
-      *static_cast<llvm::raw_string_ostream *>(data) << "\n";
+      *static_cast<std::ostringstream *>(data) << "\n";
       MlirDiagnostic note = mlirDiagnosticGetNote(diag, i);
       handler(note, data);
     }
@@ -63,7 +66,7 @@ class CollectDiagnosticsToStringScope {
   MlirDiagnosticHandlerID handlerID;
 
   std::string message;
-  llvm::raw_string_ostream messageStream{message};
+  std::ostringstream messageStream;
 };
 
 } // namespace python
diff --git a/mlir/lib/Bindings/Python/DialectLLVM.cpp b/mlir/lib/Bindings/Python/DialectLLVM.cpp
index 0c579cf261eca..dc06d0a3bf671 100644
--- a/mlir/lib/Bindings/Python/DialectLLVM.cpp
+++ b/mlir/lib/Bindings/Python/DialectLLVM.cpp
@@ -20,7 +20,6 @@
 namespace nb = nanobind;
 
 using namespace nanobind::literals;
-using namespace llvm;
 using namespace mlir;
 using namespace mlir::python::nanobind_adaptors;
 
@@ -135,7 +134,7 @@ struct StructType : PyConcreteType<StructType> {
             return std::nullopt;
 
           MlirStringRef stringRef = mlirLLVMStructTypeGetIdentifier(type);
-          return StringRef(stringRef.data, stringRef.length).str();
+          return std::string(stringRef.data, stringRef.length);
         });
 
     c.def_prop_ro("body", [](const StructType &type) -> nb::object {

>From 6be3f2b9e7b936e924f93bd1500af2b253dd7670 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 20:13:43 +0000
Subject: [PATCH 3/9] Replace densemap

---
 mlir/include/mlir/Bindings/Python/Globals.h | 22 ++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Globals.h b/mlir/include/mlir/Bindings/Python/Globals.h
index 42c38f020d7b5..aaf747e183207 100644
--- a/mlir/include/mlir/Bindings/Python/Globals.h
+++ b/mlir/include/mlir/Bindings/Python/Globals.h
@@ -13,6 +13,7 @@
 #include <regex>
 #include <string>
 #include <string_view>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
@@ -21,7 +22,6 @@
 #include "mlir/Bindings/Python/NanobindUtils.h"
 #include "mlir/CAPI/Support.h"
 
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
@@ -30,6 +30,18 @@
 namespace mlir {
 namespace python {
 namespace MLIR_BINDINGS_PYTHON_DOMAIN {
+struct MlirTypeIDHash {
+  size_t operator()(MlirTypeID typeID) const {
+    return mlirTypeIDHashValue(typeID);
+  }
+};
+
+struct MlirTypeIDEqual {
+  bool operator()(MlirTypeID lhs, MlirTypeID rhs) const {
+    return mlirTypeIDEqual(lhs, rhs);
+  }
+};
+
 /// Globals that are always accessible once the extension has been initialized.
 /// Methods of this class are thread-safe.
 class MLIR_PYTHON_API_EXPORTED PyGlobals {
@@ -202,9 +214,13 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
   /// Map of attribute ODS name to custom builder.
   llvm::StringMap<nanobind::callable> attributeBuilderMap;
   /// Map of MlirTypeID to custom type caster.
-  llvm::DenseMap<MlirTypeID, nanobind::callable> typeCasterMap;
+  std::unordered_map<MlirTypeID, nanobind::callable, MlirTypeIDHash,
+                     MlirTypeIDEqual>
+      typeCasterMap;
   /// Map of MlirTypeID to custom value caster.
-  llvm::DenseMap<MlirTypeID, nanobind::callable> valueCasterMap;
+  std::unordered_map<MlirTypeID, nanobind::callable, MlirTypeIDHash,
+                     MlirTypeIDEqual>
+      valueCasterMap;
   /// Set of dialect namespaces that we have attempted to import implementation
   /// modules for.
   llvm::StringSet<> loadedDialectModules;

>From ed5d2016e141a81cd77d7246d9a79c9a9e8fc9c8 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 21:02:15 +0000
Subject: [PATCH 4/9] Replace stringmap

---
 mlir/include/mlir/Bindings/Python/Globals.h | 10 +++++-----
 mlir/lib/Bindings/Python/Globals.cpp        | 15 +++++++++------
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Globals.h b/mlir/include/mlir/Bindings/Python/Globals.h
index aaf747e183207..c51652f708725 100644
--- a/mlir/include/mlir/Bindings/Python/Globals.h
+++ b/mlir/include/mlir/Bindings/Python/Globals.h
@@ -170,7 +170,7 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
     bool rebuildUserTracebackIncludeRegex = false;
     std::regex userTracebackExcludeRegex;
     bool rebuildUserTracebackExcludeRegex = false;
-    llvm::StringMap<bool> isUserTracebackFilenameCache;
+    std::unordered_map<std::string, bool> isUserTracebackFilenameCache;
   };
 
   TracebackLoc &getTracebackLoc() { return tracebackLoc; }
@@ -206,13 +206,13 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
   /// 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<nanobind::object> dialectClassMap;
+  std::unordered_map<std::string, nanobind::object> dialectClassMap;
   /// Map of full operation name to external operation class object.
-  llvm::StringMap<nanobind::object> operationClassMap;
+  std::unordered_map<std::string, nanobind::object> operationClassMap;
   /// Map of full operation name to external operation adaptor class object.
-  llvm::StringMap<nanobind::object> opAdaptorClassMap;
+  std::unordered_map<std::string, nanobind::object> opAdaptorClassMap;
   /// Map of attribute ODS name to custom builder.
-  llvm::StringMap<nanobind::callable> attributeBuilderMap;
+  std::unordered_map<std::string, nanobind::callable> attributeBuilderMap;
   /// Map of MlirTypeID to custom type caster.
   std::unordered_map<MlirTypeID, nanobind::callable, MlirTypeIDHash,
                      MlirTypeIDEqual>
diff --git a/mlir/lib/Bindings/Python/Globals.cpp b/mlir/lib/Bindings/Python/Globals.cpp
index 5c1c767e95b4d..58586ddf576c2 100644
--- a/mlir/lib/Bindings/Python/Globals.cpp
+++ b/mlir/lib/Bindings/Python/Globals.cpp
@@ -210,7 +210,8 @@ PyGlobals::lookupOperationClass(std::string_view operationName) {
     return std::nullopt;
 
   nb::ft_lock_guard lock(mutex);
-  auto foundIt = operationClassMap.find(operationName);
+  std::string operationNameStr(operationName);
+  auto foundIt = operationClassMap.find(operationNameStr);
   if (foundIt != operationClassMap.end()) {
     assert(foundIt->second && "OpView is defined");
     return foundIt->second;
@@ -228,7 +229,8 @@ PyGlobals::lookupOpAdaptorClass(llvm::StringRef operationName) {
     return std::nullopt;
 
   nb::ft_lock_guard lock(mutex);
-  auto foundIt = opAdaptorClassMap.find(operationName);
+  std::string operationNameStr(operationName);
+  auto foundIt = opAdaptorClassMap.find(operationNameStr);
   if (foundIt != opAdaptorClassMap.end()) {
     assert(foundIt->second && "OpAdaptor is defined");
     return foundIt->second;
@@ -296,13 +298,14 @@ bool PyGlobals::TracebackLoc::isUserTracebackFilename(
     rebuildUserTracebackExcludeRegex = false;
     isUserTracebackFilenameCache.clear();
   }
-  if (!isUserTracebackFilenameCache.contains(file)) {
-    std::string fileStr(file);
+  std::string fileStr(file);
+  const auto foundIt = isUserTracebackFilenameCache.find(fileStr);
+  if (foundIt == isUserTracebackFilenameCache.end()) {
     bool include = std::regex_search(fileStr, userTracebackIncludeRegex);
     bool exclude = std::regex_search(fileStr, userTracebackExcludeRegex);
-    isUserTracebackFilenameCache[file] = include || !exclude;
+    isUserTracebackFilenameCache[fileStr] = include || !exclude;
   }
-  return isUserTracebackFilenameCache[file];
+  return isUserTracebackFilenameCache[fileStr];
 }
 } // namespace MLIR_BINDINGS_PYTHON_DOMAIN
 } // namespace python

>From c43d9f8cb9a0f438f2517f27ebb641d9e8edaa1f Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 21:05:30 +0000
Subject: [PATCH 5/9] Replace stringset

---
 mlir/include/mlir/Bindings/Python/Globals.h | 3 +--
 mlir/lib/Bindings/Python/Globals.cpp        | 6 ++++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Globals.h b/mlir/include/mlir/Bindings/Python/Globals.h
index c51652f708725..fa1eb0bc13d20 100644
--- a/mlir/include/mlir/Bindings/Python/Globals.h
+++ b/mlir/include/mlir/Bindings/Python/Globals.h
@@ -24,7 +24,6 @@
 
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Regex.h"
 
 namespace mlir {
@@ -223,7 +222,7 @@ class MLIR_PYTHON_API_EXPORTED PyGlobals {
       valueCasterMap;
   /// Set of dialect namespaces that we have attempted to import implementation
   /// modules for.
-  llvm::StringSet<> loadedDialectModules;
+  std::unordered_set<std::string> loadedDialectModules;
 
   TracebackLoc tracebackLoc;
   TypeIDAllocator typeIDAllocator;
diff --git a/mlir/lib/Bindings/Python/Globals.cpp b/mlir/lib/Bindings/Python/Globals.cpp
index 58586ddf576c2..2838e74823d83 100644
--- a/mlir/lib/Bindings/Python/Globals.cpp
+++ b/mlir/lib/Bindings/Python/Globals.cpp
@@ -49,7 +49,9 @@ PyGlobals &PyGlobals::get() {
 bool PyGlobals::loadDialectModule(std::string_view dialectNamespace) {
   {
     nb::ft_lock_guard lock(mutex);
-    if (loadedDialectModules.contains(dialectNamespace))
+    std::string dialectNamespaceStr(dialectNamespace);
+    if (loadedDialectModules.find(dialectNamespaceStr) !=
+        loadedDialectModules.end())
       return true;
   }
   // Since re-entrancy is possible, make a copy of the search prefixes.
@@ -75,7 +77,7 @@ bool PyGlobals::loadDialectModule(std::string_view dialectNamespace) {
   // Note: Iterator cannot be shared from prior to loading, since re-entrancy
   // may have occurred, which may do anything.
   nb::ft_lock_guard lock(mutex);
-  loadedDialectModules.insert(dialectNamespace);
+  loadedDialectModules.insert(std::string(dialectNamespace));
   return true;
 }
 

>From 88e1129cc079ca58ee20565f95ff7e1c09841aa0 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 21:34:17 +0000
Subject: [PATCH 6/9] Replace raw_fd_ostream

---
 .../mlir/Bindings/Python/NanobindUtils.h      | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/NanobindUtils.h b/mlir/include/mlir/Bindings/Python/NanobindUtils.h
index 215daf245b902..71a5c4515920a 100644
--- a/mlir/include/mlir/Bindings/Python/NanobindUtils.h
+++ b/mlir/include/mlir/Bindings/Python/NanobindUtils.h
@@ -16,8 +16,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/DataTypes.h"
-#include "llvm/Support/raw_ostream.h"
-
+#include <fstream>
 #include <string>
 #include <typeinfo>
 #include <variant>
@@ -142,11 +141,14 @@ class PyFileAccumulator {
       : binary(binary) {
     std::string filePath;
     if (nanobind::try_cast<std::string>(fileOrStringObject, filePath)) {
-      std::error_code ec;
-      writeTarget.emplace<llvm::raw_fd_ostream>(filePath, ec);
-      if (ec) {
+      std::ios::openmode openMode = std::ios::out;
+      if (binary)
+        openMode |= std::ios::binary;
+      writeTarget.emplace<std::ofstream>(filePath, openMode);
+      auto &stream = std::get<std::ofstream>(writeTarget);
+      if (!stream) {
         throw nanobind::value_error(
-            (std::string("Unable to open file for writing: ") + ec.message())
+            (std::string("Unable to open file for writing: ") + filePath)
                 .c_str());
       }
     } else {
@@ -181,12 +183,11 @@ class PyFileAccumulator {
   MlirStringCallback getOstreamCallback() {
     return [](MlirStringRef part, void *userData) {
       PyFileAccumulator *accum = static_cast<PyFileAccumulator *>(userData);
-      std::get<llvm::raw_fd_ostream>(accum->writeTarget)
-          .write(part.data, part.length);
+      std::get<std::ofstream>(accum->writeTarget).write(part.data, part.length);
     };
   }
 
-  std::variant<nanobind::object, llvm::raw_fd_ostream> writeTarget;
+  std::variant<nanobind::object, std::ofstream> writeTarget;
   bool binary;
 };
 

>From 0315fe3c7e6d4d3f9a3e6e6e446bc1185c83d785 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 21:50:53 +0000
Subject: [PATCH 7/9] Move join to util and replace twine

---
 mlir/include/mlir/Bindings/Python/Globals.h   | 12 ------
 .../mlir/Bindings/Python/NanobindAdaptors.h   | 23 +++++-----
 .../mlir/Bindings/Python/NanobindUtils.h      | 42 +++++++++----------
 mlir/lib/Bindings/Python/IRCore.cpp           |  9 ----
 4 files changed, 31 insertions(+), 55 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Globals.h b/mlir/include/mlir/Bindings/Python/Globals.h
index fa1eb0bc13d20..bdcabea76cd3c 100644
--- a/mlir/include/mlir/Bindings/Python/Globals.h
+++ b/mlir/include/mlir/Bindings/Python/Globals.h
@@ -29,18 +29,6 @@
 namespace mlir {
 namespace python {
 namespace MLIR_BINDINGS_PYTHON_DOMAIN {
-struct MlirTypeIDHash {
-  size_t operator()(MlirTypeID typeID) const {
-    return mlirTypeIDHashValue(typeID);
-  }
-};
-
-struct MlirTypeIDEqual {
-  bool operator()(MlirTypeID lhs, MlirTypeID rhs) const {
-    return mlirTypeIDEqual(lhs, rhs);
-  }
-};
-
 /// Globals that are always accessible once the extension has been initialized.
 /// Methods of this class are thread-safe.
 class MLIR_PYTHON_API_EXPORTED PyGlobals {
diff --git a/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h b/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
index 6594670abaaa7..a9fd7a5d6ef71 100644
--- a/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
+++ b/mlir/include/mlir/Bindings/Python/NanobindAdaptors.h
@@ -30,7 +30,7 @@
 #include "mlir/Bindings/Python/Nanobind.h"
 #include "mlir-c/Bindings/Python/Interop.h" // This is expected after nanobind.
 // clang-format on
-#include "llvm/ADT/Twine.h"
+#include "mlir/Bindings/Python/NanobindUtils.h"
 
 namespace mlir {
 namespace python {
@@ -550,10 +550,9 @@ class mlir_attribute_subclass : public pure_subclass {
               !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());
+            throw std::invalid_argument(join("Cannot cast attribute to ",
+                                             captureTypeName, " (from ",
+                                             origRepr, ")"));
           }
           nanobind::object self = superCls.attr("__new__")(cls, otherAttribute);
           return self;
@@ -633,10 +632,9 @@ class mlir_type_subclass : public pure_subclass {
               !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());
+            throw std::invalid_argument(join("Cannot cast type to ",
+                                             captureTypeName, " (from ",
+                                             origRepr, ")"));
           }
           nanobind::object self = superCls.attr("__new__")(cls, otherType);
           return self;
@@ -720,10 +718,9 @@ class mlir_value_subclass : public pure_subclass {
               !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());
+            throw std::invalid_argument(join("Cannot cast value to ",
+                                             captureValueName, " (from ",
+                                             origRepr, ")"));
           }
           nanobind::object self = superCls.attr("__new__")(cls, otherValue);
           return self;
diff --git a/mlir/include/mlir/Bindings/Python/NanobindUtils.h b/mlir/include/mlir/Bindings/Python/NanobindUtils.h
index 71a5c4515920a..fe7371782e869 100644
--- a/mlir/include/mlir/Bindings/Python/NanobindUtils.h
+++ b/mlir/include/mlir/Bindings/Python/NanobindUtils.h
@@ -17,6 +17,7 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/DataTypes.h"
 #include <fstream>
+#include <sstream>
 #include <string>
 #include <typeinfo>
 #include <variant>
@@ -33,6 +34,26 @@ struct std::iterator_traits<nanobind::detail::fast_iterator> {
 namespace mlir {
 namespace python {
 
+/// Helper function to concatenate arguments into a `std::string`.
+template <typename... Ts>
+inline std::string join(const Ts &...args) {
+  std::ostringstream oss;
+  (oss << ... << args);
+  return oss.str();
+}
+
+struct MlirTypeIDHash {
+  size_t operator()(MlirTypeID typeID) const {
+    return mlirTypeIDHashValue(typeID);
+  }
+};
+
+struct MlirTypeIDEqual {
+  bool operator()(MlirTypeID lhs, MlirTypeID rhs) const {
+    return mlirTypeIDEqual(lhs, rhs);
+  }
+};
+
 /// CRTP template for special wrapper types that are allowed to be passed in as
 /// 'None' function arguments and can be resolved by some global mechanic if
 /// so. Such types will raise an error if this global resolution fails, and
@@ -413,25 +434,4 @@ class Sliceable {
 
 } // namespace mlir
 
-namespace llvm {
-
-template <>
-struct DenseMapInfo<MlirTypeID> {
-  static inline MlirTypeID getEmptyKey() {
-    auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
-    return mlirTypeIDCreate(pointer);
-  }
-  static inline MlirTypeID getTombstoneKey() {
-    auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
-    return mlirTypeIDCreate(pointer);
-  }
-  static inline unsigned getHashValue(const MlirTypeID &val) {
-    return mlirTypeIDHashValue(val);
-  }
-  static inline bool isEqual(const MlirTypeID &lhs, const MlirTypeID &rhs) {
-    return mlirTypeIDEqual(lhs, rhs);
-  }
-};
-} // namespace llvm
-
 #endif // MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 7f34343eba6c9..b0ae7199b33a2 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -21,7 +21,6 @@
 
 #include <functional>
 #include <optional>
-#include <sstream>
 #include <string>
 
 namespace nb = nanobind;
@@ -49,14 +48,6 @@ operations.
 // Utilities.
 //------------------------------------------------------------------------------
 
-/// Local helper to concatenate arguments into a `std::string`.
-template <typename... Ts>
-static std::string join(const Ts &...args) {
-  std::ostringstream oss;
-  (oss << ... << args);
-  return oss.str();
-}
-
 /// Local helper to compute std::hash for a value.
 template <typename T>
 static size_t hash(const T &value) {

>From ccf9f4d6a88e67b66d873ee71079ba3e4e095624 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Fri, 30 Jan 2026 22:30:28 +0000
Subject: [PATCH 8/9] Write helper for check has downcast

---
 mlir/include/mlir/Bindings/Python/NanobindUtils.h | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/NanobindUtils.h b/mlir/include/mlir/Bindings/Python/NanobindUtils.h
index fe7371782e869..5d4ee60e3ab04 100644
--- a/mlir/include/mlir/Bindings/Python/NanobindUtils.h
+++ b/mlir/include/mlir/Bindings/Python/NanobindUtils.h
@@ -19,6 +19,7 @@
 #include <fstream>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <typeinfo>
 #include <variant>
 
@@ -293,8 +294,12 @@ class Sliceable {
 
   /// Trait to check if T provides a `maybeDownCast` method.
   /// Note, you need the & to detect inherited members.
-  template <typename T, typename... Args>
-  using has_maybe_downcast = decltype(&T::maybeDownCast);
+  template <typename T, typename = void>
+  struct has_maybe_downcast : std::false_type {};
+
+  template <typename T>
+  struct has_maybe_downcast<T, std::void_t<decltype(&T::maybeDownCast)>>
+      : std::true_type {};
 
   /// Returns the element at the given slice index. Supports negative indices
   /// by taking elements in inverse order. Returns a nullptr object if out
@@ -307,7 +312,7 @@ class Sliceable {
       return {};
     }
 
-    if constexpr (llvm::is_detected<has_maybe_downcast, ElementTy>::value)
+    if constexpr (has_maybe_downcast<ElementTy>::value)
       return static_cast<Derived *>(this)
           ->getRawElement(linearizeIndex(index))
           .maybeDownCast();

>From 1e5061734c403fa0e2b3f01ee100c2b93439810d Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Mon, 2 Feb 2026 16:01:43 +0000
Subject: [PATCH 9/9] Remove aux str for ostream

---
 mlir/include/mlir/Bindings/Python/Diagnostics.h | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Diagnostics.h b/mlir/include/mlir/Bindings/Python/Diagnostics.h
index e30bbd639aade..b18f5673f0e3b 100644
--- a/mlir/include/mlir/Bindings/Python/Diagnostics.h
+++ b/mlir/include/mlir/Bindings/Python/Diagnostics.h
@@ -30,16 +30,14 @@ class CollectDiagnosticsToStringScope {
                                            /*deleteUserData=*/nullptr);
   }
   ~CollectDiagnosticsToStringScope() {
-    assert(message.empty() && "unchecked error message");
+    assert(messageStream.str().empty() && "unchecked error message");
     mlirContextDetachDiagnosticHandler(context, handlerID);
   }
 
   [[nodiscard]] std::string takeMessage() {
-    message = messageStream.str();
+    std::string newMessage = messageStream.str();
     messageStream.str("");
     messageStream.clear();
-    std::string newMessage;
-    std::swap(message, newMessage);
     return newMessage;
   }
 
@@ -65,7 +63,6 @@ class CollectDiagnosticsToStringScope {
   MlirContext context;
   MlirDiagnosticHandlerID handlerID;
 
-  std::string message;
   std::ostringstream messageStream;
 };
 



More information about the Mlir-commits mailing list