Skip to content

[mlir][Affine] Generalize the linearize(delinearize()) simplifications #117637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,9 @@ def AffineDelinearizeIndexOp : Affine_Op<"delinearize_index", [Pure]> {
%indices_2 = affine.apply #map2()[%linear_index]
```

In other words, `%0:3 = affine.delinearize_index %x into (B, C)` produces
`%0 = {%x / (B * C), (%x mod (B * C)) / C, %x mod C}`.

The basis may either contain `N` or `N-1` elements, where `N` is the number of results.
If there are N basis elements, the first one will not be used during computations,
but may be used during analysis and canonicalization to eliminate terms from
Expand All @@ -1098,7 +1101,12 @@ def AffineDelinearizeIndexOp : Affine_Op<"delinearize_index", [Pure]> {
%0:3 = affine.delinearize_index %linear_index into (244, 244) : index, index
```

Note that, due to the constraints of affine maps, all the basis elements must
Note that, for symmetry with `getPaddedBasis()`, if `hasOuterBound` is `true`
when one of the `OpFoldResult` builders is called but the first element of the
basis is `nullptr`, that first element is ignored and the builder proceeds as if
there was no outer bound.

Due to the constraints of affine maps, all the basis elements must
be strictly positive. A dynamic basis element being 0 or negative causes
undefined behavior.
}];
Expand Down Expand Up @@ -1136,6 +1144,11 @@ def AffineDelinearizeIndexOp : Affine_Op<"delinearize_index", [Pure]> {
/// Return a vector that contains the basis of the operation, removing
/// the outer bound if one is present.
SmallVector<OpFoldResult> getEffectiveBasis();

/// Return the vector with one basis element per result of the operation. If
/// there is no outer bound specified, the leading entry of this result will be
/// nullptr.
SmallVector<OpFoldResult> getPaddedBasis();
}];

let hasVerifier = 1;
Expand All @@ -1160,6 +1173,9 @@ def AffineLinearizeIndexOp : Affine_Op<"linearize_index",
sum(i = 0 to N-1) %idx_i * product(j = i + 1 to N-1) B_j
```

In other words, `%0 = affine.linearize_index [%z, %y, %x] by (Z, Y, X)`
gives `%0 = %x + %y * X + %z * X * Y`, or `%0 = %x + X * (%y + Y * (%z))`.

The basis may either have `N` or `N-1` elements, where `N` is the number of
inputs to linearize_index. If `N` inputs are provided, the first one is not used
in computation, but may be used during analysis or canonicalization as a bound
Expand All @@ -1168,6 +1184,10 @@ def AffineLinearizeIndexOp : Affine_Op<"linearize_index",
If all `N` basis elements are provided, the linearize_index operation is said to
"have an outer bound".

As a convenience, and for symmetry with `getPaddedBasis()`, ifg the first
element of a set of `OpFoldResult`s passed to the builders of this operation is
`nullptr`, that element is ignored.

If the `disjoint` property is present, this is an optimization hint that,
for all `i`, `0 <= %idx_i < B_i` - that is, no index affects any other index,
except that `%idx_0` may be negative to make the index as a whole negative.
Expand Down Expand Up @@ -1224,6 +1244,11 @@ def AffineLinearizeIndexOp : Affine_Op<"linearize_index",
/// Return a vector that contains the basis of the operation, removing
/// the outer bound if one is present.
SmallVector<OpFoldResult> getEffectiveBasis();

/// Return the vector with one basis element per index operand of the operation.
/// If there is no outer bound specified, the leading entry of this basis will be
/// nullptr.
SmallVector<OpFoldResult> getPaddedBasis();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would getPaddedMixedBasis() make more sense for the name here ?
And accordingly we can make the doc comment simpler : "Same as getMixedBasis, but the leading entry will include a nullptr if no outer bound is specified" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might, and ... yeah, I'm not strongly attached to the name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But also it's a bit wordier - let me know if you have strong thoughts here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, no worries - but I'd still prefer making the doc comment simpler : Same as getMixedBasis, but the leading entry will include a nullptr if no outer bound is specified.

}];

let hasVerifier = 1;
Expand Down
Loading
Loading