atomics A.1c: fix comptime signed fetch_min/max (was unsigned compare)
Adversarial review CRITICAL: the comptime VM's atomic_rmw min/max arm called @max/@min directly on Reg (=u64) values for SIGNED types, doing an UNSIGNED compare — so comptime fetch_min/max on negatives diverged from the runtime LLVM atomicrmw min/max (signed). Fix: reinterpret as i64 in the signed branch before comparing, bitcast back (mirrors the unsigned branch + the emit-side signedness). Closes the coverage gap that hid it: extend examples/1701 with signed min/max on a negative at BOTH comptime (#run) and runtime — they now agree (3 / -5). Suite green (716/0).
This commit is contained in:
@@ -699,13 +699,17 @@ pub const Vm = struct {
|
||||
.@"or" => old | operand,
|
||||
.xor => old ^ operand,
|
||||
.min, .max => blk: {
|
||||
// `Reg` is u64, so `@max`/`@min` on it is an UNSIGNED
|
||||
// compare. For a signed type, reinterpret as i64 first so
|
||||
// a negative value loses to a positive one — matching LLVM
|
||||
// `atomicrmw min`/`max` (signed) and the emit side.
|
||||
const want_max = a.kind == .max;
|
||||
if (table.isUnsignedInt(vty)) {
|
||||
const uo: u64 = @bitCast(old);
|
||||
const up: u64 = @bitCast(operand);
|
||||
break :blk @bitCast(if (want_max) @max(uo, up) else @min(uo, up));
|
||||
break :blk if (want_max) @max(old, operand) else @min(old, operand);
|
||||
}
|
||||
break :blk if (want_max) @max(old, operand) else @min(old, operand);
|
||||
const so: i64 = @bitCast(old);
|
||||
const sp: i64 = @bitCast(operand);
|
||||
break :blk @bitCast(if (want_max) @max(so, sp) else @min(so, sp));
|
||||
},
|
||||
};
|
||||
try self.writeField(table, frame.get(a.ptr.index()), vty, new_val);
|
||||
|
||||
Reference in New Issue
Block a user