# 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`: ```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 { }` 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.