From b65544a68c2e7552c30092ccb0f8d7a75c443a2d Mon Sep 17 00:00:00 2001 From: agra Date: Sat, 20 Jun 2026 13:51:36 +0300 Subject: [PATCH] atomics A.3b: real swap (xchg) + fence emission + unit test (green) emitAtomicRmw xchg arm (swap) and emitAtomicFence (LLVMBuildFence) now real. examples/1703 (swap old=7/now=42, 'atomicrmw xchg') + 1704 (fence release/acquire/ seq_cst) green. Unit test 'emit: atomic swap (xchg) + fence'. Stream A (atomics) is feature-complete: load/store, RMW (add/sub/and/or/xor/min/max), compare_exchange[_weak], swap, fence. Suite green (721/0). --- current/CHECKPOINT-ATOMICS.md | 6 +++++ examples/expected/1703-atomics-swap.exit | 2 +- examples/expected/1703-atomics-swap.stderr | 2 +- examples/expected/1703-atomics-swap.stdout | 3 ++- examples/expected/1704-atomics-fence.exit | 2 +- examples/expected/1704-atomics-fence.stderr | 4 +-- examples/expected/1704-atomics-fence.stdout | 2 +- src/backend/llvm/ops.zig | 13 +-------- src/ir/emit_llvm.test.zig | 29 +++++++++++++++++++++ 9 files changed, 43 insertions(+), 20 deletions(-) diff --git a/current/CHECKPOINT-ATOMICS.md b/current/CHECKPOINT-ATOMICS.md index 5e957c09..c859bbaf 100644 --- a/current/CHECKPOINT-ATOMICS.md +++ b/current/CHECKPOINT-ATOMICS.md @@ -124,3 +124,9 @@ follow-up, not an atomics blocker. - **A.1** — RMW: atomic_rmw op + RmwKind + recognizer (rmwKindFromName, integer-only) + 7 fetch_* methods/intrinsics. A.1a bail-lock → A.1b real LLVMBuildAtomicRMW (signed|unsigned min/max). comptime_vm real RMW. 1701 + unit test. Suite green (716/0). +- **A.2** — CAS: atomic_cmpxchg op + recognizer (dual-ordering validation) + emit (?T from + {actual,!success}) + comptime VM. compare_exchange/_weak methods. examples 1702 + 1186. + Review agent died; self-verified comptime↔runtime agreement, sub-8, ordering edges. + (Commits dca396e/79895be; A.2 has_value fix folded into A.3a.) +- **A.3** — swap (atomicrmw xchg) + fence (new atomic_fence op). A.3a bail-lock → A.3b real. + examples 1703/1704/1187 + unit test. Stream A feature-complete. Suite green (721/0). diff --git a/examples/expected/1703-atomics-swap.exit b/examples/expected/1703-atomics-swap.exit index d00491fd..573541ac 100644 --- a/examples/expected/1703-atomics-swap.exit +++ b/examples/expected/1703-atomics-swap.exit @@ -1 +1 @@ -1 +0 diff --git a/examples/expected/1703-atomics-swap.stderr b/examples/expected/1703-atomics-swap.stderr index 317306d7..8b137891 100644 --- a/examples/expected/1703-atomics-swap.stderr +++ b/examples/expected/1703-atomics-swap.stderr @@ -1 +1 @@ -error: atomic swap (xchg) LLVM emission not yet implemented (Stream A, A.3b) + diff --git a/examples/expected/1703-atomics-swap.stdout b/examples/expected/1703-atomics-swap.stdout index 8b137891..ec8af639 100644 --- a/examples/expected/1703-atomics-swap.stdout +++ b/examples/expected/1703-atomics-swap.stdout @@ -1 +1,2 @@ - +swap old: 7 +swap now: 42 diff --git a/examples/expected/1704-atomics-fence.exit b/examples/expected/1704-atomics-fence.exit index d00491fd..573541ac 100644 --- a/examples/expected/1704-atomics-fence.exit +++ b/examples/expected/1704-atomics-fence.exit @@ -1 +1 @@ -1 +0 diff --git a/examples/expected/1704-atomics-fence.stderr b/examples/expected/1704-atomics-fence.stderr index ed224ceb..8b137891 100644 --- a/examples/expected/1704-atomics-fence.stderr +++ b/examples/expected/1704-atomics-fence.stderr @@ -1,3 +1 @@ -error: atomic fence LLVM emission not yet implemented (Stream A, A.3b) -error: atomic fence LLVM emission not yet implemented (Stream A, A.3b) -error: atomic fence LLVM emission not yet implemented (Stream A, A.3b) + diff --git a/examples/expected/1704-atomics-fence.stdout b/examples/expected/1704-atomics-fence.stdout index 8b137891..11916f79 100644 --- a/examples/expected/1704-atomics-fence.stdout +++ b/examples/expected/1704-atomics-fence.stdout @@ -1 +1 @@ - +after fences: 3 diff --git a/src/backend/llvm/ops.zig b/src/backend/llvm/ops.zig index 1a1d634f..208ae795 100644 --- a/src/backend/llvm/ops.zig +++ b/src/backend/llvm/ops.zig @@ -416,14 +416,6 @@ pub const Ops = struct { } pub fn emitAtomicRmw(self: Ops, instruction: *const Inst, a: AtomicRmw) void { - // A.3a lock: the new `xchg` (swap) kind BAILS until A.3b. The other RMW - // kinds (A.1) keep working. - if (a.kind == .xchg) { - std.debug.print("error: atomic swap (xchg) LLVM emission not yet implemented (Stream A, A.3b)\n", .{}); - self.e.comptime_failed = true; - self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(if (instruction.ty == .void) .i64 else instruction.ty))); - return; - } const ptr = self.e.resolveRef(a.ptr); const val = self.e.resolveRef(a.operand); const ptr_kind = c.LLVMGetTypeKind(c.LLVMTypeOf(ptr)); @@ -475,11 +467,8 @@ pub const Ops = struct { } // Standalone memory fence — void result, no address. singleThread = 0. - // A.3a lock: BAILS until A.3b wires LLVMBuildFence. pub fn emitAtomicFence(self: Ops, a: AtomicFence) void { - _ = a; - std.debug.print("error: atomic fence LLVM emission not yet implemented (Stream A, A.3b)\n", .{}); - self.e.comptime_failed = true; + _ = c.LLVMBuildFence(self.e.builder, llvmOrdering(a.ordering), 0, ""); self.e.advanceRefCounter(); } diff --git a/src/ir/emit_llvm.test.zig b/src/ir/emit_llvm.test.zig index 10a5a627..f5b3a404 100644 --- a/src/ir/emit_llvm.test.zig +++ b/src/ir/emit_llvm.test.zig @@ -280,6 +280,35 @@ test "emit: atomic rmw (add + signed/unsigned min)" { try std.testing.expect(std.mem.indexOf(u8, ir_str, "atomicrmw umin") != null); // unsigned u64 } +test "emit: atomic swap (xchg) + fence" { + const alloc = std.testing.allocator; + var module = Module.init(alloc); + defer module.deinit(); + + var b = Builder.init(&module); + + _ = b.beginFunction(str(&module, "f"), &.{}, .i64); + const entry = b.appendBlock(str(&module, "entry"), &.{}); + b.switchToBlock(entry); + + const p = b.alloca(.i64); + const five = b.constInt(5, .i64); + const old = b.emit(.{ .atomic_rmw = .{ .ptr = p, .operand = five, .val_ty = .i64, .ordering = .acq_rel, .kind = .xchg } }, .i64); + b.emitVoid(.{ .atomic_fence = .{ .ordering = .seq_cst } }, .void); + b.ret(old, .i64); + b.finalize(); + + var emitter = LLVMEmitter.init(alloc, &module, "test_swap_fence", .{}); + defer emitter.deinit(); + emitter.emit(); + + try std.testing.expect(emitter.verify()); + + const ir_str = emitter.dumpToString(); + try std.testing.expect(std.mem.indexOf(u8, ir_str, "atomicrmw xchg") != null); + try std.testing.expect(std.mem.indexOf(u8, ir_str, "fence seq_cst") != null); +} + test "emit: atomic cmpxchg (strong + weak)" { const alloc = std.testing.allocator; var module = Module.init(alloc);