[Mlir-commits] [mlir] [MLIR][Python] Remove partial LLVM APIs in python bindings (PR #178290)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Jan 27 12:20:50 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: RattataKing (RattataKing)

<details>
<summary>Changes</summary>

mlir-py bindings should only reply on C mlir APIs.
This PR replaced LLVM utilities (`Twine`, `ArrayRef`, `SmallVector`) with equivalent STL.

---

Patch is 25.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/178290.diff


2 Files Affected:

- (modified) mlir/include/mlir/Bindings/Python/IRCore.h (+10-15) 
- (modified) mlir/lib/Bindings/Python/IRCore.cpp (+77-92) 


``````````diff
diff --git a/mlir/include/mlir/Bindings/Python/IRCore.h b/mlir/include/mlir/Bindings/Python/IRCore.h
index f9fc34e82c972..4ac341d759055 100644
--- a/mlir/include/mlir/Bindings/Python/IRCore.h
+++ b/mlir/include/mlir/Bindings/Python/IRCore.h
@@ -10,6 +10,7 @@
 #ifndef MLIR_BINDINGS_PYTHON_IRCORE_H
 #define MLIR_BINDINGS_PYTHON_IRCORE_H
 
+#include <cstddef>
 #include <optional>
 #include <sstream>
 #include <utility>
@@ -687,7 +688,7 @@ class MLIR_PYTHON_API_EXPORTED PyOperation : public PyOperationBase,
   /// Creates an operation. See corresponding python docstring.
   static nanobind::object
   create(std::string_view name, std::optional<std::vector<PyType *>> results,
-         llvm::ArrayRef<MlirValue> operands,
+         const MlirValue *operands, size_t numOperands,
          std::optional<nanobind::dict> attributes,
          std::optional<std::vector<PyBlock *>> successors, int regions,
          PyLocation &location, const nanobind::object &ip, bool inferType);
@@ -947,10 +948,9 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteType : public BaseTy {
     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 ") +
+      throw nanobind::value_error((std::string("Cannot cast type to ") +
                                    DerivedTy::pyClassName + " (from " +
                                    origRepr + ")")
-                                      .str()
                                       .c_str());
     }
     return orig;
@@ -966,8 +966,7 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteType : public BaseTy {
           if (DerivedTy::getTypeIdFunction)
             return PyTypeID(DerivedTy::getTypeIdFunction());
           throw nanobind::attribute_error(
-              (DerivedTy::pyClassName + ::llvm::Twine(" has no typeid."))
-                  .str()
+              (DerivedTy::pyClassName + std::string(" has no typeid."))
                   .c_str());
         },
         nanobind::sig("def static_typeid(/) -> TypeID"));
@@ -1080,10 +1079,9 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteAttribute : public BaseTy {
     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 ") +
+      throw nanobind::value_error((std::string("Cannot cast attribute to ") +
                                    DerivedTy::pyClassName + " (from " +
                                    origRepr + ")")
-                                      .str()
                                       .c_str());
     }
     return orig;
@@ -1111,8 +1109,7 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteAttribute : public BaseTy {
           if (DerivedTy::getTypeIdFunction)
             return PyTypeID(DerivedTy::getTypeIdFunction());
           throw nanobind::attribute_error(
-              (DerivedTy::pyClassName + ::llvm::Twine(" has no typeid."))
-                  .str()
+              (DerivedTy::pyClassName + std::string(" has no typeid."))
                   .c_str());
         },
         nanobind::sig("def static_typeid(/) -> TypeID"));
@@ -1329,9 +1326,9 @@ class MLIR_PYTHON_API_EXPORTED PySymbolTable {
 /// Custom exception that allows access to error diagnostic information. This is
 /// converted to the `ir.MLIRError` python exception when thrown.
 struct MLIR_PYTHON_API_EXPORTED MLIRError {
-  MLIRError(::llvm::Twine message,
+  MLIRError(std::string message,
             std::vector<PyDiagnostic::DiagnosticInfo> &&errorDiagnostics = {})
-      : message(message.str()), errorDiagnostics(std::move(errorDiagnostics)) {}
+      : message(message), errorDiagnostics(std::move(errorDiagnostics)) {}
   std::string message;
   std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
 };
@@ -1549,10 +1546,9 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteValue : public PyValue {
     if (!DerivedTy::isaFunction(orig.get())) {
       auto origRepr =
           nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
-      throw nanobind::value_error((::llvm::Twine("Cannot cast value to ") +
+      throw nanobind::value_error((std::string("Cannot cast value to ") +
                                    DerivedTy::pyClassName + " (from " +
                                    origRepr + ")")
-                                      .str()
                                       .c_str());
     }
     return orig.get();
@@ -1561,9 +1557,8 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteValue : public PyValue {
   /// Binds the Python module objects to functions of this class.
   static void bind(nanobind::module_ &m) {
     auto cls = ClassTy(m, DerivedTy::pyClassName, nanobind::is_generic(),
-                       nanobind::sig((::llvm::Twine("class ") +
+                       nanobind::sig((std::string("class ") +
                                       DerivedTy::pyClassName + "(Value[_T])")
-                                         .str()
                                          .c_str()));
     cls.def(nanobind::init<PyValue &>(), nanobind::keep_alive<0, 1>(),
             nanobind::arg("value"));
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index eb00363a54034..a2814100a77dc 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -18,8 +18,6 @@
 #include "mlir-c/Diagnostics.h"
 #include "mlir-c/IR.h"
 #include "mlir-c/Support.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
 
 #include <optional>
 
@@ -27,10 +25,6 @@ namespace nb = nanobind;
 using namespace nb::literals;
 using namespace mlir;
 
-using llvm::SmallVector;
-using llvm::StringRef;
-using llvm::Twine;
-
 static const char kModuleParseDocstring[] =
     R"(Parses a module's assembly format from a string.
 
@@ -81,13 +75,13 @@ namespace MLIR_BINDINGS_PYTHON_DOMAIN {
 
 MlirBlock createBlock(const nb::sequence &pyArgTypes,
                       const std::optional<nb::sequence> &pyArgLocs) {
-  SmallVector<MlirType> argTypes;
+  std::vector<MlirType> argTypes;
   argTypes.reserve(nb::len(pyArgTypes));
   for (const auto &pyType : pyArgTypes)
     argTypes.push_back(
         nb::cast<python::MLIR_BINDINGS_PYTHON_DOMAIN::PyType &>(pyType));
 
-  SmallVector<MlirLocation> argLocs;
+  std::vector<MlirLocation> argLocs;
   if (pyArgLocs) {
     argLocs.reserve(nb::len(*pyArgLocs));
     for (const auto &pyLoc : *pyArgLocs)
@@ -100,9 +94,8 @@ MlirBlock createBlock(const nb::sequence &pyArgTypes,
   }
 
   if (argTypes.size() != argLocs.size())
-    throw nb::value_error(("Expected " + Twine(argTypes.size()) +
-                           " locations, got: " + Twine(argLocs.size()))
-                              .str()
+    throw nb::value_error(("Expected " + std::to_string(argTypes.size()) +
+                           " locations, got: " + std::to_string(argLocs.size()))
                               .c_str());
   return mlirBlockCreate(argTypes.size(), argTypes.data(), argLocs.data());
 }
@@ -824,7 +817,7 @@ MlirDialect PyDialects::getDialectForKey(const std::string &key,
   MlirDialect dialect = mlirContextGetOrLoadDialect(getContext()->get(),
                                                     {key.data(), key.size()});
   if (mlirDialectIsNull(dialect)) {
-    std::string msg = (Twine("Dialect '") + key + "' not found").str();
+    std::string msg = (std::string("Dialect '") + key + "' not found");
     if (attrError)
       throw nb::attribute_error(msg.c_str());
     throw nb::index_error(msg.c_str());
@@ -1105,10 +1098,10 @@ void PyOperationBase::writeBytecode(const nb::object &fileOrStringObject,
       operation, config, accum.getCallback(), accum.getUserData());
   mlirBytecodeWriterConfigDestroy(config);
   if (mlirLogicalResultIsFailure(res))
-    throw nb::value_error((Twine("Unable to honor desired bytecode version ") +
-                           Twine(*bytecodeVersion))
-                              .str()
-                              .c_str());
+    throw nb::value_error(
+        (std::string("Unable to honor desired bytecode version ") +
+         std::to_string(*bytecodeVersion))
+            .c_str());
 }
 
 void PyOperationBase::walk(std::function<PyWalkResult(MlirOperation)> callback,
@@ -1255,14 +1248,14 @@ static void maybeInsertOperation(PyOperationRef &op,
 
 nb::object PyOperation::create(std::string_view name,
                                std::optional<std::vector<PyType *>> results,
-                               llvm::ArrayRef<MlirValue> operands,
+                               const MlirValue *operands, size_t numOperands,
                                std::optional<nb::dict> attributes,
                                std::optional<std::vector<PyBlock *>> successors,
                                int regions, PyLocation &location,
                                const nb::object &maybeIp, bool inferType) {
-  llvm::SmallVector<MlirType, 4> mlirResults;
-  llvm::SmallVector<MlirBlock, 4> mlirSuccessors;
-  llvm::SmallVector<std::pair<std::string, MlirAttribute>, 4> mlirAttributes;
+  std::vector<MlirType> mlirResults;
+  std::vector<MlirBlock> mlirSuccessors;
+  std::vector<std::pair<std::string, MlirAttribute>> mlirAttributes;
 
   // General parameter validation.
   if (regions < 0)
@@ -1325,8 +1318,8 @@ nb::object PyOperation::create(std::string_view name,
   // point, exceptions cannot be thrown or else the state will leak.
   MlirOperationState state =
       mlirOperationStateGet(toMlirStringRef(name), location);
-  if (!operands.empty())
-    mlirOperationStateAddOperands(&state, operands.size(), operands.data());
+  if (numOperands)
+    mlirOperationStateAddOperands(&state, numOperands, operands);
   state.enableResultTypeInference = inferType;
   if (!mlirResults.empty())
     mlirOperationStateAddResults(&state, mlirResults.size(),
@@ -1335,7 +1328,7 @@ nb::object PyOperation::create(std::string_view name,
     // Note that the attribute names directly reference bytes in
     // mlirAttributes, so that vector must not be changed from here
     // on.
-    llvm::SmallVector<MlirNamedAttribute, 4> mlirNamedAttributes;
+    std::vector<MlirNamedAttribute> mlirNamedAttributes;
     mlirNamedAttributes.reserve(mlirAttributes.size());
     for (auto &it : mlirAttributes)
       mlirNamedAttributes.push_back(mlirNamedAttributeGet(
@@ -1349,7 +1342,7 @@ nb::object PyOperation::create(std::string_view name,
     mlirOperationStateAddSuccessors(&state, mlirSuccessors.size(),
                                     mlirSuccessors.data());
   if (regions) {
-    llvm::SmallVector<MlirRegion, 4> mlirRegions;
+    std::vector<MlirRegion> mlirRegions;
     mlirRegions.resize(regions);
     for (int i = 0; i < regions; ++i)
       mlirRegions[i] = mlirRegionCreate();
@@ -1481,10 +1474,10 @@ static void populateResultTypes(StringRef name, nb::list resultTypeList,
         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()
+        throw nb::value_error((std::string("Result ") +
+                               std::to_string(it.index()) + " of operation \"" +
+                               std::string(name) + "\" must be a Type (" +
+                               err.what() + ")")
                                   .c_str());
       }
     }
@@ -1492,12 +1485,11 @@ static void populateResultTypes(StringRef name, nb::list resultTypeList,
     // Sized result unpacking.
     auto resultSegmentSpec = nb::cast<std::vector<int>>(resultSegmentSpecObj);
     if (resultSegmentSpec.size() != resultTypeList.size()) {
-      throw nb::value_error((llvm::Twine("Operation \"") + name +
+      throw nb::value_error((std::string("Operation \"") + std::string(name) +
                              "\" requires " +
-                             llvm::Twine(resultSegmentSpec.size()) +
+                             std::to_string(resultSegmentSpec.size()) +
                              " result segments but was provided " +
-                             llvm::Twine(resultTypeList.size()))
-                                .str()
+                             std::to_string(resultTypeList.size()))
                                 .c_str());
     }
     resultSegmentLengths.reserve(resultTypeList.size());
@@ -1516,18 +1508,16 @@ static void populateResultTypes(StringRef name, nb::list resultTypeList,
             resultSegmentLengths.push_back(0);
           } else {
             throw nb::value_error(
-                (llvm::Twine("Result ") + llvm::Twine(it.index()) +
-                 " of operation \"" + name +
+                (std::string("Result ") + std::to_string(it.index()) +
+                 " of operation \"" + std::string(name) +
                  "\" must be a Type (was None and result is not optional)")
-                    .str()
                     .c_str());
           }
         } 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()
+          throw nb::value_error((std::string("Result ") +
+                                 std::to_string(it.index()) +
+                                 " of operation \"" + std::string(name) +
+                                 "\" must be a Type (" + err.what() + ")")
                                     .c_str());
         }
       } else if (segmentSpec == -1) {
@@ -1551,12 +1541,12 @@ static void populateResultTypes(StringRef name, nb::list resultTypeList,
           // 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 nb::value_error((llvm::Twine("Result ") +
-                                 llvm::Twine(it.index()) + " of operation \"" +
-                                 name + "\" must be a Sequence of Types (" +
-                                 err.what() + ")")
-                                    .str()
-                                    .c_str());
+          throw nb::value_error(
+              (std::string("Result ") + std::to_string(it.index()) +
+               " of operation \"" + name + "\" must be a Sequence of Types (" +
+               err.what() + ")")
+                  .str()
+                  .c_str());
         }
       } else {
         throw nb::value_error("Unexpected segment spec");
@@ -1569,9 +1559,9 @@ MlirValue getUniqueResult(MlirOperation operation) {
   auto numResults = mlirOperationGetNumResults(operation);
   if (numResults != 1) {
     auto name = mlirIdentifierStr(mlirOperationGetName(operation));
-    throw nb::value_error((Twine("Cannot call .result on operation ") +
+    throw nb::value_error((std::string("Cannot call .result on operation ") +
                            StringRef(name.data, name.length) + " which has " +
-                           Twine(numResults) +
+                           std::to_string(numResults) +
                            " results (it is only valid for operations with a "
                            "single result)")
                               .str()
@@ -1626,18 +1616,16 @@ nb::object PyOpView::buildGeneric(
   }
   if (*regions < opMinRegionCount) {
     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()
+        (std::string("Operation \"") + std::string(name) +
+         "\" requires a minimum of " + std::to_string(opMinRegionCount) +
+         " regions but was built with regions=" + std::to_string(*regions))
             .c_str());
   }
   if (opHasNoVariadicRegions && *regions > opMinRegionCount) {
     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()
+        (std::string("Operation \"") + std::string(name) +
+         "\" requires a maximum of " + std::to_string(opMinRegionCount) +
+         " regions but was built with regions=" + std::to_string(*regions))
             .c_str());
   }
 
@@ -1649,7 +1637,7 @@ nb::object PyOpView::buildGeneric(
   }
 
   // Unpack operands.
-  llvm::SmallVector<MlirValue, 4> operands;
+  std::vector<MlirValue> operands;
   operands.reserve(operands.size());
   if (operandSegmentSpecObj.is_none()) {
     // Non-sized operand unpacking.
@@ -1657,10 +1645,10 @@ nb::object PyOpView::buildGeneric(
       try {
         operands.push_back(getOpResultOrValue(it.value()));
       } catch (nb::builtin_exception &err) {
-        throw nb::value_error((llvm::Twine("Operand ") +
-                               llvm::Twine(it.index()) + " of operation \"" +
-                               name + "\" must be a Value (" + err.what() + ")")
-                                  .str()
+        throw nb::value_error((std::string("Operand ") +
+                               std::to_string(it.index()) + " of operation \"" +
+                               std::string(name) + "\" must be a Value (" +
+                               err.what() + ")")
                                   .c_str());
       }
     }
@@ -1668,12 +1656,11 @@ nb::object PyOpView::buildGeneric(
     // Sized operand unpacking.
     auto operandSegmentSpec = nb::cast<std::vector<int>>(operandSegmentSpecObj);
     if (operandSegmentSpec.size() != operandList.size()) {
-      throw nb::value_error((llvm::Twine("Operation \"") + name +
+      throw nb::value_error((std::string("Operation \"") + std::string(name) +
                              "\" requires " +
-                             llvm::Twine(operandSegmentSpec.size()) +
+                             std::to_string(operandSegmentSpec.size()) +
                              "operand segments but was provided " +
-                             llvm::Twine(operandList.size()))
-                                .str()
+                             std::to_string(operandList.size()))
                                 .c_str());
     }
     operandSegmentLengths.reserve(operandList.size());
@@ -1688,11 +1675,10 @@ nb::object PyOpView::buildGeneric(
 
             operands.push_back(getOpResultOrValue(operand));
           } catch (nb::builtin_exception &err) {
-            throw nb::value_error((llvm::Twine("Operand ") +
-                                   llvm::Twine(it.index()) +
-                                   " of operation \"" + name +
+            throw nb::value_error((std::string("Operand ") +
+                                   std::to_string(it.index()) +
+                                   " of operation \"" + std::string(name) +
                                    "\" must be a Value (" + err.what() + ")")
-                                      .str()
                                       .c_str());
           }
 
@@ -1702,10 +1688,9 @@ nb::object PyOpView::buildGeneric(
           operandSegmentLengths.push_back(0);
         } else {
           throw nb::value_error(
-              (llvm::Twine("Operand ") + llvm::Twine(it.index()) +
-               " of operation \"" + name +
+              (std::string("Operand ") + std::to_string(it.index()) +
+               " of operation \"" + std::string(name) +
                "\" must be a Value (was None and operand is not optional)")
-                  .str()
                   .c_str());
         }
       } else if (segmentSpec == -1) {
@@ -1726,12 +1711,11 @@ nb::object PyOpView::buildGeneric(
           // 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 "c...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/178290


More information about the Mlir-commits mailing list