520 Commits

Author SHA1 Message Date
Matthias Springer
87e345b1bd [mlir] GreedyPatternRewriteDriver: Add new strict mode option
There are now three options:
* `AnyOp` (previously `false`)
* `ExistingAndNewOps` (previously `true`)
* `ExistingOps`: this one is new.

The last option corresponds to what the `applyOpPatternsAndFold(Operation*, ...)` overload is doing. It is now also supported on the `applyOpPatternsAndFold(ArrayRef<Operation *>, ...)` overload.

Differential Revision: https://reviews.llvm.org/D141904
2023-01-20 10:08:11 +01:00
Matthias Springer
11a9c05bcb [mlir] GreedyPatternRewriteDriver: Fix termination criteria in OpPatternRewriteDriver
This driver should iterate until convergence or until the specified op was erased. However, it used to stop when any op was erased.

Differential Revision: https://reviews.llvm.org/D141921
2023-01-18 15:11:06 +01:00
Matthias Springer
fefe655baa [mlir][NFC] GreedyPatternRewriteDriver: Consistent return values
All `apply...` functions now return a LogicalResult indicating whether the iterative process converged or not.

Differential Revision: https://reviews.llvm.org/D141845
2023-01-16 16:30:12 +01:00
Matthias Springer
6e5021b8dc [mlir][NFC] GreedyPatternRewriteDriver: Remove overridden eraseOp
It is not necessary to override `eraseOp`, we can use the existing `notifyOperationRemoved`.

Differential Revision: https://reviews.llvm.org/D141844
2023-01-16 16:18:53 +01: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
Matthias Springer
ed9194be6d [mlir] GreedyPatternRewriter: Add ancestors to worklist
When adding an op to the worklist, also add its ancestors to the worklist. This allows for RewritePatterns to match an op `a` based on what is inside of the body of `a`.

This change fixes a problem that became apparent with `vector.warp_execute_on_lane_0`, but could probably be triggered with similar patterns. The pattern extracts an op `b` with `eligible = true` from the body of an op `a`:
```
test.a {
  %0 = test.b() {eligible = true}
  yield %0
}
```

Afterwards:
```
%0 = test.b() {eligible = true}
test.a {
  yield %0
}
```

The pattern is an `OpRewritePattern<OpA>`. For some reason, `test.a` is not on the GreedyPatternRewriter's worklist. E.g., because no pattern could be applied and it was removed. Now, another pattern updates `test.b`, so that `eligible` is changed from `true` to `false`. The `OpRewritePattern<OpA>` could now be applied, but (without this revision) `test.a` is still not on the worklist.

Note: In the above example, an `OpRewritePattern<OpB>` could have been used instead of an `OpRewritePattern<OpA>`. With such a design, we can run into the same problem (when the `eligible` attr is on `test.a` and `test.b` is removed from the worklist because no patterns could be applied).

Note: This change uncovered an unrelated bug in TestSCFUtils.cpp that was triggered due to a change in the order in which ops are processed. A TODO is added to the broken code and test cases are adapted so that the bug is no longer triggered.

Differential Revision: https://reviews.llvm.org/D140304
2023-01-13 10:51:28 +01:00
Jeff Niu
4d67b27817 [mlir] Add operations to BlockAndValueMapping and rename it to IRMapping
The patch adds operations to `BlockAndValueMapping` and renames it to `IRMapping`. When operations are cloned, old operations are mapped to the cloned operations. This allows mapping from an operation to a cloned operation. Example:

```
Operation *opWithRegion = ...
Operation *opInsideRegion = &opWithRegion->front().front();

IRMapping map
Operation *newOpWithRegion = opWithRegion->clone(map);
Operation *newOpInsideRegion = map.lookupOrNull(opInsideRegion);
```

Migration instructions:
All includes to `mlir/IR/BlockAndValueMapping.h` should be replaced with `mlir/IR/IRMapping.h`. All uses of `BlockAndValueMapping` need to be renamed to `IRMapping`.

Reviewed By: rriddle, mehdi_amini

Differential Revision: https://reviews.llvm.org/D139665
2023-01-12 13:16:05 -08:00
Matthias Springer
0e4735546e [mlir] Fix worklist bug in MultiOpPatternRewriteDriver
When `strict = true`, only pre-existing and newly-created ops are rewritten and/or folded. Such ops are stored in `strictModeFilteredOps`.

Newly-created ops were previously added to `strictModeFilteredOps` after calling `addToWorklist` (via `GreedyPatternRewriteDriver::notifyOperationInserted`). Therefore, newly-created ops were never added to the worklist.

Also fix a test case that should have gone into an infinite loop (`test.replace_with_new_op` was replaced with itself, which should have caused the op to be rewritten over and over), but did not due to this bug.

Differential Revision: https://reviews.llvm.org/D141141
2023-01-10 15:33:22 +01:00
Matthias Springer
0ff3cf0c0c [mlir] GreedyPatternRewriter: fix counting of iterations
The GreedyPatternRewriteDriver did previously not count the first iteration. I.e., when setting `config.maxIterations = 1`, two iterations were performed. In pratice, this number is not really important; we usually just need a limit in some reasonable order of magnitude. However, this fix allows us to write better convergence/worklist tests with carefully crafted test patterns to purposely trigger edge cases in the driver.

Similarly, the first rewrite was previously not counted towards `config.maxNumRewrites`.

For consistency, `OpPatternRewriteDriver` now uses `config.maxNumRewrites` instead of `config.maxIterations`; this driver does not have "iterations", it consists of a single loop (corresponding to the inner loop in the GreedyPatternRewriteDriver).

Differential Revision: https://reviews.llvm.org/D141365
2023-01-10 12:21:08 +01: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
Matthias Springer
391cb54122 [mlir] Add option to limit number of pattern rewrites in CanonicalizerPass
The greedy pattern rewriter consists of two nested loops. `config.maxIterations` (which configurable on the CanonicalizerPass) controls the maximum number of iterations of the outer loop.

```
/// This specifies the maximum number of times the rewriter will iterate
/// between applying patterns and simplifying regions. Use `kNoLimit` to
/// disable this iteration limit.
int64_t maxIterations = 10;
```

This change adds `config.maxNumRewrites` which controls the maximum number of pattern rewrites within an iteration. (It effectively control the maximum number of iterations of the inner loop.)

This flag is meant for debugging and useful in cases where one or multiple faulty patterns can be applied indefinitely, resulting in an infinite loop.

Differential Revision: https://reviews.llvm.org/D140525
2022-12-23 13:08:53 +01:00
Ramkumar Ramachandra
0de16fafa5 mlir/DialectConversion: use std::optional (NFC)
This is part of an effort to migrate from llvm::Optional to
std::optional. This patch touches DialectConversion, and modifies
existing conversions and tests appropriately.

See also: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716

Signed-off-by: Ramkumar Ramachandra <r@artagnon.com>

Differential Revision: https://reviews.llvm.org/D140303
2022-12-19 18:48:59 +01:00
Fangrui Song
bef481df8b [mlir] Drop uses of operator<<(raw_ostream &OS, const Optional<T> &O) 2022-12-16 20:24:35 +00:00
Kazu Hirata
4f81805a3f [mlir] Use std::optional 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-10 17:11:23 -08:00
Kazu Hirata
1a36588ec6 [mlir] Use std::nullopt instead of None (NFC)
This patch mechanically replaces None with std::nullopt where the
compiler would warn if None were deprecated.  The intent is to reduce
the amount of manual work required in migrating from Optional to
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
2022-12-03 18:50:27 -08:00
Jan Svoboda
abf0c6c0c0 Use CTAD on llvm::SaveAndRestore
Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D139229
2022-12-02 15:36:12 -08:00
Matthias Springer
2fea658a74 [mlir] GreedyPatternRewriter: Reprocess modified ops
Ops that were modifed in-place (`finalizeRootUpdate` was called) should be reprocessed by the GreedyPatternRewriter. This is currently not happening with `GreedyRewriteConfig::maxIterations = 1`.

Note: If your project goes into an infinite loop because of this change, you likely have one or multiple faulty patterns that modify the same operations in-place (`updateRootInplace`) indefinitely.

Differential Revision: https://reviews.llvm.org/D138038
2022-11-18 11:43:44 +01:00
Mahesh Ravishankar
fc367dfa67 [mlir] Remove Transforms/SideEffectUtils.h and move the methods into Interface/SideEffectInterfaces.h.
The methods in `SideEffectUtils.h` (and their implementations in
`SideEffectUtils.cpp`) seem to have similar intent to methods already
existing in `SideEffectInterfaces.h`. Move the decleration (and
implementation) from `SideEffectUtils.h` (and `SideEffectUtils.cpp`)
into `SideEffectInterfaces.h` (and `SideEffectInterface.cpp`).

Also drop the `SideEffectInterface::hasNoEffect` method in favor of
`mlir::isMemoryEffectFree` which actually recurses into the operation
instead of just relying on the `hasRecursiveMemoryEffectTrait`
exclusively.

Differential Revision: https://reviews.llvm.org/D137857
2022-11-15 20:07:35 +00:00
River Riddle
8c66344ee9 [mlir:PDL] Add support for DialectConversion with pattern configurations
Up until now PDL(L) has not supported dialect conversion because we had no
way of remapping values or integrating with type conversions. This commit
rectifies that by adding a new "pattern configuration" concept to PDL. This
essentially allows for attaching external configurations to patterns, which
can hook into pattern events (for now just the scope of a rewrite, but we
could also pass configs to native rewrites as well). This allows for injecting
the type converter into the conversion pattern rewriter.

Differential Revision: https://reviews.llvm.org/D133142
2022-11-08 01:57:57 -08:00
Ivan Butygin
ed4749f937 [mlir] Add populateFunctionOpInterfaceTypeConversionPattern version which operates on any FunctionOpInterface
Exisitng version is always limited to some specific op.

Differential Revision: https://reviews.llvm.org/D137469
2022-11-05 12:10:36 +01:00
Sanjoy Das
dde9db5f93 Unbreak Windows build
Without the llvm_unreachable, Windows complains about not returning a
value from mlir::isSpeculatable on all paths.

Differential Revision: https://reviews.llvm.org/D135899
2022-10-13 11:21:43 -07:00
Matthias Springer
47424f22d4 [mlir][transforms] TopologicalSort: Support ops from different blocks
This change allows analyzing ops from different block, in particular when used in programs that have `cf` branches.

Differential Revision: https://reviews.llvm.org/D135644
2022-10-13 10:36:06 +09:00
Sanjoy Das
86771d0b65 Introduce a ConditionallySpeculatable op interface
This patch takes the first step towards a more principled modeling of undefined behavior in MLIR as discussed in the following discourse threads:

 1. https://discourse.llvm.org/t/semantics-modeling-undefined-behavior-and-side-effects/4812
 2. https://discourse.llvm.org/t/rfc-mark-tensor-dim-and-memref-dim-as-side-effecting/65729

This patch in particular does the following:

 1. Introduces a ConditionallySpeculatable OpInterface that dynamically determines whether an Operation can be speculated.
 2. Re-defines `NoSideEffect` to allow undefined behavior, making it necessary but not sufficient for speculation.  Also renames it to `NoMemoryEffect`.
 3. Makes LICM respect the above semantics.
 4. Changes all ops tagged with `NoSideEffect` today to additionally implement ConditionallySpeculatable and mark themselves as always speculatable.  This combined trait is named `Pure`.  This makes this change NFC.

For out of tree dialects:

 1. Replace `NoSideEffect` with `Pure` if the operation does not have any memory effects, undefined behavior or infinite loops.
 2. Replace `NoSideEffect` with `NoSideEffect` otherwise.

The next steps in this process are (I'm proposing to do these in upcoming patches):

 1. Update operations like `tensor.dim`, `memref.dim`, `scf.for`, `affine.for` to implement a correct hook for `ConditionallySpeculatable`.  I'm also happy to update ops in other dialects if the respective dialect owners would like to and can give me some pointers.
 2. Update other passes that speculate operations to consult `ConditionallySpeculatable` in addition to `NoMemoryEffect`.  I could not find any other than LICM on a quick skim, but I could have missed some.
 3. Add some documentation / FAQs detailing the differences between side effects, undefined behavior, speculatabilty.

Reviewed By: rriddle, mehdi_amini

Differential Revision: https://reviews.llvm.org/D135505
2022-10-12 10:56:12 -07:00
River Riddle
ecba7c58bd [mlir] Rename FunctionOpInterface::getBody to getFunctionBody
This is much more explicit, and prevents annoying conflicts with op
specific accessors (which may have a different contract). This is similar
to the past rename of getType -> getFunctionType,

Fixes #58030

Differential Revision: https://reviews.llvm.org/D135007
2022-10-03 11:53:57 -07:00
Alex Zinenko
e8aaf75810 [mlir] specify the values when notifying about op replacement
It is useful for PatternRewriter listeners to know the values that are
replacing the op in addition to only the fact of the op being replaced
for being able to keep track of changes or for debugging.

Reviewed By: Mogball

Differential Revision: https://reviews.llvm.org/D134748
2022-09-27 16:22:35 +00:00
Kazu Hirata
f55ed88936 [mlir] Use x.empty() instead of llvm::empty(x) (NFC)
I'm planning to deprecate and eventually remove llvm::empty.

Note that no use of llvm::empty requires the ability of llvm::empty to
determine the emptiness from begin/end only.
2022-09-18 10:53:49 -07:00
Kazu Hirata
0a706be316 [mlir] Don't include SetVector.h (NFC) 2022-09-17 13:36:16 -07:00
Matthias Springer
31fbdab376 [mlir][transforms] Add topological sort analysis
This change add a helper function for computing a topological sorting of a list of ops. E.g. this can be useful in transforms where a subset of ops should be cloned without dominance errors.

The analysis reuses the existing implementation in TopologicalSortUtils.cpp.

Differential Revision: https://reviews.llvm.org/D131669
2022-08-15 21:09:18 +02:00
Benjamin Kramer
9fa59e7643 [mlir] Use C++17 structured bindings instead of std::tie where applicable. NFCI 2022-08-09 13:34:17 +02:00
Fangrui Song
fc63c0542c [mlir] LLVM_FALLTHROUGH => [[fallthrough]]. NFC 2022-08-08 20:56:05 -07:00
Kazu Hirata
af2d2d7759 [mlir] Remove redundaunt return statements (NFC)
Identified with readability-redundant-control-flow.
2022-08-07 00:16:13 -07:00
srishti-cb
b508c5649f [MLIR] Add a utility to sort the operands of commutative ops
Added a commutativity utility pattern and a function to populate it. The pattern sorts the operands of an op in ascending order of the "key" associated with each operand iff the op is commutative. This sorting is stable.

The function is intended to be used inside passes to simplify the matching of commutative operations. After the application of the above-mentioned pattern, since the commutative operands now have a deterministic order in which they occur in an op, the matching of large DAGs becomes much simpler, i.e., requires much less number of checks to be written by a user in her/his pattern matching function.

The "key" associated with an operand is the list of the "AncestorKeys" associated with the ancestors of this operand, in a breadth-first order.

The operand of any op is produced by a set of ops and block arguments. Each of these ops and block arguments is called an "ancestor" of this operand.

Now, the "AncestorKey" associated with:
1. A block argument is `{type: BLOCK_ARGUMENT, opName: ""}`.
2. A non-constant-like op, for example, `arith.addi`, is `{type: NON_CONSTANT_OP, opName: "arith.addi"}`.
3. A constant-like op, for example, `arith.constant`, is `{type: CONSTANT_OP, opName: "arith.constant"}`.

So, if an operand, say `A`, was produced as follows:

```
`<block argument>`  `<block argument>`
             \          /
              \        /
              `arith.subi`           `arith.constant`
                         \            /
                         `arith.addi`
                                |
                           returns `A`
```

Then, the block arguments and operations present in the backward slice of `A`, in the breadth-first order are:
`arith.addi`, `arith.subi`, `arith.constant`, `<block argument>`, and `<block argument>`.

Thus, the "key" associated with operand `A` is:
```
{
 {type: NON_CONSTANT_OP, opName: "arith.addi"},
 {type: NON_CONSTANT_OP, opName: "arith.subi"},
 {type: CONSTANT_OP, opName: "arith.constant"},
 {type: BLOCK_ARGUMENT, opName: ""},
 {type: BLOCK_ARGUMENT, opName: ""}
}
```

Now, if "keyA" is the key associated with operand `A` and "keyB" is the key associated with operand `B`, then:
"keyA" < "keyB" iff:
1. In the first unequal pair of corresponding AncestorKeys, the AncestorKey in operand `A` is smaller, or,
2. Both the AncestorKeys in every pair are the same and the size of operand `A`'s "key" is smaller.

AncestorKeys of type `BLOCK_ARGUMENT` are considered the smallest, those of type `CONSTANT_OP`, the largest, and `NON_CONSTANT_OP` types come in between. Within the types `NON_CONSTANT_OP` and `CONSTANT_OP`, the smaller ones are the ones with smaller op names (lexicographically).

---

Some examples of such a sorting:

Assume that the sorting is being applied to `foo.commutative`, which is a commutative op.

Example 1:

> %1 = foo.const 0
> %2 = foo.mul <block argument>, <block argument>
> %3 = foo.commutative %1, %2

Here,
1. The key associated with %1 is:
```
    {
     {CONSTANT_OP, "foo.const"}
    }
```
2. The key associated with %2 is:
```
    {
     {NON_CONSTANT_OP, "foo.mul"},
     {BLOCK_ARGUMENT, ""},
     {BLOCK_ARGUMENT, ""}
    }
```

The key of %2 < the key of %1
Thus, the sorted `foo.commutative` is:
> %3 = foo.commutative %2, %1

Example 2:

> %1 = foo.const 0
> %2 = foo.mul <block argument>, <block argument>
> %3 = foo.mul %2, %1
> %4 = foo.add %2, %1
> %5 = foo.commutative %1, %2, %3, %4

Here,
1. The key associated with %1 is:
```
    {
     {CONSTANT_OP, "foo.const"}
    }
```
2. The key associated with %2 is:
```
    {
     {NON_CONSTANT_OP, "foo.mul"},
     {BLOCK_ARGUMENT, ""}
    }
```
3. The key associated with %3 is:
```
    {
     {NON_CONSTANT_OP, "foo.mul"},
     {NON_CONSTANT_OP, "foo.mul"},
     {CONSTANT_OP, "foo.const"},
     {BLOCK_ARGUMENT, ""},
     {BLOCK_ARGUMENT, ""}
    }
```
4. The key associated with %4 is:
```
    {
     {NON_CONSTANT_OP, "foo.add"},
     {NON_CONSTANT_OP, "foo.mul"},
     {CONSTANT_OP, "foo.const"},
     {BLOCK_ARGUMENT, ""},
     {BLOCK_ARGUMENT, ""}
    }
```

Thus, the sorted `foo.commutative` is:
> %5 = foo.commutative %4, %3, %2, %1

Signed-off-by: Srishti Srivastava <srishti.srivastava@polymagelabs.com>

Reviewed By: Mogball

Differential Revision: https://reviews.llvm.org/D124750
2022-07-30 19:25:18 -04:00
Kazu Hirata
6d5fc1e3d5 [mlir] Don't use Optional::getValue (NFC) 2022-06-20 23:20:25 -07:00
Kazu Hirata
30c675878c Use value_or instead of getValueOr (NFC) 2022-06-19 10:34:41 -07:00
Chia-hung Duan
ba3a9f51ff [mlir:MultiOpDriver] Add operands to worklist should be checked
Operand's defining op may not be valid for adding to the worklist under
stict mode

Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D127180
2022-06-11 15:56:23 +00:00
Chia-hung Duan
633ad1d864 [mlir:MultiOpDriver] Quick fix the assertion position
The assertion should come after null check
2022-06-02 23:25:35 +00:00
Chia-hung Duan
2aeffc6d8d [mlir:MultiOpDriver] Don't add ops which are not in the allowed list
In strict mode, only the new inserted operation is allowed to add to the
worklist. Before this change, it would add the users of a replaced op
and it didn't check if the users are allowed to be pushed into the
worklist

Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D126899
2022-06-02 18:27:37 +00:00
River Riddle
aa568e082b [mlir:GreedyDriver] Return WalkResult::skip after deleting a known constant
This avoids use-after-free when trying to access the regions after visiting
the operation.
2022-05-18 02:14:02 -07:00
rkayaith
7814b559bd [GreedyPatternRewriter] Avoid reversing constant order
The previous fix from af371f9f98da only applied when using a bottom-up
traversal. The change here applies the constant preprocessing logic to the
top-down case as well. This resolves the issue with the canonicalizer pass still
reordering constants, since it uses a top-down traversal by default.

Fixes #51892

Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D125623
2022-05-18 00:55:59 -07:00
Cullen Rhodes
9bb0f4616a [mlir][licm] Fix debug output with newlines 2022-05-17 13:28:30 +00:00
Mogball
c8457eb532 [mlir][transforms] Add a topological sort utility and pass
This patch adds a topological sort utility and pass. A topological sort reorders
the operations in a block without SSA dominance such that, as much as possible,
users of values come after their producers.

The utility function sorts topologically the operation range in a given block
with an optional user-provided callback that can be used to virtually break cycles.
The toposort pass itself recursively sorts graph regions under the target op.

Reviewed By: mehdi_amini

Differential Revision: https://reviews.llvm.org/D125063
2022-05-16 20:47:30 +00:00
Frederik Gossen
673e9828be [MLIR] Fix iteration counting in greedy pattern application
Previously, checking that a fix point is reached was counted as a full
iteration. As this "iteration" never changes the IR, this seems counter-
intuitive.

Differential Revision: https://reviews.llvm.org/D123641
2022-04-21 15:17:28 -04:00
Mogball
b1d3faab7a [NFC] fix cmake build 2022-04-16 00:56:38 +00:00
Mogball
fa26c7ff4b [mlir] Refactor LICM into a utility
LICM is refactored into a utility that is application on any region. The implementation is moved to Transform/Utils.
2022-04-16 00:37:07 +00:00
Stella Stamenova
353f0a8e43 Revert "[mlir] Refactor LICM into a utility"
This reverts commit 3131f808243abe3746280e016ab9459c14d9e53b.

This commit broke the Windows mlir bot:
https://lab.llvm.org/buildbot/#/builders/13/builds/19745
2022-04-15 17:09:16 -07:00
Mogball
3131f80824 [mlir] Refactor LICM into a utility
LICM is refactored into a utility that is application on any region. The implementation is moved to Transform/Utils.
2022-04-15 22:07:01 +00:00
Mehdi Amini
7a80912dd8 Apply clang-tidy fixes for modernize-use-default-member-init in ControlFlowSinkUtils.cpp (NFC) 2022-04-15 08:01:04 +00:00
Markus Böck
0c789db541 [mlir] Add support for operation-produced successor arguments in BranchOpInterface
This patch revamps the BranchOpInterface a bit and allows a proper implementation of what was previously `getMutableSuccessorOperands` for operations, which internally produce arguments to some of the block arguments. A motivating example for this would be an invoke op with a error handling path:
```
invoke %function(%0)
  label ^success ^error(%1 : i32)

^error(%e: !error, %arg0 : i32):
  ...
```
The advantages of this are that any users of `BranchOpInterface` can still argue over remaining block argument operands (such as `%1` in the example above), as well as make use of the modifying capabilities to add more operands, erase an operand etc.

The way this patch implements that functionality is via a new class called `SuccessorOperands`, which is now returned by `getSuccessorOperands`. It basically contains an `unsigned` denoting how many operator produced operands exist, as well as a `MutableOperandRange`, which are the usual forwarded operands we are used to. The produced operands are assumed to the first few block arguments, followed by the forwarded operands afterwards. The role of `SuccessorOperands` is to provide various utility functions to modify and query the successor arguments from a `BranchOpInterface`.

Differential Revision: https://reviews.llvm.org/D123062
2022-04-08 08:28:16 +02:00
River Riddle
af371f9f98 Reland [GreedPatternRewriter] Preprocess constants while building worklist when not processing top down
Reland Note: Adds a fix to properly mark a commutative operation as folded if we change the order
             of its operands. This was uncovered by the fact that we no longer re-process constants.

This avoids accidentally reversing the order of constants during successive
application, e.g. when running the canonicalizer. This helps reduce the number
of iterations, and also avoids unnecessary changes to input IR.

Fixes #51892

Differential Revision: https://reviews.llvm.org/D122692
2022-04-07 11:31:42 -07:00