191 Commits

Author SHA1 Message Date
Rolf Morel
f12fcf030c
[MLIR][Transform][Python] transform.foreach wrapper and .owner OpViews (#172228)
Friendlier wrapper for transform.foreach.

To facilitate that friendliness, makes it so that OpResult.owner returns
the relevant OpView instead of Operation. For good measure, also changes
Value.owner to return OpView instead of Operation, thereby ensuring
consistency. That is, makes it is so that all op-returning .owner
accessors return OpView (and thereby give access to all goodies
available on registered OpViews.)

Reland of #171544 due to fixup for integration test.
2025-12-14 22:10:31 +00:00
Mehdi Amini
b9fe6532a7
Revert "[MLIR][Transform][Python] transform.foreach wrapper and .owner OpViews" (#172225)
Reverts llvm/llvm-project#171544 ; bots are broken.
2025-12-14 21:27:02 +00:00
Rolf Morel
4cdec92827
[MLIR][Transform][Python] transform.foreach wrapper and .owner OpViews (#171544)
Friendlier wrapper for `transform.foreach`.

To facilitate that friendliness, makes it so that `OpResult.owner`
returns the relevant `OpView` instead of `Operation`. For good measure,
also changes `Value.owner` to return `OpView` instead of `Operation`,
thereby ensuring consistency. That is, makes it is so that all
op-returning `.owner` accessors return `OpView` (and thereby give access
to all goodies available on registered `OpView`s.)
2025-12-14 20:44:15 +00:00
Hongzheng Chen
86cc934b4a
[python] Expose replaceUsesOfWith C API (#171892)
This PR exposes the `replaceUsesOfWith` C API to Python
2025-12-11 16:09:18 -08:00
Benjamin Chetioui
012721d320
[mlir][python] Propagate error diagnostics when an op couldn't be created. (#169499) 2025-11-25 17:41:01 +00:00
Jacques Pienaar
5ab49edde2
[mlir][py][c] Enable setting block arg locations. (#169033)
This enables changing the location of a block argument. Follows the
approach for updating type of block arg.
2025-11-21 13:31:46 +00:00
Sergei Lebedev
31536e6e9a
[MLIR] [Python] ir.Value is now generic in the type of the value it holds (#166148)
This makes it similar to `mlir::TypedValue` in the MLIR C++ API and
allows users to be more specific about the values they produce or
accept.

Co-authored-by: Maksim Levental <maksim.levental@gmail.com>
2025-11-13 13:23:40 +00:00
Maksim Levental
8346a772bc
[MLIR][Python] fix PyRegionList __iter__ (#167466)
Fixes https://github.com/llvm/llvm-project/issues/167455
2025-11-11 07:25:50 -08:00
Maksim Levental
2d381bf65d
[MLIR][Python] add/fix docstrings in IRCore (#167063)
This PR adds all the missing doc strings in IRCore.cpp. It also

1. Normalizes all doc strings to have proper punctuation;
2. Inlines non-duplicated docstrings which are currently at the top of
the source file (and thereby possibly out of sync).

Follow-up PRs will do the same for the rest of the modules/source files.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-10 15:44:08 +00:00
Maksim Levental
c05ce9b005
[MLIR][Python] fix getOwner to return (typed) nb::object instead of abstract PyOpView (#165053)
https://github.com/llvm/llvm-project/pull/157930 changed `nb::object
getOwner()` to `PyOpView getOwner()` which implicitly constructs the
generic OpView against from a (possibly) concrete OpView. This PR fixes
that.
2025-10-26 01:48:46 +00:00
Perry Gibson
35cd291427
[mlir][python] add dict-style to IR attributes (#163200)
It makes sense that Attribute dicts/maps should behave like dicts in the
Python bindings. Previously this was not the case.
2025-10-16 18:42:05 +01:00
Twice
8181c3deae
[MLIR][Python] Expose the insertion point of pattern rewriter (#161001)
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-05 11:12:11 +08:00
Maksim Levental
a3594cd644
[MLIR][Python] fixup Context and Location stubs and NanobindAdaptors (#161433)
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-10-02 08:18:47 -07:00
Maksim Levental
fea2cca4d6
[MLIR][Python] expose Operation::setLoc (#161594) 2025-10-01 21:57:10 -07:00
Maksim Levental
0d08ffd22c
[MLIR][Python] use nb::typed for return signatures (#160221)
https://github.com/llvm/llvm-project/pull/160183 removed `nb::typed`
annotation to fix bazel but it turned out to be simply a matter of not
using the correct version of nanobind (see
https://github.com/llvm/llvm-project/pull/160183#issuecomment-3321429155).
This PR restores those annotations but (mostly) moves to the return
positions of the actual methods.
2025-09-23 10:54:22 -07:00
Maksim Levental
4a9df48cf8
[MLIR][Python] restore APIs in terms of Mlir* types (#160203)
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-22 15:00:57 -07:00
Maksim Levental
81cbd970cf
[MLIR][Python] remove nb::typed to fix bazel build (#160183)
https://github.com/llvm/llvm-project/pull/157930 broke bazel build (see
https://github.com/llvm/llvm-project/pull/157930#issuecomment-3318681217)
because bazel is stricter on implicit conversions (some difference in
flags passed to clang). This PR fixes by moving/removing `nb::typed`.

EDIT: and also the overlay...
2025-09-22 12:55:43 -07:00
Maksim Levental
efd96afedf
[MLIR][Python] reland (narrower) type stub generation (#157930)
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-20 18:47:32 +00:00
Maksim Levental
6a4f66476f
[MLIR][Python] restore liveModuleMap (#158506)
There are cases where the same module can have multiple references (via
`PyModule::forModule` via `PyModule::createFromCapsule`) and thus when
`PyModule`s get gc'd `mlirModuleDestroy` can get called multiple times
for the same actual underlying `mlir::Module` (i.e., double free). So we
do actually need a "liveness map" for modules.

Note, if `type_caster<MlirModule>::from_cpp` weren't a thing we could guarantree
this never happened except explicitly when users called `PyModule::createFromCapsule`.
2025-09-15 06:45:30 +02:00
Maksim Levental
c4181e51d1
[MLIR][Python] remove unnecessary arg.none() = nb::none() pattern (#157519)
We have `arg.none() = nb::none()` in a lot of places but this is no
longer necessary (as of
~[2022](62a23bb87b)).
2025-09-08 12:16:35 -07:00
Maksim Levental
9a0ed70319
[MLIR][Python] bind InsertionPointAfter (#157156) 2025-09-05 14:30:40 -07:00
Maksim Levental
70a291f322
[MLIR][Python] fix operation hashing (#156514)
https://github.com/llvm/llvm-project/pull/155114 broke op hashing
(because the python objects ceased to be reference equivalent). This PR
fixes by binding `OperationEquivalence::computeHash`.
2025-09-02 15:12:25 -05:00
Maksim Levental
b2a7369631
[MLIR][Python] remove liveOperations (#155114)
Historical context: `PyMlirContext::liveOperations` was an optimization
meant to cut down on the number of Python object allocations and
(partially) a mechanism for updating validity of ops after
transformation. E.g. during walking/transforming the AST. See original
patch [here](https://reviews.llvm.org/D87958).

Inspired by a
[renewed](https://github.com/llvm/llvm-project/pull/139721#issuecomment-3217131918)
interest in https://github.com/llvm/llvm-project/pull/139721 (which has
become a little stale...)

<p align="center">
<img width="504" height="375" alt="image"
src="https://github.com/user-attachments/assets/0daad562-d3d1-4876-8d01-5dba382ab186"
/>
</p>

In the previous go-around
(https://github.com/llvm/llvm-project/pull/92631) there were two issues
which have been resolved

1. ops that were "fetched" under a root op which has been transformed
are no longer reported as invalid. We simply "[formally
forbid](https://github.com/llvm/llvm-project/pull/92631#issuecomment-2119397018)"
this;
2. `Module._CAPICreate(module_capsule)` must now be followed by a
`module._clear_mlir_module()` to prevent double-freeing of the actual
`ModuleOp` object (i.e. calling the dtor on the
`OwningOpRef<ModuleOp>`):

     ```python
    module = ...
    module_dup = Module._CAPICreate(module._CAPIPtr)
    module._clear_mlir_module()
    ```
- **the alternative choice** here is to remove the `Module._CAPICreate`
API altogether and replace it with something like `Module._move(module)`
which will do both `Module._CAPICreate` and `module._clear_mlir_module`.

Note, the other approach I explored last year was a [weakref
system](https://github.com/llvm/llvm-project/pull/97340) for
`mlir::Operation` which would effectively hoist this `liveOperations`
thing into MLIR core. Possibly doable but I now believe it's a bad idea.

The other potentially breaking change is `is`, which checks object
equality rather than value equality, will now report `False` because we
are always allocating `new` Python objects (ie that's the whole point of
this change). Users wanting to check equality for `Operation` and
`Module` should use `==`.
2025-09-01 21:53:33 -07:00
Mehdi Amini
2bfbae99b9 [MLIR] Apply clang-tidy fixes for readability-identifier-naming in IRCore.cpp (NFC) 2025-08-26 12:03:01 -07:00
Mehdi Amini
8344a53c0d [MLIR] Apply clang-tidy fixes for performance-move-const-arg in IRCore.cpp (NFC) 2025-08-26 12:03:01 -07:00
Mehdi Amini
e3b0e92912 [MLIR] Apply clang-tidy fixes for modernize-use-using in IRCore.cpp (NFC) 2025-08-26 12:03:01 -07:00
Mehdi Amini
e007a383d6 [MLIR] Apply clang-tidy fixes for misc-use-internal-linkage in IRCore.cpp (NFC) 2025-08-26 06:14:24 -07:00
Maksim Levental
6fc1deb8b7
[mlir][python] handle more undefined symbols not covered by nanobind (#153861)
Introduced (but omitted from this CMake) in
https://github.com/llvm/llvm-project/pull/151246.
2025-08-16 09:25:15 -04:00
Maksim Levental
2b842e5600
[mlir][python] fix PyThreadState_GetFrame again (#153333)
add more APIs missing from 3.8 (fix rocm builder)
2025-08-12 21:29:23 -05:00
Maksim Levental
9df846bf71
[mlir][python] fix PyThreadState_GetFrame (#153325)
`PyThreadState_GetFrame` wasn't added until 3.9 (fixes currently failing
rocm builder)
2025-08-13 01:16:04 +00:00
Maksim Levental
a40f47c972
[mlir][python] automatic location inference (#151246)
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](523ddcfbca/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-08-12 16:59:59 -05:00
Maksim Levental
7fb8a44ad5
[mlir][python] expose isAttached (#153045) 2025-08-11 12:21:59 -05:00
Maksim Levental
a36508483e
[mlir][python,CAPI] expose Op::isBeforeInBlock (#150271) 2025-07-23 12:33:42 -05:00
Akshay Khadse
e4a3541ff8
[MLIR][Python] Support eliding large resource strings in PassManager (#149187)
- Introduces a `large_resource_limit` parameter across Python bindings,
enabling the eliding of resource strings exceeding a specified character
limit during IR printing.
- To maintain backward compatibilty, when using `operation.print()` API,
if `large_resource_limit` is None and the `large_elements_limit` is set,
the later will be used to elide the resource string as well. This change
was introduced by https://github.com/llvm/llvm-project/pull/125738.
- For printing using pass manager, the `large_resource_limit` and
`large_elements_limit` are completely independent of each other.
2025-07-17 12:57:04 -04:00
Maksim Levental
a2aa812a31
[mlir][python] bind block predecessors and successors (#145116)
bind `block.getSuccessor` and `block.getPredecessors`.
2025-06-23 19:59:03 -04:00
Maksim Levental
227f759644
[mlir][python] expose operation.block (#145088)
Expose `operation-getBlock()` in python.
2025-06-20 15:34:43 -04:00
Maksim Levental
9b50167ed9
[mlir][python] add use_name_loc_as_prefix to value.get_name() (#135052)
Add `use_name_loc_as_prefix` to `value.get_name()`.
2025-04-09 19:28:59 -04:00
Sergei Lebedev
c8a9a4109a
[MLIR] [python] A few improvements to the Python bindings (#131686)
* `PyRegionList` is now sliceable. The dialect bindings generator seems
to assume it is sliceable already (!), yet accessing e.g. `cases` on
`scf.IndexedSwitchOp` raises a `TypeError` at runtime.
* `PyBlockList` and `PyOperationList` support negative indexing. It is
common for containers to do that in Python, and most container in the
MLIR Python bindings already allow the index to be negative.
2025-03-21 00:13:13 -04:00
vfdev
ab18cc246c
[MLIR][py] Add PyThreadPool as wrapper around MlirLlvmThreadPool in MLIR python bindings (#130109)
In some projects like JAX ir.Context are used with disabled multi-threading to avoid
caching multiple threading pools:

623865fe95/jax/_src/interpreters/mlir.py (L606-L611)

However, when context has enabled multithreading it also uses locks on
the StorageUniquers and this can be helpful to avoid data races in the
multi-threaded execution (for example with free-threaded cpython,
https://github.com/jax-ml/jax/issues/26272).
With this PR user can enable the multi-threading: 1) enables additional
locking and 2) set a shared threading pool such that cached contexts can
have one global pool.
2025-03-10 11:19:23 +01:00
Maksim Levental
0264d42dc7
[mlir][CAPI][python] bind CallSiteLoc, FileLineColRange, FusedLoc, NameLoc (#129351)
This PR extends the python bindings for CallSiteLoc, FileLineColRange,
FusedLoc, NameLoc with field accessors. It also adds the missing
`value.location` accessor.

I also did some "spring cleaning" here (`cast` -> `dyn_cast`) after
running into some of my own illegal casts.
2025-03-10 05:10:34 -04:00
Jacques Pienaar
540d7ddb15
[mlir][py] Plumb OpPrintingFlags::printNameLocAsPrefix() through the C/Python APIs (#129607) 2025-03-04 11:49:34 -08:00
Nikhil Kalra
a60e8a2c25
[mlir] Python: write bytecode to a file path (#127118)
The current `write_bytecode` implementation necessarily requires the
serialized module to be duplicated in memory when the python `bytes`
object is created and sent over the binding. For modules with large
resources, we may want to avoid this in-memory copy by serializing
directly to a file instead of sending bytes across the boundary.
2025-02-24 17:51:49 -08:00
Nikhil Kalra
65ed4fa57e
[mlir] Python: Parse ModuleOp from file path (#126572)
For extremely large models, it may be inefficient to load the model into
memory in Python prior to passing it to the MLIR C APIs for
deserialization. This change adds an API to parse a ModuleOp directly
from a file path.

Re-lands
[4e14b8a](4e14b8afb4).
2025-02-12 14:02:41 -08:00
Mehdi Amini
67b7a2590f
Revert "[mlir] Python: Parse ModuleOp from file path" (#126482)
Reverts llvm/llvm-project#125736

The gcc7 Bot is broken at the moment.
2025-02-10 09:09:58 +01:00
Nikhil Kalra
4e14b8afb4
[mlir] Python: Parse ModuleOp from file path (#125736)
For extremely large models, it may be inefficient to load the model into
memory in Python prior to passing it to the MLIR C APIs for
deserialization. This change adds an API to parse a ModuleOp directly
from a file path.
2025-02-05 11:48:37 -08:00
Nikhil Kalra
0ad1f8369c
[mlir] Python: Extend print large elements limit to resources (#125738)
If the large element limit is specified, large elements are hidden from
the asm but large resources are not. This change extends the large
elements limit to apply to printed resources as well.
2025-02-05 11:48:11 -08:00
Peter Hawkins
acde3f722f
[mlir:python] Compute get_op_result_or_value in PyOpView's constructor. (#123953)
This logic is in the critical path for constructing an operation from
Python. It is faster to compute this in C++ than it is in Python, and it
is a minor change to do this.

This change also alters the API contract of
_ods_common.get_op_results_or_values to avoid calling
get_op_result_or_value on each element of a sequence, since the C++ code
will now do this.

Most of the diff here is simply reordering the code in IRCore.cpp.
2025-01-24 06:26:28 -08:00
Jacques Pienaar
a77250fd78
[mlir] Add C and Python interface for file range (#123276)
Plumbs through creating file ranges to C and Python.
2025-01-22 14:33:19 -08:00
Peter Hawkins
e30b703060
[mlir:python] Construct PyOperation objects in-place on the Python heap. (#123813)
Currently we make two memory allocations for each PyOperation: a Python
object, and the PyOperation class itself. With some care we can allocate
the PyOperation inline inside the Python object, saving us a malloc()
call per object and perhaps improving cache locality.
2025-01-22 06:26:44 -08:00
Peter Hawkins
f4125e0226
[mlir python] Change PyOpView constructor to construct operations. (#123777)
Previously ODS-generated Python operations had code like this:
```
  super().__init__(self.build_generic(attributes=attributes, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip))
```

we change it to:
```
  super().__init__(self.OPERATION_NAME, self._ODS_REGIONS, self._ODS_OPERAND_SEGMENTS, self._ODS_RESULT_SEGMENTS, attributes=attributes, operands=operands, successors=_ods_successors, regions=regions, loc=loc, ip=ip)
```

This:
a) avoids an extra call dispatch (to `build_generic`), and
b) passes the class attributes directly to the constructor. Benchmarks
show that it is faster to pass these as arguments rather than having the
C++ code look up attributes on the class.

This PR improves the timing of the following benchmark on my workstation
from 5.3s to 4.5s:
```
def main(_):
  with ir.Context(), ir.Location.unknown():
    typ = ir.IntegerType.get_signless(32)
    m = ir.Module.create()
    with ir.InsertionPoint(m.body):
      start = time.time()
      for i in range(1000000):
        arith.ConstantOp(typ, i)
      end = time.time()
      print(f"time: {end - start}")
```

Since this change adds an additional overload to the constructor and
does not alter any existing behaviors, it should be backwards
compatible.
2025-01-22 06:21:46 -08:00