Repository navigation
Core: include() emits a kernel's WGSL helpers and their dependencies once; workgroupBytes() - #84
Merged
Merged
Conversation
…ndencies once; workgroupBytes() A kernel listed its WGSL helpers and everything they need by hand (enableSubgroupsIfAppropriate first, commonDefinitions, subgroupEmulation, binop.wgslfn, subgroupInclusiveOpScan, wgScan, ...): HierarchicalScan and both MultisplitPerm modules repeated the same six lines, DLDFScan twelve, and OneSweep spread its list through the module. Leaving one out failed to compile; listing one twice failed too. - wgslFunctions.include(...helpers) emits each helper and its dependencies (DEPENDENCIES) once, enable first; [name, args] for helpers with arguments. A dependency is satisfied by any inclusion of that helper; a helper listed explicitly is emitted once per distinct argument set. Inline (statement) helpers add only what they need at module scope. - workgroupBytes(...helpers) is the workgroup memory those helpers declare (WORKGROUP_BYTES), per subgroup or emulated variant. - The no-subgroup wgScan (a Hillis-Steele scan in workgroup memory) no longer pulls in subgroup emulation, which it never used. - All primitives use include(). MultisplitPerm's local finish computes its reserved workgroup memory (localFinishReservedBytes: its own arrays plus workgroupBytes) instead of a hand-counted 3,328 bytes; Histogram's workgroupBins uses workgroupBytes. - Kernels compared with the previous commit, with and without subgroups (61 kernels each): unchanged except that Histogram's module now starts with `enable subgroups;` and emulated HierarchicalScan and MultisplitPerm modules no longer carry the unused emulation code. All 122 compile. - Regression test for include() (dedup, exclusive and inclusive wgScan, a helper listed after arriving as a dependency, enable first, compiles, workgroupBytes). Types for fnDeclarations; docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015kfNC6id65zEHzuAAH4jtJ
This was referenced Oct 24, 2026
…ulated CI step) In Node, the emulated CI step (DISABLE_SUBGROUPS) hides subgroups from the device; regression.mjs's useEmu is only the browser's URL switch and stays false. The test expected the subgroup variant (enable first, 256-byte scans) from a primitive that was emulated. It now asks the primitive (!scan.useSubgroups). Checked on a device with and without subgroups: the old test fails without them (as in CI run 40106488874), the new one passes both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015kfNC6id65zEHzuAAH4jtJ
jowens
pushed a commit
that referenced
this pull request
Oct 27, 2026
Conflict in docs/architecture.md: both sides added a section before "Composing primitives". Kept both: "WGSL helpers" (#84), then "Actions, and when they take effect" (this PR). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015kfNC6id65zEHzuAAH4jtJ
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.
This is the next step in moving per-primitive boilerplate into core: WGSL helpers that bring their own dependencies.
Problem
Each kernel listed its WGSL helpers, and everything they need, by hand, in an order that compiles:
enableSubgroupsIfAppropriatefirst, thencommonDefinitions,subgroupEmulation,binop.wgslfn,subgroupInclusiveOpScan,wgScan, and so on;Workgroup memory was counted by hand too. MultisplitPerm's local finish subtracted a magic 3,328 bytes.
Change
fnDeclarations.include(...helpers):enablefirst;[name, args]for helpers with arguments;A dependency is satisfied by any inclusion of that helper, whatever its arguments. A helper listed explicitly is emitted once per distinct set of arguments, so exclusive and inclusive
wgScancan coexist.fnDeclarations.workgroupBytes(...helpers): the workgroup memory those helpers declare, for the subgroup or emulated variant.All five primitives use
include():localFinishReservedBytes: its own arrays plusworkgroupBytes) instead of using 3,328 bytes;workgroupBinsusesworkgroupBytes.The no-subgroup
wgScan, a Hillis–Steele scan in workgroup memory, no longer pulls in subgroup emulation, which it never used.Checked
Kernels compared with DLDFScan and OneSweep declare their buffers once; UniformStruct slots #83's, with and without subgroups (61 kernels each). They're unchanged except for two intended differences:
enable subgroups;;All 122 compile.
New regression test for
include(). It covers:binopor builtins;wgScantogether;enablefirst;workgroupBytes.Simulated RDNA4: 84 of 84 tests pass. Lavapipe: everything passes except the existing 8-lane sort failures. The package test passes.
Note on
localFinishCapThe computed reserve is smaller than 3,328 (2,316 bytes with subgroups, 3,084 without). The cap can therefore only grow, and only when the device's workgroup memory is what limits it, which none of the defaults hit.
localFinishCapkeeps 3,328 as its default for callers that don't pass a reserve.Generated by Claude Code