authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-28 17:35:17-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-01 19:22:52-04:00
logaaef5288f886c86e4257c5c67122a0be8a64c134
tree8cabea0a1b431accb40b84529790ed122d4c28ea
parent50f96c2949bd7d396eaaf391ffd5fd55e59ebac1

x86_64: fix 128-bit cmpxchg


1 files changed, 67 insertions(+), 67 deletions(-)

src/arch/x86_64/CodeGen.zig+67-67
......@@ -219,9 +219,9 @@ pub const MCValue = union(enum) {
219219 .dead,
220220 .undef,
221221 .immediate,
222 .eflags,
222223 .register,
223224 .register_offset,
224 .eflags,
225225 .register_overflow,
226226 .lea_direct,
227227 .lea_got,
......@@ -297,6 +297,41 @@ pub const MCValue = union(enum) {
297297 };
298298 }
299299
300 fn mem(mcv: MCValue, ptr_size: Memory.PtrSize) Memory {
301 return switch (mcv) {
302 .none,
303 .unreach,
304 .dead,
305 .undef,
306 .immediate,
307 .eflags,
308 .register,
309 .register_offset,
310 .register_overflow,
311 .load_direct,
312 .lea_direct,
313 .load_got,
314 .lea_got,
315 .load_tlv,
316 .lea_tlv,
317 .lea_frame,
318 .reserved_frame,
319 => unreachable,
320 .memory => |addr| if (math.cast(i32, @bitCast(i64, addr))) |small_addr|
321 Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr })
322 else
323 Memory.moffs(.ds, addr),
324 .indirect => |reg_off| Memory.sib(ptr_size, .{
325 .base = .{ .reg = reg_off.reg },
326 .disp = reg_off.off,
327 }),
328 .load_frame => |frame_addr| Memory.sib(ptr_size, .{
329 .base = .{ .frame = frame_addr.index },
330 .disp = frame_addr.off,
331 }),
332 };
333 }
334
300335 pub fn format(
301336 mcv: MCValue,
302337 comptime _: []const u8,
......@@ -7936,70 +7971,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
79367971 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
79377972
79387973 const ptr_ty = self.air.typeOf(extra.ptr);
7939 const ptr_mcv = try self.resolveInst(extra.ptr);
79407974 const val_ty = self.air.typeOf(extra.expected_value);
79417975 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
79427976
79437977 try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
79447978 const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
7945 for (regs_lock) |lock| self.register_manager.unlockReg(lock);
7979 defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
79467980
79477981 const exp_mcv = try self.resolveInst(extra.expected_value);
7948 if (val_abi_size > 8) switch (exp_mcv) {
7949 .load_frame => |frame_addr| {
7950 try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{
7951 .index = frame_addr.index,
7952 .off = frame_addr.off + 0,
7953 } });
7954 try self.genSetReg(.rdx, Type.usize, .{ .load_frame = .{
7955 .index = frame_addr.index,
7956 .off = frame_addr.off + 8,
7957 } });
7958 },
7959 else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
7982 if (val_abi_size > 8) {
7983 try self.genSetReg(.rax, Type.usize, exp_mcv);
7984 try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref());
79607985 } else try self.genSetReg(.rax, val_ty, exp_mcv);
7961 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
7962 defer self.register_manager.unlockReg(rax_lock);
79637986
79647987 const new_mcv = try self.resolveInst(extra.new_value);
7965 const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) {
7966 .load_frame => |frame_addr| new: {
7967 try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{
7968 .index = frame_addr.index,
7969 .off = frame_addr.off + 0,
7970 } });
7971 try self.genSetReg(.rcx, Type.usize, .{ .load_frame = .{
7972 .index = frame_addr.index,
7973 .off = frame_addr.off + 8,
7974 } });
7975 break :new undefined;
7976 },
7977 else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
7988 const new_reg = if (val_abi_size > 8) new: {
7989 try self.genSetReg(.rbx, Type.usize, new_mcv);
7990 try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref());
7991 break :new null;
79787992 } else try self.copyToTmpRegister(val_ty, new_mcv);
7979 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
7980 defer self.register_manager.unlockReg(new_lock);
7993 const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
7994 defer if (new_lock) |lock| self.register_manager.unlockReg(lock);
79817995
7996 const ptr_mcv = try self.resolveInst(extra.ptr);
79827997 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
79837998 const ptr_mem = switch (ptr_mcv) {
7984 .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),
7985 .lea_frame => |frame_addr| Memory.sib(ptr_size, .{
7986 .base = .{ .frame = frame_addr.index },
7987 .disp = frame_addr.off,
7999 .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
8000 else => Memory.sib(ptr_size, .{
8001 .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
79888002 }),
7989 else => Memory.sib(ptr_size, .{ .base = .{
7990 .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
7991 } }),
79928003 };
7993 const mem_lock = switch (ptr_mem.base()) {
8004 switch (ptr_mem) {
8005 .sib, .rip => {},
8006 .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
8007 }
8008 const ptr_lock = switch (ptr_mem.base()) {
79948009 .none, .frame => null,
79958010 .reg => |reg| self.register_manager.lockReg(reg),
79968011 };
7997 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
8012 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
79988013
79998014 try self.spillEflagsIfOccupied();
80008015 if (val_abi_size <= 8) {
80018016 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
8002 .r = registerAlias(new_reg, val_abi_size),
8017 .r = registerAlias(new_reg.?, val_abi_size),
80038018 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
80048019 } } });
80058020 } else {
......@@ -8017,24 +8032,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
80178032 }
80188033
80198034 const dst_mcv = try self.allocRegOrMem(inst, false);
8020 try self.genSetMem(
8021 .{ .frame = dst_mcv.load_frame.index },
8022 dst_mcv.load_frame.off + 16,
8023 Type.bool,
8024 .{ .eflags = .ne },
8025 );
8026 try self.genSetMem(
8027 .{ .frame = dst_mcv.load_frame.index },
8028 dst_mcv.load_frame.off + 8,
8029 Type.usize,
8030 .{ .register = .rdx },
8031 );
8032 try self.genSetMem(
8033 .{ .frame = dst_mcv.load_frame.index },
8034 dst_mcv.load_frame.off + 0,
8035 Type.usize,
8036 .{ .register = .rax },
8037 );
8035 try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax });
8036 try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx });
8037 try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne });
80388038 break :result dst_mcv;
80398039 };
80408040 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
......@@ -8065,15 +8065,15 @@ fn atomicOp(
80658065 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
80668066 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
80678067 const ptr_mem = switch (ptr_mcv) {
8068 .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),
8069 .lea_frame => |frame_addr| Memory.sib(ptr_size, .{
8070 .base = .{ .frame = frame_addr.index },
8071 .disp = frame_addr.off,
8068 .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
8069 else => Memory.sib(ptr_size, .{
8070 .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
80728071 }),
8073 else => Memory.sib(ptr_size, .{ .base = .{
8074 .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
8075 } }),
80768072 };
8073 switch (ptr_mem) {
8074 .sib, .rip => {},
8075 .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
8076 }
80778077 const mem_lock = switch (ptr_mem.base()) {
80788078 .none, .frame => null,
80798079 .reg => |reg| self.register_manager.lockReg(reg),