Skip to content

Conversation

@Lunderberg
Copy link
Contributor

The goal of this PR is to allow IndexMap to express transformations that introduce padding in the transformed shape. For an arbitrary input shape, the new method IndexMap.non_surjective_inverse determines the inverse transformation, along with a predicate specifying which coordinates in the transformed index space do not contain an inverse in the original index space. The previous behavior of IndexMap.inverse, requiring transformations to be bijective over the range given, is maintained.

This functionality will be used in the future to allow buffer transformations (see #9727 and #10538) to introduce padding to the buffer.

Lunderberg added 8 commits May 6, 2022 14:59
This allows it to be used for any expression containing an
`IterMapExpr`, not just expressions whose top-level node is an
`IterMapExpr`.
The existing DetectIterMap tries to rewrite index expression as a
linear combination of split/fused iterators, where the new iterators
cover the exact same indices as the original expression.
DetectPaddedIterMap relaxes this condition, allowing the new iterators
to cover a superset of indices that the initial index expression
covered.  It uses the minimum amount of padding necessary to represent
these transformations, and also a predicate that identifies any
padding that has been added.

This is a utility function to be used for layout transformations of
buffers, in cases where the pre-transformation shape of the buffer
does not evenly fit into the post-transformation shape.
Allow non-surjective transformations, with DetectIterMap used to
determine the minimum padding to insert.  Returns the inverse
function, along with a predicate that identifies padding indices.  The
predicate is in terms of the transformed variables.
- `IndexMap::Inverse` exposed as `IndexMap.inverse`
- `IndexMap::MapShape` exposed as `IndexMap.map_shape`
- `IndexMap::NonSurjectiveInverse` exposed as `IndexMap.non_surjective_inverse`
In preparation for adding additional tests for the IndexMap class,
which will require this functionality.
Initially disabled as dynamic shapes resulted in padded lengths whose
divisiblity couldn't be proven.  Re-enabled along with a
simplification rule to resolve it.
@Lunderberg Lunderberg requested a review from vinx13 May 6, 2022 21:12
@Lunderberg
Copy link
Contributor Author

Also, name suggestions for "non-surjective inverse" would be appreciated. It's something of a mouthful, and describes what it is doing without describing why it would be desired.

@vinx13
Copy link
Member

vinx13 commented May 10, 2022

Thanks for the PR, I like this change. There is a failing test case test_reverse_compute_at_floordiv_and_floormod_indices seems relevant, probably some affine analysis is broken

@vinx13 vinx13 requested a review from spectrometerHBH May 10, 2022 00:10
@Lunderberg
Copy link
Contributor Author

Lunderberg commented May 10, 2022

Thanks for the PR, I like this change.

Thank you, and I'm liking it as well. This sort of utility should be useful regardless on the buffer padding semantics used.

There is a failing test case test_reverse_compute_at_floordiv_and_floormod_indices seems relevant, probably some affine analysis is broken

Yeah, so far I've narrowed it down to the handling of cases like (iter + 16*var)//16. This doesn't introduce padding, but the nonzero offset would make it fail DetectIterMap in this check. This boils up to the call to AnalyzerRegionUpperBound, resulting in incorrect results.

@wrongtest-intellif
Copy link
Contributor

(iter + 16*var)//16

Hi~ Does it mean pass index like (dom_irrelavant_base + i) // 16 can not pass DetectIterMap? I encounter a similar issue in a different domain, where I try to use compute_at schedule to make tiles on computation block with floormod/floordiv indices.

@Lunderberg
Copy link
Contributor Author

(iter + 16*var)//16

Hi~ Does it mean pass index like (dom_irrelavant_base + i) // 16 can not pass DetectIterMap? I encounter a similar issue in a different domain, where I try to use compute_at schedule to make tiles on computation block with floormod/floordiv indices.

Prior to this PR, that is correct. The check on the main branch is here, which requires the offset in a numerator to be zero. After this PR, an index like (dom_irrelevant_base + i)//16 could be passed if either (a) dom_irrelevant_base can be proven to be a multiple of 16, or (b) you call DetectPaddedIterMap, which may introduce padding such that (left_pad + dom_irrelevant_base) % 16 == 0 and that (left_pad + dom_irrelevant_base + i.extent + right_pad) % 16 == 0.

@vinx13 vinx13 merged commit 0e8107b into apache:main May 13, 2022
@Lunderberg Lunderberg deleted the padded_index_mapping branch May 13, 2022 19:54
mehrdadh pushed a commit to mehrdadh/tvm that referenced this pull request May 16, 2022
* [Debug] Error logging in DetectIterMap

* [Affine] Allowed PrimExpr argument to NormalizeIterMapToExpr

This allows it to be used for any expression containing an
`IterMapExpr`, not just expressions whose top-level node is an
`IterMapExpr`.

* [Affine] Implemented DetectPaddedIterMap

The existing DetectIterMap tries to rewrite index expression as a
linear combination of split/fused iterators, where the new iterators
cover the exact same indices as the original expression.
DetectPaddedIterMap relaxes this condition, allowing the new iterators
to cover a superset of indices that the initial index expression
covered.  It uses the minimum amount of padding necessary to represent
these transformations, and also a predicate that identifies any
padding that has been added.

This is a utility function to be used for layout transformations of
buffers, in cases where the pre-transformation shape of the buffer
does not evenly fit into the post-transformation shape.

* [IndexMap] Implemented IndexMap::NonSurjectiveInverse

Allow non-surjective transformations, with DetectIterMap used to
determine the minimum padding to insert.  Returns the inverse
function, along with a predicate that identifies padding indices.  The
predicate is in terms of the transformed variables.

* [IndexMap] Exposed methods to python

- `IndexMap::Inverse` exposed as `IndexMap.inverse`
- `IndexMap::MapShape` exposed as `IndexMap.map_shape`
- `IndexMap::NonSurjectiveInverse` exposed as `IndexMap.non_surjective_inverse`

* [IndexMap] Extracted _assert_equal_index_map into class method

In preparation for adding additional tests for the IndexMap class,
which will require this functionality.

* [IndexMap] Added unit tests for new behavior

* Re-enabled divisibility check in CheckMapping

Initially disabled as dynamic shapes resulted in padded lengths whose
divisiblity couldn't be proven.  Re-enabled along with a
simplification rule to resolve it.

* Fixed breakage in compute_at primitive

* Corrected typos/examples in docstring
shtinsa pushed a commit to Deelvin/tvm that referenced this pull request May 17, 2022
* [Debug] Error logging in DetectIterMap

* [Affine] Allowed PrimExpr argument to NormalizeIterMapToExpr

This allows it to be used for any expression containing an
`IterMapExpr`, not just expressions whose top-level node is an
`IterMapExpr`.

* [Affine] Implemented DetectPaddedIterMap

The existing DetectIterMap tries to rewrite index expression as a
linear combination of split/fused iterators, where the new iterators
cover the exact same indices as the original expression.
DetectPaddedIterMap relaxes this condition, allowing the new iterators
to cover a superset of indices that the initial index expression
covered.  It uses the minimum amount of padding necessary to represent
these transformations, and also a predicate that identifies any
padding that has been added.

This is a utility function to be used for layout transformations of
buffers, in cases where the pre-transformation shape of the buffer
does not evenly fit into the post-transformation shape.

* [IndexMap] Implemented IndexMap::NonSurjectiveInverse

Allow non-surjective transformations, with DetectIterMap used to
determine the minimum padding to insert.  Returns the inverse
function, along with a predicate that identifies padding indices.  The
predicate is in terms of the transformed variables.

* [IndexMap] Exposed methods to python

- `IndexMap::Inverse` exposed as `IndexMap.inverse`
- `IndexMap::MapShape` exposed as `IndexMap.map_shape`
- `IndexMap::NonSurjectiveInverse` exposed as `IndexMap.non_surjective_inverse`

* [IndexMap] Extracted _assert_equal_index_map into class method

In preparation for adding additional tests for the IndexMap class,
which will require this functionality.

* [IndexMap] Added unit tests for new behavior

* Re-enabled divisibility check in CheckMapping

Initially disabled as dynamic shapes resulted in padded lengths whose
divisiblity couldn't be proven.  Re-enabled along with a
simplification rule to resolve it.

* Fixed breakage in compute_at primitive

* Corrected typos/examples in docstring
shingjan pushed a commit to shingjan/tvm that referenced this pull request May 17, 2022
* [Debug] Error logging in DetectIterMap

* [Affine] Allowed PrimExpr argument to NormalizeIterMapToExpr

This allows it to be used for any expression containing an
`IterMapExpr`, not just expressions whose top-level node is an
`IterMapExpr`.

* [Affine] Implemented DetectPaddedIterMap

The existing DetectIterMap tries to rewrite index expression as a
linear combination of split/fused iterators, where the new iterators
cover the exact same indices as the original expression.
DetectPaddedIterMap relaxes this condition, allowing the new iterators
to cover a superset of indices that the initial index expression
covered.  It uses the minimum amount of padding necessary to represent
these transformations, and also a predicate that identifies any
padding that has been added.

This is a utility function to be used for layout transformations of
buffers, in cases where the pre-transformation shape of the buffer
does not evenly fit into the post-transformation shape.

* [IndexMap] Implemented IndexMap::NonSurjectiveInverse

Allow non-surjective transformations, with DetectIterMap used to
determine the minimum padding to insert.  Returns the inverse
function, along with a predicate that identifies padding indices.  The
predicate is in terms of the transformed variables.

* [IndexMap] Exposed methods to python

- `IndexMap::Inverse` exposed as `IndexMap.inverse`
- `IndexMap::MapShape` exposed as `IndexMap.map_shape`
- `IndexMap::NonSurjectiveInverse` exposed as `IndexMap.non_surjective_inverse`

* [IndexMap] Extracted _assert_equal_index_map into class method

In preparation for adding additional tests for the IndexMap class,
which will require this functionality.

* [IndexMap] Added unit tests for new behavior

* Re-enabled divisibility check in CheckMapping

Initially disabled as dynamic shapes resulted in padded lengths whose
divisiblity couldn't be proven.  Re-enabled along with a
simplification rule to resolve it.

* Fixed breakage in compute_at primitive

* Corrected typos/examples in docstring
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request May 23, 2022
Follow-up from apache#11235, all error
messages should be based on expressions that are not IterMapExpr.
junrushao pushed a commit that referenced this pull request May 23, 2022
Follow-up from #11235, all error
messages should be based on expressions that are not IterMapExpr.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants