authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-02 03:10:19-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:42:08-05:00
loge5d5a8bc4ea6b27dc3540ad4800a1231ff50b33d
tree114481f7bbf4d5e6a4703a7606f654dabb5df330
parentac1a975f9b5a7d939663fa90556a2f038250c531

x86_64: implement switch jump tables


33 files changed, 476 insertions(+), 199 deletions(-)

lib/std/Thread/Condition.zig+3-3
......@@ -161,17 +161,17 @@ const WindowsImpl = struct {
161161 }
162162 }
163163
164 if (comptime builtin.mode == .Debug) {
164 if (builtin.mode == .Debug) {
165165 // The internal state of the DebugMutex needs to be handled here as well.
166166 mutex.impl.locking_thread.store(0, .unordered);
167167 }
168168 const rc = os.windows.kernel32.SleepConditionVariableSRW(
169169 &self.condition,
170 if (comptime builtin.mode == .Debug) &mutex.impl.impl.srwlock else &mutex.impl.srwlock,
170 if (builtin.mode == .Debug) &mutex.impl.impl.srwlock else &mutex.impl.srwlock,
171171 timeout_ms,
172172 0, // the srwlock was assumed to acquired in exclusive mode not shared
173173 );
174 if (comptime builtin.mode == .Debug) {
174 if (builtin.mode == .Debug) {
175175 // The internal state of the DebugMutex needs to be handled here as well.
176176 mutex.impl.locking_thread.store(std.Thread.getCurrentId(), .unordered);
177177 }
lib/std/Thread/Mutex.zig+1-1
......@@ -158,7 +158,7 @@ const FutexImpl = struct {
158158 // On x86, use `lock bts` instead of `lock cmpxchg` as:
159159 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
160160 // - `lock bts` is smaller instruction-wise which makes it better for inlining
161 if (comptime builtin.target.cpu.arch.isX86()) {
161 if (builtin.target.cpu.arch.isX86()) {
162162 const locked_bit = @ctz(locked);
163163 return self.state.bitSet(locked_bit, .acquire) == 0;
164164 }
lib/std/debug.zig+3-3
......@@ -179,7 +179,7 @@ pub fn dumpHexFallible(bytes: []const u8) !void {
179179/// TODO multithreaded awareness
180180pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
181181 nosuspend {
182 if (comptime builtin.target.isWasm()) {
182 if (builtin.target.isWasm()) {
183183 if (native_os == .wasi) {
184184 const stderr = io.getStdErr().writer();
185185 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
......@@ -267,7 +267,7 @@ pub inline fn getContext(context: *ThreadContext) bool {
267267/// TODO multithreaded awareness
268268pub fn dumpStackTraceFromBase(context: *ThreadContext) void {
269269 nosuspend {
270 if (comptime builtin.target.isWasm()) {
270 if (builtin.target.isWasm()) {
271271 if (native_os == .wasi) {
272272 const stderr = io.getStdErr().writer();
273273 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
......@@ -365,7 +365,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
365365/// TODO multithreaded awareness
366366pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {
367367 nosuspend {
368 if (comptime builtin.target.isWasm()) {
368 if (builtin.target.isWasm()) {
369369 if (native_os == .wasi) {
370370 const stderr = io.getStdErr().writer();
371371 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
lib/std/debug/SelfInfo.zig+4-4
......@@ -121,13 +121,13 @@ pub fn deinit(self: *SelfInfo) void {
121121}
122122
123123pub fn getModuleForAddress(self: *SelfInfo, address: usize) !*Module {
124 if (comptime builtin.target.isDarwin()) {
124 if (builtin.target.isDarwin()) {
125125 return self.lookupModuleDyld(address);
126126 } else if (native_os == .windows) {
127127 return self.lookupModuleWin32(address);
128128 } else if (native_os == .haiku) {
129129 return self.lookupModuleHaiku(address);
130 } else if (comptime builtin.target.isWasm()) {
130 } else if (builtin.target.isWasm()) {
131131 return self.lookupModuleWasm(address);
132132 } else {
133133 return self.lookupModuleDl(address);
......@@ -138,13 +138,13 @@ pub fn getModuleForAddress(self: *SelfInfo, address: usize) !*Module {
138138// This can be called when getModuleForAddress fails, so implementations should provide
139139// a path that doesn't rely on any side-effects of a prior successful module lookup.
140140pub fn getModuleNameForAddress(self: *SelfInfo, address: usize) ?[]const u8 {
141 if (comptime builtin.target.isDarwin()) {
141 if (builtin.target.isDarwin()) {
142142 return self.lookupModuleNameDyld(address);
143143 } else if (native_os == .windows) {
144144 return self.lookupModuleNameWin32(address);
145145 } else if (native_os == .haiku) {
146146 return null;
147 } else if (comptime builtin.target.isWasm()) {
147 } else if (builtin.target.isWasm()) {
148148 return null;
149149 } else {
150150 return self.lookupModuleNameDl(address);
lib/std/heap.zig+1-1
......@@ -890,7 +890,7 @@ test {
890890 _ = @import("heap/memory_pool.zig");
891891 _ = ArenaAllocator;
892892 _ = GeneralPurposeAllocator;
893 if (comptime builtin.target.isWasm()) {
893 if (builtin.target.isWasm()) {
894894 _ = WasmAllocator;
895895 _ = WasmPageAllocator;
896896 }
lib/std/math/big/int.zig+1-1
......@@ -2523,7 +2523,7 @@ pub const Const = struct {
25232523 /// Returns the number of leading zeros in twos-complement form.
25242524 pub fn clz(a: Const, bits: Limb) Limb {
25252525 // Limbs are stored in little-endian order but we need to iterate big-endian.
2526 if (!a.positive) return 0;
2526 if (!a.positive and !a.eqlZero()) return 0;
25272527 var total_limb_lz: Limb = 0;
25282528 var i: usize = a.limbs.len;
25292529 const bits_per_limb = @bitSizeOf(Limb);
lib/std/os.zig+1-1
......@@ -157,7 +157,7 @@ pub fn getFdPath(fd: std.posix.fd_t, out_buffer: *[max_path_bytes]u8) std.posix.
157157 return target;
158158 },
159159 .freebsd => {
160 if (comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false) {
160 if (builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false) {
161161 var kfile: std.c.kinfo_file = undefined;
162162 kfile.structsize = std.c.KINFO_FILE_SIZE;
163163 switch (posix.errno(std.c.fcntl(fd, std.c.F.KINFO, @intFromPtr(&kfile)))) {
lib/std/os/windows.zig+1-1
......@@ -1061,7 +1061,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
10611061 // us INVALID_PARAMETER.
10621062 // The same reasoning for win10_rs5 as in os.renameatW() applies (FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5).
10631063 var need_fallback = true;
1064 if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs5)) {
1064 if (builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs5)) {
10651065 // Deletion with posix semantics if the filesystem supports it.
10661066 var info = FILE_DISPOSITION_INFORMATION_EX{
10671067 .Flags = FILE_DISPOSITION_DELETE |
lib/std/posix.zig+1-1
......@@ -6819,7 +6819,7 @@ pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
68196819 }
68206820 },
68216821 .freebsd => {
6822 if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt)
6822 if (builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt)
68236823 @compileError("memfd_create is unavailable on FreeBSD < 13.0");
68246824 const rc = system.memfd_create(name, flags);
68256825 switch (errno(rc)) {
lib/std/posix/test.zig+1-1
......@@ -804,7 +804,7 @@ test "getrlimit and setrlimit" {
804804 //
805805 // This happens for example if RLIMIT_MEMLOCK is bigger than ~2GiB.
806806 // In that case the following the limit would be RLIM_INFINITY and the following setrlimit fails with EPERM.
807 if (comptime builtin.cpu.arch.isMIPS() and builtin.link_libc) {
807 if (builtin.cpu.arch.isMIPS() and builtin.link_libc) {
808808 if (limit.cur != linux.RLIM.INFINITY) {
809809 try posix.setrlimit(resource, limit);
810810 }
lib/std/simd.zig+4-6
......@@ -163,7 +163,7 @@ pub fn interlace(vecs: anytype) @Vector(vectorLength(@TypeOf(vecs[0])) * vecs.le
163163 // The indices are correct. The problem seems to be with the @shuffle builtin.
164164 // On MIPS, the test that interlaces small_base gives { 0, 2, 0, 0, 64, 255, 248, 200, 0, 0 }.
165165 // Calling this with two inputs seems to work fine, but I'll let the compile error trigger for all inputs, just to be safe.
166 comptime if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why interlace() doesn't work on MIPS");
166 if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why interlace() doesn't work on MIPS");
167167
168168 const VecType = @TypeOf(vecs[0]);
169169 const vecs_arr = @as([vecs.len]VecType, vecs);
......@@ -248,7 +248,7 @@ test "vector patterns" {
248248 try std.testing.expectEqual([8]u32{ 10, 20, 30, 40, 55, 66, 77, 88 }, join(base, other_base));
249249 try std.testing.expectEqual([2]u32{ 20, 30 }, extract(base, 1, 2));
250250
251 if (comptime !builtin.cpu.arch.isMIPS()) {
251 if (!builtin.cpu.arch.isMIPS()) {
252252 try std.testing.expectEqual([8]u32{ 10, 55, 20, 66, 30, 77, 40, 88 }, interlace(.{ base, other_base }));
253253
254254 const small_braid = interlace(small_bases);
......@@ -390,7 +390,7 @@ pub fn prefixScanWithFunc(
390390 comptime identity: std.meta.Child(@TypeOf(vec)),
391391) if (ErrorType == void) @TypeOf(vec) else ErrorType!@TypeOf(vec) {
392392 // I haven't debugged this, but it might be a cousin of sorts to what's going on with interlace.
393 comptime if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why prefixScan doesn't work on MIPS");
393 if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why prefixScan doesn't work on MIPS");
394394
395395 const len = vectorLength(@TypeOf(vec));
396396
......@@ -465,9 +465,7 @@ test "vector prefix scan" {
465465 if ((builtin.cpu.arch == .armeb or builtin.cpu.arch == .thumbeb) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22060
466466 if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21893
467467
468 if (comptime builtin.cpu.arch.isMIPS()) {
469 return error.SkipZigTest;
470 }
468 if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
471469
472470 const int_base = @Vector(4, i32){ 11, 23, 9, -21 };
473471 const float_base = @Vector(4, f32){ 2, 0.5, -10, 6.54321 };
lib/std/zig/system/NativePaths.zig+1-1
......@@ -83,7 +83,7 @@ pub fn detect(arena: Allocator, native_target: std.Target) !NativePaths {
8383
8484 // TODO: consider also adding homebrew paths
8585 // TODO: consider also adding macports paths
86 if (comptime builtin.target.isDarwin()) {
86 if (builtin.target.isDarwin()) {
8787 if (std.zig.system.darwin.isSdkInstalled(arena)) sdk: {
8888 const sdk = std.zig.system.darwin.getSdk(arena, native_target) orelse break :sdk;
8989 try self.addLibDir(try std.fs.path.join(arena, &.{ sdk, "usr/lib" }));
src/Liveness.zig+6-13
......@@ -719,32 +719,25 @@ pub const SwitchBrTable = struct {
719719
720720/// Caller owns the memory.
721721pub fn getSwitchBr(l: Liveness, gpa: Allocator, inst: Air.Inst.Index, cases_len: u32) Allocator.Error!SwitchBrTable {
722 var index: usize = l.special.get(inst) orelse return SwitchBrTable{
723 .deaths = &.{},
724 };
722 var index: usize = l.special.get(inst) orelse return .{ .deaths = &.{} };
725723 const else_death_count = l.extra[index];
726724 index += 1;
727725
728 var deaths = std.ArrayList([]const Air.Inst.Index).init(gpa);
729 defer deaths.deinit();
730 try deaths.ensureTotalCapacity(cases_len + 1);
726 var deaths = try gpa.alloc([]const Air.Inst.Index, cases_len);
727 errdefer gpa.free(deaths);
731728
732729 var case_i: u32 = 0;
733730 while (case_i < cases_len - 1) : (case_i += 1) {
734731 const case_death_count: u32 = l.extra[index];
735732 index += 1;
736 const case_deaths: []const Air.Inst.Index = @ptrCast(l.extra[index..][0..case_death_count]);
733 deaths[case_i] = @ptrCast(l.extra[index..][0..case_death_count]);
737734 index += case_death_count;
738 deaths.appendAssumeCapacity(case_deaths);
739735 }
740736 {
741737 // Else
742 const else_deaths: []const Air.Inst.Index = @ptrCast(l.extra[index..][0..else_death_count]);
743 deaths.appendAssumeCapacity(else_deaths);
738 deaths[case_i] = @ptrCast(l.extra[index..][0..else_death_count]);
744739 }
745 return SwitchBrTable{
746 .deaths = try deaths.toOwnedSlice(),
747 };
740 return .{ .deaths = deaths };
748741}
749742
750743/// Note that this information is technically redundant, but is useful for
src/arch/x86_64/CodeGen.zig+273-26
......@@ -61,9 +61,10 @@ src_loc: Zcu.LazySrcLoc,
6161eflags_inst: ?Air.Inst.Index = null,
6262
6363/// MIR Instructions
64mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
64mir_instructions: std.MultiArrayList(Mir.Inst) = .empty,
6565/// MIR extra data
6666mir_extra: std.ArrayListUnmanaged(u32) = .empty,
67mir_table: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty,
6768
6869/// Byte offset within the source file of the ending curly.
6970end_di_line: u32,
......@@ -75,8 +76,8 @@ end_di_column: u32,
7576exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty,
7677
7778reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
78const_tracking: ConstTrackingMap = .{},
79inst_tracking: InstTrackingMap = .{},
79const_tracking: ConstTrackingMap = .empty,
80inst_tracking: InstTrackingMap = .empty,
8081
8182// Key is the block instruction
8283blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .empty,
......@@ -86,16 +87,26 @@ register_manager: RegisterManager = .{},
8687/// Generation of the current scope, increments by 1 for every entered scope.
8788scope_generation: u32 = 0,
8889
89frame_allocs: std.MultiArrayList(FrameAlloc) = .{},
90frame_allocs: std.MultiArrayList(FrameAlloc) = .empty,
9091free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .empty,
91frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},
92frame_locs: std.MultiArrayList(Mir.FrameLoc) = .empty,
9293
9394loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
9495 /// The state to restore before branching.
9596 state: State,
9697 /// The branch target.
9798 target: Mir.Inst.Index,
98}) = .{},
99}) = .empty,
100loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
101 start: u31,
102 len: u11,
103 min: Value,
104 else_relocs: union(enum) {
105 @"unreachable",
106 forward: std.ArrayListUnmanaged(Mir.Inst.Index),
107 backward: Mir.Inst.Index,
108 },
109}) = .empty,
99110
100111next_temp_index: Temp.Index = @enumFromInt(0),
101112temp_type: [Temp.Index.max]Type = undefined,
......@@ -904,6 +915,7 @@ pub fn generate(
904915 function.free_frame_indices.deinit(gpa);
905916 function.frame_locs.deinit(gpa);
906917 function.loops.deinit(gpa);
918 function.loop_switches.deinit(gpa);
907919 var block_it = function.blocks.valueIterator();
908920 while (block_it.next()) |block| block.deinit(gpa);
909921 function.blocks.deinit(gpa);
......@@ -912,6 +924,7 @@ pub fn generate(
912924 function.exitlude_jump_relocs.deinit(gpa);
913925 function.mir_instructions.deinit(gpa);
914926 function.mir_extra.deinit(gpa);
927 function.mir_table.deinit(gpa);
915928 }
916929 try function.inst_tracking.ensureTotalCapacity(gpa, Temp.Index.max);
917930 for (0..Temp.Index.max) |temp_index| {
......@@ -978,6 +991,7 @@ pub fn generate(
978991 var mir: Mir = .{
979992 .instructions = function.mir_instructions.toOwnedSlice(),
980993 .extra = try function.mir_extra.toOwnedSlice(gpa),
994 .table = try function.mir_table.toOwnedSlice(gpa),
981995 .frame_locs = function.frame_locs.toOwnedSlice(),
982996 };
983997 defer mir.deinit(gpa);
......@@ -1012,7 +1026,6 @@ pub fn generate(
10121026 },
10131027 .prev_di_pc = 0,
10141028 };
1015 defer emit.deinit();
10161029 emit.emitMir() catch |err| switch (err) {
10171030 error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?),
10181031
......@@ -1056,6 +1069,7 @@ pub fn generateLazy(
10561069 defer {
10571070 function.mir_instructions.deinit(gpa);
10581071 function.mir_extra.deinit(gpa);
1072 function.mir_table.deinit(gpa);
10591073 }
10601074
10611075 function.genLazy(lazy_sym) catch |err| switch (err) {
......@@ -1067,6 +1081,7 @@ pub fn generateLazy(
10671081 var mir: Mir = .{
10681082 .instructions = function.mir_instructions.toOwnedSlice(),
10691083 .extra = try function.mir_extra.toOwnedSlice(gpa),
1084 .table = try function.mir_table.toOwnedSlice(gpa),
10701085 .frame_locs = function.frame_locs.toOwnedSlice(),
10711086 };
10721087 defer mir.deinit(gpa);
......@@ -1093,7 +1108,6 @@ pub fn generateLazy(
10931108 .prev_di_loc = undefined, // no debug info yet
10941109 .prev_di_pc = undefined, // no debug info yet
10951110 };
1096 defer emit.deinit();
10971111 emit.emitMir() catch |err| switch (err) {
10981112 error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?),
10991113 error.InvalidInstruction => return function.fail("failed to find a viable x86 instruction (Zig compiler bug)", .{}),
......@@ -1161,6 +1175,7 @@ fn formatWipMir(
11611175 .mir = .{
11621176 .instructions = data.self.mir_instructions.slice(),
11631177 .extra = data.self.mir_extra.items,
1178 .table = data.self.mir_table.items,
11641179 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
11651180 },
11661181 .cc = .auto,
......@@ -20748,25 +20763,195 @@ fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index
2074820763 self.getValueIfFree(tracking.short, inst);
2074920764}
2075020765
20751fn lowerSwitchBr(self: *CodeGen, inst: Air.Inst.Index, switch_br: Air.UnwrappedSwitch, condition: MCValue) !void {
20766fn lowerSwitchBr(
20767 self: *CodeGen,
20768 inst: Air.Inst.Index,
20769 switch_br: Air.UnwrappedSwitch,
20770 condition: MCValue,
20771 condition_dies: bool,
20772 is_loop: bool,
20773) !void {
2075220774 const zcu = self.pt.zcu;
2075320775 const condition_ty = self.typeOf(switch_br.operand);
20754 const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1);
20755 defer self.gpa.free(liveness.deaths);
2075620776
20757 const signedness = switch (condition_ty.zigTypeTag(zcu)) {
20758 .bool, .pointer => .unsigned,
20759 .int, .@"enum", .error_set => condition_ty.intInfo(zcu).signedness,
20760 else => unreachable,
20777 const ExpectedContents = extern struct {
20778 liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
20779 bigint_limbs: [std.math.big.int.calcTwosCompLimbCount(1 << 8)]std.math.big.Limb,
20780 relocs: [1 << 6]Mir.Inst.Index,
2076120781 };
20782 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
20783 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
20784 const allocator = stack.get();
2076220785
2076320786 self.scope_generation += 1;
2076420787 const state = try self.saveState();
2076520788
20766 var it = switch_br.iterateCases();
20767 while (it.next()) |case| {
20768 var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
20769 defer self.gpa.free(relocs);
20789 const liveness = try self.liveness.getSwitchBr(allocator, inst, switch_br.cases_len + 1);
20790 defer allocator.free(liveness.deaths);
20791
20792 if (!self.mod.pic and self.target.ofmt == .elf) table: {
20793 var prong_items: u32 = 0;
20794 var min: ?Value = null;
20795 var max: ?Value = null;
20796 {
20797 var cases_it = switch_br.iterateCases();
20798 while (cases_it.next()) |case| {
20799 prong_items += @intCast(case.items.len + case.ranges.len);
20800 for (case.items) |item| {
20801 const val = Value.fromInterned(item.toInterned().?);
20802 if (min == null or val.compareHetero(.lt, min.?, zcu)) min = val;
20803 if (max == null or val.compareHetero(.gt, max.?, zcu)) max = val;
20804 }
20805 for (case.ranges) |range| {
20806 const low = Value.fromInterned(range[0].toInterned().?);
20807 if (min == null or low.compareHetero(.lt, min.?, zcu)) min = low;
20808 const high = Value.fromInterned(range[1].toInterned().?);
20809 if (max == null or high.compareHetero(.gt, max.?, zcu)) max = high;
20810 }
20811 }
20812 }
20813 // This condition also triggers for switches with no non-else prongs and switches on bool.
20814 if (prong_items < 1 << 2 or prong_items > 1 << 8) break :table;
20815
20816 var min_space: Value.BigIntSpace = undefined;
20817 const min_bigint = min.?.toBigInt(&min_space, zcu);
20818 var max_space: Value.BigIntSpace = undefined;
20819 const max_bigint = max.?.toBigInt(&max_space, zcu);
20820 const limbs = try allocator.alloc(
20821 std.math.big.Limb,
20822 @max(min_bigint.limbs.len, max_bigint.limbs.len) + 1,
20823 );
20824 defer allocator.free(limbs);
20825 const table_len = table_len: {
20826 var table_len_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
20827 table_len_bigint.sub(max_bigint, min_bigint);
20828 assert(table_len_bigint.positive); // min <= max
20829 break :table_len @as(u11, table_len_bigint.toConst().to(u10) catch break :table) + 1; // no more than a 1024 entry table
20830 };
20831 assert(prong_items <= table_len); // each prong item introduces at least one unique integer to the range
20832 if (prong_items < table_len >> 2) break :table; // no more than 75% waste
20833
20834 const condition_index = if (condition_dies and condition.isModifiable()) condition else condition_index: {
20835 const condition_index = try self.allocTempRegOrMem(condition_ty, true);
20836 try self.genCopy(condition_ty, condition_index, condition, .{});
20837 break :condition_index condition_index;
20838 };
20839 try self.spillEflagsIfOccupied();
20840 if (min.?.orderAgainstZero(zcu).compare(.neq)) try self.genBinOpMir(
20841 .{ ._, .sub },
20842 condition_ty,
20843 condition_index,
20844 .{ .air_ref = Air.internedToRef(min.?.toIntern()) },
20845 );
20846 const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
20847 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table_len - 1 });
20848 break :else_reloc try self.asmJccReloc(.a, undefined);
20849 } else undefined;
20850 const table_start: u31 = @intCast(self.mir_table.items.len);
20851 {
20852 const condition_index_reg = if (condition_index.isRegister())
20853 condition_index.getReg().?
20854 else
20855 try self.copyToTmpRegister(.usize, condition_index);
20856 const condition_index_lock = self.register_manager.lockReg(condition_index_reg);
20857 defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock);
20858 try self.truncateRegister(condition_ty, condition_index_reg);
20859 const ptr_size = @divExact(self.target.ptrBitWidth(), 8);
20860 try self.asmMemory(.{ ._, .jmp }, .{
20861 .base = .table,
20862 .mod = .{ .rm = .{
20863 .size = .ptr,
20864 .index = registerAlias(condition_index_reg, ptr_size),
20865 .scale = .fromFactor(@intCast(ptr_size)),
20866 .disp = table_start * ptr_size,
20867 } },
20868 });
20869 }
20870 const else_reloc_marker: u32 = 0;
20871 assert(self.mir_instructions.len > else_reloc_marker);
20872 try self.mir_table.appendNTimes(self.gpa, else_reloc_marker, table_len);
20873 if (is_loop) try self.loop_switches.putNoClobber(self.gpa, inst, .{
20874 .start = table_start,
20875 .len = table_len,
20876 .min = min.?,
20877 .else_relocs = if (switch_br.else_body_len > 0) .{ .forward = .empty } else .@"unreachable",
20878 });
20879 defer if (is_loop) {
20880 var loop_switch_data = self.loop_switches.fetchRemove(inst).?.value;
20881 switch (loop_switch_data.else_relocs) {
20882 .@"unreachable", .backward => {},
20883 .forward => |*else_relocs| else_relocs.deinit(self.gpa),
20884 }
20885 };
20886 var cases_it = switch_br.iterateCases();
20887 while (cases_it.next()) |case| {
20888 {
20889 const table = self.mir_table.items[table_start..][0..table_len];
20890 for (case.items) |item| {
20891 const val = Value.fromInterned(item.toInterned().?);
20892 var val_space: Value.BigIntSpace = undefined;
20893 const val_bigint = val.toBigInt(&val_space, zcu);
20894 var index_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
20895 index_bigint.sub(val_bigint, min_bigint);
20896 table[index_bigint.toConst().to(u10) catch unreachable] = @intCast(self.mir_instructions.len);
20897 }
20898 for (case.ranges) |range| {
20899 var low_space: Value.BigIntSpace = undefined;
20900 const low_bigint = Value.fromInterned(range[0].toInterned().?).toBigInt(&low_space, zcu);
20901 var high_space: Value.BigIntSpace = undefined;
20902 const high_bigint = Value.fromInterned(range[1].toInterned().?).toBigInt(&high_space, zcu);
20903 var index_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
20904 index_bigint.sub(low_bigint, min_bigint);
20905 const start = index_bigint.toConst().to(u10) catch unreachable;
20906 index_bigint.sub(high_bigint, min_bigint);
20907 const end = @as(u11, index_bigint.toConst().to(u10) catch unreachable) + 1;
20908 @memset(table[start..end], @intCast(self.mir_instructions.len));
20909 }
20910 }
20911
20912 for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);
20913
20914 try self.genBodyBlock(case.body);
20915 try self.restoreState(state, &.{}, .{
20916 .emit_instructions = false,
20917 .update_tracking = true,
20918 .resurrect = true,
20919 .close_scope = true,
20920 });
20921 }
20922 if (switch_br.else_body_len > 0) {
20923 const else_body = cases_it.elseBody();
20924
20925 const else_deaths = liveness.deaths.len - 1;
20926 for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand);
20927
20928 self.performReloc(else_reloc);
20929 if (is_loop) {
20930 const loop_switch_data = self.loop_switches.getPtr(inst).?;
20931 for (loop_switch_data.else_relocs.forward.items) |reloc| self.performReloc(reloc);
20932 loop_switch_data.else_relocs.forward.deinit(self.gpa);
20933 loop_switch_data.else_relocs = .{ .backward = @intCast(self.mir_instructions.len) };
20934 }
20935 for (self.mir_table.items[table_start..][0..table_len]) |*entry| if (entry.* == else_reloc_marker) {
20936 entry.* = @intCast(self.mir_instructions.len);
20937 };
20938
20939 try self.genBodyBlock(else_body);
20940 try self.restoreState(state, &.{}, .{
20941 .emit_instructions = false,
20942 .update_tracking = true,
20943 .resurrect = true,
20944 .close_scope = true,
20945 });
20946 }
20947 return;
20948 }
20949
20950 const signedness = if (condition_ty.isAbiInt(zcu)) condition_ty.intInfo(zcu).signedness else .unsigned;
20951 var cases_it = switch_br.iterateCases();
20952 while (cases_it.next()) |case| {
20953 var relocs = try allocator.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
20954 defer allocator.free(relocs);
2077020955
2077120956 try self.spillEflagsIfOccupied();
2077220957 for (case.items, relocs[0..case.items.len]) |item, *reloc| {
......@@ -20849,9 +21034,8 @@ fn lowerSwitchBr(self: *CodeGen, inst: Air.Inst.Index, switch_br: Air.UnwrappedS
2084921034 // Relocate the "skip" branch to fall through to the next case.
2085021035 self.performReloc(skip_case_reloc);
2085121036 }
20852
2085321037 if (switch_br.else_body_len > 0) {
20854 const else_body = it.elseBody();
21038 const else_body = cases_it.elseBody();
2085521039
2085621040 const else_deaths = liveness.deaths.len - 1;
2085721041 for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand);
......@@ -20873,11 +21057,11 @@ fn airSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void {
2087321057 // If the condition dies here in this switch instruction, process
2087421058 // that death now instead of later as this has an effect on
2087521059 // whether it needs to be spilled in the branches
20876 if (self.liveness.operandDies(inst, 0)) {
21060 const condition_dies = self.liveness.operandDies(inst, 0);
21061 if (condition_dies) {
2087721062 if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
2087821063 }
20879
20880 try self.lowerSwitchBr(inst, switch_br, condition);
21064 try self.lowerSwitchBr(inst, switch_br, condition, condition_dies, false);
2088121065
2088221066 // We already took care of pl_op.operand earlier, so there's nothing left to do
2088321067}
......@@ -20915,7 +21099,7 @@ fn airLoopSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void {
2091521099 // Stop tracking block result without forgetting tracking info
2091621100 try self.freeValue(mat_cond);
2091721101
20918 try self.lowerSwitchBr(inst, switch_br, mat_cond);
21102 try self.lowerSwitchBr(inst, switch_br, mat_cond, true, true);
2091921103
2092021104 try self.processDeath(inst);
2092121105}
......@@ -20924,8 +21108,67 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
2092421108 const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br;
2092521109
2092621110 const block_ty = self.typeOfIndex(br.block_inst);
20927 const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
2092821111 const loop_data = self.loops.getPtr(br.block_inst).?;
21112 if (self.loop_switches.getPtr(br.block_inst)) |table| {
21113 // Process operand death so that it is properly accounted for in the State below.
21114 const condition_dies = self.liveness.operandDies(inst, 0);
21115
21116 try self.restoreState(loop_data.state, &.{}, .{
21117 .emit_instructions = true,
21118 .update_tracking = false,
21119 .resurrect = false,
21120 .close_scope = false,
21121 });
21122
21123 const condition_ty = self.typeOf(br.operand);
21124 const condition = try self.resolveInst(br.operand);
21125 const condition_index = if (condition_dies and condition.isModifiable()) condition else condition_index: {
21126 const condition_index = try self.allocTempRegOrMem(condition_ty, true);
21127 try self.genCopy(condition_ty, condition_index, condition, .{});
21128 break :condition_index condition_index;
21129 };
21130 try self.spillEflagsIfOccupied();
21131 if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(
21132 .{ ._, .sub },
21133 condition_ty,
21134 condition_index,
21135 .{ .air_ref = Air.internedToRef(table.min.toIntern()) },
21136 );
21137 switch (table.else_relocs) {
21138 .@"unreachable" => {},
21139 .forward => |*else_relocs| {
21140 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table.len - 1 });
21141 try else_relocs.append(self.gpa, try self.asmJccReloc(.a, undefined));
21142 },
21143 .backward => |else_reloc| {
21144 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table.len - 1 });
21145 _ = try self.asmJccReloc(.a, else_reloc);
21146 },
21147 }
21148 {
21149 const condition_index_reg = if (condition_index.isRegister())
21150 condition_index.getReg().?
21151 else
21152 try self.copyToTmpRegister(.usize, condition_index);
21153 const condition_index_lock = self.register_manager.lockReg(condition_index_reg);
21154 defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock);
21155 try self.truncateRegister(condition_ty, condition_index_reg);
21156 const ptr_size = @divExact(self.target.ptrBitWidth(), 8);
21157 try self.asmMemory(.{ ._, .jmp }, .{
21158 .base = .table,
21159 .mod = .{ .rm = .{
21160 .size = .ptr,
21161 .index = registerAlias(condition_index_reg, ptr_size),
21162 .scale = .fromFactor(@intCast(ptr_size)),
21163 .disp = @intCast(table.start * ptr_size),
21164 } },
21165 });
21166 }
21167
21168 return self.finishAir(inst, .none, .{ br.operand, .none, .none });
21169 }
21170
21171 const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
2092921172 done: {
2093021173 try self.getValue(block_tracking.short, null);
2093121174 const src_mcv = try self.resolveInst(br.operand);
......@@ -22543,6 +22786,7 @@ fn genSetMem(
2254322786 .none => .{ .immediate = @bitCast(@as(i64, disp)) },
2254422787 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
2254522788 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
22789 .table => unreachable,
2254622790 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
2254722791 };
2254822792 switch (src_mcv) {
......@@ -22652,6 +22896,7 @@ fn genSetMem(
2265222896 .index = frame_index,
2265322897 .off = disp,
2265422898 }).compare(.gte, src_align),
22899 .table => unreachable,
2265522900 .reloc => false,
2265622901 })).write(
2265722902 self,
......@@ -23260,6 +23505,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
2326023505 const ptr_lock = switch (ptr_mem.base) {
2326123506 .none, .frame, .reloc => null,
2326223507 .reg => |reg| self.register_manager.lockReg(reg),
23508 .table => unreachable,
2326323509 };
2326423510 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
2326523511
......@@ -23327,6 +23573,7 @@ fn atomicOp(
2332723573 const mem_lock = switch (ptr_mem.base) {
2332823574 .none, .frame, .reloc => null,
2332923575 .reg => |reg| self.register_manager.lockReg(reg),
23576 .table => unreachable,
2333023577 };
2333123578 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
2333223579
src/arch/x86_64/Emit.zig+58-34
......@@ -10,22 +10,21 @@ prev_di_loc: Loc,
1010/// Relative to the beginning of `code`.
1111prev_di_pc: usize,
1212
13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
14relocs: std.ArrayListUnmanaged(Reloc) = .empty,
15
1613pub const Error = Lower.Error || error{
1714 EmitFail,
1815} || link.File.UpdateDebugInfoError;
1916
2017pub fn emitMir(emit: *Emit) Error!void {
2118 const gpa = emit.lower.bin_file.comp.gpa;
19 const code_offset_mapping = try emit.lower.allocator.alloc(u32, emit.lower.mir.instructions.len);
20 defer emit.lower.allocator.free(code_offset_mapping);
21 var relocs: std.ArrayListUnmanaged(Reloc) = .empty;
22 defer relocs.deinit(emit.lower.allocator);
23 var table_relocs: std.ArrayListUnmanaged(TableReloc) = .empty;
24 defer table_relocs.deinit(emit.lower.allocator);
2225 for (0..emit.lower.mir.instructions.len) |mir_i| {
2326 const mir_index: Mir.Inst.Index = @intCast(mir_i);
24 try emit.code_offset_mapping.putNoClobber(
25 emit.lower.allocator,
26 mir_index,
27 @intCast(emit.code.items.len),
28 );
27 code_offset_mapping[mir_index] = @intCast(emit.code.items.len);
2928 const lowered = try emit.lower.lowerMir(mir_index);
3029 var lowered_relocs = lowered.relocs;
3130 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
......@@ -89,13 +88,17 @@ pub fn emitMir(emit: *Emit) Error!void {
8988 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
9089 lowered_relocs = lowered_relocs[1..];
9190 }) switch (lowered_relocs[0].target) {
92 .inst => |target| try emit.relocs.append(emit.lower.allocator, .{
91 .inst => |target| try relocs.append(emit.lower.allocator, .{
9392 .source = start_offset,
9493 .source_offset = end_offset - 4,
9594 .target = target,
9695 .target_offset = lowered_relocs[0].off,
9796 .length = @intCast(end_offset - start_offset),
9897 }),
98 .table => try table_relocs.append(emit.lower.allocator, .{
99 .source_offset = end_offset - 4,
100 .target_offset = lowered_relocs[0].off,
101 }),
99102 .linker_extern_fn => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
100103 // Add relocation to the decl.
101104 const zo = elf_file.zigObjectPtr().?;
......@@ -103,7 +106,7 @@ pub fn emitMir(emit: *Emit) Error!void {
103106 const r_type = @intFromEnum(std.elf.R_X86_64.PLT32);
104107 try atom_ptr.addReloc(gpa, .{
105108 .r_offset = end_offset - 4,
106 .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
109 .r_info = @as(u64, sym_index) << 32 | r_type,
107110 .r_addend = lowered_relocs[0].off - 4,
108111 }, zo);
109112 } else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
......@@ -150,7 +153,7 @@ pub fn emitMir(emit: *Emit) Error!void {
150153 const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);
151154 try atom.addReloc(gpa, .{
152155 .r_offset = end_offset - 4,
153 .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
156 .r_info = @as(u64, sym_index) << 32 | r_type,
154157 .r_addend = lowered_relocs[0].off - 4,
155158 }, zo);
156159 },
......@@ -161,7 +164,7 @@ pub fn emitMir(emit: *Emit) Error!void {
161164 const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);
162165 try atom.addReloc(gpa, .{
163166 .r_offset = end_offset - 4,
164 .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
167 .r_info = @as(u64, sym_index) << 32 | r_type,
165168 .r_addend = lowered_relocs[0].off,
166169 }, zo);
167170 },
......@@ -176,7 +179,7 @@ pub fn emitMir(emit: *Emit) Error!void {
176179 @intFromEnum(std.elf.R_X86_64.PC32);
177180 try atom.addReloc(gpa, .{
178181 .r_offset = end_offset - 4,
179 .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
182 .r_info = @as(u64, sym_index) << 32 | r_type,
180183 .r_addend = lowered_relocs[0].off - 4,
181184 }, zo);
182185 } else {
......@@ -186,7 +189,7 @@ pub fn emitMir(emit: *Emit) Error!void {
186189 @intFromEnum(std.elf.R_X86_64.@"32");
187190 try atom.addReloc(gpa, .{
188191 .r_offset = end_offset - 4,
189 .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
192 .r_info = @as(u64, sym_index) << 32 | r_type,
190193 .r_addend = lowered_relocs[0].off,
191194 }, zo);
192195 }
......@@ -412,7 +415,7 @@ pub fn emitMir(emit: *Emit) Error!void {
412415 loc_buf[0] = switch (mem.base()) {
413416 .none => .{ .constu = 0 },
414417 .reg => |reg| .{ .breg = reg.dwarfNum() },
415 .frame => unreachable,
418 .frame, .table => unreachable,
416419 .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } },
417420 };
418421 break :base &loc_buf[0];
......@@ -463,13 +466,40 @@ pub fn emitMir(emit: *Emit) Error!void {
463466 }
464467 }
465468 }
466 try emit.fixupRelocs();
467}
469 {
470 // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
471 // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
472 // possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
473 // until the entire decl is correctly emitted with all JMP/CALL instructions within range.
474 for (relocs.items) |reloc| {
475 const target = code_offset_mapping[reloc.target];
476 const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset;
477 std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little);
478 }
479 }
480 if (emit.lower.mir.table.len > 0) {
481 if (emit.lower.bin_file.cast(.elf)) |elf_file| {
482 const zo = elf_file.zigObjectPtr().?;
483 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
468484
469pub fn deinit(emit: *Emit) void {
470 emit.relocs.deinit(emit.lower.allocator);
471 emit.code_offset_mapping.deinit(emit.lower.allocator);
472 emit.* = undefined;
485 const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8);
486 var table_offset = std.mem.alignForward(u32, @intCast(emit.code.items.len), ptr_size);
487 for (table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
488 .r_offset = table_reloc.source_offset,
489 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"),
490 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
491 }, zo);
492 for (emit.lower.mir.table) |entry| {
493 try atom.addReloc(gpa, .{
494 .r_offset = table_offset,
495 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"64"),
496 .r_addend = code_offset_mapping[entry],
497 }, zo);
498 table_offset += ptr_size;
499 }
500 try emit.code.appendNTimes(gpa, 0, table_offset - emit.code.items.len);
501 } else unreachable;
502 }
473503}
474504
475505fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
......@@ -481,7 +511,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
481511
482512const Reloc = struct {
483513 /// Offset of the instruction.
484 source: usize,
514 source: u32,
485515 /// Offset of the relocation within the instruction.
486516 source_offset: u32,
487517 /// Target of the relocation.
......@@ -492,18 +522,12 @@ const Reloc = struct {
492522 length: u5,
493523};
494524
495fn fixupRelocs(emit: *Emit) Error!void {
496 // TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
497 // This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
498 // possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
499 // until the entire decl is correctly emitted with all JMP/CALL instructions within range.
500 for (emit.relocs.items) |reloc| {
501 const target = emit.code_offset_mapping.get(reloc.target) orelse
502 return emit.fail("JMP/CALL relocation target not found!", .{});
503 const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset;
504 std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little);
505 }
506}
525const TableReloc = struct {
526 /// Offset of the relocation.
527 source_offset: u32,
528 /// Offset from the start of the table.
529 target_offset: i32,
530};
507531
508532const Loc = struct {
509533 line: u32,
src/arch/x86_64/Lower.zig+12-3
......@@ -57,6 +57,7 @@ pub const Reloc = struct {
5757
5858 const Target = union(enum) {
5959 inst: Mir.Inst.Index,
60 table,
6061 linker_reloc: u32,
6162 linker_tlsld: u32,
6263 linker_dtpoff: u32,
......@@ -348,7 +349,7 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
348349 return error.LowerFail;
349350}
350351
351pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
352pub fn imm(lower: *const Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
352353 return switch (ops) {
353354 .rri_s,
354355 .ri_s,
......@@ -379,8 +380,16 @@ pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
379380 };
380381}
381382
382pub fn mem(lower: Lower, payload: u32) Memory {
383 return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
383pub fn mem(lower: *Lower, payload: u32) Memory {
384 var m = lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
385 switch (m) {
386 .sib => |*sib| switch (sib.base) {
387 else => {},
388 .table => sib.disp = lower.reloc(.table, sib.disp).signed,
389 },
390 else => {},
391 }
392 return m;
384393}
385394
386395fn reloc(lower: *Lower, target: Reloc.Target, off: i32) Immediate {
src/arch/x86_64/Mir.zig+6-3
......@@ -9,6 +9,7 @@
99instructions: std.MultiArrayList(Inst).Slice,
1010/// The meaning of this data is determined by `Inst.Tag` value.
1111extra: []const u32,
12table: []const Inst.Index,
1213frame_locs: std.MultiArrayList(FrameLoc).Slice,
1314
1415pub const Inst = struct {
......@@ -1237,7 +1238,7 @@ pub const Memory = struct {
12371238 size: bits.Memory.Size,
12381239 index: Register,
12391240 scale: bits.Memory.Scale,
1240 _: u16 = undefined,
1241 _: u15 = undefined,
12411242 };
12421243
12431244 pub fn encode(mem: bits.Memory) Memory {
......@@ -1260,7 +1261,7 @@ pub const Memory = struct {
12601261 },
12611262 },
12621263 .base = switch (mem.base) {
1263 .none => undefined,
1264 .none, .table => undefined,
12641265 .reg => |reg| @intFromEnum(reg),
12651266 .frame => |frame_index| @intFromEnum(frame_index),
12661267 .reloc => |sym_index| sym_index,
......@@ -1289,6 +1290,7 @@ pub const Memory = struct {
12891290 .none => .none,
12901291 .reg => .{ .reg = @enumFromInt(mem.base) },
12911292 .frame => .{ .frame = @enumFromInt(mem.base) },
1293 .table => .table,
12921294 .reloc => .{ .reloc = mem.base },
12931295 },
12941296 .scale_index = switch (mem.info.index) {
......@@ -1317,6 +1319,7 @@ pub const Memory = struct {
13171319pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
13181320 mir.instructions.deinit(gpa);
13191321 gpa.free(mir.extra);
1322 gpa.free(mir.table);
13201323 mir.frame_locs.deinit(gpa);
13211324 mir.* = undefined;
13221325}
......@@ -1352,7 +1355,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
13521355
13531356pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
13541357 return switch (mem.info.base) {
1355 .none, .reg, .reloc => mem,
1358 .none, .reg, .table, .reloc => mem,
13561359 .frame => if (mir.frame_locs.len > 0) .{
13571360 .info = .{
13581361 .base = .reg,
src/arch/x86_64/bits.zig+3-2
......@@ -482,17 +482,18 @@ pub const Memory = struct {
482482 base: Base = .none,
483483 mod: Mod = .{ .rm = .{} },
484484
485 pub const Base = union(enum(u2)) {
485 pub const Base = union(enum(u3)) {
486486 none,
487487 reg: Register,
488488 frame: FrameIndex,
489 table,
489490 reloc: u32,
490491
491492 pub const Tag = @typeInfo(Base).@"union".tag_type.?;
492493
493494 pub fn isExtended(self: Base) bool {
494495 return switch (self) {
495 .none, .frame, .reloc => false, // rsp, rbp, and rip are not extended
496 .none, .frame, .table, .reloc => false, // rsp, rbp, and rip are not extended
496497 .reg => |reg| reg.isExtended(),
497498 };
498499 }
src/arch/x86_64/encoder.zig+52-51
......@@ -138,7 +138,7 @@ pub const Instruction = struct {
138138 .moffs => true,
139139 .rip => false,
140140 .sib => |s| switch (s.base) {
141 .none, .frame, .reloc => false,
141 .none, .frame, .table, .reloc => false,
142142 .reg => |reg| reg.class() == .segment,
143143 },
144144 };
......@@ -161,9 +161,9 @@ pub const Instruction = struct {
161161
162162 pub fn disp(mem: Memory) Immediate {
163163 return switch (mem) {
164 .sib => |s| Immediate.s(s.disp),
165 .rip => |r| Immediate.s(r.disp),
166 .moffs => |m| Immediate.u(m.offset),
164 .sib => |s| .s(s.disp),
165 .rip => |r| .s(r.disp),
166 .moffs => |m| .u(m.offset),
167167 };
168168 }
169169
......@@ -277,6 +277,7 @@ pub const Instruction = struct {
277277 .none => any = false,
278278 .reg => |reg| try writer.print("{s}", .{@tagName(reg)}),
279279 .frame => |frame_index| try writer.print("{}", .{frame_index}),
280 .table => try writer.print("Table", .{}),
280281 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
281282 }
282283 if (mem.scaleIndex()) |si| {
......@@ -614,7 +615,7 @@ pub const Instruction = struct {
614615 switch (mem) {
615616 .moffs => unreachable,
616617 .sib => |sib| switch (sib.base) {
617 .none => {
618 .none, .table => {
618619 try encoder.modRm_SIBDisp0(operand_enc);
619620 if (mem.scaleIndex()) |si| {
620621 const scale = math.log2_int(u4, si.scale);
......@@ -1191,7 +1192,7 @@ const TestEncode = struct {
11911192 ) !void {
11921193 var stream = std.io.fixedBufferStream(&enc.buffer);
11931194 var count_writer = std.io.countingWriter(stream.writer());
1194 const inst = try Instruction.new(.none, mnemonic, ops);
1195 const inst: Instruction = try .new(.none, mnemonic, ops);
11951196 try inst.encode(count_writer.writer(), .{});
11961197 enc.index = count_writer.bytes_written;
11971198 }
......@@ -1205,9 +1206,9 @@ test "encode" {
12051206 var buf = std.ArrayList(u8).init(testing.allocator);
12061207 defer buf.deinit();
12071208
1208 const inst = try Instruction.new(.none, .mov, &.{
1209 const inst: Instruction = try .new(.none, .mov, &.{
12091210 .{ .reg = .rbx },
1210 .{ .imm = Instruction.Immediate.u(4) },
1211 .{ .imm = .u(4) },
12111212 });
12121213 try inst.encode(buf.writer(), .{});
12131214 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
......@@ -1217,47 +1218,47 @@ test "lower I encoding" {
12171218 var enc = TestEncode{};
12181219
12191220 try enc.encode(.push, &.{
1220 .{ .imm = Instruction.Immediate.u(0x10) },
1221 .{ .imm = .u(0x10) },
12211222 });
12221223 try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
12231224
12241225 try enc.encode(.push, &.{
1225 .{ .imm = Instruction.Immediate.u(0x1000) },
1226 .{ .imm = .u(0x1000) },
12261227 });
12271228 try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
12281229
12291230 try enc.encode(.push, &.{
1230 .{ .imm = Instruction.Immediate.u(0x10000000) },
1231 .{ .imm = .u(0x10000000) },
12311232 });
12321233 try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");
12331234
12341235 try enc.encode(.adc, &.{
12351236 .{ .reg = .rax },
1236 .{ .imm = Instruction.Immediate.u(0x10000000) },
1237 .{ .imm = .u(0x10000000) },
12371238 });
12381239 try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");
12391240
12401241 try enc.encode(.add, &.{
12411242 .{ .reg = .al },
1242 .{ .imm = Instruction.Immediate.u(0x10) },
1243 .{ .imm = .u(0x10) },
12431244 });
12441245 try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
12451246
12461247 try enc.encode(.add, &.{
12471248 .{ .reg = .rax },
1248 .{ .imm = Instruction.Immediate.u(0x10) },
1249 .{ .imm = .u(0x10) },
12491250 });
12501251 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
12511252
12521253 try enc.encode(.sbb, &.{
12531254 .{ .reg = .ax },
1254 .{ .imm = Instruction.Immediate.u(0x10) },
1255 .{ .imm = .u(0x10) },
12551256 });
12561257 try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
12571258
12581259 try enc.encode(.xor, &.{
12591260 .{ .reg = .al },
1260 .{ .imm = Instruction.Immediate.u(0x10) },
1261 .{ .imm = .u(0x10) },
12611262 });
12621263 try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
12631264}
......@@ -1267,43 +1268,43 @@ test "lower MI encoding" {
12671268
12681269 try enc.encode(.mov, &.{
12691270 .{ .reg = .r12 },
1270 .{ .imm = Instruction.Immediate.u(0x1000) },
1271 .{ .imm = .u(0x1000) },
12711272 });
12721273 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
12731274
12741275 try enc.encode(.mov, &.{
12751276 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) },
1276 .{ .imm = Instruction.Immediate.u(0x10) },
1277 .{ .imm = .u(0x10) },
12771278 });
12781279 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
12791280
12801281 try enc.encode(.mov, &.{
12811282 .{ .reg = .r12 },
1282 .{ .imm = Instruction.Immediate.u(0x1000) },
1283 .{ .imm = .u(0x1000) },
12831284 });
12841285 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
12851286
12861287 try enc.encode(.mov, &.{
12871288 .{ .reg = .r12 },
1288 .{ .imm = Instruction.Immediate.u(0x1000) },
1289 .{ .imm = .u(0x1000) },
12891290 });
12901291 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
12911292
12921293 try enc.encode(.mov, &.{
12931294 .{ .reg = .rax },
1294 .{ .imm = Instruction.Immediate.u(0x10) },
1295 .{ .imm = .u(0x10) },
12951296 });
12961297 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
12971298
12981299 try enc.encode(.mov, &.{
12991300 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 } }) },
1300 .{ .imm = Instruction.Immediate.u(0x10) },
1301 .{ .imm = .u(0x10) },
13011302 });
13021303 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
13031304
13041305 try enc.encode(.mov, &.{
13051306 .{ .mem = Instruction.Memory.initRip(.qword, 0x10) },
1306 .{ .imm = Instruction.Immediate.u(0x10) },
1307 .{ .imm = .u(0x10) },
13071308 });
13081309 try expectEqualHexStrings(
13091310 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
......@@ -1313,19 +1314,19 @@ test "lower MI encoding" {
13131314
13141315 try enc.encode(.mov, &.{
13151316 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
1316 .{ .imm = Instruction.Immediate.u(0x10) },
1317 .{ .imm = .u(0x10) },
13171318 });
13181319 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
13191320
13201321 try enc.encode(.mov, &.{
13211322 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
1322 .{ .imm = Instruction.Immediate.s(-16) },
1323 .{ .imm = .s(-16) },
13231324 });
13241325 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
13251326
13261327 try enc.encode(.mov, &.{
13271328 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
1328 .{ .imm = Instruction.Immediate.u(0x10) },
1329 .{ .imm = .u(0x10) },
13291330 });
13301331 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
13311332
......@@ -1335,7 +1336,7 @@ test "lower MI encoding" {
13351336 .disp = 0x10000000,
13361337 .scale_index = .{ .scale = 2, .index = .rcx },
13371338 }) },
1338 .{ .imm = Instruction.Immediate.u(0x10) },
1339 .{ .imm = .u(0x10) },
13391340 });
13401341 try expectEqualHexStrings(
13411342 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
......@@ -1345,43 +1346,43 @@ test "lower MI encoding" {
13451346
13461347 try enc.encode(.adc, &.{
13471348 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
1348 .{ .imm = Instruction.Immediate.u(0x10) },
1349 .{ .imm = .u(0x10) },
13491350 });
13501351 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
13511352
13521353 try enc.encode(.adc, &.{
13531354 .{ .mem = Instruction.Memory.initRip(.qword, 0) },
1354 .{ .imm = Instruction.Immediate.u(0x10) },
1355 .{ .imm = .u(0x10) },
13551356 });
13561357 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
13571358
13581359 try enc.encode(.adc, &.{
13591360 .{ .reg = .rax },
1360 .{ .imm = Instruction.Immediate.u(0x10) },
1361 .{ .imm = .u(0x10) },
13611362 });
13621363 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
13631364
13641365 try enc.encode(.add, &.{
13651366 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
1366 .{ .imm = Instruction.Immediate.u(0x10) },
1367 .{ .imm = .u(0x10) },
13671368 });
13681369 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
13691370
13701371 try enc.encode(.add, &.{
13711372 .{ .reg = .rax },
1372 .{ .imm = Instruction.Immediate.u(0x10) },
1373 .{ .imm = .u(0x10) },
13731374 });
13741375 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
13751376
13761377 try enc.encode(.add, &.{
13771378 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
1378 .{ .imm = Instruction.Immediate.s(-0x10) },
1379 .{ .imm = .s(-0x10) },
13791380 });
13801381 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
13811382
13821383 try enc.encode(.@"and", &.{
13831384 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1384 .{ .imm = Instruction.Immediate.u(0x10) },
1385 .{ .imm = .u(0x10) },
13851386 });
13861387 try expectEqualHexStrings(
13871388 "\x83\x24\x25\x00\x00\x00\x10\x10",
......@@ -1391,7 +1392,7 @@ test "lower MI encoding" {
13911392
13921393 try enc.encode(.@"and", &.{
13931394 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
1394 .{ .imm = Instruction.Immediate.u(0x10) },
1395 .{ .imm = .u(0x10) },
13951396 });
13961397 try expectEqualHexStrings(
13971398 "\x26\x83\x24\x25\x00\x00\x00\x10\x10",
......@@ -1401,7 +1402,7 @@ test "lower MI encoding" {
14011402
14021403 try enc.encode(.@"and", &.{
14031404 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
1404 .{ .imm = Instruction.Immediate.u(0x10) },
1405 .{ .imm = .u(0x10) },
14051406 });
14061407 try expectEqualHexStrings(
14071408 "\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
......@@ -1411,7 +1412,7 @@ test "lower MI encoding" {
14111412
14121413 try enc.encode(.sub, &.{
14131414 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
1414 .{ .imm = Instruction.Immediate.u(0x10) },
1415 .{ .imm = .u(0x10) },
14151416 });
14161417 try expectEqualHexStrings(
14171418 "\x41\x83\xAB\x00\x00\x00\x10\x10",
......@@ -1630,14 +1631,14 @@ test "lower RMI encoding" {
16301631 try enc.encode(.imul, &.{
16311632 .{ .reg = .r11 },
16321633 .{ .reg = .r12 },
1633 .{ .imm = Instruction.Immediate.s(-2) },
1634 .{ .imm = .s(-2) },
16341635 });
16351636 try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
16361637
16371638 try enc.encode(.imul, &.{
16381639 .{ .reg = .r11 },
16391640 .{ .mem = Instruction.Memory.initRip(.qword, -16) },
1640 .{ .imm = Instruction.Immediate.s(-1024) },
1641 .{ .imm = .s(-1024) },
16411642 });
16421643 try expectEqualHexStrings(
16431644 "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
......@@ -1648,7 +1649,7 @@ test "lower RMI encoding" {
16481649 try enc.encode(.imul, &.{
16491650 .{ .reg = .bx },
16501651 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1651 .{ .imm = Instruction.Immediate.s(-1024) },
1652 .{ .imm = .s(-1024) },
16521653 });
16531654 try expectEqualHexStrings(
16541655 "\x66\x69\x5D\xF0\x00\xFC",
......@@ -1659,7 +1660,7 @@ test "lower RMI encoding" {
16591660 try enc.encode(.imul, &.{
16601661 .{ .reg = .bx },
16611662 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1662 .{ .imm = Instruction.Immediate.u(1024) },
1663 .{ .imm = .u(1024) },
16631664 });
16641665 try expectEqualHexStrings(
16651666 "\x66\x69\x5D\xF0\x00\x04",
......@@ -1775,7 +1776,7 @@ test "lower M encoding" {
17751776 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
17761777
17771778 try enc.encode(.call, &.{
1778 .{ .imm = Instruction.Immediate.s(0) },
1779 .{ .imm = .s(0) },
17791780 });
17801781 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
17811782
......@@ -1834,7 +1835,7 @@ test "lower OI encoding" {
18341835
18351836 try enc.encode(.mov, &.{
18361837 .{ .reg = .rax },
1837 .{ .imm = Instruction.Immediate.u(0x1000000000000000) },
1838 .{ .imm = .u(0x1000000000000000) },
18381839 });
18391840 try expectEqualHexStrings(
18401841 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
......@@ -1844,7 +1845,7 @@ test "lower OI encoding" {
18441845
18451846 try enc.encode(.mov, &.{
18461847 .{ .reg = .r11 },
1847 .{ .imm = Instruction.Immediate.u(0x1000000000000000) },
1848 .{ .imm = .u(0x1000000000000000) },
18481849 });
18491850 try expectEqualHexStrings(
18501851 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
......@@ -1854,19 +1855,19 @@ test "lower OI encoding" {
18541855
18551856 try enc.encode(.mov, &.{
18561857 .{ .reg = .r11d },
1857 .{ .imm = Instruction.Immediate.u(0x10000000) },
1858 .{ .imm = .u(0x10000000) },
18581859 });
18591860 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");
18601861
18611862 try enc.encode(.mov, &.{
18621863 .{ .reg = .r11w },
1863 .{ .imm = Instruction.Immediate.u(0x1000) },
1864 .{ .imm = .u(0x1000) },
18641865 });
18651866 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
18661867
18671868 try enc.encode(.mov, &.{
18681869 .{ .reg = .r11b },
1869 .{ .imm = Instruction.Immediate.u(0x10) },
1870 .{ .imm = .u(0x10) },
18701871 });
18711872 try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
18721873}
......@@ -1940,7 +1941,7 @@ test "lower NP encoding" {
19401941}
19411942
19421943fn invalidInstruction(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
1943 const err = Instruction.new(.none, mnemonic, ops);
1944 const err: Instruction = .new(.none, mnemonic, ops);
19441945 try testing.expectError(error.InvalidInstruction, err);
19451946}
19461947
......@@ -1988,12 +1989,12 @@ test "invalid instruction" {
19881989 .{ .reg = .r12d },
19891990 });
19901991 try invalidInstruction(.push, &.{
1991 .{ .imm = Instruction.Immediate.u(0x1000000000000000) },
1992 .{ .imm = .u(0x1000000000000000) },
19921993 });
19931994}
19941995
19951996fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
1996 try testing.expectError(error.CannotEncode, Instruction.new(.none, mnemonic, ops));
1997 try testing.expectError(error.CannotEncode, .new(.none, mnemonic, ops));
19971998}
19981999
19992000test "cannot encode" {
......@@ -2177,7 +2178,7 @@ const Assembler = struct {
21772178
21782179 pub fn assemble(as: *Assembler, writer: anytype) !void {
21792180 while (try as.next()) |parsed_inst| {
2180 const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
2181 const inst: Instruction = try .new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
21812182 try inst.encode(writer, .{});
21822183 }
21832184 }
src/link/MachO.zig+1-1
......@@ -3548,7 +3548,7 @@ pub fn getTarget(self: MachO) std.Target {
35483548pub fn invalidateKernelCache(dir: fs.Dir, sub_path: []const u8) !void {
35493549 const tracy = trace(@src());
35503550 defer tracy.end();
3551 if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
3551 if (builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
35523552 try dir.copyFile(sub_path, dir, sub_path, .{});
35533553 }
35543554}
test/behavior/align.zig+10-10
......@@ -277,8 +277,8 @@ test "function alignment" {
277277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279279
280 // function alignment is a compile error on wasm32/wasm64
281 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
280 // function alignment is a compile error on wasm
281 if (native_arch.isWasm()) return error.SkipZigTest;
282282
283283 const S = struct {
284284 fn alignExpr() align(@sizeOf(usize) * 2) i32 {
......@@ -307,8 +307,8 @@ test "implicitly decreasing fn alignment" {
307307 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
308308 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
309309
310 // function alignment is a compile error on wasm32/wasm64
311 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
310 // function alignment is a compile error on wasm
311 if (native_arch.isWasm()) return error.SkipZigTest;
312312
313313 try testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
314314 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
......@@ -331,9 +331,9 @@ test "@alignCast functions" {
331331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
332332 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
333333
334 // function alignment is a compile error on wasm32/wasm64
335 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
336 if (native_arch == .thumb or native_arch == .thumbeb) return error.SkipZigTest;
334 // function alignment is a compile error on wasm
335 if (native_arch.isWasm()) return error.SkipZigTest;
336 if (native_arch.isThumb()) return error.SkipZigTest;
337337
338338 try expect(fnExpectsOnly1(simple4) == 0x19);
339339}
......@@ -496,9 +496,9 @@ test "align(N) on functions" {
496496 return error.SkipZigTest;
497497 }
498498
499 // function alignment is a compile error on wasm32/wasm64
500 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
501 if (native_arch == .thumb or native_arch == .thumbeb) return error.SkipZigTest;
499 // function alignment is a compile error on wasm
500 if (native_arch.isWasm()) return error.SkipZigTest;
501 if (native_arch.isThumb()) return error.SkipZigTest;
502502
503503 try expect((@intFromPtr(&overaligned_fn) & (0x1000 - 1)) == 0);
504504}
test/behavior/asm.zig+1-1
......@@ -178,7 +178,7 @@ test "rw constraint (x86_64)" {
178178}
179179
180180test "asm modifiers (AArch64)" {
181 if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest;
181 if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;
182182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
183183
184184 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
test/behavior/call.zig+1
......@@ -660,6 +660,7 @@ test "arguments pointed to on stack into tailcall" {
660660
661661 switch (builtin.cpu.arch) {
662662 .wasm32,
663 .wasm64,
663664 .mips,
664665 .mipsel,
665666 .mips64,
test/behavior/cast.zig+2-2
......@@ -124,7 +124,7 @@ test "@floatFromInt(f80)" {
124124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
125125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
126126 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
127 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
127 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
128128 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
129129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
130130
......@@ -1362,7 +1362,7 @@ test "cast f16 to wider types" {
13621362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13631363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13641364 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1365 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
1365 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
13661366 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
13671367 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13681368
test/behavior/eval.zig+1-1
......@@ -522,7 +522,7 @@ test "runtime 128 bit integer division" {
522522 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
523523 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
524524 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
525 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
525 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
526526 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
527527 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
528528
test/behavior/math.zig+4-4
......@@ -785,7 +785,7 @@ test "128-bit multiplication" {
785785 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
786786 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
787787 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
788 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
788 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
789789 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
790790
791791 {
......@@ -1374,7 +1374,7 @@ test "remainder division" {
13741374 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13751375 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13761376 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
1377 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
1377 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
13781378 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13791379
13801380 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
......@@ -1527,7 +1527,7 @@ test "@round f80" {
15271527 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15281528 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15291529 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1530 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
1530 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
15311531 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
15321532 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15331533
......@@ -1540,7 +1540,7 @@ test "@round f128" {
15401540 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15411541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15421542 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1543 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
1543 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
15441544 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
15451545 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15461546
test/behavior/maximum_minimum.zig+1-1
......@@ -122,7 +122,7 @@ test "@min/max for floats" {
122122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
123123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
124124 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
125 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
125 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
126126 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
127127 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
128128
test/behavior/muladd.zig+4-4
......@@ -58,7 +58,7 @@ test "@mulAdd f80" {
5858 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5959 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6060 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
6262 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
6363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6464
......@@ -79,7 +79,7 @@ test "@mulAdd f128" {
7979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8080 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8181 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
82 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
82 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
8383 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
8484 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8585
......@@ -189,7 +189,7 @@ test "vector f80" {
189189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
190190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
191191 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
192 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
192 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
193193 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
194194
195195 try comptime vector80();
......@@ -216,7 +216,7 @@ test "vector f128" {
216216 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
217217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
218218 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
219 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
219 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
220220 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
221221
222222 try comptime vector128();
test/behavior/saturating_arithmetic.zig+5-5
......@@ -164,10 +164,10 @@ test "saturating multiplication <= 32 bits" {
164164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
165165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166166 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
167 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
167 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
168168 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
169169
170 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) {
170 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) {
171171 // https://github.com/ziglang/zig/issues/9660
172172 return error.SkipZigTest;
173173 }
......@@ -264,10 +264,10 @@ test "saturating multiplication" {
264264 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
265265 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
266266 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
268268 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
269269
270 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) {
270 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) {
271271 // https://github.com/ziglang/zig/issues/9660
272272 return error.SkipZigTest;
273273 }
......@@ -311,7 +311,7 @@ test "saturating shift-left" {
311311 try testSatShl(i8, 127, 1, 127);
312312 try testSatShl(i8, -128, 1, -128);
313313 // TODO: remove this check once #9668 is completed
314 if (builtin.cpu.arch != .wasm32) {
314 if (!builtin.cpu.arch.isWasm()) {
315315 // skip testing ints > 64 bits on wasm due to miscompilation / wasmtime ci error
316316 try testSatShl(i128, maxInt(i128), 64, maxInt(i128));
317317 try testSatShl(u128, maxInt(u128), 64, maxInt(u128));
test/behavior/struct.zig+4-4
......@@ -418,8 +418,8 @@ test "packed struct 24bits" {
418418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419419 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
420420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
422 if (comptime builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
421 if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
422 if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
423423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
424424 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
425425
......@@ -818,7 +818,7 @@ test "non-packed struct with u128 entry in union" {
818818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
819819 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
820820 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
821 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
821 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
822822 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
823823
824824 const U = union(enum) {
......@@ -941,7 +941,7 @@ test "tuple assigned to variable" {
941941
942942test "comptime struct field" {
943943 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
944 if (comptime builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
944 if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
945945
946946 const T = struct {
947947 a: i32,
test/behavior/var_args.zig+5-5
......@@ -100,7 +100,7 @@ test "simple variadic function" {
100100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101101 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
102102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
103 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
104104 // https://github.com/ziglang/zig/issues/14096
105105 return error.SkipZigTest;
106106 }
......@@ -161,7 +161,7 @@ test "coerce reference to var arg" {
161161 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
162162 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
163163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
164 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
164 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
165165 // https://github.com/ziglang/zig/issues/14096
166166 return error.SkipZigTest;
167167 }
......@@ -194,7 +194,7 @@ test "variadic functions" {
194194 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
195195 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
196196 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
197 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
197 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
198198 // https://github.com/ziglang/zig/issues/14096
199199 return error.SkipZigTest;
200200 }
......@@ -239,7 +239,7 @@ test "copy VaList" {
239239 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
240240 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
241241 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
242 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
242 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
243243 // https://github.com/ziglang/zig/issues/14096
244244 return error.SkipZigTest;
245245 }
......@@ -273,7 +273,7 @@ test "unused VaList arg" {
273273 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
274274 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
275275 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
276 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
276 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
277277 // https://github.com/ziglang/zig/issues/14096
278278 return error.SkipZigTest;
279279 }
test/behavior/vector.zig+4-4
......@@ -101,7 +101,7 @@ test "vector float operators" {
101101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
102102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103103 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
104 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
104 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
105105 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
106106
107107 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
......@@ -754,7 +754,7 @@ test "vector reduce operation" {
754754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
755755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
756756 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
757 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
757 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
758758 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
759759 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21091
760760
......@@ -989,7 +989,7 @@ test "saturating multiplication" {
989989 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
990990
991991 // TODO: once #9660 has been solved, remove this line
992 if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
992 if (builtin.target.cpu.arch.isWasm()) return error.SkipZigTest;
993993
994994 const S = struct {
995995 fn doTheTest() !void {
......@@ -1256,7 +1256,7 @@ test "byte vector initialized in inline function" {
12561256 if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
12571257
12581258 if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and
1259 builtin.cpu.features.isEnabled(@intFromEnum(std.Target.x86.Feature.avx512f)))
1259 std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f))
12601260 {
12611261 // TODO https://github.com/ziglang/zig/issues/13279
12621262 return error.SkipZigTest;
test/behavior/wrapping_arithmetic.zig+1-1
......@@ -83,7 +83,7 @@ test "wrapping multiplication" {
8383 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8484
8585 // TODO: once #9660 has been solved, remove this line
86 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest;
86 if (builtin.cpu.arch.isWasm()) return error.SkipZigTest;
8787
8888 const S = struct {
8989 fn doTheTest() !void {