mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
x86_64: fix 128-bit cmpxchg
This commit is contained in:
parent
50f96c2949
commit
aaef5288f8
@ -219,9 +219,9 @@ pub const MCValue = union(enum) {
|
||||
.dead,
|
||||
.undef,
|
||||
.immediate,
|
||||
.eflags,
|
||||
.register,
|
||||
.register_offset,
|
||||
.eflags,
|
||||
.register_overflow,
|
||||
.lea_direct,
|
||||
.lea_got,
|
||||
@ -297,6 +297,41 @@ pub const MCValue = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
fn mem(mcv: MCValue, ptr_size: Memory.PtrSize) Memory {
|
||||
return switch (mcv) {
|
||||
.none,
|
||||
.unreach,
|
||||
.dead,
|
||||
.undef,
|
||||
.immediate,
|
||||
.eflags,
|
||||
.register,
|
||||
.register_offset,
|
||||
.register_overflow,
|
||||
.load_direct,
|
||||
.lea_direct,
|
||||
.load_got,
|
||||
.lea_got,
|
||||
.load_tlv,
|
||||
.lea_tlv,
|
||||
.lea_frame,
|
||||
.reserved_frame,
|
||||
=> unreachable,
|
||||
.memory => |addr| if (math.cast(i32, @bitCast(i64, addr))) |small_addr|
|
||||
Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr })
|
||||
else
|
||||
Memory.moffs(.ds, addr),
|
||||
.indirect => |reg_off| Memory.sib(ptr_size, .{
|
||||
.base = .{ .reg = reg_off.reg },
|
||||
.disp = reg_off.off,
|
||||
}),
|
||||
.load_frame => |frame_addr| Memory.sib(ptr_size, .{
|
||||
.base = .{ .frame = frame_addr.index },
|
||||
.disp = frame_addr.off,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
mcv: MCValue,
|
||||
comptime _: []const u8,
|
||||
@ -7936,70 +7971,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
|
||||
|
||||
const ptr_ty = self.air.typeOf(extra.ptr);
|
||||
const ptr_mcv = try self.resolveInst(extra.ptr);
|
||||
const val_ty = self.air.typeOf(extra.expected_value);
|
||||
const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
|
||||
|
||||
try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
|
||||
const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
|
||||
for (regs_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
|
||||
const exp_mcv = try self.resolveInst(extra.expected_value);
|
||||
if (val_abi_size > 8) switch (exp_mcv) {
|
||||
.load_frame => |frame_addr| {
|
||||
try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{
|
||||
.index = frame_addr.index,
|
||||
.off = frame_addr.off + 0,
|
||||
} });
|
||||
try self.genSetReg(.rdx, Type.usize, .{ .load_frame = .{
|
||||
.index = frame_addr.index,
|
||||
.off = frame_addr.off + 8,
|
||||
} });
|
||||
},
|
||||
else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
|
||||
if (val_abi_size > 8) {
|
||||
try self.genSetReg(.rax, Type.usize, exp_mcv);
|
||||
try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref());
|
||||
} else try self.genSetReg(.rax, val_ty, exp_mcv);
|
||||
const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
|
||||
defer self.register_manager.unlockReg(rax_lock);
|
||||
|
||||
const new_mcv = try self.resolveInst(extra.new_value);
|
||||
const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) {
|
||||
.load_frame => |frame_addr| new: {
|
||||
try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{
|
||||
.index = frame_addr.index,
|
||||
.off = frame_addr.off + 0,
|
||||
} });
|
||||
try self.genSetReg(.rcx, Type.usize, .{ .load_frame = .{
|
||||
.index = frame_addr.index,
|
||||
.off = frame_addr.off + 8,
|
||||
} });
|
||||
break :new undefined;
|
||||
},
|
||||
else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
|
||||
const new_reg = if (val_abi_size > 8) new: {
|
||||
try self.genSetReg(.rbx, Type.usize, new_mcv);
|
||||
try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref());
|
||||
break :new null;
|
||||
} else try self.copyToTmpRegister(val_ty, new_mcv);
|
||||
const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
|
||||
defer self.register_manager.unlockReg(new_lock);
|
||||
const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
|
||||
defer if (new_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
|
||||
const ptr_mcv = try self.resolveInst(extra.ptr);
|
||||
const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
|
||||
const ptr_mem = switch (ptr_mcv) {
|
||||
.register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),
|
||||
.lea_frame => |frame_addr| Memory.sib(ptr_size, .{
|
||||
.base = .{ .frame = frame_addr.index },
|
||||
.disp = frame_addr.off,
|
||||
.immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
|
||||
else => Memory.sib(ptr_size, .{
|
||||
.base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
|
||||
}),
|
||||
else => Memory.sib(ptr_size, .{ .base = .{
|
||||
.reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
|
||||
} }),
|
||||
};
|
||||
const mem_lock = switch (ptr_mem.base()) {
|
||||
switch (ptr_mem) {
|
||||
.sib, .rip => {},
|
||||
.moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
|
||||
}
|
||||
const ptr_lock = switch (ptr_mem.base()) {
|
||||
.none, .frame => null,
|
||||
.reg => |reg| self.register_manager.lockReg(reg),
|
||||
};
|
||||
defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
|
||||
|
||||
try self.spillEflagsIfOccupied();
|
||||
if (val_abi_size <= 8) {
|
||||
_ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
|
||||
.r = registerAlias(new_reg, val_abi_size),
|
||||
.r = registerAlias(new_reg.?, val_abi_size),
|
||||
.payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
|
||||
} } });
|
||||
} else {
|
||||
@ -8017,24 +8032,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
|
||||
}
|
||||
|
||||
const dst_mcv = try self.allocRegOrMem(inst, false);
|
||||
try self.genSetMem(
|
||||
.{ .frame = dst_mcv.load_frame.index },
|
||||
dst_mcv.load_frame.off + 16,
|
||||
Type.bool,
|
||||
.{ .eflags = .ne },
|
||||
);
|
||||
try self.genSetMem(
|
||||
.{ .frame = dst_mcv.load_frame.index },
|
||||
dst_mcv.load_frame.off + 8,
|
||||
Type.usize,
|
||||
.{ .register = .rdx },
|
||||
);
|
||||
try self.genSetMem(
|
||||
.{ .frame = dst_mcv.load_frame.index },
|
||||
dst_mcv.load_frame.off + 0,
|
||||
Type.usize,
|
||||
.{ .register = .rax },
|
||||
);
|
||||
try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax });
|
||||
try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx });
|
||||
try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne });
|
||||
break :result dst_mcv;
|
||||
};
|
||||
return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
|
||||
@ -8065,15 +8065,15 @@ fn atomicOp(
|
||||
const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
|
||||
const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
|
||||
const ptr_mem = switch (ptr_mcv) {
|
||||
.register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),
|
||||
.lea_frame => |frame_addr| Memory.sib(ptr_size, .{
|
||||
.base = .{ .frame = frame_addr.index },
|
||||
.disp = frame_addr.off,
|
||||
.immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
|
||||
else => Memory.sib(ptr_size, .{
|
||||
.base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
|
||||
}),
|
||||
else => Memory.sib(ptr_size, .{ .base = .{
|
||||
.reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
|
||||
} }),
|
||||
};
|
||||
switch (ptr_mem) {
|
||||
.sib, .rip => {},
|
||||
.moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
|
||||
}
|
||||
const mem_lock = switch (ptr_mem.base()) {
|
||||
.none, .frame => null,
|
||||
.reg => |reg| self.register_manager.lockReg(reg),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user