[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