issue 0151 (generic $T inference through generic-struct / pointer / UFCS-pack params) is fixed and committed, so io.sx's async/await/cancel are now callable in every form. Building the async examples then tripped a SEPARATE codegen bug: Atomic(bool) emits a sub-byte (i1) atomic load/store that fails LLVM verification (must be byte-sized). Future.canceled: Atomic(bool) hits it. Filed issues/0152 with a standalone repro + investigation prompt (codegen fix in src/backend/llvm/ops.zig — promote sub-byte atomics to i8 storage). Per the STOP rule, paused B1.2's async examples (1805/1806) pending the 0152 fix. Checkpoint updated: 0151 RESOLVED, async surface BLOCKED on 0152.
3.2 KiB
0152 — Atomic(bool) emits a sub-byte (i1) atomic load/store that LLVM rejects
Symptom
Atomic(bool) lowers bool to LLVM i1 and emits the atomic load/store
at that type. LLVM requires atomic memory accesses to be byte-sized, so
codegen fails verification:
LLVM verification failed: atomic memory access' size must be byte-sized
i1 store atomic i1 %load5, ptr %gep release, align 1
i1 %atomic_load = load atomic i1, ptr %gep11 acquire, align 1
Atomic(i64),Atomic(i32), … → fine (byte-sized).Atomic(bool)→ LLVM verifier error (i1 is 1 bit, not byte-sized).
Reproduction
Standalone — depends on no project symbols beyond modules/std.sx +
modules/std/atomic.sx:
#import "modules/std.sx";
#import "modules/std/atomic.sx";
main :: () -> i32 {
a := Atomic(bool).init(false);
a.store(true, .release);
if a.load(.acquire) { print("yes\n"); } else { print("no\n"); }
return 0;
}
Expected: prints yes. Actual: LLVM verification failure (i1 atomic).
Impact
Blocks the B1.2 async surface. library/modules/std/io.sx's
Future($R) carries a canceled: Atomic(bool) cancellation flag (atomic
so a future scheduler thread can flip it). async/cancel/await all
touch it (Atomic(bool).init, .store(true, .release),
.load(.acquire)), so the async examples (1805/1806) cannot build.
This is independent of issue 0151 (generic inference) — that is now fixed,
which is what newly exposed this codegen path.
Investigation prompt
The atomic load/store emitters in src/backend/llvm/ops.zig
(emitAtomicLoad ~line 387, emitAtomicStore, emitAtomicRmw,
emitAtomicCmpxchg) use toLLVMType(instruction.ty) directly as the
atomic access type. For a bool element that is i1, which LLVM rejects
for atomics (must be a byte-multiple).
The fix should promote a sub-byte atomic to its byte-sized storage type:
load/store as i8 (the ABI storage type for bool) and trunc/zext
between i1 and i8 at the value boundary — mirroring how a non-atomic
bool field is already stored as a byte. Apply consistently across
load / store / rmw / cmpxchg so an Atomic(bool) round-trips. Confirm the
alignment (LLVMSetAlignment) uses the promoted byte size.
Possible alternative: have Atomic($T) (in library/modules/std/atomic.sx)
constrain / widen a bool element to a byte-sized integer in the type
itself — but the codegen-level promotion is more robust (any i1-typed
atomic, however it arises, becomes legal).
Verification: run the repro above; expect yes. Then restore
examples/1805-concurrency-io-blocking-async.sx (+ add 1806 cancel) per
Stream B1 / CHECKPOINT-FIBERS and confirm the async surface builds and runs
(sum: 42 / double: 42, cancel → .canceled).
Possibly-related secondary symptom (verify after the i1 fix)
The same async probe also tripped an or-merge PHI type mismatch
(%bp = phi i1 [ true, … ], [ 0, … ]) when f.await() or { <i64> } was
lowered. A minimal (i64, !E) + or { -1 } does NOT reproduce it, so this
may be entangled with the malformed Atomic(bool) field in the Future
struct rather than a second bug. Re-check once the i1 atomic is fixed; if it
persists, file separately.