summaryrefslogtreecommitdiff
path: root/mlir/lib/Bindings/Python/MainModule.cpp
AgeCommit message (Collapse)Author
2025-10-02[MLIR][Python] fixup Context and Location stubs and NanobindAdaptors (#161433)Maksim Levental
add correct names for `NB_TYPE_CASTER(..., name)` so users of `NanobindAdaptors.h` can generate the correct hints. Also fix a few straggler stubs.
2025-09-20[MLIR][Python] reland (narrower) type stub generation (#157930)Maksim Levental
This a reland of https://github.com/llvm/llvm-project/pull/155741 which was reverted at https://github.com/llvm/llvm-project/pull/157831. This version is narrower in scope - it only turns on automatic stub generation for `MLIRPythonExtension.Core._mlir` and **does not do anything automatically**. Specifically, the only CMake code added to `AddMLIRPython.cmake` is the `mlir_generate_type_stubs` function which is then used only in a manual way. The API for `mlir_generate_type_stubs` is: ``` Arguments: MODULE_NAME: The fully-qualified name of the extension module (used for importing in python). DEPENDS_TARGETS: List of targets these type stubs depend on being built; usually corresponding to the specific extension module (e.g., something like StandalonePythonModules.extension._standaloneDialectsNanobind.dso) and the core bindings extension module (e.g., something like StandalonePythonModules.extension._mlir.dso). OUTPUT_DIR: The root output directory to emit the type stubs into. OUTPUTS: List of expected outputs. DEPENDS_TARGET_SRC_DEPS: List of cpp sources for extension library (for generating a DEPFILE). IMPORT_PATHS: List of paths to add to PYTHONPATH for stubgen. PATTERN_FILE: (Optional) Pattern file (see https://nanobind.readthedocs.io/en/latest/typing.html#pattern-files). Outputs: NB_STUBGEN_CUSTOM_TARGET: The target corresponding to generation which other targets can depend on. ``` Downstream users should use `mlir_generate_type_stubs` in coordination with `declare_mlir_python_sources` to turn on stub generation for their own downstream dialect extensions and upstream dialect extensions if they so choose. Standalone example shows an example. Note, downstream will also need to set `-DMLIR_PYTHON_PACKAGE_PREFIX=...` correctly for their bindings.
2025-09-09[MLIR] [Python] Added a context manager for enabling traceback-based ↵Sergei Lebedev
locations (#157562) Previously this functionality was not surfaced in the public API.
2025-09-08[MLIR][Python] Support Python-defined passes in MLIR (#156000)Twice
It closes #155996. This PR added a method `add(callable, ..)` to `mlir.passmanager.PassManager` to accept a callable object for defining passes in the Python side. This is a simple example of a Python-defined pass. ```python from mlir.passmanager import PassManager def demo_pass_1(op): # do something with op pass class DemoPass: def __init__(self, ...): pass def __call__(op): # do something pass demo_pass_2 = DemoPass(..) pm = PassManager('any', ctx) pm.add(demo_pass_1) pm.add(demo_pass_2) pm.add("registered-passes") pm.run(..) ``` --------- Co-authored-by: cnb.bsD2OPwAgEA <QejD2DJ2eEahUVy6Zg0aZI+cnb.bsD2OPwAgEA@noreply.cnb.cool> Co-authored-by: Maksim Levental <maksim.levental@gmail.com>
2025-08-12[mlir][python] automatic location inference (#151246)Maksim Levental
This PR implements "automatic" location inference in the bindings. The way it works is it walks the frame stack collecting source locations (Python captures these in the frame itself). It is inspired by JAX's [implementation](https://github.com/jax-ml/jax/blob/523ddcfbcad005deab5a7d542df4c706f5ee5e9c/jax/_src/interpreters/mlir.py#L462) but moves the frame stack traversal into the bindings for better performance. The system supports registering "included" and "excluded" filenames; frames originating from functions in included filenames **will not** be filtered and frames originating from functions in excluded filenames **will** be filtered (in that order). This allows excluding all the generated `*_ops_gen.py` files. The system is also "toggleable" and off by default to save people who have their own systems (such as JAX) from the added cost. Note, the system stores the entire stacktrace (subject to `locTracebackFramesLimit`) in the `Location` using specifically a `CallSiteLoc`. This can be useful for profiling tools (flamegraphs etc.). Shoutout to the folks at JAX for coming up with a good system. --------- Co-authored-by: Jacques Pienaar <jpienaar@google.com>
2025-01-13Enabled freethreading support in MLIR python bindings (#122684)vfdev
Reland reverted https://github.com/llvm/llvm-project/pull/107103 with the fixes for Python 3.8 cc @jpienaar Co-authored-by: Peter Hawkins <phawkins@google.com>
2025-01-12Revert "Added free-threading CPython mode support in MLIR Python bindings ↵Jacques Pienaar
(#107103)" Breaks on 3.8, rolling back to avoid breakage while fixing. This reverts commit 9dee7c44491635ec9037b90050bcdbd3d5291e38.
2025-01-12Added free-threading CPython mode support in MLIR Python bindings (#107103)vfdev
Related to https://github.com/llvm/llvm-project/issues/105522 Description: This PR is a joint work with Peter Hawkins (@hawkinsp) originally done by myself for pybind11 and then reworked to nanobind based on Peter's branch: https://github.com/hawkinsp/llvm-project/tree/nbdev . - Added free-threading CPython mode support for MLIR Python bindings - Added a test which can reveal data races when cpython and LLVM/MLIR compiled with TSAN Context: - Related to https://github.com/google/jax/issues/23073 Co-authored-by: Peter Hawkins <phawkins@google.com>
2024-12-20[mlir python] Port in-tree dialects to nanobind. (#119924)Peter Hawkins
This is a companion to #118583, although it can be landed independently because since #117922 dialects do not have to use the same Python binding framework as the Python core code. This PR ports all of the in-tree dialect and pass extensions to nanobind, with the exception of those that remain for testing pybind11 support. This PR also: * removes CollectDiagnosticsToStringScope from NanobindAdaptors.h. This was overlooked in a previous PR and it is duplicated in Diagnostics.h. --------- Co-authored-by: Jacques Pienaar <jpienaar@google.com>
2024-12-18[mlir python] Port Python core code to nanobind. (#120473)Peter Hawkins
Relands #118583, with a fix for Python 3.8 compatibility. It was not possible to set the buffer protocol accessers via slots in Python 3.8. Why? https://nanobind.readthedocs.io/en/latest/why.html says it better than I can, but my primary motivation for this change is to improve MLIR IR construction time from JAX. For a complicated Google-internal LLM model in JAX, this change improves the MLIR lowering time by around 5s (out of around 30s), which is a significant speedup for simply switching binding frameworks. To a large extent, this is a mechanical change, for instance changing `pybind11::` to `nanobind::`. Notes: * this PR needs Nanobind 2.4.0, because it needs a bug fix (https://github.com/wjakob/nanobind/pull/806) that landed in that release. * this PR does not port the in-tree dialect extension modules. They can be ported in a future PR. * I removed the py::sibling() annotations from def_static and def_class in `PybindAdapters.h`. These ask pybind11 to try to form an overload with an existing method, but it's not possible to form mixed pybind11/nanobind overloads this ways and the parent class is now defined in nanobind. Better solutions may be possible here. * nanobind does not contain an exact equivalent of pybind11's buffer protocol support. It was not hard to add a nanobind implementation of a similar API. * nanobind is pickier about casting to std::vector<bool>, expecting that the input is a sequence of bool types, not truthy values. In a couple of places I added code to support truthy values during casting. * nanobind distinguishes bytes (`nb::bytes`) from strings (e.g., `std::string`). This required nb::bytes overloads in a few places.
2024-12-18Revert "[mlir python] Port Python core code to nanobind. (#118583)"Jacques Pienaar
This reverts commit 41bd35b58bb482fd466aa4b13aa44a810ad6470f. Breakage detected, rolling back.
2024-12-18[mlir python] Port Python core code to nanobind. (#118583)Peter Hawkins
Why? https://nanobind.readthedocs.io/en/latest/why.html says it better than I can, but my primary motivation for this change is to improve MLIR IR construction time from JAX. For a complicated Google-internal LLM model in JAX, this change improves the MLIR lowering time by around 5s (out of around 30s), which is a significant speedup for simply switching binding frameworks. To a large extent, this is a mechanical change, for instance changing `pybind11::` to `nanobind::`. Notes: * this PR needs Nanobind 2.4.0, because it needs a bug fix (https://github.com/wjakob/nanobind/pull/806) that landed in that release. * this PR does not port the in-tree dialect extension modules. They can be ported in a future PR. * I removed the py::sibling() annotations from def_static and def_class in `PybindAdapters.h`. These ask pybind11 to try to form an overload with an existing method, but it's not possible to form mixed pybind11/nanobind overloads this ways and the parent class is now defined in nanobind. Better solutions may be possible here. * nanobind does not contain an exact equivalent of pybind11's buffer protocol support. It was not hard to add a nanobind implementation of a similar API. * nanobind is pickier about casting to std::vector<bool>, expecting that the input is a sequence of bool types, not truthy values. In a couple of places I added code to support truthy values during casting. * nanobind distinguishes bytes (`nb::bytes`) from strings (e.g., `std::string`). This required nb::bytes overloads in a few places.
2024-11-11[mlir][python] Make types in register_(dialect|operation) more narrow. (#115307)Ingo Müller
This PR makes the `pyClass`/`dialectClass` arguments of the pybind11 functions `register_dialect` and `register_operation` as well as their return types more narrow, concretely, a `py::type` instead of a `py::object`. As the name of the arguments indicate, they have to be called with a type instance (a "class"). The PR also updates the typing stubs of these functions (in the corresponding `.pyi` file), such that static type checkers are aware of the changed type. With the previous typing information, `pyright` raised errors on code generated by tablegen. Signed-off-by: Ingo Müller <ingomueller@google.com>
2024-06-11[mlir] Add PDL C & Python usage (#94714)Jacques Pienaar
Following a rather direct approach to expose PDL usage from C and then Python. This doesn't yes plumb through adding support for custom matchers through this interface, so constrained to basics initially. This also exposes greedy rewrite driver. Only way currently to define patterns is via PDL (just to keep small). The creation of the PDL pattern module could be improved to avoid folks potentially accessing the module used to construct it post construction. No ergonomic work done yet. --------- Signed-off-by: Jacques Pienaar <jpienaar@google.com>
2023-11-07[mlir][python] value casting (#69644)Maksim Levental
This PR adds "value casting", i.e., a mechanism to wrap `ir.Value` in a proxy class that overloads dunders such as `__add__`, `__sub__`, and `__mul__` for fun and great profit. This is thematically similar to https://github.com/llvm/llvm-project/commit/bfb1ba752655bf09b35c486f6cc9817dbedfb1bb and https://github.com/llvm/llvm-project/commit/9566ee280607d91fa2e5eca730a6765ac84dfd0f. The example in the test demonstrates the value of the feature (no pun intended): ```python @register_value_caster(F16Type.static_typeid) @register_value_caster(F32Type.static_typeid) @register_value_caster(F64Type.static_typeid) @register_value_caster(IntegerType.static_typeid) class ArithValue(Value): __add__ = partialmethod(_binary_op, op="add") __sub__ = partialmethod(_binary_op, op="sub") __mul__ = partialmethod(_binary_op, op="mul") a = arith.constant(value=FloatAttr.get(f16_t, 42.42)) b = a + a # CHECK: ArithValue(%0 = arith.addf %cst, %cst : f16) print(b) a = arith.constant(value=FloatAttr.get(f32_t, 42.42)) b = a - a # CHECK: ArithValue(%1 = arith.subf %cst_0, %cst_0 : f32) print(b) a = arith.constant(value=FloatAttr.get(f64_t, 42.42)) b = a * a # CHECK: ArithValue(%2 = arith.mulf %cst_1, %cst_1 : f64) print(b) ``` **EDIT**: this now goes through the bindings and thus supports automatic casting of `OpResult` (including as an element of `OpResultList`), `BlockArgument` (including as an element of `BlockArgumentList`), as well as `Value`.
2023-11-03[mlir][python] remove various caching mechanisms (#70831)Maksim Levental
This PR removes the various caching mechanisms currently in the python bindings - both positive caching and negative caching.
2023-10-19[mlir][python] remove mixins (#68853)Maksim Levental
This PR replaces the mixin `OpView` extension mechanism with the standard inheritance mechanism. Why? Firstly, mixins are not very pythonic (inheritance is usually used for this), a little convoluted, and too "tight" (can only be used in the immediately adjacent `_ext.py`). Secondly, it (mixins) are now blocking are correct implementation of "value builders" (see [here](https://github.com/llvm/llvm-project/pull/68764)) where the problem becomes how to choose the correct base class that the value builder should call. This PR looks big/complicated but appearances are deceiving; 4 things were needed to make this work: 1. Drop `skipDefaultBuilders` in `OpPythonBindingGen::emitDefaultOpBuilders` 2. Former mixin extension classes are converted to inherit from the generated `OpView` instead of being "mixins" a. extension classes that simply were calling into an already generated `super().__init__` continue to do so b. (almost all) extension classes that were calling `self.build_generic` because of a lack of default builder being generated can now also just call `super().__init__` 3. To handle the [lone single use-case](https://sourcegraph.com/search?q=context%3Aglobal+select_opview_mixin&patternType=standard&sm=1&groupBy=repo) of `select_opview_mixin`, namely [linalg](https://github.com/llvm/llvm-project/blob/main/mlir/python/mlir/dialects/_linalg_ops_ext.py#L38), only a small change was necessary in `opdsl/lang/emitter.py` (thanks to the emission/generation of default builders/`__init__`s) 4. since the `extend_opview_class` decorator is removed, we need a way to register extension classes as the desired `OpView` that `op.opview` conjures into existence; so we do the standard thing and just enable replacing the existing registered `OpView` i.e., `register_operation(_Dialect, replace=True)`. Note, the upgrade path for the common case is to change an extension to inherit from the generated builder and decorate it with `register_operation(_Dialect, replace=True)`. In the slightly more complicated case where `super().__init(self.build_generic(...))` is called in the extension's `__init__`, this needs to be updated to call `__init__` in `OpView`, i.e., the grandparent (see updated docs). Note, also `<DIALECT>_ext.py` files/modules will no longer be automatically loaded. Note, the PR has 3 base commits that look funny but this was done for the purpose of tracking the line history of moving the `<DIALECT>_ops_ext.py` class into `<DIALECT>.py` and updating (commit labeled "fix").
2023-05-26[MLIR][python bindings] Add TypeCaster for returning refined types from ↵max
python APIs depends on D150839 This diff uses `MlirTypeID` to register `TypeCaster`s (i.e., `[](PyType pyType) -> DerivedTy { return pyType; }`) for all concrete types (i.e., `PyConcrete<...>`) that are then queried for (by `MlirTypeID`) and called in `struct type_caster<MlirType>::cast`. The result is that anywhere an `MlirType mlirType` is returned from a python binding, that `mlirType` is automatically cast to the correct concrete type. For example: ``` c0 = arith.ConstantOp(f32, 0.0) # CHECK: F32Type(f32) print(repr(c0.result.type)) unranked_tensor_type = UnrankedTensorType.get(f32) unranked_tensor = tensor.FromElementsOp(unranked_tensor_type, [c0]).result # CHECK: UnrankedTensorType print(type(unranked_tensor.type).__name__) # CHECK: UnrankedTensorType(tensor<*xf32>) print(repr(unranked_tensor.type)) ``` This functionality immediately extends to typed attributes (i.e., `attr.type`). The diff also implements similar functionality for `mlir_type_subclass`es but in a slightly different way - for such types (which have no cpp corresponding `class` or `struct`) the user must provide a type caster in python (similar to how `AttrBuilder` works) or in cpp as a `py::cpp_function`. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D150927
2023-03-01[mlir][python] Remove "Raw" OpView classesRahul Kayaith
The raw `OpView` classes are used to bypass the constructors of `OpView` subclasses, but having a separate class can create some confusing behaviour, e.g.: ``` op = MyOp(...) # fails, lhs is 'MyOp', rhs is '_MyOp' assert type(op) == type(op.operation.opview) ``` Instead we can use `__new__` to achieve the same thing without a separate class: ``` my_op = MyOp.__new__(MyOp) OpView.__init__(my_op, op) ``` Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D143830
2022-01-06[mlir] Split out Python bindings for dialects into separate libsAlex Zinenko
Historically, the bindings for the Linalg dialect were included into the "core" bindings library because they depended on the C++ implementation of the "core" bindings. The other dialects followed the pattern. Now that this dependency is gone, split out each dialect into a separate Python extension library. Depends On D116649, D116605 Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D116662
2022-01-05[mlir] Introduce Python bindings for the quantization dialectAlex Zinenko
So far, only the custom dialect types are exposed. The build and packaging is same as for Linalg and SparseTensor, and in need of refactoring that is beyond the scope of this patch. Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D116605
2021-11-29[mlir][python] Add pyi stub files to enable auto completion.Stella Laurenzo
There is no completely automated facility for generating stubs that are both accurate and comprehensive for native modules. After some experimentation, I found that MyPy's stubgen does the best at generating correct stubs with a few caveats that are relatively easy to fix: * Some types resolve to cross module symbols incorrectly. * staticmethod and classmethod signatures seem to always be completely generic and need to be manually provided. * It does not generate an __all__ which, from testing, causes namespace pollution to be visible to IDE code completion. As a first step, I did the following: * Ran `stubgen` for `_mlir.ir`, `_mlir.passmanager`, and `_mlirExecutionEngine`. * Manually looked for all instances where unnamed arguments were being emitted (i.e. as 'arg0', etc) and updated the C++ side to include names (and re-ran stubgen to get a good initial state). * Made/noted a few structural changes to each `pyi` file to make it minimally functional. * Added the `pyi` files to the CMake rules so they are installed and visible. To test, I added a `.env` file to the root of the project with `PYTHONPATH=...` set as per instructions. Then reload the developer window (in VsCode) and verify that completion works for various changes to test cases. There are still a number of overly generic signatures, but I want to check in this low-touch baseline before iterating on more ambiguous changes. This is already a big improvement. Differential Revision: https://reviews.llvm.org/D114679
2021-10-25[mlir] support interfaces in Python bindingsAlex Zinenko
Introduce the initial support for operation interfaces in C API and Python bindings. Interfaces are a key component of MLIR's extensibility and should be available in bindings to make use of full potential of MLIR. This initial implementation exposes InferTypeOpInterface all the way to the Python bindings since it can be later used to simplify the operation construction methods by inferring their return types instead of requiring the user to do so. The general infrastructure for binding interfaces is defined and InferTypeOpInterface can be used as an example for binding other interfaces. Reviewed By: gysit Differential Revision: https://reviews.llvm.org/D111656
2021-08-30[mlir][python] Apply py::module_local() to all classes.Stella Laurenzo
* This allows multiple MLIR-API embedding downstreams to co-exist in the same process. * I believe this is the last thing needed to enable isolated embedding. Differential Revision: https://reviews.llvm.org/D108605
2021-07-28Break apart the MLIR ExecutionEngine from core python module.Stella Laurenzo
* For python projects that don't need JIT/ExecutionEngine, cuts the number of files to compile roughly in half (with similar reduction in end binary size). Differential Revision: https://reviews.llvm.org/D106992
2021-05-10[mlir][Python] Upstream the PybindAdaptors.h helpers and use it to implement ↵Stella Laurenzo
sparse_tensor.encoding. * The PybindAdaptors.h file has been evolving across different sub-projects (npcomp, circt) and has been successfully used for out of tree python API interop/extensions and defining custom types. * Since sparse_tensor.encoding is the first in-tree custom attribute we are supporting, it seemed like the right time to upstream this header and use it to define the attribute in a way that we can support for both in-tree and out-of-tree use (prior, I had not wanted to upstream dead code which was not used in-tree). * Adapted the circt version of `mlir_type_subclass`, also providing an `mlir_attribute_subclass`. As we get a bit of mileage on this, I would like to transition the builtin types/attributes to this mechanism and delete the old in-tree only `PyConcreteType` and `PyConcreteAttribute` template helpers (which cannot work reliably out of tree as they depend on internals). * Added support for defaulting the MlirContext if none is passed so that we can support the same idioms as in-tree versions. There is quite a bit going on here and I can split it up if needed, but would prefer to keep the first use and the header together so sending out in one patch. Differential Revision: https://reviews.llvm.org/D102144
2021-04-29[mlir] Split out Python bindings entry point into a separate fileAlex Zinenko
This will allow the bindings to be built as a library and reused in out-of-tree projects that want to provide bindings on top of MLIR bindings. Reviewed By: stellaraccident, mikeurbach Differential Revision: https://reviews.llvm.org/D101075
2021-03-31[mlir][Linalg][Python] Create the body of builtin named Linalg opsNicolas Vasilache
This revision adds support to properly add the body of registered builtin named linalg ops. At this time, indexing_map and iterator_type support is still missing so the op is not executable yet. Differential Revision: https://reviews.llvm.org/D99578
2021-03-19NFC: Break up the mlir python bindings into individual sources.Stella Laurenzo
* IRModules.cpp -> (IRCore.cpp, IRAffine.cpp, IRAttributes.cpp, IRTypes.cpp). * The individual pieces now compile in the 5-15s range whereas IRModules.cpp was starting to approach a minute (didn't capture a before time). * More fine grained splitting is possible, but this represents the most obvious. Differential Revision: https://reviews.llvm.org/D98978
2021-03-03Add basic JIT Python BindingsMehdi Amini
This offers the ability to create a JIT and invoke a function by passing ctypes pointers to the argument and the result. Differential Revision: https://reviews.llvm.org/D97523
2020-11-10Add basic Python bindings for the PassManager and bind libTransformsMehdi Amini
This only exposes the ability to round-trip a textual pipeline at the moment. To exercise it, we also bind the libTransforms in a new Python extension. This does not include any interesting bindings, but it includes all the mechanism to add separate native extensions and load them dynamically. As such passes in libTransforms are only registered after `import mlir.transforms`. To support this global registration, the TableGen backend is also extended to bind to the C API the group registration for passes. Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D90819
2020-11-03[mlir][Python] Return and accept OpView for all functions.Stella Laurenzo
* All functions that return an Operation now return an OpView. * All functions that accept an Operation now accept an _OperationBase, which both Operation and OpView extend and can resolve to the backing Operation. * Moves user-facing instance methods from Operation -> _OperationBase so that both can have the same API. * Concretely, this means that if there are custom op classes defined (i.e. in Python), any iteration or creation will return the appropriate instance (i.e. if you get/create an std.addf, you will get an instance of the mlir.dialects.std.AddFOp class, getting full access to any custom API it exposes). * Refactors all __eq__ methods after realizing the proper way to do this for _OperationBase. Differential Revision: https://reviews.llvm.org/D90584
2020-10-27[mlir][Python] Custom python op view wrappers for building and traversing.Stella Laurenzo
* Still rough edges that need more sugar but the bones are there. Notes left in the test case for things that can be improved. * Does not actually yield custom OpViews yet for traversing. Will rework that in a followup. Differential Revision: https://reviews.llvm.org/D89932
2020-08-17Adds __str__ support to python mlir.ir.MlirModule.Stella Laurenzo
* Also raises an exception on parse error. * Removes placeholder smoketest. * Adds docstrings. Differential Revision: https://reviews.llvm.org/D86046
2020-08-16Initial MLIR python bindings based on the C API.zhanghb97
* Basic support for context creation, module parsing and dumping. Differential Revision: https://reviews.llvm.org/D85481
2020-07-09Initial boiler-plate for python bindings.Stella Laurenzo
Summary: * Native '_mlir' extension module. * Python mlir/__init__.py trampoline module. * Lit test that checks a message. * Uses some cmake configurations that have worked for me in the past but likely needs further elaboration. Subscribers: mgorny, mehdi_amini, rriddle, jpienaar, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, stephenneuendorffer, Joonsoo, grosul1, Kayjukh, jurahul, msifontes Tags: #mlir Differential Revision: https://reviews.llvm.org/D83279