[Mlir-commits] [mlir] [mlir][python] expose remaining Location inspection API (PR #192630)
Soowon Jeong
llvmlistbot at llvm.org
Fri Apr 17 08:33:55 PDT 2026
https://github.com/swjng updated https://github.com/llvm/llvm-project/pull/192630
>From 1468410816b8e08528b985ea9c04c6b0aa37bea7 Mon Sep 17 00:00:00 2001
From: Soowon Jeong <soowon1106 at gmail.com>
Date: Fri, 17 Apr 2026 17:40:15 +0900
Subject: [PATCH] [mlir][python] expose Location subclasses via isinstance
Currently `Location` in the Python bindings is a single class with
predicate methods (`is_a_file`, `is_a_name`, etc.) to discriminate
between LocationAttr kinds, and field accessors for every kind live on
the base class. Several kinds (UnknownLoc, OpaqueLoc, FusedLoc metadata)
have no Python-side accessors at all. Addresses #53169.
Mirrors the pattern used for Attribute subclasses: introduces a
`PyConcreteLocation<T>` CRTP template and concrete Python classes
`UnknownLoc`, `FileLineColLoc`, `NameLoc`, `CallSiteLoc`, `FusedLoc`,
`OpaqueLoc`, each registered as a nanobind subclass of `Location`.
Downcasting is driven by TypeID lookup in `PyLocation::maybeDownCast`,
called at the boundaries that return Location objects (`op.location`,
`value.location`, `Location.from_attr`, and the subclass getters
themselves). Existing `Location.unknown()`/`file()`/`name()`/
`callsite()`/`fused()` factories remain as aliases that return the
concrete subclass instance, so existing user code and tests keep
working.
Motivation: a Python tool walking arbitrary op locations can now use
`isinstance(loc, OpaqueLoc)` / `isinstance(loc, FusedLoc)`, read
`.metadata` on `FusedLoc`, or recover the raw `uintptr_t` tag from an
`OpaqueLoc` for frontends that attach their own source-location objects
(e.g. a Python-frontend DSL that stores the owning Python object via
`id(obj)` and recovers it in a diagnostic handler via `ctypes`).
C API additions required by this wiring:
- `mlirLocationIsAUnknown`, `mlirLocationUnknownGetTypeID`
- `mlirLocationOpaqueGet`, `mlirLocationOpaqueGetUnderlyingLocation`,
`mlirLocationOpaqueGetUnderlyingTypeID`,
`mlirLocationOpaqueGetFallbackLocation`,
`mlirLocationOpaqueGetTypeID`, `mlirLocationIsAOpaque`
Assisted-by: Claude (Anthropic)
Co-Authored-By: Claude (Anthropic) <noreply at anthropic.com>
---
mlir/include/mlir-c/IR.h | 30 ++
mlir/include/mlir/Bindings/Python/IRCore.h | 129 +++++++
mlir/lib/Bindings/Python/IRCore.cpp | 415 +++++++++++++++------
mlir/lib/CAPI/IR/IR.cpp | 36 ++
mlir/test/CAPI/ir.c | 36 ++
mlir/test/python/ir/location.py | 145 +++++--
6 files changed, 637 insertions(+), 154 deletions(-)
diff --git a/mlir/include/mlir-c/IR.h b/mlir/include/mlir-c/IR.h
index 8d30051d615f4..7765e9566fe2a 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/include/mlir/Bindings/Python/IRCore.h b/mlir/include/mlir/Bindings/Python/IRCore.h
index b2edcace7298e..b0f2381f62c7c 100644
--- a/mlir/include/mlir/Bindings/Python/IRCore.h
+++ b/mlir/include/mlir/Bindings/Python/IRCore.h
@@ -337,6 +337,10 @@ class MLIR_PYTHON_API_EXPORTED PyLocation : public BaseContextObject {
/// is taken by calling this function.
static PyLocation createFromCapsule(nanobind::object capsule);
+ /// Returns a Python object of the most-derived Location subclass if a type
+ /// caster is registered for this Location's TypeID, otherwise returns self.
+ nanobind::typed<nanobind::object, PyLocation> maybeDownCast();
+
private:
MlirLocation loc;
};
@@ -1164,6 +1168,131 @@ class MLIR_PYTHON_API_EXPORTED PyStringAttribute
static void bindDerived(ClassTy &c);
};
+/// CRTP base class for Python classes that subclass Location and should be
+/// castable from it (i.e. via something like FileLineColLoc(loc)).
+template <typename DerivedTy, typename BaseTy = PyLocation>
+class MLIR_PYTHON_API_EXPORTED PyConcreteLocation : public BaseTy {
+public:
+ // Derived classes must define statics for:
+ // IsAFunctionTy isaFunction
+ // const char *pyClassName
+ using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
+ using IsAFunctionTy = bool (*)(MlirLocation);
+ using GetTypeIDFunctionTy = MlirTypeID (*)();
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
+ using Base = PyConcreteLocation;
+
+ PyConcreteLocation() = default;
+ PyConcreteLocation(PyMlirContextRef contextRef, MlirLocation loc)
+ : BaseTy(std::move(contextRef), loc) {}
+ PyConcreteLocation(PyLocation &orig)
+ : PyConcreteLocation(orig.getContext(), castFrom(orig)) {}
+
+ static MlirLocation castFrom(PyLocation &orig) {
+ if (!DerivedTy::isaFunction(orig.get())) {
+ throw nanobind::value_error(
+ (std::string("Cannot cast location to ") + DerivedTy::pyClassName)
+ .c_str());
+ }
+ return orig.get();
+ }
+
+ static void bind(nanobind::module_ &m) {
+ ClassTy cls(m, DerivedTy::pyClassName);
+ cls.def(nanobind::init<PyLocation &>(), nanobind::keep_alive<0, 1>(),
+ nanobind::arg("cast_from_loc"));
+ cls.def_prop_ro_static("static_typeid", [](nanobind::object & /*class*/) {
+ if (DerivedTy::getTypeIdFunction)
+ return PyTypeID(DerivedTy::getTypeIdFunction());
+ throw nanobind::attribute_error(
+ (DerivedTy::pyClassName + std::string(" has no typeid.")).c_str());
+ });
+ if (DerivedTy::getTypeIdFunction) {
+ PyGlobals::get().registerTypeCaster(
+ DerivedTy::getTypeIdFunction(),
+ nanobind::cast<nanobind::callable>(nanobind::cpp_function(
+ [](PyLocation pyLoc) -> DerivedTy { return pyLoc; })),
+ /*replace*/ true);
+ }
+ DerivedTy::bindDerived(cls);
+ }
+
+ /// Implemented by derived classes to add methods to the Python subclass.
+ static void bindDerived(ClassTy &m) {}
+};
+
+class MLIR_PYTHON_API_EXPORTED PyUnknownLocation
+ : public PyConcreteLocation<PyUnknownLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAUnknown;
+ static constexpr const char *pyClassName = "UnknownLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationUnknownGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyFileLineColLocation
+ : public PyConcreteLocation<PyFileLineColLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAFileLineColRange;
+ static constexpr const char *pyClassName = "FileLineColLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationFileLineColRangeGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyNameLocation
+ : public PyConcreteLocation<PyNameLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAName;
+ static constexpr const char *pyClassName = "NameLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationNameGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyCallSiteLocation
+ : public PyConcreteLocation<PyCallSiteLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsACallSite;
+ static constexpr const char *pyClassName = "CallSiteLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationCallSiteGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyFusedLocation
+ : public PyConcreteLocation<PyFusedLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAFused;
+ static constexpr const char *pyClassName = "FusedLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationFusedGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyOpaqueLocation
+ : public PyConcreteLocation<PyOpaqueLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAOpaque;
+ static constexpr const char *pyClassName = "OpaqueLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationOpaqueGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
/// Wrapper around the generic MlirValue.
/// Values are managed completely by the operation that resulted in their
/// definition. For op result value, this is the operation that defines the
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index b52328a37e5f1..74189a67d2430 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -1887,6 +1887,23 @@ nb::typed<nb::object, PyAttribute> PyAttribute::maybeDownCast() {
return typeCaster.value()(thisObj);
}
+//------------------------------------------------------------------------------
+// PyLocation::maybeDownCast.
+//------------------------------------------------------------------------------
+
+nb::typed<nb::object, PyLocation> PyLocation::maybeDownCast() {
+ MlirAttribute locAttr = mlirLocationGetAttribute(this->get());
+ MlirTypeID mlirTypeID = mlirAttributeGetTypeID(locAttr);
+ assert(!mlirTypeIDIsNull(mlirTypeID) &&
+ "mlirTypeID was expected to be non-null.");
+ std::optional<nb::callable> typeCaster = PyGlobals::get().lookupTypeCaster(
+ mlirTypeID, mlirAttributeGetDialect(locAttr));
+ nb::object thisObj = nb::cast(this, nb::rv_policy::move);
+ if (!typeCaster)
+ return thisObj;
+ return typeCaster.value()(thisObj);
+}
+
//------------------------------------------------------------------------------
// PyNamedAttribute.
//------------------------------------------------------------------------------
@@ -2965,6 +2982,223 @@ void populateRoot(nb::module_ &m) {
"Register a value caster for casting MLIR values to custom user values.");
}
+//------------------------------------------------------------------------------
+// Location subclass bindDerived implementations.
+//------------------------------------------------------------------------------
+
+void PyUnknownLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](DefaultingPyMlirContext context) {
+ return PyUnknownLocation(context->getRef(),
+ mlirLocationUnknownGet(context->get()));
+ },
+ "context"_a = nb::none(),
+ "Gets a Location representing an unknown location.");
+}
+
+void PyFileLineColLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](std::string filename, int line, int col,
+ DefaultingPyMlirContext context) {
+ return PyFileLineColLocation(
+ context->getRef(),
+ mlirLocationFileLineColGet(context->get(),
+ toMlirStringRef(filename), line, col));
+ },
+ "filename"_a, "line"_a, "col"_a, "context"_a = nb::none(),
+ "Gets a FileLineColLoc for a file, line, and column.");
+ c.def_static(
+ "get",
+ [](std::string filename, int startLine, int startCol, int endLine,
+ int endCol, DefaultingPyMlirContext context) {
+ return PyFileLineColLocation(
+ context->getRef(), mlirLocationFileLineColRangeGet(
+ context->get(), toMlirStringRef(filename),
+ startLine, startCol, endLine, endCol));
+ },
+ "filename"_a, "start_line"_a, "start_col"_a, "end_line"_a, "end_col"_a,
+ "context"_a = nb::none(),
+ "Gets a FileLineColLoc spanning a file and line/column range.");
+ c.def_prop_ro(
+ "filename",
+ [](PyFileLineColLocation &self) {
+ return mlirIdentifierStr(
+ mlirLocationFileLineColRangeGetFilename(self.get()));
+ },
+ "Gets the filename from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "start_line",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetStartLine(self.get());
+ },
+ "Gets the start line number from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "start_col",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetStartColumn(self.get());
+ },
+ "Gets the start column number from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "end_line",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetEndLine(self.get());
+ },
+ "Gets the end line number from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "end_col",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetEndColumn(self.get());
+ },
+ "Gets the end column number from a `FileLineColLoc`.");
+}
+
+void PyNameLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](std::string name, std::optional<PyLocation> childLoc,
+ DefaultingPyMlirContext context) {
+ return PyNameLocation(
+ context->getRef(),
+ mlirLocationNameGet(context->get(), toMlirStringRef(name),
+ childLoc
+ ? childLoc->get()
+ : mlirLocationUnknownGet(context->get())));
+ },
+ "name"_a, "child_loc"_a = nb::none(), "context"_a = nb::none(),
+ "Gets a NameLoc with an optional child location.");
+ c.def_prop_ro(
+ "name_str",
+ [](PyNameLocation &self) {
+ return mlirIdentifierStr(mlirLocationNameGetName(self.get()));
+ },
+ "Gets the name string from a `NameLoc`.");
+ c.def_prop_ro(
+ "child_loc",
+ [](PyNameLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationNameGetChildLoc(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the child location from a `NameLoc`.");
+}
+
+void PyCallSiteLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](PyLocation callee, const std::vector<PyLocation> &frames,
+ DefaultingPyMlirContext context) {
+ if (frames.empty())
+ throw nb::value_error("No caller frames provided.");
+ MlirLocation caller = frames.back().get();
+ for (size_t index = frames.size() - 1; index-- > 0;) {
+ caller = mlirLocationCallSiteGet(frames[index].get(), caller);
+ }
+ return PyCallSiteLocation(
+ context->getRef(), mlirLocationCallSiteGet(callee.get(), caller));
+ },
+ "callee"_a, "frames"_a, "context"_a = nb::none(),
+ "Gets a CallSiteLoc chaining a callee and one or more caller frames.");
+ c.def_prop_ro(
+ "callee",
+ [](PyCallSiteLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationCallSiteGetCallee(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the callee location from a `CallSiteLoc`.");
+ c.def_prop_ro(
+ "caller",
+ [](PyCallSiteLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationCallSiteGetCaller(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the caller location from a `CallSiteLoc`.");
+}
+
+void PyFusedLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](const std::vector<PyLocation> &pyLocations,
+ std::optional<PyAttribute> metadata, DefaultingPyMlirContext context) {
+ std::vector<MlirLocation> locations;
+ locations.reserve(pyLocations.size());
+ for (const PyLocation &pyLocation : pyLocations)
+ locations.push_back(pyLocation.get());
+ MlirLocation location = mlirLocationFusedGet(
+ context->get(), locations.size(), locations.data(),
+ metadata ? metadata->get() : MlirAttribute{0});
+ // FusedLoc construction may collapse to a plain location (e.g. a single
+ // location with no metadata), so downcast to the actual subclass.
+ return PyLocation(context->getRef(), location).maybeDownCast();
+ },
+ "locations"_a, "metadata"_a = nb::none(), "context"_a = nb::none(),
+ "Gets a FusedLoc from an array of locations and optional metadata. "
+ "If the fuse collapses (e.g. single location, no metadata), returns "
+ "the underlying location instead.");
+ c.def_prop_ro(
+ "locations",
+ [](PyFusedLocation &self) {
+ unsigned numLocations = mlirLocationFusedGetNumLocations(self.get());
+ std::vector<MlirLocation> locations(numLocations);
+ if (numLocations)
+ mlirLocationFusedGetLocations(self.get(), locations.data());
+ std::vector<nb::object> pyLocations;
+ pyLocations.reserve(numLocations);
+ for (unsigned i = 0; i < numLocations; ++i)
+ pyLocations.push_back(
+ PyLocation(self.getContext(), locations[i]).maybeDownCast());
+ return pyLocations;
+ },
+ "Gets the list of locations from a `FusedLoc`.");
+ c.def_prop_ro(
+ "metadata",
+ [](PyFusedLocation &self) -> std::optional<PyAttribute> {
+ MlirAttribute metadata = mlirLocationFusedGetMetadata(self.get());
+ if (mlirAttributeIsNull(metadata))
+ return std::nullopt;
+ return PyAttribute(self.getContext(), metadata);
+ },
+ "Gets the metadata attribute from a `FusedLoc`, or None if absent.");
+}
+
+void PyOpaqueLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](uintptr_t underlyingLocation, PyTypeID &underlyingTypeID,
+ PyLocation &fallbackLocation) {
+ return PyOpaqueLocation(fallbackLocation.getContext(),
+ mlirLocationOpaqueGet(underlyingLocation,
+ underlyingTypeID.get(),
+ fallbackLocation.get()));
+ },
+ "underlying_location"_a, "underlying_type_id"_a, "fallback_location"_a,
+ "Gets an OpaqueLoc wrapping a pointer-typed underlying location "
+ "tagged with a TypeID, plus a fallback location.");
+ c.def_prop_ro(
+ "underlying_location",
+ [](PyOpaqueLocation &self) -> uintptr_t {
+ return mlirLocationOpaqueGetUnderlyingLocation(self.get());
+ },
+ "Gets the underlying pointer from an `OpaqueLoc` as an integer.");
+ c.def_prop_ro(
+ "underlying_type_id",
+ [](PyOpaqueLocation &self) {
+ return PyTypeID(mlirLocationOpaqueGetUnderlyingTypeID(self.get()));
+ },
+ "Gets the TypeID tag from an `OpaqueLoc`.");
+ c.def_prop_ro(
+ "fallback_location",
+ [](PyOpaqueLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationOpaqueGetFallbackLocation(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the fallback location from an `OpaqueLoc`.");
+}
+
//------------------------------------------------------------------------------
// Populates the core exports of the 'ir' submodule.
//------------------------------------------------------------------------------
@@ -3337,122 +3571,53 @@ void populateIRCore(nb::module_ &m) {
// clang-format on
"Gets the Location bound to the current thread or raises ValueError.")
.def_static(
- "unknown",
- [](DefaultingPyMlirContext context) {
+ "from_attr",
+ [](PyAttribute &attribute, DefaultingPyMlirContext context) {
return PyLocation(context->getRef(),
- mlirLocationUnknownGet(context->get()));
+ mlirLocationFromAttribute(attribute))
+ .maybeDownCast();
},
- "context"_a = nb::none(),
- "Gets a Location representing an unknown location.")
+ "attribute"_a, "context"_a = nb::none(),
+ "Gets a Location from a `LocationAttr`.")
+ // Factory shims. Prefer the corresponding subclass `.get()` methods in
+ // new code; these remain for backward compatibility and return the
+ // concrete subclass.
.def_static(
- "callsite",
- [](PyLocation callee, const std::vector<PyLocation> &frames,
- DefaultingPyMlirContext context) {
- if (frames.empty())
- throw nb::value_error("No caller frames provided.");
- MlirLocation caller = frames.back().get();
- for (size_t index = frames.size() - 1; index-- > 0;) {
- caller = mlirLocationCallSiteGet(frames[index].get(), caller);
- }
- return PyLocation(context->getRef(),
- mlirLocationCallSiteGet(callee.get(), caller));
- },
- "callee"_a, "frames"_a, "context"_a = nb::none(),
- "Gets a Location representing a caller and callsite.")
- .def("is_a_callsite", mlirLocationIsACallSite,
- "Returns True if this location is a CallSiteLoc.")
- .def_prop_ro(
- "callee",
- [](PyLocation &self) {
- return PyLocation(self.getContext(),
- mlirLocationCallSiteGetCallee(self));
- },
- "Gets the callee location from a CallSiteLoc.")
- .def_prop_ro(
- "caller",
- [](PyLocation &self) {
- return PyLocation(self.getContext(),
- mlirLocationCallSiteGetCaller(self));
+ "unknown",
+ [](DefaultingPyMlirContext context) {
+ return PyUnknownLocation(context->getRef(),
+ mlirLocationUnknownGet(context->get()));
},
- "Gets the caller location from a CallSiteLoc.")
+ "context"_a = nb::none(), "Alias for `UnknownLoc.get()`.")
.def_static(
"file",
[](std::string filename, int line, int col,
DefaultingPyMlirContext context) {
- return PyLocation(
+ return PyFileLineColLocation(
context->getRef(),
mlirLocationFileLineColGet(
context->get(), toMlirStringRef(filename), line, col));
},
"filename"_a, "line"_a, "col"_a, "context"_a = nb::none(),
- "Gets a Location representing a file, line and column.")
+ "Alias for `FileLineColLoc.get()`.")
.def_static(
"file",
[](std::string filename, int startLine, int startCol, int endLine,
int endCol, DefaultingPyMlirContext context) {
- return PyLocation(context->getRef(),
- mlirLocationFileLineColRangeGet(
- context->get(), toMlirStringRef(filename),
- startLine, startCol, endLine, endCol));
+ return PyFileLineColLocation(
+ context->getRef(),
+ mlirLocationFileLineColRangeGet(
+ context->get(), toMlirStringRef(filename), startLine,
+ startCol, endLine, endCol));
},
"filename"_a, "start_line"_a, "start_col"_a, "end_line"_a,
"end_col"_a, "context"_a = nb::none(),
- "Gets a Location representing a file, line and column range.")
- .def("is_a_file", mlirLocationIsAFileLineColRange,
- "Returns True if this location is a FileLineColLoc.")
- .def_prop_ro(
- "filename",
- [](PyLocation loc) {
- return mlirIdentifierStr(
- mlirLocationFileLineColRangeGetFilename(loc));
- },
- "Gets the filename from a FileLineColLoc.")
- .def_prop_ro("start_line", mlirLocationFileLineColRangeGetStartLine,
- "Gets the start line number from a `FileLineColLoc`.")
- .def_prop_ro("start_col", mlirLocationFileLineColRangeGetStartColumn,
- "Gets the start column number from a `FileLineColLoc`.")
- .def_prop_ro("end_line", mlirLocationFileLineColRangeGetEndLine,
- "Gets the end line number from a `FileLineColLoc`.")
- .def_prop_ro("end_col", mlirLocationFileLineColRangeGetEndColumn,
- "Gets the end column number from a `FileLineColLoc`.")
- .def_static(
- "fused",
- [](const std::vector<PyLocation> &pyLocations,
- std::optional<PyAttribute> metadata,
- DefaultingPyMlirContext context) {
- std::vector<MlirLocation> locations;
- locations.reserve(pyLocations.size());
- for (const PyLocation &pyLocation : pyLocations)
- locations.push_back(pyLocation.get());
- MlirLocation location = mlirLocationFusedGet(
- context->get(), locations.size(), locations.data(),
- metadata ? metadata->get() : MlirAttribute{0});
- return PyLocation(context->getRef(), location);
- },
- "locations"_a, "metadata"_a = nb::none(), "context"_a = nb::none(),
- "Gets a Location representing a fused location with optional "
- "metadata.")
- .def("is_a_fused", mlirLocationIsAFused,
- "Returns True if this location is a `FusedLoc`.")
- .def_prop_ro(
- "locations",
- [](PyLocation &self) {
- unsigned numLocations = mlirLocationFusedGetNumLocations(self);
- std::vector<MlirLocation> locations(numLocations);
- if (numLocations)
- mlirLocationFusedGetLocations(self, locations.data());
- std::vector<PyLocation> pyLocations{};
- pyLocations.reserve(numLocations);
- for (unsigned i = 0; i < numLocations; ++i)
- pyLocations.emplace_back(self.getContext(), locations[i]);
- return pyLocations;
- },
- "Gets the list of locations from a `FusedLoc`.")
+ "Alias for `FileLineColLoc.get()` over a range.")
.def_static(
"name",
[](std::string name, std::optional<PyLocation> childLoc,
DefaultingPyMlirContext context) {
- return PyLocation(
+ return PyNameLocation(
context->getRef(),
mlirLocationNameGet(
context->get(), toMlirStringRef(name),
@@ -3460,31 +3625,38 @@ void populateIRCore(nb::module_ &m) {
: mlirLocationUnknownGet(context->get())));
},
"name"_a, "childLoc"_a = nb::none(), "context"_a = nb::none(),
- "Gets a Location representing a named location with optional child "
- "location.")
- .def("is_a_name", mlirLocationIsAName,
- "Returns True if this location is a `NameLoc`.")
- .def_prop_ro(
- "name_str",
- [](PyLocation loc) {
- return mlirIdentifierStr(mlirLocationNameGetName(loc));
- },
- "Gets the name string from a `NameLoc`.")
- .def_prop_ro(
- "child_loc",
- [](PyLocation &self) {
- return PyLocation(self.getContext(),
- mlirLocationNameGetChildLoc(self));
+ "Alias for `NameLoc.get()`.")
+ .def_static(
+ "callsite",
+ [](PyLocation callee, const std::vector<PyLocation> &frames,
+ DefaultingPyMlirContext context) {
+ if (frames.empty())
+ throw nb::value_error("No caller frames provided.");
+ MlirLocation caller = frames.back().get();
+ for (size_t index = frames.size() - 1; index-- > 0;)
+ caller = mlirLocationCallSiteGet(frames[index].get(), caller);
+ return PyCallSiteLocation(
+ context->getRef(),
+ mlirLocationCallSiteGet(callee.get(), caller));
},
- "Gets the child location from a `NameLoc`.")
+ "callee"_a, "frames"_a, "context"_a = nb::none(),
+ "Alias for `CallSiteLoc.get()`.")
.def_static(
- "from_attr",
- [](PyAttribute &attribute, DefaultingPyMlirContext context) {
- return PyLocation(context->getRef(),
- mlirLocationFromAttribute(attribute));
+ "fused",
+ [](const std::vector<PyLocation> &pyLocations,
+ std::optional<PyAttribute> metadata,
+ DefaultingPyMlirContext context) {
+ std::vector<MlirLocation> locations;
+ locations.reserve(pyLocations.size());
+ for (const PyLocation &pyLocation : pyLocations)
+ locations.push_back(pyLocation.get());
+ MlirLocation location = mlirLocationFusedGet(
+ context->get(), locations.size(), locations.data(),
+ metadata ? metadata->get() : MlirAttribute{0});
+ return PyLocation(context->getRef(), location).maybeDownCast();
},
- "attribute"_a, "context"_a = nb::none(),
- "Gets a Location from a `LocationAttr`.")
+ "locations"_a, "metadata"_a = nb::none(), "context"_a = nb::none(),
+ "Alias for `FusedLoc.get()` (may collapse to a non-fused location).")
.def_prop_ro(
"context",
[](PyLocation &self) -> nb::typed<nb::object, PyMlirContext> {
@@ -3519,6 +3691,13 @@ void populateIRCore(nb::module_ &m) {
},
"Returns the assembly representation of the location.");
+ PyUnknownLocation::bind(m);
+ PyFileLineColLocation::bind(m);
+ PyNameLocation::bind(m);
+ PyCallSiteLocation::bind(m);
+ PyFusedLocation::bind(m);
+ PyOpaqueLocation::bind(m);
+
//----------------------------------------------------------------------------
// Mapping of Module
//----------------------------------------------------------------------------
@@ -3727,7 +3906,8 @@ void populateIRCore(nb::module_ &m) {
[](PyOperationBase &self) {
PyOperation &operation = self.getOperation();
return PyLocation(operation.getContext(),
- mlirOperationGetLocation(operation.get()));
+ mlirOperationGetLocation(operation.get()))
+ .maybeDownCast();
},
[](PyOperationBase &self, const PyLocation &location) {
PyOperation &operation = self.getOperation();
@@ -4905,8 +5085,9 @@ void populateIRCore(nb::module_ &m) {
"location",
[](PyValue self) {
return PyLocation(
- PyMlirContext::forContext(mlirValueGetContext(self)),
- mlirValueGetLocation(self));
+ PyMlirContext::forContext(mlirValueGetContext(self)),
+ mlirValueGetLocation(self))
+ .maybeDownCast();
},
"Returns the source location of the value.");
diff --git a/mlir/lib/CAPI/IR/IR.cpp b/mlir/lib/CAPI/IR/IR.cpp
index 481130e5069db..100d28b179e6a 100644
--- a/mlir/lib/CAPI/IR/IR.cpp
+++ b/mlir/lib/CAPI/IR/IR.cpp
@@ -403,6 +403,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 e66c931383f89..359528b6a3a3c 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..97491facc4a2f 100644
--- a/mlir/test/python/ir/location.py
+++ b/mlir/test/python/ir/location.py
@@ -14,7 +14,7 @@ def run(f):
# CHECK-LABEL: TEST: testUnknown
def testUnknown():
with Context() as ctx:
- loc = Location.unknown()
+ loc = UnknownLoc.get()
assert loc.context is ctx
ctx = None
gc.collect()
@@ -23,6 +23,14 @@ def testUnknown():
# CHECK: unknown repr: loc(unknown)
print("unknown repr:", repr(loc))
+ assert isinstance(loc, UnknownLoc)
+ assert isinstance(loc, Location)
+ assert not isinstance(loc, FileLineColLoc)
+ assert not isinstance(loc, NameLoc)
+ assert not isinstance(loc, CallSiteLoc)
+ assert not isinstance(loc, FusedLoc)
+ assert not isinstance(loc, OpaqueLoc)
+
run(testUnknown)
@@ -30,7 +38,7 @@ def testUnknown():
# CHECK-LABEL: TEST: testLocationAttr
def testLocationAttr():
with Context() as ctxt:
- loc = Location.unknown()
+ loc = UnknownLoc.get()
attr = loc.attr
clone = Location.from_attr(attr)
gc.collect()
@@ -39,6 +47,7 @@ def testLocationAttr():
# CHECK: clone: loc(unknown)
print("clone:", str(clone))
assert loc == clone
+ assert isinstance(clone, UnknownLoc)
run(testLocationAttr)
@@ -47,8 +56,8 @@ def testLocationAttr():
# CHECK-LABEL: TEST: testFileLineCol
def testFileLineCol():
with Context() as ctx:
- loc = Location.file("foo1.txt", 123, 56)
- range = Location.file("foo2.txt", 123, 56, 124, 100)
+ loc = FileLineColLoc.get("foo1.txt", 123, 56)
+ range = FileLineColLoc.get("foo2.txt", 123, 56, 124, 100)
ctx = None
gc.collect()
@@ -62,10 +71,10 @@ def testFileLineCol():
# CHECK: file range repr: loc("foo2.txt":123:56 to 124:100)
print("file range repr:", repr(range))
- assert loc.is_a_file()
- assert not loc.is_a_name()
- assert not loc.is_a_callsite()
- assert not loc.is_a_fused()
+ assert isinstance(loc, FileLineColLoc)
+ assert not isinstance(loc, NameLoc)
+ assert not isinstance(loc, CallSiteLoc)
+ assert not isinstance(loc, FusedLoc)
# CHECK: file filename: foo1.txt
print("file filename:", loc.filename)
@@ -78,7 +87,7 @@ def testFileLineCol():
# CHECK: file end_col: 56
print("file end_col:", loc.end_col)
- assert range.is_a_file()
+ assert isinstance(range, FileLineColLoc)
# CHECK: file filename: foo2.txt
print("file filename:", range.filename)
# CHECK: file start_line: 123
@@ -92,7 +101,7 @@ def testFileLineCol():
with Context() as ctx:
ctx.allow_unregistered_dialects = True
- loc = Location.file("foo3.txt", 127, 61)
+ loc = FileLineColLoc.get("foo3.txt", 127, 61)
with loc:
i32 = IntegerType.get_signless(32)
module = Module.create()
@@ -100,6 +109,7 @@ def testFileLineCol():
new_value = Operation.create("custom.op1", results=[i32]).result
# CHECK: new_value location: loc("foo3.txt":127:61)
print("new_value location: ", new_value.location)
+ assert isinstance(new_value.location, FileLineColLoc)
run(testFileLineCol)
@@ -108,8 +118,8 @@ def testFileLineCol():
# CHECK-LABEL: TEST: testName
def testName():
with Context() as ctx:
- loc = Location.name("nombre")
- loc_with_child_loc = Location.name("naam", loc)
+ loc = NameLoc.get("nombre")
+ loc_with_child_loc = NameLoc.get("naam", loc)
ctx = None
gc.collect()
@@ -123,17 +133,19 @@ def testName():
# CHECK: name repr: loc("naam"("nombre"))
print("name repr:", repr(loc_with_child_loc))
- assert loc.is_a_name()
+ assert isinstance(loc, NameLoc)
# CHECK: name name_str: nombre
print("name name_str:", loc.name_str)
# CHECK: name child_loc: loc(unknown)
print("name child_loc:", loc.child_loc)
+ assert isinstance(loc.child_loc, UnknownLoc)
- assert loc_with_child_loc.is_a_name()
+ assert isinstance(loc_with_child_loc, NameLoc)
# CHECK: name name_str: naam
print("name name_str:", loc_with_child_loc.name_str)
# CHECK: name child_loc_with_child_loc: loc("nombre")
print("name child_loc_with_child_loc:", loc_with_child_loc.child_loc)
+ assert isinstance(loc_with_child_loc.child_loc, NameLoc)
run(testName)
@@ -142,9 +154,12 @@ def testName():
# CHECK-LABEL: TEST: testCallSite
def testCallSite():
with Context() as ctx:
- loc = Location.callsite(
- Location.file("foo.text", 123, 45),
- [Location.file("util.foo", 379, 21), Location.file("main.foo", 100, 63)],
+ loc = CallSiteLoc.get(
+ FileLineColLoc.get("foo.text", 123, 45),
+ [
+ FileLineColLoc.get("util.foo", 379, 21),
+ FileLineColLoc.get("main.foo", 100, 63),
+ ],
)
ctx = None
# CHECK: callsite str: loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63))
@@ -152,12 +167,13 @@ def testCallSite():
# CHECK: callsite repr: loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63))
print("callsite repr:", repr(loc))
- assert loc.is_a_callsite()
-
+ assert isinstance(loc, CallSiteLoc)
# CHECK: callsite callee: loc("foo.text":123:45)
print("callsite callee:", loc.callee)
+ assert isinstance(loc.callee, FileLineColLoc)
# CHECK: callsite caller: loc(callsite("util.foo":379:21 at "main.foo":100:63))
print("callsite caller:", loc.caller)
+ assert isinstance(loc.caller, CallSiteLoc)
run(testCallSite)
@@ -166,35 +182,39 @@ def testCallSite():
# CHECK-LABEL: TEST: testFused
def testFused():
with Context() as ctx:
- loc_single = Location.fused([Location.name("apple")])
- loc = Location.fused([Location.name("apple"), Location.name("banana")])
+ loc_single = FusedLoc.get([NameLoc.get("apple")])
+ loc = FusedLoc.get([NameLoc.get("apple"), NameLoc.get("banana")])
attr = Attribute.parse('"sauteed"')
- loc_attr = Location.fused(
- [Location.name("carrot"), Location.name("potatoes")], attr
+ loc_attr = FusedLoc.get(
+ [NameLoc.get("carrot"), NameLoc.get("potatoes")], attr
)
- loc_empty = Location.fused([])
- loc_empty_attr = Location.fused([], attr)
- loc_single_attr = Location.fused([Location.name("apple")], attr)
+ loc_empty = FusedLoc.get([])
+ loc_empty_attr = FusedLoc.get([], attr)
+ loc_single_attr = FusedLoc.get([NameLoc.get("apple")], attr)
ctx = None
- assert not loc_single.is_a_fused()
+ # Fusing a single location without metadata returns that location unchanged.
+ assert not isinstance(loc_single, FusedLoc)
+ assert isinstance(loc_single, NameLoc)
# CHECK: fused str: loc("apple")
print("fused str:", str(loc_single))
# CHECK: fused repr: loc("apple")
print("fused repr:", repr(loc_single))
- # # CHECK: fused locations: []
- print("fused locations:", loc_single.locations)
- assert loc.is_a_fused()
+ assert isinstance(loc, FusedLoc)
# CHECK: fused str: loc(fused["apple", "banana"])
print("fused str:", str(loc))
# CHECK: fused repr: loc(fused["apple", "banana"])
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()
+ assert isinstance(loc_attr, FusedLoc)
+ # 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"])
@@ -202,15 +222,15 @@ def testFused():
# CHECK: fused locations: [loc("carrot"), loc("potatoes")]
print("fused locations:", loc_attr.locations)
- assert not loc_empty.is_a_fused()
+ # Empty fuse without metadata collapses to unknown.
+ assert not isinstance(loc_empty, FusedLoc)
+ assert isinstance(loc_empty, UnknownLoc)
# CHECK: fused str: loc(unknown)
print("fused str:", str(loc_empty))
# CHECK: fused repr: loc(unknown)
print("fused repr:", repr(loc_empty))
- # CHECK: fused locations: []
- print("fused locations:", loc_empty.locations)
- assert loc_empty_attr.is_a_fused()
+ assert isinstance(loc_empty_attr, FusedLoc)
# CHECK: fused str: loc(fused<"sauteed">[unknown])
print("fused str:", str(loc_empty_attr))
# CHECK: fused repr: loc(fused<"sauteed">[unknown])
@@ -218,7 +238,7 @@ def testFused():
# CHECK: fused locations: [loc(unknown)]
print("fused locations:", loc_empty_attr.locations)
- assert loc_single_attr.is_a_fused()
+ assert isinstance(loc_single_attr, FusedLoc)
# CHECK: fused str: loc(fused<"sauteed">["apple"])
print("fused str:", str(loc_single_attr))
# CHECK: fused repr: loc(fused<"sauteed">["apple"])
@@ -230,10 +250,61 @@ def testFused():
run(testFused)
+# CHECK-LABEL: TEST: testOpaque
+def testOpaque():
+ with Context() as ctx:
+ fallback = FileLineColLoc.get("fallback.txt", 42, 7)
+ type_id = IntegerType.get_signless(32).typeid
+ loc = OpaqueLoc.get(0xDEADBEEF, type_id, fallback)
+
+ ctx = None
+ gc.collect()
+
+ # Printing falls back to the fallback location.
+ # CHECK: opaque str: loc("fallback.txt":42:7)
+ print("opaque str:", str(loc))
+
+ assert isinstance(loc, OpaqueLoc)
+ assert not isinstance(loc, UnknownLoc)
+ assert not isinstance(loc, FileLineColLoc)
+
+ # 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
+ assert isinstance(loc.fallback_location, FileLineColLoc)
+
+
+run(testOpaque)
+
+
+# CHECK-LABEL: TEST: testCast
+def testCast():
+ with Context() as ctx:
+ unknown = UnknownLoc.get()
+ # Explicit cast from base Location to subclass succeeds for a match.
+ as_unknown = UnknownLoc(unknown)
+ assert isinstance(as_unknown, UnknownLoc)
+
+ # Casting to the wrong subclass raises.
+ try:
+ FileLineColLoc(unknown)
+ except ValueError as e:
+ # CHECK: cast error: Cannot cast location to FileLineColLoc
+ print("cast error:", str(e))
+ else:
+ assert False, "expected ValueError"
+
+ ctx = None
+
+
+run(testCast)
+
+
# CHECK-LABEL: TEST: testLocationCapsule
def testLocationCapsule():
with Context() as ctx:
- loc1 = Location.file("foo.txt", 123, 56)
+ loc1 = FileLineColLoc.get("foo.txt", 123, 56)
# CHECK: mlir.ir.Location._CAPIPtr
loc_capsule = loc1._CAPIPtr
print(loc_capsule)
More information about the Mlir-commits
mailing list