fix(msl): reject unsupported 64-bit atomics#82
Conversation
kolkov
left a comment
There was a problem hiding this comment.
Code Review: fix(msl): reject unsupported 64-bit atomics
Verdict: APPROVE — high-quality contribution that brings our MSL backend in line with Rust naga's capability boundary.
Rust naga parity — verified
Checked against Rust naga source (back/msl/writer.rs:3849-3863, valid/function.rs:453-496, valid/mod.rs:164-166):
-
Capability model matches. Rust naga defines
SHADER_INT64_ATOMIC_MIN_MAX(1 << 20, min/max only, storage only, result discarded) andSHADER_INT64_ATOMIC_ALL_OPS(1 << 21, everything). The MSL backend explicitly documents it does NOT supportALL_OPS(back/msl/mod.rs:4). This PR enforces the same boundary. -
Three-part rule matches. Rust validator (
valid/function.rs:470-474) checks: (1)matches!(*fun, Min | Max), (2)matches!(pointer_space, Storage { .. }), (3)result.is_none(). ThevalidateAtomicOperationmethod applies the identical three checks: scalarWidth == 8,AtomicMin/AtomicMaxwithresult == nil,space == ir.SpaceStorage. -
TOML configs match. Both
atomicOps-int64.tomlandatomicCompareExchange-int64.tomlin Rust reference havetargets = "SPIRV | HLSL | WGSL"— METAL explicitly excluded. Golden deletion is correct. -
Writer approach differs safely. Rust puts the check in the validator; the MSL writer assumes validation passed (
writer.rs:3849-3852: "we can assume that ifresultisSome, we are not operating on a 64-bit value"). This PR puts the check directly in the MSL writer — defense-in-depth approach, correct for Go naga which doesn't yet have a separate capability-gated validator. Good call on addingvalidateAtomicOperationtowriteUncheckedLoad/writeUncheckedStoreas well — Rust relies on its upstream validator for those paths.
What's done well
-
Stale golden cleanup — removed 380 lines of MSL output (180 + 200) that should never have existed. The old
t.Skipfon compile error was masking invalid goldens. -
compileMSLrefactoring — now returns error instead of silently skipping. UsesrustTargetForShaderto check Rust TOML config: if METAL is excluded →t.Skipf, otherwise →t.Fatalf. No more hidden failures. -
Test coverage is comprehensive — 13 rejected operations (load, store, add, subtract, and, or, xor, exchange, compare-exchange, result-producing min/max, workgroup min/max), 3 positive cases (storage min, storage max, nested struct access chain), 32-bit control test,
classifyRustTargetunit tests, Darwin xcrun regression. -
Error messages are actionable —
"64-bit atomic add is unsupported by MSL; only result-discarded min/max in the storage address space are supported"tells the caller exactly what's allowed.
Optional nit (non-blocking)
The rejection tests all use u64 — adding a single i64 rejection case (e.g. atomicAdd on atomic<i64>) would explicitly cover the signed branch. Since Width == 8 handles both uniformly this is cosmetic, but it would make the test contract more visible for future readers.
Notes
strings.SplitSeqinsnapshot_test.go— Go 1.24+ iterator, compatible with ourgo 1.25minimum.currentFunction == nilguard invalidateAtomicOperation— defensive, harmless, prevents nil panic in unexpected paths.- Future: when we add a capabilities validator (Rust naga model), the writer check becomes redundant but harmless.
LGTM.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
@besmpl CI is green, coverage at 91.8% — looks good. One optional nit from the review: all rejection tests use Ready to merge as-is if you'd prefer not to add it. |
Summary
min/maxin storage address space, with no public feature flagMETALtarget exclusion and remove the two invalid stale goldensxcrun metalregression for the supported Metal 2.4 pathRust Naga parity
Rust Naga's MSL backend supports
SHADER_INT64_ATOMIC_MIN_MAXbut notSHADER_INT64_ATOMIC_ALL_OPS. This change enforces the same three-part exception locally:minormax;Loads, stores, arithmetic/bitwise operations, exchanges, compare-exchanges, result-producing min/max, and workgroup min/max now return a descriptive
msl.Compileerror with no partial source. Existing 32-bit and image-atomic paths are unchanged.Verification
go test -count=1 ./msl/internal/codegen ./snapshotgo test -run TestRustReference -count=1 ./snapshot/go test -race -count=1 ./...go vet ./...go build ./...GOOS=linux golangci-lint v2.12.2 run --timeout=5m ./...gofmt -l .git diff --checkThe Darwin regression is present and generates the supported Metal 2.4 shader, but this host's Xcode installation does not include the optional
metalcommand-line utility, so the localxcrun metalcompilation step skipped with its explicit environment message.Fixes #79