[Mlir-commits] [mlir] [MLIR][Python] Remove partial LLVM APIs in python bindings (2/n) (PR #178529)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Jan 29 08:57:17 PST 2026
https://github.com/RattataKing updated https://github.com/llvm/llvm-project/pull/178529
>From 6a8754cd2d7720ca76cd9c8b4754cff113013dad Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Wed, 28 Jan 2026 22:05:46 +0000
Subject: [PATCH 1/6] Clean llvm enum and zip
---
mlir/lib/Bindings/Python/IRCore.cpp | 67 +++++++++++++++--------------
1 file changed, 34 insertions(+), 33 deletions(-)
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 7a344c1214c1c..8fe5f855ef450 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -1476,16 +1476,18 @@ static void populateResultTypes(std::string_view name, nb::list resultTypeList,
resultTypes.reserve(resultTypeList.size());
if (resultSegmentSpecObj.is_none()) {
// Non-variadic result unpacking.
- for (const auto &it : llvm::enumerate(resultTypeList)) {
+ size_t index = 0;
+ for (const auto &resultType : resultTypeList) {
try {
- resultTypes.push_back(nb::cast<PyType *>(it.value()));
+ resultTypes.push_back(nb::cast<PyType *>(resultType));
if (!resultTypes.back())
throw nb::cast_error();
} catch (nb::cast_error &err) {
- throw nb::value_error(join("Result ", it.index(), " of operation \"",
- name, "\" must be a Type (", err.what(), ")")
+ throw nb::value_error(join("Result ", index, " of operation \"", name,
+ "\" must be a Type (", err.what(), ")")
.c_str());
}
+ ++index;
}
} else {
// Sized result unpacking.
@@ -1497,13 +1499,13 @@ static void populateResultTypes(std::string_view name, nb::list resultTypeList,
.c_str());
}
resultSegmentLengths.reserve(resultTypeList.size());
- for (const auto &it :
- llvm::enumerate(llvm::zip(resultTypeList, resultSegmentSpec))) {
- int segmentSpec = std::get<1>(it.value());
+ size_t size = resultSegmentSpec.size();
+ for (size_t index = 0; index < size; ++index) {
+ int segmentSpec = resultSegmentSpec[index];
if (segmentSpec == 1 || segmentSpec == 0) {
// Unpack unary element.
try {
- auto *resultType = nb::cast<PyType *>(std::get<0>(it.value()));
+ auto *resultType = nb::cast<PyType *>(resultTypeList[index]);
if (resultType) {
resultTypes.push_back(resultType);
resultSegmentLengths.push_back(1);
@@ -1512,25 +1514,24 @@ static void populateResultTypes(std::string_view name, nb::list resultTypeList,
resultSegmentLengths.push_back(0);
} else {
throw nb::value_error(
- join("Result ", it.index(), " of operation \"", name,
+ join("Result ", index, " of operation \"", name,
"\" must be a Type (was None and result is not optional)")
.c_str());
}
} catch (nb::cast_error &err) {
- throw nb::value_error(join("Result ", it.index(), " of operation \"",
- name, "\" must be a Type (", err.what(),
- ")")
+ throw nb::value_error(join("Result ", index, " of operation \"", name,
+ "\" must be a Type (", err.what(), ")")
.c_str());
}
} else if (segmentSpec == -1) {
// Unpack sequence by appending.
try {
- if (std::get<0>(it.value()).is_none()) {
+ if (resultTypeList[index].is_none()) {
// Treat it as an empty list.
resultSegmentLengths.push_back(0);
} else {
// Unpack the list.
- auto segment = nb::cast<nb::sequence>(std::get<0>(it.value()));
+ auto segment = nb::cast<nb::sequence>(resultTypeList[index]);
for (nb::handle segmentItem : segment) {
resultTypes.push_back(nb::cast<PyType *>(segmentItem));
if (!resultTypes.back()) {
@@ -1543,8 +1544,8 @@ static void populateResultTypes(std::string_view 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(join("Result ", it.index(), " of operation \"",
- name, "\" must be a Sequence of Types (",
+ throw nb::value_error(join("Result ", index, " of operation \"", name,
+ "\" must be a Sequence of Types (",
err.what(), ")")
.c_str());
}
@@ -1637,17 +1638,18 @@ nb::object PyOpView::buildGeneric(
// Unpack operands.
std::vector<MlirValue> operands;
operands.reserve(operands.size());
+ size_t index = 0;
if (operandSegmentSpecObj.is_none()) {
// Non-sized operand unpacking.
- for (const auto &it : llvm::enumerate(operandList)) {
+ for (const auto &operand : operandList) {
try {
- operands.push_back(getOpResultOrValue(it.value()));
+ operands.push_back(getOpResultOrValue(operand));
} catch (nb::builtin_exception &err) {
- throw nb::value_error(join("Operand ", it.index(), " of operation \"",
- name, "\" must be a Value (", err.what(),
- ")")
+ throw nb::value_error(join("Operand ", index, " of operation \"", name,
+ "\" must be a Value (", err.what(), ")")
.c_str());
}
+ ++index;
}
} else {
// Sized operand unpacking.
@@ -1659,20 +1661,19 @@ nb::object PyOpView::buildGeneric(
.c_str());
}
operandSegmentLengths.reserve(operandList.size());
- for (const auto &it :
- llvm::enumerate(llvm::zip(operandList, operandSegmentSpec))) {
- int segmentSpec = std::get<1>(it.value());
+ size_t size = operandSegmentSpec.size();
+ for (size_t index = 0; index < size; ++index) {
+ int segmentSpec = operandSegmentSpec[index];
if (segmentSpec == 1 || segmentSpec == 0) {
// Unpack unary element.
- auto &operand = std::get<0>(it.value());
+ const auto operand = operandList[index];
if (!operand.is_none()) {
try {
-
operands.push_back(getOpResultOrValue(operand));
} catch (nb::builtin_exception &err) {
- throw nb::value_error(join("Operand ", it.index(),
- " of operation \"", name,
- "\" must be a Value (", err.what(), ")")
+ throw nb::value_error(join("Operand ", index, " of operation \"",
+ name, "\" must be a Value (", err.what(),
+ ")")
.c_str());
}
@@ -1682,19 +1683,19 @@ nb::object PyOpView::buildGeneric(
operandSegmentLengths.push_back(0);
} else {
throw nb::value_error(
- join("Operand ", it.index(), " of operation \"", name,
+ join("Operand ", index, " of operation \"", name,
"\" must be a Value (was None and operand is not optional)")
.c_str());
}
} else if (segmentSpec == -1) {
// Unpack sequence by appending.
try {
- if (std::get<0>(it.value()).is_none()) {
+ if (operandList[index].is_none()) {
// Treat it as an empty list.
operandSegmentLengths.push_back(0);
} else {
// Unpack the list.
- auto segment = nb::cast<nb::sequence>(std::get<0>(it.value()));
+ auto segment = nb::cast<nb::sequence>(operandList[index]);
for (nb::handle segmentItem : segment) {
operands.push_back(getOpResultOrValue(segmentItem));
}
@@ -1704,7 +1705,7 @@ 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 "casts". Just keep the scope above small and catch them all.
- throw nb::value_error(join("Operand ", it.index(), " of operation \"",
+ throw nb::value_error(join("Operand ", index, " of operation \"",
name, "\" must be a Sequence of Values (",
err.what(), ")")
.c_str());
>From 274f949a38e20a08d570303d37e6d12dfd116377 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Wed, 28 Jan 2026 22:15:52 +0000
Subject: [PATCH 2/6] Clean Arrayref
---
mlir/lib/Bindings/Python/IRCore.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 8fe5f855ef450..9e0ed91003463 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -3167,9 +3167,9 @@ void populateIRCore(nb::module_ &m) {
if (frames.empty())
throw nb::value_error("No caller frames provided.");
MlirLocation caller = frames.back().get();
- for (const PyLocation &frame :
- llvm::reverse(llvm::ArrayRef(frames).drop_back()))
- caller = mlirLocationCallSiteGet(frame.get(), caller);
+ for (size_t index = frames.size() - 1; index-- > 0;) {
+ caller = mlirLocationCallSiteGet(frames[index].get(), caller);
+ }
return PyLocation(context->getRef(),
mlirLocationCallSiteGet(callee.get(), caller));
},
>From c2215cbe4bd41c526c5711e12c524980fa13e118 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Wed, 28 Jan 2026 22:46:05 +0000
Subject: [PATCH 3/6] Clean llvm hash value
---
mlir/lib/Bindings/Python/IRCore.cpp | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 9e0ed91003463..02313f434b652 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -19,6 +19,7 @@
#include "mlir-c/IR.h"
#include "mlir-c/Support.h"
+#include <functional>
#include <optional>
#include <sstream>
#include <string>
@@ -4099,7 +4100,8 @@ void populateIRCore(nb::module_ &m) {
.def(
"__hash__",
[](PyBlock &self) {
- return static_cast<size_t>(llvm::hash_value(self.get().ptr));
+ return static_cast<size_t>(
+ std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
},
"Returns the hash value of the block.")
.def(
@@ -4287,7 +4289,8 @@ void populateIRCore(nb::module_ &m) {
.def(
"__hash__",
[](PyAttribute &self) {
- return static_cast<size_t>(llvm::hash_value(self.get().ptr));
+ return static_cast<size_t>(
+ std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
},
"Returns the hash value of the attribute.")
.def(
@@ -4412,7 +4415,8 @@ void populateIRCore(nb::module_ &m) {
.def(
"__hash__",
[](PyType &self) {
- return static_cast<size_t>(llvm::hash_value(self.get().ptr));
+ return static_cast<size_t>(
+ std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
},
"Returns the hash value of the `Type`.")
.def(
@@ -4554,7 +4558,8 @@ void populateIRCore(nb::module_ &m) {
.def(
"__hash__",
[](PyValue &self) {
- return static_cast<size_t>(llvm::hash_value(self.get().ptr));
+ return static_cast<size_t>(
+ std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
},
"Returns the hash value of the value.")
.def(
>From 48546d203b4881ec3e7a40fc8dad813e5809a408 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Thu, 29 Jan 2026 16:33:58 +0000
Subject: [PATCH 4/6] Add type hints
---
mlir/lib/Bindings/Python/IRCore.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 02313f434b652..55fcc493c282a 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -88,14 +88,14 @@ MlirBlock createBlock(const nb::sequence &pyArgTypes,
const std::optional<nb::sequence> &pyArgLocs) {
std::vector<MlirType> argTypes;
argTypes.reserve(nb::len(pyArgTypes));
- for (const auto &pyType : pyArgTypes)
+ for (nb::handle pyType : pyArgTypes)
argTypes.push_back(
nb::cast<python::MLIR_BINDINGS_PYTHON_DOMAIN::PyType &>(pyType));
std::vector<MlirLocation> argLocs;
if (pyArgLocs) {
argLocs.reserve(nb::len(*pyArgLocs));
- for (const auto &pyLoc : *pyArgLocs)
+ for (nb::handle pyLoc : *pyArgLocs)
argLocs.push_back(
nb::cast<python::MLIR_BINDINGS_PYTHON_DOMAIN::PyLocation &>(pyLoc));
} else if (!argTypes.empty()) {
@@ -1315,7 +1315,7 @@ nb::object PyOperation::create(std::string_view name,
// Unpack/validate successors.
if (successors) {
mlirSuccessors.reserve(successors->size());
- for (auto *successor : *successors) {
+ for (PyBlock *successor : *successors) {
// TODO: Verify successor originate from the same context.
if (!successor)
throw nb::value_error("successor block cannot be None");
@@ -1339,7 +1339,7 @@ nb::object PyOperation::create(std::string_view name,
// on.
std::vector<MlirNamedAttribute> mlirNamedAttributes;
mlirNamedAttributes.reserve(mlirAttributes.size());
- for (auto &it : mlirAttributes)
+ for (const std::pair<std::string, MlirAttribute> &it : mlirAttributes)
mlirNamedAttributes.push_back(mlirNamedAttributeGet(
mlirIdentifierGet(mlirAttributeGetContext(it.second),
toMlirStringRef(it.first)),
@@ -1478,7 +1478,7 @@ static void populateResultTypes(std::string_view name, nb::list resultTypeList,
if (resultSegmentSpecObj.is_none()) {
// Non-variadic result unpacking.
size_t index = 0;
- for (const auto &resultType : resultTypeList) {
+ for (nb::handle resultType : resultTypeList) {
try {
resultTypes.push_back(nb::cast<PyType *>(resultType));
if (!resultTypes.back())
@@ -1642,7 +1642,7 @@ nb::object PyOpView::buildGeneric(
size_t index = 0;
if (operandSegmentSpecObj.is_none()) {
// Non-sized operand unpacking.
- for (const auto &operand : operandList) {
+ for (nb::handle operand : operandList) {
try {
operands.push_back(getOpResultOrValue(operand));
} catch (nb::builtin_exception &err) {
@@ -3239,7 +3239,7 @@ void populateIRCore(nb::module_ &m) {
DefaultingPyMlirContext context) {
std::vector<MlirLocation> locations;
locations.reserve(pyLocations.size());
- for (auto &pyLocation : pyLocations)
+ for (const PyLocation &pyLocation : pyLocations)
locations.push_back(pyLocation.get());
MlirLocation location = mlirLocationFusedGet(
context->get(), locations.size(), locations.data(),
>From b5e1a58de6a42ef13014b7ca674a86079e312bb6 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Thu, 29 Jan 2026 16:40:13 +0000
Subject: [PATCH 5/6] Change for loop style
---
mlir/lib/Bindings/Python/IRCore.cpp | 39 +++++++++++++----------------
1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 55fcc493c282a..d889b892f166e 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -1500,13 +1500,12 @@ static void populateResultTypes(std::string_view name, nb::list resultTypeList,
.c_str());
}
resultSegmentLengths.reserve(resultTypeList.size());
- size_t size = resultSegmentSpec.size();
- for (size_t index = 0; index < size; ++index) {
- int segmentSpec = resultSegmentSpec[index];
+ for (size_t i = 0, e = resultSegmentSpec.size(); i < e; ++i) {
+ int segmentSpec = resultSegmentSpec[i];
if (segmentSpec == 1 || segmentSpec == 0) {
// Unpack unary element.
try {
- auto *resultType = nb::cast<PyType *>(resultTypeList[index]);
+ auto *resultType = nb::cast<PyType *>(resultTypeList[i]);
if (resultType) {
resultTypes.push_back(resultType);
resultSegmentLengths.push_back(1);
@@ -1515,24 +1514,24 @@ static void populateResultTypes(std::string_view name, nb::list resultTypeList,
resultSegmentLengths.push_back(0);
} else {
throw nb::value_error(
- join("Result ", index, " of operation \"", name,
+ join("Result ", i, " of operation \"", name,
"\" must be a Type (was None and result is not optional)")
.c_str());
}
} catch (nb::cast_error &err) {
- throw nb::value_error(join("Result ", index, " of operation \"", name,
+ throw nb::value_error(join("Result ", i, " of operation \"", name,
"\" must be a Type (", err.what(), ")")
.c_str());
}
} else if (segmentSpec == -1) {
// Unpack sequence by appending.
try {
- if (resultTypeList[index].is_none()) {
+ if (resultTypeList[i].is_none()) {
// Treat it as an empty list.
resultSegmentLengths.push_back(0);
} else {
// Unpack the list.
- auto segment = nb::cast<nb::sequence>(resultTypeList[index]);
+ auto segment = nb::cast<nb::sequence>(resultTypeList[i]);
for (nb::handle segmentItem : segment) {
resultTypes.push_back(nb::cast<PyType *>(segmentItem));
if (!resultTypes.back()) {
@@ -1545,7 +1544,7 @@ static void populateResultTypes(std::string_view 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(join("Result ", index, " of operation \"", name,
+ throw nb::value_error(join("Result ", i, " of operation \"", name,
"\" must be a Sequence of Types (",
err.what(), ")")
.c_str());
@@ -1662,19 +1661,17 @@ nb::object PyOpView::buildGeneric(
.c_str());
}
operandSegmentLengths.reserve(operandList.size());
- size_t size = operandSegmentSpec.size();
- for (size_t index = 0; index < size; ++index) {
- int segmentSpec = operandSegmentSpec[index];
+ for (size_t i = 0, e = operandSegmentSpec.size(); i < e; ++i) {
+ int segmentSpec = operandSegmentSpec[i];
if (segmentSpec == 1 || segmentSpec == 0) {
// Unpack unary element.
- const auto operand = operandList[index];
+ const auto operand = operandList[i];
if (!operand.is_none()) {
try {
operands.push_back(getOpResultOrValue(operand));
} catch (nb::builtin_exception &err) {
- throw nb::value_error(join("Operand ", index, " of operation \"",
- name, "\" must be a Value (", err.what(),
- ")")
+ throw nb::value_error(join("Operand ", i, " of operation \"", name,
+ "\" must be a Value (", err.what(), ")")
.c_str());
}
@@ -1684,19 +1681,19 @@ nb::object PyOpView::buildGeneric(
operandSegmentLengths.push_back(0);
} else {
throw nb::value_error(
- join("Operand ", index, " of operation \"", name,
+ join("Operand ", i, " of operation \"", name,
"\" must be a Value (was None and operand is not optional)")
.c_str());
}
} else if (segmentSpec == -1) {
// Unpack sequence by appending.
try {
- if (operandList[index].is_none()) {
+ if (operandList[i].is_none()) {
// Treat it as an empty list.
operandSegmentLengths.push_back(0);
} else {
// Unpack the list.
- auto segment = nb::cast<nb::sequence>(operandList[index]);
+ auto segment = nb::cast<nb::sequence>(operandList[i]);
for (nb::handle segmentItem : segment) {
operands.push_back(getOpResultOrValue(segmentItem));
}
@@ -1706,8 +1703,8 @@ 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 "casts". Just keep the scope above small and catch them all.
- throw nb::value_error(join("Operand ", index, " of operation \"",
- name, "\" must be a Sequence of Values (",
+ throw nb::value_error(join("Operand ", i, " of operation \"", name,
+ "\" must be a Sequence of Values (",
err.what(), ")")
.c_str());
}
>From b860c253d356a42ab4ebb325b75840fdd4175a37 Mon Sep 17 00:00:00 2001
From: Amily Wu <amilywu2 at amd.com>
Date: Thu, 29 Jan 2026 16:56:01 +0000
Subject: [PATCH 6/6] Add hash func
---
mlir/lib/Bindings/Python/IRCore.cpp | 30 ++++++++++-------------------
1 file changed, 10 insertions(+), 20 deletions(-)
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index d889b892f166e..c7653f1ee4b15 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -57,6 +57,12 @@ static std::string join(const Ts &...args) {
return oss.str();
}
+/// Local helper to compute std::hash for a value.
+template <typename T>
+static size_t hash(const T &value) {
+ return std::hash<T>{}(value);
+}
+
/// Helper for creating an @classmethod.
template <class Func, typename... Args>
static nb::object classmethod(Func f, Args... args) {
@@ -4095,11 +4101,7 @@ void populateIRCore(nb::module_ &m) {
"__eq__", [](PyBlock &self, nb::object &other) { return false; },
"Compares block with non-block object (always returns False).")
.def(
- "__hash__",
- [](PyBlock &self) {
- return static_cast<size_t>(
- std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
- },
+ "__hash__", [](PyBlock &self) { return hash(self.get().ptr); },
"Returns the hash value of the block.")
.def(
"__str__",
@@ -4284,11 +4286,7 @@ void populateIRCore(nb::module_ &m) {
"Compares attribute with non-attribute object (always returns "
"False).")
.def(
- "__hash__",
- [](PyAttribute &self) {
- return static_cast<size_t>(
- std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
- },
+ "__hash__", [](PyAttribute &self) { return hash(self.get().ptr); },
"Returns the hash value of the attribute.")
.def(
"dump", [](PyAttribute &self) { mlirAttributeDump(self); },
@@ -4410,11 +4408,7 @@ void populateIRCore(nb::module_ &m) {
"other"_a.none(),
"Compares type with non-type object (always returns False).")
.def(
- "__hash__",
- [](PyType &self) {
- return static_cast<size_t>(
- std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
- },
+ "__hash__", [](PyType &self) { return hash(self.get().ptr); },
"Returns the hash value of the `Type`.")
.def(
"dump", [](PyType &self) { mlirTypeDump(self); }, kDumpDocstring)
@@ -4553,11 +4547,7 @@ void populateIRCore(nb::module_ &m) {
"__eq__", [](PyValue &self, nb::object other) { return false; },
"Compares value with non-value object (always returns False).")
.def(
- "__hash__",
- [](PyValue &self) {
- return static_cast<size_t>(
- std::hash<decltype(self.get().ptr)>{}(self.get().ptr));
- },
+ "__hash__", [](PyValue &self) { return hash(self.get().ptr); },
"Returns the hash value of the value.")
.def(
"__str__",
More information about the Mlir-commits
mailing list