authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-06 03:07:14-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-07 00:29:17-04:00
log20b4401cdef1baa377276ecae31f266cf85d4d2e
treed997c575701d7b7314b5f15bbd8933311dfe5904
parent5aeb13c3500f2244efe916a88278a86692dfc400

x86_64: implement negation and `@abs` for `f80`

Also implement live-outs since the x87 requires so much care around liveness tracking.

7 files changed, 337 insertions(+), 221 deletions(-)

src/arch/x86_64/CodeGen.zig+313-207
......@@ -47,10 +47,6 @@ const RegisterManager = abi.RegisterManager;
4747const RegisterLock = RegisterManager.RegisterLock;
4848const FrameIndex = bits.FrameIndex;
4949
50const gp = abi.RegisterClass.gp;
51const x87 = abi.RegisterClass.x87;
52const sse = abi.RegisterClass.sse;
53
5450const InnerError = CodeGenError || error{OutOfRegisters};
5551
5652gpa: Allocator,
......@@ -620,6 +616,7 @@ const InstTracking = struct {
620616 }
621617
622618 fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
619 if (self.short == .dead) return;
623620 try function.freeValue(self.short);
624621 self.short = .{ .dead = function.scope_generation };
625622 tracking_log.debug("%{d} => {} (death)", .{ inst, self.* });
......@@ -635,6 +632,40 @@ const InstTracking = struct {
635632 tracking_log.debug("%{d} => {} (reuse %{d})", .{ new_inst, self.*, old_inst });
636633 }
637634
635 fn liveOut(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void {
636 for (self.short.getRegs()) |reg| {
637 if (function.register_manager.isRegFree(reg)) {
638 tracking_log.debug("%{d} => {} (live-out)", .{ inst, self.* });
639 continue;
640 }
641
642 const index = RegisterManager.indexOfRegIntoTracked(reg).?;
643 const tracked_inst = function.register_manager.registers[index];
644 const tracking = function.getResolvedInstValue(tracked_inst);
645
646 // Disable death.
647 var found_reg = false;
648 var remaining_reg: Register = .none;
649 for (tracking.short.getRegs()) |tracked_reg| if (tracked_reg.id() == reg.id()) {
650 assert(!found_reg);
651 found_reg = true;
652 } else {
653 assert(remaining_reg == .none);
654 remaining_reg = tracked_reg;
655 };
656 assert(found_reg);
657 tracking.short = switch (remaining_reg) {
658 .none => .{ .dead = function.scope_generation },
659 else => .{ .register = remaining_reg },
660 };
661
662 // Perform side-effects of freeValue manually.
663 function.register_manager.freeReg(reg);
664
665 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, self.*, tracked_inst });
666 }
667 }
668
638669 pub fn format(
639670 self: InstTracking,
640671 comptime _: []const u8,
......@@ -1144,7 +1175,7 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
11441175 } },
11451176 .z_and_np, .nz_or_p => .{ .rr = .{
11461177 .r1 = reg,
1147 .r2 = (try self.register_manager.allocReg(null, gp)).to8(),
1178 .r2 = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to8(),
11481179 } },
11491180 },
11501181 });
......@@ -1184,7 +1215,7 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
11841215 .payload = payload,
11851216 } },
11861217 .z_and_np, .nz_or_p => .{ .rx = .{
1187 .r1 = (try self.register_manager.allocReg(null, gp)).to8(),
1218 .r1 = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to8(),
11881219 .payload = payload,
11891220 } },
11901221 },
......@@ -2087,7 +2118,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
20872118 var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount(mod));
20882119 defer self.gpa.free(exitlude_jump_relocs);
20892120
2090 const data_reg = try self.register_manager.allocReg(null, gp);
2121 const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
20912122 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
20922123 defer self.register_manager.unlockReg(data_lock);
20932124 try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
......@@ -2357,7 +2388,7 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b
23572388 },
23582389 else => 8,
23592390 })) {
2360 if (self.register_manager.tryAllocReg(inst, regClassForType(ty, mod))) |reg| {
2391 if (self.register_manager.tryAllocReg(inst, self.regClassForType(ty))) |reg| {
23612392 return MCValue{ .register = registerAlias(reg, abi_size) };
23622393 }
23632394 }
......@@ -2367,10 +2398,15 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b
23672398 return .{ .load_frame = .{ .index = frame_index } };
23682399}
23692400
2370fn regClassForType(ty: Type, mod: *Module) RegisterManager.RegisterBitSet {
2401fn regClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet {
2402 const mod = self.bin_file.options.module.?;
23712403 return switch (ty.zigTypeTag(mod)) {
2372 .Float, .Vector => sse,
2373 else => gp,
2404 .Float => switch (ty.floatBits(self.target.*)) {
2405 80 => abi.RegisterClass.x87,
2406 else => abi.RegisterClass.sse,
2407 },
2408 .Vector => abi.RegisterClass.sse,
2409 else => abi.RegisterClass.gp,
23742410 };
23752411}
23762412
......@@ -2510,8 +2546,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void {
25102546/// allocated. A second call to `copyToTmpRegister` may return the same register.
25112547/// This can have a side effect of spilling instructions to the stack to free up a register.
25122548fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
2513 const mod = self.bin_file.options.module.?;
2514 const reg = try self.register_manager.allocReg(null, regClassForType(ty, mod));
2549 const reg = try self.register_manager.allocReg(null, self.regClassForType(ty));
25152550 try self.genSetReg(reg, ty, mcv);
25162551 return reg;
25172552}
......@@ -2526,8 +2561,7 @@ fn copyToRegisterWithInstTracking(
25262561 ty: Type,
25272562 mcv: MCValue,
25282563) !MCValue {
2529 const mod = self.bin_file.options.module.?;
2530 const reg: Register = try self.register_manager.allocReg(reg_owner, regClassForType(ty, mod));
2564 const reg: Register = try self.register_manager.allocReg(reg_owner, self.regClassForType(ty));
25312565 try self.genSetReg(reg, ty, mcv);
25322566 return MCValue{ .register = reg };
25332567}
......@@ -3084,7 +3118,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
30843118 };
30853119 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
30863120
3087 const limit_reg = try self.register_manager.allocReg(null, gp);
3121 const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
30883122 const limit_mcv = MCValue{ .register = limit_reg };
30893123 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
30903124 defer self.register_manager.unlockReg(limit_lock);
......@@ -3167,7 +3201,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
31673201 };
31683202 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
31693203
3170 const limit_reg = try self.register_manager.allocReg(null, gp);
3204 const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
31713205 const limit_mcv = MCValue{ .register = limit_reg };
31723206 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
31733207 defer self.register_manager.unlockReg(limit_lock);
......@@ -3245,7 +3279,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
32453279 };
32463280 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
32473281
3248 const limit_reg = try self.register_manager.allocReg(null, gp);
3282 const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
32493283 const limit_mcv = MCValue{ .register = limit_reg };
32503284 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
32513285 defer self.register_manager.unlockReg(limit_lock);
......@@ -3433,7 +3467,8 @@ fn genSetFrameTruncatedOverflowCompare(
34333467
34343468 const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_limb_bits);
34353469
3436 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);
3470 const temp_regs =
3471 try self.register_manager.allocRegs(3, .{ null, null, null }, abi.RegisterClass.gp);
34373472 const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
34383473 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
34393474
......@@ -3851,7 +3886,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
38513886 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
38523887 defer self.register_manager.unlockReg(src_lock);
38533888
3854 const dst_reg = try self.register_manager.allocReg(inst, gp);
3889 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
38553890 const dst_mcv = MCValue{ .register = dst_reg };
38563891 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
38573892 defer self.register_manager.unlockReg(dst_lock);
......@@ -3891,7 +3926,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
38913926 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
38923927 src_reg
38933928 else
3894 try self.register_manager.allocReg(inst, gp);
3929 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
38953930 const dst_mcv = MCValue{ .register = dst_reg };
38963931 const dst_lock = self.register_manager.lockReg(dst_reg);
38973932 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -3942,7 +3977,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
39423977 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
39433978 src_reg
39443979 else
3945 try self.register_manager.allocReg(inst, gp);
3980 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
39463981 const dst_lock = self.register_manager.lockReg(dst_reg);
39473982 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
39483983
......@@ -4115,7 +4150,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
41154150 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
41164151 src_reg
41174152 else
4118 try self.register_manager.allocReg(inst, gp);
4153 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
41194154 const dst_mcv = MCValue{ .register = dst_reg };
41204155 const dst_lock = self.register_manager.lockReg(dst_reg);
41214156 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -4152,7 +4187,7 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi
41524187 .immediate => |imm| {
41534188 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`
41544189 // and set the register directly to the scaled offset as an immediate.
4155 const reg = try self.register_manager.allocReg(null, gp);
4190 const reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
41564191 try self.genSetReg(reg, index_ty, .{ .immediate = imm * elem_size });
41574192 break :blk reg;
41584193 },
......@@ -4192,7 +4227,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
41924227 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
41934228 defer self.register_manager.unlockReg(offset_reg_lock);
41944229
4195 const addr_reg = try self.register_manager.allocReg(null, gp);
4230 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
41964231 try self.genSetReg(addr_reg, Type.usize, slice_mcv);
41974232 // TODO we could allocate register here, but need to expect addr register and potentially
41984233 // offset register.
......@@ -4249,7 +4284,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
42494284 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
42504285 defer self.register_manager.unlockReg(offset_reg_lock);
42514286
4252 const addr_reg = try self.register_manager.allocReg(null, gp);
4287 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
42534288 switch (array) {
42544289 .register => {
42554290 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, mod));
......@@ -4486,7 +4521,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
44864521 };
44874522 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
44884523
4489 const dst_reg = try self.register_manager.allocReg(inst, gp);
4524 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
44904525 const dst_mcv = MCValue{ .register = dst_reg };
44914526 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
44924527 defer self.register_manager.unlockReg(dst_lock);
......@@ -4510,7 +4545,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
45104545 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });
45114546 }
45124547 } else if (src_bits <= 128) {
4513 const tmp_reg = try self.register_manager.allocReg(null, gp);
4548 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
45144549 const tmp_mcv = MCValue{ .register = tmp_reg };
45154550 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
45164551 defer self.register_manager.unlockReg(tmp_lock);
......@@ -4616,7 +4651,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
46164651 };
46174652 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
46184653
4619 const dst_reg = try self.register_manager.allocReg(inst, gp);
4654 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
46204655 const dst_mcv = MCValue{ .register = dst_reg };
46214656 const dst_lock = self.register_manager.lockReg(dst_reg);
46224657 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -4643,7 +4678,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
46434678 } else mat_src_mcv;
46444679 try self.genBinOpMir(.{ ._, .tzcnt }, wide_ty, dst_mcv, masked_mcv);
46454680 } else if (src_bits <= 128) {
4646 const tmp_reg = try self.register_manager.allocReg(null, gp);
4681 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
46474682 const tmp_mcv = MCValue{ .register = tmp_reg };
46484683 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
46494684 defer self.register_manager.unlockReg(tmp_lock);
......@@ -4718,7 +4753,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
47184753 if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
47194754 src_mcv
47204755 else
4721 .{ .register = try self.register_manager.allocReg(inst, gp) };
4756 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.gp) };
47224757
47234758 const popcnt_ty = if (src_abi_size > 1) src_ty else Type.u16;
47244759 try self.genBinOpMir(.{ ._, .popcnt }, popcnt_ty, dst_mcv, mat_src_mcv);
......@@ -4739,7 +4774,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
47394774 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
47404775 defer self.register_manager.unlockReg(dst_lock);
47414776
4742 const tmp_reg = try self.register_manager.allocReg(null, gp);
4777 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
47434778 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
47444779 defer self.register_manager.unlockReg(tmp_lock);
47454780
......@@ -4747,7 +4782,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
47474782 const dst = registerAlias(dst_reg, src_abi_size);
47484783 const tmp = registerAlias(tmp_reg, src_abi_size);
47494784 const imm = if (src_abi_size > 4)
4750 try self.register_manager.allocReg(null, gp)
4785 try self.register_manager.allocReg(null, abi.RegisterClass.gp)
47514786 else
47524787 undefined;
47534788
......@@ -4848,7 +4883,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
48484883 const dst_mcv: MCValue = if (mem_ok)
48494884 try self.allocRegOrMem(inst, true)
48504885 else
4851 .{ .register = try self.register_manager.allocReg(inst, gp) };
4886 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.gp) };
48524887 if (dst_mcv.isRegister()) {
48534888 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_mcv.register);
48544889 defer self.register_manager.unlockReg(dst_lock);
......@@ -4863,7 +4898,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
48634898 return dst_mcv;
48644899 }
48654900
4866 const dst_reg = try self.register_manager.allocReg(inst, gp);
4901 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
48674902 const dst_mcv = MCValue{ .register = dst_reg };
48684903 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
48694904 defer self.register_manager.unlockReg(dst_lock);
......@@ -4906,7 +4941,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
49064941 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
49074942 defer self.register_manager.unlockReg(dst_lock);
49084943
4909 const tmp_reg = try self.register_manager.allocReg(null, gp);
4944 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
49104945 const tmp_lock = self.register_manager.lockReg(tmp_reg);
49114946 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
49124947
......@@ -4914,7 +4949,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
49144949 const dst = registerAlias(dst_reg, src_abi_size);
49154950 const tmp = registerAlias(tmp_reg, src_abi_size);
49164951 const imm = if (src_abi_size > 4)
4917 try self.register_manager.allocReg(null, gp)
4952 try self.register_manager.allocReg(null, abi.RegisterClass.gp)
49184953 else
49194954 undefined;
49204955
......@@ -5006,109 +5041,133 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
50065041fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void {
50075042 const mod = self.bin_file.options.module.?;
50085043 const tag = self.air.instructions.items(.tag)[inst];
5009 const abi_size: u32 = switch (ty.abiSize(mod)) {
5010 1...16 => 16,
5011 17...32 => 32,
5012 else => return self.fail("TODO implement floatSign for {}", .{
5013 ty.fmt(mod),
5014 }),
5015 };
5016 const scalar_bits = ty.scalarType(mod).floatBits(self.target.*);
5017 if (scalar_bits == 80) return self.fail("TODO implement floatSign for {}", .{
5018 ty.fmt(mod),
5019 });
50205044
5021 const src_mcv = try self.resolveInst(operand);
5022 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
5023 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
5045 const result = result: {
5046 const scalar_bits = ty.scalarType(mod).floatBits(self.target.*);
5047 if (scalar_bits == 80) {
5048 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement floatSign for {}", .{
5049 ty.fmt(mod),
5050 });
50245051
5025 const dst_mcv: MCValue = if (src_mcv.isRegister() and self.reuseOperand(inst, operand, 0, src_mcv))
5026 src_mcv
5027 else if (self.hasFeature(.avx))
5028 .{ .register = try self.register_manager.allocReg(inst, sse) }
5029 else
5030 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5031 const dst_reg = dst_mcv.getReg().?;
5032 const dst_lock = self.register_manager.lockReg(dst_reg);
5033 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5052 const src_mcv = try self.resolveInst(operand);
5053 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
5054 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
50345055
5035 const vec_ty = try mod.vectorType(.{
5036 .len = @divExact(abi_size * 8, scalar_bits),
5037 .child = (try mod.intType(.signed, scalar_bits)).ip_index,
5038 });
5056 const dst_mcv: MCValue = .{ .register = .st0 };
5057 if (std.meta.eql(src_mcv, dst_mcv) and self.reuseOperand(inst, operand, 0, src_mcv))
5058 try self.register_manager.getReg(.st0, inst);
50395059
5040 const sign_val = switch (tag) {
5041 .neg => try vec_ty.minInt(mod, vec_ty),
5042 .abs => try vec_ty.maxInt(mod, vec_ty),
5043 else => unreachable,
5044 };
5060 try self.genCopy(ty, dst_mcv, src_mcv);
5061 switch (tag) {
5062 .neg => try self.asmOpOnly(.{ .f_, .chs }),
5063 .abs => try self.asmOpOnly(.{ .f_, .abs }),
5064 else => unreachable,
5065 }
5066 break :result dst_mcv;
5067 }
50455068
5046 const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val });
5047 const sign_mem = if (sign_mcv.isMemory())
5048 sign_mcv.mem(Memory.PtrSize.fromSize(abi_size))
5049 else
5050 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5051 .base = .{ .reg = try self.copyToTmpRegister(Type.usize, sign_mcv.address()) },
5069 const abi_size: u32 = switch (ty.abiSize(mod)) {
5070 1...16 => 16,
5071 17...32 => 32,
5072 else => return self.fail("TODO implement floatSign for {}", .{
5073 ty.fmt(mod),
5074 }),
5075 };
5076
5077 const src_mcv = try self.resolveInst(operand);
5078 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
5079 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
5080
5081 const dst_mcv: MCValue = if (src_mcv.isRegister() and
5082 self.reuseOperand(inst, operand, 0, src_mcv))
5083 src_mcv
5084 else if (self.hasFeature(.avx))
5085 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
5086 else
5087 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5088 const dst_reg = dst_mcv.getReg().?;
5089 const dst_lock = self.register_manager.lockReg(dst_reg);
5090 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5091
5092 const vec_ty = try mod.vectorType(.{
5093 .len = @divExact(abi_size * 8, scalar_bits),
5094 .child = (try mod.intType(.signed, scalar_bits)).ip_index,
50525095 });
50535096
5054 if (self.hasFeature(.avx)) try self.asmRegisterRegisterMemory(
5055 switch (scalar_bits) {
5056 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {
5057 .neg => .{ .vp_, .xor },
5058 .abs => .{ .vp_, .@"and" },
5059 else => unreachable,
5060 } else switch (tag) {
5061 .neg => .{ .v_ps, .xor },
5062 .abs => .{ .v_ps, .@"and" },
5063 else => unreachable,
5064 },
5065 32 => switch (tag) {
5066 .neg => .{ .v_ps, .xor },
5067 .abs => .{ .v_ps, .@"and" },
5068 else => unreachable,
5069 },
5070 64 => switch (tag) {
5071 .neg => .{ .v_pd, .xor },
5072 .abs => .{ .v_pd, .@"and" },
5073 else => unreachable,
5074 },
5075 80 => return self.fail("TODO implement floatSign for {}", .{
5076 ty.fmt(self.bin_file.options.module.?),
5077 }),
5097 const sign_val = switch (tag) {
5098 .neg => try vec_ty.minInt(mod, vec_ty),
5099 .abs => try vec_ty.maxInt(mod, vec_ty),
50785100 else => unreachable,
5079 },
5080 registerAlias(dst_reg, abi_size),
5081 registerAlias(if (src_mcv.isRegister())
5082 src_mcv.getReg().?
5101 };
5102
5103 const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val });
5104 const sign_mem = if (sign_mcv.isMemory())
5105 sign_mcv.mem(Memory.PtrSize.fromSize(abi_size))
50835106 else
5084 try self.copyToTmpRegister(ty, src_mcv), abi_size),
5085 sign_mem,
5086 ) else try self.asmRegisterMemory(
5087 switch (scalar_bits) {
5088 16, 128 => switch (tag) {
5089 .neg => .{ .p_, .xor },
5090 .abs => .{ .p_, .@"and" },
5091 else => unreachable,
5092 },
5093 32 => switch (tag) {
5094 .neg => .{ ._ps, .xor },
5095 .abs => .{ ._ps, .@"and" },
5107 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5108 .base = .{ .reg = try self.copyToTmpRegister(Type.usize, sign_mcv.address()) },
5109 });
5110
5111 if (self.hasFeature(.avx)) try self.asmRegisterRegisterMemory(
5112 switch (scalar_bits) {
5113 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {
5114 .neg => .{ .vp_, .xor },
5115 .abs => .{ .vp_, .@"and" },
5116 else => unreachable,
5117 } else switch (tag) {
5118 .neg => .{ .v_ps, .xor },
5119 .abs => .{ .v_ps, .@"and" },
5120 else => unreachable,
5121 },
5122 32 => switch (tag) {
5123 .neg => .{ .v_ps, .xor },
5124 .abs => .{ .v_ps, .@"and" },
5125 else => unreachable,
5126 },
5127 64 => switch (tag) {
5128 .neg => .{ .v_pd, .xor },
5129 .abs => .{ .v_pd, .@"and" },
5130 else => unreachable,
5131 },
5132 80 => return self.fail("TODO implement floatSign for {}", .{
5133 ty.fmt(self.bin_file.options.module.?),
5134 }),
50965135 else => unreachable,
50975136 },
5098 64 => switch (tag) {
5099 .neg => .{ ._pd, .xor },
5100 .abs => .{ ._pd, .@"and" },
5137 registerAlias(dst_reg, abi_size),
5138 registerAlias(if (src_mcv.isRegister())
5139 src_mcv.getReg().?
5140 else
5141 try self.copyToTmpRegister(ty, src_mcv), abi_size),
5142 sign_mem,
5143 ) else try self.asmRegisterMemory(
5144 switch (scalar_bits) {
5145 16, 128 => switch (tag) {
5146 .neg => .{ .p_, .xor },
5147 .abs => .{ .p_, .@"and" },
5148 else => unreachable,
5149 },
5150 32 => switch (tag) {
5151 .neg => .{ ._ps, .xor },
5152 .abs => .{ ._ps, .@"and" },
5153 else => unreachable,
5154 },
5155 64 => switch (tag) {
5156 .neg => .{ ._pd, .xor },
5157 .abs => .{ ._pd, .@"and" },
5158 else => unreachable,
5159 },
5160 80 => return self.fail("TODO implement floatSign for {}", .{
5161 ty.fmt(self.bin_file.options.module.?),
5162 }),
51015163 else => unreachable,
51025164 },
5103 80 => return self.fail("TODO implement floatSign for {}", .{
5104 ty.fmt(self.bin_file.options.module.?),
5105 }),
5106 else => unreachable,
5107 },
5108 registerAlias(dst_reg, abi_size),
5109 sign_mem,
5110 );
5111 return self.finishAir(inst, dst_mcv, .{ operand, .none, .none });
5165 registerAlias(dst_reg, abi_size),
5166 sign_mem,
5167 );
5168 break :result dst_mcv;
5169 };
5170 return self.finishAir(inst, result, .{ operand, .none, .none });
51125171}
51135172
51145173fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
......@@ -5292,19 +5351,43 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
52925351 const ty = self.typeOf(un_op);
52935352 const abi_size: u32 = @intCast(ty.abiSize(mod));
52945353
5295 const src_mcv = try self.resolveInst(un_op);
5296 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
5297 src_mcv
5298 else
5299 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5300 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
5301 const dst_lock = self.register_manager.lockReg(dst_reg);
5302 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5303
53045354 const result: MCValue = result: {
5355 switch (ty.zigTypeTag(mod)) {
5356 .Float => {
5357 const float_bits = ty.floatBits(self.target.*);
5358 if (switch (float_bits) {
5359 16 => !self.hasFeature(.f16c),
5360 32, 64 => false,
5361 80, 128 => true,
5362 else => unreachable,
5363 }) {
5364 var callee: ["__sqrt?".len]u8 = undefined;
5365 break :result try self.genCall(.{ .lib = .{
5366 .return_type = ty.toIntern(),
5367 .param_types = &.{ty.toIntern()},
5368 .callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{
5369 floatLibcAbiPrefix(ty),
5370 floatLibcAbiSuffix(ty),
5371 }) catch unreachable,
5372 } }, &.{ty}, &.{.{ .air_ref = un_op }});
5373 }
5374 },
5375 else => {},
5376 }
5377
5378 const src_mcv = try self.resolveInst(un_op);
5379 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
5380 src_mcv
5381 else
5382 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5383 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
5384 const dst_lock = self.register_manager.lockReg(dst_reg);
5385 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5386
53055387 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
53065388 .Float => switch (ty.floatBits(self.target.*)) {
5307 16 => if (self.hasFeature(.f16c)) {
5389 16 => {
5390 assert(self.hasFeature(.f16c));
53085391 const mat_src_reg = if (src_mcv.isRegister())
53095392 src_mcv.getReg().?
53105393 else
......@@ -5318,10 +5401,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
53185401 Immediate.u(0b1_00),
53195402 );
53205403 break :result dst_mcv;
5321 } else null,
5404 },
53225405 32 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },
53235406 64 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },
5324 80, 128 => null,
53255407 else => unreachable,
53265408 },
53275409 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
......@@ -5395,21 +5477,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
53955477 else => unreachable,
53965478 },
53975479 else => unreachable,
5398 }) orelse {
5399 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement airSqrt for {}", .{
5400 ty.fmt(mod),
5401 });
5402
5403 var callee: ["__sqrt?".len]u8 = undefined;
5404 break :result try self.genCall(.{ .lib = .{
5405 .return_type = ty.toIntern(),
5406 .param_types = &.{ty.toIntern()},
5407 .callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{
5408 floatLibcAbiPrefix(ty),
5409 floatLibcAbiSuffix(ty),
5410 }) catch unreachable,
5411 } }, &.{ty}, &.{src_mcv});
5412 };
5480 }) orelse return self.fail("TODO implement airSqrt for {}", .{
5481 ty.fmt(mod),
5482 });
54135483 switch (mir_tag[0]) {
54145484 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
54155485 mir_tag,
......@@ -5536,7 +5606,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
55365606
55375607 const dst_reg = switch (dst_mcv) {
55385608 .register => |reg| reg,
5539 else => try self.register_manager.allocReg(null, gp),
5609 else => try self.register_manager.allocReg(null, abi.RegisterClass.gp),
55405610 };
55415611 const dst_lock = self.register_manager.lockReg(dst_reg);
55425612 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -5555,7 +5625,8 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
55555625 );
55565626 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off));
55575627 } else {
5558 const tmp_reg = registerAlias(try self.register_manager.allocReg(null, gp), val_abi_size);
5628 const tmp_reg =
5629 registerAlias(try self.register_manager.allocReg(null, abi.RegisterClass.gp), val_abi_size);
55595630 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
55605631 defer self.register_manager.unlockReg(tmp_lock);
55615632
......@@ -5640,8 +5711,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
56405711 const ptr_ty = self.typeOf(ty_op.operand);
56415712 const elem_size = elem_ty.abiSize(mod);
56425713
5643 const elem_rc = regClassForType(elem_ty, mod);
5644 const ptr_rc = regClassForType(ptr_ty, mod);
5714 const elem_rc = self.regClassForType(elem_ty);
5715 const ptr_rc = self.regClassForType(ptr_ty);
56455716
56465717 const ptr_mcv = try self.resolveInst(ty_op.operand);
56475718 const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and
......@@ -5696,13 +5767,13 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
56965767 } else if (math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| {
56975768 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.s(small));
56985769 } else {
5699 const part_mask_reg = try self.register_manager.allocReg(null, gp);
5770 const part_mask_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
57005771 try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, Immediate.u(part_mask_not));
57015772 try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);
57025773 }
57035774
57045775 if (src_bit_size <= 64) {
5705 const tmp_reg = try self.register_manager.allocReg(null, gp);
5776 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
57065777 const tmp_mcv = MCValue{ .register = tmp_reg };
57075778 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
57085779 defer self.register_manager.unlockReg(tmp_lock);
......@@ -5840,11 +5911,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
58405911 const index = extra.field_index;
58415912
58425913 const container_ty = self.typeOf(operand);
5843 const container_rc = regClassForType(container_ty, mod);
5914 const container_rc = self.regClassForType(container_ty);
58445915 const field_ty = container_ty.structFieldType(index, mod);
58455916 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;
5846 const field_rc = regClassForType(field_ty, mod);
5847 const field_is_gp = field_rc.supersetOf(gp);
5917 const field_rc = self.regClassForType(field_ty);
5918 const field_is_gp = field_rc.supersetOf(abi.RegisterClass.gp);
58485919
58495920 const src_mcv = try self.resolveInst(operand);
58505921 const field_off: u32 = switch (container_ty.containerLayout(mod)) {
......@@ -5868,8 +5939,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
58685939 @intCast(field_ty.bitSize(mod)),
58695940 );
58705941
5871 const dst_reg =
5872 try self.register_manager.allocReg(if (field_is_gp) inst else null, gp);
5942 const dst_reg = try self.register_manager.allocReg(
5943 if (field_is_gp) inst else null,
5944 abi.RegisterClass.gp,
5945 );
58735946 const dst_mcv = MCValue{ .register = dst_reg };
58745947 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
58755948 defer self.register_manager.unlockReg(dst_lock);
......@@ -5898,7 +5971,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
58985971 return self.fail("TODO implement struct_field_val with large packed field", .{});
58995972 }
59005973
5901 const dst_reg = try self.register_manager.allocReg(if (field_is_gp) inst else null, gp);
5974 const dst_reg = try self.register_manager.allocReg(
5975 if (field_is_gp) inst else null,
5976 abi.RegisterClass.gp,
5977 );
59025978 const field_extra_bits = self.regExtraBits(field_ty);
59035979 const load_abi_size =
59045980 if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2;
......@@ -5915,7 +5991,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
59155991 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off));
59165992 } else {
59175993 const tmp_reg = registerAlias(
5918 try self.register_manager.allocReg(null, gp),
5994 try self.register_manager.allocReg(null, abi.RegisterClass.gp),
59195995 field_abi_size,
59205996 );
59215997 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -5975,7 +6051,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
59756051 );
59766052 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
59776053
5978 break :result if (field_rc.supersetOf(gp))
6054 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
59796055 dst_mcv
59806056 else
59816057 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
......@@ -5996,7 +6072,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
59966072 self.eflags_inst = inst;
59976073 break :result .{ .eflags = ro.eflags };
59986074 } else {
5999 const dst_reg = try self.register_manager.allocReg(inst, gp);
6075 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
60006076 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
60016077 break :result .{ .register = dst_reg.to8() };
60026078 },
......@@ -6117,7 +6193,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
61176193 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
61186194 .register_pair => unreachable, // unimplemented
61196195 .memory, .load_got, .load_direct, .load_tlv => {
6120 const addr_reg = try self.register_manager.allocReg(null, gp);
6196 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
61216197 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
61226198 defer self.register_manager.unlockReg(addr_reg_lock);
61236199
......@@ -6219,7 +6295,7 @@ fn genShiftBinOpMir(
62196295 }),
62206296 }
62216297 } else if (abi_size <= 16) {
6222 const tmp_reg = try self.register_manager.allocReg(null, gp);
6298 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
62236299 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
62246300 defer self.register_manager.unlockReg(tmp_lock);
62256301
......@@ -6297,11 +6373,11 @@ fn genShiftBinOpMir(
62976373 }
62986374 },
62996375 else => {
6300 const first_reg = try self.register_manager.allocReg(null, gp);
6376 const first_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
63016377 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
63026378 defer self.register_manager.unlockReg(first_lock);
63036379
6304 const second_reg = try self.register_manager.allocReg(null, gp);
6380 const second_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
63056381 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
63066382 defer self.register_manager.unlockReg(second_lock);
63076383
......@@ -6663,7 +6739,7 @@ fn genBinOp(
66636739 if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: {
66646740 try self.register_manager.getReg(.xmm0, null);
66656741 break :mask .xmm0;
6666 } else try self.register_manager.allocReg(null, sse),
6742 } else try self.register_manager.allocReg(null, abi.RegisterClass.sse),
66676743 abi_size,
66686744 ) else null,
66696745 .rem, .mod => return self.fail("TODO implement genBinOp for {s} {}", .{
......@@ -6916,7 +6992,8 @@ fn genBinOp(
69166992 .Float => switch (lhs_ty.floatBits(self.target.*)) {
69176993 16 => {
69186994 assert(self.hasFeature(.f16c));
6919 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
6995 const tmp_reg =
6996 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
69206997 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
69216998 defer self.register_manager.unlockReg(tmp_lock);
69226999
......@@ -7223,7 +7300,10 @@ fn genBinOp(
72237300 assert(self.hasFeature(.f16c));
72247301 switch (lhs_ty.vectorLen(mod)) {
72257302 1 => {
7226 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
7303 const tmp_reg = (try self.register_manager.allocReg(
7304 null,
7305 abi.RegisterClass.sse,
7306 )).to128();
72277307 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
72287308 defer self.register_manager.unlockReg(tmp_lock);
72297309
......@@ -7267,7 +7347,10 @@ fn genBinOp(
72677347 return dst_mcv;
72687348 },
72697349 2 => {
7270 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
7350 const tmp_reg = (try self.register_manager.allocReg(
7351 null,
7352 abi.RegisterClass.sse,
7353 )).to128();
72717354 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
72727355 defer self.register_manager.unlockReg(tmp_lock);
72737356
......@@ -7315,7 +7398,10 @@ fn genBinOp(
73157398 return dst_mcv;
73167399 },
73177400 3...4 => {
7318 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
7401 const tmp_reg = (try self.register_manager.allocReg(
7402 null,
7403 abi.RegisterClass.sse,
7404 )).to128();
73197405 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
73207406 defer self.register_manager.unlockReg(tmp_lock);
73217407
......@@ -7355,7 +7441,10 @@ fn genBinOp(
73557441 return dst_mcv;
73567442 },
73577443 5...8 => {
7358 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to256();
7444 const tmp_reg = (try self.register_manager.allocReg(
7445 null,
7446 abi.RegisterClass.sse,
7447 )).to256();
73597448 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
73607449 defer self.register_manager.unlockReg(tmp_lock);
73617450
......@@ -7948,7 +8037,8 @@ fn genBinOpMir(
79488037 const dst_info: OpInfo = switch (dst_mcv) {
79498038 else => unreachable,
79508039 .memory, .load_got, .load_direct, .load_tlv => dst: {
7951 const dst_addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
8040 const dst_addr_reg =
8041 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
79528042 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
79538043 errdefer self.register_manager.unlockReg(dst_addr_lock);
79548044
......@@ -7993,7 +8083,8 @@ fn genBinOpMir(
79938083 else => unreachable,
79948084 }
79958085
7996 const src_addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
8086 const src_addr_reg =
8087 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
79978088 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
79988089 errdefer self.register_manager.unlockReg(src_addr_lock);
79998090
......@@ -8619,6 +8710,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
86198710 const mod = self.bin_file.options.module.?;
86208711 const un_op = self.air.instructions.items(.data)[inst].un_op;
86218712 const operand = try self.resolveInst(un_op);
8713
86228714 const ret_ty = self.fn_type.fnReturnType(mod);
86238715 switch (self.ret_mcv.short) {
86248716 .none => {},
......@@ -8633,6 +8725,8 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
86338725 },
86348726 else => unreachable,
86358727 }
8728 self.ret_mcv.liveOut(self, inst);
8729
86368730 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
86378731 // which is available if the jump is 127 bytes or less forward.
86388732 const jmp_reloc = try self.asmJmpReloc(undefined);
......@@ -8643,6 +8737,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
86438737fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
86448738 const un_op = self.air.instructions.items(.data)[inst].un_op;
86458739 const ptr = try self.resolveInst(un_op);
8740
86468741 const ptr_ty = self.typeOf(un_op);
86478742 switch (self.ret_mcv.short) {
86488743 .none => {},
......@@ -8650,6 +8745,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
86508745 .indirect => |reg_off| try self.genSetReg(reg_off.reg, ptr_ty, ptr),
86518746 else => unreachable,
86528747 }
8748 self.ret_mcv.liveOut(self, inst);
8749
86538750 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
86548751 // which is available if the jump is 127 bytes or less forward.
86558752 const jmp_reloc = try self.asmJmpReloc(undefined);
......@@ -8800,8 +8897,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
88008897 else => unreachable,
88018898 }
88028899
8803 const dst_addr_reg =
8804 (try self.register_manager.allocReg(null, gp)).to64();
8900 const dst_addr_reg = (try self.register_manager.allocReg(
8901 null,
8902 abi.RegisterClass.gp,
8903 )).to64();
88058904 const dst_addr_lock =
88068905 self.register_manager.lockRegAssumeUnused(dst_addr_reg);
88078906 errdefer self.register_manager.unlockReg(dst_addr_lock);
......@@ -8856,8 +8955,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
88568955 else => unreachable,
88578956 }
88588957
8859 const src_addr_reg =
8860 (try self.register_manager.allocReg(null, gp)).to64();
8958 const src_addr_reg = (try self.register_manager.allocReg(
8959 null,
8960 abi.RegisterClass.gp,
8961 )).to64();
88618962 const src_addr_lock =
88628963 self.register_manager.lockRegAssumeUnused(src_addr_reg);
88638964 errdefer self.register_manager.unlockReg(src_addr_lock);
......@@ -8876,8 +8977,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
88768977 defer if (src_info) |info|
88778978 self.register_manager.unlockReg(info.addr_lock);
88788979
8879 const regs =
8880 try self.register_manager.allocRegs(2, .{ null, null }, gp);
8980 const regs = try self.register_manager.allocRegs(
8981 2,
8982 .{ null, null },
8983 abi.RegisterClass.gp,
8984 );
88818985 const acc_reg = regs[0].to64();
88828986 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);
88838987 defer for (locks) |lock| self.register_manager.unlockReg(lock);
......@@ -8964,12 +9068,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
89649068 switch (ty.floatBits(self.target.*)) {
89659069 16 => {
89669070 assert(self.hasFeature(.f16c));
8967 const tmp1_reg = (try self.register_manager.allocReg(null, sse)).to128();
9071 const tmp1_reg =
9072 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
89689073 const tmp1_mcv = MCValue{ .register = tmp1_reg };
89699074 const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);
89709075 defer self.register_manager.unlockReg(tmp1_lock);
89719076
8972 const tmp2_reg = (try self.register_manager.allocReg(null, sse)).to128();
9077 const tmp2_reg =
9078 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
89739079 const tmp2_mcv = MCValue{ .register = tmp2_reg };
89749080 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
89759081 defer self.register_manager.unlockReg(tmp2_lock);
......@@ -9032,7 +9138,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
90329138 const mod = self.bin_file.options.module.?;
90339139 const un_op = self.air.instructions.items(.data)[inst].un_op;
90349140
9035 const addr_reg = try self.register_manager.allocReg(null, gp);
9141 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
90369142 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
90379143 defer self.register_manager.unlockReg(addr_lock);
90389144 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
......@@ -9293,7 +9399,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
92939399 .load_direct,
92949400 .load_tlv,
92959401 => {
9296 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
9402 const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
92979403 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
92989404 defer self.register_manager.unlockReg(addr_reg_lock);
92999405
......@@ -9778,7 +9884,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
97789884 else => self.typeOf(output).childType(mod),
97799885 };
97809886 const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint, "=r"))
9781 self.register_manager.tryAllocReg(maybe_inst, regClassForType(ty, mod)) orelse
9887 self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
97829888 return self.fail("ran out of registers lowering inline asm", .{})
97839889 else if (mem.eql(u8, constraint, "=m"))
97849890 if (output != .none) null else return self.fail(
......@@ -9786,7 +9892,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
97869892 .{},
97879893 )
97889894 else if (mem.eql(u8, constraint, "=g"))
9789 self.register_manager.tryAllocReg(maybe_inst, regClassForType(ty, mod)) orelse
9895 self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
97909896 if (output != .none) null else return self.fail(
97919897 "ran out of register lowering inline asm",
97929898 .{},
......@@ -9840,7 +9946,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
98409946 break :arg temp_mcv;
98419947 },
98429948 }
9843 const addr_reg = self.register_manager.tryAllocReg(null, gp) orelse {
9949 const addr_reg = self.register_manager.tryAllocReg(null, abi.RegisterClass.gp) orelse {
98449950 const temp_mcv = try self.allocTempRegOrMem(ty, false);
98459951 try self.genCopy(ty, temp_mcv, input_mcv);
98469952 break :arg temp_mcv;
......@@ -10946,8 +11052,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
1094611052 const src_ty = self.typeOf(ty_op.operand);
1094711053
1094811054 const result = result: {
10949 const dst_rc = regClassForType(dst_ty, mod);
10950 const src_rc = regClassForType(src_ty, mod);
11055 const dst_rc = self.regClassForType(dst_ty);
11056 const src_rc = self.regClassForType(src_ty);
1095111057 const src_mcv = try self.resolveInst(ty_op.operand);
1095211058
1095311059 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
......@@ -11074,7 +11180,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
1107411180
1107511181 if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);
1107611182
11077 const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));
11183 const dst_reg = try self.register_manager.allocReg(inst, self.regClassForType(dst_ty));
1107811184 const dst_mcv = MCValue{ .register = dst_reg };
1107911185 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
1108011186 defer self.register_manager.unlockReg(dst_lock);
......@@ -11151,7 +11257,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
1115111257 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
1115211258 defer self.register_manager.unlockReg(src_lock);
1115311259
11154 const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));
11260 const dst_reg = try self.register_manager.allocReg(inst, self.regClassForType(dst_ty));
1115511261 const dst_mcv = MCValue{ .register = dst_reg };
1115611262 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
1115711263 defer self.register_manager.unlockReg(dst_lock);
......@@ -11332,7 +11438,7 @@ fn atomicOp(
1133211438 .SeqCst => .xchg,
1133311439 };
1133411440
11335 const dst_reg = try self.register_manager.allocReg(null, gp);
11441 const dst_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1133611442 const dst_mcv = MCValue{ .register = dst_reg };
1133711443 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
1133811444 defer self.register_manager.unlockReg(dst_lock);
......@@ -11354,7 +11460,7 @@ fn atomicOp(
1135411460 return if (unused) .unreach else dst_mcv;
1135511461 },
1135611462 .loop => _ = if (val_abi_size <= 8) {
11357 const tmp_reg = try self.register_manager.allocReg(null, gp);
11463 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1135811464 const tmp_mcv = MCValue{ .register = tmp_reg };
1135911465 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
1136011466 defer self.register_manager.unlockReg(tmp_lock);
......@@ -11628,7 +11734,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
1162811734
1162911735 // Used to store the number of elements for comparison.
1163011736 // After comparison, updated to store number of bytes needed to copy.
11631 const len_reg = try self.register_manager.allocReg(null, gp);
11737 const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1163211738 const len_mcv: MCValue = .{ .register = len_reg };
1163311739 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
1163411740 defer self.register_manager.unlockReg(len_lock);
......@@ -11638,7 +11744,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
1163811744 const skip_reloc = try self.asmJccReloc(undefined, .z);
1163911745 try self.store(slice_ptr_ty, ptr, src_val);
1164011746
11641 const second_elem_ptr_reg = try self.register_manager.allocReg(null, gp);
11747 const second_elem_ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1164211748 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
1164311749 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
1164411750 defer self.register_manager.unlockReg(second_elem_ptr_lock);
......@@ -11667,7 +11773,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
1166711773 assert(len != 0); // prevented by Sema
1166811774 try self.store(elem_ptr_ty, dst_ptr, src_val);
1166911775
11670 const second_elem_ptr_reg = try self.register_manager.allocReg(null, gp);
11776 const second_elem_ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1167111777 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
1167211778 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
1167311779 defer self.register_manager.unlockReg(second_elem_ptr_lock);
......@@ -11774,16 +11880,16 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
1177411880 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
1177511881 defer self.register_manager.unlockReg(err_lock);
1177611882
11777 const addr_reg = try self.register_manager.allocReg(null, gp);
11883 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1177811884 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
1177911885 defer self.register_manager.unlockReg(addr_lock);
1178011886 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
1178111887
11782 const start_reg = try self.register_manager.allocReg(null, gp);
11888 const start_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1178311889 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);
1178411890 defer self.register_manager.unlockReg(start_lock);
1178511891
11786 const end_reg = try self.register_manager.allocReg(null, gp);
11892 const end_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
1178711893 const end_lock = self.register_manager.lockRegAssumeUnused(end_reg);
1178811894 defer self.register_manager.unlockReg(end_lock);
1178911895
......@@ -11851,7 +11957,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
1185111957 const mod = self.bin_file.options.module.?;
1185211958 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1185311959 const vector_ty = self.typeOfIndex(inst);
11854 const dst_rc = regClassForType(vector_ty, mod);
11960 const dst_rc = self.regClassForType(vector_ty);
1185511961 const scalar_ty = vector_ty.scalarType(mod);
1185611962
1185711963 const src_mcv = try self.resolveInst(ty_op.operand);
src/arch/x86_64/Encoding.zig+1-1
......@@ -260,7 +260,7 @@ pub const Mnemonic = enum {
260260 ud2,
261261 xadd, xchg, xor,
262262 // X87
263 ffree, fisttp, fld, fst, fstp,
263 fabs, fchs, ffree, fisttp, fld, fst, fstp,
264264 // MMX
265265 movd, movq,
266266 packssdw, packsswb, packuswb,
src/arch/x86_64/Mir.zig+4
......@@ -442,6 +442,10 @@ pub const Inst = struct {
442442 /// Bitwise logical xor of packed double-precision floating-point values
443443 xor,
444444
445 /// Absolute value
446 abs,
447 /// Change sign
448 chs,
445449 /// Free floating-point register
446450 free,
447451 /// Store integer with truncation
src/arch/x86_64/encodings.zig+4
......@@ -829,6 +829,10 @@ pub const table = [_]Entry{
829829 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long, .none },
830830
831831 // X87
832 .{ .fabs, .np, &.{}, &.{ 0xd9, 0xe1 }, 0, .none, .x87 },
833
834 .{ .fchs, .np, &.{}, &.{ 0xd9, 0xe0 }, 0, .none, .x87 },
835
832836 .{ .ffree, .o, &.{ .st }, &.{ 0xdd, 0xc0 }, 0, .none, .x87 },
833837
834838 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },
src/register_manager.zig+4-2
......@@ -91,11 +91,13 @@ pub fn RegisterManager(
9191 return null;
9292 }
9393
94 pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {
94 pub fn indexOfRegIntoTracked(
95 reg: Register,
96 ) ?std.math.IntFittingRange(0, tracked_registers.len) {
9597 return indexOfReg(tracked_registers, reg);
9698 }
9799
98 pub fn regAtTrackedIndex(index: RegisterBitSet.ShiftInt) Register {
100 pub fn regAtTrackedIndex(index: std.math.IntFittingRange(0, tracked_registers.len)) Register {
99101 return tracked_registers[index];
100102 }
101103
test/behavior/abs.zig+1-1
......@@ -95,7 +95,7 @@ test "@abs floats" {
9595 try comptime testAbsFloats(f64);
9696 try testAbsFloats(f64);
9797 try comptime testAbsFloats(f80);
98 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);
98 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);
9999 try comptime testAbsFloats(f128);
100100 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);
101101}
test/behavior/floatop.zig+10-10
......@@ -270,7 +270,7 @@ test "@sqrt f80/f128/c_longdouble" {
270270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
271271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
272272 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
274274
275275 if (builtin.os.tag == .freebsd) {
276276 // TODO https://github.com/ziglang/zig/issues/10875
......@@ -378,7 +378,7 @@ test "@sin f80/f128/c_longdouble" {
378378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
379379 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
380380 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
381 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
381 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
382382
383383 try testSin(f80);
384384 comptime try testSin(f80);
......@@ -447,7 +447,7 @@ test "@cos f80/f128/c_longdouble" {
447447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449449 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
450 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
450 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
451451
452452 try testCos(f80);
453453 try comptime testCos(f80);
......@@ -516,7 +516,7 @@ test "@tan f80/f128/c_longdouble" {
516516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
517517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
518518 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
519 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
519 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
520520
521521 try testTan(f80);
522522 try comptime testTan(f80);
......@@ -585,7 +585,7 @@ test "@exp f80/f128/c_longdouble" {
585585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
586586 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
587587 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
588 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
588 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
589589
590590 try testExp(f80);
591591 try comptime testExp(f80);
......@@ -654,7 +654,7 @@ test "@exp2 f80/f128/c_longdouble" {
654654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
655655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
656656 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
657 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
657 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
658658
659659 try testExp2(f80);
660660 try comptime testExp2(f80);
......@@ -723,7 +723,7 @@ test "@log f80/f128/c_longdouble" {
723723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
724724 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
725725 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
726 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
726 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
727727
728728 try testLog(f80);
729729 try comptime testLog(f80);
......@@ -790,7 +790,7 @@ test "@log2 f80/f128/c_longdouble" {
790790 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
791791 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
792792 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
793 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
793 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
794794
795795 try testLog2(f80);
796796 try comptime testLog2(f80);
......@@ -863,7 +863,7 @@ test "@log10 f80/f128/c_longdouble" {
863863 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
864864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
865865 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
866 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
866 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
867867
868868 try testLog10(f80);
869869 try comptime testLog10(f80);
......@@ -929,7 +929,7 @@ test "@abs f80/f128/c_longdouble" {
929929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
930930 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
931931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
932 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
933933
934934 try testFabs(f80);
935935 try comptime testFabs(f80);