atomics A.1b: real RMW emission (atomicrmw) + unit test (green)

emitAtomicRmw: LLVMBuildAtomicRMW (binop from RmwKind; signed Min/Max vs
unsigned UMin/UMax from val_ty; singleThread=0; LLVM supplies ABI alignment).
examples/1701 green (add/sub/and/or/xor/min/max return old values, results
verified). Unit test 'emit: atomic rmw (add + signed/unsigned min)' locks
'atomicrmw add' + signed 'min' vs unsigned 'umin'. Suite green (716/0).
This commit is contained in:
agra
2026-06-20 10:19:44 +03:00
parent 718f27e27f
commit 05311646aa
6 changed files with 98 additions and 51 deletions

View File

@@ -396,13 +396,33 @@ pub const Ops = struct {
}
}
// A.1a (Stream A) lock: emission BAILS LOUDLY until A.1b wires the real
// LLVMBuildAtomicRMW (binop from kind; signed/unsigned Min/Max from val_ty).
// atomicrmw returns the OLD value. The binop comes from the kind; min/max
// pick signed vs unsigned from val_ty. singleThread stays 0. LLVM gives the
// op the type's ABI alignment automatically (no explicit SetAlignment needed,
// unlike plain load/store).
fn rmwBinOp(kind: ir_inst.RmwKind, is_unsigned: bool) c.LLVMAtomicRMWBinOp {
return switch (kind) {
.add => c.LLVMAtomicRMWBinOpAdd,
.sub => c.LLVMAtomicRMWBinOpSub,
.@"and" => c.LLVMAtomicRMWBinOpAnd,
.@"or" => c.LLVMAtomicRMWBinOpOr,
.xor => c.LLVMAtomicRMWBinOpXor,
.min => if (is_unsigned) c.LLVMAtomicRMWBinOpUMin else c.LLVMAtomicRMWBinOpMin,
.max => if (is_unsigned) c.LLVMAtomicRMWBinOpUMax else c.LLVMAtomicRMWBinOpMax,
};
}
pub fn emitAtomicRmw(self: Ops, instruction: *const Inst, a: AtomicRmw) void {
_ = a;
std.debug.print("error: atomic rmw LLVM emission not yet implemented (Stream A, A.1b)\n", .{});
self.e.comptime_failed = true;
self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(if (instruction.ty == .void) .i64 else instruction.ty)));
const ptr = self.e.resolveRef(a.ptr);
const val = self.e.resolveRef(a.operand);
const ptr_kind = c.LLVMGetTypeKind(c.LLVMTypeOf(ptr));
if (ptr_kind == c.LLVMPointerTypeKind and instruction.ty != .void) {
const is_unsigned = self.e.ir_mod.types.isUnsignedInt(a.val_ty);
const result = c.LLVMBuildAtomicRMW(self.e.builder, rmwBinOp(a.kind, is_unsigned), ptr, val, llvmOrdering(a.ordering), 0);
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 {