Skip to content
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

[Vulkan] Rewrote PointerValueTypeRewrite transform #8528

Merged
merged 3 commits into from
Jul 30, 2021

Conversation

Lunderberg
Copy link
Contributor

In C-style codegen, pointer types can be freely cast between scalar and vectorized types (e.g. float16x4* <-> float16*). In SPIR-V, these are separate types, and no such casting is allowed. This was previously handled by having a special-case for Ramp(base, stride=1, lanes) in the codegen. That method didn't cover all possible cases, including Broadcast nodes used as indices.

PointerValueTypeRewrite previously re-wrote the AllocateNode and parameter pointer types, but didn't update the Load/Store node. This change tracks which variables can be updated to a vectorized type, and then updates all references to those. This includes removing the RampNode, as the vectorization is then included as part of the variable type.

The existing behavior of the StorageRewrite pass, which uses much of the same code, is maintained, to avoid breaking codegen that relies on it.

@Lunderberg
Copy link
Contributor Author

Potential reviewer: @masahi , @tqchen

* runtimes. Once all runtimes support vectorized buffer elements, these
* parameters can be removed.
*/
class VectorTypeRewriter : public StmtExprMutator {
Copy link
Member

Choose a reason for hiding this comment

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

I think I understand what this pass does, but I don't get the following point:

My understanding is that

  • For SPIR-V target, this pass should be run
  • For C-codegen targets, this should be nop

How these two conflicting requirements are satisfied?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, good point. Currently, the tir.transform.PointerValueTypeRewrite pass is only used in the SPIR-V codegen step, while the tir.transform.StorageRewrite pass is used as part of tvm.lower. These two passes both share the PointerValueTypeRewrite function. Currently, those two conflicting requirements are handled by having different arguments to PointerValueTypeRewrite for those two cases.

Unfortunately, for the C-codegen, it isn't quite a nop, as that would have been simpler to handle. Instead, the AllocateNode, any function parameters, and references to those variables get rewritten, but the StoreNode and LoadNode do not have their indices rewritten to account for the different variable type. I'm trying to determine the best way to handle that on the C codegens, but for now the previous behavior can be maintained with the boolean options to PointerValueTypeRewrite.

Copy link
Member

Choose a reason for hiding this comment

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

Oh I didn't know that PointerValueTypeRewrite is called from build_vulkan.cc !

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was surprised as well, as my mental model was that all changes to the TIR graph occur before being passed to the codegen. This extra call is fairly vulkan-specific, and from talking with @tqchen exists to adjust the pointer-type through which Vulkan accesses an array. For cuda, it's unnecessary because the pointer can be cast to the desired output type, but Vulkan doesn't allow those pointer casts. Instead, we need to choose one specific type for each pointer that is passed in, and stick with it through the entire PrimFunc.

My preference would be to pull it out into a target-aware optimization pass, which could be added into either tvm.lower or tvm.build. I've put together some comments over on discuss, and will tag you there as well.

In C-style codegen, pointer types can be freely cast between scalar
and vectorized types (e.g. `float16x4* <-> float16*`).  In SPIR-V,
these are separate types, and no such casting is allowed.  This was
previously handled by having a special-case for `Ramp(base, stride=1,
lanes)` in the codegen.  That method didn't cover all possible cases,
including Broadcast nodes used as indices.

PointerValueTypeRewrite previously re-wrote the AllocateNode and
parameter pointer types, but didn't update the Load/Store node.  This
change tracks which variables can be updated to a vectorized type, and
then updates all references to those.  This includes removing the
`RampNode`, as the vectorization is then included as part of the
variable type.
- Added explicit TODO(Lunderberg) for follow-ups

- Pass `checker.info_map_` instead of `checker` to
  `VectorTypeRewriter`
A single memory allocation may have more than one type of data stored
within it.  This allows the PointerTypeRewrite pass to recognize if a
function only uses the pointer as a particular base type.  This wasn't
an issue in C-based codegen, but is required for Vulkan.  Since Vulkan
shaders do not permit type-casting, the cast must be done when passing
the pointer argument into the shader.
@masahi
Copy link
Member

masahi commented Jul 30, 2021

cc @tqchen if you want to review

@masahi masahi merged commit c8a892b into apache:main Jul 30, 2021
@masahi
Copy link
Member

masahi commented Jul 30, 2021

Thanks @Lunderberg

@Lunderberg Lunderberg deleted the vulkan_loadnode branch August 3, 2021 14:27
ylc pushed a commit to ylc/tvm that referenced this pull request Sep 29, 2021
* [Vulkan] Rewrote PointerValueTypeRewrite transform

In C-style codegen, pointer types can be freely cast between scalar
and vectorized types (e.g. `float16x4* <-> float16*`).  In SPIR-V,
these are separate types, and no such casting is allowed.  This was
previously handled by having a special-case for `Ramp(base, stride=1,
lanes)` in the codegen.  That method didn't cover all possible cases,
including Broadcast nodes used as indices.

PointerValueTypeRewrite previously re-wrote the AllocateNode and
parameter pointer types, but didn't update the Load/Store node.  This
change tracks which variables can be updated to a vectorized type, and
then updates all references to those.  This includes removing the
`RampNode`, as the vectorization is then included as part of the
variable type.

* [StorageRewrite] Updates as recommended in review.

- Added explicit TODO(Lunderberg) for follow-ups

- Pass `checker.info_map_` instead of `checker` to
  `VectorTypeRewriter`

* [Vulkan] Allow for pointer rewrites that change base type.

A single memory allocation may have more than one type of data stored
within it.  This allows the PointerTypeRewrite pass to recognize if a
function only uses the pointer as a particular base type.  This wasn't
an issue in C-based codegen, but is required for Vulkan.  Since Vulkan
shaders do not permit type-casting, the cast must be done when passing
the pointer argument into the shader.

Co-authored-by: Eric Lunderberg <elunderberg@octoml.ai>
ylc pushed a commit to ylc/tvm that referenced this pull request Jan 13, 2022
* [Vulkan] Rewrote PointerValueTypeRewrite transform

In C-style codegen, pointer types can be freely cast between scalar
and vectorized types (e.g. `float16x4* <-> float16*`).  In SPIR-V,
these are separate types, and no such casting is allowed.  This was
previously handled by having a special-case for `Ramp(base, stride=1,
lanes)` in the codegen.  That method didn't cover all possible cases,
including Broadcast nodes used as indices.

PointerValueTypeRewrite previously re-wrote the AllocateNode and
parameter pointer types, but didn't update the Load/Store node.  This
change tracks which variables can be updated to a vectorized type, and
then updates all references to those.  This includes removing the
`RampNode`, as the vectorization is then included as part of the
variable type.

* [StorageRewrite] Updates as recommended in review.

- Added explicit TODO(Lunderberg) for follow-ups

- Pass `checker.info_map_` instead of `checker` to
  `VectorTypeRewriter`

* [Vulkan] Allow for pointer rewrites that change base type.

A single memory allocation may have more than one type of data stored
within it.  This allows the PointerTypeRewrite pass to recognize if a
function only uses the pointer as a particular base type.  This wasn't
an issue in C-based codegen, but is required for Vulkan.  Since Vulkan
shaders do not permit type-casting, the cast must be done when passing
the pointer argument into the shader.

Co-authored-by: Eric Lunderberg <elunderberg@octoml.ai>
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.

2 participants