31 Commits

Author SHA1 Message Date
klensy
9f2dd085ae
[mlir] fix copypaste typos in asserts (#119878)
This fixes few copypaste typos

I've also spotted weird `getNumRows() == getNumRows()`: looks like
leftover after refactoring


ea8e328ae2/mlir/lib/Analysis/Presburger/Simplex.cpp (L107-L111)

Co-authored-by: klensy <nightouser@gmail.com>
2024-12-13 21:39:55 +01:00
Kazu Hirata
6ffa7cd8b0
[Interfaces] Avoid repeated hash lookups (NFC) (#108140) 2024-09-11 06:40:37 -07:00
Benjamin Maxwell
29a925abb6
[mlir][affine][Analysis] Add conservative bounds for semi-affine mods (#93576)
This patch adds support for computing bounds for semi-affine mod
expression to FlatLinearConstraints. This is then enabled within the
ScalableValueBoundsConstraintSet to allow computing the bounds of
scalable remainder loops.

E.g. computing the bound of something like:
```
// `1000 mod s0` is a semi-affine.
#remainder_start_index = affine_map<()[s0] -> (-(1000 mod s0) + 1000)>
#remaining_iterations = affine_map<(d0) -> (-d0 + 1000)>

%0 = affine.apply #remainder_start_index()[%c8_vscale]
scf.for %i = %0 to %c1000 step %c8_vscale {
  %remaining_iterations = affine.apply #remaining_iterations(%i)
  // The upper bound for the remainder loop iterations should be:
  // %c8_vscale - 1  (expressed as an affine map,
  // affine_map<()[s0] -> (s0 * 8 - 1)>, where s0 is vscale)
  %bound = "test.reify_bound"(%remaining_iterations) <{scalable, ...}>
}
```

There are caveats to this implementation. To be able to add a bound for
a `mod` we need to assume the rhs is positive (> 0). This may not be
known when adding the bounds for the `mod` expression. So to handle this
a constraint is added for `rhs > 0`, this may later be found not to hold
(in which case the constraints set becomes empty/invalid).

This is not a problem for computing scalable bounds where it's safe to
assume `s0` is vscale (or some positive multiple of it). But this may
need to be considered when enabling this feature elsewhere (to ensure
correctness).
2024-06-05 11:35:13 +01:00
Matthias Springer
40dd3aa91d
[mlir][Interfaces] Variable abstraction for ValueBoundsOpInterface (#87980)
This commit generalizes and cleans up the `ValueBoundsConstraintSet`
API. The API used to provide function overloads for comparing/computing
bounds of:
- index-typed SSA value
- dimension of shaped value
- affine map + operands

This commit removes all overloads. There is now a single entry point for
each `compare` variant and each `computeBound` variant. These functions
now take a `Variable`, which is internally represented as an affine map
and map operands.

This commit also adds support for computing bounds for an affine map +
operands. There was previously no public API for that.
2024-04-16 10:59:02 +02:00
Jie Fu
dc39028906 [mlir] Fix -Wsign-compare in ValueBoundsOpInterface.cpp (NFC)
/llvm-project/mlir/lib/Interfaces/ValueBoundsOpInterface.cpp:762:16:
error: comparison of integers of different signs: 'int64_t' (aka 'long') and 'size_t' (aka 'unsigned long') [-Werror,-Wsign-compare]
        rhsPos >= cstr.positionToValueDim.size())
        ~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/llvm-project/mlir/lib/Interfaces/ValueBoundsOpInterface.cpp:761:16:
error: comparison of integers of different signs: 'int64_t' (aka 'long') and 'size_t' (aka 'unsigned long') [-Werror,-Wsign-compare]
    if (lhsPos >= cstr.positionToValueDim.size() ||
        ~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 errors generated.
2024-04-11 14:50:40 +08:00
Matthias Springer
21265f692e
[mlir][Interfaces] ValueBoundsOpInterface: Fix typo (#87976)
This was likely a copy-and-paste typo.
2024-04-11 08:27:12 +02:00
Matthias Springer
297eca981e
[mlir][Interfaces] ValueBoundsOpInterface: Add API to compare values (#86915)
This commit adds a new public API to `ValueBoundsOpInterface` to compare
values/dims. Supported comparison operators are: LT, LE, EQ, GE, GT.

The new `ValueBoundsOpInterface::compare` API replaces and generalizes
`ValueBoundsOpInterface::areEqual`. Not only does it provide additional
comparison operators, it also works in cases where the difference
between the two values/dims is non-constant. The previous implementation
of `areEqual` used to compute a constant bound of `val1 - val2` (check
if it `== 0` or `!= 0`).

Note: This commit refactors, generalizes and adds a public API for
value/dim comparison. The comparison functionality itself was introduced
in #85895 and is already in use for analyzing `scf.if`.

In the long term, this improvement will allow for a more powerful
analysis of subset ops. A future commit will update
`areOverlappingSlices` to use the new comparison API.
(`areEquivalentSlices` is already using the new API.) This will improve
subset equivalence/disjointness checks with non-constant
offsets/sizes/strides.
2024-04-11 08:23:48 +02:00
Matthias Springer
76435f2dca
[mlir][SCF] ValueBoundsConstraintSet: Support scf.if (branches) (#87860)
This commit adds support for `scf.if` to `ValueBoundsConstraintSet`.

Example:
```
%0 = scf.if ... -> index {
  scf.yield %a : index
} else {
  scf.yield %b : index
}
```

The following constraints hold for %0:
* %0 >= min(%a, %b)
* %0 <= max(%a, %b)

Such constraints cannot be added to the constraint set; min/max is not
supported by `IntegerRelation`. However, if we know which one of %a and
%b is larger, we can add constraints for %0. E.g., if %a <= %b:
* %0 >= %a
* %0 <= %b

This commit required a few minor changes to the
`ValueBoundsConstraintSet` infrastructure, so that values can be
compared while we are still in the process of traversing the IR/adding
constraints.

Note: This is a re-upload of #85895, which was reverted. The bug that
caused the failure was fixed in #87859.
2024-04-06 13:04:49 +09:00
Mehdi Amini
8487e05967 Revert "[mlir][SCF] ValueBoundsConstraintSet: Support scf.if (branches) (#85895)"
This reverts commit 6b30ffef28c35c24bfd8190e06eeaa0c5cd73cbd.

gcc7 bot is broken
2024-04-05 03:00:35 -07:00
Matthias Springer
6b30ffef28
[mlir][SCF] ValueBoundsConstraintSet: Support scf.if (branches) (#85895)
This commit adds support for `scf.if` to `ValueBoundsConstraintSet`.

Example:
```
%0 = scf.if ... -> index {
  scf.yield %a : index
} else {
  scf.yield %b : index
}
```

The following constraints hold for %0:
* %0 >= min(%a, %b)
* %0 <= max(%a, %b)

Such constraints cannot be added to the constraint set; min/max is not
supported by `IntegerRelation`. However, if we know which one of %a and
%b is larger, we can add constraints for %0. E.g., if %a <= %b:
* %0 >= %a
* %0 <= %b

This commit required a few minor changes to the
`ValueBoundsConstraintSet` infrastructure, so that values can be
compared while we are still in the process of traversing the IR/adding
constraints.
2024-04-05 13:14:00 +09:00
Matthias Springer
5e4a44380e
[mlir][Interfaces][NFC] ValueBoundsConstraintSet: Pass stop condition in the constructor (#86099)
This commit changes the API of `ValueBoundsConstraintSet`: the stop
condition is now passed to the constructor instead of `processWorklist`.
That makes it easier to add items to the worklist multiple times and
process them in a consistent manner. The current
`ValueBoundsConstraintSet` is passed as a reference to the stop
function, so that the stop function can be defined before the the
`ValueBoundsConstraintSet` is constructed.

This change is in preparation of adding support for branches.
2024-04-04 17:05:47 +09:00
Matthias Springer
d542cb3175
[mlir][Interfaces][NFC] ValueBoundsConstraintSet: Delete dead code (#86098)
There is an assertion that the stop condition is not satisfied for the
the starting point at the beginning of `computeBound`. Therefore, that
case does not have to be handled later on in that function.
2024-04-04 16:56:31 +09:00
Matthias Springer
10b07f2324
[mlir][Interfaces] ValueBoundsConstraintSet: Add dump helper function (#86634)
This commit adds a helper function that dumps the constraint set and the
mapping of columns to values/dims. For debugging only.

Example output:
```
==========
Columns:
(column	dim	value)
 0	1	linalg.fill (result 0)
 1	1	tensor.extract_slice (result 0)
 2	n/a	affine.min (result 0)
 3	n/a	scf.for (bbarg 0)
 4	n/a	func.func (bbarg 2)

Constraint set:
Domain: 0, Range: 1, Symbols: 4, Locals: 0
6 constraints
(None	None	None	None	None	const)
 1	-1	0	0	0	0	= 0
 0	1	-1	0	0	0	= 0
 0	0	-1	-1	1	0	>= 0
 0	0	-1	0	0	4	>= 0
 0	0	0	1	0	0	>= 0
 0	0	0	-1	1	-1	>= 0
==========
```
2024-03-27 10:49:24 +09:00
Benjamin Maxwell
2861856baf
[mlir][Vector] Add utility for computing scalable value bounds (#83876)
This adds a new API built with the `ValueBoundsConstraintSet` to compute
the bounds of possibly scalable quantities. It uses knowledge of the
range of vscale (which is defined by the target architecture), to solve
for the bound as either a constant or an expression in terms of vscale.

The result is an `AffineMap` that will always take at most one
parameter, vscale, and returns a single result, which is the bound of
`value`.

The API is defined as follows:

```c++
FailureOr<ConstantOrScalableBound>
vector::ScalableValueBoundsConstraintSet::computeScalableBound(
  Value value, std::optional<int64_t> dim,
  unsigned vscaleMin, unsigned vscaleMax,
  presburger::BoundType boundType, 
  bool closedUB = true,
  StopConditionFn stopCondition = nullptr);
```

Note: `ConstantOrScalableBound` is a thin wrapper over the `AffineMap`
with a utility for converting the bound to a single quantity (i.e. a
size and scalable flag).

We believe this API could prove useful downstream in IREE (which uses a
similar analysis to hoist allocas, which currently fails for scalable
vectors).
2024-03-21 14:18:56 +00:00
Mehdi Amini
9b514235fc Apply clang-tidy fixes for bugprone-argument-comment in ValueBoundsOpInterface.cpp (NFC) 2024-02-15 10:17:27 -08:00
Matthias Springer
ff614a5729
[mlir][Interfaces] LISH: Add helpers for hyperrectangular subsets (#70628)
The majority of subset ops operate on hyperrectangular subsets. This
commit adds a new optional interface method
(`getAccessedHyperrectangularSlice`) that can be implemented by such
subset ops. If implemented, the other `operatesOn...` interface methods
of the `SubsetOpInterface` do not have to be implemented anymore.

The comparison logic for hyperrectangular subsets (is
disjoint/equivalent) is implemented with `ValueBoundsOpInterface`. This
makes the subset hoisting more powerful: simple cases where two
different SSA values always have the same runtime value can now be
supported.
2023-11-01 11:29:00 +09: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
Lei Zhang
3049ac44e6
[mlir][vector] Enable transfer op hoisting with dynamic indices (#68500)
Recent changes (https://github.com/llvm/llvm-project/pull/66930)
disabled vector transfer ops hoisting with view-like intermediate ops.
The recommended way is to fold subview ops into transfer op indices
before invoking hoisting. That would mean now we see transfer op indices
involving dynamic values, instead of static constant values before with
subview ops. Therefore hoisting won't kick in anymore. This breaks
downstream users.

To fix it, this commit enables hoisting transfer ops with dynamic
indices by using `ValueBoundsConstraintSet` to prove ranges are disjoint
in `isDisjointTransferIndices`. Given that utility is used in many
places including op folders, right now we introduce a flag to it and
only set as true for "heavy" transforms in hoisting and load-store
forwarding.
2023-10-15 16:37:54 -07:00
Matthias Springer
c5624dc055
[mlir][Interfaces] ValueBoundsOpInterface: Handle all destination style ops (#65736)
This commit provides a default implementation for all ops that implement
the `DestinationStyleOpInterface`. Result values of such ops are tied to
operand, and those have the same type.
2023-09-08 19:46:40 +02:00
Tres Popp
68f58812e3 [mlir] Move casting calls from methods to function calls
The MLIR classes Type/Attribute/Operation/Op/Value support
cast/dyn_cast/isa/dyn_cast_or_null functionality through llvm's doCast
functionality in addition to defining methods with the same name.
This change begins the migration of uses of the method to the
corresponding function call as has been decided as more consistent.

Note that there still exist classes that only define methods directly,
such as AffineExpr, and this does not include work currently to support
a functional cast/isa call.

Context:
- https://mlir.llvm.org/deprecation/ at "Use the free function variants
  for dyn_cast/cast/isa/…"
- Original discussion at https://discourse.llvm.org/t/preferred-casting-style-going-forward/68443

Implementation:
This patch updates all remaining uses of the deprecated functionality in
mlir/. This was done with clang-tidy as described below and further
modifications to GPUBase.td and OpenMPOpsInterfaces.td.

Steps are described per line, as comments are removed by git:
0. Retrieve the change from the following to build clang-tidy with an
   additional check:
   main...tpopp:llvm-project:tidy-cast-check
1. Build clang-tidy
2. Run clang-tidy over your entire codebase while disabling all checks
   and enabling the one relevant one. Run on all header files also.
3. Delete .inc files that were also modified, so the next build rebuilds
   them to a pure state.

```
ninja -C $BUILD_DIR clang-tidy

run-clang-tidy -clang-tidy-binary=$BUILD_DIR/bin/clang-tidy -checks='-*,misc-cast-functions'\
               -header-filter=mlir/ mlir/* -fix

rm -rf $BUILD_DIR/tools/mlir/**/*.inc
```

Differential Revision: https://reviews.llvm.org/D151542
2023-05-26 10:29:55 +02:00
Matthias Springer
ff9306459f [mlir][Interfaces] ValueBoundsOpInterface: Check if two values are equal
Add a helper function that computes if two SSA values have the same value, utilizing the `ValueBoundsOpInterface` infrastructure. Two SSA values have the same value, an equality bound of 0 can be derived for their subtraction.

The helper function can also be used to determine if two tensor dimension sizes are equal.

Differential Revision: https://reviews.llvm.org/D151443
2023-05-25 19:08:48 +02:00
Matthias Springer
c872e6c743 [mlir][Interfaces][NFC] ValueBoundsConstraintSet: Simplify constructor
Differential Revision: https://reviews.llvm.org/D151442
2023-05-25 18:56:24 +02:00
Tres Popp
5550c82189 [mlir] Move casting calls from methods to function calls
The MLIR classes Type/Attribute/Operation/Op/Value support
cast/dyn_cast/isa/dyn_cast_or_null functionality through llvm's doCast
functionality in addition to defining methods with the same name.
This change begins the migration of uses of the method to the
corresponding function call as has been decided as more consistent.

Note that there still exist classes that only define methods directly,
such as AffineExpr, and this does not include work currently to support
a functional cast/isa call.

Caveats include:
- This clang-tidy script probably has more problems.
- This only touches C++ code, so nothing that is being generated.

Context:
- https://mlir.llvm.org/deprecation/ at "Use the free function variants
  for dyn_cast/cast/isa/…"
- Original discussion at https://discourse.llvm.org/t/preferred-casting-style-going-forward/68443

Implementation:
This first patch was created with the following steps. The intention is
to only do automated changes at first, so I waste less time if it's
reverted, and so the first mass change is more clear as an example to
other teams that will need to follow similar steps.

Steps are described per line, as comments are removed by git:
0. Retrieve the change from the following to build clang-tidy with an
   additional check:
   https://github.com/llvm/llvm-project/compare/main...tpopp:llvm-project:tidy-cast-check
1. Build clang-tidy
2. Run clang-tidy over your entire codebase while disabling all checks
   and enabling the one relevant one. Run on all header files also.
3. Delete .inc files that were also modified, so the next build rebuilds
   them to a pure state.
4. Some changes have been deleted for the following reasons:
   - Some files had a variable also named cast
   - Some files had not included a header file that defines the cast
     functions
   - Some files are definitions of the classes that have the casting
     methods, so the code still refers to the method instead of the
     function without adding a prefix or removing the method declaration
     at the same time.

```
ninja -C $BUILD_DIR clang-tidy

run-clang-tidy -clang-tidy-binary=$BUILD_DIR/bin/clang-tidy -checks='-*,misc-cast-functions'\
               -header-filter=mlir/ mlir/* -fix

rm -rf $BUILD_DIR/tools/mlir/**/*.inc

git restore mlir/lib/IR mlir/lib/Dialect/DLTI/DLTI.cpp\
            mlir/lib/Dialect/Complex/IR/ComplexDialect.cpp\
            mlir/lib/**/IR/\
            mlir/lib/Dialect/SparseTensor/Transforms/SparseVectorization.cpp\
            mlir/lib/Dialect/Vector/Transforms/LowerVectorMultiReduction.cpp\
            mlir/test/lib/Dialect/Test/TestTypes.cpp\
            mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp\
            mlir/test/lib/Dialect/Test/TestAttributes.cpp\
            mlir/unittests/TableGen/EnumsGenTest.cpp\
            mlir/test/python/lib/PythonTestCAPI.cpp\
            mlir/include/mlir/IR/
```

Differential Revision: https://reviews.llvm.org/D150123
2023-05-12 11:21:25 +02:00
Matthias Springer
77124386fe [mlir][tensor] Add transform to make tensor.pad loop-independent
Add a transform to make `tensor.pad` and `tensor.empty` ops independent of SCF loop IVs. Such ops can then be hoisted.

E.g.:
```
scf.for %iv = %lb to %ub step %step {
  %high = affine.apply affine_map<(d0)[s0] -> (s0 - d0)> (%i)[%ub]
  %p = tensor.pad %t low[5] high[%high] ...
  ...
}
```
Is transformed to:
```
%high_new = affine.apply affine_map<()[s0, s1] -> (-s0 + s1)> ()[%lb, %ub]
%p_hoistable = tensor.pad %t low[5] high[%high_new]
%dim = tensor.dim %t, %c0
%size = affine.apply affine_map<(d0)[s0, s1] -> (-d0 + s0 + s1 + 5)>(%iv)[%ub, %dim]
%slice = tensor.extract_slice %p_hoistable [0] [%size] [1]
```

Differential Revision: https://reviews.llvm.org/D143910
2023-04-28 11:46:32 +09:00
Matthias Springer
eabb6ccdc8 [mlir][linalg] Replace getUpperBoundForIndex implementation
Use `reifyValueBound` instead, which is more general not hard-coded to a specific list supported ops.

Also add a `closedUB` parameter to the ValueBoundsOpInterface API.

Differential Revision: https://reviews.llvm.org/D146356
2023-04-11 10:32:34 +09:00
Matthias Springer
d8804ecd76 [mlir][Interfaces] Better error handling for addBound
Do not assert if a bound could not be added. This may or may not cause an error. We have the appropriate error handling in `computeBound` (which returns a `LogicalResult`).

Differential Revision: https://reviews.llvm.org/D147769
2023-04-11 10:09:52 +09:00
Kazu Hirata
af6ad7ac9a [mlir] Use DenseMap::contains (NFC) 2023-04-08 15:44:18 -07:00
Matthias Springer
c3f5fd76d6 [mlir][SCF] ValueBoundsOpInterface: Support scf.for results and iter_args
If an `scf.for` loop yields an equal index-typed value or a shaped value with the same dimension sizes (in comparison to the corresponding iter_arg), bounds can be computed for the iter_arg and the OpResult of the `scf.for` op.

Differential Revision: https://reviews.llvm.org/D146306
2023-04-07 11:57:44 +09:00
Matthias Springer
0dc9087ac7 [mlir][Interfaces] ValueBoundsOpInterface: Compute constant bounds
Add a helper function that computes a constant (`int64_t`) bound. The `stopCondition` is optional: If none is provided, the traversal continues until a constant bound could be computed.

Differential Revision: https://reviews.llvm.org/D146296
2023-04-07 11:35:02 +09:00
Matthias Springer
041bc485bf [mlir][Interfaces] ValueBoundsOpInterface: Support LB and UB bounds
This change also adds support for `affine.min` and `affine.max` ops.

Differential Revision: https://reviews.llvm.org/D145787
2023-04-07 10:48:19 +09:00
Matthias Springer
8c885658ed [mlir][Interfaces] Add ValueBoundsOpInterface
Ops can implement this interface to specify lower/upper bounds for their result values and block arguments. Bounds can be specified for:
* Index-type values
* Dimension sizes of shapes values

The bounds are added to a constraint set. Users can query this constraint set to compute bounds wrt. to a user-specified set of values. Only EQ bounds are supported at the moment.

This revision also contains interface implementations for various tensor dialect ops, which illustrates how to implement this interface.

Differential Revision: https://reviews.llvm.org/D145681
2023-04-06 02:57:14 +02:00