authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-02 08:25:57-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-05-02 08:25:57-07:00
loga2e2e25165b51ef92dbfbd9c46b6a01c90b250b3
tree7a3889971c17987ed1644945f1399e3c4309ed92
parent28923474401051a9aa0bddd60904b9be64943dba
parent3b1ea390a301dbdc992043d97cf618a94e8801de
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15505 from jacobly0/x86_64-behavior

x86_64: fixes for behavior tests

36 files changed, 1578 insertions(+), 859 deletions(-)

lib/std/start.zig+1-1
......@@ -18,7 +18,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
1818// Until then, we have simplified logic here for self-hosted. TODO remove this once
1919// self-hosted is capable enough to handle all of the real start.zig logic.
2020pub const simplified_logic =
21 (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or
21 (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .plan9) or
2222 builtin.zig_backend == .stage2_x86 or
2323 builtin.zig_backend == .stage2_aarch64 or
2424 builtin.zig_backend == .stage2_arm or
lib/test_runner.zig+12-5
......@@ -13,7 +13,6 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
1313
1414pub fn main() void {
1515 if (builtin.zig_backend == .stage2_wasm or
16 (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) or
1716 builtin.zig_backend == .stage2_aarch64)
1817 {
1918 return mainSimple() catch @panic("test failure");
......@@ -234,25 +233,33 @@ pub fn log(
234233/// work-in-progress backends can handle it.
235234pub fn mainSimple() anyerror!void {
236235 const enable_print = false;
236 const print_all = false;
237237
238238 var passed: u64 = 0;
239239 var skipped: u64 = 0;
240240 var failed: u64 = 0;
241241 const stderr = if (enable_print) std.io.getStdErr() else {};
242242 for (builtin.test_functions) |test_fn| {
243 if (enable_print and print_all) {
244 stderr.writeAll(test_fn.name) catch {};
245 stderr.writeAll("... ") catch {};
246 }
243247 test_fn.func() catch |err| {
244 if (enable_print) stderr.writeAll(test_fn.name) catch {};
248 if (enable_print and !print_all) {
249 stderr.writeAll(test_fn.name) catch {};
250 stderr.writeAll("... ") catch {};
251 }
245252 if (err != error.SkipZigTest) {
246 if (enable_print) stderr.writeAll("... FAIL\n") catch {};
253 if (enable_print) stderr.writeAll("FAIL\n") catch {};
247254 failed += 1;
248255 if (!enable_print) return err;
249256 continue;
250257 }
251 if (enable_print) stderr.writeAll("... SKIP\n") catch {};
258 if (enable_print) stderr.writeAll("SKIP\n") catch {};
252259 skipped += 1;
253260 continue;
254261 };
255 //if (enable_print) stderr.writeAll("... PASS\n") catch {};
262 if (enable_print and print_all) stderr.writeAll("PASS\n") catch {};
256263 passed += 1;
257264 }
258265 if (enable_print) {
src/Sema.zig+3-6
......@@ -23287,8 +23287,7 @@ fn panicWithMsg(
2328723287 const arena = sema.arena;
2328823288
2328923289 if (!mod.backendSupportsFeature(.panic_fn)) {
23290 _ = try block.addNoOp(.breakpoint);
23291 _ = try block.addNoOp(.unreach);
23290 _ = try block.addNoOp(.trap);
2329223291 return;
2329323292 }
2329423293 const panic_fn = try sema.getBuiltin("panic");
......@@ -23336,8 +23335,7 @@ fn panicUnwrapError(
2333623335
2333723336 {
2333823337 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
23339 _ = try fail_block.addNoOp(.breakpoint);
23340 _ = try fail_block.addNoOp(.unreach);
23338 _ = try fail_block.addNoOp(.trap);
2334123339 } else {
2334223340 const panic_fn = try sema.getBuiltin("panicUnwrapError");
2334323341 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
......@@ -23462,8 +23460,7 @@ fn safetyCheckFormatted(
2346223460 defer fail_block.instructions.deinit(gpa);
2346323461
2346423462 if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
23465 _ = try fail_block.addNoOp(.breakpoint);
23466 _ = try fail_block.addNoOp(.unreach);
23463 _ = try fail_block.addNoOp(.trap);
2346723464 } else {
2346823465 const panic_fn = try sema.getBuiltin(func);
2346923466 _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);
src/arch/x86_64/CodeGen.zig+1115-621
......@@ -7,6 +7,8 @@ const leb128 = std.leb;
77const link = @import("../../link.zig");
88const log = std.log.scoped(.codegen);
99const tracking_log = std.log.scoped(.tracking);
10const verbose_tracking_log = std.log.scoped(.verbose_tracking);
11const wip_mir_log = std.log.scoped(.wip_mir);
1012const math = std.math;
1113const mem = std.mem;
1214const trace = @import("../../tracy.zig").trace;
......@@ -48,16 +50,13 @@ const sse = abi.RegisterClass.sse;
4850
4951const InnerError = CodeGenError || error{OutOfRegisters};
5052
51const debug_wip_mir = false;
52const debug_tracking = false;
53
5453gpa: Allocator,
5554air: Air,
5655liveness: Liveness,
5756bin_file: *link.File,
5857debug_output: DebugInfoOutput,
5958target: *const std.Target,
60mod_fn: *const Module.Fn,
59owner: Owner,
6160err_msg: ?*ErrorMsg,
6261args: []MCValue,
6362ret_mcv: InstTracking,
......@@ -109,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged
109108const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
110109const RegisterOffset = struct { reg: Register, off: i32 = 0 };
111110
111const Owner = union(enum) {
112 mod_fn: *const Module.Fn,
113 lazy_sym: link.File.LazySymbol,
114
115 fn getDecl(owner: Owner) Module.Decl.Index {
116 return switch (owner) {
117 .mod_fn => |mod_fn| mod_fn.owner_decl,
118 .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(),
119 };
120 }
121
122 fn getSymbolIndex(owner: Owner, ctx: *Self) !u32 {
123 switch (owner) {
124 .mod_fn => |mod_fn| {
125 const decl_index = mod_fn.owner_decl;
126 if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
127 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
128 return macho_file.getAtom(atom).getSymbolIndex().?;
129 } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| {
130 const atom = try coff_file.getOrCreateAtomForDecl(decl_index);
131 return coff_file.getAtom(atom).getSymbolIndex().?;
132 } else unreachable;
133 },
134 .lazy_sym => |lazy_sym| {
135 if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
136 const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
137 return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
138 return macho_file.getAtom(atom).getSymbolIndex().?;
139 } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| {
140 const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
141 return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
142 return coff_file.getAtom(atom).getSymbolIndex().?;
143 } else unreachable;
144 },
145 }
146 }
147};
148
112149pub const MCValue = union(enum) {
113150 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
114151 /// TODO Look into deleting this tag and using `dead` instead, since every use
......@@ -220,9 +257,9 @@ pub const MCValue = union(enum) {
220257 .dead,
221258 .undef,
222259 .immediate,
260 .eflags,
223261 .register,
224262 .register_offset,
225 .eflags,
226263 .register_overflow,
227264 .lea_direct,
228265 .lea_got,
......@@ -298,6 +335,41 @@ pub const MCValue = union(enum) {
298335 };
299336 }
300337
338 fn mem(mcv: MCValue, ptr_size: Memory.PtrSize) Memory {
339 return switch (mcv) {
340 .none,
341 .unreach,
342 .dead,
343 .undef,
344 .immediate,
345 .eflags,
346 .register,
347 .register_offset,
348 .register_overflow,
349 .load_direct,
350 .lea_direct,
351 .load_got,
352 .lea_got,
353 .load_tlv,
354 .lea_tlv,
355 .lea_frame,
356 .reserved_frame,
357 => unreachable,
358 .memory => |addr| if (math.cast(i32, @bitCast(i64, addr))) |small_addr|
359 Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr })
360 else
361 Memory.moffs(.ds, addr),
362 .indirect => |reg_off| Memory.sib(ptr_size, .{
363 .base = .{ .reg = reg_off.reg },
364 .disp = reg_off.off,
365 }),
366 .load_frame => |frame_addr| Memory.sib(ptr_size, .{
367 .base = .{ .frame = frame_addr.index },
368 .disp = frame_addr.off,
369 }),
370 };
371 }
372
301373 pub fn format(
302374 mcv: MCValue,
303375 comptime _: []const u8,
......@@ -575,12 +647,6 @@ pub fn generate(
575647 assert(fn_owner_decl.has_tv);
576648 const fn_type = fn_owner_decl.ty;
577649
578 if (debug_wip_mir) {
579 const stderr = std.io.getStdErr().writer();
580 fn_owner_decl.renderFullyQualifiedName(mod, stderr) catch {};
581 stderr.writeAll(":\n") catch {};
582 }
583
584650 const gpa = bin_file.allocator;
585651 var function = Self{
586652 .gpa = gpa,
......@@ -589,7 +655,7 @@ pub fn generate(
589655 .target = &bin_file.options.target,
590656 .bin_file = bin_file,
591657 .debug_output = debug_output,
592 .mod_fn = module_fn,
658 .owner = .{ .mod_fn = module_fn },
593659 .err_msg = null,
594660 .args = undefined, // populated after `resolveCallingConventionValues`
595661 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
......@@ -614,6 +680,8 @@ pub fn generate(
614680 if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa);
615681 }
616682
683 wip_mir_log.debug("{}:", .{function.fmtDecl(module_fn.owner_decl)});
684
617685 try function.frame_allocs.resize(gpa, FrameIndex.named_count);
618686 function.frame_allocs.set(
619687 @enumToInt(FrameIndex.stack_frame),
......@@ -715,48 +783,190 @@ pub fn generate(
715783 }
716784}
717785
718fn dumpWipMir(self: *Self, inst: Mir.Inst) !void {
719 if (!debug_wip_mir) return;
720 const stderr = std.io.getStdErr().writer();
786pub fn generateLazy(
787 bin_file: *link.File,
788 src_loc: Module.SrcLoc,
789 lazy_sym: link.File.LazySymbol,
790 code: *std.ArrayList(u8),
791 debug_output: DebugInfoOutput,
792) CodeGenError!Result {
793 const gpa = bin_file.allocator;
794 var function = Self{
795 .gpa = gpa,
796 .air = undefined,
797 .liveness = undefined,
798 .target = &bin_file.options.target,
799 .bin_file = bin_file,
800 .debug_output = debug_output,
801 .owner = .{ .lazy_sym = lazy_sym },
802 .err_msg = null,
803 .args = undefined,
804 .ret_mcv = undefined,
805 .fn_type = undefined,
806 .arg_index = undefined,
807 .src_loc = src_loc,
808 .end_di_line = undefined, // no debug info yet
809 .end_di_column = undefined, // no debug info yet
810 };
811 defer {
812 function.mir_instructions.deinit(gpa);
813 function.mir_extra.deinit(gpa);
814 }
815
816 function.genLazy(lazy_sym) catch |err| switch (err) {
817 error.CodegenFail => return Result{ .fail = function.err_msg.? },
818 error.OutOfRegisters => return Result{
819 .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
820 },
821 else => |e| return e,
822 };
823
824 var mir = Mir{
825 .instructions = function.mir_instructions.toOwnedSlice(),
826 .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator),
827 .frame_locs = function.frame_locs.toOwnedSlice(),
828 };
829 defer mir.deinit(bin_file.allocator);
830
831 var emit = Emit{
832 .lower = .{
833 .allocator = bin_file.allocator,
834 .mir = mir,
835 .target = &bin_file.options.target,
836 .src_loc = src_loc,
837 },
838 .bin_file = bin_file,
839 .debug_output = debug_output,
840 .code = code,
841 .prev_di_pc = undefined, // no debug info yet
842 .prev_di_line = undefined, // no debug info yet
843 .prev_di_column = undefined, // no debug info yet
844 };
845 defer emit.deinit();
846 emit.emitMir() catch |err| switch (err) {
847 error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? },
848 error.InvalidInstruction, error.CannotEncode => |e| {
849 const msg = switch (e) {
850 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
851 error.CannotEncode => "CodeGen failed to encode the instruction.",
852 };
853 return Result{
854 .fail = try ErrorMsg.create(
855 bin_file.allocator,
856 src_loc,
857 "{s} This is a bug in the Zig compiler.",
858 .{msg},
859 ),
860 };
861 },
862 else => |e| return e,
863 };
864
865 if (function.err_msg) |em| {
866 return Result{ .fail = em };
867 } else {
868 return Result.ok;
869 }
870}
871
872const FormatDeclData = struct {
873 mod: *Module,
874 decl_index: Module.Decl.Index,
875};
876fn formatDecl(
877 data: FormatDeclData,
878 comptime _: []const u8,
879 _: std.fmt.FormatOptions,
880 writer: anytype,
881) @TypeOf(writer).Error!void {
882 try data.mod.declPtr(data.decl_index).renderFullyQualifiedName(data.mod, writer);
883}
884fn fmtDecl(self: *Self, decl_index: Module.Decl.Index) std.fmt.Formatter(formatDecl) {
885 return .{ .data = .{
886 .mod = self.bin_file.options.module.?,
887 .decl_index = decl_index,
888 } };
889}
890
891const FormatAirData = struct {
892 self: *Self,
893 inst: Air.Inst.Index,
894};
895fn formatAir(
896 data: FormatAirData,
897 comptime _: []const u8,
898 _: std.fmt.FormatOptions,
899 writer: anytype,
900) @TypeOf(writer).Error!void {
901 @import("../../print_air.zig").dumpInst(
902 data.inst,
903 data.self.bin_file.options.module.?,
904 data.self.air,
905 data.self.liveness,
906 );
907}
908fn fmtAir(self: *Self, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
909 return .{ .data = .{ .self = self, .inst = inst } };
910}
721911
912const FormatWipMirData = struct {
913 self: *Self,
914 inst: Mir.Inst.Index,
915};
916fn formatWipMir(
917 data: FormatWipMirData,
918 comptime _: []const u8,
919 _: std.fmt.FormatOptions,
920 writer: anytype,
921) @TypeOf(writer).Error!void {
722922 var lower = Lower{
723 .allocator = self.gpa,
923 .allocator = data.self.gpa,
724924 .mir = .{
725 .instructions = self.mir_instructions.slice(),
726 .extra = self.mir_extra.items,
925 .instructions = data.self.mir_instructions.slice(),
926 .extra = data.self.mir_extra.items,
727927 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
728928 },
729 .target = self.target,
730 .src_loc = self.src_loc,
929 .target = data.self.target,
930 .src_loc = data.self.src_loc,
731931 };
732 for (lower.lowerMir(inst) catch |err| switch (err) {
932 for (lower.lowerMir(data.self.mir_instructions.get(data.inst)) catch |err| switch (err) {
733933 error.LowerFail => {
734934 defer {
735 lower.err_msg.?.deinit(self.gpa);
935 lower.err_msg.?.deinit(data.self.gpa);
736936 lower.err_msg = null;
737937 }
738 try stderr.print("{s}\n", .{lower.err_msg.?.msg});
938 try writer.writeAll(lower.err_msg.?.msg);
739939 return;
740940 },
741 error.InvalidInstruction, error.CannotEncode => |e| {
742 try stderr.writeAll(switch (e) {
743 error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n",
744 error.CannotEncode => "CodeGen failed to encode the instruction.\n",
941 error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| {
942 try writer.writeAll(switch (e) {
943 error.OutOfMemory => "Out of memory",
944 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
945 error.CannotEncode => "CodeGen failed to encode the instruction.",
745946 });
746947 return;
747948 },
748949 else => |e| return e,
749 }) |lower_inst| {
750 try stderr.print(" | {}\n", .{lower_inst});
751 }
950 }) |lower_inst| try writer.print(" | {}", .{lower_inst});
951}
952fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
953 return .{ .data = .{ .self = self, .inst = inst } };
752954}
753955
754fn dumpTracking(self: *Self) !void {
755 if (!debug_tracking) return;
756 const stderr = std.io.getStdErr().writer();
757
758 var it = self.inst_tracking.iterator();
759 while (it.next()) |entry| try stderr.print("%{d} = {}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
956const FormatTrackingData = struct {
957 self: *Self,
958};
959fn formatTracking(
960 data: FormatTrackingData,
961 comptime _: []const u8,
962 _: std.fmt.FormatOptions,
963 writer: anytype,
964) @TypeOf(writer).Error!void {
965 var it = data.self.inst_tracking.iterator();
966 while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* });
967}
968fn fmtTracking(self: *Self) std.fmt.Formatter(formatTracking) {
969 return .{ .data = .{ .self = self } };
760970}
761971
762972fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
......@@ -764,7 +974,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
764974 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
765975 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
766976 self.mir_instructions.appendAssumeCapacity(inst);
767 self.dumpWipMir(inst) catch {};
977 switch (inst.tag) {
978 else => wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}),
979 .dbg_line,
980 .dbg_prologue_end,
981 .dbg_epilogue_begin,
982 .dead,
983 => {},
984 }
768985 return result_index;
769986}
770987
......@@ -1186,13 +1403,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
11861403 }
11871404
11881405 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue;
1189 if (debug_wip_mir) @import("../../print_air.zig").dumpInst(
1190 inst,
1191 self.bin_file.options.module.?,
1192 self.air,
1193 self.liveness,
1194 );
1195 self.dumpTracking() catch {};
1406 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
1407 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
11961408
11971409 const old_air_bookkeeping = self.air_bookkeeping;
11981410 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
......@@ -1244,9 +1456,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
12441456 .ceil,
12451457 .round,
12461458 .trunc_float,
1247 .neg,
12481459 => try self.airUnaryMath(inst),
12491460
1461 .neg => try self.airNeg(inst),
1462
12501463 .add_with_overflow => try self.airAddSubWithOverflow(inst),
12511464 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
12521465 .mul_with_overflow => try self.airMulWithOverflow(inst),
......@@ -1453,7 +1666,69 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
14531666 }
14541667 }
14551668 }
1456 self.dumpTracking() catch {};
1669 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
1670}
1671
1672fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
1673 switch (lazy_sym.ty.zigTypeTag()) {
1674 .Enum => {
1675 const enum_ty = lazy_sym.ty;
1676 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)});
1677
1678 const param_regs = abi.getCAbiIntParamRegs(self.target.*);
1679 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
1680 defer for (param_locks) |lock| self.register_manager.unlockReg(lock);
1681
1682 const ret_reg = param_regs[0];
1683 const enum_mcv = MCValue{ .register = param_regs[1] };
1684
1685 var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount());
1686 defer self.gpa.free(exitlude_jump_relocs);
1687
1688 const data_reg = try self.register_manager.allocReg(null, gp);
1689 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
1690 defer self.register_manager.unlockReg(data_lock);
1691 try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
1692
1693 var data_off: i32 = 0;
1694 for (
1695 exitlude_jump_relocs,
1696 enum_ty.enumFields().keys(),
1697 0..,
1698 ) |*exitlude_jump_reloc, tag_name, index| {
1699 var tag_pl = Value.Payload.U32{
1700 .base = .{ .tag = .enum_field_index },
1701 .data = @intCast(u32, index),
1702 };
1703 const tag_val = Value.initPayload(&tag_pl.base);
1704 const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });
1705 try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv);
1706 const skip_reloc = try self.asmJccReloc(undefined, .ne);
1707
1708 try self.genSetMem(
1709 .{ .reg = ret_reg },
1710 0,
1711 Type.usize,
1712 .{ .register_offset = .{ .reg = data_reg, .off = data_off } },
1713 );
1714 try self.genSetMem(.{ .reg = ret_reg }, 8, Type.usize, .{ .immediate = tag_name.len });
1715
1716 exitlude_jump_reloc.* = try self.asmJmpReloc(undefined);
1717 try self.performReloc(skip_reloc);
1718
1719 data_off += @intCast(i32, tag_name.len + 1);
1720 }
1721
1722 try self.airTrap();
1723
1724 for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc);
1725 try self.asmOpOnly(.ret);
1726 },
1727 else => return self.fail(
1728 "TODO implement {s} for {}",
1729 .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(self.bin_file.options.module.?) },
1730 ),
1731 }
14571732}
14581733
14591734fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
......@@ -1619,15 +1894,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
16191894 const frame_allocs_slice = self.frame_allocs.slice();
16201895 const frame_size = frame_allocs_slice.items(.abi_size);
16211896 const frame_align = frame_allocs_slice.items(.abi_align);
1897
1898 const stack_frame_align = &frame_align[@enumToInt(FrameIndex.stack_frame)];
1899 stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align);
1900
16221901 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {
16231902 const abi_size = frame_size[@enumToInt(frame_index)];
16241903 if (abi_size != alloc.abi_size) continue;
16251904 const abi_align = &frame_align[@enumToInt(frame_index)];
16261905 abi_align.* = @max(abi_align.*, alloc.abi_align);
16271906
1628 const stack_frame_align = &frame_align[@enumToInt(FrameIndex.stack_frame)];
1629 stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align);
1630
16311907 _ = self.free_frame_indices.swapRemoveAt(free_i);
16321908 return frame_index;
16331909 }
......@@ -1828,7 +2104,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void {
18282104/// allocated. A second call to `copyToTmpRegister` may return the same register.
18292105/// This can have a side effect of spilling instructions to the stack to free up a register.
18302106fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
1831 const reg: Register = try self.register_manager.allocReg(null, try self.regClassForType(ty));
2107 const reg = try self.register_manager.allocReg(null, try self.regClassForType(ty));
18322108 try self.genSetReg(reg, ty, mcv);
18332109 return reg;
18342110}
......@@ -1871,16 +2147,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
18712147
18722148fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
18732149 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1874 _ = ty_op;
1875 return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch});
1876 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2150 const dst_ty = self.air.typeOfIndex(inst);
2151 const src_ty = self.air.typeOf(ty_op.operand);
2152 if (dst_ty.floatBits(self.target.*) != 32 or src_ty.floatBits(self.target.*) != 64 or
2153 !Target.x86.featureSetHas(self.target.cpu.features, .sse2))
2154 return self.fail("TODO implement airFptrunc from {} to {}", .{
2155 src_ty.fmt(self.bin_file.options.module.?),
2156 dst_ty.fmt(self.bin_file.options.module.?),
2157 });
2158
2159 const src_mcv = try self.resolveInst(ty_op.operand);
2160 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2161 src_mcv
2162 else
2163 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
2164 const dst_lock = self.register_manager.lockReg(dst_mcv.register);
2165 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
2166
2167 try self.genBinOpMir(.cvtsd2ss, src_ty, dst_mcv, src_mcv);
2168 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
18772169}
18782170
18792171fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
18802172 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1881 _ = ty_op;
1882 return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch});
1883 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2173 const dst_ty = self.air.typeOfIndex(inst);
2174 const src_ty = self.air.typeOf(ty_op.operand);
2175 if (dst_ty.floatBits(self.target.*) != 64 or src_ty.floatBits(self.target.*) != 32 or
2176 !Target.x86.featureSetHas(self.target.cpu.features, .sse2))
2177 return self.fail("TODO implement airFpext from {} to {}", .{
2178 src_ty.fmt(self.bin_file.options.module.?),
2179 dst_ty.fmt(self.bin_file.options.module.?),
2180 });
2181
2182 const src_mcv = try self.resolveInst(ty_op.operand);
2183 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2184 src_mcv
2185 else
2186 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
2187 const dst_lock = self.register_manager.lockReg(dst_mcv.register);
2188 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
2189
2190 try self.genBinOpMir(.cvtss2sd, src_ty, dst_mcv, src_mcv);
2191 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
18842192}
18852193
18862194fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1928,13 +2236,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
19282236 registerAlias(src_reg, min_abi_size),
19292237 );
19302238 },
1931 .load_frame => |frame_addr| try self.asmRegisterMemory(
2239 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
19322240 tag,
19332241 dst_alias,
1934 Memory.sib(Memory.PtrSize.fromSize(min_abi_size), .{
1935 .base = .{ .frame = frame_addr.index },
1936 .disp = frame_addr.off,
1937 }),
2242 src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)),
19382243 ),
19392244 else => return self.fail("TODO airIntCast from {s} to {s}", .{
19402245 @tagName(src_mcv),
......@@ -2102,6 +2407,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
21022407 } };
21032408 const src_ty = Type.initPayload(&src_pl.base);
21042409
2410 try self.spillEflagsIfOccupied();
21052411 try self.spillRegisters(&.{ .rax, .rdx });
21062412 const lhs = try self.resolveInst(bin_op.lhs);
21072413 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -2315,12 +2621,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23152621
23162622 const frame_index =
23172623 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2318 try self.genSetFrameTruncatedOverflowCompare(
2319 tuple_ty,
2320 frame_index,
2321 partial_mcv.register,
2322 cc,
2323 );
2624 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
23242625 break :result .{ .load_frame = .{ .index = frame_index } };
23252626 },
23262627 else => unreachable,
......@@ -2392,12 +2693,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23922693
23932694 const frame_index =
23942695 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2395 try self.genSetFrameTruncatedOverflowCompare(
2396 tuple_ty,
2397 frame_index,
2398 partial_mcv.register,
2399 cc,
2400 );
2696 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
24012697 break :result .{ .load_frame = .{ .index = frame_index } };
24022698 },
24032699 else => unreachable,
......@@ -2410,173 +2706,175 @@ fn genSetFrameTruncatedOverflowCompare(
24102706 self: *Self,
24112707 tuple_ty: Type,
24122708 frame_index: FrameIndex,
2413 reg: Register,
2414 cc: Condition,
2709 src_mcv: MCValue,
2710 overflow_cc: ?Condition,
24152711) !void {
2416 const reg_lock = self.register_manager.lockReg(reg);
2417 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
2712 const src_lock = switch (src_mcv) {
2713 .register => |reg| self.register_manager.lockReg(reg),
2714 else => null,
2715 };
2716 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
24182717
24192718 const ty = tuple_ty.structFieldType(0);
24202719 const int_info = ty.intInfo(self.target.*);
2421 const extended_ty = switch (int_info.signedness) {
2422 .signed => Type.isize,
2423 .unsigned => ty,
2720
2721 var hi_limb_pl = Type.Payload.Bits{
2722 .base = .{ .tag = switch (int_info.signedness) {
2723 .signed => .int_signed,
2724 .unsigned => .int_unsigned,
2725 } },
2726 .data = (int_info.bits - 1) % 64 + 1,
24242727 };
2728 const hi_limb_ty = Type.initPayload(&hi_limb_pl.base);
24252729
2426 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);
2427 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
2428 defer for (temp_regs_locks) |rreg| {
2429 self.register_manager.unlockReg(rreg);
2730 var rest_pl = Type.Payload.Bits{
2731 .base = .{ .tag = .int_unsigned },
2732 .data = int_info.bits - hi_limb_pl.data,
24302733 };
2734 const rest_ty = Type.initPayload(&rest_pl.base);
2735
2736 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);
2737 const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
2738 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
24312739
24322740 const overflow_reg = temp_regs[0];
2433 try self.asmSetccRegister(overflow_reg.to8(), cc);
2741 if (overflow_cc) |cc| try self.asmSetccRegister(overflow_reg.to8(), cc);
24342742
24352743 const scratch_reg = temp_regs[1];
2436 try self.genSetReg(scratch_reg, extended_ty, .{ .register = reg });
2437 try self.truncateRegister(ty, scratch_reg);
2438 try self.genBinOpMir(
2439 .cmp,
2440 extended_ty,
2441 .{ .register = reg },
2442 .{ .register = scratch_reg },
2443 );
2744 const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8;
2745 const hi_limb_mcv = if (hi_limb_off > 0)
2746 src_mcv.address().offset(int_info.bits / 64 * 8).deref()
2747 else
2748 src_mcv;
2749 try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv);
2750 try self.truncateRegister(hi_limb_ty, scratch_reg);
2751 try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);
24442752
24452753 const eq_reg = temp_regs[2];
2446 try self.asmSetccRegister(eq_reg.to8(), .ne);
2447 try self.genBinOpMir(
2448 .@"or",
2449 Type.u8,
2450 .{ .register = overflow_reg },
2451 .{ .register = eq_reg },
2452 );
2754 if (overflow_cc) |_| {
2755 try self.asmSetccRegister(eq_reg.to8(), .ne);
2756 try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg });
2757 }
24532758
2759 const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*));
2760 if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv);
24542761 try self.genSetMem(
24552762 .{ .frame = frame_index },
2456 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2457 tuple_ty.structFieldType(1),
2458 .{ .register = overflow_reg.to8() },
2763 payload_off + hi_limb_off,
2764 hi_limb_ty,
2765 .{ .register = scratch_reg },
24592766 );
24602767 try self.genSetMem(
24612768 .{ .frame = frame_index },
2462 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),
2463 ty,
2464 .{ .register = scratch_reg },
2769 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2770 tuple_ty.structFieldType(1),
2771 if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne },
24652772 );
24662773}
24672774
24682775fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
24692776 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
24702777 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2471 const result: MCValue = result: {
2472 const dst_ty = self.air.typeOf(bin_op.lhs);
2473 switch (dst_ty.zigTypeTag()) {
2474 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
2475 .Int => {
2476 try self.spillEflagsIfOccupied();
2778 const dst_ty = self.air.typeOf(bin_op.lhs);
2779 const result: MCValue = switch (dst_ty.zigTypeTag()) {
2780 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
2781 .Int => result: {
2782 try self.spillEflagsIfOccupied();
2783 try self.spillRegisters(&.{ .rax, .rdx });
24772784
2478 const dst_info = dst_ty.intInfo(self.target.*);
2479 const cc: Condition = switch (dst_info.signedness) {
2480 .unsigned => .c,
2481 .signed => .o,
2785 const dst_info = dst_ty.intInfo(self.target.*);
2786 const cc: Condition = switch (dst_info.signedness) {
2787 .unsigned => .c,
2788 .signed => .o,
2789 };
2790
2791 const lhs_active_bits = self.activeIntBits(bin_op.lhs);
2792 const rhs_active_bits = self.activeIntBits(bin_op.rhs);
2793 var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) {
2794 .signed => .int_signed,
2795 .unsigned => .int_unsigned,
2796 } }, .data = math.max3(lhs_active_bits, rhs_active_bits, dst_info.bits / 2) };
2797 const src_ty = Type.initPayload(&src_pl.base);
2798
2799 const lhs = try self.resolveInst(bin_op.lhs);
2800 const rhs = try self.resolveInst(bin_op.rhs);
2801
2802 const tuple_ty = self.air.typeOfIndex(inst);
2803 const extra_bits = if (dst_info.bits <= 64)
2804 self.regExtraBits(dst_ty)
2805 else
2806 dst_info.bits % 64;
2807 const partial_mcv = if (dst_info.signedness == .signed and extra_bits > 0) dst: {
2808 const rhs_lock: ?RegisterLock = switch (rhs) {
2809 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2810 else => null,
24822811 };
2812 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
24832813
2484 const tuple_ty = self.air.typeOfIndex(inst);
2485 if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) {
2486 var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) {
2487 .signed => .int_signed,
2488 .unsigned => .int_unsigned,
2489 } }, .data = math.max3(
2490 self.activeIntBits(bin_op.lhs),
2491 self.activeIntBits(bin_op.rhs),
2492 dst_info.bits / 2,
2493 ) };
2494 const src_ty = Type.initPayload(&src_pl.base);
2814 const dst_reg: Register = blk: {
2815 if (lhs.isRegister()) break :blk lhs.register;
2816 break :blk try self.copyToTmpRegister(dst_ty, lhs);
2817 };
2818 const dst_mcv = MCValue{ .register = dst_reg };
2819 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
2820 defer self.register_manager.unlockReg(dst_reg_lock);
24952821
2496 try self.spillRegisters(&.{ .rax, .rdx });
2497 const lhs = try self.resolveInst(bin_op.lhs);
2498 const rhs = try self.resolveInst(bin_op.rhs);
2822 const rhs_mcv: MCValue = blk: {
2823 if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
2824 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) };
2825 };
2826 const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) {
2827 .register => |reg| self.register_manager.lockReg(reg),
2828 else => null,
2829 };
2830 defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock);
24992831
2500 const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
2501 switch (partial_mcv) {
2502 .register => |reg| {
2503 self.eflags_inst = inst;
2504 break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
2505 },
2506 else => {},
2507 }
2832 try self.genIntMulComplexOpMir(Type.isize, dst_mcv, rhs_mcv);
2833 break :dst dst_mcv;
2834 } else try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
25082835
2509 // For now, this is the only supported multiply that doesn't fit in a register.
2510 assert(dst_info.bits == 128 and src_pl.data == 64);
2836 switch (partial_mcv) {
2837 .register => |reg| if (extra_bits == 0) {
2838 self.eflags_inst = inst;
2839 break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
2840 } else {
25112841 const frame_index =
25122842 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2513 try self.genSetMem(
2514 .{ .frame = frame_index },
2515 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2516 tuple_ty.structFieldType(1),
2517 .{ .immediate = 0 }, // overflow is impossible for 64-bit*64-bit -> 128-bit
2518 );
2519 try self.genSetMem(
2520 .{ .frame = frame_index },
2521 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),
2522 tuple_ty.structFieldType(0),
2523 partial_mcv,
2524 );
2843 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
25252844 break :result .{ .load_frame = .{ .index = frame_index } };
2526 }
2527
2528 const dst_reg: Register = dst_reg: {
2529 switch (dst_info.signedness) {
2530 .signed => {
2531 const lhs = try self.resolveInst(bin_op.lhs);
2532 const rhs = try self.resolveInst(bin_op.rhs);
2533
2534 const rhs_lock: ?RegisterLock = switch (rhs) {
2535 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2536 else => null,
2537 };
2538 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
2539
2540 const dst_reg: Register = blk: {
2541 if (lhs.isRegister()) break :blk lhs.register;
2542 break :blk try self.copyToTmpRegister(dst_ty, lhs);
2543 };
2544 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
2545 defer self.register_manager.unlockReg(dst_reg_lock);
2546
2547 const rhs_mcv: MCValue = blk: {
2548 if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
2549 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) };
2550 };
2551 const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) {
2552 .register => |reg| self.register_manager.lockReg(reg),
2553 else => null,
2554 };
2555 defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock);
2556
2557 try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv);
2558
2559 break :dst_reg dst_reg;
2560 },
2561 .unsigned => {
2562 try self.spillRegisters(&.{ .rax, .rdx });
2563
2564 const lhs = try self.resolveInst(bin_op.lhs);
2565 const rhs = try self.resolveInst(bin_op.rhs);
2845 },
2846 else => {
2847 // For now, this is the only supported multiply that doesn't fit in a register,
2848 // so cc being set is impossible.
25662849
2567 const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs);
2568 break :dst_reg dst_mcv.register;
2569 },
2570 }
2571 };
2850 assert(dst_info.bits <= 128 and src_pl.data == 64);
25722851
2573 const frame_index =
2574 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2575 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, dst_reg, cc);
2576 break :result .{ .load_frame = .{ .index = frame_index } };
2577 },
2578 else => unreachable,
2579 }
2852 const frame_index =
2853 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2854 if (dst_info.bits >= lhs_active_bits + rhs_active_bits) {
2855 try self.genSetMem(
2856 .{ .frame = frame_index },
2857 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),
2858 tuple_ty.structFieldType(0),
2859 partial_mcv,
2860 );
2861 try self.genSetMem(
2862 .{ .frame = frame_index },
2863 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2864 tuple_ty.structFieldType(1),
2865 .{ .immediate = 0 },
2866 );
2867 } else try self.genSetFrameTruncatedOverflowCompare(
2868 tuple_ty,
2869 frame_index,
2870 partial_mcv,
2871 null,
2872 );
2873 break :result .{ .load_frame = .{ .index = frame_index } };
2874 },
2875 }
2876 },
2877 else => unreachable,
25802878 };
25812879 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
25822880}
......@@ -2616,19 +2914,9 @@ fn genIntMulDivOpMir(
26162914 };
26172915 switch (mat_rhs) {
26182916 .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),
2619 .indirect, .load_frame => try self.asmMemory(
2917 .memory, .indirect, .load_frame => try self.asmMemory(
26202918 tag,
2621 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {
2622 .indirect => |reg_off| .{
2623 .base = .{ .reg = reg_off.reg },
2624 .disp = reg_off.off,
2625 },
2626 .load_frame => |frame_addr| .{
2627 .base = .{ .frame = frame_addr.index },
2628 .disp = frame_addr.off,
2629 },
2630 else => unreachable,
2631 }),
2919 mat_rhs.mem(Memory.PtrSize.fromSize(abi_size)),
26322920 ),
26332921 else => unreachable,
26342922 }
......@@ -3900,10 +4188,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
39004188 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
39014189}
39024190
4191fn airNeg(self: *Self, inst: Air.Inst.Index) !void {
4192 const un_op = self.air.instructions.items(.data)[inst].un_op;
4193 const ty = self.air.typeOf(un_op);
4194 const ty_bits = ty.floatBits(self.target.*);
4195
4196 var arena = std.heap.ArenaAllocator.init(self.gpa);
4197 defer arena.deinit();
4198
4199 const ExpectedContents = union {
4200 f16: Value.Payload.Float_16,
4201 f32: Value.Payload.Float_32,
4202 f64: Value.Payload.Float_64,
4203 f80: Value.Payload.Float_80,
4204 f128: Value.Payload.Float_128,
4205 };
4206 var stack align(@alignOf(ExpectedContents)) =
4207 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
4208
4209 var vec_pl = Type.Payload.Array{
4210 .base = .{ .tag = .vector },
4211 .data = .{
4212 .len = @divExact(128, ty_bits),
4213 .elem_type = ty,
4214 },
4215 };
4216 const vec_ty = Type.initPayload(&vec_pl.base);
4217
4218 var sign_pl = Value.Payload.SubValue{
4219 .base = .{ .tag = .repeated },
4220 .data = try Value.floatToValue(-0.0, stack.get(), ty, self.target.*),
4221 };
4222 const sign_val = Value.initPayload(&sign_pl.base);
4223
4224 const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val });
4225
4226 const src_mcv = try self.resolveInst(un_op);
4227 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
4228 src_mcv
4229 else
4230 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
4231 const dst_lock = self.register_manager.lockReg(dst_mcv.register);
4232 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
4233
4234 try self.genBinOpMir(switch (ty_bits) {
4235 32 => .xorps,
4236 64 => .xorpd,
4237 else => return self.fail("TODO implement airNeg for {}", .{
4238 ty.fmt(self.bin_file.options.module.?),
4239 }),
4240 }, vec_ty, dst_mcv, sign_mcv);
4241 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
4242}
4243
39034244fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
39044245 const un_op = self.air.instructions.items(.data)[inst].un_op;
39054246 _ = un_op;
3906 return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch});
4247 return self.fail("TODO implement airUnaryMath for {}", .{
4248 self.air.instructions.items(.tag)[inst],
4249 });
39074250 //return self.finishAir(inst, result, .{ un_op, .none, .none });
39084251}
39094252
......@@ -4056,7 +4399,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
40564399fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
40574400 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
40584401 const elem_ty = self.air.typeOfIndex(inst);
4059 const elem_size = elem_ty.abiSize(self.target.*);
40604402 const result: MCValue = result: {
40614403 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
40624404
......@@ -4064,14 +4406,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
40644406 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
40654407 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
40664408
4409 const ptr_ty = self.air.typeOf(ty_op.operand);
4410 const elem_size = elem_ty.abiSize(self.target.*);
4411
4412 const elem_rc = try self.regClassForType(elem_ty);
4413 const ptr_rc = try self.regClassForType(ptr_ty);
4414
40674415 const ptr_mcv = try self.resolveInst(ty_op.operand);
4068 const dst_mcv = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
4416 const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and
4417 self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
40694418 // The MCValue that holds the pointer can be re-used as the value.
40704419 ptr_mcv
40714420 else
40724421 try self.allocRegOrMem(inst, true);
40734422
4074 const ptr_ty = self.air.typeOf(ty_op.operand);
40754423 if (ptr_ty.ptrInfo().data.host_size > 0) {
40764424 try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv);
40774425 } else {
......@@ -4293,17 +4641,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
42934641
42944642 switch (src_mcv) {
42954643 .load_frame => |frame_addr| {
4296 const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*));
4297 const limb_abi_size = @min(field_abi_size, 8);
4298 const limb_abi_bits = limb_abi_size * 8;
4299 const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size);
4300 const field_bit_off = field_off % limb_abi_bits;
4301
4302 if (field_bit_off == 0) {
4303 const off_mcv = MCValue{ .load_frame = .{
4304 .index = frame_addr.index,
4305 .off = frame_addr.off + field_byte_off,
4306 } };
4644 if (field_off % 8 == 0) {
4645 const off_mcv =
4646 src_mcv.address().offset(@intCast(i32, @divExact(field_off, 8))).deref();
43074647 if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv;
43084648
43094649 const dst_mcv = try self.allocRegOrMem(inst, true);
......@@ -4311,6 +4651,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
43114651 break :result dst_mcv;
43124652 }
43134653
4654 const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*));
4655 const limb_abi_size = @min(field_abi_size, 8);
4656 const limb_abi_bits = limb_abi_size * 8;
4657 const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size);
4658 const field_bit_off = field_off % limb_abi_bits;
4659
43144660 if (field_abi_size > 8) {
43154661 return self.fail("TODO implement struct_field_val with large packed field", .{});
43164662 }
......@@ -4448,9 +4794,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
44484794 if (src_ty.zigTypeTag() == .Vector) {
44494795 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
44504796 }
4451 if (src_ty.abiSize(self.target.*) > 8) {
4452 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
4453 }
44544797
44554798 switch (src_mcv) {
44564799 .eflags => |cc| switch (tag) {
......@@ -4466,13 +4809,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
44664809 };
44674810 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
44684811
4469 const dst_mcv: MCValue = if (maybe_inst) |inst|
4470 if (self.reuseOperand(inst, src_air, 0, src_mcv))
4471 src_mcv
4472 else
4473 try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv)
4474 else
4475 .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) };
4812 const dst_mcv: MCValue = dst: {
4813 if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv;
4814
4815 const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true);
4816 try self.genCopy(src_ty, dst_mcv, src_mcv);
4817 break :dst dst_mcv;
4818 };
44764819 const dst_lock = switch (dst_mcv) {
44774820 .register => |reg| self.register_manager.lockReg(reg),
44784821 else => null,
......@@ -4481,19 +4824,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
44814824
44824825 switch (tag) {
44834826 .not => {
4827 const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8));
44844828 const int_info = if (src_ty.tag() == .bool)
44854829 std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 }
44864830 else
44874831 src_ty.intInfo(self.target.*);
4488 const extra_bits = self.regExtraBits(src_ty);
4489 if (int_info.signedness == .unsigned and extra_bits > 0) {
4490 const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1;
4491 try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask });
4492 } else try self.genUnOpMir(.not, src_ty, dst_mcv);
4493 },
4832 var byte_off: i32 = 0;
4833 while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) {
4834 var limb_pl = Type.Payload.Bits{
4835 .base = .{ .tag = switch (int_info.signedness) {
4836 .signed => .int_signed,
4837 .unsigned => .int_unsigned,
4838 } },
4839 .data = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)),
4840 };
4841 const limb_ty = Type.initPayload(&limb_pl.base);
4842 const limb_mcv = switch (byte_off) {
4843 0 => dst_mcv,
4844 else => dst_mcv.address().offset(byte_off).deref(),
4845 };
44944846
4847 if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) {
4848 const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data);
4849 try self.genBinOpMir(.xor, limb_ty, limb_mcv, .{ .immediate = mask });
4850 } else try self.genUnOpMir(.not, limb_ty, limb_mcv);
4851 }
4852 },
44954853 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),
4496
44974854 else => unreachable,
44984855 }
44994856 return dst_mcv;
......@@ -4534,17 +4891,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
45344891 },
45354892 .indirect, .load_frame => try self.asmMemory(
45364893 mir_tag,
4537 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (dst_mcv) {
4538 .indirect => |reg_off| .{
4539 .base = .{ .reg = reg_off.reg },
4540 .disp = reg_off.off,
4541 },
4542 .load_frame => |frame_addr| .{
4543 .base = .{ .frame = frame_addr.index },
4544 .disp = frame_addr.off,
4545 },
4546 else => unreachable,
4547 }),
4894 dst_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
45484895 ),
45494896 }
45504897}
......@@ -5128,24 +5475,69 @@ fn genBinOp(
51285475 switch (tag) {
51295476 .add,
51305477 .addwrap,
5131 => try self.genBinOpMir(switch (lhs_ty.tag()) {
5478 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
51325479 else => .add,
5133 .f32 => .addss,
5134 .f64 => .addsd,
5480 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5481 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5482 .addss
5483 else
5484 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5485 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5486 }),
5487 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5488 .addsd
5489 else
5490 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5491 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5492 }),
5493 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5494 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5495 }),
5496 },
51355497 }, lhs_ty, dst_mcv, src_mcv),
51365498
51375499 .sub,
51385500 .subwrap,
5139 => try self.genBinOpMir(switch (lhs_ty.tag()) {
5501 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
51405502 else => .sub,
5141 .f32 => .subss,
5142 .f64 => .subsd,
5503 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5504 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5505 .subss
5506 else
5507 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5508 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5509 }),
5510 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5511 .subsd
5512 else
5513 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5514 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5515 }),
5516 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5517 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5518 }),
5519 },
51435520 }, lhs_ty, dst_mcv, src_mcv),
51445521
5145 .mul => try self.genBinOpMir(switch (lhs_ty.tag()) {
5146 .f32 => .mulss,
5147 .f64 => .mulsd,
5522 .mul => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
51485523 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
5524 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5525 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5526 .mulss
5527 else
5528 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5529 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5530 }),
5531 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5532 .mulsd
5533 else
5534 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5535 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5536 }),
5537 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5538 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5539 }),
5540 },
51495541 }, lhs_ty, dst_mcv, src_mcv),
51505542
51515543 .div_float,
......@@ -5153,12 +5545,27 @@ fn genBinOp(
51535545 .div_trunc,
51545546 .div_floor,
51555547 => {
5156 try self.genBinOpMir(switch (lhs_ty.tag()) {
5157 .f32 => .divss,
5158 .f64 => .divsd,
5548 try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
51595549 else => return self.fail("TODO implement genBinOp for {s} {}", .{
51605550 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
51615551 }),
5552 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5553 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
5554 .divss
5555 else
5556 return self.fail("TODO implement genBinOp for {s} {} without sse", .{
5557 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5558 }),
5559 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
5560 .divsd
5561 else
5562 return self.fail("TODO implement genBinOp for {s} {} without sse2", .{
5563 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5564 }),
5565 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5566 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5567 }),
5568 },
51625569 }, lhs_ty, dst_mcv, src_mcv);
51635570 switch (tag) {
51645571 .div_float,
......@@ -5169,16 +5576,18 @@ fn genBinOp(
51695576 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
51705577 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
51715578 const dst_alias = registerAlias(dst_mcv.register, abi_size);
5172 try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {
5173 .f32 => .roundss,
5174 .f64 => .roundsd,
5579 try self.asmRegisterRegisterImmediate(switch (lhs_ty.floatBits(self.target.*)) {
5580 32 => .roundss,
5581 64 => .roundsd,
51755582 else => unreachable,
51765583 }, dst_alias, dst_alias, Immediate.u(switch (tag) {
51775584 .div_trunc => 0b1_0_11,
51785585 .div_floor => 0b1_0_01,
51795586 else => unreachable,
51805587 }));
5181 } else return self.fail("TODO implement round without sse4_1", .{}),
5588 } else return self.fail("TODO implement genBinOp for {s} {} without sse4_1", .{
5589 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5590 }),
51825591 else => unreachable,
51835592 }
51845593 },
......@@ -5400,39 +5809,68 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
54005809 )),
54015810 else => unreachable,
54025811 },
5403 .register_offset,
54045812 .eflags,
5813 .register_offset,
54055814 .memory,
5815 .indirect,
54065816 .load_direct,
54075817 .lea_direct,
54085818 .load_got,
54095819 .lea_got,
54105820 .load_tlv,
54115821 .lea_tlv,
5822 .load_frame,
54125823 .lea_frame,
54135824 => {
5414 assert(abi_size <= 8);
5825 blk: {
5826 return self.asmRegisterMemory(
5827 mir_tag,
5828 registerAlias(dst_reg, abi_size),
5829 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
5830 .memory => |addr| .{
5831 .base = .{ .reg = .ds },
5832 .disp = math.cast(i32, addr) orelse break :blk,
5833 },
5834 .indirect => |reg_off| .{
5835 .base = .{ .reg = reg_off.reg },
5836 .disp = reg_off.off,
5837 },
5838 .load_frame => |frame_addr| .{
5839 .base = .{ .frame = frame_addr.index },
5840 .disp = frame_addr.off,
5841 },
5842 else => break :blk,
5843 }),
5844 );
5845 }
5846
54155847 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
54165848 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
54175849
5418 const reg = try self.copyToTmpRegister(ty, src_mcv);
5419 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
5420 },
5421 .indirect, .load_frame => try self.asmRegisterMemory(
5422 mir_tag,
5423 registerAlias(dst_reg, abi_size),
5424 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
5425 .indirect => |reg_off| .{
5426 .base = .{ .reg = reg_off.reg },
5427 .disp = reg_off.off,
5850 switch (src_mcv) {
5851 .eflags,
5852 .register_offset,
5853 .lea_direct,
5854 .lea_got,
5855 .lea_tlv,
5856 .lea_frame,
5857 => {
5858 const reg = try self.copyToTmpRegister(ty, src_mcv);
5859 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
54285860 },
5429 .load_frame => |frame_addr| .{
5430 .base = .{ .frame = frame_addr.index },
5431 .disp = frame_addr.off,
5861 .memory,
5862 .load_direct,
5863 .load_got,
5864 .load_tlv,
5865 => {
5866 const addr_reg = try self.copyToTmpRegister(ty, src_mcv.address());
5867 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{
5868 .indirect = .{ .reg = addr_reg },
5869 });
54325870 },
54335871 else => unreachable,
5434 }),
5435 ),
5872 }
5873 },
54365874 }
54375875 },
54385876 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
......@@ -5769,7 +6207,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
57696207
57706208 const ty = self.air.typeOfIndex(inst);
57716209 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
5772 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index);
6210 const name = self.owner.mod_fn.getParamName(self.bin_file.options.module.?, src_index);
57736211 try self.genArgDbgInfo(ty, name, dst_mcv);
57746212
57756213 break :result dst_mcv;
......@@ -5793,7 +6231,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
57936231 //},
57946232 else => unreachable, // not a valid function parameter
57956233 };
5796 try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, loc);
6234 // TODO: this might need adjusting like the linkers do.
6235 // Instead of flattening the owner and passing Decl.Index here we may
6236 // want to special case LazySymbol in DWARF linker too.
6237 try dw.genArgDbgInfo(name, ty, self.owner.getDecl(), loc);
57976238 },
57986239 .plan9 => {},
57996240 .none => {},
......@@ -5834,7 +6275,10 @@ fn genVarDbgInfo(
58346275 break :blk .nop;
58356276 },
58366277 };
5837 try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc);
6278 // TODO: this might need adjusting like the linkers do.
6279 // Instead of flattening the owner and passing Decl.Index here we may
6280 // want to special case LazySymbol in DWARF linker too.
6281 try dw.genVarDbgInfo(name, ty, self.owner.getDecl(), is_ptr, loc);
58386282 },
58396283 .plan9 => {},
58406284 .none => {},
......@@ -5966,12 +6410,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
59666410 .base = .{ .reg = .ds },
59676411 .disp = @intCast(i32, got_addr),
59686412 }));
5969 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5970 const sym_index = try self.getSymbolIndexForDecl(func.owner_decl);
6413 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6414 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
6415 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
59716416 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
59726417 try self.asmRegister(.call, .rax);
5973 } else if (self.bin_file.cast(link.File.MachO)) |_| {
5974 const sym_index = try self.getSymbolIndexForDecl(func.owner_decl);
6418 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6419 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
6420 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
59756421 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
59766422 try self.asmRegister(.call, .rax);
59776423 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
......@@ -5992,7 +6438,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
59926438 const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0);
59936439 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);
59946440 if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5995 const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl);
6441 const atom_index = try self.owner.getSymbolIndex(self);
59966442 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
59976443 _ = try self.addInst(.{
59986444 .tag = .mov_linker,
......@@ -6005,8 +6451,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
60056451 });
60066452 try self.asmRegister(.call, .rax);
60076453 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6454 const atom_index = try self.owner.getSymbolIndex(self);
60086455 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
6009 const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl);
60106456 _ = try self.addInst(.{
60116457 .tag = .call_extern,
60126458 .ops = undefined,
......@@ -6122,10 +6568,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
61226568 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
61236569
61246570 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6125 try self.genBinOpMir(switch (ty.tag()) {
6571 try self.genBinOpMir(switch (ty.zigTypeTag()) {
61266572 else => .cmp,
6127 .f32 => .ucomiss,
6128 .f64 => .ucomisd,
6573 .Float => switch (ty.floatBits(self.target.*)) {
6574 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
6575 .ucomiss
6576 else
6577 return self.fail("TODO implement airCmp for {} without sse", .{
6578 ty.fmt(self.bin_file.options.module.?),
6579 }),
6580 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
6581 .ucomisd
6582 else
6583 return self.fail("TODO implement airCmp for {} without sse2", .{
6584 ty.fmt(self.bin_file.options.module.?),
6585 }),
6586 else => return self.fail("TODO implement airCmp for {}", .{
6587 ty.fmt(self.bin_file.options.module.?),
6588 }),
6589 },
61296590 }, ty, dst_mcv, src_mcv);
61306591
61316592 const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
......@@ -6141,42 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
61416602}
61426603
61436604fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
6605 const mod = self.bin_file.options.module.?;
61446606 const un_op = self.air.instructions.items(.data)[inst].un_op;
61456607
61466608 const addr_reg = try self.register_manager.allocReg(null, gp);
6147 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
6148 defer self.register_manager.unlockReg(addr_lock);
6149
6150 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6151 const atom_index = try elf_file.getOrCreateAtomForLazySymbol(
6152 .{ .kind = .const_data, .ty = Type.anyerror },
6153 4, // dword alignment
6154 );
6155 const atom = elf_file.getAtom(atom_index);
6156 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
6157 const got_addr = atom.getOffsetTableAddress(elf_file);
6158 try self.asmRegisterMemory(
6159 .mov,
6160 addr_reg.to64(),
6161 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }),
6162 );
6163 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6164 const atom_index = try coff_file.getOrCreateAtomForLazySymbol(
6165 .{ .kind = .const_data, .ty = Type.anyerror },
6166 4, // dword alignment
6167 );
6168 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
6169 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
6170 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6171 const atom_index = try macho_file.getOrCreateAtomForLazySymbol(
6172 .{ .kind = .const_data, .ty = Type.anyerror },
6173 4, // dword alignment
6174 );
6175 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
6176 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
6177 } else {
6178 return self.fail("TODO implement airCmpLtErrorsLen for x86_64 {s}", .{@tagName(self.bin_file.tag)});
6179 }
6609 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
6610 defer self.register_manager.unlockReg(addr_lock);
6611 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
61806612
61816613 try self.spillEflagsIfOccupied();
61826614 self.eflags_inst = inst;
......@@ -6345,35 +6777,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
63456777 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
63466778 }
63476779
6348 const outer_state = try self.saveState();
6349 {
6350 self.scope_generation += 1;
6351 const inner_state = try self.saveState();
6780 self.scope_generation += 1;
6781 const state = try self.saveState();
63526782
6353 for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand);
6354 try self.genBody(then_body);
6355 try self.restoreState(inner_state, &.{}, .{
6356 .emit_instructions = false,
6357 .update_tracking = true,
6358 .resurrect = true,
6359 .close_scope = true,
6360 });
6783 for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand);
6784 try self.genBody(then_body);
6785 try self.restoreState(state, &.{}, .{
6786 .emit_instructions = false,
6787 .update_tracking = true,
6788 .resurrect = true,
6789 .close_scope = true,
6790 });
63616791
6362 try self.performReloc(reloc);
6792 try self.performReloc(reloc);
63636793
6364 for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand);
6365 try self.genBody(else_body);
6366 try self.restoreState(inner_state, &.{}, .{
6367 .emit_instructions = false,
6368 .update_tracking = true,
6369 .resurrect = true,
6370 .close_scope = true,
6371 });
6372 }
6373 try self.restoreState(outer_state, &.{}, .{
6794 for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand);
6795 try self.genBody(else_body);
6796 try self.restoreState(state, &.{}, .{
63746797 .emit_instructions = false,
6375 .update_tracking = false,
6376 .resurrect = false,
6798 .update_tracking = true,
6799 .resurrect = true,
63776800 .close_scope = true,
63786801 });
63796802
......@@ -6746,64 +7169,56 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
67467169 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
67477170 }
67487171
6749 const outer_state = try self.saveState();
6750 {
6751 self.scope_generation += 1;
6752 const inner_state = try self.saveState();
6753
6754 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
6755 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
6756 const items = @ptrCast(
6757 []const Air.Inst.Ref,
6758 self.air.extra[case.end..][0..case.data.items_len],
6759 );
6760 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
6761 extra_index = case.end + items.len + case_body.len;
7172 self.scope_generation += 1;
7173 const state = try self.saveState();
67627174
6763 var relocs = try self.gpa.alloc(u32, items.len);
6764 defer self.gpa.free(relocs);
7175 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
7176 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
7177 const items = @ptrCast(
7178 []const Air.Inst.Ref,
7179 self.air.extra[case.end..][0..case.data.items_len],
7180 );
7181 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
7182 extra_index = case.end + items.len + case_body.len;
67657183
6766 for (items, relocs) |item, *reloc| {
6767 try self.spillEflagsIfOccupied();
6768 const item_mcv = try self.resolveInst(item);
6769 try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
6770 reloc.* = try self.asmJccReloc(undefined, .ne);
6771 }
7184 var relocs = try self.gpa.alloc(u32, items.len);
7185 defer self.gpa.free(relocs);
67727186
6773 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);
7187 try self.spillEflagsIfOccupied();
7188 for (items, relocs, 0..) |item, *reloc, i| {
7189 const item_mcv = try self.resolveInst(item);
7190 try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
7191 reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne);
7192 }
67747193
6775 try self.genBody(case_body);
6776 try self.restoreState(inner_state, &.{}, .{
6777 .emit_instructions = false,
6778 .update_tracking = true,
6779 .resurrect = true,
6780 .close_scope = true,
6781 });
7194 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);
67827195
6783 for (relocs) |reloc| try self.performReloc(reloc);
6784 }
7196 for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc);
7197 try self.genBody(case_body);
7198 try self.restoreState(state, &.{}, .{
7199 .emit_instructions = false,
7200 .update_tracking = true,
7201 .resurrect = true,
7202 .close_scope = true,
7203 });
67857204
6786 if (switch_br.data.else_body_len > 0) {
6787 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
7205 try self.performReloc(relocs[relocs.len - 1]);
7206 }
67887207
6789 const else_deaths = liveness.deaths.len - 1;
6790 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);
7208 if (switch_br.data.else_body_len > 0) {
7209 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
67917210
6792 try self.genBody(else_body);
6793 try self.restoreState(inner_state, &.{}, .{
6794 .emit_instructions = false,
6795 .update_tracking = true,
6796 .resurrect = true,
6797 .close_scope = true,
6798 });
6799 }
7211 const else_deaths = liveness.deaths.len - 1;
7212 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);
7213
7214 try self.genBody(else_body);
7215 try self.restoreState(state, &.{}, .{
7216 .emit_instructions = false,
7217 .update_tracking = true,
7218 .resurrect = true,
7219 .close_scope = true,
7220 });
68007221 }
6801 try self.restoreState(outer_state, &.{}, .{
6802 .emit_instructions = false,
6803 .update_tracking = false,
6804 .resurrect = false,
6805 .close_scope = true,
6806 });
68077222
68087223 // We already took care of pl_op.operand earlier, so we're going to pass .none here
68097224 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
......@@ -7289,7 +7704,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
72897704 }),
72907705 ),
72917706 .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) {
7292 const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl);
7707 const atom_index = try self.owner.getSymbolIndex(self);
72937708 _ = try self.addInst(.{
72947709 .tag = .mov_linker,
72957710 .ops = .direct_reloc,
......@@ -7316,7 +7731,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
73167731 );
73177732 },
73187733 .lea_direct, .lea_got => |sym_index| {
7319 const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl);
7734 const atom_index = try self.owner.getSymbolIndex(self);
73207735 _ = try self.addInst(.{
73217736 .tag = switch (src_mcv) {
73227737 .lea_direct => .lea_linker,
......@@ -7336,7 +7751,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
73367751 });
73377752 },
73387753 .lea_tlv => |sym_index| {
7339 const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl);
7754 const atom_index = try self.owner.getSymbolIndex(self);
73407755 if (self.bin_file.cast(link.File.MachO)) |_| {
73417756 _ = try self.addInst(.{
73427757 .tag = .lea_linker,
......@@ -7531,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
75317946 });
75327947}
75337948
7949fn genLazySymbolRef(
7950 self: *Self,
7951 comptime tag: Mir.Inst.Tag,
7952 reg: Register,
7953 lazy_sym: link.File.LazySymbol,
7954) InnerError!void {
7955 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
7956 const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
7957 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
7958 const atom = elf_file.getAtom(atom_index);
7959 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
7960 const got_addr = atom.getOffsetTableAddress(elf_file);
7961 const got_mem =
7962 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });
7963 switch (tag) {
7964 .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem),
7965 .call => try self.asmMemory(.call, got_mem),
7966 else => unreachable,
7967 }
7968 switch (tag) {
7969 .lea, .call => {},
7970 .mov => try self.asmRegisterMemory(
7971 tag,
7972 reg.to64(),
7973 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
7974 ),
7975 else => unreachable,
7976 }
7977 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
7978 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
7979 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
7980 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
7981 switch (tag) {
7982 .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }),
7983 .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }),
7984 else => unreachable,
7985 }
7986 switch (tag) {
7987 .lea, .mov => {},
7988 .call => try self.asmRegister(.call, reg),
7989 else => unreachable,
7990 }
7991 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
7992 const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
7993 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
7994 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
7995 switch (tag) {
7996 .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }),
7997 .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }),
7998 else => unreachable,
7999 }
8000 switch (tag) {
8001 .lea, .mov => {},
8002 .call => try self.asmRegister(.call, reg),
8003 else => unreachable,
8004 }
8005 } else {
8006 return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)});
8007 }
8008}
8009
75348010fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
75358011 const un_op = self.air.instructions.items(.data)[inst].un_op;
75368012 const result = result: {
......@@ -7555,7 +8031,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
75558031 const dst_rc = try self.regClassForType(dst_ty);
75568032 const src_rc = try self.regClassForType(src_ty);
75578033 const operand = try self.resolveInst(ty_op.operand);
7558 if (dst_rc.eql(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
8034 if (dst_rc.supersetOf(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand))
8035 break :result operand;
75598036
75608037 const operand_lock = switch (operand) {
75618038 .register => |reg| self.register_manager.lockReg(reg),
......@@ -7595,9 +8072,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
75958072
75968073fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
75978074 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7598 _ = ty_op;
7599 return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch});
7600 //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
8075
8076 const src_ty = self.air.typeOf(ty_op.operand);
8077 const src_bits = @intCast(u32, src_ty.bitSize(self.target.*));
8078 const src_signedness =
8079 if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned;
8080 const dst_ty = self.air.typeOfIndex(inst);
8081
8082 const src_size = std.math.divCeil(u32, @max(switch (src_signedness) {
8083 .signed => src_bits,
8084 .unsigned => src_bits + 1,
8085 }, 32), 8) catch unreachable;
8086 if (src_size > 8) return self.fail("TODO implement airIntToFloat from {} to {}", .{
8087 src_ty.fmt(self.bin_file.options.module.?),
8088 dst_ty.fmt(self.bin_file.options.module.?),
8089 });
8090
8091 const src_mcv = try self.resolveInst(ty_op.operand);
8092 const src_reg = switch (src_mcv) {
8093 .register => |reg| reg,
8094 else => try self.copyToTmpRegister(src_ty, src_mcv),
8095 };
8096 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
8097 defer self.register_manager.unlockReg(src_lock);
8098
8099 if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);
8100
8101 const dst_reg = try self.register_manager.allocReg(inst, try self.regClassForType(dst_ty));
8102 const dst_mcv = MCValue{ .register = dst_reg };
8103 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
8104 defer self.register_manager.unlockReg(dst_lock);
8105
8106 try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) {
8107 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
8108 .cvtsi2ss
8109 else
8110 return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{
8111 src_ty.fmt(self.bin_file.options.module.?),
8112 dst_ty.fmt(self.bin_file.options.module.?),
8113 }),
8114 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
8115 .cvtsi2sd
8116 else
8117 return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{
8118 src_ty.fmt(self.bin_file.options.module.?),
8119 dst_ty.fmt(self.bin_file.options.module.?),
8120 }),
8121 else => return self.fail("TODO implement airIntToFloat from {} to {}", .{
8122 src_ty.fmt(self.bin_file.options.module.?),
8123 dst_ty.fmt(self.bin_file.options.module.?),
8124 }),
8125 }, dst_reg.to128(), registerAlias(src_reg, src_size));
8126
8127 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
76018128}
76028129
76038130fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
......@@ -7652,70 +8179,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
76528179 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
76538180
76548181 const ptr_ty = self.air.typeOf(extra.ptr);
7655 const ptr_mcv = try self.resolveInst(extra.ptr);
76568182 const val_ty = self.air.typeOf(extra.expected_value);
76578183 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
76588184
76598185 try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
76608186 const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
7661 for (regs_lock) |lock| self.register_manager.unlockReg(lock);
8187 defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
76628188
76638189 const exp_mcv = try self.resolveInst(extra.expected_value);
7664 if (val_abi_size > 8) switch (exp_mcv) {
7665 .load_frame => |frame_addr| {
7666 try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{
7667 .index = frame_addr.index,
7668 .off = frame_addr.off + 0,
7669 } });
7670 try self.genSetReg(.rdx, Type.usize, .{ .load_frame = .{
7671 .index = frame_addr.index,
7672 .off = frame_addr.off + 8,
7673 } });
7674 },
7675 else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
8190 if (val_abi_size > 8) {
8191 try self.genSetReg(.rax, Type.usize, exp_mcv);
8192 try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref());
76768193 } else try self.genSetReg(.rax, val_ty, exp_mcv);
7677 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
7678 defer self.register_manager.unlockReg(rax_lock);
76798194
76808195 const new_mcv = try self.resolveInst(extra.new_value);
7681 const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) {
7682 .load_frame => |frame_addr| new: {
7683 try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{
7684 .index = frame_addr.index,
7685 .off = frame_addr.off + 0,
7686 } });
7687 try self.genSetReg(.rcx, Type.usize, .{ .load_frame = .{
7688 .index = frame_addr.index,
7689 .off = frame_addr.off + 8,
7690 } });
7691 break :new undefined;
7692 },
7693 else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
8196 const new_reg = if (val_abi_size > 8) new: {
8197 try self.genSetReg(.rbx, Type.usize, new_mcv);
8198 try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref());
8199 break :new null;
76948200 } else try self.copyToTmpRegister(val_ty, new_mcv);
7695 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
7696 defer self.register_manager.unlockReg(new_lock);
8201 const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
8202 defer if (new_lock) |lock| self.register_manager.unlockReg(lock);
76978203
8204 const ptr_mcv = try self.resolveInst(extra.ptr);
76988205 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
76998206 const ptr_mem = switch (ptr_mcv) {
7700 .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),
7701 .lea_frame => |frame_addr| Memory.sib(ptr_size, .{
7702 .base = .{ .frame = frame_addr.index },
7703 .disp = frame_addr.off,
8207 .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
8208 else => Memory.sib(ptr_size, .{
8209 .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
77048210 }),
7705 else => Memory.sib(ptr_size, .{ .base = .{
7706 .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
7707 } }),
77088211 };
7709 const mem_lock = switch (ptr_mem.base()) {
8212 switch (ptr_mem) {
8213 .sib, .rip => {},
8214 .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
8215 }
8216 const ptr_lock = switch (ptr_mem.base()) {
77108217 .none, .frame => null,
77118218 .reg => |reg| self.register_manager.lockReg(reg),
77128219 };
7713 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
8220 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
77148221
77158222 try self.spillEflagsIfOccupied();
77168223 if (val_abi_size <= 8) {
77178224 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
7718 .r = registerAlias(new_reg, val_abi_size),
8225 .r = registerAlias(new_reg.?, val_abi_size),
77198226 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
77208227 } } });
77218228 } else {
......@@ -7733,24 +8240,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
77338240 }
77348241
77358242 const dst_mcv = try self.allocRegOrMem(inst, false);
7736 try self.genSetMem(
7737 .{ .frame = dst_mcv.load_frame.index },
7738 dst_mcv.load_frame.off + 16,
7739 Type.bool,
7740 .{ .eflags = .ne },
7741 );
7742 try self.genSetMem(
7743 .{ .frame = dst_mcv.load_frame.index },
7744 dst_mcv.load_frame.off + 8,
7745 Type.usize,
7746 .{ .register = .rdx },
7747 );
7748 try self.genSetMem(
7749 .{ .frame = dst_mcv.load_frame.index },
7750 dst_mcv.load_frame.off + 0,
7751 Type.usize,
7752 .{ .register = .rax },
7753 );
8243 try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax });
8244 try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx });
8245 try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne });
77548246 break :result dst_mcv;
77558247 };
77568248 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
......@@ -7781,15 +8273,15 @@ fn atomicOp(
77818273 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
77828274 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
77838275 const ptr_mem = switch (ptr_mcv) {
7784 .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),
7785 .lea_frame => |frame_addr| Memory.sib(ptr_size, .{
7786 .base = .{ .frame = frame_addr.index },
7787 .disp = frame_addr.off,
8276 .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
8277 else => Memory.sib(ptr_size, .{
8278 .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
77888279 }),
7789 else => Memory.sib(ptr_size, .{ .base = .{
7790 .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
7791 } }),
77928280 };
8281 switch (ptr_mem) {
8282 .sib, .rip => {},
8283 .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
8284 }
77938285 const mem_lock = switch (ptr_mem.base()) {
77948286 .none, .frame => null,
77958287 .reg => |reg| self.register_manager.lockReg(reg),
......@@ -7895,12 +8387,9 @@ fn atomicOp(
78958387 registerAlias(val_reg, cmov_abi_size),
78968388 cc,
78978389 ),
7898 .load_frame => |frame_addr| try self.asmCmovccRegisterMemory(
8390 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
78998391 registerAlias(tmp_reg, cmov_abi_size),
7900 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{
7901 .base = .{ .frame = frame_addr.index },
7902 .disp = frame_addr.off,
7903 }),
8392 val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
79048393 cc,
79058394 ),
79068395 else => {
......@@ -7923,72 +8412,62 @@ fn atomicOp(
79238412 } else {
79248413 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
79258414 .base = ptr_mem.sib.base,
7926 .scale_index = ptr_mem.sib.scale_index,
8415 .scale_index = ptr_mem.scaleIndex(),
79278416 .disp = ptr_mem.sib.disp + 0,
79288417 }));
79298418 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{
79308419 .base = ptr_mem.sib.base,
7931 .scale_index = ptr_mem.sib.scale_index,
8420 .scale_index = ptr_mem.scaleIndex(),
79328421 .disp = ptr_mem.sib.disp + 8,
79338422 }));
79348423 const loop = @intCast(u32, self.mir_instructions.len);
7935 switch (val_mcv) {
7936 .load_frame => |frame_addr| {
7937 const val_lo_mem = Memory.sib(.qword, .{
7938 .base = .{ .frame = frame_addr.index },
7939 .disp = frame_addr.off + 0,
7940 });
7941 const val_hi_mem = Memory.sib(.qword, .{
7942 .base = .{ .frame = frame_addr.index },
7943 .disp = frame_addr.off + 8,
7944 });
7945
7946 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
7947 try self.asmRegisterRegister(.mov, .rbx, .rax);
7948 try self.asmRegisterRegister(.mov, .rcx, .rdx);
7949 }
7950 if (rmw_op) |op| switch (op) {
7951 .Xchg => {
7952 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
7953 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
7954 },
7955 .Add => {
7956 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
7957 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
7958 },
7959 .Sub => {
7960 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
7961 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
7962 },
7963 .And => {
7964 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
7965 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
7966 },
7967 .Nand => {
7968 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
7969 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
7970 try self.asmRegister(.not, .rbx);
7971 try self.asmRegister(.not, .rcx);
7972 },
7973 .Or => {
7974 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
7975 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
7976 },
7977 .Xor => {
7978 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
7979 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
7980 },
7981 else => return self.fail(
7982 "TODO implement x86 atomic loop for large abi {s}",
7983 .{@tagName(op)},
7984 ),
7985 };
7986 },
7987 else => return self.fail(
7988 "TODO implement x86 atomic loop for large abi {s}",
7989 .{@tagName(val_mcv)},
7990 ),
8424 const val_mem_mcv: MCValue = switch (val_mcv) {
8425 .memory, .indirect, .load_frame => val_mcv,
8426 else => .{ .indirect = .{
8427 .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()),
8428 } },
8429 };
8430 const val_lo_mem = val_mem_mcv.mem(.qword);
8431 const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword);
8432 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
8433 try self.asmRegisterRegister(.mov, .rbx, .rax);
8434 try self.asmRegisterRegister(.mov, .rcx, .rdx);
79918435 }
8436 if (rmw_op) |op| switch (op) {
8437 .Xchg => {
8438 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
8439 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
8440 },
8441 .Add => {
8442 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
8443 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
8444 },
8445 .Sub => {
8446 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
8447 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
8448 },
8449 .And => {
8450 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8451 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8452 },
8453 .Nand => {
8454 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
8455 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
8456 try self.asmRegister(.not, .rbx);
8457 try self.asmRegister(.not, .rcx);
8458 },
8459 .Or => {
8460 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
8461 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
8462 },
8463 .Xor => {
8464 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
8465 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
8466 },
8467 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{
8468 val_ty.fmt(self.bin_file.options.module.?), @tagName(op),
8469 }),
8470 };
79928471 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
79938472 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
79948473 } });
......@@ -8230,14 +8709,48 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
82308709}
82318710
82328711fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
8712 const mod = self.bin_file.options.module.?;
82338713 const un_op = self.air.instructions.items(.data)[inst].un_op;
8714 const inst_ty = self.air.typeOfIndex(inst);
8715 const enum_ty = self.air.typeOf(un_op);
8716
8717 // We need a properly aligned and sized call frame to be able to call this function.
8718 {
8719 const needed_call_frame = FrameAlloc.init(.{
8720 .size = inst_ty.abiSize(self.target.*),
8721 .alignment = inst_ty.abiAlignment(self.target.*),
8722 });
8723 const frame_allocs_slice = self.frame_allocs.slice();
8724 const stack_frame_size =
8725 &frame_allocs_slice.items(.abi_size)[@enumToInt(FrameIndex.call_frame)];
8726 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
8727 const stack_frame_align =
8728 &frame_allocs_slice.items(.abi_align)[@enumToInt(FrameIndex.call_frame)];
8729 stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align);
8730 }
8731
8732 try self.spillEflagsIfOccupied();
8733 try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*));
8734
8735 const param_regs = abi.getCAbiIntParamRegs(self.target.*);
8736
8737 const dst_mcv = try self.allocRegOrMem(inst, false);
8738 try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address());
8739
82348740 const operand = try self.resolveInst(un_op);
8235 _ = operand;
8236 return self.fail("TODO implement airTagName for x86_64", .{});
8237 //return self.finishAir(inst, result, .{ un_op, .none, .none });
8741 try self.genSetReg(param_regs[1], enum_ty, operand);
8742
8743 try self.genLazySymbolRef(
8744 .call,
8745 .rax,
8746 link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod),
8747 );
8748
8749 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
82388750}
82398751
82408752fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8753 const mod = self.bin_file.options.module.?;
82418754 const un_op = self.air.instructions.items(.data)[inst].un_op;
82428755
82438756 const err_ty = self.air.typeOf(un_op);
......@@ -8249,37 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
82498762 const addr_reg = try self.register_manager.allocReg(null, gp);
82508763 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
82518764 defer self.register_manager.unlockReg(addr_lock);
8252
8253 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
8254 const atom_index = try elf_file.getOrCreateAtomForLazySymbol(
8255 .{ .kind = .const_data, .ty = Type.anyerror },
8256 4, // dword alignment
8257 );
8258 const atom = elf_file.getAtom(atom_index);
8259 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
8260 const got_addr = atom.getOffsetTableAddress(elf_file);
8261 try self.asmRegisterMemory(
8262 .mov,
8263 addr_reg.to64(),
8264 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }),
8265 );
8266 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
8267 const atom_index = try coff_file.getOrCreateAtomForLazySymbol(
8268 .{ .kind = .const_data, .ty = Type.anyerror },
8269 4, // dword alignment
8270 );
8271 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
8272 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
8273 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
8274 const atom_index = try macho_file.getOrCreateAtomForLazySymbol(
8275 .{ .kind = .const_data, .ty = Type.anyerror },
8276 4, // dword alignment
8277 );
8278 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
8279 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
8280 } else {
8281 return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)});
8282 }
8765 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
82838766
82848767 const start_reg = try self.register_manager.allocReg(null, gp);
82858768 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);
......@@ -8596,12 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
85969079}
85979080
85989081fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
8599 const mcv: MCValue = switch (try codegen.genTypedValue(
8600 self.bin_file,
8601 self.src_loc,
8602 arg_tv,
8603 self.mod_fn.owner_decl,
8604 )) {
9082 return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) {
86059083 .mcv => |mcv| switch (mcv) {
86069084 .none => .none,
86079085 .undef => .undef,
......@@ -8616,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
86169094 return error.CodegenFail;
86179095 },
86189096 };
8619 return mcv;
86209097}
86219098
86229099const CallMCValues = struct {
......@@ -8664,6 +9141,7 @@ fn resolveCallingConventionValues(
86649141 },
86659142 .C => {
86669143 var param_reg_i: usize = 0;
9144 var param_sse_reg_i: usize = 0;
86679145 result.stack_align = 16;
86689146
86699147 switch (self.target.os.tag) {
......@@ -8681,26 +9159,39 @@ fn resolveCallingConventionValues(
86819159 // TODO: is this even possible for C calling convention?
86829160 result.return_value = InstTracking.init(.none);
86839161 } else {
8684 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];
8685 const ret_ty_size = @intCast(u31, ret_ty.abiSize(self.target.*));
8686 if (ret_ty_size <= 8) {
8687 const aliased_reg = registerAlias(ret_reg, ret_ty_size);
8688 result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none };
8689 } else {
8690 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
8691 param_reg_i += 1;
8692 result.return_value = .{
8693 .short = .{ .indirect = .{ .reg = ret_reg } },
8694 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
8695 };
9162 const classes = switch (self.target.os.tag) {
9163 .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)},
9164 else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none),
9165 };
9166 if (classes.len > 1) {
9167 return self.fail("TODO handle multiple classes per type", .{});
86969168 }
9169 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];
9170 result.return_value = switch (classes[0]) {
9171 .integer => InstTracking.init(.{ .register = registerAlias(
9172 ret_reg,
9173 @intCast(u32, ret_ty.abiSize(self.target.*)),
9174 ) }),
9175 .float, .sse => InstTracking.init(.{ .register = .xmm0 }),
9176 .memory => ret: {
9177 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
9178 param_reg_i += 1;
9179 break :ret .{
9180 .short = .{ .indirect = .{ .reg = ret_reg } },
9181 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
9182 };
9183 },
9184 else => |class| return self.fail("TODO handle calling convention class {s}", .{
9185 @tagName(class),
9186 }),
9187 };
86979188 }
86989189
86999190 // Input params
87009191 for (param_types, result.args) |ty, *arg| {
87019192 assert(ty.hasRuntimeBitsIgnoreComptime());
87029193
8703 const classes: []const abi.Class = switch (self.target.os.tag) {
9194 const classes = switch (self.target.os.tag) {
87049195 .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)},
87059196 else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none),
87069197 };
......@@ -8708,13 +9199,29 @@ fn resolveCallingConventionValues(
87089199 return self.fail("TODO handle multiple classes per type", .{});
87099200 }
87109201 switch (classes[0]) {
8711 .integer => blk: {
8712 if (param_reg_i >= abi.getCAbiIntParamRegs(self.target.*).len) break :blk;
8713 const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
9202 .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) {
9203 arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] };
87149204 param_reg_i += 1;
8715 arg.* = .{ .register = param_reg };
87169205 continue;
87179206 },
9207 .float, .sse => switch (self.target.os.tag) {
9208 .windows => if (param_reg_i < 4) {
9209 arg.* = .{ .register = @intToEnum(
9210 Register,
9211 @enumToInt(Register.xmm0) + param_reg_i,
9212 ) };
9213 param_reg_i += 1;
9214 continue;
9215 },
9216 else => if (param_sse_reg_i < 8) {
9217 arg.* = .{ .register = @intToEnum(
9218 Register,
9219 @enumToInt(Register.xmm0) + param_sse_reg_i,
9220 ) };
9221 param_sse_reg_i += 1;
9222 continue;
9223 },
9224 },
87189225 .memory => {}, // fallthrough
87199226 else => |class| return self.fail("TODO handle calling convention class {s}", .{
87209227 @tagName(class),
......@@ -8863,15 +9370,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
88639370}
88649371
88659372fn regBitSize(self: *Self, ty: Type) u64 {
9373 const abi_size = ty.abiSize(self.target.*);
88669374 return switch (ty.zigTypeTag()) {
8867 else => switch (ty.abiSize(self.target.*)) {
9375 else => switch (abi_size) {
88689376 1 => 8,
88699377 2 => 16,
88709378 3...4 => 32,
88719379 5...8 => 64,
88729380 else => unreachable,
88739381 },
8874 .Float => switch (ty.abiSize(self.target.*)) {
9382 .Float => switch (abi_size) {
88759383 1...16 => 128,
88769384 17...32 => 256,
88779385 else => unreachable,
......@@ -8882,17 +9390,3 @@ fn regBitSize(self: *Self, ty: Type) u64 {
88829390fn regExtraBits(self: *Self, ty: Type) u64 {
88839391 return self.regBitSize(ty) - ty.bitSize(self.target.*);
88849392}
8885
8886fn hasAvxSupport(target: Target) bool {
8887 return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 });
8888}
8889
8890fn getSymbolIndexForDecl(self: *Self, decl_index: Module.Decl.Index) !u32 {
8891 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
8892 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
8893 return macho_file.getAtom(atom).getSymbolIndex().?;
8894 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
8895 const atom = try coff_file.getOrCreateAtomForDecl(decl_index);
8896 return coff_file.getAtom(atom).getSymbolIndex().?;
8897 } else unreachable;
8898}
src/arch/x86_64/Encoding.zig+16-11
......@@ -58,7 +58,7 @@ pub fn findByMnemonic(
5858 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
5959 switch (data.mode) {
6060 .rex => if (!rex_required) continue,
61 .long, .sse2_long => {},
61 .long, .sse_long, .sse2_long => {},
6262 else => if (rex_required) continue,
6363 }
6464 for (input_ops, data.ops) |input_op, data_op|
......@@ -90,7 +90,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
9090 if (prefixes.rex.w) {
9191 switch (data.mode) {
9292 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
93 .long, .sse2_long, .rex => {},
93 .long, .sse_long, .sse2_long, .rex => {},
9494 }
9595 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
9696 switch (data.mode) {
......@@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {
138138pub fn operandBitSize(encoding: Encoding) u64 {
139139 switch (encoding.data.mode) {
140140 .short => return 16,
141 .long, .sse2_long => return 64,
141 .long, .sse_long, .sse2_long => return 64,
142142 else => {},
143143 }
144144 const bit_size: u64 = switch (encoding.data.op_en) {
......@@ -163,7 +163,7 @@ pub fn format(
163163 _ = options;
164164 _ = fmt;
165165 switch (encoding.data.mode) {
166 .long, .sse2_long => try writer.writeAll("REX.W + "),
166 .long, .sse_long, .sse2_long => try writer.writeAll("REX.W + "),
167167 else => {},
168168 }
169169
......@@ -269,21 +269,25 @@ pub const Mnemonic = enum {
269269 // SSE
270270 addss,
271271 cmpss,
272 cvtsi2ss,
272273 divss,
273274 maxss, minss,
274275 movss,
275276 mulss,
276277 subss,
277278 ucomiss,
279 xorps,
278280 // SSE2
279281 addsd,
280282 //cmpsd,
283 cvtsd2ss, cvtsi2sd, cvtss2sd,
281284 divsd,
282285 maxsd, minsd,
283286 movq, //movd, movsd,
284287 mulsd,
285288 subsd,
286289 ucomisd,
290 xorpd,
287291 // SSE4.1
288292 roundss,
289293 roundsd,
......@@ -318,7 +322,7 @@ pub const Op = enum {
318322 m,
319323 moffs,
320324 sreg,
321 xmm, xmm_m32, xmm_m64,
325 xmm, xmm_m32, xmm_m64, xmm_m128,
322326 // zig fmt: on
323327
324328 pub fn fromOperand(operand: Instruction.Operand) Op {
......@@ -400,7 +404,7 @@ pub const Op = enum {
400404 .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
401405 .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
402406 .m80 => 80,
403 .m128, .xmm => 128,
407 .m128, .xmm, .xmm_m128 => 128,
404408 };
405409 }
406410
......@@ -423,8 +427,8 @@ pub const Op = enum {
423427 .al, .ax, .eax, .rax,
424428 .r8, .r16, .r32, .r64,
425429 .rm8, .rm16, .rm32, .rm64,
426 .xmm, .xmm_m32, .xmm_m64,
427 => true,
430 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
431 => true,
428432 else => false,
429433 };
430434 // zig fmt: on
......@@ -449,7 +453,7 @@ pub const Op = enum {
449453 .rm8, .rm16, .rm32, .rm64,
450454 .m8, .m16, .m32, .m64, .m80, .m128,
451455 .m,
452 .xmm_m32, .xmm_m64,
456 .xmm_m32, .xmm_m64, .xmm_m128,
453457 => true,
454458 else => false,
455459 };
......@@ -470,13 +474,13 @@ pub const Op = enum {
470474 .r8, .r16, .r32, .r64 => .general_purpose,
471475 .rm8, .rm16, .rm32, .rm64 => .general_purpose,
472476 .sreg => .segment,
473 .xmm, .xmm_m32, .xmm_m64 => .floating_point,
477 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
474478 };
475479 }
476480
477481 pub fn isFloatingPointRegister(op: Op) bool {
478482 return switch (op) {
479 .xmm, .xmm_m32, .xmm_m64 => true,
483 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => true,
480484 else => false,
481485 };
482486 }
......@@ -535,6 +539,7 @@ pub const Mode = enum {
535539 rex,
536540 long,
537541 sse,
542 sse_long,
538543 sse2,
539544 sse2_long,
540545 sse4_1,
src/arch/x86_64/Lower.zig+6
......@@ -95,6 +95,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
9595
9696 .addss,
9797 .cmpss,
98 .cvtsi2ss,
9899 .divss,
99100 .maxss,
100101 .minss,
......@@ -103,8 +104,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
103104 .roundss,
104105 .subss,
105106 .ucomiss,
107 .xorps,
106108 .addsd,
107109 .cmpsd,
110 .cvtsd2ss,
111 .cvtsi2sd,
112 .cvtss2sd,
108113 .divsd,
109114 .maxsd,
110115 .minsd,
......@@ -113,6 +118,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
113118 .roundsd,
114119 .subsd,
115120 .ucomisd,
121 .xorpd,
116122 => try lower.mirGeneric(inst),
117123
118124 .cmps,
src/arch/x86_64/Mir.zig+12
......@@ -170,6 +170,8 @@ pub const Inst = struct {
170170 addss,
171171 /// Compare scalar single-precision floating-point values
172172 cmpss,
173 /// Convert doubleword integer to scalar single-precision floating-point value
174 cvtsi2ss,
173175 /// Divide scalar single-precision floating-point values
174176 divss,
175177 /// Return maximum single-precision floating-point value
......@@ -186,10 +188,18 @@ pub const Inst = struct {
186188 subss,
187189 /// Unordered compare scalar single-precision floating-point values
188190 ucomiss,
191 /// Bitwise logical xor of packed single precision floating-point values
192 xorps,
189193 /// Add double precision floating point values
190194 addsd,
191195 /// Compare scalar double-precision floating-point values
192196 cmpsd,
197 /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value
198 cvtsd2ss,
199 /// Convert doubleword integer to scalar double-precision floating-point value
200 cvtsi2sd,
201 /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value
202 cvtss2sd,
193203 /// Divide scalar double-precision floating-point values
194204 divsd,
195205 /// Return maximum double-precision floating-point value
......@@ -206,6 +216,8 @@ pub const Inst = struct {
206216 subsd,
207217 /// Unordered compare scalar double-precision floating-point values
208218 ucomisd,
219 /// Bitwise logical xor of packed double precision floating-point values
220 xorpd,
209221
210222 /// Compare string operands
211223 cmps,
src/arch/x86_64/encoder.zig+1-1
......@@ -323,7 +323,7 @@ pub const Instruction = struct {
323323 var rex = Rex{};
324324 rex.present = inst.encoding.data.mode == .rex;
325325 switch (inst.encoding.data.mode) {
326 .long, .sse2_long => rex.w = true,
326 .long, .sse_long, .sse2_long => rex.w = true,
327327 else => {},
328328 }
329329
src/arch/x86_64/encodings.zig+14
......@@ -834,6 +834,9 @@ pub const table = [_]Entry{
834834
835835 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse },
836836
837 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse },
838 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse_long },
839
837840 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },
838841
839842 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },
......@@ -849,11 +852,20 @@ pub const table = [_]Entry{
849852
850853 .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse },
851854
855 .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .sse },
856
852857 // SSE2
853858 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },
854859
855860 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 },
856861
862 .{ .cvtsd2ss, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .sse2 },
863
864 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2 },
865 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2_long },
866
867 .{ .cvtss2sd, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .sse2 },
868
857869 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },
858870
859871 .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },
......@@ -878,6 +890,8 @@ pub const table = [_]Entry{
878890
879891 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },
880892
893 .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .sse2 },
894
881895 // SSE4.1
882896 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
883897 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },
src/codegen.zig+117-40
......@@ -7,6 +7,7 @@ const link = @import("link.zig");
77const log = std.log.scoped(.codegen);
88const mem = std.mem;
99const math = std.math;
10const target_util = @import("target.zig");
1011const trace = @import("tracy.zig").trace;
1112
1213const Air = @import("Air.zig");
......@@ -89,25 +90,36 @@ pub fn generateFunction(
8990 }
9091}
9192
93pub fn generateLazyFunction(
94 bin_file: *link.File,
95 src_loc: Module.SrcLoc,
96 lazy_sym: link.File.LazySymbol,
97 code: *std.ArrayList(u8),
98 debug_output: DebugInfoOutput,
99) CodeGenError!Result {
100 switch (bin_file.options.target.cpu.arch) {
101 .x86_64 => return @import("arch/x86_64/CodeGen.zig").generateLazy(bin_file, src_loc, lazy_sym, code, debug_output),
102 else => unreachable,
103 }
104}
105
92106fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void {
93107 _ = target;
94 const Int = @Type(.{ .Int = .{
95 .signedness = .unsigned,
96 .bits = @typeInfo(F).Float.bits,
97 } });
108 const bits = @typeInfo(F).Float.bits;
109 const Int = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } });
98110 const int = @bitCast(Int, f);
99 mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian);
111 mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian);
100112}
101113
102114pub fn generateLazySymbol(
103115 bin_file: *link.File,
104116 src_loc: Module.SrcLoc,
105117 lazy_sym: link.File.LazySymbol,
118 alignment: *u32,
106119 code: *std.ArrayList(u8),
107120 debug_output: DebugInfoOutput,
108121 reloc_info: RelocInfo,
109122) CodeGenError!Result {
110 _ = debug_output;
111123 _ = reloc_info;
112124
113125 const tracy = trace(@src());
......@@ -122,7 +134,13 @@ pub fn generateLazySymbol(
122134 lazy_sym.ty.fmt(mod),
123135 });
124136
125 if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) {
137 if (lazy_sym.kind == .code) {
138 alignment.* = target_util.defaultFunctionAlignment(target);
139 return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output);
140 }
141
142 if (lazy_sym.ty.isAnyError()) {
143 alignment.* = 4;
126144 const err_names = mod.error_name_list.items;
127145 mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian);
128146 var offset = code.items.len;
......@@ -136,6 +154,14 @@ pub fn generateLazySymbol(
136154 }
137155 mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian);
138156 return Result.ok;
157 } else if (lazy_sym.ty.zigTypeTag() == .Enum) {
158 alignment.* = 1;
159 for (lazy_sym.ty.enumFields().keys()) |tag_name| {
160 try code.ensureUnusedCapacity(tag_name.len + 1);
161 code.appendSliceAssumeCapacity(tag_name);
162 code.appendAssumeCapacity(0);
163 }
164 return Result.ok;
139165 } else return .{ .fail = try ErrorMsg.create(
140166 bin_file.allocator,
141167 src_loc,
......@@ -187,18 +213,14 @@ pub fn generateSymbol(
187213 };
188214 },
189215 .Float => {
190 const float_bits = typed_value.ty.floatBits(target);
191 switch (float_bits) {
216 switch (typed_value.ty.floatBits(target)) {
192217 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)),
193218 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)),
194219 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)),
195 80 => return Result{
196 .fail = try ErrorMsg.create(
197 bin_file.allocator,
198 src_loc,
199 "TODO handle f80 in generateSymbol",
200 .{},
201 ),
220 80 => {
221 writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10));
222 const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;
223 try code.appendNTimes(0, abi_size - 10);
202224 },
203225 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)),
204226 else => unreachable,
......@@ -291,6 +313,20 @@ pub fn generateSymbol(
291313 },
292314 },
293315 .Pointer => switch (typed_value.val.tag()) {
316 .null_value => {
317 switch (target.cpu.arch.ptrBitWidth()) {
318 32 => {
319 mem.writeInt(u32, try code.addManyAsArray(4), 0, endian);
320 if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 4);
321 },
322 64 => {
323 mem.writeInt(u64, try code.addManyAsArray(8), 0, endian);
324 if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 8);
325 },
326 else => unreachable,
327 }
328 return Result.ok;
329 },
294330 .zero, .one, .int_u64, .int_big_positive => {
295331 switch (target.cpu.arch.ptrBitWidth()) {
296332 32 => {
......@@ -397,30 +433,15 @@ pub fn generateSymbol(
397433 },
398434 }
399435 },
400 .elem_ptr => {
401 const elem_ptr = typed_value.val.castTag(.elem_ptr).?.data;
402 const elem_size = typed_value.ty.childType().abiSize(target);
403 const addend = @intCast(u32, elem_ptr.index * elem_size);
404 const array_ptr = elem_ptr.array_ptr;
405
406 switch (array_ptr.tag()) {
407 .decl_ref => {
408 const decl_index = array_ptr.castTag(.decl_ref).?.data;
409 return lowerDeclRef(bin_file, src_loc, typed_value, decl_index, code, debug_output, .{
410 .parent_atom_index = reloc_info.parent_atom_index,
411 .addend = (reloc_info.addend orelse 0) + addend,
412 });
413 },
414 else => return Result{
415 .fail = try ErrorMsg.create(
416 bin_file.allocator,
417 src_loc,
418 "TODO implement generateSymbol for pointer type value: '{s}'",
419 .{@tagName(typed_value.val.tag())},
420 ),
421 },
422 }
423 },
436 .elem_ptr => return lowerParentPtr(
437 bin_file,
438 src_loc,
439 typed_value,
440 typed_value.val,
441 code,
442 debug_output,
443 reloc_info,
444 ),
424445 else => return Result{
425446 .fail = try ErrorMsg.create(
426447 bin_file.allocator,
......@@ -838,9 +859,62 @@ pub fn generateSymbol(
838859 }
839860}
840861
862fn lowerParentPtr(
863 bin_file: *link.File,
864 src_loc: Module.SrcLoc,
865 typed_value: TypedValue,
866 parent_ptr: Value,
867 code: *std.ArrayList(u8),
868 debug_output: DebugInfoOutput,
869 reloc_info: RelocInfo,
870) CodeGenError!Result {
871 const target = bin_file.options.target;
872
873 switch (parent_ptr.tag()) {
874 .elem_ptr => {
875 const elem_ptr = parent_ptr.castTag(.elem_ptr).?.data;
876 return lowerParentPtr(
877 bin_file,
878 src_loc,
879 typed_value,
880 elem_ptr.array_ptr,
881 code,
882 debug_output,
883 reloc_info.offset(@intCast(u32, elem_ptr.index * elem_ptr.elem_ty.abiSize(target))),
884 );
885 },
886 .decl_ref => {
887 const decl_index = parent_ptr.castTag(.decl_ref).?.data;
888 return lowerDeclRef(
889 bin_file,
890 src_loc,
891 typed_value,
892 decl_index,
893 code,
894 debug_output,
895 reloc_info,
896 );
897 },
898 else => |t| {
899 return Result{
900 .fail = try ErrorMsg.create(
901 bin_file.allocator,
902 src_loc,
903 "TODO implement lowerParentPtr for type '{s}'",
904 .{@tagName(t)},
905 ),
906 };
907 },
908 }
909}
910
841911const RelocInfo = struct {
842912 parent_atom_index: u32,
843913 addend: ?u32 = null,
914
915 fn offset(ri: RelocInfo, addend: u32) RelocInfo {
916 return .{ .parent_atom_index = ri.parent_atom_index, .addend = (ri.addend orelse 0) + addend };
917 }
844918};
845919
846920fn lowerDeclRef(
......@@ -1095,6 +1169,9 @@ pub fn genTypedValue(
10951169 .Slice => {},
10961170 else => {
10971171 switch (typed_value.val.tag()) {
1172 .null_value => {
1173 return GenResult.mcv(.{ .immediate = 0 });
1174 },
10981175 .int_u64 => {
10991176 return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) });
11001177 },
src/link.zig+2-2
......@@ -1120,8 +1120,8 @@ pub const File = struct {
11201120 kind: Kind,
11211121 ty: Type,
11221122
1123 pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol {
1124 return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index|
1123 pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol {
1124 return .{ .kind = kind, .ty = if (decl) |decl_index|
11251125 mod.declPtr(decl_index).val.castTag(.ty).?.data
11261126 else
11271127 Type.anyerror };
src/link/Coff.zig+66-45
......@@ -143,9 +143,11 @@ const Section = struct {
143143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
144144
145145const LazySymbolMetadata = struct {
146 text_atom: ?Atom.Index = null,
147 rdata_atom: ?Atom.Index = null,
148 alignment: u32,
146 const State = enum { unused, pending_flush, flushed };
147 text_atom: Atom.Index = undefined,
148 rdata_atom: Atom.Index = undefined,
149 text_state: State = .unused,
150 rdata_state: State = .unused,
149151};
150152
151153const DeclMetadata = struct {
......@@ -1137,7 +1139,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
11371139 return atom.getSymbolIndex().?;
11381140}
11391141
1140pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void {
1142pub fn updateDecl(
1143 self: *Coff,
1144 module: *Module,
1145 decl_index: Module.Decl.Index,
1146) link.File.UpdateDeclError!void {
11411147 if (build_options.skip_non_native and builtin.object_format != .coff) {
11421148 @panic("Attempted to compile for object format that was disabled by build configuration");
11431149 }
......@@ -1189,32 +1195,16 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
11891195 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
11901196}
11911197
1192fn updateLazySymbol(self: *Coff, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void {
1193 const mod = self.base.options.module.?;
1194 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
1195 link.File.LazySymbol.initDecl(.code, decl, mod),
1196 atom,
1197 self.text_section_index.?,
1198 metadata.alignment,
1199 );
1200 if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom(
1201 link.File.LazySymbol.initDecl(.const_data, decl, mod),
1202 atom,
1203 self.rdata_section_index.?,
1204 metadata.alignment,
1205 );
1206}
1207
12081198fn updateLazySymbolAtom(
12091199 self: *Coff,
12101200 sym: link.File.LazySymbol,
12111201 atom_index: Atom.Index,
12121202 section_index: u16,
1213 required_alignment: u32,
12141203) !void {
12151204 const gpa = self.base.allocator;
12161205 const mod = self.base.options.module.?;
12171206
1207 var required_alignment: u32 = undefined;
12181208 var code_buffer = std.ArrayList(u8).init(gpa);
12191209 defer code_buffer.deinit();
12201210
......@@ -1235,9 +1225,15 @@ fn updateLazySymbolAtom(
12351225 .parent_decl_node = undefined,
12361226 .lazy = .unneeded,
12371227 };
1238 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
1239 .parent_atom_index = local_sym_index,
1240 });
1228 const res = try codegen.generateLazySymbol(
1229 &self.base,
1230 src,
1231 sym,
1232 &required_alignment,
1233 &code_buffer,
1234 .none,
1235 .{ .parent_atom_index = local_sym_index },
1236 );
12411237 const code = switch (res) {
12421238 .ok => code_buffer.items,
12431239 .fail => |em| {
......@@ -1265,20 +1261,27 @@ fn updateLazySymbolAtom(
12651261 try self.writeAtom(atom_index, code);
12661262}
12671263
1268pub fn getOrCreateAtomForLazySymbol(
1269 self: *Coff,
1270 sym: link.File.LazySymbol,
1271 alignment: u32,
1272) !Atom.Index {
1264pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index {
12731265 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
1274 errdefer _ = self.lazy_syms.pop();
1275 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
1276 const atom = switch (sym.kind) {
1277 .code => &gop.value_ptr.text_atom,
1278 .const_data => &gop.value_ptr.rdata_atom,
1266 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
1267 if (!gop.found_existing) gop.value_ptr.* = .{};
1268 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
1269 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
1270 .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state },
12791271 };
1280 if (atom.* == null) atom.* = try self.createAtom();
1281 return atom.*.?;
1272 switch (metadata.state.*) {
1273 .unused => metadata.atom.* = try self.createAtom(),
1274 .pending_flush => return metadata.atom.*,
1275 .flushed => {},
1276 }
1277 metadata.state.* = .pending_flush;
1278 const atom = metadata.atom.*;
1279 // anyerror needs to be deferred until flushModule
1280 if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
1281 .code => self.text_section_index.?,
1282 .const_data => self.rdata_section_index.?,
1283 });
1284 return atom;
12821285}
12831286
12841287pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
......@@ -1410,7 +1413,7 @@ pub fn updateDeclExports(
14101413 module: *Module,
14111414 decl_index: Module.Decl.Index,
14121415 exports: []const *Module.Export,
1413) !void {
1416) link.File.UpdateDeclExportsError!void {
14141417 if (build_options.skip_non_native and builtin.object_format != .coff) {
14151418 @panic("Attempted to compile for object format that was disabled by build configuration");
14161419 }
......@@ -1605,16 +1608,34 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
16051608 sub_prog_node.activate();
16061609 defer sub_prog_node.end();
16071610
1608 // Most lazy symbols can be updated when the corresponding decl is,
1609 // so we only have to worry about the one without an associated decl.
1610 if (self.lazy_syms.get(.none)) |metadata| {
1611 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
1612 error.CodegenFail => return error.FlushFailure,
1613 else => |e| return e,
1611 const gpa = self.base.allocator;
1612
1613 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
1614
1615 if (self.lazy_syms.getPtr(.none)) |metadata| {
1616 // Most lazy symbols can be updated on first use, but
1617 // anyerror needs to wait for everything to be flushed.
1618 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
1619 link.File.LazySymbol.initDecl(.code, null, module),
1620 metadata.text_atom,
1621 self.text_section_index.?,
1622 ) catch |err| return switch (err) {
1623 error.CodegenFail => error.FlushFailure,
1624 else => |e| e,
1625 };
1626 if (metadata.rdata_state != .unused) self.updateLazySymbolAtom(
1627 link.File.LazySymbol.initDecl(.const_data, null, module),
1628 metadata.rdata_atom,
1629 self.rdata_section_index.?,
1630 ) catch |err| return switch (err) {
1631 error.CodegenFail => error.FlushFailure,
1632 else => |e| e,
16141633 };
16151634 }
1616
1617 const gpa = self.base.allocator;
1635 for (self.lazy_syms.values()) |*metadata| {
1636 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1637 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
1638 }
16181639
16191640 while (self.unresolved.popOrNull()) |entry| {
16201641 assert(entry.value); // We only expect imports generated by the incremental linker for now.
src/link/Elf.zig+65-42
......@@ -65,9 +65,11 @@ const Section = struct {
6565};
6666
6767const LazySymbolMetadata = struct {
68 text_atom: ?Atom.Index = null,
69 rodata_atom: ?Atom.Index = null,
70 alignment: u32,
68 const State = enum { unused, pending_flush, flushed };
69 text_atom: Atom.Index = undefined,
70 rodata_atom: Atom.Index = undefined,
71 text_state: State = .unused,
72 rodata_state: State = .unused,
7173};
7274
7375const DeclMetadata = struct {
......@@ -1033,19 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10331035 sub_prog_node.activate();
10341036 defer sub_prog_node.end();
10351037
1036 // Most lazy symbols can be updated when the corresponding decl is,
1037 // so we only have to worry about the one without an associated decl.
1038 if (self.lazy_syms.get(.none)) |metadata| {
1039 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
1040 error.CodegenFail => return error.FlushFailure,
1041 else => |e| return e,
1042 };
1043 }
1044
10451038 // TODO This linker code currently assumes there is only 1 compilation unit and it
10461039 // corresponds to the Zig source code.
10471040 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
10481041
1042 if (self.lazy_syms.getPtr(.none)) |metadata| {
1043 // Most lazy symbols can be updated on first use, but
1044 // anyerror needs to wait for everything to be flushed.
1045 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
1046 File.LazySymbol.initDecl(.code, null, module),
1047 metadata.text_atom,
1048 self.text_section_index.?,
1049 ) catch |err| return switch (err) {
1050 error.CodegenFail => error.FlushFailure,
1051 else => |e| e,
1052 };
1053 if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
1054 File.LazySymbol.initDecl(.const_data, null, module),
1055 metadata.rodata_atom,
1056 self.rodata_section_index.?,
1057 ) catch |err| return switch (err) {
1058 error.CodegenFail => error.FlushFailure,
1059 else => |e| e,
1060 };
1061 }
1062 for (self.lazy_syms.values()) |*metadata| {
1063 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1064 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
1065 }
1066
10491067 const target_endian = self.base.options.target.cpu.arch.endian();
10501068 const foreign_endian = target_endian != builtin.cpu.arch.endian();
10511069
......@@ -2377,16 +2395,27 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
23772395 }
23782396}
23792397
2380pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index {
2398pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index {
23812399 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2382 errdefer _ = self.lazy_syms.pop();
2383 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
2384 const atom = switch (sym.kind) {
2385 .code => &gop.value_ptr.text_atom,
2386 .const_data => &gop.value_ptr.rodata_atom,
2400 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2401 if (!gop.found_existing) gop.value_ptr.* = .{};
2402 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2403 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2404 .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
23872405 };
2388 if (atom.* == null) atom.* = try self.createAtom();
2389 return atom.*.?;
2406 switch (metadata.state.*) {
2407 .unused => metadata.atom.* = try self.createAtom(),
2408 .pending_flush => return metadata.atom.*,
2409 .flushed => {},
2410 }
2411 metadata.state.* = .pending_flush;
2412 const atom = metadata.atom.*;
2413 // anyerror needs to be deferred until flushModule
2414 if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
2415 .code => self.text_section_index.?,
2416 .const_data => self.rodata_section_index.?,
2417 });
2418 return atom;
23902419}
23912420
23922421pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
......@@ -2580,7 +2609,11 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
25802609 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
25812610}
25822611
2583pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !void {
2612pub fn updateDecl(
2613 self: *Elf,
2614 module: *Module,
2615 decl_index: Module.Decl.Index,
2616) File.UpdateDeclError!void {
25842617 if (build_options.skip_non_native and builtin.object_format != .elf) {
25852618 @panic("Attempted to compile for object format that was disabled by build configuration");
25862619 }
......@@ -2657,32 +2690,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
26572690 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
26582691}
26592692
2660fn updateLazySymbol(self: *Elf, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void {
2661 const mod = self.base.options.module.?;
2662 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
2663 File.LazySymbol.initDecl(.code, decl, mod),
2664 atom,
2665 self.text_section_index.?,
2666 metadata.alignment,
2667 );
2668 if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom(
2669 File.LazySymbol.initDecl(.const_data, decl, mod),
2670 atom,
2671 self.rodata_section_index.?,
2672 metadata.alignment,
2673 );
2674}
2675
26762693fn updateLazySymbolAtom(
26772694 self: *Elf,
26782695 sym: File.LazySymbol,
26792696 atom_index: Atom.Index,
26802697 shdr_index: u16,
2681 required_alignment: u32,
26822698) !void {
26832699 const gpa = self.base.allocator;
26842700 const mod = self.base.options.module.?;
26852701
2702 var required_alignment: u32 = undefined;
26862703 var code_buffer = std.ArrayList(u8).init(gpa);
26872704 defer code_buffer.deinit();
26882705
......@@ -2707,9 +2724,15 @@ fn updateLazySymbolAtom(
27072724 .parent_decl_node = undefined,
27082725 .lazy = .unneeded,
27092726 };
2710 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
2711 .parent_atom_index = local_sym_index,
2712 });
2727 const res = try codegen.generateLazySymbol(
2728 &self.base,
2729 src,
2730 sym,
2731 &required_alignment,
2732 &code_buffer,
2733 .none,
2734 .{ .parent_atom_index = local_sym_index },
2735 );
27132736 const code = switch (res) {
27142737 .ok => code_buffer.items,
27152738 .fail => |em| {
......@@ -2814,7 +2837,7 @@ pub fn updateDeclExports(
28142837 module: *Module,
28152838 decl_index: Module.Decl.Index,
28162839 exports: []const *Module.Export,
2817) !void {
2840) File.UpdateDeclExportsError!void {
28182841 if (build_options.skip_non_native and builtin.object_format != .elf) {
28192842 @panic("Attempted to compile for object format that was disabled by build configuration");
28202843 }
src/link/MachO.zig+64-45
......@@ -236,9 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
236236const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
237237
238238const LazySymbolMetadata = struct {
239 text_atom: ?Atom.Index = null,
240 data_const_atom: ?Atom.Index = null,
241 alignment: u32,
239 const State = enum { unused, pending_flush, flushed };
240 text_atom: Atom.Index = undefined,
241 data_const_atom: Atom.Index = undefined,
242 text_state: State = .unused,
243 data_const_state: State = .unused,
242244};
243245
244246const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index);
......@@ -494,16 +496,32 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
494496 sub_prog_node.activate();
495497 defer sub_prog_node.end();
496498
497 // Most lazy symbols can be updated when the corresponding decl is,
498 // so we only have to worry about the one without an associated decl.
499 if (self.lazy_syms.get(.none)) |metadata| {
500 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
501 error.CodegenFail => return error.FlushFailure,
502 else => |e| return e,
499 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
500
501 if (self.lazy_syms.getPtr(.none)) |metadata| {
502 // Most lazy symbols can be updated on first use, but
503 // anyerror needs to wait for everything to be flushed.
504 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
505 File.LazySymbol.initDecl(.code, null, module),
506 metadata.text_atom,
507 self.text_section_index.?,
508 ) catch |err| return switch (err) {
509 error.CodegenFail => error.FlushFailure,
510 else => |e| e,
511 };
512 if (metadata.data_const_state != .unused) self.updateLazySymbolAtom(
513 File.LazySymbol.initDecl(.const_data, null, module),
514 metadata.data_const_atom,
515 self.data_const_section_index.?,
516 ) catch |err| return switch (err) {
517 error.CodegenFail => error.FlushFailure,
518 else => |e| e,
503519 };
504520 }
505
506 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
521 for (self.lazy_syms.values()) |*metadata| {
522 if (metadata.text_state != .unused) metadata.text_state = .flushed;
523 if (metadata.data_const_state != .unused) metadata.data_const_state = .flushed;
524 }
507525
508526 if (self.d_sym) |*d_sym| {
509527 try d_sym.dwarf.flushModule(module);
......@@ -2037,32 +2055,16 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
20372055 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
20382056}
20392057
2040fn updateLazySymbol(self: *MachO, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void {
2041 const mod = self.base.options.module.?;
2042 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
2043 File.LazySymbol.initDecl(.code, decl, mod),
2044 atom,
2045 self.text_section_index.?,
2046 metadata.alignment,
2047 );
2048 if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom(
2049 File.LazySymbol.initDecl(.const_data, decl, mod),
2050 atom,
2051 self.data_const_section_index.?,
2052 metadata.alignment,
2053 );
2054}
2055
20562058fn updateLazySymbolAtom(
20572059 self: *MachO,
20582060 sym: File.LazySymbol,
20592061 atom_index: Atom.Index,
20602062 section_index: u8,
2061 required_alignment: u32,
20622063) !void {
20632064 const gpa = self.base.allocator;
20642065 const mod = self.base.options.module.?;
20652066
2067 var required_alignment: u32 = undefined;
20662068 var code_buffer = std.ArrayList(u8).init(gpa);
20672069 defer code_buffer.deinit();
20682070
......@@ -2087,9 +2089,15 @@ fn updateLazySymbolAtom(
20872089 .parent_decl_node = undefined,
20882090 .lazy = .unneeded,
20892091 };
2090 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
2091 .parent_atom_index = local_sym_index,
2092 });
2092 const res = try codegen.generateLazySymbol(
2093 &self.base,
2094 src,
2095 sym,
2096 &required_alignment,
2097 &code_buffer,
2098 .none,
2099 .{ .parent_atom_index = local_sym_index },
2100 );
20932101 const code = switch (res) {
20942102 .ok => code_buffer.items,
20952103 .fail => |em| {
......@@ -2108,7 +2116,7 @@ fn updateLazySymbolAtom(
21082116 errdefer self.freeAtom(atom_index);
21092117
21102118 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
2111 log.debug(" (required alignment 0x{x}", .{required_alignment});
2119 log.debug(" (required alignment 0x{x})", .{required_alignment});
21122120
21132121 atom.size = code.len;
21142122 symbol.n_value = vaddr;
......@@ -2117,16 +2125,30 @@ fn updateLazySymbolAtom(
21172125 try self.writeAtom(atom_index, code);
21182126}
21192127
2120pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index {
2128pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index {
21212129 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2122 errdefer _ = self.lazy_syms.pop();
2123 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
2124 const atom = switch (sym.kind) {
2125 .code => &gop.value_ptr.text_atom,
2126 .const_data => &gop.value_ptr.data_const_atom,
2130 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2131 if (!gop.found_existing) gop.value_ptr.* = .{};
2132 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2133 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2134 .const_data => .{
2135 .atom = &gop.value_ptr.data_const_atom,
2136 .state = &gop.value_ptr.data_const_state,
2137 },
21272138 };
2128 if (atom.* == null) atom.* = try self.createAtom();
2129 return atom.*.?;
2139 switch (metadata.state.*) {
2140 .unused => metadata.atom.* = try self.createAtom(),
2141 .pending_flush => return metadata.atom.*,
2142 .flushed => {},
2143 }
2144 metadata.state.* = .pending_flush;
2145 const atom = metadata.atom.*;
2146 // anyerror needs to be deferred until flushModule
2147 if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
2148 .code => self.text_section_index.?,
2149 .const_data => self.data_const_section_index.?,
2150 });
2151 return atom;
21302152}
21312153
21322154fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {
......@@ -2357,7 +2379,7 @@ pub fn updateDeclExports(
23572379 module: *Module,
23582380 decl_index: Module.Decl.Index,
23592381 exports: []const *Module.Export,
2360) !void {
2382) File.UpdateDeclExportsError!void {
23612383 if (build_options.skip_non_native and builtin.object_format != .macho) {
23622384 @panic("Attempted to compile for object format that was disabled by build configuration");
23632385 }
......@@ -4147,9 +4169,6 @@ pub fn logSymtab(self: *MachO) void {
41474169
41484170 log.debug("stubs entries:", .{});
41494171 log.debug("{}", .{self.stub_table});
4150
4151 // log.debug("threadlocal entries:", .{});
4152 // log.debug("{}", .{self.tlv_table});
41534172}
41544173
41554174pub fn logAtoms(self: *MachO) void {
......@@ -4189,6 +4208,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index) void {
41894208 sym.n_value,
41904209 atom.size,
41914210 atom.file,
4192 sym.n_sect,
4211 sym.n_sect + 1,
41934212 });
41944213}
src/print_air.zig+9-3
......@@ -94,14 +94,20 @@ const Writer = struct {
9494 for (w.air.instructions.items(.tag), 0..) |tag, i| {
9595 const inst = @intCast(Air.Inst.Index, i);
9696 switch (tag) {
97 .constant, .const_ty => try w.writeInst(s, inst),
97 .constant, .const_ty => {
98 try w.writeInst(s, inst);
99 try s.writeByte('\n');
100 },
98101 else => continue,
99102 }
100103 }
101104 }
102105
103106 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
104 for (body) |inst| try w.writeInst(s, inst);
107 for (body) |inst| {
108 try w.writeInst(s, inst);
109 try s.writeByte('\n');
110 }
105111 }
106112
107113 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
......@@ -336,7 +342,7 @@ const Writer = struct {
336342 .work_group_id,
337343 => try w.writeWorkDimension(s, inst),
338344 }
339 try s.writeAll(")\n");
345 try s.writeByte(')');
340346 }
341347
342348 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
test/behavior/align.zig-5
......@@ -282,7 +282,6 @@ fn give() anyerror!u128 {
282282
283283test "page aligned array on stack" {
284284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
285 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
286285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
287286 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
288287
......@@ -491,10 +490,6 @@ test "read 128-bit field from default aligned struct in global memory" {
491490}
492491
493492test "struct field explicit alignment" {
494 if (builtin.zig_backend == .stage2_x86_64) {
495 // Careful enabling this test, fails randomly.
496 return error.SkipZigTest;
497 }
498493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
499494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
500495 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
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/basic.zig+8-4
......@@ -363,7 +363,8 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
363363}
364364
365365test "take address of parameter" {
366 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
366 if (builtin.zig_backend == .stage2_x86_64 and
367 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
367368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
369370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -391,7 +392,8 @@ test "array 2D const double ptr" {
391392 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
392393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
393394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
394 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
395 if (builtin.zig_backend == .stage2_x86_64 and
396 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
395397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
396398
397399 const rect_2d_vertexes = [_][1]f32{
......@@ -405,7 +407,8 @@ test "array 2D const double ptr with offset" {
405407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
406408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
408 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
410 if (builtin.zig_backend == .stage2_x86_64 and
411 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
409412 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
410413
411414 const rect_2d_vertexes = [_][2]f32{
......@@ -419,7 +422,8 @@ test "array 3D const double ptr with offset" {
419422 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
422 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
425 if (builtin.zig_backend == .stage2_x86_64 and
426 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
423427 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
424428
425429 const rect_3d_vertexes = [_][2][2]f32{
test/behavior/bugs/13069.zig+2
......@@ -6,6 +6,8 @@ test {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_x86_64 and
10 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
911
1012 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
1113
test/behavior/cast.zig+5-2
......@@ -95,7 +95,9 @@ test "comptime_int @intToFloat" {
9595
9696test "@intToFloat" {
9797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_x86_64 and
99 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
100
99101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
100102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
101103
......@@ -634,7 +636,8 @@ test "vector casts" {
634636}
635637
636638test "@floatCast cast down" {
637 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_x86_64 and
640 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
638641 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
639642 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
640643 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/enum.zig+2-5
......@@ -940,6 +940,8 @@ test "constant enum initialization with differing sizes" {
940940 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
941941 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
942942 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
943 if (builtin.zig_backend == .stage2_x86_64 and
944 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
943945
944946 try test3_1(test3_foo);
945947 try test3_2(test3_bar);
......@@ -979,7 +981,6 @@ fn test3_2(f: Test3Foo) !void {
979981}
980982
981983test "@tagName" {
982 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
983984 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
984985 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
985986 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -995,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 {
995996const BareNumber = enum { One, Two, Three };
996997
997998test "@tagName non-exhaustive enum" {
998 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
999999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10001000 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10011001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1006,7 +1006,6 @@ test "@tagName non-exhaustive enum" {
10061006const NonExhaustive = enum(u8) { A, B, _ };
10071007
10081008test "@tagName is null-terminated" {
1009 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
10101009 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10111010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10121011 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1021,7 +1020,6 @@ test "@tagName is null-terminated" {
10211020}
10221021
10231022test "tag name with assigned enum values" {
1024 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
10251023 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10261024 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10271025 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1111,7 +1109,6 @@ test "enum literal in array literal" {
11111109
11121110test "tag name functions are unique" {
11131111 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1114 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
11151112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11161113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11171114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/eval.zig+2
......@@ -535,6 +535,8 @@ test "static eval list init" {
535535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
536536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
538 if (builtin.zig_backend == .stage2_x86_64 and
539 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
538540
539541 try expect(static_vec3.data[2] == 1.0);
540542 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
test/behavior/floatop.zig+8-5
......@@ -904,7 +904,8 @@ test "negation f16" {
904904}
905905
906906test "negation f32" {
907 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
907 if (builtin.zig_backend == .stage2_x86_64 and
908 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
908909 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
909910 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
910911 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -924,7 +925,8 @@ test "negation f32" {
924925}
925926
926927test "negation f64" {
927 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
928 if (builtin.zig_backend == .stage2_x86_64 and
929 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
928930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
929931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
930932 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1021,7 +1023,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
10211023
10221024test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
10231025 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1024 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10251026 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10261027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10271028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1060,7 +1061,8 @@ test "nan negation f16" {
10601061}
10611062
10621063test "nan negation f32" {
1063 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1064 if (builtin.zig_backend == .stage2_x86_64 and
1065 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
10641066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10651067 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10661068 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1080,7 +1082,8 @@ test "nan negation f32" {
10801082
10811083test "nan negation f64" {
10821084 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1083 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1085 if (builtin.zig_backend == .stage2_x86_64 and
1086 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
10841087 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10851088 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10861089 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/fn.zig+4
......@@ -338,6 +338,8 @@ test "function call with anon list literal" {
338338 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
339339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
340340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_x86_64 and
342 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
341343
342344 const S = struct {
343345 fn doTheTest() !void {
......@@ -358,6 +360,8 @@ test "function call with anon list literal - 2D" {
358360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
359361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
360362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
363 if (builtin.zig_backend == .stage2_x86_64 and
364 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
361365
362366 const S = struct {
363367 fn doTheTest() !void {
test/behavior/generics.zig+4
......@@ -59,6 +59,8 @@ test "fn with comptime args" {
5959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
62 if (builtin.zig_backend == .stage2_x86_64 and
63 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
6264
6365 try expect(gimmeTheBigOne(1234, 5678) == 5678);
6466 try expect(shouldCallSameInstance(34, 12) == 34);
......@@ -69,6 +71,8 @@ test "anytype params" {
6971 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7072 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_x86_64 and
75 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
7276
7377 try expect(max_i32(12, 34) == 34);
7478 try expect(max_f64(1.2, 3.4) == 3.4);
test/behavior/inline_switch.zig-1
......@@ -94,7 +94,6 @@ test "inline else error" {
9494
9595test "inline else enum" {
9696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9897 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9998
10099 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };
test/behavior/math.zig+2-2
......@@ -203,6 +203,8 @@ test "float equality" {
203203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
204204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
205205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_x86_64 and
207 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
206208
207209 const x: f64 = 0.012;
208210 const y: f64 = x + 1.0;
......@@ -377,7 +379,6 @@ fn testBinaryNot(x: u16) !void {
377379
378380test "binary not 128-bit" {
379381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
381382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
382383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
383384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1533,7 +1534,6 @@ test "signed zeros are represented properly" {
15331534 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
15341535 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15351536 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1536 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
15371537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15381538
15391539 const S = struct {
test/behavior/maximum_minimum.zig+4
......@@ -8,6 +8,8 @@ test "@max" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64 and
12 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
1113
1214 const S = struct {
1315 fn doTheTest() !void {
......@@ -54,6 +56,8 @@ test "@min" {
5456 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5557 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5658 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
59 if (builtin.zig_backend == .stage2_x86_64 and
60 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
5761
5862 const S = struct {
5963 fn doTheTest() !void {
test/behavior/memset.zig+2-2
......@@ -114,7 +114,7 @@ test "memset with large array element, runtime known" {
114114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
115115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
116116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
117 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
117 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) return error.SkipZigTest;
118118
119119 const A = [128]u64;
120120 var buf: [5]A = undefined;
......@@ -132,7 +132,7 @@ test "memset with large array element, comptime known" {
132132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
133133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
134134 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
135 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
135 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) return error.SkipZigTest;
136136
137137 const A = [128]u64;
138138 var buf: [5]A = undefined;
test/behavior/pointers.zig+4-1
......@@ -206,7 +206,8 @@ test "allowzero pointer and slice" {
206206}
207207
208208test "assign null directly to C pointer and test null equality" {
209 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
209 if (builtin.zig_backend == .stage2_x86_64 and
210 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
210211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
211212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
212213 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -345,6 +346,8 @@ test "pointer sentinel with +inf" {
345346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
346347 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
347348 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
349 if (builtin.zig_backend == .stage2_x86_64 and
350 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
348351
349352 const S = struct {
350353 fn doTheTest() !void {
test/behavior/struct.zig+2-1
......@@ -744,7 +744,8 @@ var g_foo: S0 = S0.init();
744744
745745test "packed struct with fp fields" {
746746 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
747 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
747 if (builtin.zig_backend == .stage2_x86_64 and
748 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
748749 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
749750 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
750751 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/switch.zig+2-4
......@@ -88,7 +88,6 @@ fn nonConstSwitch(foo: SwitchStatementFoo) !void {
8888const SwitchStatementFoo = enum { A, B, C, D };
8989
9090test "switch with multiple expressions" {
91 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9392
9493 const x = switch (returnsFive()) {
......@@ -231,6 +230,8 @@ test "switch prong with variable" {
231230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
232231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
233232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
233 if (builtin.zig_backend == .stage2_x86_64 and
234 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
234235
235236 try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
236237 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
......@@ -273,7 +274,6 @@ fn testSwitchEnumPtrCapture() !void {
273274}
274275
275276test "switch handles all cases of number" {
276 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
277277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
278278
279279 try testSwitchHandleAllCases();
......@@ -453,7 +453,6 @@ test "else prong of switch on error set excludes other cases" {
453453}
454454
455455test "switch prongs with error set cases make a new error set type for capture value" {
456 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
457456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458457 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -530,7 +529,6 @@ test "switch with null and T peer types and inferred result location type" {
530529test "switch prongs with cases with identical payload types" {
531530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
532531 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
534532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535533
536534 const Union = union(enum) {
test/behavior/type.zig-2
......@@ -258,7 +258,6 @@ test "Type.ErrorSet" {
258258
259259test "Type.Struct" {
260260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
261 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
262261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
263262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
264263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -383,7 +382,6 @@ test "Type.Enum" {
383382
384383test "Type.Union" {
385384 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
386 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
387385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
388386 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
389387
test/behavior/union.zig+14-2
......@@ -14,6 +14,8 @@ test "basic unions with floats" {
1414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64 and
18 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
1719
1820 var foo = FooWithFloats{ .int = 1 };
1921 try expect(foo.int == 1);
......@@ -29,6 +31,8 @@ test "init union with runtime value - floats" {
2931 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3032 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_x86_64 and
35 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
3236
3337 var foo: FooWithFloats = undefined;
3438
......@@ -216,6 +220,8 @@ test "union with specified enum tag" {
216220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
217221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
218222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
223 if (builtin.zig_backend == .stage2_x86_64 and
224 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
219225
220226 try doTest();
221227 comptime try doTest();
......@@ -225,6 +231,8 @@ test "packed union generates correctly aligned type" {
225231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
227233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
234 if (builtin.zig_backend == .stage2_x86_64 and
235 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
228236
229237 const U = packed union {
230238 f1: *const fn () error{TestUnexpectedResult}!void,
......@@ -903,6 +911,8 @@ test "anonymous union literal syntax" {
903911 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
904912 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
905913 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
914 if (builtin.zig_backend == .stage2_x86_64 and
915 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
906916
907917 const S = struct {
908918 const Number = union {
......@@ -1055,6 +1065,8 @@ test "containers with single-field enums" {
10551065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10561066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10571067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1068 if (builtin.zig_backend == .stage2_x86_64 and
1069 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
10581070
10591071 const S = struct {
10601072 const A = union(enum) { f1 };
......@@ -1082,7 +1094,6 @@ test "containers with single-field enums" {
10821094test "@unionInit on union with tag but no fields" {
10831095 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10841096 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1085 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10861097 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10871098 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10881099
......@@ -1277,7 +1288,6 @@ test "return an extern union from C calling convention" {
12771288test "noreturn field in union" {
12781289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12791290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1280 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12811291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12821292
12831293 const U = union(enum) {
......@@ -1515,6 +1525,8 @@ test "reinterpreting enum value inside packed union" {
15151525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15161526 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15171527 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1528 if (builtin.zig_backend == .stage2_x86_64 and
1529 comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO
15181530
15191531 const U = packed union {
15201532 tag: enum { a, b },
test/behavior/vector.zig+4
......@@ -321,6 +321,7 @@ test "load vector elements via comptime index" {
321321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
323323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
324325
325326 const S = struct {
326327 fn doTheTest() !void {
......@@ -342,6 +343,7 @@ test "store vector elements via comptime index" {
342343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344345 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
345347
346348 const S = struct {
347349 fn doTheTest() !void {
......@@ -369,6 +371,7 @@ test "load vector elements via runtime index" {
369371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
370372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
371373 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
372375
373376 const S = struct {
374377 fn doTheTest() !void {
......@@ -390,6 +393,7 @@ test "store vector elements via runtime index" {
390393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
391394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
392395 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
393397
394398 const S = struct {
395399 fn doTheTest() !void {
test/src/Cases.zig+6
......@@ -396,6 +396,12 @@ fn addFromDirInner(
396396 // Other backends don't support new liveness format
397397 continue;
398398 }
399 if (backend == .stage2 and target.getOsTag() == .macos and
400 target.getCpuArch() == .x86_64 and builtin.cpu.arch == .aarch64)
401 {
402 // Rosetta has issues with ZLD
403 continue;
404 }
399405
400406 const next = ctx.cases.items.len;
401407 try ctx.cases.append(.{