Commit Graph

363 Commits

Author SHA1 Message Date
Matthias Springer
c4457e10fe [mlir][IR] Change block/region walkers to enumerate this block/region (#75020)
This change makes block/region walkers consistent with operation
walkers. An operation walk enumerates the current operation. Similarly,
block/region walks should enumerate the current block/region.

Example:
```
// Current behavior:
op1->walk([](Operation *op2) { /* op1 is enumerated */ });
block1->walk([](Block *block2) { /* block1 is NOT enumerated */ });
region1->walk([](Block *block) { /* blocks of region1 are NOT enumerated */ });
region1->walk([](Region *region2) { /* region1 is NOT enumerated });

// New behavior:
op1->walk([](Operation *op2) { /* op1 is enumerated */ });
block1->walk([](Block *block2) { /* block1 IS enumerated */ });
region1->walk([](Block *block) { /* blocks of region1 ARE enumerated */ });
region1->walk([](Region *region2) { /* region1 IS enumerated });
```
2023-12-20 14:51:45 +09:00
Matthias Springer
a43641c9db [mlir][bufferization] Fix regionOperatesOnMemrefValues (#75016)
`Region::walk([](Block *b) {...})` does not enumerate blocks that are
direct children of the region. These blocks must be checked manually.
2023-12-12 08:56:23 +09:00
Matthias Springer
68f91cd257 [mlir][bufferization] Fix invalid IR in SimplifyClones canonicalization (#74417)
`SimplifyClones` used to generate an invalid op:
```
error: 'memref.cast' op operand type 'memref<*xf32>' and result type 'memref<*xf32>' are cast incompatible
  %2 = bufferization.clone %1 : memref<*xf32> to memref<*xf32
```

This commit fixes tests such as
`mlir/test/Dialect/Bufferization/canonicalize.mlir` when verifying the
IR after each pattern (#74270).
2023-12-06 09:41:57 +09:00
Matthias Springer
3dae97cc01 [mlir][bufferization] Fix op dominance bug in rewrite pattern (#74159)
Fixes a bug in `SplitDeallocWhenNotAliasingAnyOther`. This pattern used
to generate invalid IR (op dominance error). We never noticed this bug
in existing test cases because other patterns and/or foldings were
applied afterwards and those rewrites "fixed up" the IR again. (The bug
is visible when running `mlir-opt -debug`.) Also add additional comments
to the implementation and simplify the code a bit.

Apart from the fixed dominance error, this change is NFC. Without this
change, buffer deallocation tests will fail when running with #74270.
2023-12-05 11:46:30 +09:00
Matthias Springer
437c62178c [mlir][memref] Remove redundant memref.tensor_store op (#71010)
`bufferization.materialize_in_destination` should be used instead. Both
ops bufferize to a memcpy. This change also conceptually cleans up the
memref dialect a bit: the memref dialect no longer contains ops that
operate on tensor values.
2023-11-05 12:47:18 +09:00
Mehdi Amini
5a71f7a4b7 [mlir] Fix bufferization.alloc_tensor canonicalization crash (#70891)
This make sure that an invalid negative dimension is ignored and stays
dynamic instead of crashing the compiler.

Fixes #70887
2023-10-31 20:58:29 -07:00
Matthias Springer
1abd8d1a8d [mlir][Interfaces] Add SubsetOpInterface and SubsetExtractionOpInterface (#70617)
There is currently an op interface for subset insertion ops
(`SubsetInsertionOpInterface`), but not for subset extraction ops. This
commit adds `SubsetExtractionOpInterface` to `mlir/Interfaces`, as well
as a common dependent op interface: `SubsetOpInterface`.

- `SubsetOpInterface` is for ops that operate on tensor subsets. It
provides interface methods to check if two subset ops operate on
equivalent or disjoint subsets. Ops that implement this interface must
implement either `SubsetExtractionOpInterface` or
`SubsetInsertionOpInterface`.
- `SubsetExtractionOpInterface` is for ops that extract from a tensor at
a subset. E.g., `tensor.extract_slice`, `tensor.gather`,
`vector.transfer_read`. Current implemented only on
`tensor.extract_slice`.
- `SubsetInsertionOpInterface` is for ops that insert into a destination
tensor at a subset. E.g., `tensor.insert_slice`,
`tensor.parallel_insert_slice`, `tensor.scatter`,
`vector.transfer_write`. Currently only implemented on
`tensor.insert_slice`, `tensor.parallel_insert_slice`.

Other changes:
- Rename `SubsetInsertionOpInterface.td` to `SubsetOpInterface.td`.
- Add helper functions to `ValueBoundsOpInterface.cpp` for checking
whether two slices are disjoint.

The new interfaces will be utilized by a new "loop-invariant subset
hoisting"
transformation. (This new transform is roughly
what `Linalg/Transforms/SubsetHoisting.cpp` is doing, but in a generic
and interface-driven way.)
2023-11-01 10:26:31 +09:00
Matthias Springer
4fbbb7ad7c [mlir][bufferization] Fix ownership computation of unknown ops (#70773)
No ownership is assumed for memref results of ops that implement none of
the relevant interfaces and have no memref operands. This fixes #68948.
2023-11-01 09:26:47 +09:00
Matthias Springer
a8d0c86174 [mlir][Interfaces][NFC] Move SubsetInsertionOpInterface to mlir/Interfaces (#70615)
`SubsetInsertionOpInterface` is an interface for ops that insert into a
destination tensor at a subset. It is currently used by the
bufferization framework to support efficient
`tensor.extract_slice/insert_slice` bufferization and to drive "empty
tensor elimination".

This commit moves the interface to `mlir/Interfaces`. This is in
preparation of adding a new "loop-invariant subset hoisting"
transformation to
`mlir/Transforms/Utils/LoopInvariantCodeMotionUtils.cpp`, which will
utilize `SubsetInsertionOpInterface`. (This new transform is roughly
what `Linalg/Transforms/SubsetHoisting.cpp` is doing, but in a generic
and interface-driven way.)
2023-10-30 13:42:44 +09:00
Matthias Springer
5558504374 [mlir][IR] Make OpOperand comparable (#70410)
Two `OpOperand`s are the same if they belong to the same owner and have
the same operand number. There are currently no comparison operators
defined on `OpOperand` and we work around this in multiple places by
comparing pointers.

Note: `OpOperand`s are stored in an op, so it is valid to compare their
pointers to determine if they are the same operand. E.g.,
`getOperandNumber` is also implemented via pointer arithmetics.
2023-10-27 15:51:45 +09:00
Kazu Hirata
f9306f6de3 [ADT] Rename llvm::erase_value to llvm::erase (NFC) (#70156)
C++20 comes with std::erase to erase a value from std::vector.  This
patch renames llvm::erase_value to llvm::erase for consistency with
C++20.

We could make llvm::erase more similar to std::erase by having it
return the number of elements removed, but I'm not doing that for now
because nobody seems to care about that in our code base.

Since there are only 50 occurrences of erase_value in our code base,
this patch replaces all of them with llvm::erase and deprecates
llvm::erase_value.
2023-10-24 23:03:13 -07:00
Matthias Springer
4d80eff861 [mlir][bufferization] Ownership-based deallocation: Allow manual (de)allocs (#68648)
Add a new attribute `bufferization.manual_deallocation` that can be
attached to allocation and deallocation ops. Buffers that are allocated
with this attribute are assigned an ownership of "false". Such buffers
can be deallocated manually (e.g., with `memref.dealloc`) if the
deallocation op also has the attribute set. Previously, the
ownership-based buffer deallocation pass used to reject IR with existing
deallocation ops. This is no longer the case if such ops have this new
attribute.

This change is useful for the sparse compiler, which currently
deallocates the sparse tensor buffers by itself.
2023-10-23 09:45:33 +09:00
Kazu Hirata
195f6236c7 [mlir] Use llvm::erase_value (NFC) 2023-10-19 23:35:11 -07:00
Matthias Springer
6d88ac11d7 [mlir][bufferization] Transfer restrict during empty tensor elimination (#68729)
Empty tensor elimination is looking for
`bufferization.materialize_in_destination` ops with a `tensor.empty`
source. It replaces the `tensor.empty` with a `bufferization.to_tensor
restrict` of the memref destination. As part of this rewrite, the
`restrict` keyword should be removed, so that no second `to_tensor
restrict` op will be inserted. Such IR would be invalid.
`bufferization.materialize_in_destination` with memref destination and
without the `restrict` attribute are ignored by empty tensor
elimination.

Also relax the verifier of `materialize_in_destination`. The `restrict`
keyword is not generally needed because the op does not expose the
buffer as a tensor.
2023-10-11 08:51:16 -07:00
Matthias Springer
9d34c05222 [mlir][bufferization][NFC] Simplify bufferizeOp function signature (#68625)
Remove the `opFilter` and `copyBeforeWrite` function arguments. These
options can already be configured in the `options` object.
2023-10-09 17:52:52 -07:00
Matthias Springer
3d0ca2cfe3 [mlir][bufferization] Allow cyclic function graphs without tensors (#68632)
Cyclic function call graphs are generally not supported by One-Shot
Bufferize. However, they can be allowed when a function does not have
tensor arguments or results. This is because it is then no longer
necessary that the callee will be bufferized before the caller.
2023-10-09 17:52:04 -07:00
Matthias Springer
876334321f [mlir][bufferization] Update empty_tensor_elimination transform op (#68497)
The empty tensor elimination pass semantics have changed recently: when
applied to a module, the One-Shot Module Analysis is run. Otherwise, the
regular One-Shot Analysis is run. The latter one is slightly different
because it ignores function boundaries and treats function block
arguments as "read-only".

This commit updates the transform dialect op to behave in the same way.
2023-10-08 08:46:43 -07:00
Matthias Springer
8ee38f3b32 [mlir][bufferization] Follow up for #68074 (#68488)
Address additional comments in #68074. This should have been part of
#68074.
2023-10-07 10:07:17 -07:00
Matthias Springer
0fcaca2fea [mlir][bufferization] MaterializeInDestinationOp: Support memref destinations (#68074)
Extend `bufferization.materialize_in_destination` to support memref
destinations. This op can now be used to indicate that a tensor
computation should materialize in a given buffer (that may have been
allocated by another component/runtime). The op still participates in
"empty tensor elimination".

Example:
```mlir
func.func @test(%out: memref<10xf32>) {
  %t = tensor.empty() : tensor<10xf32>
  %c = linalg.generic ... outs(%t: tensor<10xf32>) -> tensor<10xf32>
  bufferization.materialize_in_destination %c in restrict writable %out : (tensor<10xf32>, memref<10xf32>) -> ()
  return
}
```
After "empty tensor elimination", the above IR can bufferize without an
allocation:
```mlir
func.func @test(%out: memref<10xf32>) {
  linalg.generic ... outs(%out: memref<10xf32>)
  return
}
```

This change also clarifies the meaning of the `restrict` unit attribute
on `bufferization.to_tensor` ops.
2023-10-06 11:57:10 +02:00
Matthias Springer
5958043e2d [mlir][bufferization] Add dump_alias_sets option to transform op (#68289)
Add `dump_alias_sets` to `transform.bufferization.one_shot_bufferize`.
This option is useful for debugging. Also improve the verifier to ensure
that `test_analysis_only` is set when other debugging flags are enabled.
2023-10-05 14:05:45 +02:00
long.chen
5979e1dfb1 [mlir] Fix empty-tensor-elimination around self-copies (#68129)
* Fixes #67977, a crash in `empty-tensor-elimination`.
* Also improves `linalg.copy` canonicalization.
* Also improves indentation indentation in `mlir-linalg-ods-yaml-gen.cpp`.
2023-10-05 12:04:20 +02:00
Matthias Springer
8823e961f6 [mlir][ODS] Change get...Mutable to return OpOperand & for single operands (#66519)
The TableGen code generator now generates C++ code that returns a single
`OpOperand &` for `get...Mutable` of operands that are not variadic and
not optional. `OpOperand::set`/`assign` can be used to set a value (same
as `MutableOperandRange::assign`). This is safer than
`MutableOperandRange` because only single values (and no longer
`ValueRange`) can be assigned.

E.g.:
```
// Assignment of multiple values to non-variadic operand.
// Before: Compiles, but produces invalid op.
// After: Compilation error.
extractSliceOp.getSourceMutable().assign({v1, v2});
```
2023-10-04 08:35:40 +02:00
Matthias Springer
c95fcd343d [mlir][bufferization] Remove resolveUsesInRepetitiveRegions (#67927)
The bufferization analysis has been improved over the last months and
this workaround is no longer needed.
2023-10-02 16:04:27 +02:00
Matthias Springer
43198b0aa2 [mlir][bufferization] Better analysis around allocs and block arguments (#67923)
Values that are the result of buffer allocation ops are guaranteed to
*not* be the same allocation as block arguments of containing blocks.
This fact can be used to allow for more aggressive simplification of
`bufferization.dealloc` ops.
2023-10-02 11:01:12 +02:00
Matthias Springer
0ef990d57c [mlir][bufferization] Improve verifier for bufferization.dealloc (#67912)
Check that the number of retained operands and updated conditions match.
2023-10-01 19:36:43 +02:00
Martin Erhart
6a651c7f44 Revert "[mlir][bufferization] Don't clone on unknown ownership and verify function boundary ABI (#66626)"
This reverts commit aa9eb47da2.
It introduced a double free in a test case. Reverting to have some time
for fixing this and relanding later.
2023-09-28 09:14:46 +00:00
Martin Erhart
aa9eb47da2 [mlir][bufferization] Don't clone on unknown ownership and verify function boundary ABI (#66626)
Inserting clones requires a lot of assumptions to hold on the input IR, e.g., all writes to a buffer need to dominate all reads. This is not guaranteed by one-shot bufferization and isn't easy to verify, thus it could quickly lead to incorrect results that are hard to debug. This commit changes the mechanism of how an ownership indicator is materialized when there is not already a unique ownership present. Additionally, we don't create copies of returned memrefs anymore when we don't have ownership. Instead, we insert assert operations to make sure we have ownership at runtime, or otherwise report to the user that correctness could not be guaranteed.
2023-09-28 10:45:35 +02:00
Matthias Springer
5109cb28fd [mlir][bufferization] Make buffer deallocation pipeline op type independent (#67546)
The buffer deallocation pipeline now works on modules and functions.
Also add extra test cases that run the buffer deallocation pipeline on
modules and functions. (Test cases that insert a helper function.)
2023-09-27 15:06:25 +02:00
Matthias Springer
913286baed [mlir][linalg] Add SubsetInsertionOpInterface to linalg.copy (#67524)
This commit enables empty tensor elimination on `linalg.copy` ops.
2023-09-27 10:04:37 +02:00
Martin Erhart
77813b088e [mlir][bufferization] OwnershipBasedBufferDeallocation fixes (#67418)
* Properly handle the case where an op is deleted and thus no other
interfaces should be processed anymore.
* Don't add ownership indicator arguments and results to function
declarations
2023-09-27 09:16:43 +02:00
Martin Erhart
5c6eefb252 [mlir][bufferization] LowerDeallocation: declare helper function private (#67408) 2023-09-26 12:35:42 +02:00
Matthias Springer
caa2a4ae6a [mlir][bufferization] Remove deallocationFn from BufferizationOptions (#67128)
One-Shot Bufferize no longer deallocates buffers, so `deallocationFn`
can be removed.

Note: There is a `bufferization.dealloc_tensor` op that now always
bufferizes to `memref.dealloc`. This op will be phased out soon.
2023-09-22 15:14:40 +02:00
Matthias Springer
1a3abc254a [mlir][bufferization][NFC] Remove yielded tensor analysis (#67126)
Remove the yielded tensor analysis. This analysis was used to detect
cases where One-Shot Bufferize cannot deallocate buffers. Deallocation
has recently been removed from One-Shot Bufferize. Buffers are now
deallocated by the buffer deallocation pass. This analysis is no longer
needed.
2023-09-22 15:13:55 +02:00
Martin Erhart
65341b09b0 [mlir][bufferization][NFC] Move memref specific implementation of AllocationOpInterface to memref dialect directory (#66637)
Follow-up on #65578
2023-09-20 14:49:52 +02:00
Martin Erhart
522c1d0eea [mlir][gpu][bufferization] Implement BufferDeallocationOpInterface for gpu.terminator (#66880)
This is necessary to support deallocation of IR with gpu.launch
operations because it does not implement the RegionBranchOpInterface.
Implementing the interface would require it to support regions with
unstructured control flow and produced arguments/results.
2023-09-20 12:28:28 +02:00
Matthias Springer
695a5a6a66 [mlir][IR] Trigger notifyOperationRemoved callback for nested ops (#66771)
When cloning an op, the `notifyOperationInserted` callback is triggered
for all nested ops. Similarly, the `notifyOperationRemoved` callback
should be triggered for all nested ops when removing an op.

Listeners may inspect the IR during a `notifyOperationRemoved` callback.
Therefore, when multiple ops are removed in a single
`RewriterBase::eraseOp` call, the notifications must be triggered in an
order in which the ops could have been removed one-by-one:

* Op removals must be interleaved with `notifyOperationRemoved`
callbacks. A callback is triggered right before the respective op is
removed.
* Ops are removed post-order and in reverse order. Other traversal
orders could delete an op that still has uses. (This is not avoidable in
graph regions and with cyclic block graphs.)

Differential Revision: Imported from https://reviews.llvm.org/D144193.
2023-09-20 08:45:46 +02:00
Matthias Springer
6923a31542 [mlir][IR] Change MutableArrayRange to enumerate OpOperand & (#66622)
In line with #66515, change `MutableArrayRange::begin`/`end` to
enumerate `OpOperand &` instead of `Value`. Also remove
`ForOp::getIterOpOperands`/`setIterArg`, which are now redundant.

Note: `MutableOperandRange` cannot be made a derived class of
`indexed_accessor_range_base` (like `OperandRange`), because
`MutableOperandRange::assign` can change the number of operands in the
range.
2023-09-19 09:09:21 +02:00
Martin Erhart
6bf043e743 [mlir][bufferization] Remove allow-return-allocs and create-deallocs pass options, remove bufferization.escape attribute (#66619)
This commit removes the deallocation capabilities of
one-shot-bufferization. One-shot-bufferization should never deallocate
any memrefs as this should be entirely handled by the
ownership-based-buffer-deallocation pass going forward. This means the
`allow-return-allocs` pass option will default to true now,
`create-deallocs` defaults to false and they, as well as the escape
attribute indicating whether a memref escapes the current region, will
be removed. A new `allow-return-allocs-from-loops` option is added as a
temporary workaround for some bufferization limitations.
2023-09-18 16:44:48 +02:00
Matthias Springer
64839fbd45 [mlir][bufferization] Empty tensor elimination for materialize_in_destination (#65468)
This revision adds support for empty tensor elimination to
"bufferization.materialize_in_destination" by implementing the
`SubsetInsertionOpInterface`.

Furthermore, the One-Shot Bufferize conflict detection is improved for
"bufferization.materialize_in_destination".
2023-09-18 15:34:28 +02:00
Matthias Springer
0f952cfe24 [mlir][IR] Change MutableOperandRange::operator[] to return an OpOperand & (#66515)
`operator[]` returns `OpOperand &` instead of `Value`.

* This allows users to get OpOperands by name instead of "magic" number.
E.g., `extractSliceOp->getOpOperand(0)` can be written as
`extractSliceOp.getSourceMutable()[0]`.
* `OperandRange` provides a read-only API to operands: `operator[]`
returns `Value`. `MutableOperandRange` now provides a mutable API:
`operator[]` returns `OpOperand &`, which can be used to set operands.

Note: The TableGen code generator could be changed to return `OpOperand
&` (instead of `MutableOperandRange`) for non-variadic and non-optional
arguments in a subsequent change. Then the `[0]` part in the above
example would no longer be necessary.
2023-09-18 09:43:03 +02:00
Martin Erhart
08b7a71bcc [mlir][bufferization] Define a pipeline for buffer deallocation (#66352)
Since ownership based buffer deallocation requires a few passes to be run in a somewhat fixed sequence, it makes sense to have a pipeline for convenience (and to reduce the number of transform ops to represent default deallocation).
2023-09-15 09:39:17 +02:00
Martin Erhart
942ce31985 [mlir][bufferization] BufferDeallocationOpInterface: support custom ownership update logic (#66350)
Add a method to the BufferDeallocationOpInterface that allows operations to implement the interface and provide custom logic to compute the ownership indicators of values it defines. As a demonstrating example, this new method is implemented by the `arith.select` operation.
2023-09-14 14:34:04 +02:00
Martin Erhart
8160bce969 [mlir][bufferization][NFC] Introduce BufferDeallocationOpInterface (#66349)
This new interface allows operations to implement custom handling of ownership values and insertion of dealloc operations which is useful when an op cannot implement the interfaces supported by default by the buffer deallocation pass (e.g., because they are not exactly compatible or because there are some additional semantics to it that would render the default implementations in buffer deallocation invalid, or because no interfaces exist for this
kind of behavior and it's not worth introducing one plus a default implementation in buffer deallocation). Additionally, it can also be used to provide more efficient handling for a specific op than the interface based default
implementations can.
2023-09-14 13:58:30 +02:00
Martin Erhart
01334d1abb [mlir][bufferization] Add an ownership based buffer deallocation pass (#66337)
Add a new Buffer Deallocation pass with the intend to replace the old
one. For now it is added as a separate pass alongside in order to allow
downstream users to migrate over gradually. This new pass has the goal
of inserting fewer clone operations and supporting additional use-cases.
Please refer to the Buffer Deallocation section in the updated
Bufferization.md file for more information on how this new pass works.
2023-09-14 12:13:37 +02:00
Matthias Springer
a1ef5a9437 [mlir][bufferization] Empty tensor elimination based on SubsetOpInterface (#65766)
This commit generalizes empty tensor elimination to operate on subset
ops. No new test cases are added because all current subset ops were
already supported previously. From this perspective, this change is NFC.

A new interface method (and a helper method) are added to
`SubsetInsertionOpInterface` to build the subset of the destination
tensor.
2023-09-14 09:45:22 +02:00
Martin Erhart
c199f7dc62 Revert "[mlir][bufferization] Remove allow-return-allocs and create-deallocs pass options, remove bufferization.escape attribute"
This reverts commit 6a91dfedeb.

This caused problems in downstream projects. We are reverting to give
them more time for integration.
2023-09-13 13:53:48 +00:00
Martin Erhart
520407a7c8 Revert "[mlir][bufferization] Improve buffer deallocation pass"
This reverts commit 1bebb60a75.

This caused problems in downstream projects. We are reverting to give
them more time for integration.
2023-09-13 13:53:48 +00:00
Martin Erhart
792caac0f8 Revert "[mlir][bufferization][NFC] Introduce BufferDeallocationOpInterface"
This reverts commit 29d86175e6.

This caused problems in downstream projects. We are reverting to give
them more time for integration.
2023-09-13 13:53:47 +00:00
Martin Erhart
9782232ec7 Revert "[mlir][bufferization] BufferDeallocationOpInterface: support custom ownership update logic"
This reverts commit 89117f1807.

This caused problems in downstream projects. We are reverting to give
them more time for integration.
2023-09-13 13:53:47 +00:00
Martin Erhart
7995a4701d Revert "[mlir][bufferization] Define a pipeline for buffer deallocation"
This reverts commit f0c4663942.

This caused problems in downstream projects. We are reverting to give
them more time for integration.
2023-09-13 13:53:47 +00:00