[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:02:01 PST 2026


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

>From 06c37327f42b3b65cf27e897db42521a4ae45a71 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 5548a716cbe21..56695cda09340 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.
@@ -115,7 +116,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);
 
   class MLIR_PYTHON_API_EXPORTED TracebackLoc {
   public:
@@ -131,7 +132,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 e2e8693ba45f3..5e48d258ebf14 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))
@@ -190,10 +190,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;
 
@@ -252,7 +252,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(
@@ -267,7 +267,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 b0d239992fefd0716a3313b90c5e39b375213f31 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 75e96a97964ec18c011f911cbf8f762397bb5b99 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 56695cda09340..403019693321e 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 {
@@ -188,9 +200,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 59932a4a683a5071c5e9cc2ee67d2f1b6940e42d 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 |  8 ++++----
 mlir/lib/Bindings/Python/Globals.cpp        | 12 +++++++-----
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/mlir/include/mlir/Bindings/Python/Globals.h b/mlir/include/mlir/Bindings/Python/Globals.h
index 403019693321e..aa4cfdf960b89 100644
--- a/mlir/include/mlir/Bindings/Python/Globals.h
+++ b/mlir/include/mlir/Bindings/Python/Globals.h
@@ -158,7 +158,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; }
@@ -194,11 +194,11 @@ 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 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 5e48d258ebf14..9a56e7af8dc14 100644
--- a/mlir/lib/Bindings/Python/Globals.cpp
+++ b/mlir/lib/Bindings/Python/Globals.cpp
@@ -198,7 +198,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;
@@ -266,13 +267,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 8bb654457844c1d61a111f1e085b67648505f53a 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 aa4cfdf960b89..e1ae84ee2b9ff 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 {
@@ -209,7 +208,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 9a56e7af8dc14..c0d919043c533 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 80f6a91f31a9afe24038c5c7484237227930b21c 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 e4db27ce6c582bb64a7c01ed53318855550e8979 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 e1ae84ee2b9ff..016cf002c0d90 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 c7653f1ee4b15..6233ca35ae5f5 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 2c99d0938beb57f73b532fd72ae3c82f39351d95 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 c2ce82f937356b53ee3beebe92ef61bff6565390 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