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";...@@ -18,7 +18,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
18// Until then, we have simplified logic here for self-hosted. TODO remove this once18// Until then, we have simplified logic here for self-hosted. TODO remove this once
19// self-hosted is capable enough to handle all of the real start.zig logic.19// self-hosted is capable enough to handle all of the real start.zig logic.
20pub const simplified_logic =20pub const simplified_logic =
21 (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or21 (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .plan9) or
22 builtin.zig_backend == .stage2_x86 or22 builtin.zig_backend == .stage2_x86 or
23 builtin.zig_backend == .stage2_aarch64 or23 builtin.zig_backend == .stage2_aarch64 or
24 builtin.zig_backend == .stage2_arm or24 builtin.zig_backend == .stage2_arm or
lib/test_runner.zig+12-5
...@@ -13,7 +13,6 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);...@@ -13,7 +13,6 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
1313
14pub fn main() void {14pub fn main() void {
15 if (builtin.zig_backend == .stage2_wasm or15 if (builtin.zig_backend == .stage2_wasm or
16 (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) or
17 builtin.zig_backend == .stage2_aarch64)16 builtin.zig_backend == .stage2_aarch64)
18 {17 {
19 return mainSimple() catch @panic("test failure");18 return mainSimple() catch @panic("test failure");
...@@ -234,25 +233,33 @@ pub fn log(...@@ -234,25 +233,33 @@ pub fn log(
234/// work-in-progress backends can handle it.233/// work-in-progress backends can handle it.
235pub fn mainSimple() anyerror!void {234pub fn mainSimple() anyerror!void {
236 const enable_print = false;235 const enable_print = false;
236 const print_all = false;
237237
238 var passed: u64 = 0;238 var passed: u64 = 0;
239 var skipped: u64 = 0;239 var skipped: u64 = 0;
240 var failed: u64 = 0;240 var failed: u64 = 0;
241 const stderr = if (enable_print) std.io.getStdErr() else {};241 const stderr = if (enable_print) std.io.getStdErr() else {};
242 for (builtin.test_functions) |test_fn| {242 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 }
243 test_fn.func() catch |err| {247 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 }
245 if (err != error.SkipZigTest) {252 if (err != error.SkipZigTest) {
246 if (enable_print) stderr.writeAll("... FAIL\n") catch {};253 if (enable_print) stderr.writeAll("FAIL\n") catch {};
247 failed += 1;254 failed += 1;
248 if (!enable_print) return err;255 if (!enable_print) return err;
249 continue;256 continue;
250 }257 }
251 if (enable_print) stderr.writeAll("... SKIP\n") catch {};258 if (enable_print) stderr.writeAll("SKIP\n") catch {};
252 skipped += 1;259 skipped += 1;
253 continue;260 continue;
254 };261 };
255 //if (enable_print) stderr.writeAll("... PASS\n") catch {};262 if (enable_print and print_all) stderr.writeAll("PASS\n") catch {};
256 passed += 1;263 passed += 1;
257 }264 }
258 if (enable_print) {265 if (enable_print) {
src/Sema.zig+3-6
...@@ -23287,8 +23287,7 @@ fn panicWithMsg(...@@ -23287,8 +23287,7 @@ fn panicWithMsg(
23287 const arena = sema.arena;23287 const arena = sema.arena;
2328823288
23289 if (!mod.backendSupportsFeature(.panic_fn)) {23289 if (!mod.backendSupportsFeature(.panic_fn)) {
23290 _ = try block.addNoOp(.breakpoint);23290 _ = try block.addNoOp(.trap);
23291 _ = try block.addNoOp(.unreach);
23292 return;23291 return;
23293 }23292 }
23294 const panic_fn = try sema.getBuiltin("panic");23293 const panic_fn = try sema.getBuiltin("panic");
...@@ -23336,8 +23335,7 @@ fn panicUnwrapError(...@@ -23336,8 +23335,7 @@ fn panicUnwrapError(
2333623335
23337 {23336 {
23338 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {23337 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
23339 _ = try fail_block.addNoOp(.breakpoint);23338 _ = try fail_block.addNoOp(.trap);
23340 _ = try fail_block.addNoOp(.unreach);
23341 } else {23339 } else {
23342 const panic_fn = try sema.getBuiltin("panicUnwrapError");23340 const panic_fn = try sema.getBuiltin("panicUnwrapError");
23343 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);23341 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
...@@ -23462,8 +23460,7 @@ fn safetyCheckFormatted(...@@ -23462,8 +23460,7 @@ fn safetyCheckFormatted(
23462 defer fail_block.instructions.deinit(gpa);23460 defer fail_block.instructions.deinit(gpa);
2346323461
23464 if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {23462 if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
23465 _ = try fail_block.addNoOp(.breakpoint);23463 _ = try fail_block.addNoOp(.trap);
23466 _ = try fail_block.addNoOp(.unreach);
23467 } else {23464 } else {
23468 const panic_fn = try sema.getBuiltin(func);23465 const panic_fn = try sema.getBuiltin(func);
23469 _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);23466 _ = 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;...@@ -7,6 +7,8 @@ const leb128 = std.leb;
7const link = @import("../../link.zig");7const link = @import("../../link.zig");
8const log = std.log.scoped(.codegen);8const log = std.log.scoped(.codegen);
9const tracking_log = std.log.scoped(.tracking);9const tracking_log = std.log.scoped(.tracking);
10const verbose_tracking_log = std.log.scoped(.verbose_tracking);
11const wip_mir_log = std.log.scoped(.wip_mir);
10const math = std.math;12const math = std.math;
11const mem = std.mem;13const mem = std.mem;
12const trace = @import("../../tracy.zig").trace;14const trace = @import("../../tracy.zig").trace;
...@@ -48,16 +50,13 @@ const sse = abi.RegisterClass.sse;...@@ -48,16 +50,13 @@ const sse = abi.RegisterClass.sse;
4850
49const InnerError = CodeGenError || error{OutOfRegisters};51const InnerError = CodeGenError || error{OutOfRegisters};
5052
51const debug_wip_mir = false;
52const debug_tracking = false;
53
54gpa: Allocator,53gpa: Allocator,
55air: Air,54air: Air,
56liveness: Liveness,55liveness: Liveness,
57bin_file: *link.File,56bin_file: *link.File,
58debug_output: DebugInfoOutput,57debug_output: DebugInfoOutput,
59target: *const std.Target,58target: *const std.Target,
60mod_fn: *const Module.Fn,59owner: Owner,
61err_msg: ?*ErrorMsg,60err_msg: ?*ErrorMsg,
62args: []MCValue,61args: []MCValue,
63ret_mcv: InstTracking,62ret_mcv: InstTracking,
...@@ -109,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged...@@ -109,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged
109const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };108const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
110const RegisterOffset = struct { reg: Register, off: i32 = 0 };109const 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
112pub const MCValue = union(enum) {149pub const MCValue = union(enum) {
113 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.150 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
114 /// TODO Look into deleting this tag and using `dead` instead, since every use151 /// TODO Look into deleting this tag and using `dead` instead, since every use
...@@ -220,9 +257,9 @@ pub const MCValue = union(enum) {...@@ -220,9 +257,9 @@ pub const MCValue = union(enum) {
220 .dead,257 .dead,
221 .undef,258 .undef,
222 .immediate,259 .immediate,
260 .eflags,
223 .register,261 .register,
224 .register_offset,262 .register_offset,
225 .eflags,
226 .register_overflow,263 .register_overflow,
227 .lea_direct,264 .lea_direct,
228 .lea_got,265 .lea_got,
...@@ -298,6 +335,41 @@ pub const MCValue = union(enum) {...@@ -298,6 +335,41 @@ pub const MCValue = union(enum) {
298 };335 };
299 }336 }
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
301 pub fn format(373 pub fn format(
302 mcv: MCValue,374 mcv: MCValue,
303 comptime _: []const u8,375 comptime _: []const u8,
...@@ -575,12 +647,6 @@ pub fn generate(...@@ -575,12 +647,6 @@ pub fn generate(
575 assert(fn_owner_decl.has_tv);647 assert(fn_owner_decl.has_tv);
576 const fn_type = fn_owner_decl.ty;648 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
584 const gpa = bin_file.allocator;650 const gpa = bin_file.allocator;
585 var function = Self{651 var function = Self{
586 .gpa = gpa,652 .gpa = gpa,
...@@ -589,7 +655,7 @@ pub fn generate(...@@ -589,7 +655,7 @@ pub fn generate(
589 .target = &bin_file.options.target,655 .target = &bin_file.options.target,
590 .bin_file = bin_file,656 .bin_file = bin_file,
591 .debug_output = debug_output,657 .debug_output = debug_output,
592 .mod_fn = module_fn,658 .owner = .{ .mod_fn = module_fn },
593 .err_msg = null,659 .err_msg = null,
594 .args = undefined, // populated after `resolveCallingConventionValues`660 .args = undefined, // populated after `resolveCallingConventionValues`
595 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`661 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
...@@ -614,6 +680,8 @@ pub fn generate(...@@ -614,6 +680,8 @@ pub fn generate(
614 if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa);680 if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa);
615 }681 }
616682
683 wip_mir_log.debug("{}:", .{function.fmtDecl(module_fn.owner_decl)});
684
617 try function.frame_allocs.resize(gpa, FrameIndex.named_count);685 try function.frame_allocs.resize(gpa, FrameIndex.named_count);
618 function.frame_allocs.set(686 function.frame_allocs.set(
619 @enumToInt(FrameIndex.stack_frame),687 @enumToInt(FrameIndex.stack_frame),
...@@ -715,48 +783,190 @@ pub fn generate(...@@ -715,48 +783,190 @@ pub fn generate(
715 }783 }
716}784}
717785
718fn dumpWipMir(self: *Self, inst: Mir.Inst) !void {786pub fn generateLazy(
719 if (!debug_wip_mir) return;787 bin_file: *link.File,
720 const stderr = std.io.getStdErr().writer();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 {
722 var lower = Lower{922 var lower = Lower{
723 .allocator = self.gpa,923 .allocator = data.self.gpa,
724 .mir = .{924 .mir = .{
725 .instructions = self.mir_instructions.slice(),925 .instructions = data.self.mir_instructions.slice(),
726 .extra = self.mir_extra.items,926 .extra = data.self.mir_extra.items,
727 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),927 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
728 },928 },
729 .target = self.target,929 .target = data.self.target,
730 .src_loc = self.src_loc,930 .src_loc = data.self.src_loc,
731 };931 };
732 for (lower.lowerMir(inst) catch |err| switch (err) {932 for (lower.lowerMir(data.self.mir_instructions.get(data.inst)) catch |err| switch (err) {
733 error.LowerFail => {933 error.LowerFail => {
734 defer {934 defer {
735 lower.err_msg.?.deinit(self.gpa);935 lower.err_msg.?.deinit(data.self.gpa);
736 lower.err_msg = null;936 lower.err_msg = null;
737 }937 }
738 try stderr.print("{s}\n", .{lower.err_msg.?.msg});938 try writer.writeAll(lower.err_msg.?.msg);
739 return;939 return;
740 },940 },
741 error.InvalidInstruction, error.CannotEncode => |e| {941 error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| {
742 try stderr.writeAll(switch (e) {942 try writer.writeAll(switch (e) {
743 error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n",943 error.OutOfMemory => "Out of memory",
744 error.CannotEncode => "CodeGen failed to encode the instruction.\n",944 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
945 error.CannotEncode => "CodeGen failed to encode the instruction.",
745 });946 });
746 return;947 return;
747 },948 },
748 else => |e| return e,949 else => |e| return e,
749 }) |lower_inst| {950 }) |lower_inst| try writer.print(" | {}", .{lower_inst});
750 try stderr.print(" | {}\n", .{lower_inst});951}
751 }952fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
953 return .{ .data = .{ .self = self, .inst = inst } };
752}954}
753955
754fn dumpTracking(self: *Self) !void {956const FormatTrackingData = struct {
755 if (!debug_tracking) return;957 self: *Self,
756 const stderr = std.io.getStdErr().writer();958};
757959fn formatTracking(
758 var it = self.inst_tracking.iterator();960 data: FormatTrackingData,
759 while (it.next()) |entry| try stderr.print("%{d} = {}\n", .{ entry.key_ptr.*, entry.value_ptr.* });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 } };
760}970}
761971
762fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {972fn 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 {...@@ -764,7 +974,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
764 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);974 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
765 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);975 const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
766 self.mir_instructions.appendAssumeCapacity(inst);976 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 }
768 return result_index;985 return result_index;
769}986}
770987
...@@ -1186,13 +1403,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1186,13 +1403,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1186 }1403 }
11871404
1188 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue;1405 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue;
1189 if (debug_wip_mir) @import("../../print_air.zig").dumpInst(1406 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
1190 inst,1407 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
1191 self.bin_file.options.module.?,
1192 self.air,
1193 self.liveness,
1194 );
1195 self.dumpTracking() catch {};
11961408
1197 const old_air_bookkeeping = self.air_bookkeeping;1409 const old_air_bookkeeping = self.air_bookkeeping;
1198 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);1410 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
...@@ -1244,9 +1456,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1244,9 +1456,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1244 .ceil,1456 .ceil,
1245 .round,1457 .round,
1246 .trunc_float,1458 .trunc_float,
1247 .neg,
1248 => try self.airUnaryMath(inst),1459 => try self.airUnaryMath(inst),
12491460
1461 .neg => try self.airNeg(inst),
1462
1250 .add_with_overflow => try self.airAddSubWithOverflow(inst),1463 .add_with_overflow => try self.airAddSubWithOverflow(inst),
1251 .sub_with_overflow => try self.airAddSubWithOverflow(inst),1464 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
1252 .mul_with_overflow => try self.airMulWithOverflow(inst),1465 .mul_with_overflow => try self.airMulWithOverflow(inst),
...@@ -1453,7 +1666,69 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1453,7 +1666,69 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1453 }1666 }
1454 }1667 }
1455 }1668 }
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 }
1457}1732}
14581733
1459fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {1734fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
...@@ -1619,15 +1894,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {...@@ -1619,15 +1894,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
1619 const frame_allocs_slice = self.frame_allocs.slice();1894 const frame_allocs_slice = self.frame_allocs.slice();
1620 const frame_size = frame_allocs_slice.items(.abi_size);1895 const frame_size = frame_allocs_slice.items(.abi_size);
1621 const frame_align = frame_allocs_slice.items(.abi_align);1896 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
1622 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {1901 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {
1623 const abi_size = frame_size[@enumToInt(frame_index)];1902 const abi_size = frame_size[@enumToInt(frame_index)];
1624 if (abi_size != alloc.abi_size) continue;1903 if (abi_size != alloc.abi_size) continue;
1625 const abi_align = &frame_align[@enumToInt(frame_index)];1904 const abi_align = &frame_align[@enumToInt(frame_index)];
1626 abi_align.* = @max(abi_align.*, alloc.abi_align);1905 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
1631 _ = self.free_frame_indices.swapRemoveAt(free_i);1907 _ = self.free_frame_indices.swapRemoveAt(free_i);
1632 return frame_index;1908 return frame_index;
1633 }1909 }
...@@ -1828,7 +2104,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void {...@@ -1828,7 +2104,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void {
1828/// allocated. A second call to `copyToTmpRegister` may return the same register.2104/// allocated. A second call to `copyToTmpRegister` may return the same register.
1829/// This can have a side effect of spilling instructions to the stack to free up a register.2105/// This can have a side effect of spilling instructions to the stack to free up a register.
1830fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {2106fn 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));
1832 try self.genSetReg(reg, ty, mcv);2108 try self.genSetReg(reg, ty, mcv);
1833 return reg;2109 return reg;
1834}2110}
...@@ -1871,16 +2147,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1871,16 +2147,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
18712147
1872fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {2148fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
1873 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2149 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1874 _ = ty_op;2150 const dst_ty = self.air.typeOfIndex(inst);
1875 return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch});2151 const src_ty = self.air.typeOf(ty_op.operand);
1876 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });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 });
1877}2169}
18782170
1879fn airFpext(self: *Self, inst: Air.Inst.Index) !void {2171fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
1880 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2172 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1881 _ = ty_op;2173 const dst_ty = self.air.typeOfIndex(inst);
1882 return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch});2174 const src_ty = self.air.typeOf(ty_op.operand);
1883 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });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 });
1884}2192}
18852193
1886fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {2194fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1928,13 +2236,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1928,13 +2236,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1928 registerAlias(src_reg, min_abi_size),2236 registerAlias(src_reg, min_abi_size),
1929 );2237 );
1930 },2238 },
1931 .load_frame => |frame_addr| try self.asmRegisterMemory(2239 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
1932 tag,2240 tag,
1933 dst_alias,2241 dst_alias,
1934 Memory.sib(Memory.PtrSize.fromSize(min_abi_size), .{2242 src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)),
1935 .base = .{ .frame = frame_addr.index },
1936 .disp = frame_addr.off,
1937 }),
1938 ),2243 ),
1939 else => return self.fail("TODO airIntCast from {s} to {s}", .{2244 else => return self.fail("TODO airIntCast from {s} to {s}", .{
1940 @tagName(src_mcv),2245 @tagName(src_mcv),
...@@ -2102,6 +2407,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2102,6 +2407,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
2102 } };2407 } };
2103 const src_ty = Type.initPayload(&src_pl.base);2408 const src_ty = Type.initPayload(&src_pl.base);
21042409
2410 try self.spillEflagsIfOccupied();
2105 try self.spillRegisters(&.{ .rax, .rdx });2411 try self.spillRegisters(&.{ .rax, .rdx });
2106 const lhs = try self.resolveInst(bin_op.lhs);2412 const lhs = try self.resolveInst(bin_op.lhs);
2107 const rhs = try self.resolveInst(bin_op.rhs);2413 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -2315,12 +2621,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2315,12 +2621,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23152621
2316 const frame_index =2622 const frame_index =
2317 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));2623 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2318 try self.genSetFrameTruncatedOverflowCompare(2624 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
2319 tuple_ty,
2320 frame_index,
2321 partial_mcv.register,
2322 cc,
2323 );
2324 break :result .{ .load_frame = .{ .index = frame_index } };2625 break :result .{ .load_frame = .{ .index = frame_index } };
2325 },2626 },
2326 else => unreachable,2627 else => unreachable,
...@@ -2392,12 +2693,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2392,12 +2693,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
23922693
2393 const frame_index =2694 const frame_index =
2394 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));2695 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2395 try self.genSetFrameTruncatedOverflowCompare(2696 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
2396 tuple_ty,
2397 frame_index,
2398 partial_mcv.register,
2399 cc,
2400 );
2401 break :result .{ .load_frame = .{ .index = frame_index } };2697 break :result .{ .load_frame = .{ .index = frame_index } };
2402 },2698 },
2403 else => unreachable,2699 else => unreachable,
...@@ -2410,173 +2706,175 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -2410,173 +2706,175 @@ fn genSetFrameTruncatedOverflowCompare(
2410 self: *Self,2706 self: *Self,
2411 tuple_ty: Type,2707 tuple_ty: Type,
2412 frame_index: FrameIndex,2708 frame_index: FrameIndex,
2413 reg: Register,2709 src_mcv: MCValue,
2414 cc: Condition,2710 overflow_cc: ?Condition,
2415) !void {2711) !void {
2416 const reg_lock = self.register_manager.lockReg(reg);2712 const src_lock = switch (src_mcv) {
2417 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);2713 .register => |reg| self.register_manager.lockReg(reg),
2714 else => null,
2715 };
2716 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
24182717
2419 const ty = tuple_ty.structFieldType(0);2718 const ty = tuple_ty.structFieldType(0);
2420 const int_info = ty.intInfo(self.target.*);2719 const int_info = ty.intInfo(self.target.*);
2421 const extended_ty = switch (int_info.signedness) {2720
2422 .signed => Type.isize,2721 var hi_limb_pl = Type.Payload.Bits{
2423 .unsigned => ty,2722 .base = .{ .tag = switch (int_info.signedness) {
2723 .signed => .int_signed,
2724 .unsigned => .int_unsigned,
2725 } },
2726 .data = (int_info.bits - 1) % 64 + 1,
2424 };2727 };
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);2730 var rest_pl = Type.Payload.Bits{
2427 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);2731 .base = .{ .tag = .int_unsigned },
2428 defer for (temp_regs_locks) |rreg| {2732 .data = int_info.bits - hi_limb_pl.data,
2429 self.register_manager.unlockReg(rreg);
2430 };2733 };
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
2432 const overflow_reg = temp_regs[0];2740 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
2435 const scratch_reg = temp_regs[1];2743 const scratch_reg = temp_regs[1];
2436 try self.genSetReg(scratch_reg, extended_ty, .{ .register = reg });2744 const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8;
2437 try self.truncateRegister(ty, scratch_reg);2745 const hi_limb_mcv = if (hi_limb_off > 0)
2438 try self.genBinOpMir(2746 src_mcv.address().offset(int_info.bits / 64 * 8).deref()
2439 .cmp,2747 else
2440 extended_ty,2748 src_mcv;
2441 .{ .register = reg },2749 try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv);
2442 .{ .register = scratch_reg },2750 try self.truncateRegister(hi_limb_ty, scratch_reg);
2443 );2751 try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);
24442752
2445 const eq_reg = temp_regs[2];2753 const eq_reg = temp_regs[2];
2446 try self.asmSetccRegister(eq_reg.to8(), .ne);2754 if (overflow_cc) |_| {
2447 try self.genBinOpMir(2755 try self.asmSetccRegister(eq_reg.to8(), .ne);
2448 .@"or",2756 try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg });
2449 Type.u8,2757 }
2450 .{ .register = overflow_reg },
2451 .{ .register = eq_reg },
2452 );
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);
2454 try self.genSetMem(2761 try self.genSetMem(
2455 .{ .frame = frame_index },2762 .{ .frame = frame_index },
2456 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),2763 payload_off + hi_limb_off,
2457 tuple_ty.structFieldType(1),2764 hi_limb_ty,
2458 .{ .register = overflow_reg.to8() },2765 .{ .register = scratch_reg },
2459 );2766 );
2460 try self.genSetMem(2767 try self.genSetMem(
2461 .{ .frame = frame_index },2768 .{ .frame = frame_index },
2462 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),2769 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2463 ty,2770 tuple_ty.structFieldType(1),
2464 .{ .register = scratch_reg },2771 if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne },
2465 );2772 );
2466}2773}
24672774
2468fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {2775fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2469 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2776 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2470 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2777 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2471 const result: MCValue = result: {2778 const dst_ty = self.air.typeOf(bin_op.lhs);
2472 const dst_ty = self.air.typeOf(bin_op.lhs);2779 const result: MCValue = switch (dst_ty.zigTypeTag()) {
2473 switch (dst_ty.zigTypeTag()) {2780 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
2474 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),2781 .Int => result: {
2475 .Int => {2782 try self.spillEflagsIfOccupied();
2476 try self.spillEflagsIfOccupied();2783 try self.spillRegisters(&.{ .rax, .rdx });
24772784
2478 const dst_info = dst_ty.intInfo(self.target.*);2785 const dst_info = dst_ty.intInfo(self.target.*);
2479 const cc: Condition = switch (dst_info.signedness) {2786 const cc: Condition = switch (dst_info.signedness) {
2480 .unsigned => .c,2787 .unsigned => .c,
2481 .signed => .o,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,
2482 };2811 };
2812 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
24832813
2484 const tuple_ty = self.air.typeOfIndex(inst);2814 const dst_reg: Register = blk: {
2485 if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) {2815 if (lhs.isRegister()) break :blk lhs.register;
2486 var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) {2816 break :blk try self.copyToTmpRegister(dst_ty, lhs);
2487 .signed => .int_signed,2817 };
2488 .unsigned => .int_unsigned,2818 const dst_mcv = MCValue{ .register = dst_reg };
2489 } }, .data = math.max3(2819 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
2490 self.activeIntBits(bin_op.lhs),2820 defer self.register_manager.unlockReg(dst_reg_lock);
2491 self.activeIntBits(bin_op.rhs),
2492 dst_info.bits / 2,
2493 ) };
2494 const src_ty = Type.initPayload(&src_pl.base);
24952821
2496 try self.spillRegisters(&.{ .rax, .rdx });2822 const rhs_mcv: MCValue = blk: {
2497 const lhs = try self.resolveInst(bin_op.lhs);2823 if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
2498 const rhs = try self.resolveInst(bin_op.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);2832 try self.genIntMulComplexOpMir(Type.isize, dst_mcv, rhs_mcv);
2501 switch (partial_mcv) {2833 break :dst dst_mcv;
2502 .register => |reg| {2834 } else try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
2503 self.eflags_inst = inst;
2504 break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
2505 },
2506 else => {},
2507 }
25082835
2509 // For now, this is the only supported multiply that doesn't fit in a register.2836 switch (partial_mcv) {
2510 assert(dst_info.bits == 128 and src_pl.data == 64);2837 .register => |reg| if (extra_bits == 0) {
2838 self.eflags_inst = inst;
2839 break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
2840 } else {
2511 const frame_index =2841 const frame_index =
2512 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));2842 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2513 try self.genSetMem(2843 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
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 );
2525 break :result .{ .load_frame = .{ .index = frame_index } };2844 break :result .{ .load_frame = .{ .index = frame_index } };
2526 }2845 },
25272846 else => {
2528 const dst_reg: Register = dst_reg: {2847 // For now, this is the only supported multiply that doesn't fit in a register,
2529 switch (dst_info.signedness) {2848 // so cc being set is impossible.
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);
25662849
2567 const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs);2850 assert(dst_info.bits <= 128 and src_pl.data == 64);
2568 break :dst_reg dst_mcv.register;
2569 },
2570 }
2571 };
25722851
2573 const frame_index =2852 const frame_index =
2574 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));2853 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2575 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, dst_reg, cc);2854 if (dst_info.bits >= lhs_active_bits + rhs_active_bits) {
2576 break :result .{ .load_frame = .{ .index = frame_index } };2855 try self.genSetMem(
2577 },2856 .{ .frame = frame_index },
2578 else => unreachable,2857 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),
2579 }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,
2580 };2878 };
2581 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2879 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2582}2880}
...@@ -2616,19 +2914,9 @@ fn genIntMulDivOpMir(...@@ -2616,19 +2914,9 @@ fn genIntMulDivOpMir(
2616 };2914 };
2617 switch (mat_rhs) {2915 switch (mat_rhs) {
2618 .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),2916 .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(
2620 tag,2918 tag,
2621 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {2919 mat_rhs.mem(Memory.PtrSize.fromSize(abi_size)),
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 }),
2632 ),2920 ),
2633 else => unreachable,2921 else => unreachable,
2634 }2922 }
...@@ -3900,10 +4188,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -3900,10 +4188,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
3900 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });4188 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
3901}4189}
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
3903fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {4244fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
3904 const un_op = self.air.instructions.items(.data)[inst].un_op;4245 const un_op = self.air.instructions.items(.data)[inst].un_op;
3905 _ = un_op;4246 _ = 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 });
3907 //return self.finishAir(inst, result, .{ un_op, .none, .none });4250 //return self.finishAir(inst, result, .{ un_op, .none, .none });
3908}4251}
39094252
...@@ -4056,7 +4399,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro...@@ -4056,7 +4399,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
4056fn airLoad(self: *Self, inst: Air.Inst.Index) !void {4399fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
4057 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4400 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4058 const elem_ty = self.air.typeOfIndex(inst);4401 const elem_ty = self.air.typeOfIndex(inst);
4059 const elem_size = elem_ty.abiSize(self.target.*);
4060 const result: MCValue = result: {4402 const result: MCValue = result: {
4061 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;4403 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
40624404
...@@ -4064,14 +4406,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -4064,14 +4406,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
4064 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });4406 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
4065 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);4407 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
4067 const ptr_mcv = try self.resolveInst(ty_op.operand);4415 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))
4069 // The MCValue that holds the pointer can be re-used as the value.4418 // The MCValue that holds the pointer can be re-used as the value.
4070 ptr_mcv4419 ptr_mcv
4071 else4420 else
4072 try self.allocRegOrMem(inst, true);4421 try self.allocRegOrMem(inst, true);
40734422
4074 const ptr_ty = self.air.typeOf(ty_op.operand);
4075 if (ptr_ty.ptrInfo().data.host_size > 0) {4423 if (ptr_ty.ptrInfo().data.host_size > 0) {
4076 try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv);4424 try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv);
4077 } else {4425 } else {
...@@ -4293,17 +4641,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4293,17 +4641,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
42934641
4294 switch (src_mcv) {4642 switch (src_mcv) {
4295 .load_frame => |frame_addr| {4643 .load_frame => |frame_addr| {
4296 const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*));4644 if (field_off % 8 == 0) {
4297 const limb_abi_size = @min(field_abi_size, 8);4645 const off_mcv =
4298 const limb_abi_bits = limb_abi_size * 8;4646 src_mcv.address().offset(@intCast(i32, @divExact(field_off, 8))).deref();
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 } };
4307 if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv;4647 if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv;
43084648
4309 const dst_mcv = try self.allocRegOrMem(inst, true);4649 const dst_mcv = try self.allocRegOrMem(inst, true);
...@@ -4311,6 +4651,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4311,6 +4651,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4311 break :result dst_mcv;4651 break :result dst_mcv;
4312 }4652 }
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
4314 if (field_abi_size > 8) {4660 if (field_abi_size > 8) {
4315 return self.fail("TODO implement struct_field_val with large packed field", .{});4661 return self.fail("TODO implement struct_field_val with large packed field", .{});
4316 }4662 }
...@@ -4448,9 +4794,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -4448,9 +4794,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
4448 if (src_ty.zigTypeTag() == .Vector) {4794 if (src_ty.zigTypeTag() == .Vector) {
4449 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});4795 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
4450 }4796 }
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
4455 switch (src_mcv) {4798 switch (src_mcv) {
4456 .eflags => |cc| switch (tag) {4799 .eflags => |cc| switch (tag) {
...@@ -4466,13 +4809,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -4466,13 +4809,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
4466 };4809 };
4467 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);4810 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
44684811
4469 const dst_mcv: MCValue = if (maybe_inst) |inst|4812 const dst_mcv: MCValue = dst: {
4470 if (self.reuseOperand(inst, src_air, 0, src_mcv))4813 if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv;
4471 src_mcv4814
4472 else4815 const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true);
4473 try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv)4816 try self.genCopy(src_ty, dst_mcv, src_mcv);
4474 else4817 break :dst dst_mcv;
4475 .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) };4818 };
4476 const dst_lock = switch (dst_mcv) {4819 const dst_lock = switch (dst_mcv) {
4477 .register => |reg| self.register_manager.lockReg(reg),4820 .register => |reg| self.register_manager.lockReg(reg),
4478 else => null,4821 else => null,
...@@ -4481,19 +4824,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -4481,19 +4824,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
44814824
4482 switch (tag) {4825 switch (tag) {
4483 .not => {4826 .not => {
4827 const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8));
4484 const int_info = if (src_ty.tag() == .bool)4828 const int_info = if (src_ty.tag() == .bool)
4485 std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 }4829 std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 }
4486 else4830 else
4487 src_ty.intInfo(self.target.*);4831 src_ty.intInfo(self.target.*);
4488 const extra_bits = self.regExtraBits(src_ty);4832 var byte_off: i32 = 0;
4489 if (int_info.signedness == .unsigned and extra_bits > 0) {4833 while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) {
4490 const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1;4834 var limb_pl = Type.Payload.Bits{
4491 try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask });4835 .base = .{ .tag = switch (int_info.signedness) {
4492 } else try self.genUnOpMir(.not, src_ty, dst_mcv);4836 .signed => .int_signed,
4493 },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 },
4495 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),4853 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),
4496
4497 else => unreachable,4854 else => unreachable,
4498 }4855 }
4499 return dst_mcv;4856 return dst_mcv;
...@@ -4534,17 +4891,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue...@@ -4534,17 +4891,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
4534 },4891 },
4535 .indirect, .load_frame => try self.asmMemory(4892 .indirect, .load_frame => try self.asmMemory(
4536 mir_tag,4893 mir_tag,
4537 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (dst_mcv) {4894 dst_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
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 }),
4548 ),4895 ),
4549 }4896 }
4550}4897}
...@@ -5128,24 +5475,69 @@ fn genBinOp(...@@ -5128,24 +5475,69 @@ fn genBinOp(
5128 switch (tag) {5475 switch (tag) {
5129 .add,5476 .add,
5130 .addwrap,5477 .addwrap,
5131 => try self.genBinOpMir(switch (lhs_ty.tag()) {5478 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5132 else => .add,5479 else => .add,
5133 .f32 => .addss,5480 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5134 .f64 => .addsd,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 },
5135 }, lhs_ty, dst_mcv, src_mcv),5497 }, lhs_ty, dst_mcv, src_mcv),
51365498
5137 .sub,5499 .sub,
5138 .subwrap,5500 .subwrap,
5139 => try self.genBinOpMir(switch (lhs_ty.tag()) {5501 => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5140 else => .sub,5502 else => .sub,
5141 .f32 => .subss,5503 .Float => switch (lhs_ty.floatBits(self.target.*)) {
5142 .f64 => .subsd,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 },
5143 }, lhs_ty, dst_mcv, src_mcv),5520 }, lhs_ty, dst_mcv, src_mcv),
51445521
5145 .mul => try self.genBinOpMir(switch (lhs_ty.tag()) {5522 .mul => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5146 .f32 => .mulss,
5147 .f64 => .mulsd,
5148 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),5523 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 },
5149 }, lhs_ty, dst_mcv, src_mcv),5541 }, lhs_ty, dst_mcv, src_mcv),
51505542
5151 .div_float,5543 .div_float,
...@@ -5153,12 +5545,27 @@ fn genBinOp(...@@ -5153,12 +5545,27 @@ fn genBinOp(
5153 .div_trunc,5545 .div_trunc,
5154 .div_floor,5546 .div_floor,
5155 => {5547 => {
5156 try self.genBinOpMir(switch (lhs_ty.tag()) {5548 try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) {
5157 .f32 => .divss,
5158 .f64 => .divsd,
5159 else => return self.fail("TODO implement genBinOp for {s} {}", .{5549 else => return self.fail("TODO implement genBinOp for {s} {}", .{
5160 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),5550 @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?),
5161 }),5551 }),
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 },
5162 }, lhs_ty, dst_mcv, src_mcv);5569 }, lhs_ty, dst_mcv, src_mcv);
5163 switch (tag) {5570 switch (tag) {
5164 .div_float,5571 .div_float,
...@@ -5169,16 +5576,18 @@ fn genBinOp(...@@ -5169,16 +5576,18 @@ fn genBinOp(
5169 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {5576 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
5170 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));5577 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
5171 const dst_alias = registerAlias(dst_mcv.register, abi_size);5578 const dst_alias = registerAlias(dst_mcv.register, abi_size);
5172 try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {5579 try self.asmRegisterRegisterImmediate(switch (lhs_ty.floatBits(self.target.*)) {
5173 .f32 => .roundss,5580 32 => .roundss,
5174 .f64 => .roundsd,5581 64 => .roundsd,
5175 else => unreachable,5582 else => unreachable,
5176 }, dst_alias, dst_alias, Immediate.u(switch (tag) {5583 }, dst_alias, dst_alias, Immediate.u(switch (tag) {
5177 .div_trunc => 0b1_0_11,5584 .div_trunc => 0b1_0_11,
5178 .div_floor => 0b1_0_01,5585 .div_floor => 0b1_0_01,
5179 else => unreachable,5586 else => unreachable,
5180 }));5587 }));
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 }),
5182 else => unreachable,5591 else => unreachable,
5183 }5592 }
5184 },5593 },
...@@ -5400,39 +5809,68 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -5400,39 +5809,68 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
5400 )),5809 )),
5401 else => unreachable,5810 else => unreachable,
5402 },5811 },
5403 .register_offset,
5404 .eflags,5812 .eflags,
5813 .register_offset,
5405 .memory,5814 .memory,
5815 .indirect,
5406 .load_direct,5816 .load_direct,
5407 .lea_direct,5817 .lea_direct,
5408 .load_got,5818 .load_got,
5409 .lea_got,5819 .lea_got,
5410 .load_tlv,5820 .load_tlv,
5411 .lea_tlv,5821 .lea_tlv,
5822 .load_frame,
5412 .lea_frame,5823 .lea_frame,
5413 => {5824 => {
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
5415 const dst_reg_lock = self.register_manager.lockReg(dst_reg);5847 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
5416 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);5848 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
54175849
5418 const reg = try self.copyToTmpRegister(ty, src_mcv);5850 switch (src_mcv) {
5419 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });5851 .eflags,
5420 },5852 .register_offset,
5421 .indirect, .load_frame => try self.asmRegisterMemory(5853 .lea_direct,
5422 mir_tag,5854 .lea_got,
5423 registerAlias(dst_reg, abi_size),5855 .lea_tlv,
5424 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {5856 .lea_frame,
5425 .indirect => |reg_off| .{5857 => {
5426 .base = .{ .reg = reg_off.reg },5858 const reg = try self.copyToTmpRegister(ty, src_mcv);
5427 .disp = reg_off.off,5859 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
5428 },5860 },
5429 .load_frame => |frame_addr| .{5861 .memory,
5430 .base = .{ .frame = frame_addr.index },5862 .load_direct,
5431 .disp = frame_addr.off,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 });
5432 },5870 },
5433 else => unreachable,5871 else => unreachable,
5434 }),5872 }
5435 ),5873 },
5436 }5874 }
5437 },5875 },
5438 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {5876 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
...@@ -5769,7 +6207,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -5769,7 +6207,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
57696207
5770 const ty = self.air.typeOfIndex(inst);6208 const ty = self.air.typeOfIndex(inst);
5771 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;6209 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);
5773 try self.genArgDbgInfo(ty, name, dst_mcv);6211 try self.genArgDbgInfo(ty, name, dst_mcv);
57746212
5775 break :result dst_mcv;6213 break :result dst_mcv;
...@@ -5793,7 +6231,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {...@@ -5793,7 +6231,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
5793 //},6231 //},
5794 else => unreachable, // not a valid function parameter6232 else => unreachable, // not a valid function parameter
5795 };6233 };
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);
5797 },6238 },
5798 .plan9 => {},6239 .plan9 => {},
5799 .none => {},6240 .none => {},
...@@ -5834,7 +6275,10 @@ fn genVarDbgInfo(...@@ -5834,7 +6275,10 @@ fn genVarDbgInfo(
5834 break :blk .nop;6275 break :blk .nop;
5835 },6276 },
5836 };6277 };
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);
5838 },6282 },
5839 .plan9 => {},6283 .plan9 => {},
5840 .none => {},6284 .none => {},
...@@ -5966,12 +6410,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5966,12 +6410,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5966 .base = .{ .reg = .ds },6410 .base = .{ .reg = .ds },
5967 .disp = @intCast(i32, got_addr),6411 .disp = @intCast(i32, got_addr),
5968 }));6412 }));
5969 } else if (self.bin_file.cast(link.File.Coff)) |_| {6413 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5970 const sym_index = try self.getSymbolIndexForDecl(func.owner_decl);6414 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
6415 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
5971 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });6416 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
5972 try self.asmRegister(.call, .rax);6417 try self.asmRegister(.call, .rax);
5973 } else if (self.bin_file.cast(link.File.MachO)) |_| {6418 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
5974 const sym_index = try self.getSymbolIndexForDecl(func.owner_decl);6419 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
6420 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
5975 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });6421 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
5976 try self.asmRegister(.call, .rax);6422 try self.asmRegister(.call, .rax);
5977 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6423 } 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...@@ -5992,7 +6438,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5992 const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0);6438 const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0);
5993 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);6439 const lib_name = mem.sliceTo(extern_fn.lib_name, 0);
5994 if (self.bin_file.cast(link.File.Coff)) |coff_file| {6440 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);
5996 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);6442 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
5997 _ = try self.addInst(.{6443 _ = try self.addInst(.{
5998 .tag = .mov_linker,6444 .tag = .mov_linker,
...@@ -6005,8 +6451,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -6005,8 +6451,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
6005 });6451 });
6006 try self.asmRegister(.call, .rax);6452 try self.asmRegister(.call, .rax);
6007 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6453 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6454 const atom_index = try self.owner.getSymbolIndex(self);
6008 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);6455 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
6009 const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl);
6010 _ = try self.addInst(.{6456 _ = try self.addInst(.{
6011 .tag = .call_extern,6457 .tag = .call_extern,
6012 .ops = undefined,6458 .ops = undefined,
...@@ -6122,10 +6568,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -6122,10 +6568,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
6122 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);6568 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
61236569
6124 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;6570 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
6125 try self.genBinOpMir(switch (ty.tag()) {6571 try self.genBinOpMir(switch (ty.zigTypeTag()) {
6126 else => .cmp,6572 else => .cmp,
6127 .f32 => .ucomiss,6573 .Float => switch (ty.floatBits(self.target.*)) {
6128 .f64 => .ucomisd,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 },
6129 }, ty, dst_mcv, src_mcv);6590 }, ty, dst_mcv, src_mcv);
61306591
6131 const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;6592 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 {...@@ -6141,42 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
6141}6602}
61426603
6143fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {6604fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
6605 const mod = self.bin_file.options.module.?;
6144 const un_op = self.air.instructions.items(.data)[inst].un_op;6606 const un_op = self.air.instructions.items(.data)[inst].un_op;
61456607
6146 const addr_reg = try self.register_manager.allocReg(null, gp);6608 const addr_reg = try self.register_manager.allocReg(null, gp);
6147 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);6609 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
6148 defer self.register_manager.unlockReg(addr_lock);6610 defer self.register_manager.unlockReg(addr_lock);
61496611 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
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 }
61806612
6181 try self.spillEflagsIfOccupied();6613 try self.spillEflagsIfOccupied();
6182 self.eflags_inst = inst;6614 self.eflags_inst = inst;
...@@ -6345,35 +6777,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6345,35 +6777,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
6345 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);6777 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
6346 }6778 }
63476779
6348 const outer_state = try self.saveState();6780 self.scope_generation += 1;
6349 {6781 const state = try self.saveState();
6350 self.scope_generation += 1;
6351 const inner_state = try self.saveState();
63526782
6353 for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand);6783 for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand);
6354 try self.genBody(then_body);6784 try self.genBody(then_body);
6355 try self.restoreState(inner_state, &.{}, .{6785 try self.restoreState(state, &.{}, .{
6356 .emit_instructions = false,6786 .emit_instructions = false,
6357 .update_tracking = true,6787 .update_tracking = true,
6358 .resurrect = true,6788 .resurrect = true,
6359 .close_scope = true,6789 .close_scope = true,
6360 });6790 });
63616791
6362 try self.performReloc(reloc);6792 try self.performReloc(reloc);
63636793
6364 for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand);6794 for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand);
6365 try self.genBody(else_body);6795 try self.genBody(else_body);
6366 try self.restoreState(inner_state, &.{}, .{6796 try self.restoreState(state, &.{}, .{
6367 .emit_instructions = false,
6368 .update_tracking = true,
6369 .resurrect = true,
6370 .close_scope = true,
6371 });
6372 }
6373 try self.restoreState(outer_state, &.{}, .{
6374 .emit_instructions = false,6797 .emit_instructions = false,
6375 .update_tracking = false,6798 .update_tracking = true,
6376 .resurrect = false,6799 .resurrect = true,
6377 .close_scope = true,6800 .close_scope = true,
6378 });6801 });
63796802
...@@ -6746,64 +7169,56 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6746,64 +7169,56 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
6746 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);7169 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
6747 }7170 }
67487171
6749 const outer_state = try self.saveState();7172 self.scope_generation += 1;
6750 {7173 const state = try self.saveState();
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;
67627174
6763 var relocs = try self.gpa.alloc(u32, items.len);7175 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
6764 defer self.gpa.free(relocs);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| {7184 var relocs = try self.gpa.alloc(u32, items.len);
6767 try self.spillEflagsIfOccupied();7185 defer self.gpa.free(relocs);
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 }
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);7194 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);
6776 try self.restoreState(inner_state, &.{}, .{
6777 .emit_instructions = false,
6778 .update_tracking = true,
6779 .resurrect = true,
6780 .close_scope = true,
6781 });
67827195
6783 for (relocs) |reloc| try self.performReloc(reloc);7196 for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc);
6784 }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) {7205 try self.performReloc(relocs[relocs.len - 1]);
6787 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];7206 }
67887207
6789 const else_deaths = liveness.deaths.len - 1;7208 if (switch_br.data.else_body_len > 0) {
6790 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);7209 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
67917210
6792 try self.genBody(else_body);7211 const else_deaths = liveness.deaths.len - 1;
6793 try self.restoreState(inner_state, &.{}, .{7212 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);
6794 .emit_instructions = false,7213
6795 .update_tracking = true,7214 try self.genBody(else_body);
6796 .resurrect = true,7215 try self.restoreState(state, &.{}, .{
6797 .close_scope = true,7216 .emit_instructions = false,
6798 });7217 .update_tracking = true,
6799 }7218 .resurrect = true,
7219 .close_scope = true,
7220 });
6800 }7221 }
6801 try self.restoreState(outer_state, &.{}, .{
6802 .emit_instructions = false,
6803 .update_tracking = false,
6804 .resurrect = false,
6805 .close_scope = true,
6806 });
68077222
6808 // We already took care of pl_op.operand earlier, so we're going to pass .none here7223 // We already took care of pl_op.operand earlier, so we're going to pass .none here
6809 return self.finishAir(inst, .unreach, .{ .none, .none, .none });7224 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...@@ -7289,7 +7704,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7289 }),7704 }),
7290 ),7705 ),
7291 .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) {7706 .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);
7293 _ = try self.addInst(.{7708 _ = try self.addInst(.{
7294 .tag = .mov_linker,7709 .tag = .mov_linker,
7295 .ops = .direct_reloc,7710 .ops = .direct_reloc,
...@@ -7316,7 +7731,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7316,7 +7731,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7316 );7731 );
7317 },7732 },
7318 .lea_direct, .lea_got => |sym_index| {7733 .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);
7320 _ = try self.addInst(.{7735 _ = try self.addInst(.{
7321 .tag = switch (src_mcv) {7736 .tag = switch (src_mcv) {
7322 .lea_direct => .lea_linker,7737 .lea_direct => .lea_linker,
...@@ -7336,7 +7751,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -7336,7 +7751,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7336 });7751 });
7337 },7752 },
7338 .lea_tlv => |sym_index| {7753 .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);
7340 if (self.bin_file.cast(link.File.MachO)) |_| {7755 if (self.bin_file.cast(link.File.MachO)) |_| {
7341 _ = try self.addInst(.{7756 _ = try self.addInst(.{
7342 .tag = .lea_linker,7757 .tag = .lea_linker,
...@@ -7531,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)...@@ -7531,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
7531 });7946 });
7532}7947}
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
7534fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {8010fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
7535 const un_op = self.air.instructions.items(.data)[inst].un_op;8011 const un_op = self.air.instructions.items(.data)[inst].un_op;
7536 const result = result: {8012 const result = result: {
...@@ -7555,7 +8031,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -7555,7 +8031,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
7555 const dst_rc = try self.regClassForType(dst_ty);8031 const dst_rc = try self.regClassForType(dst_ty);
7556 const src_rc = try self.regClassForType(src_ty);8032 const src_rc = try self.regClassForType(src_ty);
7557 const operand = try self.resolveInst(ty_op.operand);8033 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
7560 const operand_lock = switch (operand) {8037 const operand_lock = switch (operand) {
7561 .register => |reg| self.register_manager.lockReg(reg),8038 .register => |reg| self.register_manager.lockReg(reg),
...@@ -7595,9 +8072,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -7595,9 +8072,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
75958072
7596fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {8073fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
7597 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8074 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7598 _ = ty_op;8075
7599 return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch});8076 const src_ty = self.air.typeOf(ty_op.operand);
7600 //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });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 });
7601}8128}
76028129
7603fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {8130fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
...@@ -7652,70 +8179,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -7652,70 +8179,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
7652 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;8179 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
76538180
7654 const ptr_ty = self.air.typeOf(extra.ptr);8181 const ptr_ty = self.air.typeOf(extra.ptr);
7655 const ptr_mcv = try self.resolveInst(extra.ptr);
7656 const val_ty = self.air.typeOf(extra.expected_value);8182 const val_ty = self.air.typeOf(extra.expected_value);
7657 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));8183 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
76588184
7659 try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });8185 try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
7660 const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });8186 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
7663 const exp_mcv = try self.resolveInst(extra.expected_value);8189 const exp_mcv = try self.resolveInst(extra.expected_value);
7664 if (val_abi_size > 8) switch (exp_mcv) {8190 if (val_abi_size > 8) {
7665 .load_frame => |frame_addr| {8191 try self.genSetReg(.rax, Type.usize, exp_mcv);
7666 try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{8192 try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref());
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)}),
7676 } else try self.genSetReg(.rax, val_ty, exp_mcv);8193 } 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
7680 const new_mcv = try self.resolveInst(extra.new_value);8195 const new_mcv = try self.resolveInst(extra.new_value);
7681 const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) {8196 const new_reg = if (val_abi_size > 8) new: {
7682 .load_frame => |frame_addr| new: {8197 try self.genSetReg(.rbx, Type.usize, new_mcv);
7683 try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{8198 try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref());
7684 .index = frame_addr.index,8199 break :new null;
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)}),
7694 } else try self.copyToTmpRegister(val_ty, new_mcv);8200 } else try self.copyToTmpRegister(val_ty, new_mcv);
7695 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);8201 const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
7696 defer self.register_manager.unlockReg(new_lock);8202 defer if (new_lock) |lock| self.register_manager.unlockReg(lock);
76978203
8204 const ptr_mcv = try self.resolveInst(extra.ptr);
7698 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);8205 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
7699 const ptr_mem = switch (ptr_mcv) {8206 const ptr_mem = switch (ptr_mcv) {
7700 .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),8207 .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
7701 .lea_frame => |frame_addr| Memory.sib(ptr_size, .{8208 else => Memory.sib(ptr_size, .{
7702 .base = .{ .frame = frame_addr.index },8209 .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
7703 .disp = frame_addr.off,
7704 }),8210 }),
7705 else => Memory.sib(ptr_size, .{ .base = .{
7706 .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
7707 } }),
7708 };8211 };
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()) {
7710 .none, .frame => null,8217 .none, .frame => null,
7711 .reg => |reg| self.register_manager.lockReg(reg),8218 .reg => |reg| self.register_manager.lockReg(reg),
7712 };8219 };
7713 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);8220 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
77148221
7715 try self.spillEflagsIfOccupied();8222 try self.spillEflagsIfOccupied();
7716 if (val_abi_size <= 8) {8223 if (val_abi_size <= 8) {
7717 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{8224 _ = 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),
7719 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8226 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7720 } } });8227 } } });
7721 } else {8228 } else {
...@@ -7733,24 +8240,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -7733,24 +8240,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
7733 }8240 }
77348241
7735 const dst_mcv = try self.allocRegOrMem(inst, false);8242 const dst_mcv = try self.allocRegOrMem(inst, false);
7736 try self.genSetMem(8243 try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax });
7737 .{ .frame = dst_mcv.load_frame.index },8244 try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx });
7738 dst_mcv.load_frame.off + 16,8245 try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne });
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 );
7754 break :result dst_mcv;8246 break :result dst_mcv;
7755 };8247 };
7756 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });8248 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
...@@ -7781,15 +8273,15 @@ fn atomicOp(...@@ -7781,15 +8273,15 @@ fn atomicOp(
7781 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));8273 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
7782 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);8274 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
7783 const ptr_mem = switch (ptr_mcv) {8275 const ptr_mem = switch (ptr_mcv) {
7784 .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }),8276 .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size),
7785 .lea_frame => |frame_addr| Memory.sib(ptr_size, .{8277 else => Memory.sib(ptr_size, .{
7786 .base = .{ .frame = frame_addr.index },8278 .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
7787 .disp = frame_addr.off,
7788 }),8279 }),
7789 else => Memory.sib(ptr_size, .{ .base = .{
7790 .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
7791 } }),
7792 };8280 };
8281 switch (ptr_mem) {
8282 .sib, .rip => {},
8283 .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
8284 }
7793 const mem_lock = switch (ptr_mem.base()) {8285 const mem_lock = switch (ptr_mem.base()) {
7794 .none, .frame => null,8286 .none, .frame => null,
7795 .reg => |reg| self.register_manager.lockReg(reg),8287 .reg => |reg| self.register_manager.lockReg(reg),
...@@ -7895,12 +8387,9 @@ fn atomicOp(...@@ -7895,12 +8387,9 @@ fn atomicOp(
7895 registerAlias(val_reg, cmov_abi_size),8387 registerAlias(val_reg, cmov_abi_size),
7896 cc,8388 cc,
7897 ),8389 ),
7898 .load_frame => |frame_addr| try self.asmCmovccRegisterMemory(8390 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
7899 registerAlias(tmp_reg, cmov_abi_size),8391 registerAlias(tmp_reg, cmov_abi_size),
7900 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{8392 val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
7901 .base = .{ .frame = frame_addr.index },
7902 .disp = frame_addr.off,
7903 }),
7904 cc,8393 cc,
7905 ),8394 ),
7906 else => {8395 else => {
...@@ -7923,72 +8412,62 @@ fn atomicOp(...@@ -7923,72 +8412,62 @@ fn atomicOp(
7923 } else {8412 } else {
7924 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{8413 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
7925 .base = ptr_mem.sib.base,8414 .base = ptr_mem.sib.base,
7926 .scale_index = ptr_mem.sib.scale_index,8415 .scale_index = ptr_mem.scaleIndex(),
7927 .disp = ptr_mem.sib.disp + 0,8416 .disp = ptr_mem.sib.disp + 0,
7928 }));8417 }));
7929 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{8418 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{
7930 .base = ptr_mem.sib.base,8419 .base = ptr_mem.sib.base,
7931 .scale_index = ptr_mem.sib.scale_index,8420 .scale_index = ptr_mem.scaleIndex(),
7932 .disp = ptr_mem.sib.disp + 8,8421 .disp = ptr_mem.sib.disp + 8,
7933 }));8422 }));
7934 const loop = @intCast(u32, self.mir_instructions.len);8423 const loop = @intCast(u32, self.mir_instructions.len);
7935 switch (val_mcv) {8424 const val_mem_mcv: MCValue = switch (val_mcv) {
7936 .load_frame => |frame_addr| {8425 .memory, .indirect, .load_frame => val_mcv,
7937 const val_lo_mem = Memory.sib(.qword, .{8426 else => .{ .indirect = .{
7938 .base = .{ .frame = frame_addr.index },8427 .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()),
7939 .disp = frame_addr.off + 0,8428 } },
7940 });8429 };
7941 const val_hi_mem = Memory.sib(.qword, .{8430 const val_lo_mem = val_mem_mcv.mem(.qword);
7942 .base = .{ .frame = frame_addr.index },8431 const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword);
7943 .disp = frame_addr.off + 8,8432 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
7944 });8433 try self.asmRegisterRegister(.mov, .rbx, .rax);
79458434 try self.asmRegisterRegister(.mov, .rcx, .rdx);
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 ),
7991 }8435 }
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 };
7992 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{8471 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
7993 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8472 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7994 } });8473 } });
...@@ -8230,14 +8709,48 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -8230,14 +8709,48 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
8230}8709}
82318710
8232fn airTagName(self: *Self, inst: Air.Inst.Index) !void {8711fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
8712 const mod = self.bin_file.options.module.?;
8233 const un_op = self.air.instructions.items(.data)[inst].un_op;8713 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
8234 const operand = try self.resolveInst(un_op);8740 const operand = try self.resolveInst(un_op);
8235 _ = operand;8741 try self.genSetReg(param_regs[1], enum_ty, operand);
8236 return self.fail("TODO implement airTagName for x86_64", .{});8742
8237 //return self.finishAir(inst, result, .{ un_op, .none, .none });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 });
8238}8750}
82398751
8240fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {8752fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8753 const mod = self.bin_file.options.module.?;
8241 const un_op = self.air.instructions.items(.data)[inst].un_op;8754 const un_op = self.air.instructions.items(.data)[inst].un_op;
82428755
8243 const err_ty = self.air.typeOf(un_op);8756 const err_ty = self.air.typeOf(un_op);
...@@ -8249,37 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8249,37 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8249 const addr_reg = try self.register_manager.allocReg(null, gp);8762 const addr_reg = try self.register_manager.allocReg(null, gp);
8250 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);8763 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
8251 defer self.register_manager.unlockReg(addr_lock);8764 defer self.register_manager.unlockReg(addr_lock);
82528765 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
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 }
82838766
8284 const start_reg = try self.register_manager.allocReg(null, gp);8767 const start_reg = try self.register_manager.allocReg(null, gp);
8285 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);8768 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...@@ -8596,12 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
8596}9079}
85979080
8598fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {9081fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
8599 const mcv: MCValue = switch (try codegen.genTypedValue(9082 return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) {
8600 self.bin_file,
8601 self.src_loc,
8602 arg_tv,
8603 self.mod_fn.owner_decl,
8604 )) {
8605 .mcv => |mcv| switch (mcv) {9083 .mcv => |mcv| switch (mcv) {
8606 .none => .none,9084 .none => .none,
8607 .undef => .undef,9085 .undef => .undef,
...@@ -8616,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {...@@ -8616,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
8616 return error.CodegenFail;9094 return error.CodegenFail;
8617 },9095 },
8618 };9096 };
8619 return mcv;
8620}9097}
86219098
8622const CallMCValues = struct {9099const CallMCValues = struct {
...@@ -8664,6 +9141,7 @@ fn resolveCallingConventionValues(...@@ -8664,6 +9141,7 @@ fn resolveCallingConventionValues(
8664 },9141 },
8665 .C => {9142 .C => {
8666 var param_reg_i: usize = 0;9143 var param_reg_i: usize = 0;
9144 var param_sse_reg_i: usize = 0;
8667 result.stack_align = 16;9145 result.stack_align = 16;
86689146
8669 switch (self.target.os.tag) {9147 switch (self.target.os.tag) {
...@@ -8681,26 +9159,39 @@ fn resolveCallingConventionValues(...@@ -8681,26 +9159,39 @@ fn resolveCallingConventionValues(
8681 // TODO: is this even possible for C calling convention?9159 // TODO: is this even possible for C calling convention?
8682 result.return_value = InstTracking.init(.none);9160 result.return_value = InstTracking.init(.none);
8683 } else {9161 } else {
8684 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];9162 const classes = switch (self.target.os.tag) {
8685 const ret_ty_size = @intCast(u31, ret_ty.abiSize(self.target.*));9163 .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)},
8686 if (ret_ty_size <= 8) {9164 else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none),
8687 const aliased_reg = registerAlias(ret_reg, ret_ty_size);9165 };
8688 result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none };9166 if (classes.len > 1) {
8689 } else {9167 return self.fail("TODO handle multiple classes per type", .{});
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 };
8696 }9168 }
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 };
8697 }9188 }
86989189
8699 // Input params9190 // Input params
8700 for (param_types, result.args) |ty, *arg| {9191 for (param_types, result.args) |ty, *arg| {
8701 assert(ty.hasRuntimeBitsIgnoreComptime());9192 assert(ty.hasRuntimeBitsIgnoreComptime());
87029193
8703 const classes: []const abi.Class = switch (self.target.os.tag) {9194 const classes = switch (self.target.os.tag) {
8704 .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)},9195 .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)},
8705 else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none),9196 else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none),
8706 };9197 };
...@@ -8708,13 +9199,29 @@ fn resolveCallingConventionValues(...@@ -8708,13 +9199,29 @@ fn resolveCallingConventionValues(
8708 return self.fail("TODO handle multiple classes per type", .{});9199 return self.fail("TODO handle multiple classes per type", .{});
8709 }9200 }
8710 switch (classes[0]) {9201 switch (classes[0]) {
8711 .integer => blk: {9202 .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) {
8712 if (param_reg_i >= abi.getCAbiIntParamRegs(self.target.*).len) break :blk;9203 arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] };
8713 const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
8714 param_reg_i += 1;9204 param_reg_i += 1;
8715 arg.* = .{ .register = param_reg };
8716 continue;9205 continue;
8717 },9206 },
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 },
8718 .memory => {}, // fallthrough9225 .memory => {}, // fallthrough
8719 else => |class| return self.fail("TODO handle calling convention class {s}", .{9226 else => |class| return self.fail("TODO handle calling convention class {s}", .{
8720 @tagName(class),9227 @tagName(class),
...@@ -8863,15 +9370,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -8863,15 +9370,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
8863}9370}
88649371
8865fn regBitSize(self: *Self, ty: Type) u64 {9372fn regBitSize(self: *Self, ty: Type) u64 {
9373 const abi_size = ty.abiSize(self.target.*);
8866 return switch (ty.zigTypeTag()) {9374 return switch (ty.zigTypeTag()) {
8867 else => switch (ty.abiSize(self.target.*)) {9375 else => switch (abi_size) {
8868 1 => 8,9376 1 => 8,
8869 2 => 16,9377 2 => 16,
8870 3...4 => 32,9378 3...4 => 32,
8871 5...8 => 64,9379 5...8 => 64,
8872 else => unreachable,9380 else => unreachable,
8873 },9381 },
8874 .Float => switch (ty.abiSize(self.target.*)) {9382 .Float => switch (abi_size) {
8875 1...16 => 128,9383 1...16 => 128,
8876 17...32 => 256,9384 17...32 => 256,
8877 else => unreachable,9385 else => unreachable,
...@@ -8882,17 +9390,3 @@ fn regBitSize(self: *Self, ty: Type) u64 {...@@ -8882,17 +9390,3 @@ fn regBitSize(self: *Self, ty: Type) u64 {
8882fn regExtraBits(self: *Self, ty: Type) u64 {9390fn regExtraBits(self: *Self, ty: Type) u64 {
8883 return self.regBitSize(ty) - ty.bitSize(self.target.*);9391 return self.regBitSize(ty) - ty.bitSize(self.target.*);
8884}9392}
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(...@@ -58,7 +58,7 @@ pub fn findByMnemonic(
58 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {58 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
59 switch (data.mode) {59 switch (data.mode) {
60 .rex => if (!rex_required) continue,60 .rex => if (!rex_required) continue,
61 .long, .sse2_long => {},61 .long, .sse_long, .sse2_long => {},
62 else => if (rex_required) continue,62 else => if (rex_required) continue,
63 }63 }
64 for (input_ops, data.ops) |input_op, data_op|64 for (input_ops, data.ops) |input_op, data_op|
...@@ -90,7 +90,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {...@@ -90,7 +90,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
90 if (prefixes.rex.w) {90 if (prefixes.rex.w) {
91 switch (data.mode) {91 switch (data.mode) {
92 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,92 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
93 .long, .sse2_long, .rex => {},93 .long, .sse_long, .sse2_long, .rex => {},
94 }94 }
95 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {95 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
96 switch (data.mode) {96 switch (data.mode) {
...@@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {...@@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {
138pub fn operandBitSize(encoding: Encoding) u64 {138pub fn operandBitSize(encoding: Encoding) u64 {
139 switch (encoding.data.mode) {139 switch (encoding.data.mode) {
140 .short => return 16,140 .short => return 16,
141 .long, .sse2_long => return 64,141 .long, .sse_long, .sse2_long => return 64,
142 else => {},142 else => {},
143 }143 }
144 const bit_size: u64 = switch (encoding.data.op_en) {144 const bit_size: u64 = switch (encoding.data.op_en) {
...@@ -163,7 +163,7 @@ pub fn format(...@@ -163,7 +163,7 @@ pub fn format(
163 _ = options;163 _ = options;
164 _ = fmt;164 _ = fmt;
165 switch (encoding.data.mode) {165 switch (encoding.data.mode) {
166 .long, .sse2_long => try writer.writeAll("REX.W + "),166 .long, .sse_long, .sse2_long => try writer.writeAll("REX.W + "),
167 else => {},167 else => {},
168 }168 }
169169
...@@ -269,21 +269,25 @@ pub const Mnemonic = enum {...@@ -269,21 +269,25 @@ pub const Mnemonic = enum {
269 // SSE269 // SSE
270 addss,270 addss,
271 cmpss,271 cmpss,
272 cvtsi2ss,
272 divss,273 divss,
273 maxss, minss,274 maxss, minss,
274 movss,275 movss,
275 mulss,276 mulss,
276 subss,277 subss,
277 ucomiss,278 ucomiss,
279 xorps,
278 // SSE2280 // SSE2
279 addsd,281 addsd,
280 //cmpsd,282 //cmpsd,
283 cvtsd2ss, cvtsi2sd, cvtss2sd,
281 divsd,284 divsd,
282 maxsd, minsd,285 maxsd, minsd,
283 movq, //movd, movsd,286 movq, //movd, movsd,
284 mulsd,287 mulsd,
285 subsd,288 subsd,
286 ucomisd,289 ucomisd,
290 xorpd,
287 // SSE4.1291 // SSE4.1
288 roundss,292 roundss,
289 roundsd,293 roundsd,
...@@ -318,7 +322,7 @@ pub const Op = enum {...@@ -318,7 +322,7 @@ pub const Op = enum {
318 m,322 m,
319 moffs,323 moffs,
320 sreg,324 sreg,
321 xmm, xmm_m32, xmm_m64,325 xmm, xmm_m32, xmm_m64, xmm_m128,
322 // zig fmt: on326 // zig fmt: on
323327
324 pub fn fromOperand(operand: Instruction.Operand) Op {328 pub fn fromOperand(operand: Instruction.Operand) Op {
...@@ -400,7 +404,7 @@ pub const Op = enum {...@@ -400,7 +404,7 @@ pub const Op = enum {
400 .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,404 .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
401 .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,405 .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
402 .m80 => 80,406 .m80 => 80,
403 .m128, .xmm => 128,407 .m128, .xmm, .xmm_m128 => 128,
404 };408 };
405 }409 }
406410
...@@ -423,8 +427,8 @@ pub const Op = enum {...@@ -423,8 +427,8 @@ pub const Op = enum {
423 .al, .ax, .eax, .rax,427 .al, .ax, .eax, .rax,
424 .r8, .r16, .r32, .r64,428 .r8, .r16, .r32, .r64,
425 .rm8, .rm16, .rm32, .rm64,429 .rm8, .rm16, .rm32, .rm64,
426 .xmm, .xmm_m32, .xmm_m64,430 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
427 => true,431 => true,
428 else => false,432 else => false,
429 };433 };
430 // zig fmt: on434 // zig fmt: on
...@@ -449,7 +453,7 @@ pub const Op = enum {...@@ -449,7 +453,7 @@ pub const Op = enum {
449 .rm8, .rm16, .rm32, .rm64,453 .rm8, .rm16, .rm32, .rm64,
450 .m8, .m16, .m32, .m64, .m80, .m128,454 .m8, .m16, .m32, .m64, .m80, .m128,
451 .m,455 .m,
452 .xmm_m32, .xmm_m64,456 .xmm_m32, .xmm_m64, .xmm_m128,
453 => true,457 => true,
454 else => false,458 else => false,
455 };459 };
...@@ -470,13 +474,13 @@ pub const Op = enum {...@@ -470,13 +474,13 @@ pub const Op = enum {
470 .r8, .r16, .r32, .r64 => .general_purpose,474 .r8, .r16, .r32, .r64 => .general_purpose,
471 .rm8, .rm16, .rm32, .rm64 => .general_purpose,475 .rm8, .rm16, .rm32, .rm64 => .general_purpose,
472 .sreg => .segment,476 .sreg => .segment,
473 .xmm, .xmm_m32, .xmm_m64 => .floating_point,477 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
474 };478 };
475 }479 }
476480
477 pub fn isFloatingPointRegister(op: Op) bool {481 pub fn isFloatingPointRegister(op: Op) bool {
478 return switch (op) {482 return switch (op) {
479 .xmm, .xmm_m32, .xmm_m64 => true,483 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => true,
480 else => false,484 else => false,
481 };485 };
482 }486 }
...@@ -535,6 +539,7 @@ pub const Mode = enum {...@@ -535,6 +539,7 @@ pub const Mode = enum {
535 rex,539 rex,
536 long,540 long,
537 sse,541 sse,
542 sse_long,
538 sse2,543 sse2,
539 sse2_long,544 sse2_long,
540 sse4_1,545 sse4_1,
src/arch/x86_64/Lower.zig+6
...@@ -95,6 +95,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -95,6 +95,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
9595
96 .addss,96 .addss,
97 .cmpss,97 .cmpss,
98 .cvtsi2ss,
98 .divss,99 .divss,
99 .maxss,100 .maxss,
100 .minss,101 .minss,
...@@ -103,8 +104,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -103,8 +104,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
103 .roundss,104 .roundss,
104 .subss,105 .subss,
105 .ucomiss,106 .ucomiss,
107 .xorps,
106 .addsd,108 .addsd,
107 .cmpsd,109 .cmpsd,
110 .cvtsd2ss,
111 .cvtsi2sd,
112 .cvtss2sd,
108 .divsd,113 .divsd,
109 .maxsd,114 .maxsd,
110 .minsd,115 .minsd,
...@@ -113,6 +118,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -113,6 +118,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
113 .roundsd,118 .roundsd,
114 .subsd,119 .subsd,
115 .ucomisd,120 .ucomisd,
121 .xorpd,
116 => try lower.mirGeneric(inst),122 => try lower.mirGeneric(inst),
117123
118 .cmps,124 .cmps,
src/arch/x86_64/Mir.zig+12
...@@ -170,6 +170,8 @@ pub const Inst = struct {...@@ -170,6 +170,8 @@ pub const Inst = struct {
170 addss,170 addss,
171 /// Compare scalar single-precision floating-point values171 /// Compare scalar single-precision floating-point values
172 cmpss,172 cmpss,
173 /// Convert doubleword integer to scalar single-precision floating-point value
174 cvtsi2ss,
173 /// Divide scalar single-precision floating-point values175 /// Divide scalar single-precision floating-point values
174 divss,176 divss,
175 /// Return maximum single-precision floating-point value177 /// Return maximum single-precision floating-point value
...@@ -186,10 +188,18 @@ pub const Inst = struct {...@@ -186,10 +188,18 @@ pub const Inst = struct {
186 subss,188 subss,
187 /// Unordered compare scalar single-precision floating-point values189 /// Unordered compare scalar single-precision floating-point values
188 ucomiss,190 ucomiss,
191 /// Bitwise logical xor of packed single precision floating-point values
192 xorps,
189 /// Add double precision floating point values193 /// Add double precision floating point values
190 addsd,194 addsd,
191 /// Compare scalar double-precision floating-point values195 /// Compare scalar double-precision floating-point values
192 cmpsd,196 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,
193 /// Divide scalar double-precision floating-point values203 /// Divide scalar double-precision floating-point values
194 divsd,204 divsd,
195 /// Return maximum double-precision floating-point value205 /// Return maximum double-precision floating-point value
...@@ -206,6 +216,8 @@ pub const Inst = struct {...@@ -206,6 +216,8 @@ pub const Inst = struct {
206 subsd,216 subsd,
207 /// Unordered compare scalar double-precision floating-point values217 /// Unordered compare scalar double-precision floating-point values
208 ucomisd,218 ucomisd,
219 /// Bitwise logical xor of packed double precision floating-point values
220 xorpd,
209221
210 /// Compare string operands222 /// Compare string operands
211 cmps,223 cmps,
src/arch/x86_64/encoder.zig+1-1
...@@ -323,7 +323,7 @@ pub const Instruction = struct {...@@ -323,7 +323,7 @@ pub const Instruction = struct {
323 var rex = Rex{};323 var rex = Rex{};
324 rex.present = inst.encoding.data.mode == .rex;324 rex.present = inst.encoding.data.mode == .rex;
325 switch (inst.encoding.data.mode) {325 switch (inst.encoding.data.mode) {
326 .long, .sse2_long => rex.w = true,326 .long, .sse_long, .sse2_long => rex.w = true,
327 else => {},327 else => {},
328 }328 }
329329
src/arch/x86_64/encodings.zig+14
...@@ -834,6 +834,9 @@ pub const table = [_]Entry{...@@ -834,6 +834,9 @@ pub const table = [_]Entry{
834834
835 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse },835 .{ .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
837 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },840 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },
838841
839 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },842 .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },
...@@ -849,11 +852,20 @@ pub const table = [_]Entry{...@@ -849,11 +852,20 @@ pub const table = [_]Entry{
849852
850 .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse },853 .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse },
851854
855 .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .sse },
856
852 // SSE2857 // SSE2
853 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },858 .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },
854859
855 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 },860 .{ .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
857 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },869 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },
858870
859 .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },871 .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },
...@@ -878,6 +890,8 @@ pub const table = [_]Entry{...@@ -878,6 +890,8 @@ pub const table = [_]Entry{
878890
879 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },891 .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },
880892
893 .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .sse2 },
894
881 // SSE4.1895 // SSE4.1
882 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },896 .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
883 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },897 .{ .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");...@@ -7,6 +7,7 @@ const link = @import("link.zig");
7const log = std.log.scoped(.codegen);7const log = std.log.scoped(.codegen);
8const mem = std.mem;8const mem = std.mem;
9const math = std.math;9const math = std.math;
10const target_util = @import("target.zig");
10const trace = @import("tracy.zig").trace;11const trace = @import("tracy.zig").trace;
1112
12const Air = @import("Air.zig");13const Air = @import("Air.zig");
...@@ -89,25 +90,36 @@ pub fn generateFunction(...@@ -89,25 +90,36 @@ pub fn generateFunction(
89 }90 }
90}91}
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
92fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void {106fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void {
93 _ = target;107 _ = target;
94 const Int = @Type(.{ .Int = .{108 const bits = @typeInfo(F).Float.bits;
95 .signedness = .unsigned,109 const Int = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } });
96 .bits = @typeInfo(F).Float.bits,
97 } });
98 const int = @bitCast(Int, f);110 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);
100}112}
101113
102pub fn generateLazySymbol(114pub fn generateLazySymbol(
103 bin_file: *link.File,115 bin_file: *link.File,
104 src_loc: Module.SrcLoc,116 src_loc: Module.SrcLoc,
105 lazy_sym: link.File.LazySymbol,117 lazy_sym: link.File.LazySymbol,
118 alignment: *u32,
106 code: *std.ArrayList(u8),119 code: *std.ArrayList(u8),
107 debug_output: DebugInfoOutput,120 debug_output: DebugInfoOutput,
108 reloc_info: RelocInfo,121 reloc_info: RelocInfo,
109) CodeGenError!Result {122) CodeGenError!Result {
110 _ = debug_output;
111 _ = reloc_info;123 _ = reloc_info;
112124
113 const tracy = trace(@src());125 const tracy = trace(@src());
...@@ -122,7 +134,13 @@ pub fn generateLazySymbol(...@@ -122,7 +134,13 @@ pub fn generateLazySymbol(
122 lazy_sym.ty.fmt(mod),134 lazy_sym.ty.fmt(mod),
123 });135 });
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;
126 const err_names = mod.error_name_list.items;144 const err_names = mod.error_name_list.items;
127 mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian);145 mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian);
128 var offset = code.items.len;146 var offset = code.items.len;
...@@ -136,6 +154,14 @@ pub fn generateLazySymbol(...@@ -136,6 +154,14 @@ pub fn generateLazySymbol(
136 }154 }
137 mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian);155 mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian);
138 return Result.ok;156 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;
139 } else return .{ .fail = try ErrorMsg.create(165 } else return .{ .fail = try ErrorMsg.create(
140 bin_file.allocator,166 bin_file.allocator,
141 src_loc,167 src_loc,
...@@ -187,18 +213,14 @@ pub fn generateSymbol(...@@ -187,18 +213,14 @@ pub fn generateSymbol(
187 };213 };
188 },214 },
189 .Float => {215 .Float => {
190 const float_bits = typed_value.ty.floatBits(target);216 switch (typed_value.ty.floatBits(target)) {
191 switch (float_bits) {
192 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)),217 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)),
193 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)),218 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)),
194 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)),219 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)),
195 80 => return Result{220 80 => {
196 .fail = try ErrorMsg.create(221 writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10));
197 bin_file.allocator,222 const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;
198 src_loc,223 try code.appendNTimes(0, abi_size - 10);
199 "TODO handle f80 in generateSymbol",
200 .{},
201 ),
202 },224 },
203 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)),225 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)),
204 else => unreachable,226 else => unreachable,
...@@ -291,6 +313,20 @@ pub fn generateSymbol(...@@ -291,6 +313,20 @@ pub fn generateSymbol(
291 },313 },
292 },314 },
293 .Pointer => switch (typed_value.val.tag()) {315 .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 },
294 .zero, .one, .int_u64, .int_big_positive => {330 .zero, .one, .int_u64, .int_big_positive => {
295 switch (target.cpu.arch.ptrBitWidth()) {331 switch (target.cpu.arch.ptrBitWidth()) {
296 32 => {332 32 => {
...@@ -397,30 +433,15 @@ pub fn generateSymbol(...@@ -397,30 +433,15 @@ pub fn generateSymbol(
397 },433 },
398 }434 }
399 },435 },
400 .elem_ptr => {436 .elem_ptr => return lowerParentPtr(
401 const elem_ptr = typed_value.val.castTag(.elem_ptr).?.data;437 bin_file,
402 const elem_size = typed_value.ty.childType().abiSize(target);438 src_loc,
403 const addend = @intCast(u32, elem_ptr.index * elem_size);439 typed_value,
404 const array_ptr = elem_ptr.array_ptr;440 typed_value.val,
405441 code,
406 switch (array_ptr.tag()) {442 debug_output,
407 .decl_ref => {443 reloc_info,
408 const decl_index = array_ptr.castTag(.decl_ref).?.data;444 ),
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 },
424 else => return Result{445 else => return Result{
425 .fail = try ErrorMsg.create(446 .fail = try ErrorMsg.create(
426 bin_file.allocator,447 bin_file.allocator,
...@@ -838,9 +859,62 @@ pub fn generateSymbol(...@@ -838,9 +859,62 @@ pub fn generateSymbol(
838 }859 }
839}860}
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
841const RelocInfo = struct {911const RelocInfo = struct {
842 parent_atom_index: u32,912 parent_atom_index: u32,
843 addend: ?u32 = null,913 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 }
844};918};
845919
846fn lowerDeclRef(920fn lowerDeclRef(
...@@ -1095,6 +1169,9 @@ pub fn genTypedValue(...@@ -1095,6 +1169,9 @@ pub fn genTypedValue(
1095 .Slice => {},1169 .Slice => {},
1096 else => {1170 else => {
1097 switch (typed_value.val.tag()) {1171 switch (typed_value.val.tag()) {
1172 .null_value => {
1173 return GenResult.mcv(.{ .immediate = 0 });
1174 },
1098 .int_u64 => {1175 .int_u64 => {
1099 return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) });1176 return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) });
1100 },1177 },
src/link.zig+2-2
...@@ -1120,8 +1120,8 @@ pub const File = struct {...@@ -1120,8 +1120,8 @@ pub const File = struct {
1120 kind: Kind,1120 kind: Kind,
1121 ty: Type,1121 ty: Type,
11221122
1123 pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol {1123 pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol {
1124 return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index|1124 return .{ .kind = kind, .ty = if (decl) |decl_index|
1125 mod.declPtr(decl_index).val.castTag(.ty).?.data1125 mod.declPtr(decl_index).val.castTag(.ty).?.data
1126 else1126 else
1127 Type.anyerror };1127 Type.anyerror };
src/link/Coff.zig+66-45
...@@ -143,9 +143,11 @@ const Section = struct {...@@ -143,9 +143,11 @@ const Section = struct {
143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
144144
145const LazySymbolMetadata = struct {145const LazySymbolMetadata = struct {
146 text_atom: ?Atom.Index = null,146 const State = enum { unused, pending_flush, flushed };
147 rdata_atom: ?Atom.Index = null,147 text_atom: Atom.Index = undefined,
148 alignment: u32,148 rdata_atom: Atom.Index = undefined,
149 text_state: State = .unused,
150 rdata_state: State = .unused,
149};151};
150152
151const DeclMetadata = struct {153const DeclMetadata = struct {
...@@ -1137,7 +1139,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -1137,7 +1139,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
1137 return atom.getSymbolIndex().?;1139 return atom.getSymbolIndex().?;
1138}1140}
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 {
1141 if (build_options.skip_non_native and builtin.object_format != .coff) {1147 if (build_options.skip_non_native and builtin.object_format != .coff) {
1142 @panic("Attempted to compile for object format that was disabled by build configuration");1148 @panic("Attempted to compile for object format that was disabled by build configuration");
1143 }1149 }
...@@ -1189,32 +1195,16 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1189,32 +1195,16 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1189 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));1195 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1190}1196}
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
1208fn updateLazySymbolAtom(1198fn updateLazySymbolAtom(
1209 self: *Coff,1199 self: *Coff,
1210 sym: link.File.LazySymbol,1200 sym: link.File.LazySymbol,
1211 atom_index: Atom.Index,1201 atom_index: Atom.Index,
1212 section_index: u16,1202 section_index: u16,
1213 required_alignment: u32,
1214) !void {1203) !void {
1215 const gpa = self.base.allocator;1204 const gpa = self.base.allocator;
1216 const mod = self.base.options.module.?;1205 const mod = self.base.options.module.?;
12171206
1207 var required_alignment: u32 = undefined;
1218 var code_buffer = std.ArrayList(u8).init(gpa);1208 var code_buffer = std.ArrayList(u8).init(gpa);
1219 defer code_buffer.deinit();1209 defer code_buffer.deinit();
12201210
...@@ -1235,9 +1225,15 @@ fn updateLazySymbolAtom(...@@ -1235,9 +1225,15 @@ fn updateLazySymbolAtom(
1235 .parent_decl_node = undefined,1225 .parent_decl_node = undefined,
1236 .lazy = .unneeded,1226 .lazy = .unneeded,
1237 };1227 };
1238 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{1228 const res = try codegen.generateLazySymbol(
1239 .parent_atom_index = local_sym_index,1229 &self.base,
1240 });1230 src,
1231 sym,
1232 &required_alignment,
1233 &code_buffer,
1234 .none,
1235 .{ .parent_atom_index = local_sym_index },
1236 );
1241 const code = switch (res) {1237 const code = switch (res) {
1242 .ok => code_buffer.items,1238 .ok => code_buffer.items,
1243 .fail => |em| {1239 .fail => |em| {
...@@ -1265,20 +1261,27 @@ fn updateLazySymbolAtom(...@@ -1265,20 +1261,27 @@ fn updateLazySymbolAtom(
1265 try self.writeAtom(atom_index, code);1261 try self.writeAtom(atom_index, code);
1266}1262}
12671263
1268pub fn getOrCreateAtomForLazySymbol(1264pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index {
1269 self: *Coff,
1270 sym: link.File.LazySymbol,
1271 alignment: u32,
1272) !Atom.Index {
1273 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());1265 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
1274 errdefer _ = self.lazy_syms.pop();1266 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
1275 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };1267 if (!gop.found_existing) gop.value_ptr.* = .{};
1276 const atom = switch (sym.kind) {1268 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
1277 .code => &gop.value_ptr.text_atom,1269 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
1278 .const_data => &gop.value_ptr.rdata_atom,1270 .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state },
1279 };1271 };
1280 if (atom.* == null) atom.* = try self.createAtom();1272 switch (metadata.state.*) {
1281 return atom.*.?;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;
1282}1285}
12831286
1284pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {1287pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
...@@ -1410,7 +1413,7 @@ pub fn updateDeclExports(...@@ -1410,7 +1413,7 @@ pub fn updateDeclExports(
1410 module: *Module,1413 module: *Module,
1411 decl_index: Module.Decl.Index,1414 decl_index: Module.Decl.Index,
1412 exports: []const *Module.Export,1415 exports: []const *Module.Export,
1413) !void {1416) link.File.UpdateDeclExportsError!void {
1414 if (build_options.skip_non_native and builtin.object_format != .coff) {1417 if (build_options.skip_non_native and builtin.object_format != .coff) {
1415 @panic("Attempted to compile for object format that was disabled by build configuration");1418 @panic("Attempted to compile for object format that was disabled by build configuration");
1416 }1419 }
...@@ -1605,16 +1608,34 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1605,16 +1608,34 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1605 sub_prog_node.activate();1608 sub_prog_node.activate();
1606 defer sub_prog_node.end();1609 defer sub_prog_node.end();
16071610
1608 // Most lazy symbols can be updated when the corresponding decl is,1611 const gpa = self.base.allocator;
1609 // so we only have to worry about the one without an associated decl.1612
1610 if (self.lazy_syms.get(.none)) |metadata| {1613 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
1611 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {1614
1612 error.CodegenFail => return error.FlushFailure,1615 if (self.lazy_syms.getPtr(.none)) |metadata| {
1613 else => |e| return e,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,
1614 };1633 };
1615 }1634 }
16161635 for (self.lazy_syms.values()) |*metadata| {
1617 const gpa = self.base.allocator;1636 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1637 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
1638 }
16181639
1619 while (self.unresolved.popOrNull()) |entry| {1640 while (self.unresolved.popOrNull()) |entry| {
1620 assert(entry.value); // We only expect imports generated by the incremental linker for now.1641 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 {...@@ -65,9 +65,11 @@ const Section = struct {
65};65};
6666
67const LazySymbolMetadata = struct {67const LazySymbolMetadata = struct {
68 text_atom: ?Atom.Index = null,68 const State = enum { unused, pending_flush, flushed };
69 rodata_atom: ?Atom.Index = null,69 text_atom: Atom.Index = undefined,
70 alignment: u32,70 rodata_atom: Atom.Index = undefined,
71 text_state: State = .unused,
72 rodata_state: State = .unused,
71};73};
7274
73const DeclMetadata = struct {75const DeclMetadata = struct {
...@@ -1033,19 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1033,19 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1033 sub_prog_node.activate();1035 sub_prog_node.activate();
1034 defer sub_prog_node.end();1036 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
1045 // TODO This linker code currently assumes there is only 1 compilation unit and it1038 // TODO This linker code currently assumes there is only 1 compilation unit and it
1046 // corresponds to the Zig source code.1039 // corresponds to the Zig source code.
1047 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;1040 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
1049 const target_endian = self.base.options.target.cpu.arch.endian();1067 const target_endian = self.base.options.target.cpu.arch.endian();
1050 const foreign_endian = target_endian != builtin.cpu.arch.endian();1068 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 {...@@ -2377,16 +2395,27 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2377 }2395 }
2378}2396}
23792397
2380pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index {2398pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index {
2381 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());2399 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2382 errdefer _ = self.lazy_syms.pop();2400 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2383 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };2401 if (!gop.found_existing) gop.value_ptr.* = .{};
2384 const atom = switch (sym.kind) {2402 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2385 .code => &gop.value_ptr.text_atom,2403 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2386 .const_data => &gop.value_ptr.rodata_atom,2404 .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
2387 };2405 };
2388 if (atom.* == null) atom.* = try self.createAtom();2406 switch (metadata.state.*) {
2389 return atom.*.?;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;
2390}2419}
23912420
2392pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {2421pub 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...@@ -2580,7 +2609,11 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2580 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2609 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2581}2610}
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 {
2584 if (build_options.skip_non_native and builtin.object_format != .elf) {2617 if (build_options.skip_non_native and builtin.object_format != .elf) {
2585 @panic("Attempted to compile for object format that was disabled by build configuration");2618 @panic("Attempted to compile for object format that was disabled by build configuration");
2586 }2619 }
...@@ -2657,32 +2690,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2657,32 +2690,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2657 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2690 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2658}2691}
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
2676fn updateLazySymbolAtom(2693fn updateLazySymbolAtom(
2677 self: *Elf,2694 self: *Elf,
2678 sym: File.LazySymbol,2695 sym: File.LazySymbol,
2679 atom_index: Atom.Index,2696 atom_index: Atom.Index,
2680 shdr_index: u16,2697 shdr_index: u16,
2681 required_alignment: u32,
2682) !void {2698) !void {
2683 const gpa = self.base.allocator;2699 const gpa = self.base.allocator;
2684 const mod = self.base.options.module.?;2700 const mod = self.base.options.module.?;
26852701
2702 var required_alignment: u32 = undefined;
2686 var code_buffer = std.ArrayList(u8).init(gpa);2703 var code_buffer = std.ArrayList(u8).init(gpa);
2687 defer code_buffer.deinit();2704 defer code_buffer.deinit();
26882705
...@@ -2707,9 +2724,15 @@ fn updateLazySymbolAtom(...@@ -2707,9 +2724,15 @@ fn updateLazySymbolAtom(
2707 .parent_decl_node = undefined,2724 .parent_decl_node = undefined,
2708 .lazy = .unneeded,2725 .lazy = .unneeded,
2709 };2726 };
2710 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{2727 const res = try codegen.generateLazySymbol(
2711 .parent_atom_index = local_sym_index,2728 &self.base,
2712 });2729 src,
2730 sym,
2731 &required_alignment,
2732 &code_buffer,
2733 .none,
2734 .{ .parent_atom_index = local_sym_index },
2735 );
2713 const code = switch (res) {2736 const code = switch (res) {
2714 .ok => code_buffer.items,2737 .ok => code_buffer.items,
2715 .fail => |em| {2738 .fail => |em| {
...@@ -2814,7 +2837,7 @@ pub fn updateDeclExports(...@@ -2814,7 +2837,7 @@ pub fn updateDeclExports(
2814 module: *Module,2837 module: *Module,
2815 decl_index: Module.Decl.Index,2838 decl_index: Module.Decl.Index,
2816 exports: []const *Module.Export,2839 exports: []const *Module.Export,
2817) !void {2840) File.UpdateDeclExportsError!void {
2818 if (build_options.skip_non_native and builtin.object_format != .elf) {2841 if (build_options.skip_non_native and builtin.object_format != .elf) {
2819 @panic("Attempted to compile for object format that was disabled by build configuration");2842 @panic("Attempted to compile for object format that was disabled by build configuration");
2820 }2843 }
src/link/MachO.zig+64-45
...@@ -236,9 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {...@@ -236,9 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
236const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);236const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
237237
238const LazySymbolMetadata = struct {238const LazySymbolMetadata = struct {
239 text_atom: ?Atom.Index = null,239 const State = enum { unused, pending_flush, flushed };
240 data_const_atom: ?Atom.Index = null,240 text_atom: Atom.Index = undefined,
241 alignment: u32,241 data_const_atom: Atom.Index = undefined,
242 text_state: State = .unused,
243 data_const_state: State = .unused,
242};244};
243245
244const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index);246const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index);
...@@ -494,16 +496,32 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -494,16 +496,32 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
494 sub_prog_node.activate();496 sub_prog_node.activate();
495 defer sub_prog_node.end();497 defer sub_prog_node.end();
496498
497 // Most lazy symbols can be updated when the corresponding decl is,499 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
498 // so we only have to worry about the one without an associated decl.500
499 if (self.lazy_syms.get(.none)) |metadata| {501 if (self.lazy_syms.getPtr(.none)) |metadata| {
500 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {502 // Most lazy symbols can be updated on first use, but
501 error.CodegenFail => return error.FlushFailure,503 // anyerror needs to wait for everything to be flushed.
502 else => |e| return e,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,
503 };519 };
504 }520 }
505521 for (self.lazy_syms.values()) |*metadata| {
506 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;522 if (metadata.text_state != .unused) metadata.text_state = .flushed;
523 if (metadata.data_const_state != .unused) metadata.data_const_state = .flushed;
524 }
507525
508 if (self.d_sym) |*d_sym| {526 if (self.d_sym) |*d_sym| {
509 try d_sym.dwarf.flushModule(module);527 try d_sym.dwarf.flushModule(module);
...@@ -2037,32 +2055,16 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2037,32 +2055,16 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2037 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2055 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2038}2056}
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
2056fn updateLazySymbolAtom(2058fn updateLazySymbolAtom(
2057 self: *MachO,2059 self: *MachO,
2058 sym: File.LazySymbol,2060 sym: File.LazySymbol,
2059 atom_index: Atom.Index,2061 atom_index: Atom.Index,
2060 section_index: u8,2062 section_index: u8,
2061 required_alignment: u32,
2062) !void {2063) !void {
2063 const gpa = self.base.allocator;2064 const gpa = self.base.allocator;
2064 const mod = self.base.options.module.?;2065 const mod = self.base.options.module.?;
20652066
2067 var required_alignment: u32 = undefined;
2066 var code_buffer = std.ArrayList(u8).init(gpa);2068 var code_buffer = std.ArrayList(u8).init(gpa);
2067 defer code_buffer.deinit();2069 defer code_buffer.deinit();
20682070
...@@ -2087,9 +2089,15 @@ fn updateLazySymbolAtom(...@@ -2087,9 +2089,15 @@ fn updateLazySymbolAtom(
2087 .parent_decl_node = undefined,2089 .parent_decl_node = undefined,
2088 .lazy = .unneeded,2090 .lazy = .unneeded,
2089 };2091 };
2090 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{2092 const res = try codegen.generateLazySymbol(
2091 .parent_atom_index = local_sym_index,2093 &self.base,
2092 });2094 src,
2095 sym,
2096 &required_alignment,
2097 &code_buffer,
2098 .none,
2099 .{ .parent_atom_index = local_sym_index },
2100 );
2093 const code = switch (res) {2101 const code = switch (res) {
2094 .ok => code_buffer.items,2102 .ok => code_buffer.items,
2095 .fail => |em| {2103 .fail => |em| {
...@@ -2108,7 +2116,7 @@ fn updateLazySymbolAtom(...@@ -2108,7 +2116,7 @@ fn updateLazySymbolAtom(
2108 errdefer self.freeAtom(atom_index);2116 errdefer self.freeAtom(atom_index);
21092117
2110 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });2118 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
2113 atom.size = code.len;2121 atom.size = code.len;
2114 symbol.n_value = vaddr;2122 symbol.n_value = vaddr;
...@@ -2117,16 +2125,30 @@ fn updateLazySymbolAtom(...@@ -2117,16 +2125,30 @@ fn updateLazySymbolAtom(
2117 try self.writeAtom(atom_index, code);2125 try self.writeAtom(atom_index, code);
2118}2126}
21192127
2120pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index {2128pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index {
2121 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());2129 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2122 errdefer _ = self.lazy_syms.pop();2130 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2123 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };2131 if (!gop.found_existing) gop.value_ptr.* = .{};
2124 const atom = switch (sym.kind) {2132 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2125 .code => &gop.value_ptr.text_atom,2133 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2126 .const_data => &gop.value_ptr.data_const_atom,2134 .const_data => .{
2135 .atom = &gop.value_ptr.data_const_atom,
2136 .state = &gop.value_ptr.data_const_state,
2137 },
2127 };2138 };
2128 if (atom.* == null) atom.* = try self.createAtom();2139 switch (metadata.state.*) {
2129 return atom.*.?;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;
2130}2152}
21312153
2132fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {2154fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {
...@@ -2357,7 +2379,7 @@ pub fn updateDeclExports(...@@ -2357,7 +2379,7 @@ pub fn updateDeclExports(
2357 module: *Module,2379 module: *Module,
2358 decl_index: Module.Decl.Index,2380 decl_index: Module.Decl.Index,
2359 exports: []const *Module.Export,2381 exports: []const *Module.Export,
2360) !void {2382) File.UpdateDeclExportsError!void {
2361 if (build_options.skip_non_native and builtin.object_format != .macho) {2383 if (build_options.skip_non_native and builtin.object_format != .macho) {
2362 @panic("Attempted to compile for object format that was disabled by build configuration");2384 @panic("Attempted to compile for object format that was disabled by build configuration");
2363 }2385 }
...@@ -4147,9 +4169,6 @@ pub fn logSymtab(self: *MachO) void {...@@ -4147,9 +4169,6 @@ pub fn logSymtab(self: *MachO) void {
41474169
4148 log.debug("stubs entries:", .{});4170 log.debug("stubs entries:", .{});
4149 log.debug("{}", .{self.stub_table});4171 log.debug("{}", .{self.stub_table});
4150
4151 // log.debug("threadlocal entries:", .{});
4152 // log.debug("{}", .{self.tlv_table});
4153}4172}
41544173
4155pub fn logAtoms(self: *MachO) void {4174pub fn logAtoms(self: *MachO) void {
...@@ -4189,6 +4208,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index) void {...@@ -4189,6 +4208,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index) void {
4189 sym.n_value,4208 sym.n_value,
4190 atom.size,4209 atom.size,
4191 atom.file,4210 atom.file,
4192 sym.n_sect,4211 sym.n_sect + 1,
4193 });4212 });
4194}4213}
src/print_air.zig+9-3
...@@ -94,14 +94,20 @@ const Writer = struct {...@@ -94,14 +94,20 @@ const Writer = struct {
94 for (w.air.instructions.items(.tag), 0..) |tag, i| {94 for (w.air.instructions.items(.tag), 0..) |tag, i| {
95 const inst = @intCast(Air.Inst.Index, i);95 const inst = @intCast(Air.Inst.Index, i);
96 switch (tag) {96 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 },
98 else => continue,101 else => continue,
99 }102 }
100 }103 }
101 }104 }
102105
103 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {106 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 }
105 }111 }
106112
107 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {113 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -336,7 +342,7 @@ const Writer = struct {...@@ -336,7 +342,7 @@ const Writer = struct {
336 .work_group_id,342 .work_group_id,
337 => try w.writeWorkDimension(s, inst),343 => try w.writeWorkDimension(s, inst),
338 }344 }
339 try s.writeAll(")\n");345 try s.writeByte(')');
340 }346 }
341347
342 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {348 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 {...@@ -282,7 +282,6 @@ fn give() anyerror!u128 {
282282
283test "page aligned array on stack" {283test "page aligned array on stack" {
284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
285 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
287 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO286 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" {...@@ -491,10 +490,6 @@ test "read 128-bit field from default aligned struct in global memory" {
491}490}
492491
493test "struct field explicit alignment" {492test "struct field explicit alignment" {
494 if (builtin.zig_backend == .stage2_x86_64) {
495 // Careful enabling this test, fails randomly.
496 return error.SkipZigTest;
497 }
498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO495 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/atomics.zig-1
...@@ -112,7 +112,6 @@ test "128-bit cmpxchg" {...@@ -112,7 +112,6 @@ test "128-bit cmpxchg" {
112 if (!supports_128_bit_atomics) return error.SkipZigTest;112 if (!supports_128_bit_atomics) return error.SkipZigTest;
113113
114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO117 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 {...@@ -363,7 +363,8 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
363}363}
364364
365test "take address of parameter" {365test "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
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -391,7 +392,8 @@ test "array 2D const double ptr" {...@@ -391,7 +392,8 @@ test "array 2D const double ptr" {
391 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;392 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
393 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;394 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
395 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
396398
397 const rect_2d_vertexes = [_][1]f32{399 const rect_2d_vertexes = [_][1]f32{
...@@ -405,7 +407,8 @@ test "array 2D const double ptr with offset" {...@@ -405,7 +407,8 @@ test "array 2D const double ptr with offset" {
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;409 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
409 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;412 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
410413
411 const rect_2d_vertexes = [_][2]f32{414 const rect_2d_vertexes = [_][2]f32{
...@@ -419,7 +422,8 @@ test "array 3D const double ptr with offset" {...@@ -419,7 +422,8 @@ test "array 3D const double ptr with offset" {
419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;422 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;424 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
423 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO427 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
424428
425 const rect_3d_vertexes = [_][2][2]f32{429 const rect_3d_vertexes = [_][2][2]f32{
test/behavior/bugs/13069.zig+2
...@@ -6,6 +6,8 @@ test {...@@ -6,6 +6,8 @@ test {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 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
10 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;12 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
1113
test/behavior/cast.zig+5-2
...@@ -95,7 +95,9 @@ test "comptime_int @intToFloat" {...@@ -95,7 +95,9 @@ test "comptime_int @intToFloat" {
9595
96test "@intToFloat" {96test "@intToFloat" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO98 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
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
101103
...@@ -634,7 +636,8 @@ test "vector casts" {...@@ -634,7 +636,8 @@ test "vector casts" {
634}636}
635637
636test "@floatCast cast down" {638test "@floatCast cast down" {
637 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO639 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
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO641 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO642 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
640 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO643 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" {...@@ -940,6 +940,8 @@ test "constant enum initialization with differing sizes" {
940 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;940 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
941 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;941 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
942 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO942 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
944 try test3_1(test3_foo);946 try test3_1(test3_foo);
945 try test3_2(test3_bar);947 try test3_2(test3_bar);
...@@ -979,7 +981,6 @@ fn test3_2(f: Test3Foo) !void {...@@ -979,7 +981,6 @@ fn test3_2(f: Test3Foo) !void {
979}981}
980982
981test "@tagName" {983test "@tagName" {
982 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;984 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;985 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
985 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO986 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -995,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 {...@@ -995,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 {
995const BareNumber = enum { One, Two, Three };996const BareNumber = enum { One, Two, Three };
996997
997test "@tagName non-exhaustive enum" {998test "@tagName non-exhaustive enum" {
998 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1000 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1000 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1006,7 +1006,6 @@ test "@tagName non-exhaustive enum" {...@@ -1006,7 +1006,6 @@ test "@tagName non-exhaustive enum" {
1006const NonExhaustive = enum(u8) { A, B, _ };1006const NonExhaustive = enum(u8) { A, B, _ };
10071007
1008test "@tagName is null-terminated" {1008test "@tagName is null-terminated" {
1009 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1009 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1011 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1011 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1021,7 +1020,6 @@ test "@tagName is null-terminated" {...@@ -1021,7 +1020,6 @@ test "@tagName is null-terminated" {
1021}1020}
10221021
1023test "tag name with assigned enum values" {1022test "tag name with assigned enum values" {
1024 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1025 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1023 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1026 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1024 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1027 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1025 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1111,7 +1109,6 @@ test "enum literal in array literal" {...@@ -1111,7 +1109,6 @@ test "enum literal in array literal" {
11111109
1112test "tag name functions are unique" {1110test "tag name functions are unique" {
1113 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1111 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1114 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/eval.zig+2
...@@ -535,6 +535,8 @@ test "static eval list init" {...@@ -535,6 +535,8 @@ test "static eval list init" {
535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO537 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
539 try expect(static_vec3.data[2] == 1.0);541 try expect(static_vec3.data[2] == 1.0);
540 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);542 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" {...@@ -904,7 +904,8 @@ test "negation f16" {
904}904}
905905
906test "negation f32" {906test "negation f32" {
907 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO907 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
908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO909 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
909 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO910 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
910 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO911 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -924,7 +925,8 @@ test "negation f32" {...@@ -924,7 +925,8 @@ test "negation f32" {
924}925}
925926
926test "negation f64" {927test "negation f64" {
927 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO928 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
928 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
930 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO932 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" {...@@ -1021,7 +1023,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
10211023
1022test "comptime fixed-width float non-zero divided by zero produces signed Inf" {1024test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
1023 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1025 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1024 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1025 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1026 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1026 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1027 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1060,7 +1061,8 @@ test "nan negation f16" {...@@ -1060,7 +1061,8 @@ test "nan negation f16" {
1060}1061}
10611062
1062test "nan negation f32" {1063test "nan negation f32" {
1063 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1064 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
1064 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1067 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1068 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1080,7 +1082,8 @@ test "nan negation f32" {...@@ -1080,7 +1082,8 @@ test "nan negation f32" {
10801082
1081test "nan negation f64" {1083test "nan negation f64" {
1082 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1084 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1083 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1085 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
1084 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1087 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1085 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1088 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1086 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1089 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" {...@@ -338,6 +338,8 @@ test "function call with anon list literal" {
338 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO338 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO340 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
342 const S = struct {344 const S = struct {
343 fn doTheTest() !void {345 fn doTheTest() !void {
...@@ -358,6 +360,8 @@ test "function call with anon list literal - 2D" {...@@ -358,6 +360,8 @@ test "function call with anon list literal - 2D" {
358 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
360 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO362 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
362 const S = struct {366 const S = struct {
363 fn doTheTest() !void {367 fn doTheTest() !void {
test/behavior/generics.zig+4
...@@ -59,6 +59,8 @@ test "fn with comptime args" {...@@ -59,6 +59,8 @@ test "fn with comptime args" {
59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO61 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
63 try expect(gimmeTheBigOne(1234, 5678) == 5678);65 try expect(gimmeTheBigOne(1234, 5678) == 5678);
64 try expect(shouldCallSameInstance(34, 12) == 34);66 try expect(shouldCallSameInstance(34, 12) == 34);
...@@ -69,6 +71,8 @@ test "anytype params" {...@@ -69,6 +71,8 @@ test "anytype params" {
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO73 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
73 try expect(max_i32(12, 34) == 34);77 try expect(max_i32(12, 34) == 34);
74 try expect(max_f64(1.2, 3.4) == 3.4);78 try expect(max_f64(1.2, 3.4) == 3.4);
test/behavior/inline_switch.zig-1
...@@ -94,7 +94,6 @@ test "inline else error" {...@@ -94,7 +94,6 @@ test "inline else error" {
9494
95test "inline else enum" {95test "inline else enum" {
96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9998
100 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };99 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" {...@@ -203,6 +203,8 @@ test "float equality" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO205 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
207 const x: f64 = 0.012;209 const x: f64 = 0.012;
208 const y: f64 = x + 1.0;210 const y: f64 = x + 1.0;
...@@ -377,7 +379,6 @@ fn testBinaryNot(x: u16) !void {...@@ -377,7 +379,6 @@ fn testBinaryNot(x: u16) !void {
377379
378test "binary not 128-bit" {380test "binary not 128-bit" {
379 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1533,7 +1534,6 @@ test "signed zeros are represented properly" {...@@ -1533,7 +1534,6 @@ test "signed zeros are represented properly" {
1533 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1534 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1534 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1535 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1535 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1536 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1536 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15381538
1539 const S = struct {1539 const S = struct {
test/behavior/maximum_minimum.zig+4
...@@ -8,6 +8,8 @@ test "@max" {...@@ -8,6 +8,8 @@ test "@max" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 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
12 const S = struct {14 const S = struct {
13 fn doTheTest() !void {15 fn doTheTest() !void {
...@@ -54,6 +56,8 @@ test "@min" {...@@ -54,6 +56,8 @@ test "@min" {
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO58 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
58 const S = struct {62 const S = struct {
59 fn doTheTest() !void {63 fn doTheTest() !void {
test/behavior/memset.zig+2-2
...@@ -114,7 +114,7 @@ test "memset with large array element, runtime known" {...@@ -114,7 +114,7 @@ test "memset with large array element, runtime known" {
114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;116 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
119 const A = [128]u64;119 const A = [128]u64;
120 var buf: [5]A = undefined;120 var buf: [5]A = undefined;
...@@ -132,7 +132,7 @@ test "memset with large array element, comptime known" {...@@ -132,7 +132,7 @@ test "memset with large array element, comptime known" {
132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
134 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;134 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
137 const A = [128]u64;137 const A = [128]u64;
138 var buf: [5]A = undefined;138 var buf: [5]A = undefined;
test/behavior/pointers.zig+4-1
...@@ -206,7 +206,8 @@ test "allowzero pointer and slice" {...@@ -206,7 +206,8 @@ test "allowzero pointer and slice" {
206}206}
207207
208test "assign null directly to C pointer and test null equality" {208test "assign null directly to C pointer and test null equality" {
209 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO209 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
210 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
211 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
212 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO213 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -345,6 +346,8 @@ test "pointer sentinel with +inf" {...@@ -345,6 +346,8 @@ test "pointer sentinel with +inf" {
345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO347 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
347 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO348 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
349 const S = struct {352 const S = struct {
350 fn doTheTest() !void {353 fn doTheTest() !void {
test/behavior/struct.zig+2-1
...@@ -744,7 +744,8 @@ var g_foo: S0 = S0.init();...@@ -744,7 +744,8 @@ var g_foo: S0 = S0.init();
744744
745test "packed struct with fp fields" {745test "packed struct with fp fields" {
746 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO746 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
747 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO747 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
748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO749 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO750 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
750 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO751 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 {...@@ -88,7 +88,6 @@ fn nonConstSwitch(foo: SwitchStatementFoo) !void {
88const SwitchStatementFoo = enum { A, B, C, D };88const SwitchStatementFoo = enum { A, B, C, D };
8989
90test "switch with multiple expressions" {90test "switch with multiple expressions" {
91 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO91 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9392
94 const x = switch (returnsFive()) {93 const x = switch (returnsFive()) {
...@@ -231,6 +230,8 @@ test "switch prong with variable" {...@@ -231,6 +230,8 @@ test "switch prong with variable" {
231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO232 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
235 try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });236 try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
236 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });237 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
...@@ -273,7 +274,6 @@ fn testSwitchEnumPtrCapture() !void {...@@ -273,7 +274,6 @@ fn testSwitchEnumPtrCapture() !void {
273}274}
274275
275test "switch handles all cases of number" {276test "switch handles all cases of number" {
276 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
278278
279 try testSwitchHandleAllCases();279 try testSwitchHandleAllCases();
...@@ -453,7 +453,6 @@ test "else prong of switch on error set excludes other cases" {...@@ -453,7 +453,6 @@ test "else prong of switch on error set excludes other cases" {
453}453}
454454
455test "switch prongs with error set cases make a new error set type for capture value" {455test "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
457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO457 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO458 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" {...@@ -530,7 +529,6 @@ test "switch with null and T peer types and inferred result location type" {
530test "switch prongs with cases with identical payload types" {529test "switch prongs with cases with identical payload types" {
531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO531 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535533
536 const Union = union(enum) {534 const Union = union(enum) {
test/behavior/type.zig-2
...@@ -258,7 +258,6 @@ test "Type.ErrorSet" {...@@ -258,7 +258,6 @@ test "Type.ErrorSet" {
258258
259test "Type.Struct" {259test "Type.Struct" {
260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
261 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
263 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
264 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -383,7 +382,6 @@ test "Type.Enum" {...@@ -383,7 +382,6 @@ test "Type.Enum" {
383382
384test "Type.Union" {383test "Type.Union" {
385 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO384 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
386 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO386 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" {...@@ -14,6 +14,8 @@ test "basic unions with floats" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 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
18 var foo = FooWithFloats{ .int = 1 };20 var foo = FooWithFloats{ .int = 1 };
19 try expect(foo.int == 1);21 try expect(foo.int == 1);
...@@ -29,6 +31,8 @@ test "init union with runtime value - floats" {...@@ -29,6 +31,8 @@ test "init union with runtime value - floats" {
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO33 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
33 var foo: FooWithFloats = undefined;37 var foo: FooWithFloats = undefined;
3438
...@@ -216,6 +220,8 @@ test "union with specified enum tag" {...@@ -216,6 +220,8 @@ test "union with specified enum tag" {
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
217 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
218 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO222 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
220 try doTest();226 try doTest();
221 comptime try doTest();227 comptime try doTest();
...@@ -225,6 +231,8 @@ test "packed union generates correctly aligned type" {...@@ -225,6 +231,8 @@ test "packed union generates correctly aligned type" {
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO233 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
229 const U = packed union {237 const U = packed union {
230 f1: *const fn () error{TestUnexpectedResult}!void,238 f1: *const fn () error{TestUnexpectedResult}!void,
...@@ -903,6 +911,8 @@ test "anonymous union literal syntax" {...@@ -903,6 +911,8 @@ test "anonymous union literal syntax" {
903 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO911 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
904 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO912 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
905 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO913 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
907 const S = struct {917 const S = struct {
908 const Number = union {918 const Number = union {
...@@ -1055,6 +1065,8 @@ test "containers with single-field enums" {...@@ -1055,6 +1065,8 @@ test "containers with single-field enums" {
1055 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1056 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1057 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1067 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
1059 const S = struct {1071 const S = struct {
1060 const A = union(enum) { f1 };1072 const A = union(enum) { f1 };
...@@ -1082,7 +1094,6 @@ test "containers with single-field enums" {...@@ -1082,7 +1094,6 @@ test "containers with single-field enums" {
1082test "@unionInit on union with tag but no fields" {1094test "@unionInit on union with tag but no fields" {
1083 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1095 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1084 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1096 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1085 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1086 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1097 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1087 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1098 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10881099
...@@ -1277,7 +1288,6 @@ test "return an extern union from C calling convention" {...@@ -1277,7 +1288,6 @@ test "return an extern union from C calling convention" {
1277test "noreturn field in union" {1288test "noreturn field in union" {
1278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1279 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1280 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12821292
1283 const U = union(enum) {1293 const U = union(enum) {
...@@ -1515,6 +1525,8 @@ test "reinterpreting enum value inside packed union" {...@@ -1515,6 +1525,8 @@ test "reinterpreting enum value inside packed union" {
1515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1526 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1517 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1527 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
1519 const U = packed union {1531 const U = packed union {
1520 tag: enum { a, b },1532 tag: enum { a, b },
test/behavior/vector.zig+4
...@@ -321,6 +321,7 @@ test "load vector elements via comptime index" {...@@ -321,6 +321,7 @@ test "load vector elements via comptime index" {
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
324325
325 const S = struct {326 const S = struct {
326 fn doTheTest() !void {327 fn doTheTest() !void {
...@@ -342,6 +343,7 @@ test "store vector elements via comptime index" {...@@ -342,6 +343,7 @@ test "store vector elements via comptime index" {
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO345 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
345347
346 const S = struct {348 const S = struct {
347 fn doTheTest() !void {349 fn doTheTest() !void {
...@@ -369,6 +371,7 @@ test "load vector elements via runtime index" {...@@ -369,6 +371,7 @@ test "load vector elements via runtime index" {
369 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO373 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
372375
373 const S = struct {376 const S = struct {
374 fn doTheTest() !void {377 fn doTheTest() !void {
...@@ -390,6 +393,7 @@ test "store vector elements via runtime index" {...@@ -390,6 +393,7 @@ test "store vector elements via runtime index" {
390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO395 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
393397
394 const S = struct {398 const S = struct {
395 fn doTheTest() !void {399 fn doTheTest() !void {
test/src/Cases.zig+6
...@@ -396,6 +396,12 @@ fn addFromDirInner(...@@ -396,6 +396,12 @@ fn addFromDirInner(
396 // Other backends don't support new liveness format396 // Other backends don't support new liveness format
397 continue;397 continue;
398 }398 }
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
400 const next = ctx.cases.items.len;406 const next = ctx.cases.items.len;
401 try ctx.cases.append(.{407 try ctx.cases.append(.{