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:
@@ -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).
|
||||
|
||||
@@ -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 | 4–12 | metatype, A (for channels) | the bulk; likely splits into B1 (runtime) + B2 (channels/cancel/stdlib) when carved |
|
||||
| **C** | Parallel schedulers | 13–14 | A, B | N×(M:1) → M:N |
|
||||
| **D** | Comptime JIT/FFI | 15–18 | — (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%
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
swap old: 7
|
||||
swap now: 42
|
||||
comptime swap: 742
|
||||
|
||||
30
readme.md
30
readme.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user