Commit Graph

110 Commits

Author SHA1 Message Date
Maksim Levental
bdc3e6cb45 [MLIR][python bindings] invalidate ops after PassManager run (#69746)
Fixes https://github.com/llvm/llvm-project/issues/69730 (also see
https://reviews.llvm.org/D155543).

There are  two things outstanding (why I didn't land before):

1. add some C API tests for `mlirOperationWalk`;
2. potentially refactor how the invalidation in `run` works; the first
version of the code looked like this:
    ```cpp
    if (invalidateOps) {
      auto *context = op.getOperation().getContext().get();
      MlirOperationWalkCallback invalidatingCallback =
          [](MlirOperation op, void *userData) {
            PyMlirContext *context =
                static_cast<PyMlirContext *>(userData);
            context->setOperationInvalid(op);
          };
      auto numRegions =
          mlirOperationGetNumRegions(op.getOperation().get());
      for (int i = 0; i < numRegions; ++i) {
        MlirRegion region =
            mlirOperationGetRegion(op.getOperation().get(), i);
        for (MlirBlock block = mlirRegionGetFirstBlock(region);
             !mlirBlockIsNull(block);
             block = mlirBlockGetNextInRegion(block))
          for (MlirOperation childOp =
                   mlirBlockGetFirstOperation(block);
               !mlirOperationIsNull(childOp);
               childOp = mlirOperationGetNextInBlock(childOp))
            mlirOperationWalk(childOp, invalidatingCallback, context,
                              MlirWalkPostOrder);
      }
    }
    ```
This is verbose and ugly but it has the important benefit of not
executing `mlirOperationEqual(rootOp->get(), op)` for every op
underneath the root op.

Supposing there's no desire for the slightly more efficient but highly
convoluted approach, I can land this "posthaste".
But, since we have eyes on this now, any suggestions or approaches (or
needs/concerns) are welcome.
2023-10-20 20:28:32 -05:00
Tomás Longeri
5a600c23f9 [mlir][python] Expose PyInsertionPoint's reference operation (#69082)
The reason I want this is that I am writing my own Python bindings and
would like to use the insertion point from
`PyThreadContextEntry::getDefaultInsertionPoint()` to call C++ functions
that take an `OpBuilder` (I don't need to expose it in Python but it
also seems appropriate). AFAICT, there is currently no way to translate
a `PyInsertionPoint` into an `OpBuilder` because the operation is
inaccessible.
2023-10-18 16:53:18 +02:00
Jacques Pienaar
f1dbfcc14d [mlir][py] Use overloads instead (NFC)
Was using a local, pseudo overload rather than just using an overload proper.
2023-10-02 21:17:49 -07:00
Maksim Levental
d7e49736e6 [mlir][CAPI, python bindings] Expose Operation::setSuccessor (#67922)
This is useful for emitting (using the python bindings) `cf.br` to
blocks that are declared lexically post block creation.
2023-10-02 15:37:25 -05:00
Jacques Pienaar
a677a17327 [mlir][py] Enable AsmState overload for operation. 2023-09-25 12:25:08 -07:00
Jacques Pienaar
75453714f0 [mlir][python] Expose AsmState python side. (#66819)
This does basic plumbing, ideally want a context approach to reduce
needing to thread these manually, but the current is useful even in that
state.

Made Value.get_name change backwards compatible, so one could either set
a field or create a state to pass in.
2023-09-20 15:12:06 -07:00
Stella Laurenzo
33df617dfd [mlir] Quality of life improvements to python API types. (#66723)
* Moves several orphaned methods from Operation/OpView -> _OperationBase
so that both hierarchies share them (whether unknown or known to ODS).
* Adds typing information for missing `MLIRError` exception.
* Adds `DiagnosticInfo` typing.
* Adds `DenseResourceElementsAttr` typing that was missing.
2023-09-18 21:30:41 -07:00
Jacques Pienaar
31ebe98e48 [mlir][c] Expose AsmState. (#66693)
Enable usage where capturing AsmState is good (e.g., avoiding creating AsmState over and over again when walking IR and printing).

This also only changes one C API to verify plumbing. But using the AsmState makes the cost more explicit than the flags interface (which hides the traversals and construction here) and also enables a more efficient usage C side.
2023-09-18 20:12:12 -07:00
max
92233062c1 [mlir][python bindings] generate all the enums
This PR implements python enum bindings for *all* the enums - this includes `I*Attrs` (including positional/bit) and `Dialect/EnumAttr`.

There are a few parts to this:

1. CMake: a small addition to `declare_mlir_dialect_python_bindings` and `declare_mlir_dialect_extension_python_bindings` to generate the enum, a boolean arg `GEN_ENUM_BINDINGS` to make it opt-in (even though it works for basically all of the dialects), and an optional `GEN_ENUM_BINDINGS_TD_FILE` for handling corner cases.
2. EnumPythonBindingGen.cpp: there are two weedy aspects here that took investigation:
    1. If an enum attribute is not a `Dialect/EnumAttr` then the `EnumAttrInfo` record is canonical, as far as both the cases of the enum **and the `AttrDefName`**. On the otherhand, if an enum is a `Dialect/EnumAttr` then the `EnumAttr` record has the correct `AttrDefName` ("load bearing", i.e., populates `ods.ir.AttributeBuilder('<NAME>')`) but its `enum` field contains the cases, which is an instance of `EnumAttrInfo`. The solution is to generate an one enum class for both `Dialect/EnumAttr` and "independent" `EnumAttrInfo` but to make that class interopable with two builder registrations that both do the right thing (see next sub-bullet).
    2. Because we don't have a good connection to cpp `EnumAttr`, i.e., only the `enum class` getters are exposed (like `DimensionAttr::get(Dimension value)`), we have to resort to parsing e.g., `Attribute.parse(f'#gpu<dim {x}>')`. This means that the set of supported `assemblyFormat`s (for the enum) is fixed at compile of MLIR (currently 2, the only 2 I saw). There might be some things that could be done here but they would require quite a bit more C API work to support generically (e.g., casting ints to enum cases and binding all the getters or going generically through the `symbolize*` methods, like `symbolizeDimension(uint32_t)` or `symbolizeDimension(StringRef)`).

A few small changes:

1. In addition, since this patch registers default builders for attributes where people might've had their own builders already written, I added a `replace` param to `AttributeBuilder.insert` (`False` by default).
2. `makePythonEnumCaseName` can't handle all the different ways in which people write their enum cases, e.g., `llvm.CConv.Intel_OCL_BI`, which gets turned into `INTEL_O_C_L_B_I` (because `llvm::convertToSnakeFromCamelCase` doesn't look for runs of caps). So I dropped it. On the otherhand regularization does need to done because some enums have `None` as a case (and others might have other python keywords).
3. I turned on `llvm` dialect generation here in order to test `nvvm.WGMMAScaleIn`, which is an enum with [[ d7e26b5620/mlir/include/mlir/IR/EnumAttr.td (L22-L25) | no explicit discriminator ]] for the `neg` case.

Note, dialects that didn't get a `GEN_ENUM_BINDINGS` don't have any enums to generate.

Let me know if I should add more tests (the three trivial ones I added exercise both the supported `assemblyFormat`s and `replace=True`).

Reviewed By: stellaraccident

Differential Revision: https://reviews.llvm.org/D157934
2023-08-23 15:03:55 -05:00
max
6e4ea4eeba add owner to OpResultsList. this is useful for when the list is empty and an element can't be used to fetch the owner.
Differential Revision: https://reviews.llvm.org/D157769
2023-08-11 21:09:06 -05:00
Mehdi Amini
363b655920 Finish renaming getOperandSegmentSizeAttr() from operand_segment_sizes to operandSegmentSizes
This renaming started with the native ODS support for properties, this is completing it.

A mass automated textual rename seems safe for most codebases.
Drop also the ods prefix to keep the accessors the same as they were before
this change:
 properties.odsOperandSegmentSizes
reverts back to:
 properties.operandSegementSizes

The ODS prefix was creating divergence between all the places and make it harder to
be consistent.

Reviewed By: jpienaar

Differential Revision: https://reviews.llvm.org/D157173
2023-08-09 19:37:01 -07:00
max
25b8433b75 add set_type to ir.Value
Differential Revision: https://reviews.llvm.org/D156289
2023-07-26 07:28:21 -05:00
Jacques Pienaar
f573bc24d4 [mlir][py] Reuse more of CAPI build time inference.
This reduces code generated for type inference and instead reuses
facilities CAPI side that performed same role.

Differential Revision: https://reviews.llvm.org/D156041t
2023-07-23 21:26:52 -07:00
Adam Paszke
c83318e3e0 [MLIR][Python] Implement pybind adapters for MlirBlock
Reviewed By: jpienaar

Differential Revision: https://reviews.llvm.org/D155092
2023-07-12 22:27:01 -07:00
Rahul Kayaith
974c1596ab [mlir][python] Downcast attributes in more places
Update remaining `PyAttribute`-returning APIs to return `MlirAttribute` instead,
so that they go through the downcasting mechanism.

Reviewed By: makslevental

Differential Revision: https://reviews.llvm.org/D154462
2023-07-10 22:01:34 -04:00
max
4eee9ef976 Add SymbolRefAttr to python bindings
Differential Revision: https://reviews.llvm.org/D154541
2023-07-05 20:51:33 -05:00
Adam Paszke
9816cc916f Fix a memory leak in the Python implementation of bytecode writer
The bytecode writer config was heap-allocated, but was never freed, causing ASAN errors.

Reviewed By: jpienaar

Differential Revision: https://reviews.llvm.org/D153440
2023-06-21 09:40:51 -07:00
max
9566ee2806 [MLIR][python bindings] TypeCasters for Attributes
Differential Revision: https://reviews.llvm.org/D151840
2023-06-07 12:01:00 -05:00
max
bfb1ba7526 [MLIR][python bindings] Add TypeCaster for returning refined types from 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-05-26 11:02:05 -05:00
Rahul Kayaith
d0d26ee78c [mlir][python] Hook up PyRegionList.__iter__ to PyRegionIterator
This fixes a -Wunused-member-function warning, at the moment
`PyRegionIterator` is never constructed by anything (the only use was
removed in D111697), and iterating over region lists is just falling
back to a generic python iterator object.

Reviewed By: stellaraccident

Differential Revision: https://reviews.llvm.org/D150244
2023-05-24 22:16:58 -04:00
Rahul Kayaith
514dddbeba [mlir][python] Allow specifying block arg locations
Currently blocks are always created with UnknownLoc's for their arguments. This
adds an `arg_locs` argument to all block creation APIs, which takes an optional
sequence of locations to use, one per block argument. If no locations are
supplied, the current Location context is used.

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D150084
2023-05-24 21:55:51 -04:00
max
4811270bac [MLIR][python bindings] use pybind C++ APIs for throwing python errors.
Differential Revision: https://reviews.llvm.org/D151167
2023-05-23 11:31:16 -05:00
max
d39a784402 [MLIR][python bindings] Expose TypeIDs in python
This diff adds python bindings for `MlirTypeID`. It paves the way for returning accurately typed `Type`s from python APIs (see D150927) and then further along building type "conscious" `Value` APIs (see D150413).

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D150839
2023-05-22 13:19:54 -05:00
Rahul Kayaith
2b7c453307 Revert "[mlir][python] Allow specifying block arg locations"
This reverts commit 4d0d295b61.

This caused a buildbot failure: https://lab.llvm.org/buildbot/#/builders/61/builds/43479
2023-05-09 18:09:41 -04:00
Rahul Kayaith
4d0d295b61 [mlir][python] Allow specifying block arg locations
Currently blocks are always created with UnknownLoc's for their arguments. This
adds an `arg_locs` argument to all block creation APIs, which takes an optional
sequence of locations to use, one per block argument. If no locations are
supplied, the current Location context is used.

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D150084
2023-05-09 12:40:17 -04:00
max
81233c70cb [MLIR][python bindings] Add PyValue.print_as_operand (Value::printAsOperand)
Useful for easier debugging (no need to regex out all of the stuff around the id).

Differential Revision: https://reviews.llvm.org/D149902
2023-05-08 10:41:35 -05:00
Jacques Pienaar
5c90e1ffb0 [mlir][bytecode] Return error instead of min version
Can't return a well-formed IR output while enabling version to be bumped
up during emission. Previously it would return min version but
potentially invalid IR which was confusing, instead make it return
error and abort immediately instead.

Differential Revision: https://reviews.llvm.org/D149569
2023-04-30 22:11:02 -07:00
Jacques Pienaar
0610e2f6a2 [mlir][bytecode] Allow client to specify a desired version.
Add method to set a desired bytecode file format to generate. Change
write method to be able to return status including the minimum bytecode
version needed by reader. This enables generating an older version of
the bytecode (not dialect ops, attributes or types). But this does not
guarantee that an older version can always be generated, e.g., if a
dialect uses a new encoding only available at later bytecode version.
This clamps setting to at most current version.

Differential Revision: https://reviews.llvm.org/D146555
2023-04-29 05:35:53 -07:00
max
5b303f21d3 [MLIR][python bindings] Reimplement replace_all_uses_with on PyValue
Differential Revision: https://reviews.llvm.org/D149261
2023-04-26 14:04:33 -05:00
max
fd527ceff1 Revert "[MLIR][python bindings] implement replace_all_uses_with on PyValue"
This reverts commit 3bab7cb089 because it breaks sanitizers.

Differential Revision: https://reviews.llvm.org/D149188
2023-04-25 15:45:17 -05:00
max
98fbd9d3f9 [MLIR][python bindings] implement replace_all_uses_with on PyValue
Differential Revision: https://reviews.llvm.org/D148816
2023-04-24 10:08:43 -05:00
max
69cc3cfb21 [MLIR][python bindings] implement PyValue subclassing to enable operator overloading
Differential Revision: https://reviews.llvm.org/D147758
2023-04-14 14:25:06 -05:00
Rahul Kayaith
e6d738e0c7 [mlir][python] Mark operator== overloads as const
This resolves some warnings when building with C++20, e.g.:
```
llvm-project/mlir/lib/Bindings/Python/IRAffine.cpp:545:60: warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'mlir::python::PyAffineExpr' and 'mlir::python::PyAffineExpr') to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator]
                        PyAffineExpr &other) { return self == other; })
                                                      ~~~~ ^  ~~~~~
llvm-project/mlir/lib/Bindings/Python/IRAffine.cpp:350:20: note: ambiguity is between a regular call to this operator and a call with the argument order reversed
bool PyAffineExpr::operator==(const PyAffineExpr &other) {
                   ^
```

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D147018
2023-03-28 11:06:13 -04:00
Rahul Kayaith
3ea4c5014d [mlir][python] Capture error diagnostics in exceptions
This updates most (all?) error-diagnostic-emitting python APIs to
capture error diagnostics and include them in the raised exception's
message:
```
>>> Operation.parse('"arith.addi"() : () -> ()'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
mlir._mlir_libs.MLIRError: Unable to parse operation assembly:
error: "-":1:1: 'arith.addi' op requires one result
 note: "-":1:1: see current operation: "arith.addi"() : () -> ()
```

The diagnostic information is available on the exception for users who
may want to customize the error message:
```
>>> try:
...   Operation.parse('"arith.addi"() : () -> ()')
... except MLIRError as e:
...   print(e.message)
...   print(e.error_diagnostics)
...   print(e.error_diagnostics[0].message)
...
Unable to parse operation assembly
[<mlir._mlir_libs._mlir.ir.DiagnosticInfo object at 0x7fed32bd6b70>]
'arith.addi' op requires one result
```

Error diagnostics captured in exceptions aren't propagated to diagnostic
handlers, to avoid double-reporting of errors. The context-level
`emit_error_diagnostics` option can be used to revert to the old
behaviour, causing error diagnostics to be reported to handlers instead
of as part of exceptions.

API changes:
- `Operation.verify` now raises an exception on verification failure,
  instead of returning `false`
- The exception raised by the following methods has been changed to
  `MLIRError`:
  - `PassManager.run`
  - `{Module,Operation,Type,Attribute}.parse`
  - `{RankedTensorType,UnrankedTensorType}.get`
  - `{MemRefType,UnrankedMemRefType}.get`
  - `VectorType.get`
  - `FloatAttr.get`

closes #60595

depends on D144804, D143830

Reviewed By: stellaraccident

Differential Revision: https://reviews.llvm.org/D143869
2023-03-07 14:59:22 -05:00
Rahul Kayaith
a7f8b7cd8e [mlir][python] Remove "Raw" OpView classes
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
2023-03-01 18:17:14 -05:00
rkayaith
37107e177e [mlir][python] Add generic operation parse APIs
Currently the bindings only allow for parsing IR with a top-level
`builtin.module` op, since the parse APIs insert an implicit module op.
This change adds `Operation.parse`, which returns whatever top-level op
is actually in the source.

To simplify parsing of specific operations, `OpView.parse` is also
added, which handles the error checking for `OpView` subclasses.

Reviewed By: ftynse, stellaraccident

Differential Revision: https://reviews.llvm.org/D143352
2023-03-01 18:17:12 -05:00
Rahul Kayaith
2aa12583e6 [mlir][python] Don't emit diagnostics when printing invalid ops
The asm printer grew the ability to automatically fall back to the
generic format for invalid ops, so this logic doesn't need to be in the
bindings anymore. The printer already handles supressing diagnostics
that get emitted while checking if the op is valid.

Reviewed By: mehdi_amini, stellaraccident

Differential Revision: https://reviews.llvm.org/D144805
2023-02-26 23:50:18 -05:00
Andrew Young
792f3c8141 [MLIR] Add LocationAttr to the Python API
This is a follow up to D142182, to expose LocationAttrs through Python.

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D142522
2023-01-25 16:09:29 -08:00
Kazu Hirata
0a81ace004 [mlir] Use std::optional instead of llvm::Optional (NFC)
This patch replaces (llvm::|)Optional< with std::optional<.  I'll post
a separate patch to remove #include "llvm/ADT/Optional.h".

This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2023-01-14 01:25:58 -08:00
Kazu Hirata
a1fe1f5f77 [mlir] Add #include <optional> (NFC)
This patch adds #include <optional> to those files containing
llvm::Optional<...> or Optional<...>.

I'll post a separate patch to actually replace llvm::Optional with
std::optional.

This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2023-01-13 21:05:06 -08:00
serge-sans-paille
984b800a03 Move from llvm::makeArrayRef to ArrayRef deduction guides - last part
This is a follow-up to https://reviews.llvm.org/D140896, split into
several parts as it touches a lot of files.

Differential Revision: https://reviews.llvm.org/D141298
2023-01-10 11:47:43 +01:00
Jacques Pienaar
b57acb9a40 Revert "Revert "[mlir][py] Enable building ops with raw inputs""
Fix Python 3.6.9 issue encountered due to type checking here. Will
add back in follow up.

This reverts commit 1f47fee294.
2022-12-21 16:22:39 -08:00
Jacques Pienaar
1f47fee294 Revert "[mlir][py] Enable building ops with raw inputs"
Reverting to fix build bot.

This reverts commit 3781b7905d.
2022-12-21 14:53:12 -08:00
Jacques Pienaar
3781b7905d [mlir][py] Enable building ops with raw inputs
For cases where we can automatically construct the Attribute allow for more
user-friendly input. This is consistent with C++ builder generation as well
choice of which single builder to generate here (most
specialized/user-friendly).

Registration of attribute builders from more pythonic input is all Python side.
The downside is that
  * extra checking to see if user provided a custom builder in op builders,
  * the ODS attribute name is load bearing
upside is that
  * easily change these/register dialect specific ones in downstream projects,
  * adding support/changing to different convenience builders are all along with
    the rest of the convenience functions in Python (and no additional changes
    to tablegen file or recompilation needed);

Allow for both building with Attributes as well as raw inputs. This change
should therefore be backwards compatible as well as allow for avoiding
recreating Attribute where already available.

Differential Revision: https://reviews.llvm.org/D139568
2022-12-21 10:10:31 -08:00
Fangrui Song
14ce58f3bf [mlir][python] llvm::Optional::value => operator*
And convert it to std::optional while updating.
2022-12-19 04:28:55 +00:00
Mike Urbach
afb2ed80cb [mlir][Python] Add a simple PyOpOperand iterator for PyValue uses.
This adds a simple PyOpOperand based on MlirOpOperand, which can has
properties for the owner op and operation number.

This also adds a PyOpOperandIterator that defines methods for __iter__
and __next__ so PyOpOperands can be iterated over using the the
MlirOpOperand C API.

Finally, a uses psuedo-container is added to PyValue so the uses can
generically be iterated.

Depends on D139596

Reviewed By: stellaraccident, jdd

Differential Revision: https://reviews.llvm.org/D139597
2022-12-13 19:20:29 -07:00
Mike Urbach
fa45b2fb2a [mlir][Python] Add __hash__ implementation for Block.
This allows us to hash Blocks and use them in sets or parts of larger
hashable objects. The implementation is the same as other core IR
constructs: the C API object's pointer is hashed.

Differential Revision: https://reviews.llvm.org/D139599
2022-12-13 12:03:00 -07:00
Kazu Hirata
e823abab48 [mlir] Use std::nullopt instead of None in comments (NFC)
This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-12-06 00:03:44 -08:00
River Riddle
d023661115 [mlir][AsmPrinter] Allow explicitly disabling debug info
This adds an `enable` flag to OpPrintingFlags::enableDebugInfo
that allows for overriding any command line flags for debug printing,
and matches the format that we use for other `enableBlah` API.
2022-11-18 02:09:57 -08:00
Mehdi Amini
30c7c42341 Apply clang-tidy fixes for performance-unnecessary-value-param in IRCore.cpp (NFC) 2022-10-08 18:18:13 +00:00