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

@@ -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