Narrow blanket SPIR-V legalization work in optimizer recipes#6612
Open
AnastaZIuk wants to merge 9 commits intoKhronosGroup:mainfrom
Open
Narrow blanket SPIR-V legalization work in optimizer recipes#6612AnastaZIuk wants to merge 9 commits intoKhronosGroup:mainfrom
AnastaZIuk wants to merge 9 commits intoKhronosGroup:mainfrom
Conversation
s-perron
reviewed
Mar 26, 2026
Collaborator
s-perron
left a comment
There was a problem hiding this comment.
I have responded on the corresponding DXC pr: microsoft/DirectXShaderCompiler#8283 (review).
Comment on lines
133
to
134
| // Make sure uses and definitions are in the same function. | ||
| .RegisterPass(CreateInlineExhaustivePass()) |
There was a problem hiding this comment.
whats the purpose here?
Collaborator
There was a problem hiding this comment.
Inline enables many other optimizations. We do not implement inter-procedural-optimizations. If you are going to copy-propagate something written to in one function, and used in another function, the have to be inlined.
There was a problem hiding this comment.
oh I just hacked a NBL_REF_ARG via expanding vk::ext_reference on regular function inout parameters, so we have less copies, but yes makes sense.
The O1experimental fast performance path can leave explicit VariablePointers / VariablePointersStorageBuffer declarations in the final module even after the final IR no longer contains the pointer forms that require them. In our EX37 sampler workload the resulting SPIR-V remained legal and the failing shader contained only scalar OpSelect %float instructions, with no pointer OpSelect or pointer OpPhi. Removing only the stale capability lines fixed the downstream runtime corruption. Keep the shared TrimCapabilitiesPass and the default optimizer paths untouched by adding a dedicated TrimVariablePointersCapabilitiesPass and invoking it only at the end of the fast performance recipe. Preserve real Workgroup and StorageBuffer variable-pointer cases with focused tests.
VariablePointers is needed when the final module still uses pointer values as first-class SSA objects. A plain OpStore stores through a pointer. It does not by itself prove that the module still needs VariablePointers. The SPIR-V OpStore definition distinguishes the pointer to store through from the object being stored. The variable pointer rules separately constrain cases where a pointer is the Object operand of OpStore or the result of OpLoad. An ordinary StorageBuffer store of a non-pointer object should therefore not keep VariablePointers alive on its own. Stop treating every OpStore as a capability requirement and add a regression test for a normal StorageBuffer store that should trim the stale capability. Spec references: https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpStore https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#VariablePointers
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.
Summary
-O1experimentalprofileOpImageTexelPointerimage operands inLocalSingleStoreElimAliasedPointerandRestrictPointeronly on legal replacement memory object declarations after scalar replacementOpCopyObjectso the late cleanup can remove copied dead pointer chains as wellVariablePointers/VariablePointersStorageBufferdeclarations only in the-O1experimentalfast path, without changing the default trim pathWhy each change is needed
This branch is the optimizer side of the opt-in
-O1experimentalprofile.The goal is not to change the default optimizer behavior. The goal is to keep the default entry points intact and move the more aggressive recipe into explicit fast compile entry points.
That split needs three kinds of changes:
A separate fast recipe.
The generic default recipes should stay unchanged. The fast profile therefore gets its own performance and legalization entry points.
Explicit control over the transforms that materially change IR shape.
Legalization-time full loop unroll and legalization-time SSA rewrite are no longer implicit blanket work in the generic path. They are explicit parts of the fast path and are driven by narrow producer-side signals from the companion DXC branch.
Minimal legality cleanup for the IR shapes that the fast path can expose.
The fast path keeps the recipe win and the explicit unroll behavior, but it also needs a few narrow legality-oriented cleanups:
LocalSingleStoreElimcan otherwise rewrite through copied image values and leaveOpImageTexelPointerwith a non-pointer image operand.AliasedPointerorRestrictPointerfrom a struct member onto replacements that are not legal memory object declarations for those decorations.VariablePointers/VariablePointersStorageBufferdeclarations in the final module even after the final IR no longer contains the pointer forms that require them. A dedicated follow-up pass trims only those stale declarations and stays off the shared default trim path.These are the only extra legality cleanups kept here. The branch does not restore the old blanket generic cleanup.
Spec basis
Loop control is only a hint in core SPIR-V:
Spec:
Khronos guidance for offline transforms is aligned with that:
Whitepaper:
The image-operand rule for
OpImageTexelPointeris explicit:Spec:
The aliasing decorations are also explicit:
Spec:
And the aliasing section narrows that further for physical-storage-buffer pointers:
Spec:
The late dead-local cleanup is justified by the logical-pointer rules:
Spec:
Validation
CodeGenSPIRVvalidation on the companion DXC /SPIRV-Toolsbranch state passed with1438expected passes,2expected failures, and0unexpected failuresPhysicalStorageBufferpointer wrappers in a downstream consumer tree, including https://github.com/Devsh-Graphics-Programming/Nabla-Examples-and-TestsCompanion DXC PR: