emitAtomicRmw xchg arm (swap) and emitAtomicFence (LLVMBuildFence) now real. examples/1703 (swap old=7/now=42, 'atomicrmw xchg') + 1704 (fence release/acquire/ seq_cst) green. Unit test 'emit: atomic swap (xchg) + fence'. Stream A (atomics) is feature-complete: load/store, RMW (add/sub/and/or/xor/min/max), compare_exchange[_weak], swap, fence. Suite green (721/0).
9.3 KiB
CHECKPOINT-ATOMICS — Stream A (atomics lowering)
Companion to PLAN-ATOMICS.md. Update after every step (one step at a
time, per the cadence rule). New corpus category: 17xx.
Last completed step
A.2 (CAS) — DONE (A.2a lock + A.2b green). compare_exchange/_weak → LLVM cmpxchg
(result ?T, null = SUCCESS; failure carries the actual value for retry). New IR op
atomic_cmpxchg + AtomicCmpxchg{ptr, cmp, new, val_ty, success_ordering, failure_ordering, weak}. emitAtomicCmpxchg: LLVMBuildAtomicCmpXchg (success/failure orderings, singleThread=0)
→ {T, i1} pair; LLVMSetWeak for weak; ?T result = { extractvalue 0 (actual), xor(extractvalue 1, true) } (has_value = NOT success). comptime_vm arm does real single-thread
CAS (read/compare/store-on-equal, build ?T; weak == strong at comptime). Recognizer
(atomic_cmpxchg/_weak, 6 args) — CAS restricted to INTEGER T; BOTH orderings via
atomicOrderingFromNode; dual-ordering validation (failure may not be release/acq_rel nor
stronger than success, atomicOrderingRank). Methods compare_exchange/_weak on Atomic($T)
with comptime $success/$failure: Ordering. examples/1702 green (CAS ok→20 / fail actual=20 /
weak retry loop 100→105); examples/1186 locks a rejected ordering pair; unit test emit: atomic cmpxchg (strong + weak) asserts cmpxchg + cmpxchg weak. Suite green (718/0).
A.1 (RMW) — DONE (A.1a lock + A.1b green)
fetch_add/sub/and/or/xor + fetch_min/max → LLVM atomicrmw (returns OLD value). New IR op
atomic_rmw + RmwKind (no nand); LLVMBuildAtomicRMW with binop from kind, signed/unsigned
Min/Max from val_ty. RMW restricted to INTEGER T (float fadd / pointer RMW out of scope,
rejected loudly); all five orderings valid for RMW. comptime_vm does real single-thread RMW.
examples/1701 green; unit test locks atomicrmw add + signed min vs unsigned umin.
Next step
A.3 — fence (atomic_fence($o: Ordering) → LLVM fence), per PLAN-ATOMICS. No value
result; ordering must be acquire/release/acq_rel/seq_cst (relaxed is meaningless for a fence —
reject loudly). New IR op atomic_fence + dispatch/print/comptime_vm (no-op single-thread) +
LLVMBuildFence. Lock-then-green cadence as before.
Earlier — A.0c (guard hardening)
Adversarial review of A.0 found two CRITICAL silent-wrong defects (raw LLVM verifier errors
via the public intrinsics) + a latent align fallback; all fixed: scalar-kind allowlist +
per-op ordering validity (call.zig), val_ty align bail (ops.zig). Locked by examples
1130/1131. Suite green (713/0).
Earlier — A.0b (green)
Real atomic load/store emission: LLVMBuildLoad2/LLVMBuildStore
LLVMSetOrdering+ mandatoryLLVMSetAlignment, ordering via an explicit sx-tag→LLVMAtomicOrderingswitch (llvmOrdering).examples/1700green (7/42/43); IR showsload atomic i64, ptr … seq_cst, align 8+store atomic …. Added unit testemit: atomic load/store (seq_cst, aligned)inemit_llvm.test.zig(assertsload atomic/store atomic/seq_cst/align 8). No fragile full-module.irsnapshot for 1700 (it usesprint); the unit test is the emission-shape gate. Suite green (710 + units).
Earlier — A.0a (lock commit)
Full atomic load/store plumbing with LLVM emission deliberately bailing loudly;
examples/1700 locked to the bail diagnostic.
library/modules/std/atomic.sx:Orderingenum,Atomic($T)struct (init/load/store, seq_cst-only — see capability gap below),atomic_load/atomic_store#builtindecls. Opt-in import, NOT in the universalstd.sxfacade (mirrorstrace) — puttingOrderingin the prelude grew every program's type table 378→380 and churned 37.irsnapshots; reverted.- IR ops
atomic_load/atomic_store+AtomicOrdering(all 5) + structs (inst.zig); print arms (print.zig); comptime_vm arms reuse load/store (single-thread correct); recognizertryLowerAtomicIntrinsic(call.zig) — const-ordering-literal guard + scalar-size guard, both loud; emit dispatch arms (emit_llvm.zig) →emitAtomicLoad/emitAtomicStore(ops.zig) currently BAIL viacomptime_failed.
A.0.5 — full ordering surface (DONE)
Atomic($T).load($o: Ordering) / store(v, $o) — ordering is a COMPTIME value param,
explicit (Rust-style, no default; design §4.6). a.load(.acquire) emits load atomic … acquire; a.store(v, .release) emits store atomic … release; a.load(.release) is a
compile error (per-op validity guard fires through the method path). Recognizer
atomicOrderingFromNode now resolves a comptime-bound ordering identifier via
comptimeIntNamed (+ atomicOrderingFromTag, with the sx-Ordering ↔ IR-AtomicOrdering
declaration-order invariant documented). 1700 migrated to explicit orderings (output
unchanged 7/42/43). Suite green (715/0).
Unblocked by three comptime-value-param commits (workers): enum (3c4305f), tagged_union
(d7a6857), generic-struct methods (d95ba0a). NOTE: default VALUES for comptime params on
generic-struct methods are NOT bound (orthogonal gap — free-fn defaults work); atomics
sidesteps it cleanly by requiring explicit ordering (matches the design). Candidate
follow-up, not an atomics blocker.
Known issues / capability gaps
- RESOLVED: comptime-constant ordering propagation — landed via comptime value params
(
3c4305f/d7a6857/d95ba0a); A.0.5 migrated the methods, no seq_cst-only legacy. - Orthogonal gap (not an atomics blocker): default VALUES for comptime params don't bind on generic-struct methods (free-fn defaults DO work). Atomics requires explicit ordering (design-aligned), so it's unaffected. Candidate future fix.
- Cosmetic: an invalid ordering passed through a method (
a.load(.release)) reports the diagnostic at the lib forward site (atomic.sx), not the user's call. Loud + correct, but the span could be improved by threading the call-site span. Polish. - Latent (observed, not yet filed): calling an unrecognized bodiless
#builtinsilently returns 0 / no-ops with exit 0 (that's how 1700 behaved before recognition landed) — a silent-fallback footgun in the generic builtin-call path, independent of atomics. Flag to user; candidateissues/entry.
Decisions (Stream A specifics; surface locked in design §4.6)
Atomic($T)= pure-sx transparent 1-field struct (NO new IR type); ops =#builtinintrinsics emitted as new IR ops. Minimal compiler surface.- Ordering is compile-time-only (const enum literal), baked into the op as a Zig enum; non-literal = loud diagnostic. sx tag → LLVM ordering via explicit switch (LLVM enum is non-contiguous: 2/4/5/6/7).
- Atomic load/store REQUIRE explicit alignment (
LLVMSetAlignment) — verifier mandate. - Comptime VM treats atomics as ordinary load/store (single-thread ⇒ correct), not a bail.
- Snapshot scope corrected:
.ir(LLVM IR) is arch-invariant for atomics → ONE host.irper op, not arch-gated x86/aarch64 pairs (they'd be byte-identical). Asm-level arch divergence + weak-memory semantics are OUT of corpus scope (stress harness, Stream C).
Log
- carve — wrote PLAN-ATOMICS.md + CHECKPOINT-ATOMICS.md; grounded the intrinsic path,
switch sites, LLVM-C API (no
LLVMBuildAtomicLoad; useLLVMBuildLoad2+SetOrdering+SetAlignment), and corrected the arch-.irmisconception (sx iremits arch-invariant LLVM IR). Stream ready; A.0a is the first implementation step. - A.0a — landed lib (atomic.sx, opt-in import) + IR ops (atomic_load/atomic_store +
AtomicOrdering) + recognizer + print/vm arms + emit BAIL; locked
examples/1700to the bail diagnostic. Reverted a universal-facade wiring that churned 37.irsnapshots (Ordering would bloat every program's type table). Suite green (710/0). - A.0b — real atomic load/store emission (LLVMBuildLoad2/Store + SetOrdering +
SetAlignment; explicit sx→LLVM ordering switch). 1700 green (7/42/43,
load atomic … seq_cst, align 8). Unit test added. Suite green (710 + units). - A.0c — guard hardening from the adversarial review: scalar-kind allowlist + per-op ordering validity (call.zig), val_ty align bail (ops.zig), + diagnostic examples 1130/1131. Suite green (713/0). (comptime enum value params landed via worker 3c4305f.)
- A.0.5 — full ordering surface:
Atomic($T).load/store($o: Ordering)comptime ordering (explicit). Recognizer resolves comptime-bound ordering viacomptimeIntNamed. 1700 migrated to explicit orderings (acquire/release/relaxed/seq_cst). Unblocked by comptime-value-param workers (3c4305f/d7a6857/d95ba0a). Suite green (715/0). - A.1 — RMW: atomic_rmw op + RmwKind + recognizer (rmwKindFromName, integer-only) + 7 fetch_* methods/intrinsics. A.1a bail-lock → A.1b real LLVMBuildAtomicRMW (signed|unsigned min/max). comptime_vm real RMW. 1701 + unit test. Suite green (716/0).
- A.2 — CAS: atomic_cmpxchg op + recognizer (dual-ordering validation) + emit (?T from {actual,!success}) + comptime VM. compare_exchange/_weak methods. examples 1702 + 1186. Review agent died; self-verified comptime↔runtime agreement, sub-8, ordering edges. (Commits dca396e/79895be; A.2 has_value fix folded into A.3a.)
- A.3 — swap (atomicrmw xchg) + fence (new atomic_fence op). A.3a bail-lock → A.3b real. examples 1703/1704/1187 + unit test. Stream A feature-complete. Suite green (721/0).