| ... | ... | @@ -219,9 +219,9 @@ pub const MCValue = union(enum) { |
| 219 | 219 | .dead, |
| 220 | 220 | .undef, |
| 221 | 221 | .immediate, |
| 222 | .eflags, |
| 222 | 223 | .register, |
| 223 | 224 | .register_offset, |
| 224 | | .eflags, |
| 225 | 225 | .register_overflow, |
| 226 | 226 | .lea_direct, |
| 227 | 227 | .lea_got, |
| ... | ... | @@ -297,6 +297,41 @@ pub const MCValue = union(enum) { |
| 297 | 297 | }; |
| 298 | 298 | } |
| 299 | 299 | |
| 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 | |
| 300 | 335 | pub fn format( |
| 301 | 336 | mcv: MCValue, |
| 302 | 337 | comptime _: []const u8, |
| ... | ... | @@ -7936,70 +7971,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 7936 | 7971 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 7937 | 7972 | |
| 7938 | 7973 | const ptr_ty = self.air.typeOf(extra.ptr); |
| 7939 | | const ptr_mcv = try self.resolveInst(extra.ptr); |
| 7940 | 7974 | const val_ty = self.air.typeOf(extra.expected_value); |
| 7941 | 7975 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 7942 | 7976 | |
| 7943 | 7977 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); |
| 7944 | 7978 | 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); |
| 7946 | 7980 | |
| 7947 | 7981 | 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()); |
| 7960 | 7985 | } 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); |
| 7963 | 7986 | |
| 7964 | 7987 | 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; |
| 7978 | 7992 | } 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); |
| 7981 | 7995 | |
| 7996 | const ptr_mcv = try self.resolveInst(extra.ptr); |
| 7982 | 7997 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 7983 | 7998 | 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) }, |
| 7988 | 8002 | }), |
| 7989 | | else => Memory.sib(ptr_size, .{ .base = .{ |
| 7990 | | .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv), |
| 7991 | | } }), |
| 7992 | 8003 | }; |
| 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()) { |
| 7994 | 8009 | .none, .frame => null, |
| 7995 | 8010 | .reg => |reg| self.register_manager.lockReg(reg), |
| 7996 | 8011 | }; |
| 7997 | | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| 8012 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 7998 | 8013 | |
| 7999 | 8014 | try self.spillEflagsIfOccupied(); |
| 8000 | 8015 | if (val_abi_size <= 8) { |
| 8001 | 8016 | _ = 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), |
| 8003 | 8018 | .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), |
| 8004 | 8019 | } } }); |
| 8005 | 8020 | } else { |
| ... | ... | @@ -8017,24 +8032,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 8017 | 8032 | } |
| 8018 | 8033 | |
| 8019 | 8034 | 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 }); |
| 8038 | 8038 | break :result dst_mcv; |
| 8039 | 8039 | }; |
| 8040 | 8040 | return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| ... | ... | @@ -8065,15 +8065,15 @@ fn atomicOp( |
| 8065 | 8065 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 8066 | 8066 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 8067 | 8067 | 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) }, |
| 8072 | 8071 | }), |
| 8073 | | else => Memory.sib(ptr_size, .{ .base = .{ |
| 8074 | | .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv), |
| 8075 | | } }), |
| 8076 | 8072 | }; |
| 8073 | switch (ptr_mem) { |
| 8074 | .sib, .rip => {}, |
| 8075 | .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), |
| 8076 | } |
| 8077 | 8077 | const mem_lock = switch (ptr_mem.base()) { |
| 8078 | 8078 | .none, .frame => null, |
| 8079 | 8079 | .reg => |reg| self.register_manager.lockReg(reg), |