Replace the A.0a emit bail with real LLVM atomic codegen: - emitAtomicLoad: LLVMBuildLoad2 + LLVMSetOrdering + LLVMSetAlignment - emitAtomicStore: LLVMBuildStore + LLVMSetOrdering + LLVMSetAlignment (value coerced to the pointee type, mirroring emitStore) - llvmOrdering: explicit sx AtomicOrdering -> LLVMAtomicOrdering map (LLVM's enum is non-contiguous; never an identity cast) examples/1700 now prints 7/42/43; IR is 'load atomic i64, ptr .. seq_cst, align 8' + 'store atomic ..'. Unit test 'emit: atomic load/store (seq_cst, aligned)' locks the emission shape (load atomic/store atomic/seq_cst/align 8) without a fragile full-module .ir snapshot. Suite green (710 examples + units).
78 lines
5.0 KiB
Markdown
78 lines
5.0 KiB
Markdown
# CHECKPOINT-ATOMICS — Stream A (atomics lowering)
|
|
|
|
Companion to [PLAN-ATOMICS.md](PLAN-ATOMICS.md). Update after every step (one step at a
|
|
time, per the cadence rule). New corpus category: `17xx`.
|
|
|
|
## Last completed step
|
|
**A.0b (green) — DONE.** Real atomic load/store emission: `LLVMBuildLoad2`/`LLVMBuildStore`
|
|
+ `LLVMSetOrdering` + mandatory `LLVMSetAlignment`, ordering via an explicit
|
|
sx-tag→`LLVMAtomicOrdering` switch (`llvmOrdering`). `examples/1700` green (7/42/43); IR
|
|
shows `load atomic i64, ptr … seq_cst, align 8` + `store atomic …`. Added unit test
|
|
`emit: atomic load/store (seq_cst, aligned)` in `emit_llvm.test.zig` (asserts `load
|
|
atomic`/`store atomic`/`seq_cst`/`align 8`). No fragile full-module `.ir` snapshot for 1700
|
|
(it uses `print`); 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`: `Ordering` enum, `Atomic($T)` struct (`init`/`load`/
|
|
`store`, **seq_cst-only** — see capability gap below), `atomic_load`/`atomic_store`
|
|
`#builtin` decls. **Opt-in import**, NOT in the universal `std.sx` facade (mirrors
|
|
`trace`) — putting `Ordering` in the prelude grew every program's type table 378→380 and
|
|
churned 37 `.ir` snapshots; 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);
|
|
recognizer `tryLowerAtomicIntrinsic` (call.zig) — const-ordering-literal guard +
|
|
scalar-size guard, both loud; emit dispatch arms (emit_llvm.zig) → `emitAtomicLoad`/
|
|
`emitAtomicStore` (ops.zig) currently BAIL via `comptime_failed`.
|
|
|
|
## Current state
|
|
- A.0a committed; suite green.
|
|
- The recognizer + IR + emit already handle ALL FIVE orderings; only the surface bakes a
|
|
`.seq_cst` literal (the methods can't yet forward a runtime/comptime ordering — gap below).
|
|
- emit bodies are the ONLY placeholder; A.0b swaps them for real builders.
|
|
|
|
## Next step
|
|
**A.0b** — replace the `emitAtomicLoad`/`emitAtomicStore` bail with real
|
|
`LLVMBuildLoad2`+`SetOrdering`+`SetAlignment` / `LLVMBuildStore`+`SetOrdering`+
|
|
`SetAlignment` (explicit sx-tag→LLVM ordering switch); regen 1700 → green (7/42/43) + host
|
|
`.ir`; add `emit_llvm.test.zig` unit. Then adversarial review, then the comptime-enum worker
|
|
+ A.0.5 migration to the full ordering surface.
|
|
|
|
## Known issues / capability gaps
|
|
- **Comptime-constant ordering propagation MISSING (blocks the full surface).** A runtime
|
|
`Ordering` method param can't reach LLVM (orderings are instruction attributes, not
|
|
operands), and comptime enum value params don't exist (`$o: Ordering` → `o` unresolved in
|
|
body; `resolveValueParamArg` folds integers only). So A.0 ships seq_cst-only; A.0.5 closes
|
|
the gap (worker: implement comptime enum value params) and MIGRATES the methods — NO
|
|
legacy left by stream end.
|
|
- **Latent (observed, not yet filed):** calling an *unrecognized* bodiless `#builtin`
|
|
silently 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; candidate `issues/` entry.
|
|
|
|
## Decisions (Stream A specifics; surface locked in design §4.6)
|
|
- `Atomic($T)` = pure-sx transparent 1-field struct (NO new IR type); ops = `#builtin`
|
|
intrinsics 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
|
|
`.ir` per 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`; use `LLVMBuildLoad2`+`SetOrdering`+
|
|
`SetAlignment`), and corrected the arch-`.ir` misconception (`sx ir` emits 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/1700` to the
|
|
bail diagnostic. Reverted a universal-facade wiring that churned 37 `.ir` snapshots
|
|
(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).
|