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

[naga wgsl-in] Allow global const declarations to have abstract types #7055

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from

Conversation

jamienicol
Copy link
Contributor

@jamienicol jamienicol commented Feb 4, 2025

Connections
Fixes #6232
Depends on #7035 as it builds upon testcases added there. But could be made independent if we choose not to land that for whatever reason. The first commit of the 4 in this PR is actually from there. If there's a better way to handle dependent PRs in github please let me know!

Description
Currently global const declarations are concretized when declared, meaning if you declared an abstract float or abstract int they will be given an effective value type of f32 or i32 respectively, and can only be subsequently used as those types. The spec, however, allows const declarations to have an abstract type, which then allows, for example, an abstract int const to later be used as either an f32 or an i32 (or both) depending on the context. These patches implement that behaviour by removing the call to concretize() when lowering a global const declaration, instead appending the Constant to the IR with its abstract type.

We must, however, ensure that abstract types do not end up in the final IR that will be validated or passed to the backends. We therefore ensure that the compact pass removes any constants of abstract types. Any other non-constant expressions in the IR which referenced that abstract constant will have had to have been concretized, meaning they no longer will reference the constant. Meaning this does not remove any expressions that were actually used. It does, however, remove some unused expressions, which does have some effect on our snapshot tests.

Testing
Inspected snapshot changes and ensured validation still passes. Checked that some webgpu:shader,validation,const_assert,const_assert:constant_expression_assert:* tests in the CTS now pass. (Some still fail in that group for other reasons.)

Added some additional tests in the final patch in series. For reviewability I kept them separate from the snapshot changes caused by the fix itself.

Checklist

  • Run cargo fmt.
  • Run cargo clippy. If applicable, add:
  • Run cargo xtask test to run tests.
  • Add change to CHANGELOG.md. See simple instructions inside file.

@jamienicol jamienicol changed the title Allow const declarations to have abstract types [naga wgsl-in] Allow const declarations to have abstract types Feb 4, 2025
@ErichDonGubler ErichDonGubler self-assigned this Feb 4, 2025
Comment on lines 46 to 49
let mut expr_ty = typifier.get(value, self.types);
while let crate::TypeInner::Array { base, .. } = *expr_ty {
expr_ty = &self.types[base].inner;
}
Copy link
Member

Choose a reason for hiding this comment

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

question: Here and in other places, we're recursing into types that can have abstract numeric components, and making sure those aren't abstract. This sounds correct. However, we're only checking for Arrays' components. Don't we also need to check for vector and matrix components?

Copy link
Member

Choose a reason for hiding this comment

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

Face-to-face discussion with @jamienicol: This is because the scalar() helper below handles the cases I'm thinking of, but not Array. A separate helper here sounds interesting.

ErichDonGubler
ErichDonGubler previously approved these changes Feb 4, 2025
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.

LGTM!

@ErichDonGubler ErichDonGubler added type: enhancement New feature or request naga Shader Translator area: naga front-end lang: WGSL WebGPU Shading Language type: bug Something isn't working area: ecosystem Help the connected projects grow and prosper area: correctness We're behaving incorrectly labels Feb 4, 2025
Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

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

I'd like to split out global constants and local constants into separate PRs. Also, I think we need to take a different approach for local constants.

Comment on lines 7 to 8
pub types: &'a crate::UniqueArena<crate::Type>,
pub resolve_context: crate::proc::ResolveContext<'a>,
Copy link
Member

@jimblandy jimblandy Feb 5, 2025

Choose a reason for hiding this comment

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

I don't think this is the right approach. We talked in person about how this works, and I see that it does accomplish the goal. But as much as possible, I would really like to keep the compactor a dumb structural algorithm: you give it this DAG-gy module thing, and it shakes out all the disconnected pieces without looking too hard at their semantics, and that's it. Running the typifier in compaction introduces subtleties that are not the direction that I would like to see things going.

Instead, as discussed, let's try having the WGSL front end simply not add abstract-typed constants to the function's named expressions table at all. The hope is that this would make compaction just remove them naturally, since constant evaluation should have left them all unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The avoid adding them to named expressions trick seemed to work. Patch is updated. It felt trivial enough just to keep it in the same PR

@cwfitzgerald cwfitzgerald dismissed ErichDonGubler’s stale review February 5, 2025 16:35

Code was indeed fine, some structural changes are needed per discussion with jimb

@jamienicol jamienicol force-pushed the abstract-consts branch 3 times, most recently from bbfb99c to 8563e3a Compare February 5, 2025 16:42
When lowering a return statement, call expression_for_abstract()
rather than expression() to avoid concretizing the return value. Then,
if the function has a return type, call try_automatic_conversions() to
attempt to convert our return value to the correct type.

This has the unfortunate side effect that some errors that would have
been caught by the validator are instead encountered as conversion
errors by the parser. This may result in a slightly less descriptive
error message in some cases. (See the change to the invalid_functions()
test, for example.)
…t expressions

It must call ConstantEvaluator::check_and_get() to possibly retrieve
the constant expression from a separate arena, like is currently done
when evaluating `As` expressions for non-array casts.
… abstract types

Instead allow the const to be converted and each time it is const
evaluated as part of another expression. This allows an abstract const
to be used as a different type depending on the context.

A consequence of this is that abstract types may now find their way in
to the IR, which we don't want. We therefore additionally now ensure
that the compact pass removes global constants of abstract types. This
will have no *functional* effect on shaders generated by the backends,
as the expressions belonging to the abstract consts in the IR will not
actually be used, as any usage in the input shader will have been
const-evaluated away. Certain unused const declarations will now be
removed, however, as can be seen by the effect on the snapshot
outputs.
@jamienicol
Copy link
Contributor Author

Updated this PR to only handle global const declarations per @jimblandy's request.

As a consequence, noticed an issue with the first patch in the series (the one to handle casting constant arrays.) The problem was that ConstantEvaluator.cast_array() did not properly handle Constant expressions by calling check_and_get(). My old patch fixed this from one callsight by making it eval a Expression::As instead (which does call check_and_get(). And making evaluating an Expression:As call cast_array instead of just cast.

However, by splitting out the local and global consts from eachother, I noticed we run in to the same problem from a different callsight - when concretizing a local const which is set to a global const. The concretize() call here also calls cast_array(). So I think the better solution is just to make cast_array() itself call check_and_get(). Additionally I noticed the comment for cast_array() specifically mentions that Expression::As does not handle arrays, so I think my previous patch was incorrect to make it do so.

@jamienicol jamienicol changed the title [naga wgsl-in] Allow const declarations to have abstract types [naga wgsl-in] Allow global const declarations to have abstract types Feb 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: correctness We're behaving incorrectly area: ecosystem Help the connected projects grow and prosper area: naga front-end lang: WGSL WebGPU Shading Language naga Shader Translator type: bug Something isn't working type: enhancement New feature or request
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

WGSL constant values should not be concretized
3 participants