atomics A.0b: real seq_cst load/store emission (green)

Replace the A.0a emit bail with real LLVM atomic codegen:
- emitAtomicLoad: LLVMBuildLoad2 + LLVMSetOrdering + LLVMSetAlignment
- emitAtomicStore: LLVMBuildStore + LLVMSetOrdering + LLVMSetAlignment (value
  coerced to the pointee type, mirroring emitStore)
- llvmOrdering: explicit sx AtomicOrdering -> LLVMAtomicOrdering map (LLVM's enum
  is non-contiguous; never an identity cast)

examples/1700 now prints 7/42/43; IR is 'load atomic i64, ptr .. seq_cst, align 8'
+ 'store atomic ..'. Unit test 'emit: atomic load/store (seq_cst, aligned)' locks
the emission shape (load atomic/store atomic/seq_cst/align 8) without a fragile
full-module .ir snapshot. Suite green (710 examples + units).
This commit is contained in:
agra
2026-06-20 09:08:05 +03:00
parent 22af40413d
commit 64c7db5eb1
6 changed files with 98 additions and 22 deletions

View File

@@ -366,25 +366,55 @@ pub const Ops = struct {
}
// ── Atomics ───────────────────────────────────────────
// A.0a (Stream A) lock: the IR ops, lowering, and comptime VM are wired,
// but LLVM emission deliberately BAILS LOUDLY (clean diagnostic + build
// abort via `comptime_failed`) rather than silently emitting a non-atomic
// load/store. A.0b replaces these bodies with the real builders:
// load: LLVMBuildLoad2 + LLVMSetOrdering + LLVMSetAlignment
// store: LLVMBuildStore + LLVMSetOrdering + LLVMSetAlignment
// (ordering via an explicit sx-tag → LLVMAtomicOrdering switch).
// Atomic load/store = ordinary LLVMBuildLoad2/Store made atomic via
// LLVMSetOrdering, with a MANDATORY explicit alignment (the LLVM verifier
// rejects atomic load/store without it). singleThread stays 0 (cross-thread
// ordering). The sx ordering tag → LLVM ordering map is explicit (LLVM's
// enum is non-contiguous), never an identity cast.
fn llvmOrdering(o: ir_inst.AtomicOrdering) c.LLVMAtomicOrdering {
return switch (o) {
.relaxed => c.LLVMAtomicOrderingMonotonic,
.acquire => c.LLVMAtomicOrderingAcquire,
.release => c.LLVMAtomicOrderingRelease,
.acq_rel => c.LLVMAtomicOrderingAcquireRelease,
.seq_cst => c.LLVMAtomicOrderingSequentiallyConsistent,
};
}
pub fn emitAtomicLoad(self: Ops, instruction: *const Inst, a: AtomicLoad) void {
_ = a;
std.debug.print("error: atomic load LLVM emission not yet implemented (Stream A, A.0b)\n", .{});
self.e.comptime_failed = true;
// Keep emit from crashing downstream: yield an undef of the result type.
self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(if (instruction.ty == .void) .i64 else instruction.ty)));
const ptr = self.e.resolveRef(a.ptr);
const ptr_kind = c.LLVMGetTypeKind(c.LLVMTypeOf(ptr));
if (ptr_kind == c.LLVMPointerTypeKind and instruction.ty != .void) {
const llvm_ty = self.e.toLLVMType(instruction.ty);
const result = c.LLVMBuildLoad2(self.e.builder, llvm_ty, ptr, "atomic_load");
c.LLVMSetOrdering(result, llvmOrdering(a.ordering));
c.LLVMSetAlignment(result, @intCast(self.e.ir_mod.types.typeSizeBytes(instruction.ty)));
self.e.mapRef(result);
} else {
self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(if (instruction.ty == .void) .i64 else instruction.ty)));
}
}
pub fn emitAtomicStore(self: Ops, a: AtomicStore) void {
_ = a;
std.debug.print("error: atomic store LLVM emission not yet implemented (Stream A, A.0b)\n", .{});
self.e.comptime_failed = true;
const ptr = self.e.resolveRef(a.ptr);
var val = self.e.resolveRef(a.val);
const ptr_kind = c.LLVMGetTypeKind(c.LLVMTypeOf(ptr));
const val_kind = c.LLVMGetTypeKind(c.LLVMTypeOf(val));
if (ptr_kind == c.LLVMPointerTypeKind and val_kind != c.LLVMVoidTypeKind) {
// Coerce the value to the pointer's IR target type, mirroring emitStore.
if (self.e.getRefIRType(a.ptr)) |ptr_ir_ty| {
const pointee_info = self.e.ir_mod.types.get(ptr_ir_ty);
const target_ty: ?c.LLVMTypeRef = switch (pointee_info) {
.pointer => |p| self.e.toLLVMType(p.pointee),
else => null,
};
if (target_ty) |tt| val = self.e.coerceArg(val, tt);
}
const st = c.LLVMBuildStore(self.e.builder, val, ptr);
c.LLVMSetOrdering(st, llvmOrdering(a.ordering));
const align_ty = if (a.val_ty != .void) a.val_ty else .i64;
c.LLVMSetAlignment(st, @intCast(self.e.ir_mod.types.typeSizeBytes(align_ty)));
}
self.e.advanceRefCounter();
}