[Mlir-commits] [mlir] [mlir][python] expose remaining Location inspection API (PR #192630)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Apr 17 04:10:54 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Soowon Jeong (swjng)
<details>
<summary>Changes</summary>
Rounds out `Location` deconstruction/inspection (#<!-- -->53169). Prior to this PR, `UnknownLoc` lacked an isA check, `FusedLoc.metadata` was reachable from the C API but not from Python, and `OpaqueLoc` had no C API or Python surface at all. Any Python tool iterating over arbitrary locations hit a wall on those three.
### Changes
C API (`mlir/include/mlir-c/IR.h`, `mlir/lib/CAPI/IR/IR.cpp`):
- `mlirLocationIsAUnknown`, `mlirLocationUnknownGetTypeID`
- `mlirLocationOpaqueGet`, `mlirLocationOpaqueGetUnderlyingLocation`, `mlirLocationOpaqueGetUnderlyingTypeID`, `mlirLocationOpaqueGetFallbackLocation`, `mlirLocationOpaqueGetTypeID`, `mlirLocationIsAOpaque`
Python (`mlir/lib/Bindings/Python/IRCore.cpp`):
- `Location.is_a_unknown()`
- `FusedLoc.metadata` (returns `None` when absent)
- `Location.opaque(underlying_location, underlying_type_id, fallback_location)` plus `is_a_opaque()`, `underlying_location`, `underlying_type_id`, `fallback_location`
Tests:
- `mlir/test/python/ir/location.py` — `testUnknown` gets isA coverage, `testFused` checks metadata (absent / present), new `testOpaque` exercises round-trip construction and accessors.
- `mlir/test/CAPI/ir.c` — `testLocation` covers the new C API.
### Notes
`OpaqueLoc.underlying_location` surfaces the raw `uintptr_t` as a Python `int`; interpreting it is the caller's responsibility (e.g. via `ctypes`), same contract as the C++ side. TypeIDs are passed through as opaque tokens.
---
Full diff: https://github.com/llvm/llvm-project/pull/192630.diff
5 Files Affected:
- (modified) mlir/include/mlir-c/IR.h (+30)
- (modified) mlir/lib/Bindings/Python/IRCore.cpp (+36)
- (modified) mlir/lib/CAPI/IR/IR.cpp (+36)
- (modified) mlir/test/CAPI/ir.c (+36)
- (modified) mlir/test/python/ir/location.py (+37)
``````````diff
diff --git a/mlir/include/mlir-c/IR.h b/mlir/include/mlir-c/IR.h
index c464e4da66f17..fed9e7f9cf2db 100644
--- a/mlir/include/mlir-c/IR.h
+++ b/mlir/include/mlir-c/IR.h
@@ -363,6 +363,36 @@ MLIR_CAPI_EXPORTED bool mlirLocationIsAName(MlirLocation location);
/// Creates a location with unknown position owned by the given context.
MLIR_CAPI_EXPORTED MlirLocation mlirLocationUnknownGet(MlirContext context);
+/// TypeID Getter for Unknown.
+MLIR_CAPI_EXPORTED MlirTypeID mlirLocationUnknownGetTypeID(void);
+
+/// Checks whether the given location is an Unknown.
+MLIR_CAPI_EXPORTED bool mlirLocationIsAUnknown(MlirLocation location);
+
+/// Creates an opaque location with an underlying pointer, a TypeID tag, and a
+/// fallback location.
+MLIR_CAPI_EXPORTED MlirLocation
+mlirLocationOpaqueGet(uintptr_t underlyingLocation, MlirTypeID underlyingTypeID,
+ MlirLocation fallbackLocation);
+
+/// Getter for underlyingLocation of Opaque.
+MLIR_CAPI_EXPORTED uintptr_t
+mlirLocationOpaqueGetUnderlyingLocation(MlirLocation location);
+
+/// Getter for underlyingTypeID of Opaque.
+MLIR_CAPI_EXPORTED MlirTypeID
+mlirLocationOpaqueGetUnderlyingTypeID(MlirLocation location);
+
+/// Getter for fallbackLocation of Opaque.
+MLIR_CAPI_EXPORTED MlirLocation
+mlirLocationOpaqueGetFallbackLocation(MlirLocation location);
+
+/// TypeID Getter for Opaque.
+MLIR_CAPI_EXPORTED MlirTypeID mlirLocationOpaqueGetTypeID(void);
+
+/// Checks whether the given location is an Opaque.
+MLIR_CAPI_EXPORTED bool mlirLocationIsAOpaque(MlirLocation location);
+
/// Gets the context that a location was created with.
MLIR_CAPI_EXPORTED MlirContext mlirLocationGetContext(MlirLocation location);
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 06d0256e6287b..dc477ea88e6b6 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -3226,6 +3226,7 @@ void mlir::python::populateIRCore(nb::module_ &m) {
},
nb::arg("context") = nb::none(),
"Gets a Location representing an unknown location")
+ .def("is_a_unknown", mlirLocationIsAUnknown)
.def_static(
"callsite",
[](PyLocation callee, const std::vector<PyLocation> &frames,
@@ -3315,6 +3316,14 @@ void mlir::python::populateIRCore(nb::module_ &m) {
pyLocations.emplace_back(self.getContext(), locations[i]);
return pyLocations;
})
+ .def_prop_ro("metadata",
+ [](PyLocation &self) -> std::optional<PyAttribute> {
+ MlirAttribute metadata =
+ mlirLocationFusedGetMetadata(self);
+ if (mlirAttributeIsNull(metadata))
+ return std::nullopt;
+ return PyAttribute(self.getContext(), metadata);
+ })
.def_static(
"name",
[](std::string name, std::optional<PyLocation> childLoc,
@@ -3338,6 +3347,33 @@ void mlir::python::populateIRCore(nb::module_ &m) {
return PyLocation(self.getContext(),
mlirLocationNameGetChildLoc(self));
})
+ .def_static(
+ "opaque",
+ [](uintptr_t underlyingLocation, PyTypeID &underlyingTypeID,
+ PyLocation &fallbackLocation) {
+ return PyLocation(fallbackLocation.getContext(),
+ mlirLocationOpaqueGet(underlyingLocation,
+ underlyingTypeID.get(),
+ fallbackLocation.get()));
+ },
+ nb::arg("underlying_location"), nb::arg("underlying_type_id"),
+ nb::arg("fallback_location"))
+ .def("is_a_opaque", mlirLocationIsAOpaque)
+ .def_prop_ro("underlying_location",
+ [](PyLocation &self) -> uintptr_t {
+ return mlirLocationOpaqueGetUnderlyingLocation(self);
+ })
+ .def_prop_ro("underlying_type_id",
+ [](PyLocation &self) {
+ return PyTypeID(
+ mlirLocationOpaqueGetUnderlyingTypeID(self));
+ })
+ .def_prop_ro("fallback_location",
+ [](PyLocation &self) {
+ return PyLocation(
+ self.getContext(),
+ mlirLocationOpaqueGetFallbackLocation(self));
+ })
.def_static(
"from_attr",
[](PyAttribute &attribute, DefaultingPyMlirContext context) {
diff --git a/mlir/lib/CAPI/IR/IR.cpp b/mlir/lib/CAPI/IR/IR.cpp
index 188186598c5c5..43d0f31e2cab2 100644
--- a/mlir/lib/CAPI/IR/IR.cpp
+++ b/mlir/lib/CAPI/IR/IR.cpp
@@ -404,6 +404,42 @@ MlirLocation mlirLocationUnknownGet(MlirContext context) {
return wrap(Location(UnknownLoc::get(unwrap(context))));
}
+MlirTypeID mlirLocationUnknownGetTypeID() {
+ return wrap(UnknownLoc::getTypeID());
+}
+
+bool mlirLocationIsAUnknown(MlirLocation location) {
+ return isa<UnknownLoc>(unwrap(location));
+}
+
+MlirLocation mlirLocationOpaqueGet(uintptr_t underlyingLocation,
+ MlirTypeID underlyingTypeID,
+ MlirLocation fallbackLocation) {
+ return wrap(Location(OpaqueLoc::get(
+ underlyingLocation, unwrap(underlyingTypeID), unwrap(fallbackLocation))));
+}
+
+uintptr_t mlirLocationOpaqueGetUnderlyingLocation(MlirLocation location) {
+ return llvm::cast<OpaqueLoc>(unwrap(location)).getUnderlyingLocation();
+}
+
+MlirTypeID mlirLocationOpaqueGetUnderlyingTypeID(MlirLocation location) {
+ return wrap(llvm::cast<OpaqueLoc>(unwrap(location)).getUnderlyingTypeID());
+}
+
+MlirLocation mlirLocationOpaqueGetFallbackLocation(MlirLocation location) {
+ return wrap(
+ Location(llvm::cast<OpaqueLoc>(unwrap(location)).getFallbackLocation()));
+}
+
+MlirTypeID mlirLocationOpaqueGetTypeID() {
+ return wrap(OpaqueLoc::getTypeID());
+}
+
+bool mlirLocationIsAOpaque(MlirLocation location) {
+ return isa<OpaqueLoc>(unwrap(location));
+}
+
bool mlirLocationEqual(MlirLocation l1, MlirLocation l2) {
return unwrap(l1) == unwrap(l2);
}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index c2caae4e795f3..75df7cc8c3021 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -2376,6 +2376,41 @@ void testExplicitThreadPools(void) {
mlirLlvmThreadPoolDestroy(threadPool);
}
+void testLocation(void) {
+ MlirContext ctx = mlirContextCreate();
+ fprintf(stderr, "@test_location\n");
+
+ MlirLocation unknownLoc = mlirLocationUnknownGet(ctx);
+ MlirLocation fileLoc = mlirLocationFileLineColGet(
+ ctx, mlirStringRefCreateFromCString("foo.c"), 1, 2);
+
+ // CHECK-LABEL: @test_location
+ // CHECK: unknown is_a_unknown: 1
+ fprintf(stderr, "unknown is_a_unknown: %d\n",
+ mlirLocationIsAUnknown(unknownLoc));
+ // CHECK: file is_a_unknown: 0
+ fprintf(stderr, "file is_a_unknown: %d\n", mlirLocationIsAUnknown(fileLoc));
+
+ MlirTypeID typeID = mlirLocationFileLineColRangeGetTypeID();
+ MlirLocation opaqueLoc =
+ mlirLocationOpaqueGet((uintptr_t)0xcafef00d, typeID, fileLoc);
+ // CHECK: opaque is_a_opaque: 1
+ fprintf(stderr, "opaque is_a_opaque: %d\n", mlirLocationIsAOpaque(opaqueLoc));
+ // CHECK: opaque underlying: cafef00d
+ fprintf(stderr, "opaque underlying: %" PRIxPTR "\n",
+ mlirLocationOpaqueGetUnderlyingLocation(opaqueLoc));
+ // CHECK: opaque typeid matches: 1
+ fprintf(stderr, "opaque typeid matches: %d\n",
+ mlirTypeIDEqual(mlirLocationOpaqueGetUnderlyingTypeID(opaqueLoc),
+ typeID));
+ // CHECK: opaque fallback equal: 1
+ fprintf(stderr, "opaque fallback equal: %d\n",
+ mlirLocationEqual(mlirLocationOpaqueGetFallbackLocation(opaqueLoc),
+ fileLoc));
+
+ mlirContextDestroy(ctx);
+}
+
void testDiagnostics(void) {
MlirContext ctx = mlirContextCreate();
MlirDiagnosticHandlerID id = mlirContextAttachDiagnosticHandler(
@@ -2552,6 +2587,7 @@ int main(void) {
return 16;
testExplicitThreadPools();
+ testLocation();
testDiagnostics();
if (testBlockPredecessorsSuccessors(ctx))
diff --git a/mlir/test/python/ir/location.py b/mlir/test/python/ir/location.py
index 3e54dc922cd67..6754221c5cb10 100644
--- a/mlir/test/python/ir/location.py
+++ b/mlir/test/python/ir/location.py
@@ -23,6 +23,13 @@ def testUnknown():
# CHECK: unknown repr: loc(unknown)
print("unknown repr:", repr(loc))
+ assert loc.is_a_unknown()
+ assert not loc.is_a_file()
+ assert not loc.is_a_name()
+ assert not loc.is_a_callsite()
+ assert not loc.is_a_fused()
+ assert not loc.is_a_opaque()
+
run(testUnknown)
@@ -193,8 +200,12 @@ def testFused():
print("fused repr:", repr(loc))
# CHECK: fused locations: [loc("apple"), loc("banana")]
print("fused locations:", loc.locations)
+ # CHECK: fused metadata: None
+ print("fused metadata:", loc.metadata)
assert loc_attr.is_a_fused()
+ # CHECK: fused metadata: "sauteed"
+ print("fused metadata:", loc_attr.metadata)
# CHECK: fused str: loc(fused<"sauteed">["carrot", "potatoes"])
print("fused str:", str(loc_attr))
# CHECK: fused repr: loc(fused<"sauteed">["carrot", "potatoes"])
@@ -230,6 +241,32 @@ def testFused():
run(testFused)
+# CHECK-LABEL: TEST: testOpaque
+def testOpaque():
+ with Context() as ctx:
+ fallback = Location.file("fallback.txt", 42, 7)
+ type_id = IntegerType.get_signless(32).typeid
+ loc = Location.opaque(0xDEADBEEF, type_id, fallback)
+
+ ctx = None
+ gc.collect()
+
+ # CHECK: opaque str: loc("fallback.txt":42:7)
+ print("opaque str:", str(loc))
+
+ assert loc.is_a_opaque()
+ assert not loc.is_a_unknown()
+ assert not loc.is_a_file()
+
+ # CHECK: opaque underlying_location: 0xdeadbeef
+ print("opaque underlying_location:", hex(loc.underlying_location))
+ assert loc.underlying_type_id == type_id
+ assert loc.fallback_location == fallback
+
+
+run(testOpaque)
+
+
# CHECK-LABEL: TEST: testLocationCapsule
def testLocationCapsule():
with Context() as ctx:
``````````
</details>
https://github.com/llvm/llvm-project/pull/192630
More information about the Mlir-commits
mailing list