authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-10-31 09:00:02+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-12 17:07:49+02:00
log4c36a403a895bd3e7dc7b4dd308f2b82a3dab60a
tree50763d16076bdc4d5c636f0aa39654fb8b631e39
parentd4ca9804f8a546c45451a58c8bde20bc2299d4a6
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

Air: Fix mustLower() for atomic_load with inter-thread ordering.


3 files changed, 29 insertions(+), 18 deletions(-)

src/Air.zig+4-1
......@@ -1889,7 +1889,10 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
18891889 },
18901890 .load => air.typeOf(data.ty_op.operand, ip).isVolatilePtrIp(ip),
18911891 .slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs, ip).isVolatilePtrIp(ip),
1892 .atomic_load => air.typeOf(data.atomic_load.ptr, ip).isVolatilePtrIp(ip),
1892 .atomic_load => switch (data.atomic_load.order) {
1893 .unordered, .monotonic => air.typeOf(data.atomic_load.ptr, ip).isVolatilePtrIp(ip),
1894 else => true, // Stronger memory orderings have inter-thread side effects.
1895 },
18931896 };
18941897}
18951898
src/arch/riscv64/CodeGen.zig+8-6
......@@ -7738,7 +7738,10 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
77387738 const bit_size = elem_ty.bitSize(zcu);
77397739 if (bit_size > 64) return func.fail("TODO: airAtomicLoad > 64 bits", .{});
77407740
7741 const result_mcv = try func.allocRegOrMem(elem_ty, inst, true);
7741 const result_mcv: MCValue = if (func.liveness.isUnused(inst))
7742 .{ .register = .zero }
7743 else
7744 try func.allocRegOrMem(elem_ty, inst, true);
77427745 assert(result_mcv == .register); // should be less than 8 bytes
77437746
77447747 if (order == .seq_cst) {
......@@ -7754,11 +7757,10 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
77547757 try func.load(result_mcv, ptr_mcv, ptr_ty);
77557758
77567759 switch (order) {
7757 // Don't guarnetee other memory operations to be ordered after the load.
7758 .unordered => {},
7759 .monotonic => {},
7760 // Make sure all previous reads happen before any reading or writing accurs.
7761 .seq_cst, .acquire => {
7760 // Don't guarantee other memory operations to be ordered after the load.
7761 .unordered, .monotonic => {},
7762 // Make sure all previous reads happen before any reading or writing occurs.
7763 .acquire, .seq_cst => {
77627764 _ = try func.addInst(.{
77637765 .tag = .fence,
77647766 .data = .{ .fence = .{
src/arch/x86_64/CodeGen.zig+17-11
......@@ -106219,23 +106219,29 @@ fn airAtomicRmw(self: *CodeGen, inst: Air.Inst.Index) !void {
106219106219
106220106220fn airAtomicLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
106221106221 const atomic_load = self.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
106222 const result: MCValue = result: {
106223 const ptr_ty = self.typeOf(atomic_load.ptr);
106224 const ptr_mcv = try self.resolveInst(atomic_load.ptr);
106225 const ptr_lock = switch (ptr_mcv) {
106226 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
106227 else => null,
106228 };
106229 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
106222106230
106223 const ptr_ty = self.typeOf(atomic_load.ptr);
106224 const ptr_mcv = try self.resolveInst(atomic_load.ptr);
106225 const ptr_lock = switch (ptr_mcv) {
106226 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
106227 else => null,
106228 };
106229 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
106231 const unused = self.liveness.isUnused(inst);
106230106232
106231 const dst_mcv =
106232 if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv))
106233 const dst_mcv: MCValue = if (unused)
106234 .{ .register = try self.register_manager.allocReg(null, self.regSetForType(ptr_ty.childType(self.pt.zcu))) }
106235 else if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv))
106233106236 ptr_mcv
106234106237 else
106235106238 try self.allocRegOrMem(inst, true);
106236106239
106237 try self.load(dst_mcv, ptr_ty, ptr_mcv);
106238 return self.finishAir(inst, dst_mcv, .{ atomic_load.ptr, .none, .none });
106240 try self.load(dst_mcv, ptr_ty, ptr_mcv);
106241
106242 break :result if (unused) .unreach else dst_mcv;
106243 };
106244 return self.finishAir(inst, result, .{ atomic_load.ptr, .none, .none });
106239106245}
106240106246
106241106247fn airAtomicStore(self: *CodeGen, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {