summaryrefslogtreecommitdiff
path: root/mlir/lib/Bindings/Python/Rewrite.cpp
AgeCommit message (Collapse)Author
2025-10-17[MLIR] Fix typo of the word "pattern" in CAPI and docs (#163780)Shenghang Tsai
This includes the rename from `mlirOpRewritePattenCreate` to `mlirOpRewritePatternCreate` in CAPI, and other typo fixes in docs and code comments.
2025-10-13[MLIR][Python] Pass OpView subclasses instead of Operation in rewrite ↵Twice
patterns (#163080) This is a follow-up PR for #162699. Currently, in the function where we define rewrite patterns, the `op` we receive is of type `ir.Operation` rather than a specific `OpView` type (such as `arith.AddIOp`). This means we can’t conveniently access certain parts of the operation — for example, we need to use `op.operands[0]` instead of `op.lhs`. The following example code illustrates this situation. ```python def to_muli(op, rewriter): # op is typed ir.Operation instead of arith.AddIOp pass patterns.add(arith.AddIOp, to_muli) ``` In this PR, we convert the operation to its corresponding `OpView` subclass before invoking the rewrite pattern callback, making it much easier to write patterns. --------- Co-authored-by: Maksim Levental <maksim.levental@gmail.com>
2025-10-11[MLIR][NFC] Clean up rewrite CAPI implementation and Python bindings (#162974)Twice
This is a follow-up PR of #162699. In this PR we clean CAPI and Python bindings of MLIR rewrite part by: - remove all manually-defined `wrap`/`unwrap` functions; - remove useless nanobind-defined Python class `RewritePattern`.
2025-10-11[MLIR][Python] Support Python-defined rewrite patterns (#162699)Twice
This PR adds support for defining custom **`RewritePattern`** implementations directly in the Python bindings. Previously, users could define similar patterns using the PDL dialect’s bindings. However, for more complex patterns, this often required writing multiple Python callbacks as PDL native constraints or rewrite functions, which made the overall logic less intuitive—though it could be more performant than a pure Python implementation (especially for simple patterns). With this change, we introduce an additional, straightforward way to define patterns purely in Python, complementing the existing PDL-based approach. ### Example ```python def to_muli(op, rewriter): with rewriter.ip: new_op = arith.muli(op.operands[0], op.operands[1], loc=op.location) rewriter.replace_op(op, new_op.owner) with Context(): patterns = RewritePatternSet() patterns.add(arith.AddIOp, to_muli) # a pattern that rewrites arith.addi to arith.muli frozen = patterns.freeze() module = ... apply_patterns_and_fold_greedily(module, frozen) ``` --------- Co-authored-by: Maksim Levental <maksim.levental@gmail.com>
2025-10-05[MLIR][Python] Expose the insertion point of pattern rewriter (#161001)Twice
In [#160520](https://github.com/llvm/llvm-project/pull/160520), we discussed the current limitations of PDL rewriting in Python (see [this comment](https://github.com/llvm/llvm-project/pull/160520#issuecomment-3332326184)). At the moment, we cannot create new operations in PDL native (python) rewrite functions because the `PatternRewriter` APIs are not exposed. This PR introduces bindings to retrieve the insertion point of the `PatternRewriter`, enabling users to create new operations within Python rewrite functions. With this capability, more complex rewrites e.g. with branching and loops that involve op creations become possible. --------- Co-authored-by: Maksim Levental <maksim.levental@gmail.com>
2025-10-01[MLIR] Apply clang-tidy fixes for performance-unnecessary-value-param in ↵Mehdi Amini
Rewrite.cpp (NFC)
2025-09-29[MLIR][Python] Fix PDLResultList bindings (#161102)Billy Zhu
Adds argument names to the method stubs for PDLResultList (from https://github.com/llvm/llvm-project/pull/159926).
2025-09-25[MLIR][Python] Add bindings for PDL constraint function registering (#160520)Twice
This is a follow-up to #159926. That PR (#159926) exposed native rewrite function registration in PDL through the C API and Python, enabling use with `pdl.apply_native_rewrite`. In this PR, we add support for native constraint functions in PDL via `pdl.apply_native_constraint`, further completing the PDL API.
2025-09-24[MLIR][Python] Add bindings for PDL native rewrite function registering ↵Twice
(#159926) In the MLIR Python bindings, we can currently use PDL to define simple patterns and then execute them with the greedy rewrite driver. However, when dealing with more complex patterns—such as constant folding for integer addition—we find that we need `apply_native_rewrite` to actually perform arithmetic (i.e., compute the sum of two constants). For example, consider the following PDL pseudocode: ```mlir pdl.pattern : benefit(1) { %a0 = pdl.attribute %a1 = pdl.attribute %c0 = pdl.operation "arith.constant" {value = %a0} %c1 = pdl.operation "arith.constant" {value = %a1} %op = pdl.operation "arith.addi"(%c0, %c1) %sum = pdl.apply_native_rewrite "addIntegers"(%a0, %a1) %new_cst = pdl.operation "arith.constant" {value = %sum} pdl.replace %op with %new_cst } ``` Here, `addIntegers` cannot be expressed in PDL alone—it requires a *native rewrite function*. This PR introduces a mechanism to support exactly that, allowing complex rewrite patterns to be expressed in Python and enabling many passes to be implemented directly in Python as well. As a test case, we defined two new operations (`myint.constant` and `myint.add`) in Python and implemented a constant-folding rewrite pattern for them. The core code looks like this: ```python m = Module.create() with InsertionPoint(m.body): @pdl.pattern(benefit=1, sym_name="myint_add_fold") def pat(): ... op0 = pdl.OperationOp(name="myint.add", args=[v0, v1], types=[t]) @pdl.rewrite() def rew(): sum = pdl.apply_native_rewrite( [pdl.AttributeType.get()], "add_fold", [a0, a1] ) newOp = pdl.OperationOp( name="myint.constant", attributes={"value": sum}, types=[t] ) pdl.ReplaceOp(op0, with_op=newOp) def add_fold(rewriter, results, values): a0, a1 = values results.push_back(IntegerAttr.get(i32, a0.value + a1.value)) pdl_module = PDLModule(m) pdl_module.register_rewrite_function("add_fold", add_fold) ``` The idea is previously discussed in Discord #mlir-python channel with @makslevental. --------- Co-authored-by: Maksim Levental <maksim.levental@gmail.com>
2025-09-22[MLIR][Python] restore APIs in terms of Mlir* types (#160203)Maksim Levental
https://github.com/llvm/llvm-project/pull/157930 changed a few APIs from `Mlir*` to `Py*` and broke users that were using them (see https://github.com/llvm/llvm-project/pull/160183#issuecomment-3321383969). This PR restores those APIs.
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-08[MLIR][Python] Add a python function to apply patterns with MlirOperation ↵Twice
(#157487) In https://github.com/llvm/llvm-project/pull/94714, we add a python function `apply_patterns_and_fold_greedily` which accepts an `MlirModule` as the argument type. However, sometimes we want to apply patterns with an `MlirOperation` argument, and there is currently no python API to convert an `MlirOperation` to `MlirModule`. So here we overload this function `apply_patterns_and_fold_greedily` to do this (also a corresponding new C API `mlirApplyPatternsAndFoldGreedilyWithOp`)
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-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>