[naga spv-out] Ensure loops generated by SPIRV backend are bounded#7080
Merged
teoxoy merged 1 commit intogfx-rs:trunkfrom Feb 25, 2025
Merged
[naga spv-out] Ensure loops generated by SPIRV backend are bounded#7080teoxoy merged 1 commit intogfx-rs:trunkfrom
teoxoy merged 1 commit intogfx-rs:trunkfrom
Conversation
6d5a471 to
e7e914a
Compare
JMS55
reviewed
Feb 8, 2025
ee4b7ea to
ea7babd
Compare
jimblandy
previously requested changes
Feb 12, 2025
Member
jimblandy
left a comment
There was a problem hiding this comment.
We think there might be a nicer way to generate the temporary variables as we go, rather than making a separate pass over them beforehand.
ea7babd to
d2c4df7
Compare
Contributor
Author
Indeed, the pass to generate a Function's Patch updated |
d2c4df7 to
1ee50df
Compare
Member
|
@jamienicol looks like there are some conflicts now |
If it is undefined behaviour for loops to be infinite, then, when encountering an infinite loop, downstream compilers are able to make certain optimizations that may be unsafe. For example, omitting bounds checks. To prevent this, we must ensure that any loops emitted by our backends are provably bounded. We already do this for both the MSL and HLSL backends. This patch makes us do so for SPIRV as well. The construct used is the same as for HLSL and MSL backends: use a vec2<u32> to emulate a 64-bit counter, which is incremented every iteration and breaks after 2^64 iterations. While the implementation is fairly verbose for the SPIRV backend, the logic is simple enough. The one point of note is that SPIRV requires `OpVariable` instructions with a `Function` storage class to be located at the start of the first block of the function. We therefore remember the IDs generated for each loop counter variable in a function whilst generating the function body's code. The instructions to declare these variables are then emitted in `Function::to_words()` prior to emitting the function's body. As this may negatively impact shader performance, this workaround can be disabled using the same mechanism as for other backends: eg calling Device::create_shader_module_trusted() and setting the ShaderRuntimeChecks::force_loop_bounding flag to false.
1ee50df to
67c18e8
Compare
sharmajai
pushed a commit
to sharmajai/wgpu
that referenced
this pull request
Oct 12, 2025
…fx-rs#7080) If it is undefined behaviour for loops to be infinite, then, when encountering an infinite loop, downstream compilers are able to make certain optimizations that may be unsafe. For example, omitting bounds checks. To prevent this, we must ensure that any loops emitted by our backends are provably bounded. We already do this for both the MSL and HLSL backends. This patch makes us do so for SPIRV as well. The construct used is the same as for HLSL and MSL backends: use a vec2<u32> to emulate a 64-bit counter, which is incremented every iteration and breaks after 2^64 iterations. While the implementation is fairly verbose for the SPIRV backend, the logic is simple enough. The one point of note is that SPIRV requires `OpVariable` instructions with a `Function` storage class to be located at the start of the first block of the function. We therefore remember the IDs generated for each loop counter variable in a function whilst generating the function body's code. The instructions to declare these variables are then emitted in `Function::to_words()` prior to emitting the function's body. As this may negatively impact shader performance, this workaround can be disabled using the same mechanism as for other backends: eg calling Device::create_shader_module_trusted() and setting the ShaderRuntimeChecks::force_loop_bounding flag to false.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Connections
Partial fix for #6572 (can tick SPIR-V off, still GLSL to go)
Related to #6929: that updated the previous MSL workaround to use the 64bit counter approach, and added the workaround for HLSL
Description
If it is undefined behaviour for loops to be infinite, then, when encountering an infinite loop, downstream compilers are able to make certain optimizations that may be unsafe. For example, omitting bounds checks. To prevent this, we must ensure that any loops emitted by our backends are provably bounded. We already do this for both the MSL and HLSL backends. This patch makes us do so for SPIRV as well.
The construct used is the same as for HLSL and MSL backends: use a vec2 to emulate a 64-bit counter, which is incremented every iteration and breaks after 2^64 iterations.
While the implementation is fairly verbose for the SPIRV backend, the logic is simple enough. The one point of note is that SPIRV requires
OpVariableinstructions with aFunctionstorage class to be located at the start of the first block of the function. We must therefore do an initial pass over the function to generate the IDs used for the loop counter variables, and ensure the correspondingOpVariableinstructions are emitted at the start of the function. Then finally during the main code-generation pass we can refer to these IDs.As this may negatively impact performance, this workaround can be disabled using the same mechanism as for other backends: eg calling Device::create_shader_module_trusted() and setting the ShaderRuntimeChecks::force_loop_bounding flag to false.
Testing
Inspected snapshot test changes. Ensured validation still passes
Checklist
cargo fmt.cargo clippy. If applicable, add:cargo xtask testto run tests.CHANGELOG.md. See simple instructions inside file. (also added the HLSL fix from [naga msl-out hlsl-out] Improve workaround for infinite loops causing undefined behaviour #6929)