Skip to content

[msl-out] Fix ReadZeroSkipWrite bounds check mode for pointer arguments #7323

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 7 commits into from
Apr 9, 2025

Conversation

andyleiserson
Copy link
Contributor

Connections
Fixes #4541

Description
See the description of #4541 for more detail and sample code, but in short, the ReadZeroSkipWrite bounds check policy didn't previously work when the result of the indexing operation was itself a pointer that then gets passed to a function. With this change, a dummy local variable is created for each type that may appear in this manner. If a bounds check fails, the address of the dummy variable is substituted as the argument value for the called function.

This change is based on gfx-rs/naga#2451.

Testing
Added snapshot tests for the test case from the issue and a variety of other cases. I also ran the output from naga through the metal compiler to verify it is now accepted.

Checklist

  • Run cargo fmt.
  • Run taplo format.
  • Run cargo clippy. If applicable, add:
    • --target wasm32-unknown-unknown
  • Run cargo xtask test to run tests.
  • If this contains user-facing changes, add a CHANGELOG.md entry.

@ErichDonGubler ErichDonGubler self-assigned this Mar 12, 2025
@andyleiserson
Copy link
Contributor Author

After spending more time with the spec, I think we'd be justified in disallowing this case (pointer to array element) just like pointer to matrix or vector component, at least until we want to claim support for unrestricted_pointer_parameters.

@ErichDonGubler
Copy link
Member

Two things have been complicating my ability to get to this review:

  1. Some protracted time during which I haven't felt like I could prioritize this against my other work. Despite this, I think this should have been reviewed much earlier, and I apologize for this; reviews from maintainers deserve a much faster turnaround than what I've done here (3 weeks!? 😱).

  2. Actually understanding the different changes in this PR's single commit. It took me a few hours to peel apart the commit into multiple ones that can stand on their own, and I'm feeling confident enough that the changes are distinct enough for me to review meaningfully.

    I also pushed some fixup!s that came up in my review; I'll refer to the commits in my feedback that's soon to follow today.

Copy link
Member

@ErichDonGubler ErichDonGubler left a comment

Choose a reason for hiding this comment

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

This mostly LGTM, with some minor issues.


I used Conventional Comments in this review! I hope they help with clarity and tone. 🙂

Comment on lines 707 to 727
Item = (
Handle<crate::Expression>,
index::GuardedIndex,
index::IndexableLength,
),
Copy link
Member

Choose a reason for hiding this comment

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

thought: This return type is complicated enough that some follow-up at some point to refactor to a named struct might be nice.

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 went ahead and did this, not hard and it's new (or at least newly more complicated) code.

let result_ty_handle = match result_ty {
Some(TypeResolution::Handle(handle)) => handle,
Some(TypeResolution::Value(_)) => {
// I don't have a succinct argument why this is the case.
Copy link
Member

@ErichDonGubler ErichDonGubler Apr 3, 2025

Choose a reason for hiding this comment

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

nitpick: This is a collective artifact, so writing commentary in first person without a note of authorship is, at best, detail without context. Let's either get your name in here, or re-write this to simply acknowledge that this might not be correct (independent of trying to make this correct, which I'll address in a separate comment) and that we can collectively revise as needed.

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 reworded the comment, although I'm also curious what your thoughts were on "trying to make this correct" -- I don't see another comment about it. I was hoping for some scrutiny on this from reviewers, so thank you for that.

@@ -611,6 +611,13 @@ trait NameKeyExt {
FunctionOrigin::EntryPoint(idx) => NameKey::EntryPointLocal(idx, local_handle),
}
}

fn oob_local(origin: FunctionOrigin, ty: Handle<crate::Type>) -> NameKey {
Copy link
Member

Choose a reason for hiding this comment

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

question: It's rather confusing to only use the noun local when there are types at play here rather than just local variables.

suggestion: Let's rename to something like s/local/local_type.

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 see how it is confusing, but I'm not sure that oob_local_type is better since the thing we're naming really is a local, not a type (it's just that there is one per type, and we name it based on the type it's for).

I added a bit more documentation that may help clarify this. If you still think the names are confusing, maybe s/oob_locals/oob_local_types and s/oob_local/oob_local_for_type?

Copy link
Member

Choose a reason for hiding this comment

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

oob_local_for_type seems like a good option to me!

@ErichDonGubler ErichDonGubler added backend: metal Issues with Metal area: naga back-end Outputs of naga shader conversion naga Shader Translator lang: Metal Metal Shading Language labels Apr 3, 2025
@ErichDonGubler ErichDonGubler moved this from Todo to In Progress in WebGPU for Firefox Apr 3, 2025
@ErichDonGubler
Copy link
Member

Rebased snapshots onto recent changes merged into trunk from #7414.

## Pointer-typed bounds-checked expressions and OOB locals

MSL (unlike HLSL and GLSL) has native support for pointer-typed function
arguments. When the [`BoundsCheckPolicy`] is `ReadZeroSkipWrite` and an
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: It'd be nice to doc-link ReadZeroSkipWrite here, but I see that some existing commentary has also not linked it.

@andyleiserson
Copy link
Contributor Author

Github seems not to be triggering the CI jobs any more. I am going to try closing and reopening.

@github-project-automation github-project-automation bot moved this from In Progress to Done in WebGPU for Firefox Apr 9, 2025
@andyleiserson andyleiserson reopened this Apr 9, 2025
@github-project-automation github-project-automation bot moved this from Done to In Progress in WebGPU for Firefox Apr 9, 2025
@ErichDonGubler ErichDonGubler enabled auto-merge (rebase) April 9, 2025 22:36
@ErichDonGubler ErichDonGubler merged commit a0dbe5e into gfx-rs:trunk Apr 9, 2025
37 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in WebGPU for Firefox Apr 9, 2025
@andyleiserson andyleiserson deleted the bounds-check branch April 10, 2025 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: naga back-end Outputs of naga shader conversion backend: metal Issues with Metal lang: Metal Metal Shading Language naga Shader Translator
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[msl-out] BoundsCheckPolicy::ReadZeroSkipWrite produces invalid Metal when calling functions with pointers to array elements
2 participants