atomics A.3a: swap + fence ops + recognizer, emit bails (lock)
swap (atomicrmw xchg) and a standalone fence wired end-to-end except LLVM emission (both bail loudly; A.3b makes them real). - RmwKind += xchg; atomic_swap intrinsic + swap method reuse the atomic_rmw op. - new atomic_fence op (+ AtomicFence) — ordering-only, void; fence($o)/atomic_fence intrinsic; recognizer rejects .relaxed (LLVM has no monotonic fence). - comptime_vm: xchg = store operand/return old; fence = no-op (single-thread). - examples 1703 (swap) + 1704 (fence) locked to bails; 1187 (relaxed-fence reject). - 1186 converted to a direct-intrinsic call → stable user-file diagnostic span (the lib-forward-site span shifted when atomic.sx grew — fragile-snapshot fix). Also fixes a latent A.2 comptime-CAS bug found while here: the success/null has_value write was 'writeWord(addr, SIZE=0, val=1)' — a 0-byte no-op, correct ONLY because allocBytes zero-inits (REJECTED-PATTERNS 'coincidentally correct'). Now writes the flag explicitly (size=1, val=0). Suite green (721/0).
This commit is contained in:
@@ -19,6 +19,7 @@ const AtomicLoad = ir_inst.AtomicLoad;
|
||||
const AtomicStore = ir_inst.AtomicStore;
|
||||
const AtomicRmw = ir_inst.AtomicRmw;
|
||||
const AtomicCmpxchg = ir_inst.AtomicCmpxchg;
|
||||
const AtomicFence = ir_inst.AtomicFence;
|
||||
const Conversion = ir_inst.Conversion;
|
||||
const GlobalId = ir_inst.GlobalId;
|
||||
const GlobalSet = ir_inst.GlobalSet;
|
||||
@@ -410,10 +411,19 @@ pub const Ops = struct {
|
||||
.xor => c.LLVMAtomicRMWBinOpXor,
|
||||
.min => if (is_unsigned) c.LLVMAtomicRMWBinOpUMin else c.LLVMAtomicRMWBinOpMin,
|
||||
.max => if (is_unsigned) c.LLVMAtomicRMWBinOpUMax else c.LLVMAtomicRMWBinOpMax,
|
||||
.xchg => c.LLVMAtomicRMWBinOpXchg, // swap
|
||||
};
|
||||
}
|
||||
|
||||
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));
|
||||
@@ -464,6 +474,15 @@ 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;
|
||||
self.e.advanceRefCounter();
|
||||
}
|
||||
|
||||
pub fn emitAtomicStore(self: Ops, a: AtomicStore) void {
|
||||
const ptr = self.e.resolveRef(a.ptr);
|
||||
var val = self.e.resolveRef(a.val);
|
||||
|
||||
Reference in New Issue
Block a user