Commit Graph

852 Commits

Author SHA1 Message Date
Kunwar Grover
32db6fbdb9 [mlir][vector] Implement speculation for vector.transferx ops (#111533)
This patch implements speculation for
vector.transfer_read/vector.transfer_write ops, allowing these ops to
work with LICM.
2024-10-09 13:50:33 +01:00
Perry Gibson
7ad566d575 [mlir] Fix remove-dead-values pass throws error when module has a name (#109990)
Fixes #107870.

We can allow the enclosing Module operation to have a symbol.
The check was likely originally not considering this case and intended
to catch symbols inside the region, not accounting that the walk would
visit the enclosing operation.
2024-10-03 10:51:55 +02:00
MaheshRavishankar
cca32174fe [mlir][SCF] Use Affine ops for indexing math. (#108450)
For index type of induction variable, the indexing math is better
represented using affine ops such as `affine.delinearize_index`.

This also further demonstrates that some of these `affine` ops might
need to move to a different dialect. For one these ops only support
`IndexType` when they should be able to work with any integer type.

This change also includes some canonicalization patterns for
`affine.delinearize_index` operation to
1) Drop unit `basis` values
2) Remove the `delinearize_index` op when the `linear_index` is a loop
induction variable of a normalized loop and the `basis` is of size 1 and
is also the upper bound of the normalized loop.

---------

Signed-off-by: MaheshRavishankar <mahesh.ravishankar@gmail.com>
2024-09-27 18:25:41 -07:00
Longsheng Mou
1208699618 [mlir][transforms] Skip RemoveDeadValues for function declaration (#108221)
This patch skips `RemoveDeadValues` if funcOp is declaration, which
fixes a crash.
Fixes #107546.
2024-09-14 21:24:51 +08:00
Matthias Springer
6093c26ac9 [mlir][Transforms] Dialect conversion: Align handling of dropped values (#106760)
Handle dropped block arguments and dropped op results in the same way:
build a source materialization (that may fold away if unused). This
simplifies the code base a bit and makes it possible to merge
`legalizeConvertedArgumentTypes` and `legalizeConvertedOpResultTypes` in
a future commit. These two functions are almost doing the same thing
now.

As a side effect, this commit also changes the dialect conversion such
that temporary circular cast ops are no longer generated. (There was a
workaround in #107109 that can now be removed again.) Example:
```
%0 = "builtin.unrealized_conversion_cast"(%1) : (!a) -> !b
%1 = "builtin.unrealized_conversion_cast"(%0) : (!b) -> !a
// No further uses of %0, %1.
```

This happened when:
1. An op was erased. (No replacement values provided.)
2. A conversion pattern for another op builds a replacement value for
the erased op's results (first cast op) during `remapValues`, but that
SSA value is not used during the pattern application.
3. During the finalization phase, `legalizeConvertedOpResultTypes`
thinks that the erased op is alive because of the cast op that was built
in Step 2. It builds a cast from that replacement value to the original
type.
4. During the commit phase, all uses of the original op are replaced
with the casted value produced in Step 3. We have generated circular IR.

This problem can be avoided by making sure that source materializations
are generated for all dropped results. This ensures that we always have
some replacement SSA value in the mapping. Previously, we sometimes had
a value mapped and sometimes not. (No more special casing is needed
anymore to distinguish between "value dropped" or "value replaced with
SSA value".)
2024-09-12 15:30:29 +02:00
Kunwar Grover
c9aa55da62 [mlir][Linalg] Add speculation for LinalgStructuredOps (#108032)
This patch adds speculation behavior for linalg structured ops, allowing
them to be hoisted out of loops using LICM.
2024-09-11 09:30:05 +01:00
Matthias Springer
3815f478bb [mlir][Transforms] Dialect conversion: Make materializations optional (#107109)
This commit makes source/target/argument materializations (via the
`TypeConverter` API) optional.

By default (`ConversionConfig::buildMaterializations = true`), the
dialect conversion infrastructure tries to legalize all unresolved
materializations right after the main transformation process has
succeeded. If at least one unresolved materialization fails to resolve,
the dialect conversion fails. (With an error message such as `failed to
legalize unresolved materialization ...`.) Automatic materializations
through the `TypeConverter` API can now be deactivated. In that case,
every unresolved materialization will show up as a
`builtin.unrealized_conversion_cast` op in the output IR.

There used to be a complex and error-prone analysis in the dialect
conversion that predicted the future uses of unresolved
materializations. Based on that logic, some casts (that were deemed to
unnecessary) were folded. This analysis was needed because folding
happened at a point of time when some IR changes (e.g., op replacements)
had not materialized yet.

This commit removes that analysis. Any folding of cast ops now happens
after all other IR changes have been materialized and the uses can
directly be queried from the IR. This simplifies the analysis
significantly. And certain helper data structures such as
`inverseMapping` are no longer needed for the analysis. The folding
itself is done by `reconcileUnrealizedCasts` (which also exists as a
standalone pass).

After casts have been folded, the remaining casts are materialized
through the `TypeConverter`, as usual. This last step can be deactivated
in the `ConversionConfig`.

`ConversionConfig::buildMaterializations = false` can be used to debug
error messages such as `failed to legalize unresolved materialization
...`. (It is also useful in case automatic materializations are not
needed.) The materializations that failed to resolve can then be seen as
`builtin.unrealized_conversion_cast` ops in the resulting IR. (This is
better than running with `-debug`, because `-debug` shows IR where some
IR changes have not been materialized yet.)

Note: This is a reupload of #104668, but with correct handling of cyclic
unrealized_conversion_casts that may be generated by the dialect
conversion.
2024-09-05 19:40:58 +02:00
Ben Howe
c50fecaaaa [mlir] Fix region simplification bug when later blocks use prior block argument values (#97960)
This fixes #94520 by ensuring that any if any block arguments are being
used outside of the original block that the block is not considered a
candidate for merging.

More details: the root cause of the issue described in #94520 was that
`^bb2` and `^bb5` were being merged despite `%4` (an argument to `^bb2`)
was being used later in `^bb7`. When the block merge occurred, that
unintentionally changed the value of `%4` for all downstream code. This
change prevents that from happening.
2024-09-04 21:37:14 +02:00
Menooker
26645ae2ee [mlir][memref] Fix hoist-static-allocs option of buffer-results-to-out-params when function parameters are returned (#102093)
buffer-results-to-out-params pass will have a nullptr-referencing error
when hoist-static-allocs option is on, when the return value of a
function is a parameter of the function. This PR fixes this issue.
2024-09-04 20:36:19 +08:00
Matthias Springer
5eda498811 Revert "[mlir][Transforms] Dialect conversion: Make materializations optional" (#106778)
Reverts llvm/llvm-project#104668

This commit triggers an edge case that can cause circular
`unrealized_conversion_cast` ops.
https://github.com/llvm/llvm-project/pull/106760 may fix it, but it is
has other issues. Reverting this PR for now, until I find a solution for
that problem.
2024-08-30 12:34:41 -07:00
Christian Ulmann
6f092e501b [MLIR][Transforms] Update block arg locations during inlining (#106064)
This commit changes the inlining to also update the locations of block
arguments. Not updating these locations leads to LLVM IR verification
issues when exporting converted block arguments to phi nodes. This lack
of location update was not visible due to ignoring the argument
locations until recently.
Relevant change: https://github.com/llvm/llvm-project/pull/105534
2024-08-26 15:23:39 +02:00
Matthias Springer
d7073c5274 [mlir][Transforms] Dialect conversion: Make materializations optional (#104668)
This commit makes source/target/argument materializations (via the
`TypeConverter` API) optional.

By default (`ConversionConfig::buildMaterializations = true`), the
dialect conversion infrastructure tries to legalize all unresolved
materializations right after the main transformation process has
succeeded. If at least one unresolved materialization fails to resolve,
the dialect conversion fails. (With an error message such as `failed to
legalize unresolved materialization ...`.) Automatic materializations
through the `TypeConverter` API can now be deactivated. In that case,
every unresolved materialization will show up as a
`builtin.unrealized_conversion_cast` op in the output IR.

There used to be a complex and error-prone analysis in the dialect
conversion that predicted the future uses of unresolved
materializations. Based on that logic, some casts (that were deemed to
unnecessary) were folded. This analysis was needed because folding
happened at a point of time when some IR changes (e.g., op replacements)
had not materialized yet.

This commit removes that analysis. Any folding of cast ops now happens
after all other IR changes have been materialized and the uses can
directly be queried from the IR. This simplifies the analysis
significantly. And certain helper data structures such as
`inverseMapping` are no longer needed for the analysis. The folding
itself is done by `reconcileUnrealizedCasts` (which also exists as a
standalone pass).

After casts have been folded, the remaining casts are materialized
through the `TypeConverter`, as usual. This last step can be deactivated
in the `ConversionConfig`.

`ConversionConfig::buildMaterializations = false` can be used to debug
error messages such as `failed to legalize unresolved materialization
...`. (It is also useful in case automatic materializations are not
needed.) The materializations that failed to resolve can then be seen as
`builtin.unrealized_conversion_cast` ops in the resulting IR. (This is
better than running with `-debug`, because `-debug` shows IR where some
IR changes have not been materialized yet.)
2024-08-23 14:03:10 -07:00
Théo Degioanni
b084111c8e [mlir][mem2reg] Fix Mem2Reg attempting to promote in graph regions (#104910)
Mem2Reg assumes SSA dependencies but did not check for graph regions.
This fixes it.

---------

Co-authored-by: Christian Ulmann <christianulmann@gmail.com>
2024-08-23 15:15:10 +02:00
Billy Zhu
baa6627a0a [MLIR][Transforms] Fix dialect conversion inverse mapping (#104648)
Inverse mapping needs to be updated for the result that was remapped (it
was previously only updated halfway).
2024-08-19 18:04:16 -07:00
Matthias Springer
cb7614e839 [mlir][Transforms] Dialect conversion: Fix bug in computeNecessaryMaterializations (#104630)
There was a typo in the code path that removes unnecessary
materializations.

Before: Update `opResult` (result of an op different from `user`) in
mapping and remove `user`.
```
replaceMaterialization(rewriterImpl, opResult, inputOperands,
                       inverseMapping);
necessaryMaterializations.remove(materializationOps.lookup(user));
```

After: Update `user->getResults()` in mapping and remove `user`.
```
replaceMaterialization(rewriterImpl, user->getResults(), inputOperands,
                       inverseMapping);
necessaryMaterializations.remove(materializationOps.lookup(user));
```
2024-08-17 09:43:30 +02:00
Matthias Springer
2d50029f98 [mlir][Transforms] Dialect conversion: Build unresolved materialization for replaced ops (#101514)
When inserting an argument/source/target materialization, the dialect
conversion framework first inserts a "dummy"
`unrealized_conversion_cast` op (during the rewrite process) and then
(in the "finialize" phase) replaces these cast ops with the IR generated
by the type converter callback.

This is the case for all materializations, except when ops are being
replaced with values that have a different type. In that case, the
dialect conversion currently directly emits a source materialization.
This commit changes the implementation, such that a temporary
`unrealized_conversion_cast` is also inserted in that case.

This commit simplifies the code base: all materializations now happen in
`legalizeUnresolvedMaterialization`. This commit makes it possible to
decouple source/target/argument materializations from the dialect
conversion (to reduce the complexity of the code base). Such
materializations can then also be optional. This will be implemented in
a follow-up commit.

Depends on #101476.

---------

Co-authored-by: Jakub Kuderski <jakub@nod-labs.com>
2024-08-15 11:33:37 +02:00
Tobias Gysi
b72ac6f97a [MLIR] Let matchers work on int ranges (#102494)
This commit adds three matchers that unlike the m_NonZero matcher
not only match constants, but also operations that implement the
InferIntRangeInterface. These matchers can then match a non-zero value
or a value that is not minus one based on the inferred range. Additionally,
the commit uses the new matchers in the getSpeculatability functions of
Arith's signed and unsigned integer divisions. At the moment, the
matchers only look at the defining operation to avoid expensive IR walks.

This range based matchers can be useful when hoisting divisions out of
a loop, which requires knowing the divisor is non-zero and not minus one
for signed divisions. Just checking for a constant divisor may not be
sufficient, if the divisor is, for example, the result of an operation that
returns the number of threads of a team of threads.
2024-08-14 14:44:23 +02:00
Diego Caballero
2ac2e9a5b6 [mlir][LLVM] Improve lowering of llvm.byval function arguments (#100028)
When a function argument is annotated with the `llvm.byval` attribute,
[LLVM expects](https://llvm.org/docs/LangRef.html#parameter-attributes)
the function argument type to be an `llvm.ptr`. For example:

```
func.func (%args0 : llvm.ptr {llvm.byval = !llvm.struct<(i32)>} {
  ...
}
```

Unfortunately, this makes the type conversion context-dependent, which
is something that the type conversion infrastructure (i.e.,
`LLVMTypeConverter` in this particular case) doesn't support. For
example, we may want to convert `MyType` to `llvm.struct<(i32)>` in
general, but to an `llvm.ptr` type only when it's a function argument
passed by value.

To fix this problem, this PR changes the FuncToLLVM conversion logic to
generate an `llvm.ptr` when the function argument has a `llvm.byval`
attribute. An `llvm.load` is inserted into the function to retrieve the
value expected by the argument users.
2024-08-08 19:27:54 -07:00
Giuseppe Rossini
441b672bbd [mlir] Fix block merging (#102038)
With this PR I am trying to address:
https://github.com/llvm/llvm-project/issues/63230.

What changed:
- While merging identical blocks, don't add a block argument if it is
"identical" to another block argument. I.e., if the two block arguments
refer to the same `Value`. The operations operands in the block will
point to the argument we already inserted. This needs to happen to all
the arguments we pass to the different successors of the parent block
- After merged the blocks, get rid of "unnecessary" arguments. I.e., if
all the predecessors pass the same block argument, there is no need to
pass it as an argument.
- This last simplification clashed with
`BufferDeallocationSimplification`. The reason, I think, is that the two
simplifications are clashing. I.e., `BufferDeallocationSimplification`
contains an analysis based on the block structure. If we simplify the
block structure (by merging and/or dropping block arguments) the
analysis is invalid . The solution I found is to do a more prudent
simplification when running that pass.

**Note-1**: I ran all the integration tests
(`-DMLIR_INCLUDE_INTEGRATION_TESTS=ON`) and they passed.
**Note-2**: I fixed a bug found by @Dinistro in #97697 . The issue was
that, when looking for redundant arguments, I was not considering that
the block might have already some arguments. So the index (in the block
args list) of the i-th `newArgument` is `i+numOfOldArguments`.
2024-08-07 09:10:01 +01:00
Adrian Kuegel
17ba4f4053 Revert "[mlir][Transforms] Dialect conversion: Skip materializations when running without converter (#101318)"
This reverts commit 2aa96fcf75.

This was merged without a test. Also it seems it was only fixing an
issue for users which used a particular workaround that is not actually
needed anymore (skipping UnrealizedConversionCast operands).
2024-08-01 08:43:59 +00:00
Matthias Springer
2aa96fcf75 [mlir][Transforms] Dialect conversion: Skip materializations when running without converter (#101318)
TODO: test case
2024-07-31 14:36:50 -07:00
Matthias Springer
8fc329421b [mlir][Transforms] Dialect conversion: Add missing "else if" branch (#101148)
This code got lost in #97213 and there was no test for it. Add it back
with an MLIR test.

When a pattern is run without a type converter, we can assume that the
new block argument types of a signature conversion are legal. That's
because they were specified by the user. This won't work for 1->N
conversions due to limitations in the dialect conversion infrastructure,
so the original `FIXME` has to stay in place.
2024-07-30 16:36:47 +02:00
Krzysztof Drewniak
8955e285e1 [mlir] Add property combinators, initial ODS support (#94732)
While we have had a Properties.td that allowed for defining
non-attribute-backed properties, such properties were not plumbed
through the basic autogeneration facilities available to attributes,
forcing those who want to migrate to the new system to write such code
by hand.

## Potentially breaking changes

- The `setFoo()` methods on `Properties` struct no longer take their
inputs by const reference. Those wishing to pass non-owned values of a
property by reference to constructors and setters should set the
interface type to `const [storageType]&`
- Adapters and operations now define getters and setters for properties
listed in ODS, which may conflict with custom getters.
- Builders now include properties listed in ODS specifications,
potentially conflicting with custom builders with the same type
signature.

## Extensions to the `Property` class

This commit  adds several fields to the `Property` class, including:
- `parser`, `optionalParser`, and `printer` (for parsing/printing
properties of a given type in ODS syntax)
- `storageTypeValueOverride`, an extension of `defaultValue` to allow
the storage and interface type defaults to differ
- `baseProperty` (allowing for classes like `DefaultValuedProperty`)

Existing fields have also had their documentation comments updated.

This commit does not add a `PropertyConstraint` analogous to
`AttrConstraint`, but this is a natural evolution of the work here.

This commit also adds the concrete property kinds `I32Property`,
`I64Property`, `UnitProperty` (and special handling for it like for
UnitAttr), and `BoolProperty`.

## Property combinators

`Properties.td` also now includes several ways to combine properties.

One is `ArrayProperty<Property elem>`, which now stores a
variable-length array of some property as
`SmallVector<elem.storageType>` and uses `ArrayRef<elem.storageType>` as
its interface type. It has `IntArrayProperty` subclasses that change its
conversion to attributes to use `DenseI[N]Attr`s instead of an
`ArrayAttr`.

Similarly, `OptionalProperty<Property p>` wraps a property's storage in
`std::optional<>` and adds a `std::nullopt` default value. In the case
where the underlying property can be parsed optionally but doesn't have
its own default value, `OptionalProperty` can piggyback off the optional
parser to produce a cleaner syntax, as opposed to its general form,
which is either `none` or `some<[value]>`.

(Note that `OptionalProperty` can be nested if desired).

  ## Autogeneration changes

Operations and adaptors now support getters and setters for properties
like those for attributes. Unlike for attributes, there aren't separate
value and attribute forms, since there is no `FooAttr()` available for a
`getFooAttr()` to return.

The largest change is to operation formats. Previously, properties could
only be used in custom directives. Now, they can be used anywhere an
attribute could be used, and have parsers and printers defined in their
tablegen records.

These updates include special `UnitProperty` logic like that used for
`UnitAttr`.

## Misc.

Some attempt has been made to test the new functionality.

This commit takes tentative steps towards updating the documentation to
account for properties. A full update will be in order once any followup
work has been completed and the interfaces have stabilized.

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
Co-authored-by: Christian Ulmann <christianulmann@gmail.com>
2024-07-26 09:35:06 -05:00
Matthias Springer
684a5a30e1 [mlir][Transforms] Dialect conversion: fix crash when converting detached region (#100633)
This commit fixes a crash in the dialect conversion when applying a
signature conversion to a block inside of a detached region.

This fixes an issue reported in
4114d5be87 (r1691809730).
2024-07-25 22:14:15 +02:00
Christian Ulmann
6a5a64c56b Revert "[mlir] Fix block merging" (#100510)
Reverts llvm/llvm-project#97697

This commit introduced non-trivial bugs related to type consistency.
2024-07-25 10:42:25 +02:00
Matthias Springer
bbd4af5da2 [mlir][Transforms] Dialect conversion: Simplify handling of dropped arguments (#97213)
This commit simplifies the handling of dropped arguments and updates
some dialect conversion documentation that is outdated.

When converting a block signature, a `BlockTypeConversionRewrite` object
and potentially multiple `ReplaceBlockArgRewrite` are created. During
the "commit" phase, uses of the old block arguments are replaced with
the new block arguments, but the old implementation was written in an
inconsistent way: some block arguments were replaced in
`BlockTypeConversionRewrite::commit` and some were replaced in
`ReplaceBlockArgRewrite::commit`. The new
`BlockTypeConversionRewrite::commit` implementation is much simpler and
no longer modifies any IR; that is done only in `ReplaceBlockArgRewrite`
now. The `ConvertedArgInfo` data structure is no longer needed.

To that end, materializations of dropped arguments are now built in
`applySignatureConversion` instead of `materializeLiveConversions`; the
latter function no longer has to deal with dropped arguments.

Other minor improvements:
- Add more comments to `applySignatureConversion`.

Note: Error messages around failed materializations for dropped basic
block arguments changed slightly. That is because those materializations
are now built in `legalizeUnresolvedMaterialization` instead of
`legalizeConvertedArgumentTypes`.

This commit is in preparation of decoupling argument/source/target
materializations from the dialect conversion.

This is a re-upload of #96207.
2024-07-20 10:12:13 +02:00
Giuseppe Rossini
c63125d453 [mlir] Fix block merging (#97697)
With this PR I am trying to address:
https://github.com/llvm/llvm-project/issues/63230.

What changed:
- While merging identical blocks, don't add a block argument if it is
"identical" to another block argument. I.e., if the two block arguments
refer to the same `Value`. The operations operands in the block will
point to the argument we already inserted. This needs to happen to all
the arguments we pass to the different successors of the parent block
- After merged the blocks, get rid of "unnecessary" arguments. I.e., if
all the predecessors pass the same block argument, there is no need to
pass it as an argument.
- This last simplification clashed with
`BufferDeallocationSimplification`. The reason, I think, is that the two
simplifications are clashing. I.e., `BufferDeallocationSimplification`
contains an analysis based on the block structure. If we simplify the
block structure (by merging and/or dropping block arguments) the
analysis is invalid . The solution I found is to do a more prudent
simplification when running that pass.

**Note**: this a rework of #96871 . I ran all the integration tests
(`-DMLIR_INCLUDE_INTEGRATION_TESTS=ON`) and they passed.
2024-07-17 17:05:40 +01:00
Matthias Springer
acc159aea1 [mlir][Transforms] Dialect conversion: Fix missing source materialization (#97903)
This commit fixes a bug in the dialect conversion. During a 1:N
signature conversion, the dialect conversion did not insert a cast back
to the original block argument type, producing invalid IR.

See `test-block-legalization.mlir`: Without this commit, the operand
type of the op changes because an `unrealized_conversion_cast` is
missing:
```
"test.consumer_of_complex"(%v) : (!llvm.struct<(f64, f64)>) -> ()
```

To implement this fix, it was necessary to change the meaning of
argument materializations. An argument materialization now maps from the
new block argument types to the original block argument type. (It now
behaves almost like a source materialization.) This also addresses a
`FIXME` in the code base:
```
// FIXME: The current argument materialization hook expects the original
// output type, even though it doesn't use that as the actual output type
// of the generated IR. The output type is just used as an indicator of
// the type of materialization to do. This behavior is really awkward in
// that it diverges from the behavior of the other hooks, and can be
// easily misunderstood. We should clean up the argument hooks to better
// represent the desired invariants we actually care about.
```

It is no longer necessary to distinguish between the "output type" and
the "original output type".

Most type converter are already written according to the new API. (Most
implementations use the same conversion functions as for source
materializations.) One exception is the MemRef-to-LLVM type converter,
which materialized an `!llvm.struct` based on the elements of a memref
descriptor. It still does that, but casts the `!llvm.struct` back to the
original memref type. The dialect conversion inserts a target
materialization (to `!llvm.struct`) which cancels out with the other
cast.

This commit also fixes a bug in `computeNecessaryMaterializations`. The
implementation did not account for the possibility that a value was
replaced multiple times. E.g., replace `a` by `b`, then `b` by `c`.

This commit also adds a transform dialect op to populate SCF-to-CF
patterns. This transform op was needed to write a test case. The bug
described here appears only during a complex interplay of 1:N signature
conversions and op replacements. (I was not able to trigger it with ops
and patterns from the `test` dialect without duplicating the `scf.if`
pattern.)

Note for LLVM integration: Make sure that all
`addArgument/Source/TargetMaterialization` functions produce an SSA of
the specified type.

Depends on #98743.
2024-07-15 17:04:56 +02:00
Mehdi Amini
28a11cc492 Revert "Fix block merging" (#97460)
Reverts llvm/llvm-project#96871

Bots are broken.
2024-07-02 20:57:16 +02:00
Giuseppe Rossini
6c3897d90e Fix block merging (#96871)
With this PR I am trying to address:
https://github.com/llvm/llvm-project/issues/63230.

What changed:
- While merging identical blocks, don't add a block argument if it is
"identical" to another block argument. I.e., if the two block arguments
refer to the same `Value`. The operations operands in the block will
point to the argument we already inserted
- After merged the blocks, get rid of "unnecessary" arguments. I.e., if
all the predecessors pass the same block argument, there is no need to
pass it as an argument.
- This last simplification clashed with
`BufferDeallocationSimplification`. The reason, I think, is that the two
simplifications are clashing. I.e., `BufferDeallocationSimplification`
contains an analysis based on the block structure. If we simplify the
block structure (by merging and/or dropping block arguments) the
analysis is invalid . The solution I found is to do a more prudent
simplification when running that pass.

**Note**: many tests are still not passing. But I wanted to submit the
code before changing all the tests (and probably adding a couple), so
that we can agree in principle on the algorithm/design.
2024-07-02 17:12:33 +01:00
Benjamin Kramer
4d46b460f9 Revert "[mlir][Transforms] Dialect conversion: Simplify handling of dropped arguments (#96207)"
This reverts commit f1e0657d14.

It breaks SCF conversion, see test case on the PR.
2024-06-27 09:16:40 +02:00
Matthias Springer
f1e0657d14 [mlir][Transforms] Dialect conversion: Simplify handling of dropped arguments (#96207)
This commit simplifies the handling of dropped arguments and updates
some dialect conversion documentation that is outdated.

When converting a block signature, a `BlockTypeConversionRewrite` object
and potentially multiple `ReplaceBlockArgRewrite` are created. During
the "commit" phase, uses of the old block arguments are replaced with
the new block arguments, but the old implementation was written in an
inconsistent way: some block arguments were replaced in
`BlockTypeConversionRewrite::commit` and some were replaced in
`ReplaceBlockArgRewrite::commit`. The new
`BlockTypeConversionRewrite::commit` implementation is much simpler and
no longer modifies any IR; that is done only in `ReplaceBlockArgRewrite`
now. The `ConvertedArgInfo` data structure is no longer needed.

To that end, materializations of dropped arguments are now built in
`applySignatureConversion` instead of `materializeLiveConversions`; the
latter function no longer has to deal with dropped arguments.

Other minor improvements:
- Improve variable name: `origOutputType` -> `origArgType`. Add an
assertion to check that this field is only used for argument
materializations.
- Add more comments to `applySignatureConversion`.

Note: Error messages around failed materializations for dropped basic
block arguments changed slightly. That is because those materializations
are now built in `legalizeUnresolvedMaterialization` instead of
`legalizeConvertedArgumentTypes`.

This commit is in preparation of decoupling argument/source/target
materializations from the dialect conversion.
2024-06-25 08:43:28 +02:00
Matthias Springer
6dc8de7a0a [mlir][memref] Improve memref.subview type inference (#96421)
The `memref.subview` result type inference
(`SubViewOp::inferResultType`) sometimes used to produce a dynamic
offset when a static offset is possible.

When a dynamic value (stride, size, etc.) is multiplied with zero, the
result is always a "static 0". Based on this, the result type inference
implementation can be improved to produce more static type information
in memref types.
2024-06-23 19:05:00 +02:00
Mehdi Amini
a506279e5c [mlir] Do not merge blocks during canonicalization by default (#95057)
This is a heavy process, and it can trigger a massive explosion in
adding block arguments. While potentially reducing the code size, the
resulting merged blocks with arguments are hiding some of the def-use
chain and can even hinder some further analyses/optimizations: a merge
block does not have it's own path-sensitive context, instead the context
is merged from all the predecessors.

Previous behavior can be restored by passing:

  {test-convergence region-simplify=aggressive}

to the canonicalize pass.
2024-06-14 22:38:56 +02:00
klensy
a5985ca51d [mlir][test] Fix filecheck annotation typos [2/n] (#93476)
Few more fixes
previous: https://github.com/llvm/llvm-project/pull/92897 pr
Issues from https://github.com/llvm/llvm-project/issues/93154 unfixed.

---------

Co-authored-by: klensy <nightouser@gmail.com>
2024-06-14 17:16:02 +02:00
drazi
a4490217fc merge code for llvm.emit_c_interface into convertFuncOpToLLVMFuncOp (#92986)
In today's repo, attribute `llvm.emit_c_interface` of func op is handled
outside of `mlir::convertFuncOpToLLVMFuncOp` in `FuncOpConversion`
pattern. In some cases, `FuncOpConversion` can't be directly re-used,
but we still want to re-use the code to emit c interface for
`llvm.emit_c_interface`.

Changes in this PR
* move the code to generate c with "llvm.emit_c_interface" interface
into `mlir::convertFuncOpToLLVMFuncOp` to be able to re-use it.
* added unit test to verify c interface for jit can be generated
correctly if only call `convertFuncOpToLLVMFuncOp`.
* removed `FuncOpConversionBase`

---------

Co-authored-by: Fung Xie <ftse@nvidia.com>
2024-05-23 23:41:46 +02:00
Christian Ulmann
b00e0c1671 [MLIR][Analysis] Consolidate topological sort utilities (#92563)
This PR attempts to consolidate the different topological sort utilities
into one place. It adds them to the analysis folder because the
`SliceAnalysis` uses some of these.

There are now two different sorting strategies: 
1. Sort only according to SSA use-def chains
2. Sort while taking regions into account. This requires a much more
elaborate traversal and cannot be applied on graph regions that easily.

This additionally reimplements the region aware topological sorting
because the previous implementation had an exponential space complexity.

I'm open to suggestions on how to combine this further or how to fuse
the test passes.
2024-05-22 08:48:10 +02:00
Christian Ulmann
0b5b2027f9 [MLIR][SROA] Reuse allocators to avoid rewalking the IR (#91971)
This commit extends the SROA interfaces to ensure the interface
instantiations can communicate newly created allocators to the
algorithm. This ensures that the SROA implementation does no longer
require re-walking the IR to find new allocators.
2024-05-14 10:26:27 +02:00
Christian Ulmann
eeafc9daa1 [MLIR][Mem2Reg] Fix multi slot handling & move retry handling (#91464)
This commit fixes Mem2Regs mutli-slot allocator handling and extends the
test dialect to test this.

Additionally, this modifies Mem2Reg's API to always attempt a full
promotion on all the passed in "allocators". This ensures that the pass
does not require unnecessary walks over the regions and improves caching
benefits.
2024-05-13 07:37:41 +02:00
Andrzej Warzyński
b1da82ae3d [mlir][arith] Fix overflow bug in arith::CeilDivSIOp::fold (#90947)
The folder for arith::CeilDivSIOp should only be applied when it can be
guaranteed that no overflow would happen. The current implementation
works fine when both dividends are positive and the only arithmetic
operation is the division itself.

However, in cases where either the dividend or divisor is negative (or
both),
the division is split into multiple arith operations, e.g.: `- ( -a /
b)`. That's
additional 2 operations on top of the actual division that can overflow 
- the folder should check all 3 ops for overflow. 

The current logic doesn't do that - it effectively only checks the last
operation
(i.e. the division). It breaks when using e.g. MININT values (e.g. -128
for
8-bit integers) - negating such values overflows.

This PR makes sure that no folding happens if any of the intermediate
arithmetic operations overflows.

Fixes https://github.com/llvm/llvm-project/issues/89382
2024-05-08 21:06:03 +01:00
Menooker
0af448b711 [MLIR][Bufferization] BufferResultsToOutParams: Add an option to eliminate AllocOp and avoid Copy (#90011)
Add an option hoist-static-allocs to remove the unnecessary memref.alloc
and memref.copy after this pass, when the memref in ReturnOp is
allocated by memref.alloc and is statically shaped. Instead, it replaces
the uses of the allocated memref with the memref in the out argument.
By default, BufferResultsToOutParams will result in a memcpy operation
to copy the originally returned memref to the output argument memref.
This is inefficient when the source of memcpy (the returned memref in
the original ReturnOp) is from a local AllocOp. The pass can use the
output argument memref to replace the locally allocated memref for
better performance.hoist-static-allocs avoids dynamic allocation and
memory movement.
This option will be critical for performance-sensivtive applications,
which require BufferResultsToOutParams pass for a caller-owned output
buffer calling convension.
2024-05-08 10:14:52 +08:00
Christian Ulmann
4513050f52 [MLIR] Harmonize the behavior of the folding API functions (#88508)
This commit changes `OpBuilder::tryFold` to behave more similarly to
`Operation::fold`. Concretely, this ensures that even an in-place fold
returns `success`.
This is necessary to fix a bug in the dialect conversion that occurred
when an in-place folding made an operation legal. The dialect conversion
infrastructure did not check if the result of an in-place folding
legalized the operation and just went ahead and tried to apply pattern
anyways.

The added test contains a simplified version of a breakage we observed
downstream.
2024-04-23 08:05:55 +02:00
MaheshRavishankar
5aeb604c7c [mlir][SCF] Modernize coalesceLoops method to handle scf.for loops with iter_args (#87019)
As part of this extension this change also does some general cleanup

1) Make all the methods take `RewriterBase` as arguments instead of
   creating their own builders that tend to crash when used within
   pattern rewrites
2) Split `coalesePerfectlyNestedLoops` into two separate methods, one
   for `scf.for` and other for `affine.for`. The templatization didnt
   seem to be buying much there.

Also general clean up of tests.
2024-04-04 13:44:24 -07:00
Ivan Butygin
5b66b6a32a [mlir][pass] Add composite pass utility (#87166)
Composite pass allows to run sequence of passes in the loop until fixed
point or maximum number of iterations is reached. The usual candidates
are canonicalize+CSE as canonicalize can open more opportunities for CSE
and vice-versa.
2024-04-02 13:30:45 +03:00
long.chen
631e54aa1a [mlir][arith] fix wrong floordivsi fold (#83248)
Fixs https://github.com/llvm/llvm-project/issues/83079
2024-03-22 23:52:47 +08:00
Matthias Gehre
e6048b728d [MLIR][Bufferization] BufferResultsToOutParams: Add option to add attribute to output arguments (#84320)
Adds a new pass option `add-result-attr` that will make the pass add the
attribute `{bufferize.result}` to each argument that was converted from
a result.
This is important e.g. when later using the python bindings / execution
engine to understand which arguments are actually results.

To be able to test this, the pass option was added to the tablegen. To
avoid collisions with the existing, manually defined option struct
`BufferResultsToOutParamsOptions`, that one was renamed to
`BufferResultsToOutParamsOpts`.
2024-03-14 07:50:16 +01:00
Christian Sigg
bb893fa23f [mlir] Fix inlining-threshold.mlir test for NDEBUG builds. 2024-03-13 17:26:50 +01:00
Slava Zakharin
732f5368cd [RFC][mlir] Add profitability callback to the Inliner. (#84258)
Discussion at https://discourse.llvm.org/t/inliner-cost-model/2992

This change adds a callback that reports whether inlining
of the particular call site (communicated via ResolvedCall argument)
is profitable or not. The default MLIR inliner pass behavior
is unchanged, i.e. the callback always returns true.
This callback may be used to customize the inliner behavior
based on the target specifics (like target instructions costs),
profitability of the inlining for further optimizations
(e.g. if inlining may enable loop optimizations or scalar optimizations
due to object shape propagation), optimization levels (e.g. -Os inlining
may be quite different from -Ofast inlining), etc.

One of the questions is whether the ResolvedCall entity represents
enough of the context for the custom inlining models to come up with
the profitability decision. I think we can start with this and
extend it as necessary.

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
2024-03-13 08:23:10 -07:00
Congcong Cai
ad23127222 [mlir][inline] avoid inline self-recursive function (#83092) 2024-03-12 06:49:09 +08:00
Matthias Springer
60a20bd697 [mlir][Transforms] Add listener support to dialect conversion (#83425)
This commit adds listener support to the dialect conversion. Similarly
to the greedy pattern rewrite driver, an optional listener can be
specified in the configuration object.

Listeners are notified only if the dialect conversion succeeds. In case
of a failure, where some IR changes are first performed and then rolled
back, no notifications are sent.

Due to the fact that some kinds of rewrite are reflected in the IR
immediately and some in a delayed fashion, there are certain limitations
when attaching a listener; these are documented in `ConversionConfig`.
To summarize, users are always notified about all rewrites that
happened, but the notifications are sent all at once at the very end,
and not interleaved with the actual IR changes.

This change is in preparation improvements to
`transform.apply_conversion_patterns`, which currently invalidates all
handles. In the future, it can use a listener to update handles
accordingly, similar to `transform.apply_patterns`.
2024-03-08 10:34:45 +09:00