atomics: close out Stream A (feature-complete)

Final whole-stream adversarial review came back CLEAN (no CRITICAL/MEDIUM/LOW).
Close the one informational gap it noted: extend examples/1703 with a #run
comptime swap so swap's comptime VM arm is locked (742, matches runtime) — every
op now has comptime↔runtime corpus coverage.

Docs: PLAN-ATOMICS.md status banner (COMPLETE); PLAN-POST-METATYPE.md Stream A
marked done (unblocks B2-channels + C-parallel); readme.md gains a user-facing
Atomics section. Suite green (721/0).
This commit is contained in:
agra
2026-06-20 14:02:41 +03:00
parent b65544a68c
commit 9bcb4159ef
5 changed files with 53 additions and 2 deletions

View File

@@ -1,5 +1,20 @@
# PLAN-ATOMICS — Stream A (atomics lowering)
> **STATUS: ✅ COMPLETE (feature-complete).** All phases A.0 → A.3 landed + green.
> Surface shipped: `Atomic($T)` `load`/`store`/`fetch_add`/`sub`/`and`/`or`/`xor`/`min`/`max`/
> `swap`/`compare_exchange`/`compare_exchange_weak` (all comptime `$o: Ordering`) + free
> `fence(.ordering)`. IR ops `atomic_load`/`store`/`rmw`/`cmpxchg`/`fence`. Both LLVM emit
> AND the comptime VM implemented (verified to agree). Enabled by net-new comptime value
> params (enum/tagged_union/generic-struct methods — 3 commits). Corpus `17xx` (1700-1704) +
> `11xx` diagnostics (1130/1131/1186/1187). Commits: 22af404, 64c7db5, 8144a88, acf3183,
> 718f27e, 0531164, 68ed732, dca396e, 79895be, fca4304, b65544a (+ comptime-param 3c4305f,
> d7a6857, d95ba0a). **Unblocks Stream B2 channels + Stream C parallel schedulers.**
>
> Deferred (documented, NOT legacy — intentional scope): RMW/CAS/swap are integer-only
> (float fadd / pointer atomics out of scope); fence/orderings explicit (no defaults — the
> comptime-default-on-generic-method gap is orthogonal). Asm-level arch divergence +
> weak-memory *semantics* remain OUT of corpus scope (Stream-C stress harness).
Carved from [PLAN-POST-METATYPE.md](PLAN-POST-METATYPE.md) Stream A + the design-of-record
[../design/execution-evolution-roadmap.md](../design/execution-evolution-roadmap.md) §3 (N1)
+ §4.6 (locked surface). Progress in [CHECKPOINT-ATOMICS.md](CHECKPOINT-ATOMICS.md).

View File

@@ -19,7 +19,7 @@ JIT/FFI cluster comes after. New corpus categories: `17xx` atomics, `18xx` concu
| # | Stream | Roadmap steps | Depends on | Notes |
|---|--------|---------------|-----------|-------|
| **A** | Atomics | N1 (1) | — | independent foundation; gates B-parallel + channels |
| **A** | Atomics | N1 (1) | — | **DONE**`PLAN-ATOMICS.md`. load/store/RMW/CAS/swap/fence; comptime value params landed alongside. Gates B2-channels + C-parallel |
| **B** | Async runtime | 412 | metatype, A (for channels) | the bulk; likely splits into B1 (runtime) + B2 (channels/cancel/stdlib) when carved |
| **C** | Parallel schedulers | 1314 | A, B | N×(M:1) → M:N |
| **D** | Comptime JIT/FFI | 1518 | — (independent of async) | S1 → C1 → C2 → C3 |
@@ -31,7 +31,7 @@ earlier if FFI/`#compiler`-collapse becomes a priority).
---
## Stream A — ATOMICS (N1) · `PLAN-ATOMICS.md` when carved
## Stream A — ATOMICS (N1) · ✅ **COMPLETE** — see [PLAN-ATOMICS.md](PLAN-ATOMICS.md)
**Goal:** LLVM atomic codegen — the net-new emit primitive. Surface = `Atomic($T)`
wrapper + `Ordering` enum (locked, design §4.6). **Grounding correction: this is 100%

View File

@@ -1,11 +1,16 @@
// Atomic($T).swap — atomic exchange (LLVM atomicrmw xchg): store the new value,
// return the OLD one. Stream A (atomics) A.3. Single-thread.
// Covers swap at BOTH comptime (#run) and runtime — they must agree.
#import "modules/std.sx";
#import "modules/std/atomic.sx";
c_swap :: () -> i64 { a := Atomic(i64).init(7); old := a.swap(42, .seq_cst); return old * 100 + a.load(.seq_cst); }
G_SWAP :: #run c_swap(); // 742 (old 7, now 42)
main :: () {
a := Atomic(i64).init(7);
old := a.swap(42, .acq_rel);
print("swap old: {}\n", old); // 7
print("swap now: {}\n", a.load(.acquire)); // 42
print("comptime swap: {}\n", G_SWAP); // 742 (matches runtime)
}

View File

@@ -1,2 +1,3 @@
swap old: 7
swap now: 42
comptime swap: 742

View File

@@ -675,6 +675,36 @@ The standard library (`modules/std.sx`) provides:
- **Math**: `sqrt`, `sin`, `cos`
- **Introspection**: `type_of`, `type_name`, `type_is_unsigned`, `type_eq`, `field_count`, `field_name`, `field_value`, `size_of`, `align_of`, `is_flags` — the type-only builtins (`size_of`, `align_of`, `field_count`, `type_name`, `type_eq`, `type_is_unsigned`, `is_flags`) require a type argument (a spelled type or a generic `T`); passing a value is a compile-time error. A runtime `Type` value (`type_of(x)`) is currently accepted by `type_name` and `type_is_unsigned` only — the other five are compile-time-only (runtime reflection is deferred)
### Atomics (`modules/std/atomic.sx`)
Opt-in import (not in the universal prelude). `Atomic($T)` is a transparent
wrapper over an integer/pointer-sized `T`; the memory `Ordering` is a **compile-time
value parameter** (`$o`) — LLVM atomic ordering is an instruction attribute, so it
must be known at compile time, and it's always explicit (Rust-style, no default):
```sx
#import "modules/std/atomic.sx";
counter : Atomic(i64) = .init(0);
counter.store(0, .relaxed);
n := counter.load(.acquire);
prev := counter.fetch_add(1, .seq_cst); // + fetch_sub/and/or/xor/min/max
old := counter.swap(42, .acq_rel);
// compare-exchange returns ?T — null = SUCCESS; a present value is the actual
// current value on failure (for a retry loop). `_weak` may fail spuriously.
got := counter.compare_exchange(old, 99, .acq_rel, .acquire);
if got == null { /* swapped */ } else { /* retry with got! */ }
fence(.seq_cst); // standalone memory fence (.relaxed is rejected)
```
`Ordering` = `relaxed`/`acquire`/`release`/`acq_rel`/`seq_cst`. Invalid combinations
are compile errors (a load can't be `.release`; a store can't be `.acquire`; CAS's
failure ordering can't be stronger than success; a fence can't be `.relaxed`).
RMW/CAS/swap are integer-only. The same operations run at compile time (`#run`)
under single-threaded semantics, matching the runtime result.
### Command-line interface (`modules/std/cli.sx`)
`std.cli` builds command-line front-ends over an explicit logical argv