authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-28 20:02:28-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-01 19:22:52-04:00
logc3889600424e3720dc07b22397129f82f2111d72
treeda4dd704ae943f5fa9db33ba4cce8e15166172d7
parent00ae3592e6d054276b61404808d016dc2ef7ced5

x86_64: fix large not and atomicrmw


3 files changed, 86 insertions(+), 116 deletions(-)

src/arch/x86_64/CodeGen.zig+86-114
......@@ -2050,13 +2050,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
20502050 registerAlias(src_reg, min_abi_size),
20512051 );
20522052 },
2053 .load_frame => |frame_addr| try self.asmRegisterMemory(
2053 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
20542054 tag,
20552055 dst_alias,
2056 Memory.sib(Memory.PtrSize.fromSize(min_abi_size), .{
2057 .base = .{ .frame = frame_addr.index },
2058 .disp = frame_addr.off,
2059 }),
2056 src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)),
20602057 ),
20612058 else => return self.fail("TODO airIntCast from {s} to {s}", .{
20622059 @tagName(src_mcv),
......@@ -2738,19 +2735,9 @@ fn genIntMulDivOpMir(
27382735 };
27392736 switch (mat_rhs) {
27402737 .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),
2741 .indirect, .load_frame => try self.asmMemory(
2738 .memory, .indirect, .load_frame => try self.asmMemory(
27422739 tag,
2743 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {
2744 .indirect => |reg_off| .{
2745 .base = .{ .reg = reg_off.reg },
2746 .disp = reg_off.off,
2747 },
2748 .load_frame => |frame_addr| .{
2749 .base = .{ .frame = frame_addr.index },
2750 .disp = frame_addr.off,
2751 },
2752 else => unreachable,
2753 }),
2740 mat_rhs.mem(Memory.PtrSize.fromSize(abi_size)),
27542741 ),
27552742 else => unreachable,
27562743 }
......@@ -4628,9 +4615,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
46284615 if (src_ty.zigTypeTag() == .Vector) {
46294616 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
46304617 }
4631 if (src_ty.abiSize(self.target.*) > 8) {
4632 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
4633 }
46344618
46354619 switch (src_mcv) {
46364620 .eflags => |cc| switch (tag) {
......@@ -4646,13 +4630,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
46464630 };
46474631 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
46484632
4649 const dst_mcv: MCValue = if (maybe_inst) |inst|
4650 if (self.reuseOperand(inst, src_air, 0, src_mcv))
4651 src_mcv
4652 else
4653 try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv)
4654 else
4655 .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) };
4633 const dst_mcv: MCValue = dst: {
4634 if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv;
4635
4636 const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true);
4637 try self.genCopy(src_ty, dst_mcv, src_mcv);
4638 break :dst dst_mcv;
4639 };
46564640 const dst_lock = switch (dst_mcv) {
46574641 .register => |reg| self.register_manager.lockReg(reg),
46584642 else => null,
......@@ -4661,19 +4645,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
46614645
46624646 switch (tag) {
46634647 .not => {
4648 const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8));
46644649 const int_info = if (src_ty.tag() == .bool)
46654650 std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 }
46664651 else
46674652 src_ty.intInfo(self.target.*);
4668 const extra_bits = self.regExtraBits(src_ty);
4669 if (int_info.signedness == .unsigned and extra_bits > 0) {
4670 const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1;
4671 try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask });
4672 } else try self.genUnOpMir(.not, src_ty, dst_mcv);
4673 },
4653 var byte_off: i32 = 0;
4654 while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) {
4655 var limb_pl = Type.Payload.Bits{
4656 .base = .{ .tag = switch (int_info.signedness) {
4657 .signed => .int_signed,
4658 .unsigned => .int_unsigned,
4659 } },
4660 .data = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)),
4661 };
4662 const limb_ty = Type.initPayload(&limb_pl.base);
4663 const limb_mcv = switch (byte_off) {
4664 0 => dst_mcv,
4665 else => dst_mcv.address().offset(byte_off).deref(),
4666 };
46744667
4668 if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) {
4669 const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data);
4670 try self.genBinOpMir(.xor, limb_ty, limb_mcv, .{ .immediate = mask });
4671 } else try self.genUnOpMir(.not, limb_ty, limb_mcv);
4672 }
4673 },
46754674 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),
4676
46774675 else => unreachable,
46784676 }
46794677 return dst_mcv;
......@@ -4714,17 +4712,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
47144712 },
47154713 .indirect, .load_frame => try self.asmMemory(
47164714 mir_tag,
4717 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (dst_mcv) {
4718 .indirect => |reg_off| .{
4719 .base = .{ .reg = reg_off.reg },
4720 .disp = reg_off.off,
4721 },
4722 .load_frame => |frame_addr| .{
4723 .base = .{ .frame = frame_addr.index },
4724 .disp = frame_addr.off,
4725 },
4726 else => unreachable,
4727 }),
4715 dst_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
47284716 ),
47294717 }
47304718}
......@@ -8179,12 +8167,9 @@ fn atomicOp(
81798167 registerAlias(val_reg, cmov_abi_size),
81808168 cc,
81818169 ),
8182 .load_frame => |frame_addr| try self.asmCmovccRegisterMemory(
8170 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
81838171 registerAlias(tmp_reg, cmov_abi_size),
8184 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{
8185 .base = .{ .frame = frame_addr.index },
8186 .disp = frame_addr.off,
8187 }),
8172 val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
81888173 cc,
81898174 ),
81908175 else => {
......@@ -8207,72 +8192,62 @@ fn atomicOp(
82078192 } else {
82088193 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
82098194 .base = ptr_mem.sib.base,
8210 .scale_index = ptr_mem.sib.scale_index,
8195 .scale_index = ptr_mem.scaleIndex(),
82118196 .disp = ptr_mem.sib.disp + 0,
82128197 }));
82138198 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{
82148199 .base = ptr_mem.sib.base,
8215 .scale_index = ptr_mem.sib.scale_index,
8200 .scale_index = ptr_mem.scaleIndex(),
82168201 .disp = ptr_mem.sib.disp + 8,
82178202 }));
82188203 const loop = @intCast(u32, self.mir_instructions.len);
8219 switch (val_mcv) {
8220 .load_frame => |frame_addr| {
8221 const val_lo_mem = Memory.sib(.qword, .{
8222 .base = .{ .frame = frame_addr.index },
8223 .disp = frame_addr.off + 0,
8224 });
8225 const val_hi_mem = Memory.sib(.qword, .{
8226 .base = .{ .frame = frame_addr.index },
8227 .disp = frame_addr.off + 8,
8228 });
8229
8230 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
8231 try self.asmRegisterRegister(.mov, .rbx, .rax);
8232 try self.asmRegisterRegister(.mov, .rcx, .rdx);
8233 }
8234 if (rmw_op) |op| switch (op) {
8235 .Xchg => {
8236 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
8237 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
8238 },
8239 .Add => {
8240 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
8241 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
8242 },
8243 .Sub => {
8244 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
8245 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
8246 },
8247 .And => {
8248 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8249 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8250 },
8251 .Nand => {
8252 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8253 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8254 try self.asmRegister(.not, .rbx);
8255 try self.asmRegister(.not, .rcx);
8256 },
8257 .Or => {
8258 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
8259 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
8260 },
8261 .Xor => {
8262 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
8263 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
8264 },
8265 else => return self.fail(
8266 "TODO implement x86 atomic loop for large abi {s}",
8267 .{@tagName(op)},
8268 ),
8269 };
8270 },
8271 else => return self.fail(
8272 "TODO implement x86 atomic loop for large abi {s}",
8273 .{@tagName(val_mcv)},
8274 ),
8204 const val_mem_mcv: MCValue = switch (val_mcv) {
8205 .memory, .indirect, .load_frame => val_mcv,
8206 else => .{ .indirect = .{
8207 .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()),
8208 } },
8209 };
8210 const val_lo_mem = val_mem_mcv.mem(.qword);
8211 const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword);
8212 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
8213 try self.asmRegisterRegister(.mov, .rbx, .rax);
8214 try self.asmRegisterRegister(.mov, .rcx, .rdx);
82758215 }
8216 if (rmw_op) |op| switch (op) {
8217 .Xchg => {
8218 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
8219 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
8220 },
8221 .Add => {
8222 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
8223 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
8224 },
8225 .Sub => {
8226 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
8227 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
8228 },
8229 .And => {
8230 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8231 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8232 },
8233 .Nand => {
8234 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8235 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8236 try self.asmRegister(.not, .rbx);
8237 try self.asmRegister(.not, .rcx);
8238 },
8239 .Or => {
8240 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
8241 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
8242 },
8243 .Xor => {
8244 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
8245 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
8246 },
8247 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{
8248 val_ty.fmt(self.bin_file.options.module.?), @tagName(op),
8249 }),
8250 };
82768251 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
82778252 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
82788253 } });
......@@ -9177,15 +9152,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
91779152}
91789153
91799154fn regBitSize(self: *Self, ty: Type) u64 {
9155 const abi_size = ty.abiSize(self.target.*);
91809156 return switch (ty.zigTypeTag()) {
9181 else => switch (ty.abiSize(self.target.*)) {
9157 else => switch (abi_size) {
91829158 1 => 8,
91839159 2 => 16,
91849160 3...4 => 32,
91859161 5...8 => 64,
91869162 else => unreachable,
91879163 },
9188 .Float => switch (ty.abiSize(self.target.*)) {
9164 .Float => switch (abi_size) {
91899165 1...16 => 128,
91909166 17...32 => 256,
91919167 else => unreachable,
......@@ -9197,10 +9173,6 @@ fn regExtraBits(self: *Self, ty: Type) u64 {
91979173 return self.regBitSize(ty) - ty.bitSize(self.target.*);
91989174}
91999175
9200fn hasAvxSupport(target: Target) bool {
9201 return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 });
9202}
9203
92049176fn getSymbolIndexForDecl(self: *Self, decl_index: Module.Decl.Index) !u32 {
92059177 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
92069178 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
test/behavior/atomics.zig-1
......@@ -112,7 +112,6 @@ test "128-bit cmpxchg" {
112112 if (!supports_128_bit_atomics) return error.SkipZigTest;
113113
114114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
116115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
117116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/math.zig-1
......@@ -379,7 +379,6 @@ fn testBinaryNot(x: u16) !void {
379379
380380test "binary not 128-bit" {
381381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
383382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
384383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO