authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-08 09:15:35-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-08 09:15:35-04:00
log1de242cd732b63bbd8b24579b42b0ccfaf40e193
tree894348970d0f8a4eaf415dd147184fd7d2997318
parenta9b37ac63724a79805f00b4e6966ebb8329151a2
parentb5dedd7c00604bc687aab373a430058d9a97cdf9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17416 from jacobly0/x86_64

x86_64: implement more `f80` operations and other features

15 files changed, 1606 insertions(+), 805 deletions(-)

src/arch/x86_64/CodeGen.zig+1497-736
...@@ -32,10 +32,10 @@ const Target = std.Target;...@@ -32,10 +32,10 @@ const Target = std.Target;
32const Type = @import("../../type.zig").Type;32const Type = @import("../../type.zig").Type;
33const TypedValue = @import("../../TypedValue.zig");33const TypedValue = @import("../../TypedValue.zig");
34const Value = @import("../../value.zig").Value;34const Value = @import("../../value.zig").Value;
35const Instruction = @import("encoder.zig").Instruction;
3536
36const abi = @import("abi.zig");37const abi = @import("abi.zig");
37const bits = @import("bits.zig");38const bits = @import("bits.zig");
38const encoder = @import("encoder.zig");
39const errUnionErrorOffset = codegen.errUnionErrorOffset;39const errUnionErrorOffset = codegen.errUnionErrorOffset;
40const errUnionPayloadOffset = codegen.errUnionPayloadOffset;40const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
4141
...@@ -47,9 +47,6 @@ const RegisterManager = abi.RegisterManager;...@@ -47,9 +47,6 @@ const RegisterManager = abi.RegisterManager;
47const RegisterLock = RegisterManager.RegisterLock;47const RegisterLock = RegisterManager.RegisterLock;
48const FrameIndex = bits.FrameIndex;48const FrameIndex = bits.FrameIndex;
4949
50const gp = abi.RegisterClass.gp;
51const sse = abi.RegisterClass.sse;
52
53const InnerError = CodeGenError || error{OutOfRegisters};50const InnerError = CodeGenError || error{OutOfRegisters};
5451
55gpa: Allocator,52gpa: Allocator,
...@@ -61,6 +58,15 @@ target: *const std.Target,...@@ -61,6 +58,15 @@ target: *const std.Target,
61owner: Owner,58owner: Owner,
62err_msg: ?*ErrorMsg,59err_msg: ?*ErrorMsg,
63args: []MCValue,60args: []MCValue,
61va_info: union {
62 sysv: struct {
63 gp_count: u32,
64 fp_count: u32,
65 overflow_arg_area: FrameAddr,
66 reg_save_area: FrameAddr,
67 },
68 win64: struct {},
69},
64ret_mcv: InstTracking,70ret_mcv: InstTracking,
65fn_type: Type,71fn_type: Type,
66arg_index: u32,72arg_index: u32,
...@@ -532,8 +538,8 @@ const InstTracking = struct {...@@ -532,8 +538,8 @@ const InstTracking = struct {
532 };538 };
533 }539 }
534540
535 fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void {541 fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
536 function.freeValue(self.short);542 try function.freeValue(self.short);
537 self.reuseFrame();543 self.reuseFrame();
538 tracking_log.debug("%{d} => {} (spilled)", .{ inst, self.* });544 tracking_log.debug("%{d} => {} (spilled)", .{ inst, self.* });
539 }545 }
...@@ -618,8 +624,9 @@ const InstTracking = struct {...@@ -618,8 +624,9 @@ const InstTracking = struct {
618 }624 }
619 }625 }
620626
621 fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void {627 fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
622 function.freeValue(self.short);628 if (self.short == .dead) return;
629 try function.freeValue(self.short);
623 self.short = .{ .dead = function.scope_generation };630 self.short = .{ .dead = function.scope_generation };
624 tracking_log.debug("%{d} => {} (death)", .{ inst, self.* });631 tracking_log.debug("%{d} => {} (death)", .{ inst, self.* });
625 }632 }
...@@ -634,6 +641,40 @@ const InstTracking = struct {...@@ -634,6 +641,40 @@ const InstTracking = struct {
634 tracking_log.debug("%{d} => {} (reuse %{d})", .{ new_inst, self.*, old_inst });641 tracking_log.debug("%{d} => {} (reuse %{d})", .{ new_inst, self.*, old_inst });
635 }642 }
636643
644 fn liveOut(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void {
645 for (self.short.getRegs()) |reg| {
646 if (function.register_manager.isRegFree(reg)) {
647 tracking_log.debug("%{d} => {} (live-out)", .{ inst, self.* });
648 continue;
649 }
650
651 const index = RegisterManager.indexOfRegIntoTracked(reg).?;
652 const tracked_inst = function.register_manager.registers[index];
653 const tracking = function.getResolvedInstValue(tracked_inst);
654
655 // Disable death.
656 var found_reg = false;
657 var remaining_reg: Register = .none;
658 for (tracking.short.getRegs()) |tracked_reg| if (tracked_reg.id() == reg.id()) {
659 assert(!found_reg);
660 found_reg = true;
661 } else {
662 assert(remaining_reg == .none);
663 remaining_reg = tracked_reg;
664 };
665 assert(found_reg);
666 tracking.short = switch (remaining_reg) {
667 .none => .{ .dead = function.scope_generation },
668 else => .{ .register = remaining_reg },
669 };
670
671 // Perform side-effects of freeValue manually.
672 function.register_manager.freeReg(reg);
673
674 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, self.*, tracked_inst });
675 }
676 }
677
637 pub fn format(678 pub fn format(
638 self: InstTracking,679 self: InstTracking,
639 comptime _: []const u8,680 comptime _: []const u8,
...@@ -713,6 +754,7 @@ pub fn generate(...@@ -713,6 +754,7 @@ pub fn generate(
713 .owner = .{ .func_index = func_index },754 .owner = .{ .func_index = func_index },
714 .err_msg = null,755 .err_msg = null,
715 .args = undefined, // populated after `resolveCallingConventionValues`756 .args = undefined, // populated after `resolveCallingConventionValues`
757 .va_info = undefined, // populated after `resolveCallingConventionValues`
716 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`758 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
717 .fn_type = fn_type,759 .fn_type = fn_type,
718 .arg_index = 0,760 .arg_index = 0,
...@@ -753,6 +795,7 @@ pub fn generate(...@@ -753,6 +795,7 @@ pub fn generate(
753 );795 );
754796
755 const fn_info = mod.typeToFunc(fn_type).?;797 const fn_info = mod.typeToFunc(fn_type).?;
798 const cc = abi.resolveCallingConvention(fn_info.cc, function.target.*);
756 var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) {799 var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) {
757 error.CodegenFail => return Result{ .fail = function.err_msg.? },800 error.CodegenFail => return Result{ .fail = function.err_msg.? },
758 error.OutOfRegisters => return Result{801 error.OutOfRegisters => return Result{
...@@ -787,6 +830,16 @@ pub fn generate(...@@ -787,6 +830,16 @@ pub fn generate(
787 .alignment = call_info.stack_align,830 .alignment = call_info.stack_align,
788 }),831 }),
789 );832 );
833 function.va_info = switch (cc) {
834 .SysV => .{ .sysv = .{
835 .gp_count = call_info.gp_count,
836 .fp_count = call_info.fp_count,
837 .overflow_arg_area = .{ .index = .args_frame, .off = call_info.stack_byte_count },
838 .reg_save_area = undefined,
839 } },
840 .Win64 => .{ .win64 = .{} },
841 else => undefined,
842 };
790843
791 function.gen() catch |err| switch (err) {844 function.gen() catch |err| switch (err) {
792 error.CodegenFail => return Result{ .fail = function.err_msg.? },845 error.CodegenFail => return Result{ .fail = function.err_msg.? },
...@@ -807,7 +860,7 @@ pub fn generate(...@@ -807,7 +860,7 @@ pub fn generate(
807 .lower = .{860 .lower = .{
808 .allocator = bin_file.allocator,861 .allocator = bin_file.allocator,
809 .mir = mir,862 .mir = mir,
810 .cc = abi.resolveCallingConvention(fn_info.cc, function.target.*),863 .cc = cc,
811 .src_loc = src_loc,864 .src_loc = src_loc,
812 },865 },
813 .bin_file = bin_file,866 .bin_file = bin_file,
...@@ -862,6 +915,7 @@ pub fn generateLazy(...@@ -862,6 +915,7 @@ pub fn generateLazy(
862 .owner = .{ .lazy_sym = lazy_sym },915 .owner = .{ .lazy_sym = lazy_sym },
863 .err_msg = null,916 .err_msg = null,
864 .args = undefined,917 .args = undefined,
918 .va_info = undefined,
865 .ret_mcv = undefined,919 .ret_mcv = undefined,
866 .fn_type = undefined,920 .fn_type = undefined,
867 .arg_index = undefined,921 .arg_index = undefined,
...@@ -980,7 +1034,6 @@ fn formatWipMir(...@@ -980,7 +1034,6 @@ fn formatWipMir(
980 _: std.fmt.FormatOptions,1034 _: std.fmt.FormatOptions,
981 writer: anytype,1035 writer: anytype,
982) @TypeOf(writer).Error!void {1036) @TypeOf(writer).Error!void {
983 const mod = data.self.bin_file.options.module.?;
984 var lower = Lower{1037 var lower = Lower{
985 .allocator = data.self.gpa,1038 .allocator = data.self.gpa,
986 .mir = .{1039 .mir = .{
...@@ -988,7 +1041,7 @@ fn formatWipMir(...@@ -988,7 +1041,7 @@ fn formatWipMir(
988 .extra = data.self.mir_extra.items,1041 .extra = data.self.mir_extra.items,
989 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),1042 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
990 },1043 },
991 .cc = mod.typeToFunc(data.self.fn_type).?.cc,1044 .cc = .Unspecified,
992 .src_loc = data.self.src_loc,1045 .src_loc = data.self.src_loc,
993 };1046 };
994 for ((lower.lowerMir(data.inst) catch |err| switch (err) {1047 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
...@@ -1144,7 +1197,7 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {...@@ -1144,7 +1197,7 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
1144 } },1197 } },
1145 .z_and_np, .nz_or_p => .{ .rr = .{1198 .z_and_np, .nz_or_p => .{ .rr = .{
1146 .r1 = reg,1199 .r1 = reg,
1147 .r2 = (try self.register_manager.allocReg(null, gp)).to8(),1200 .r2 = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to8(),
1148 } },1201 } },
1149 },1202 },
1150 });1203 });
...@@ -1184,7 +1237,7 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {...@@ -1184,7 +1237,7 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
1184 .payload = payload,1237 .payload = payload,
1185 } },1238 } },
1186 .z_and_np, .nz_or_p => .{ .rx = .{1239 .z_and_np, .nz_or_p => .{ .rx = .{
1187 .r1 = (try self.register_manager.allocReg(null, gp)).to8(),1240 .r1 = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to8(),
1188 .payload = payload,1241 .payload = payload,
1189 } },1242 } },
1190 },1243 },
...@@ -1222,6 +1275,17 @@ fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Ins...@@ -1222,6 +1275,17 @@ fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Ins
1222 });1275 });
1223}1276}
12241277
1278fn asmReloc(self: *Self, tag: Mir.Inst.FixedTag, target: Mir.Inst.Index) !void {
1279 _ = try self.addInst(.{
1280 .tag = tag[1],
1281 .ops = .inst,
1282 .data = .{ .inst = .{
1283 .fixes = tag[0],
1284 .inst = target,
1285 } },
1286 });
1287}
1288
1225fn asmPlaceholder(self: *Self) !Mir.Inst.Index {1289fn asmPlaceholder(self: *Self) !Mir.Inst.Index {
1226 return self.addInst(.{1290 return self.addInst(.{
1227 .tag = .pseudo,1291 .tag = .pseudo,
...@@ -1629,7 +1693,8 @@ fn asmMemoryRegisterImmediate(...@@ -1629,7 +1693,8 @@ fn asmMemoryRegisterImmediate(
16291693
1630fn gen(self: *Self) InnerError!void {1694fn gen(self: *Self) InnerError!void {
1631 const mod = self.bin_file.options.module.?;1695 const mod = self.bin_file.options.module.?;
1632 const cc = self.fn_type.fnCallingConvention(mod);1696 const fn_info = mod.typeToFunc(self.fn_type).?;
1697 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
1633 if (cc != .Naked) {1698 if (cc != .Naked) {
1634 try self.asmRegister(.{ ._, .push }, .rbp);1699 try self.asmRegister(.{ ._, .push }, .rbp);
1635 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();1700 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
...@@ -1659,6 +1724,42 @@ fn gen(self: *Self) InnerError!void {...@@ -1659,6 +1724,42 @@ fn gen(self: *Self) InnerError!void {
1659 else => unreachable,1724 else => unreachable,
1660 }1725 }
16611726
1727 if (fn_info.is_var_args) switch (cc) {
1728 .SysV => {
1729 const info = &self.va_info.sysv;
1730 const reg_save_area_fi = try self.allocFrameIndex(FrameAlloc.init(.{
1731 .size = abi.SysV.c_abi_int_param_regs.len * 8 +
1732 abi.SysV.c_abi_sse_param_regs.len * 16,
1733 .alignment = .@"16",
1734 }));
1735 info.reg_save_area = .{ .index = reg_save_area_fi };
1736
1737 for (abi.SysV.c_abi_int_param_regs[info.gp_count..], info.gp_count..) |reg, reg_i|
1738 try self.genSetMem(
1739 .{ .frame = reg_save_area_fi },
1740 @intCast(reg_i * 8),
1741 Type.usize,
1742 .{ .register = reg },
1743 );
1744
1745 try self.asmRegisterImmediate(.{ ._, .cmp }, .al, Immediate.u(info.fp_count));
1746 const skip_sse_reloc = try self.asmJccReloc(undefined, .na);
1747
1748 const vec_2_f64 = try mod.vectorType(.{ .len = 2, .child = .f64_type });
1749 for (abi.SysV.c_abi_sse_param_regs[info.fp_count..], info.fp_count..) |reg, reg_i|
1750 try self.genSetMem(
1751 .{ .frame = reg_save_area_fi },
1752 @intCast(abi.SysV.c_abi_int_param_regs.len * 8 + reg_i * 16),
1753 vec_2_f64,
1754 .{ .register = reg },
1755 );
1756
1757 try self.performReloc(skip_sse_reloc);
1758 },
1759 .Win64 => return self.fail("TODO implement gen var arg function for Win64", .{}),
1760 else => unreachable,
1761 };
1762
1662 try self.asmPseudo(.pseudo_dbg_prologue_end_none);1763 try self.asmPseudo(.pseudo_dbg_prologue_end_none);
16631764
1664 try self.genBody(self.air.getMainBody());1765 try self.genBody(self.air.getMainBody());
...@@ -2033,10 +2134,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -2033,10 +2134,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
2033 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),2134 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
2034 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),2135 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
20352136
2036 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),2137 .c_va_arg => try self.airVaArg(inst),
2037 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),2138 .c_va_copy => try self.airVaCopy(inst),
2038 .c_va_end => return self.fail("TODO implement c_va_end", .{}),2139 .c_va_end => try self.airVaEnd(inst),
2039 .c_va_start => return self.fail("TODO implement c_va_start", .{}),2140 .c_va_start => try self.airVaStart(inst),
20402141
2041 .wasm_memory_size => unreachable,2142 .wasm_memory_size => unreachable,
2042 .wasm_memory_grow => unreachable,2143 .wasm_memory_grow => unreachable,
...@@ -2074,7 +2175,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -2074,7 +2175,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2074 switch (lazy_sym.ty.zigTypeTag(mod)) {2175 switch (lazy_sym.ty.zigTypeTag(mod)) {
2075 .Enum => {2176 .Enum => {
2076 const enum_ty = lazy_sym.ty;2177 const enum_ty = lazy_sym.ty;
2077 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)});2178 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(mod)});
20782179
2079 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);2180 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);
2080 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);2181 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);
...@@ -2084,10 +2185,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -2084,10 +2185,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2084 const ret_reg = param_regs[0];2185 const ret_reg = param_regs[0];
2085 const enum_mcv = MCValue{ .register = param_regs[1] };2186 const enum_mcv = MCValue{ .register = param_regs[1] };
20862187
2087 var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount(mod));2188 var exitlude_jump_relocs = try self.gpa.alloc(Mir.Inst.Index, enum_ty.enumFieldCount(mod));
2088 defer self.gpa.free(exitlude_jump_relocs);2189 defer self.gpa.free(exitlude_jump_relocs);
20892190
2090 const data_reg = try self.register_manager.allocReg(null, gp);2191 const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
2091 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);2192 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
2092 defer self.register_manager.unlockReg(data_lock);2193 defer self.register_manager.unlockReg(data_lock);
2093 try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });2194 try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
...@@ -2122,7 +2223,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -2122,7 +2223,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2122 },2223 },
2123 else => return self.fail(2224 else => return self.fail(
2124 "TODO implement {s} for {}",2225 "TODO implement {s} for {}",
2125 .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(self.bin_file.options.module.?) },2226 .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod) },
2126 ),2227 ),
2127 }2228 }
2128}2229}
...@@ -2132,9 +2233,12 @@ fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {...@@ -2132,9 +2233,12 @@ fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
2132 self.register_manager.getRegAssumeFree(reg, inst);2233 self.register_manager.getRegAssumeFree(reg, inst);
2133}2234}
21342235
2135fn freeValue(self: *Self, value: MCValue) void {2236fn freeValue(self: *Self, value: MCValue) !void {
2136 switch (value) {2237 switch (value) {
2137 .register => |reg| self.register_manager.freeReg(reg),2238 .register => |reg| {
2239 if (reg.class() == .x87) try self.asmRegister(.{ .f_, .free }, reg);
2240 self.register_manager.freeReg(reg);
2241 },
2138 .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg),2242 .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg),
2139 .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg),2243 .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg),
2140 .register_overflow => |reg_ov| {2244 .register_overflow => |reg_ov| {
...@@ -2146,13 +2250,13 @@ fn freeValue(self: *Self, value: MCValue) void {...@@ -2146,13 +2250,13 @@ fn freeValue(self: *Self, value: MCValue) void {
2146 }2250 }
2147}2251}
21482252
2149fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void {2253fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void {
2150 if (bt.feed()) if (Air.refToIndex(operand)) |inst| self.processDeath(inst);2254 if (bt.feed()) if (Air.refToIndex(operand)) |inst| try self.processDeath(inst);
2151}2255}
21522256
2153/// Asserts there is already capacity to insert into top branch inst_table.2257/// Asserts there is already capacity to insert into top branch inst_table.
2154fn processDeath(self: *Self, inst: Air.Inst.Index) void {2258fn processDeath(self: *Self, inst: Air.Inst.Index) !void {
2155 self.inst_tracking.getPtr(inst).?.die(self, inst);2259 try self.inst_tracking.getPtr(inst).?.die(self, inst);
2156}2260}
21572261
2158/// Called when there are no operands, and the instruction is always unreferenced.2262/// Called when there are no operands, and the instruction is always unreferenced.
...@@ -2177,13 +2281,18 @@ fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {...@@ -2177,13 +2281,18 @@ fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {
2177 self.finishAirBookkeeping();2281 self.finishAirBookkeeping();
2178}2282}
21792283
2180fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {2284fn finishAir(
2285 self: *Self,
2286 inst: Air.Inst.Index,
2287 result: MCValue,
2288 operands: [Liveness.bpi - 1]Air.Inst.Ref,
2289) !void {
2181 var tomb_bits = self.liveness.getTombBits(inst);2290 var tomb_bits = self.liveness.getTombBits(inst);
2182 for (operands) |op| {2291 for (operands) |op| {
2183 const dies = @as(u1, @truncate(tomb_bits)) != 0;2292 const dies = @as(u1, @truncate(tomb_bits)) != 0;
2184 tomb_bits >>= 1;2293 tomb_bits >>= 1;
2185 if (!dies) continue;2294 if (!dies) continue;
2186 self.processDeath(Air.refToIndexAllowNone(op) orelse continue);2295 try self.processDeath(Air.refToIndexAllowNone(op) orelse continue);
2187 }2296 }
2188 self.finishAirResult(inst, result);2297 self.finishAirResult(inst, result);
2189}2298}
...@@ -2349,7 +2458,7 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b...@@ -2349,7 +2458,7 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b
2349 },2458 },
2350 else => 8,2459 else => 8,
2351 })) {2460 })) {
2352 if (self.register_manager.tryAllocReg(inst, regClassForType(ty, mod))) |reg| {2461 if (self.register_manager.tryAllocReg(inst, self.regClassForType(ty))) |reg| {
2353 return MCValue{ .register = registerAlias(reg, abi_size) };2462 return MCValue{ .register = registerAlias(reg, abi_size) };
2354 }2463 }
2355 }2464 }
...@@ -2359,10 +2468,15 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b...@@ -2359,10 +2468,15 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b
2359 return .{ .load_frame = .{ .index = frame_index } };2468 return .{ .load_frame = .{ .index = frame_index } };
2360}2469}
23612470
2362fn regClassForType(ty: Type, mod: *Module) RegisterManager.RegisterBitSet {2471fn regClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet {
2472 const mod = self.bin_file.options.module.?;
2363 return switch (ty.zigTypeTag(mod)) {2473 return switch (ty.zigTypeTag(mod)) {
2364 .Float, .Vector => sse,2474 .Float => switch (ty.floatBits(self.target.*)) {
2365 else => gp,2475 80 => abi.RegisterClass.x87,
2476 else => abi.RegisterClass.sse,
2477 },
2478 .Vector => abi.RegisterClass.sse,
2479 else => abi.RegisterClass.gp,
2366 };2480 };
2367}2481}
23682482
...@@ -2409,7 +2523,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2409,7 +2523,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2409 for (2523 for (
2410 self.inst_tracking.keys()[state.inst_tracking_len..],2524 self.inst_tracking.keys()[state.inst_tracking_len..],
2411 self.inst_tracking.values()[state.inst_tracking_len..],2525 self.inst_tracking.values()[state.inst_tracking_len..],
2412 ) |inst, *tracking| tracking.die(self, inst);2526 ) |inst, *tracking| try tracking.die(self, inst);
2413 self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);2527 self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);
2414 }2528 }
24152529
...@@ -2417,7 +2531,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2417,7 +2531,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2417 self.inst_tracking.keys()[0..state.inst_tracking_len],2531 self.inst_tracking.keys()[0..state.inst_tracking_len],
2418 self.inst_tracking.values()[0..state.inst_tracking_len],2532 self.inst_tracking.values()[0..state.inst_tracking_len],
2419 ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation);2533 ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation);
2420 for (deaths) |death| self.processDeath(death);2534 for (deaths) |death| try self.processDeath(death);
24212535
2422 for (0..state.registers.len) |index| {2536 for (0..state.registers.len) |index| {
2423 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))2537 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))
...@@ -2444,7 +2558,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2444,7 +2558,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2444 }2558 }
2445 if (opts.update_tracking) {2559 if (opts.update_tracking) {
2446 if (current_maybe_inst) |current_inst| {2560 if (current_maybe_inst) |current_inst| {
2447 self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst);2561 try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst);
2448 }2562 }
2449 {2563 {
2450 const reg = RegisterManager.regAtTrackedIndex(@intCast(index));2564 const reg = RegisterManager.regAtTrackedIndex(@intCast(index));
...@@ -2463,7 +2577,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2463,7 +2577,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2463 try self.inst_tracking.getPtr(inst).?.spill(self, inst);2577 try self.inst_tracking.getPtr(inst).?.spill(self, inst);
2464 if (opts.update_tracking) if (self.eflags_inst) |inst| {2578 if (opts.update_tracking) if (self.eflags_inst) |inst| {
2465 self.eflags_inst = null;2579 self.eflags_inst = null;
2466 self.inst_tracking.getPtr(inst).?.trackSpill(self, inst);2580 try self.inst_tracking.getPtr(inst).?.trackSpill(self, inst);
2467 };2581 };
24682582
2469 if (opts.update_tracking and std.debug.runtime_safety) {2583 if (opts.update_tracking and std.debug.runtime_safety) {
...@@ -2481,7 +2595,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -2481,7 +2595,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
2481 if (tracked_reg.id() == reg.id()) break;2595 if (tracked_reg.id() == reg.id()) break;
2482 } else unreachable; // spilled reg not tracked with spilled instruciton2596 } else unreachable; // spilled reg not tracked with spilled instruciton
2483 try tracking.spill(self, inst);2597 try tracking.spill(self, inst);
2484 tracking.trackSpill(self, inst);2598 try tracking.trackSpill(self, inst);
2485}2599}
24862600
2487pub fn spillEflagsIfOccupied(self: *Self) !void {2601pub fn spillEflagsIfOccupied(self: *Self) !void {
...@@ -2490,7 +2604,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {...@@ -2490,7 +2604,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
2490 const tracking = self.inst_tracking.getPtr(inst).?;2604 const tracking = self.inst_tracking.getPtr(inst).?;
2491 assert(tracking.getCondition() != null);2605 assert(tracking.getCondition() != null);
2492 try tracking.spill(self, inst);2606 try tracking.spill(self, inst);
2493 tracking.trackSpill(self, inst);2607 try tracking.trackSpill(self, inst);
2494 }2608 }
2495}2609}
24962610
...@@ -2502,8 +2616,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void {...@@ -2502,8 +2616,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void {
2502/// allocated. A second call to `copyToTmpRegister` may return the same register.2616/// allocated. A second call to `copyToTmpRegister` may return the same register.
2503/// This can have a side effect of spilling instructions to the stack to free up a register.2617/// This can have a side effect of spilling instructions to the stack to free up a register.
2504fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {2618fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
2505 const mod = self.bin_file.options.module.?;2619 const reg = try self.register_manager.allocReg(null, self.regClassForType(ty));
2506 const reg = try self.register_manager.allocReg(null, regClassForType(ty, mod));
2507 try self.genSetReg(reg, ty, mcv);2620 try self.genSetReg(reg, ty, mcv);
2508 return reg;2621 return reg;
2509}2622}
...@@ -2518,8 +2631,7 @@ fn copyToRegisterWithInstTracking(...@@ -2518,8 +2631,7 @@ fn copyToRegisterWithInstTracking(
2518 ty: Type,2631 ty: Type,
2519 mcv: MCValue,2632 mcv: MCValue,
2520) !MCValue {2633) !MCValue {
2521 const mod = self.bin_file.options.module.?;2634 const reg: Register = try self.register_manager.allocReg(reg_owner, self.regClassForType(ty));
2522 const reg: Register = try self.register_manager.allocReg(reg_owner, regClassForType(ty, mod));
2523 try self.genSetReg(reg, ty, mcv);2635 try self.genSetReg(reg, ty, mcv);
2524 return MCValue{ .register = reg };2636 return MCValue{ .register = reg };
2525}2637}
...@@ -2568,7 +2680,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -2568,7 +2680,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
2568 80, 128 => true,2680 80, 128 => true,
2569 else => unreachable,2681 else => unreachable,
2570 },2682 },
2571 80 => switch (dst_bits) {2683 80 => switch (src_bits) {
2572 128 => true,2684 128 => true,
2573 else => unreachable,2685 else => unreachable,
2574 },2686 },
...@@ -2872,9 +2984,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -2872,9 +2984,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
2872 else => null,2984 else => null,
2873 },2985 },
2874 else => null,2986 else => null,
2875 }) orelse return self.fail("TODO implement airTrunc for {}", .{2987 }) orelse return self.fail("TODO implement airTrunc for {}", .{dst_ty.fmt(mod)});
2876 dst_ty.fmt(self.bin_file.options.module.?),
2877 });
28782988
2879 const elem_ty = src_ty.childType(mod);2989 const elem_ty = src_ty.childType(mod);
2880 const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits));2990 const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits));
...@@ -3076,7 +3186,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3076,7 +3186,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
3076 };3186 };
3077 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);3187 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
30783188
3079 const limit_reg = try self.register_manager.allocReg(null, gp);3189 const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
3080 const limit_mcv = MCValue{ .register = limit_reg };3190 const limit_mcv = MCValue{ .register = limit_reg };
3081 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);3191 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
3082 defer self.register_manager.unlockReg(limit_lock);3192 defer self.register_manager.unlockReg(limit_lock);
...@@ -3159,7 +3269,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3159,7 +3269,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
3159 };3269 };
3160 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);3270 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
31613271
3162 const limit_reg = try self.register_manager.allocReg(null, gp);3272 const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
3163 const limit_mcv = MCValue{ .register = limit_reg };3273 const limit_mcv = MCValue{ .register = limit_reg };
3164 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);3274 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
3165 defer self.register_manager.unlockReg(limit_lock);3275 defer self.register_manager.unlockReg(limit_lock);
...@@ -3237,7 +3347,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3237,7 +3347,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
3237 };3347 };
3238 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);3348 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
32393349
3240 const limit_reg = try self.register_manager.allocReg(null, gp);3350 const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
3241 const limit_mcv = MCValue{ .register = limit_reg };3351 const limit_mcv = MCValue{ .register = limit_reg };
3242 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);3352 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
3243 defer self.register_manager.unlockReg(limit_lock);3353 defer self.register_manager.unlockReg(limit_lock);
...@@ -3425,7 +3535,8 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -3425,7 +3535,8 @@ fn genSetFrameTruncatedOverflowCompare(
34253535
3426 const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_limb_bits);3536 const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_limb_bits);
34273537
3428 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);3538 const temp_regs =
3539 try self.register_manager.allocRegs(3, .{ null, null, null }, abi.RegisterClass.gp);
3429 const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);3540 const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
3430 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);3541 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
34313542
...@@ -3843,7 +3954,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3843,7 +3954,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
3843 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);3954 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
3844 defer self.register_manager.unlockReg(src_lock);3955 defer self.register_manager.unlockReg(src_lock);
38453956
3846 const dst_reg = try self.register_manager.allocReg(inst, gp);3957 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
3847 const dst_mcv = MCValue{ .register = dst_reg };3958 const dst_mcv = MCValue{ .register = dst_reg };
3848 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);3959 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
3849 defer self.register_manager.unlockReg(dst_lock);3960 defer self.register_manager.unlockReg(dst_lock);
...@@ -3883,7 +3994,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3883,7 +3994,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
3883 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))3994 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
3884 src_reg3995 src_reg
3885 else3996 else
3886 try self.register_manager.allocReg(inst, gp);3997 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
3887 const dst_mcv = MCValue{ .register = dst_reg };3998 const dst_mcv = MCValue{ .register = dst_reg };
3888 const dst_lock = self.register_manager.lockReg(dst_reg);3999 const dst_lock = self.register_manager.lockReg(dst_reg);
3889 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);4000 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -3934,7 +4045,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -3934,7 +4045,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
3934 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))4045 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
3935 src_reg4046 src_reg
3936 else4047 else
3937 try self.register_manager.allocReg(inst, gp);4048 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
3938 const dst_lock = self.register_manager.lockReg(dst_reg);4049 const dst_lock = self.register_manager.lockReg(dst_reg);
3939 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);4050 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
39404051
...@@ -4107,7 +4218,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4107,7 +4218,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
4107 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))4218 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
4108 src_reg4219 src_reg
4109 else4220 else
4110 try self.register_manager.allocReg(inst, gp);4221 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
4111 const dst_mcv = MCValue{ .register = dst_reg };4222 const dst_mcv = MCValue{ .register = dst_reg };
4112 const dst_lock = self.register_manager.lockReg(dst_reg);4223 const dst_lock = self.register_manager.lockReg(dst_reg);
4113 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);4224 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -4144,7 +4255,7 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi...@@ -4144,7 +4255,7 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi
4144 .immediate => |imm| {4255 .immediate => |imm| {
4145 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`4256 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`
4146 // and set the register directly to the scaled offset as an immediate.4257 // and set the register directly to the scaled offset as an immediate.
4147 const reg = try self.register_manager.allocReg(null, gp);4258 const reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4148 try self.genSetReg(reg, index_ty, .{ .immediate = imm * elem_size });4259 try self.genSetReg(reg, index_ty, .{ .immediate = imm * elem_size });
4149 break :blk reg;4260 break :blk reg;
4150 },4261 },
...@@ -4184,7 +4295,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -4184,7 +4295,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
4184 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);4295 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
4185 defer self.register_manager.unlockReg(offset_reg_lock);4296 defer self.register_manager.unlockReg(offset_reg_lock);
41864297
4187 const addr_reg = try self.register_manager.allocReg(null, gp);4298 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4188 try self.genSetReg(addr_reg, Type.usize, slice_mcv);4299 try self.genSetReg(addr_reg, Type.usize, slice_mcv);
4189 // TODO we could allocate register here, but need to expect addr register and potentially4300 // TODO we could allocate register here, but need to expect addr register and potentially
4190 // offset register.4301 // offset register.
...@@ -4241,7 +4352,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4241,7 +4352,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
4241 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);4352 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
4242 defer self.register_manager.unlockReg(offset_reg_lock);4353 defer self.register_manager.unlockReg(offset_reg_lock);
42434354
4244 const addr_reg = try self.register_manager.allocReg(null, gp);4355 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4245 switch (array) {4356 switch (array) {
4246 .register => {4357 .register => {
4247 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, mod));4358 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, mod));
...@@ -4478,7 +4589,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4478,7 +4589,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
4478 };4589 };
4479 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);4590 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
44804591
4481 const dst_reg = try self.register_manager.allocReg(inst, gp);4592 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
4482 const dst_mcv = MCValue{ .register = dst_reg };4593 const dst_mcv = MCValue{ .register = dst_reg };
4483 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);4594 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
4484 defer self.register_manager.unlockReg(dst_lock);4595 defer self.register_manager.unlockReg(dst_lock);
...@@ -4502,7 +4613,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4502,7 +4613,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
4502 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });4613 try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });
4503 }4614 }
4504 } else if (src_bits <= 128) {4615 } else if (src_bits <= 128) {
4505 const tmp_reg = try self.register_manager.allocReg(null, gp);4616 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4506 const tmp_mcv = MCValue{ .register = tmp_reg };4617 const tmp_mcv = MCValue{ .register = tmp_reg };
4507 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);4618 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
4508 defer self.register_manager.unlockReg(tmp_lock);4619 defer self.register_manager.unlockReg(tmp_lock);
...@@ -4525,7 +4636,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4525,7 +4636,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
4525 .{ .immediate = 128 - src_bits },4636 .{ .immediate = 128 - src_bits },
4526 );4637 );
4527 }4638 }
4528 } else return self.fail("TODO airClz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});4639 } else return self.fail("TODO airClz of {}", .{src_ty.fmt(mod)});
4529 break :result dst_mcv;4640 break :result dst_mcv;
4530 }4641 }
45314642
...@@ -4608,7 +4719,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4608,7 +4719,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
4608 };4719 };
4609 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);4720 defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
46104721
4611 const dst_reg = try self.register_manager.allocReg(inst, gp);4722 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
4612 const dst_mcv = MCValue{ .register = dst_reg };4723 const dst_mcv = MCValue{ .register = dst_reg };
4613 const dst_lock = self.register_manager.lockReg(dst_reg);4724 const dst_lock = self.register_manager.lockReg(dst_reg);
4614 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);4725 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -4635,7 +4746,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4635,7 +4746,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
4635 } else mat_src_mcv;4746 } else mat_src_mcv;
4636 try self.genBinOpMir(.{ ._, .tzcnt }, wide_ty, dst_mcv, masked_mcv);4747 try self.genBinOpMir(.{ ._, .tzcnt }, wide_ty, dst_mcv, masked_mcv);
4637 } else if (src_bits <= 128) {4748 } else if (src_bits <= 128) {
4638 const tmp_reg = try self.register_manager.allocReg(null, gp);4749 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4639 const tmp_mcv = MCValue{ .register = tmp_reg };4750 const tmp_mcv = MCValue{ .register = tmp_reg };
4640 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);4751 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
4641 defer self.register_manager.unlockReg(tmp_lock);4752 defer self.register_manager.unlockReg(tmp_lock);
...@@ -4654,12 +4765,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -4654,12 +4765,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
4654 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });4765 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });
4655 try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, mat_src_mcv);4766 try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, mat_src_mcv);
4656 try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc);4767 try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc);
4657 } else return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});4768 } else return self.fail("TODO airCtz of {}", .{src_ty.fmt(mod)});
4658 break :result dst_mcv;4769 break :result dst_mcv;
4659 }4770 }
46604771
4661 if (src_bits > 64)4772 if (src_bits > 64) return self.fail("TODO airCtz of {}", .{src_ty.fmt(mod)});
4662 return self.fail("TODO airCtz of {}", .{src_ty.fmt(self.bin_file.options.module.?)});
46634773
4664 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });4774 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
4665 const width_lock = self.register_manager.lockRegAssumeUnused(width_reg);4775 const width_lock = self.register_manager.lockRegAssumeUnused(width_reg);
...@@ -4710,7 +4820,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -4710,7 +4820,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
4710 if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))4820 if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
4711 src_mcv4821 src_mcv
4712 else4822 else
4713 .{ .register = try self.register_manager.allocReg(inst, gp) };4823 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.gp) };
47144824
4715 const popcnt_ty = if (src_abi_size > 1) src_ty else Type.u16;4825 const popcnt_ty = if (src_abi_size > 1) src_ty else Type.u16;
4716 try self.genBinOpMir(.{ ._, .popcnt }, popcnt_ty, dst_mcv, mat_src_mcv);4826 try self.genBinOpMir(.{ ._, .popcnt }, popcnt_ty, dst_mcv, mat_src_mcv);
...@@ -4731,7 +4841,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -4731,7 +4841,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
4731 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);4841 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
4732 defer self.register_manager.unlockReg(dst_lock);4842 defer self.register_manager.unlockReg(dst_lock);
47334843
4734 const tmp_reg = try self.register_manager.allocReg(null, gp);4844 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4735 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);4845 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
4736 defer self.register_manager.unlockReg(tmp_lock);4846 defer self.register_manager.unlockReg(tmp_lock);
47374847
...@@ -4739,7 +4849,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -4739,7 +4849,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
4739 const dst = registerAlias(dst_reg, src_abi_size);4849 const dst = registerAlias(dst_reg, src_abi_size);
4740 const tmp = registerAlias(tmp_reg, src_abi_size);4850 const tmp = registerAlias(tmp_reg, src_abi_size);
4741 const imm = if (src_abi_size > 4)4851 const imm = if (src_abi_size > 4)
4742 try self.register_manager.allocReg(null, gp)4852 try self.register_manager.allocReg(null, abi.RegisterClass.gp)
4743 else4853 else
4744 undefined;4854 undefined;
47454855
...@@ -4840,7 +4950,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m...@@ -4840,7 +4950,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
4840 const dst_mcv: MCValue = if (mem_ok)4950 const dst_mcv: MCValue = if (mem_ok)
4841 try self.allocRegOrMem(inst, true)4951 try self.allocRegOrMem(inst, true)
4842 else4952 else
4843 .{ .register = try self.register_manager.allocReg(inst, gp) };4953 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.gp) };
4844 if (dst_mcv.isRegister()) {4954 if (dst_mcv.isRegister()) {
4845 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_mcv.register);4955 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_mcv.register);
4846 defer self.register_manager.unlockReg(dst_lock);4956 defer self.register_manager.unlockReg(dst_lock);
...@@ -4855,7 +4965,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m...@@ -4855,7 +4965,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
4855 return dst_mcv;4965 return dst_mcv;
4856 }4966 }
48574967
4858 const dst_reg = try self.register_manager.allocReg(inst, gp);4968 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
4859 const dst_mcv = MCValue{ .register = dst_reg };4969 const dst_mcv = MCValue{ .register = dst_reg };
4860 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);4970 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
4861 defer self.register_manager.unlockReg(dst_lock);4971 defer self.register_manager.unlockReg(dst_lock);
...@@ -4898,7 +5008,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4898,7 +5008,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4898 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);5008 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
4899 defer self.register_manager.unlockReg(dst_lock);5009 defer self.register_manager.unlockReg(dst_lock);
49005010
4901 const tmp_reg = try self.register_manager.allocReg(null, gp);5011 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
4902 const tmp_lock = self.register_manager.lockReg(tmp_reg);5012 const tmp_lock = self.register_manager.lockReg(tmp_reg);
4903 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);5013 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
49045014
...@@ -4906,7 +5016,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4906,7 +5016,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4906 const dst = registerAlias(dst_reg, src_abi_size);5016 const dst = registerAlias(dst_reg, src_abi_size);
4907 const tmp = registerAlias(tmp_reg, src_abi_size);5017 const tmp = registerAlias(tmp_reg, src_abi_size);
4908 const imm = if (src_abi_size > 4)5018 const imm = if (src_abi_size > 4)
4909 try self.register_manager.allocReg(null, gp)5019 try self.register_manager.allocReg(null, abi.RegisterClass.gp)
4910 else5020 else
4911 undefined;5021 undefined;
49125022
...@@ -4998,109 +5108,129 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4998,109 +5108,129 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4998fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void {5108fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void {
4999 const mod = self.bin_file.options.module.?;5109 const mod = self.bin_file.options.module.?;
5000 const tag = self.air.instructions.items(.tag)[inst];5110 const tag = self.air.instructions.items(.tag)[inst];
5001 const abi_size: u32 = switch (ty.abiSize(mod)) {
5002 1...16 => 16,
5003 17...32 => 32,
5004 else => return self.fail("TODO implement floatSign for {}", .{
5005 ty.fmt(mod),
5006 }),
5007 };
5008 const scalar_bits = ty.scalarType(mod).floatBits(self.target.*);
5009 if (scalar_bits == 80) return self.fail("TODO implement floatSign for {}", .{
5010 ty.fmt(mod),
5011 });
50125111
5013 const src_mcv = try self.resolveInst(operand);5112 const result = result: {
5014 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;5113 const scalar_bits = ty.scalarType(mod).floatBits(self.target.*);
5015 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);5114 if (scalar_bits == 80) {
5115 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement floatSign for {}", .{
5116 ty.fmt(mod),
5117 });
50165118
5017 const dst_mcv: MCValue = if (src_mcv.isRegister() and self.reuseOperand(inst, operand, 0, src_mcv))5119 const src_mcv = try self.resolveInst(operand);
5018 src_mcv5120 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
5019 else if (self.hasFeature(.avx))5121 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
5020 .{ .register = try self.register_manager.allocReg(inst, sse) }
5021 else
5022 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5023 const dst_reg = dst_mcv.getReg().?;
5024 const dst_lock = self.register_manager.lockReg(dst_reg);
5025 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
50265122
5027 const vec_ty = try mod.vectorType(.{5123 const dst_mcv: MCValue = .{ .register = .st0 };
5028 .len = @divExact(abi_size * 8, scalar_bits),5124 if (std.meta.eql(src_mcv, dst_mcv) and self.reuseOperand(inst, operand, 0, src_mcv))
5029 .child = (try mod.intType(.signed, scalar_bits)).ip_index,5125 try self.register_manager.getReg(.st0, inst);
5030 });
50315126
5032 const sign_val = switch (tag) {5127 try self.genCopy(ty, dst_mcv, src_mcv);
5033 .neg => try vec_ty.minInt(mod, vec_ty),5128 switch (tag) {
5034 .abs => try vec_ty.maxInt(mod, vec_ty),5129 .neg => try self.asmOpOnly(.{ .f_, .chs }),
5035 else => unreachable,5130 .abs => try self.asmOpOnly(.{ .f_, .abs }),
5036 };5131 else => unreachable,
5132 }
5133 break :result dst_mcv;
5134 }
50375135
5038 const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val });5136 const abi_size: u32 = switch (ty.abiSize(mod)) {
5039 const sign_mem = if (sign_mcv.isMemory())5137 1...16 => 16,
5040 sign_mcv.mem(Memory.PtrSize.fromSize(abi_size))5138 17...32 => 32,
5041 else5139 else => return self.fail("TODO implement floatSign for {}", .{
5042 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{5140 ty.fmt(mod),
5043 .base = .{ .reg = try self.copyToTmpRegister(Type.usize, sign_mcv.address()) },5141 }),
5142 };
5143
5144 const src_mcv = try self.resolveInst(operand);
5145 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
5146 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
5147
5148 const dst_mcv: MCValue = if (src_mcv.isRegister() and
5149 self.reuseOperand(inst, operand, 0, src_mcv))
5150 src_mcv
5151 else if (self.hasFeature(.avx))
5152 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
5153 else
5154 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5155 const dst_reg = dst_mcv.getReg().?;
5156 const dst_lock = self.register_manager.lockReg(dst_reg);
5157 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5158
5159 const vec_ty = try mod.vectorType(.{
5160 .len = @divExact(abi_size * 8, scalar_bits),
5161 .child = (try mod.intType(.signed, scalar_bits)).ip_index,
5044 });5162 });
50455163
5046 if (self.hasFeature(.avx)) try self.asmRegisterRegisterMemory(5164 const sign_val = switch (tag) {
5047 switch (scalar_bits) {5165 .neg => try vec_ty.minInt(mod, vec_ty),
5048 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {5166 .abs => try vec_ty.maxInt(mod, vec_ty),
5049 .neg => .{ .vp_, .xor },
5050 .abs => .{ .vp_, .@"and" },
5051 else => unreachable,
5052 } else switch (tag) {
5053 .neg => .{ .v_ps, .xor },
5054 .abs => .{ .v_ps, .@"and" },
5055 else => unreachable,
5056 },
5057 32 => switch (tag) {
5058 .neg => .{ .v_ps, .xor },
5059 .abs => .{ .v_ps, .@"and" },
5060 else => unreachable,
5061 },
5062 64 => switch (tag) {
5063 .neg => .{ .v_pd, .xor },
5064 .abs => .{ .v_pd, .@"and" },
5065 else => unreachable,
5066 },
5067 80 => return self.fail("TODO implement floatSign for {}", .{
5068 ty.fmt(self.bin_file.options.module.?),
5069 }),
5070 else => unreachable,5167 else => unreachable,
5071 },5168 };
5072 registerAlias(dst_reg, abi_size),5169
5073 registerAlias(if (src_mcv.isRegister())5170 const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val });
5074 src_mcv.getReg().?5171 const sign_mem = if (sign_mcv.isMemory())
5172 sign_mcv.mem(Memory.PtrSize.fromSize(abi_size))
5075 else5173 else
5076 try self.copyToTmpRegister(ty, src_mcv), abi_size),5174 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
5077 sign_mem,5175 .base = .{ .reg = try self.copyToTmpRegister(Type.usize, sign_mcv.address()) },
5078 ) else try self.asmRegisterMemory(5176 });
5079 switch (scalar_bits) {5177
5080 16, 128 => switch (tag) {5178 if (self.hasFeature(.avx)) try self.asmRegisterRegisterMemory(
5081 .neg => .{ .p_, .xor },5179 switch (scalar_bits) {
5082 .abs => .{ .p_, .@"and" },5180 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {
5083 else => unreachable,5181 .neg => .{ .vp_, .xor },
5084 },5182 .abs => .{ .vp_, .@"and" },
5085 32 => switch (tag) {5183 else => unreachable,
5086 .neg => .{ ._ps, .xor },5184 } else switch (tag) {
5087 .abs => .{ ._ps, .@"and" },5185 .neg => .{ .v_ps, .xor },
5186 .abs => .{ .v_ps, .@"and" },
5187 else => unreachable,
5188 },
5189 32 => switch (tag) {
5190 .neg => .{ .v_ps, .xor },
5191 .abs => .{ .v_ps, .@"and" },
5192 else => unreachable,
5193 },
5194 64 => switch (tag) {
5195 .neg => .{ .v_pd, .xor },
5196 .abs => .{ .v_pd, .@"and" },
5197 else => unreachable,
5198 },
5199 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(mod)}),
5088 else => unreachable,5200 else => unreachable,
5089 },5201 },
5090 64 => switch (tag) {5202 registerAlias(dst_reg, abi_size),
5091 .neg => .{ ._pd, .xor },5203 registerAlias(if (src_mcv.isRegister())
5092 .abs => .{ ._pd, .@"and" },5204 src_mcv.getReg().?
5205 else
5206 try self.copyToTmpRegister(ty, src_mcv), abi_size),
5207 sign_mem,
5208 ) else try self.asmRegisterMemory(
5209 switch (scalar_bits) {
5210 16, 128 => switch (tag) {
5211 .neg => .{ .p_, .xor },
5212 .abs => .{ .p_, .@"and" },
5213 else => unreachable,
5214 },
5215 32 => switch (tag) {
5216 .neg => .{ ._ps, .xor },
5217 .abs => .{ ._ps, .@"and" },
5218 else => unreachable,
5219 },
5220 64 => switch (tag) {
5221 .neg => .{ ._pd, .xor },
5222 .abs => .{ ._pd, .@"and" },
5223 else => unreachable,
5224 },
5225 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(mod)}),
5093 else => unreachable,5226 else => unreachable,
5094 },5227 },
5095 80 => return self.fail("TODO implement floatSign for {}", .{5228 registerAlias(dst_reg, abi_size),
5096 ty.fmt(self.bin_file.options.module.?),5229 sign_mem,
5097 }),5230 );
5098 else => unreachable,5231 break :result dst_mcv;
5099 },5232 };
5100 registerAlias(dst_reg, abi_size),5233 return self.finishAir(inst, result, .{ operand, .none, .none });
5101 sign_mem,
5102 );
5103 return self.finishAir(inst, dst_mcv, .{ operand, .none, .none });
5104}5234}
51055235
5106fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {5236fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5133,21 +5263,29 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {...@@ -5133,21 +5263,29 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {
5133 const un_op = self.air.instructions.items(.data)[inst].un_op;5263 const un_op = self.air.instructions.items(.data)[inst].un_op;
5134 const ty = self.typeOf(un_op);5264 const ty = self.typeOf(un_op);
51355265
5136 const src_mcv = try self.resolveInst(un_op);5266 const result = result: {
5137 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))5267 switch (try self.genRoundLibcall(ty, .{ .air_ref = un_op }, mode)) {
5138 src_mcv5268 .none => {},
5139 else5269 else => |dst_mcv| break :result dst_mcv,
5140 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);5270 }
5141 const dst_reg = dst_mcv.getReg().?;5271
5142 const dst_lock = self.register_manager.lockReg(dst_reg);5272 const src_mcv = try self.resolveInst(un_op);
5143 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);5273 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
5144 try self.genRound(ty, dst_reg, src_mcv, mode);5274 src_mcv
5145 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });5275 else
5276 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5277 const dst_reg = dst_mcv.getReg().?;
5278 const dst_lock = self.register_manager.lockReg(dst_reg);
5279 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5280 try self.genRound(ty, dst_reg, src_mcv, mode);
5281 break :result dst_mcv;
5282 };
5283 return self.finishAir(inst, result, .{ un_op, .none, .none });
5146}5284}
51475285
5148fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void {5286fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag {
5149 const mod = self.bin_file.options.module.?;5287 const mod = self.bin_file.options.module.?;
5150 const mir_tag = @as(?Mir.Inst.FixedTag, if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) {5288 return if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) {
5151 .Float => switch (ty.floatBits(self.target.*)) {5289 .Float => switch (ty.floatBits(self.target.*)) {
5152 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },5290 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
5153 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },5291 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
...@@ -5174,27 +5312,38 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro...@@ -5174,27 +5312,38 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro
5174 else => null,5312 else => null,
5175 },5313 },
5176 else => unreachable,5314 else => unreachable,
5177 } else null) orelse {5315 } else null;
5178 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement genRound for {}", .{5316}
5179 ty.fmt(self.bin_file.options.module.?),
5180 });
51815317
5182 var callee: ["__trunc?".len]u8 = undefined;5318fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue {
5183 const res = try self.genCall(.{ .lib = .{5319 const mod = self.bin_file.options.module.?;
5184 .return_type = ty.toIntern(),5320 if (self.getRoundTag(ty)) |_| return .none;
5185 .param_types = &.{ty.toIntern()},5321
5186 .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{5322 if (ty.zigTypeTag(mod) != .Float)
5187 floatLibcAbiPrefix(ty),5323 return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)});
5188 switch (mode.mode) {5324
5189 .down => "floor",5325 var callee: ["__trunc?".len]u8 = undefined;
5190 .up => "ceil",5326 return try self.genCall(.{ .lib = .{
5191 .zero => "trunc",5327 .return_type = ty.toIntern(),
5192 else => unreachable,5328 .param_types = &.{ty.toIntern()},
5193 },5329 .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
5194 floatLibcAbiSuffix(ty),5330 floatLibcAbiPrefix(ty),
5195 }) catch unreachable,5331 switch (mode.mode) {
5196 } }, &.{ty}, &.{src_mcv});5332 .down => "floor",
5197 return self.genSetReg(dst_reg, ty, res);5333 .up => "ceil",
5334 .zero => "trunc",
5335 else => unreachable,
5336 },
5337 floatLibcAbiSuffix(ty),
5338 }) catch unreachable,
5339 } }, &.{ty}, &.{src_mcv});
5340}
5341
5342fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void {
5343 const mod = self.bin_file.options.module.?;
5344 const mir_tag = self.getRoundTag(ty) orelse {
5345 const result = try self.genRoundLibcall(ty, src_mcv, mode);
5346 return self.genSetReg(dst_reg, ty, result);
5198 };5347 };
5199 const abi_size: u32 = @intCast(ty.abiSize(mod));5348 const abi_size: u32 = @intCast(ty.abiSize(mod));
5200 const dst_alias = registerAlias(dst_reg, abi_size);5349 const dst_alias = registerAlias(dst_reg, abi_size);
...@@ -5236,46 +5385,104 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {...@@ -5236,46 +5385,104 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
5236 const mod = self.bin_file.options.module.?;5385 const mod = self.bin_file.options.module.?;
5237 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5386 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5238 const ty = self.typeOf(ty_op.operand);5387 const ty = self.typeOf(ty_op.operand);
5239 const scalar_ty = ty.scalarType(mod);
52405388
5241 switch (scalar_ty.zigTypeTag(mod)) {5389 const result: MCValue = result: {
5242 .Int => if (ty.zigTypeTag(mod) == .Vector) {5390 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
5243 return self.fail("TODO implement airAbs for {}", .{ty.fmt(mod)});5391 else => null,
5244 } else {5392 .Int => {
5245 if (ty.abiSize(mod) > 8) {5393 if (ty.abiSize(mod) > 8) {
5246 return self.fail("TODO implement abs for integer abi sizes larger than 8", .{});5394 return self.fail("TODO implement abs for integer abi sizes larger than 8", .{});
5247 }5395 }
5248 const src_mcv = try self.resolveInst(ty_op.operand);5396 const src_mcv = try self.resolveInst(ty_op.operand);
5249 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);5397 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
52505398
5251 try self.genUnOpMir(.{ ._, .neg }, ty, dst_mcv);5399 try self.genUnOpMir(.{ ._, .neg }, ty, dst_mcv);
52525400
5253 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);5401 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
5254 switch (src_mcv) {5402 switch (src_mcv) {
5255 .register => |val_reg| try self.asmCmovccRegisterRegister(5403 .register => |val_reg| try self.asmCmovccRegisterRegister(
5256 registerAlias(dst_mcv.register, cmov_abi_size),
5257 registerAlias(val_reg, cmov_abi_size),
5258 .l,
5259 ),
5260 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
5261 registerAlias(dst_mcv.register, cmov_abi_size),
5262 src_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
5263 .l,
5264 ),
5265 else => {
5266 const val_reg = try self.copyToTmpRegister(ty, src_mcv);
5267 try self.asmCmovccRegisterRegister(
5268 registerAlias(dst_mcv.register, cmov_abi_size),5404 registerAlias(dst_mcv.register, cmov_abi_size),
5269 registerAlias(val_reg, cmov_abi_size),5405 registerAlias(val_reg, cmov_abi_size),
5270 .l,5406 .l,
5271 );5407 ),
5408 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
5409 registerAlias(dst_mcv.register, cmov_abi_size),
5410 src_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
5411 .l,
5412 ),
5413 else => {
5414 const val_reg = try self.copyToTmpRegister(ty, src_mcv);
5415 try self.asmCmovccRegisterRegister(
5416 registerAlias(dst_mcv.register, cmov_abi_size),
5417 registerAlias(val_reg, cmov_abi_size),
5418 .l,
5419 );
5420 },
5421 }
5422 break :result dst_mcv;
5423 },
5424 .Float => return self.floatSign(inst, ty_op.operand, ty),
5425 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
5426 else => null,
5427 .Int => switch (ty.childType(mod).intInfo(mod).bits) {
5428 else => null,
5429 8 => switch (ty.vectorLen(mod)) {
5430 else => null,
5431 1...16 => if (self.hasFeature(.avx))
5432 .{ .vp_b, .abs }
5433 else if (self.hasFeature(.ssse3))
5434 .{ .p_b, .abs }
5435 else
5436 null,
5437 17...32 => if (self.hasFeature(.avx2)) .{ .vp_b, .abs } else null,
5438 },
5439 16 => switch (ty.vectorLen(mod)) {
5440 else => null,
5441 1...8 => if (self.hasFeature(.avx))
5442 .{ .vp_w, .abs }
5443 else if (self.hasFeature(.ssse3))
5444 .{ .p_w, .abs }
5445 else
5446 null,
5447 9...16 => if (self.hasFeature(.avx2)) .{ .vp_w, .abs } else null,
5448 },
5449 32 => switch (ty.vectorLen(mod)) {
5450 else => null,
5451 1...4 => if (self.hasFeature(.avx))
5452 .{ .vp_d, .abs }
5453 else if (self.hasFeature(.ssse3))
5454 .{ .p_d, .abs }
5455 else
5456 null,
5457 5...8 => if (self.hasFeature(.avx2)) .{ .vp_d, .abs } else null,
5458 },
5272 },5459 },
5273 }5460 .Float => return self.floatSign(inst, ty_op.operand, ty),
5274 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });5461 },
5275 },5462 }) orelse return self.fail("TODO implement airAbs for {}", .{ty.fmt(mod)});
5276 .Float => return self.floatSign(inst, ty_op.operand, ty),5463
5277 else => unreachable,5464 const abi_size: u32 = @intCast(ty.abiSize(mod));
5278 }5465 const src_mcv = try self.resolveInst(ty_op.operand);
5466 const dst_reg = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
5467 src_mcv.getReg().?
5468 else
5469 try self.register_manager.allocReg(inst, self.regClassForType(ty));
5470 const dst_alias = registerAlias(dst_reg, abi_size);
5471 if (src_mcv.isMemory()) try self.asmRegisterMemory(
5472 mir_tag,
5473 dst_alias,
5474 src_mcv.mem(self.memPtrSize(ty)),
5475 ) else try self.asmRegisterRegister(
5476 mir_tag,
5477 dst_alias,
5478 registerAlias(if (src_mcv.isRegister())
5479 src_mcv.getReg().?
5480 else
5481 try self.copyToTmpRegister(ty, src_mcv), abi_size),
5482 );
5483 break :result .{ .register = dst_reg };
5484 };
5485 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5279}5486}
52805487
5281fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {5488fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5284,19 +5491,43 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5284,19 +5491,43 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5284 const ty = self.typeOf(un_op);5491 const ty = self.typeOf(un_op);
5285 const abi_size: u32 = @intCast(ty.abiSize(mod));5492 const abi_size: u32 = @intCast(ty.abiSize(mod));
52865493
5287 const src_mcv = try self.resolveInst(un_op);
5288 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
5289 src_mcv
5290 else
5291 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5292 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
5293 const dst_lock = self.register_manager.lockReg(dst_reg);
5294 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5295
5296 const result: MCValue = result: {5494 const result: MCValue = result: {
5495 switch (ty.zigTypeTag(mod)) {
5496 .Float => {
5497 const float_bits = ty.floatBits(self.target.*);
5498 if (switch (float_bits) {
5499 16 => !self.hasFeature(.f16c),
5500 32, 64 => false,
5501 80, 128 => true,
5502 else => unreachable,
5503 }) {
5504 var callee: ["__sqrt?".len]u8 = undefined;
5505 break :result try self.genCall(.{ .lib = .{
5506 .return_type = ty.toIntern(),
5507 .param_types = &.{ty.toIntern()},
5508 .callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{
5509 floatLibcAbiPrefix(ty),
5510 floatLibcAbiSuffix(ty),
5511 }) catch unreachable,
5512 } }, &.{ty}, &.{.{ .air_ref = un_op }});
5513 }
5514 },
5515 else => {},
5516 }
5517
5518 const src_mcv = try self.resolveInst(un_op);
5519 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
5520 src_mcv
5521 else
5522 try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5523 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
5524 const dst_lock = self.register_manager.lockReg(dst_reg);
5525 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
5526
5297 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {5527 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
5298 .Float => switch (ty.floatBits(self.target.*)) {5528 .Float => switch (ty.floatBits(self.target.*)) {
5299 16 => if (self.hasFeature(.f16c)) {5529 16 => {
5530 assert(self.hasFeature(.f16c));
5300 const mat_src_reg = if (src_mcv.isRegister())5531 const mat_src_reg = if (src_mcv.isRegister())
5301 src_mcv.getReg().?5532 src_mcv.getReg().?
5302 else5533 else
...@@ -5310,10 +5541,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5310,10 +5541,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5310 Immediate.u(0b1_00),5541 Immediate.u(0b1_00),
5311 );5542 );
5312 break :result dst_mcv;5543 break :result dst_mcv;
5313 } else null,5544 },
5314 32 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },5545 32 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },
5315 64 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },5546 64 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },
5316 80, 128 => null,
5317 else => unreachable,5547 else => unreachable,
5318 },5548 },
5319 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {5549 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
...@@ -5387,21 +5617,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5387,21 +5617,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5387 else => unreachable,5617 else => unreachable,
5388 },5618 },
5389 else => unreachable,5619 else => unreachable,
5390 }) orelse {5620 }) orelse return self.fail("TODO implement airSqrt for {}", .{
5391 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement airSqrt for {}", .{5621 ty.fmt(mod),
5392 ty.fmt(mod),5622 });
5393 });
5394
5395 var callee: ["__sqrt?".len]u8 = undefined;
5396 break :result try self.genCall(.{ .lib = .{
5397 .return_type = ty.toIntern(),
5398 .param_types = &.{ty.toIntern()},
5399 .callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{
5400 floatLibcAbiPrefix(ty),
5401 floatLibcAbiSuffix(ty),
5402 }) catch unreachable,
5403 } }, &.{ty}, &.{src_mcv});
5404 };
5405 switch (mir_tag[0]) {5623 switch (mir_tag[0]) {
5406 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(5624 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
5407 mir_tag,5625 mir_tag,
...@@ -5518,9 +5736,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -5518,9 +5736,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
5518 const val_bit_off = ptr_info.packed_offset.bit_offset % limb_abi_bits;5736 const val_bit_off = ptr_info.packed_offset.bit_offset % limb_abi_bits;
5519 const val_extra_bits = self.regExtraBits(val_ty);5737 const val_extra_bits = self.regExtraBits(val_ty);
55205738
5521 if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{5739 if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{val_ty.fmt(mod)});
5522 val_ty.fmt(self.bin_file.options.module.?),
5523 });
55245740
5525 const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);5741 const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
5526 const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg);5742 const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg);
...@@ -5528,7 +5744,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -5528,7 +5744,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
55285744
5529 const dst_reg = switch (dst_mcv) {5745 const dst_reg = switch (dst_mcv) {
5530 .register => |reg| reg,5746 .register => |reg| reg,
5531 else => try self.register_manager.allocReg(null, gp),5747 else => try self.register_manager.allocReg(null, abi.RegisterClass.gp),
5532 };5748 };
5533 const dst_lock = self.register_manager.lockReg(dst_reg);5749 const dst_lock = self.register_manager.lockReg(dst_reg);
5534 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);5750 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -5547,7 +5763,8 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -5547,7 +5763,8 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
5547 );5763 );
5548 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off));5764 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off));
5549 } else {5765 } else {
5550 const tmp_reg = registerAlias(try self.register_manager.allocReg(null, gp), val_abi_size);5766 const tmp_reg =
5767 registerAlias(try self.register_manager.allocReg(null, abi.RegisterClass.gp), val_abi_size);
5551 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);5768 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
5552 defer self.register_manager.unlockReg(tmp_lock);5769 defer self.register_manager.unlockReg(tmp_lock);
55535770
...@@ -5632,8 +5849,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -5632,8 +5849,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
5632 const ptr_ty = self.typeOf(ty_op.operand);5849 const ptr_ty = self.typeOf(ty_op.operand);
5633 const elem_size = elem_ty.abiSize(mod);5850 const elem_size = elem_ty.abiSize(mod);
56345851
5635 const elem_rc = regClassForType(elem_ty, mod);5852 const elem_rc = self.regClassForType(elem_ty);
5636 const ptr_rc = regClassForType(ptr_ty, mod);5853 const ptr_rc = self.regClassForType(ptr_ty);
56375854
5638 const ptr_mcv = try self.resolveInst(ty_op.operand);5855 const ptr_mcv = try self.resolveInst(ty_op.operand);
5639 const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and5856 const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and
...@@ -5688,13 +5905,13 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In...@@ -5688,13 +5905,13 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
5688 } else if (math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| {5905 } else if (math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| {
5689 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.s(small));5906 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.s(small));
5690 } else {5907 } else {
5691 const part_mask_reg = try self.register_manager.allocReg(null, gp);5908 const part_mask_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
5692 try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, Immediate.u(part_mask_not));5909 try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, Immediate.u(part_mask_not));
5693 try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);5910 try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);
5694 }5911 }
56955912
5696 if (src_bit_size <= 64) {5913 if (src_bit_size <= 64) {
5697 const tmp_reg = try self.register_manager.allocReg(null, gp);5914 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
5698 const tmp_mcv = MCValue{ .register = tmp_reg };5915 const tmp_mcv = MCValue{ .register = tmp_reg };
5699 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);5916 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
5700 defer self.register_manager.unlockReg(tmp_lock);5917 defer self.register_manager.unlockReg(tmp_lock);
...@@ -5721,9 +5938,7 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In...@@ -5721,9 +5938,7 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
5721 limb_mem,5938 limb_mem,
5722 registerAlias(tmp_reg, limb_abi_size),5939 registerAlias(tmp_reg, limb_abi_size),
5723 );5940 );
5724 } else return self.fail("TODO: implement packed store of {}", .{5941 } else return self.fail("TODO: implement packed store of {}", .{src_ty.fmt(mod)});
5725 src_ty.fmt(self.bin_file.options.module.?),
5726 });
5727 }5942 }
5728}5943}
57295944
...@@ -5761,7 +5976,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr...@@ -5761,7 +5976,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
57615976
5762 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);5977 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
5763 },5978 },
5764 .air_ref => |ptr_ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ptr_ref)),5979 .air_ref => |ptr_ref| try self.store(ptr_ty, try self.resolveInst(ptr_ref), src_mcv),
5765 }5980 }
5766}5981}
57675982
...@@ -5832,11 +6047,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5832,11 +6047,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5832 const index = extra.field_index;6047 const index = extra.field_index;
58336048
5834 const container_ty = self.typeOf(operand);6049 const container_ty = self.typeOf(operand);
5835 const container_rc = regClassForType(container_ty, mod);6050 const container_rc = self.regClassForType(container_ty);
5836 const field_ty = container_ty.structFieldType(index, mod);6051 const field_ty = container_ty.structFieldType(index, mod);
5837 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;6052 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;
5838 const field_rc = regClassForType(field_ty, mod);6053 const field_rc = self.regClassForType(field_ty);
5839 const field_is_gp = field_rc.supersetOf(gp);6054 const field_is_gp = field_rc.supersetOf(abi.RegisterClass.gp);
58406055
5841 const src_mcv = try self.resolveInst(operand);6056 const src_mcv = try self.resolveInst(operand);
5842 const field_off: u32 = switch (container_ty.containerLayout(mod)) {6057 const field_off: u32 = switch (container_ty.containerLayout(mod)) {
...@@ -5860,8 +6075,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5860,8 +6075,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5860 @intCast(field_ty.bitSize(mod)),6075 @intCast(field_ty.bitSize(mod)),
5861 );6076 );
58626077
5863 const dst_reg =6078 const dst_reg = try self.register_manager.allocReg(
5864 try self.register_manager.allocReg(if (field_is_gp) inst else null, gp);6079 if (field_is_gp) inst else null,
6080 abi.RegisterClass.gp,
6081 );
5865 const dst_mcv = MCValue{ .register = dst_reg };6082 const dst_mcv = MCValue{ .register = dst_reg };
5866 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);6083 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
5867 defer self.register_manager.unlockReg(dst_lock);6084 defer self.register_manager.unlockReg(dst_lock);
...@@ -5890,7 +6107,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5890,7 +6107,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5890 return self.fail("TODO implement struct_field_val with large packed field", .{});6107 return self.fail("TODO implement struct_field_val with large packed field", .{});
5891 }6108 }
58926109
5893 const dst_reg = try self.register_manager.allocReg(if (field_is_gp) inst else null, gp);6110 const dst_reg = try self.register_manager.allocReg(
6111 if (field_is_gp) inst else null,
6112 abi.RegisterClass.gp,
6113 );
5894 const field_extra_bits = self.regExtraBits(field_ty);6114 const field_extra_bits = self.regExtraBits(field_ty);
5895 const load_abi_size =6115 const load_abi_size =
5896 if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2;6116 if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2;
...@@ -5907,7 +6127,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5907,7 +6127,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5907 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off));6127 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off));
5908 } else {6128 } else {
5909 const tmp_reg = registerAlias(6129 const tmp_reg = registerAlias(
5910 try self.register_manager.allocReg(null, gp),6130 try self.register_manager.allocReg(null, abi.RegisterClass.gp),
5911 field_abi_size,6131 field_abi_size,
5912 );6132 );
5913 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);6133 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
...@@ -5967,7 +6187,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5967,7 +6187,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5967 );6187 );
5968 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);6188 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
59696189
5970 break :result if (field_rc.supersetOf(gp))6190 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
5971 dst_mcv6191 dst_mcv
5972 else6192 else
5973 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);6193 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
...@@ -5988,7 +6208,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5988,7 +6208,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5988 self.eflags_inst = inst;6208 self.eflags_inst = inst;
5989 break :result .{ .eflags = ro.eflags };6209 break :result .{ .eflags = ro.eflags };
5990 } else {6210 } else {
5991 const dst_reg = try self.register_manager.allocReg(inst, gp);6211 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
5992 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);6212 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
5993 break :result .{ .register = dst_reg.to8() };6213 break :result .{ .register = dst_reg.to8() };
5994 },6214 },
...@@ -6024,9 +6244,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -6024,9 +6244,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
6024 const mod = self.bin_file.options.module.?;6244 const mod = self.bin_file.options.module.?;
6025 const src_ty = self.typeOf(src_air);6245 const src_ty = self.typeOf(src_air);
6026 const src_mcv = try self.resolveInst(src_air);6246 const src_mcv = try self.resolveInst(src_air);
6027 if (src_ty.zigTypeTag(mod) == .Vector) {6247 if (src_ty.zigTypeTag(mod) == .Vector)
6028 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});6248 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(mod)});
6029 }
60306249
6031 switch (src_mcv) {6250 switch (src_mcv) {
6032 .eflags => |cc| switch (tag) {6251 .eflags => |cc| switch (tag) {
...@@ -6086,10 +6305,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -6086,10 +6305,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
6086fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void {6305fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void {
6087 const mod = self.bin_file.options.module.?;6306 const mod = self.bin_file.options.module.?;
6088 const abi_size: u32 = @intCast(dst_ty.abiSize(mod));6307 const abi_size: u32 = @intCast(dst_ty.abiSize(mod));
6089 if (abi_size > 8) return self.fail("TODO implement {} for {}", .{6308 if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(mod) });
6090 mir_tag,
6091 dst_ty.fmt(self.bin_file.options.module.?),
6092 });
6093 switch (dst_mcv) {6309 switch (dst_mcv) {
6094 .none,6310 .none,
6095 .unreach,6311 .unreach,
...@@ -6109,7 +6325,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC...@@ -6109,7 +6325,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
6109 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),6325 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
6110 .register_pair => unreachable, // unimplemented6326 .register_pair => unreachable, // unimplemented
6111 .memory, .load_got, .load_direct, .load_tlv => {6327 .memory, .load_got, .load_direct, .load_tlv => {
6112 const addr_reg = try self.register_manager.allocReg(null, gp);6328 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6113 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);6329 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
6114 defer self.register_manager.unlockReg(addr_reg_lock);6330 defer self.register_manager.unlockReg(addr_reg_lock);
61156331
...@@ -6211,7 +6427,7 @@ fn genShiftBinOpMir(...@@ -6211,7 +6427,7 @@ fn genShiftBinOpMir(
6211 }),6427 }),
6212 }6428 }
6213 } else if (abi_size <= 16) {6429 } else if (abi_size <= 16) {
6214 const tmp_reg = try self.register_manager.allocReg(null, gp);6430 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6215 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);6431 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6216 defer self.register_manager.unlockReg(tmp_lock);6432 defer self.register_manager.unlockReg(tmp_lock);
62176433
...@@ -6289,11 +6505,11 @@ fn genShiftBinOpMir(...@@ -6289,11 +6505,11 @@ fn genShiftBinOpMir(
6289 }6505 }
6290 },6506 },
6291 else => {6507 else => {
6292 const first_reg = try self.register_manager.allocReg(null, gp);6508 const first_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6293 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);6509 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
6294 defer self.register_manager.unlockReg(first_lock);6510 defer self.register_manager.unlockReg(first_lock);
62956511
6296 const second_reg = try self.register_manager.allocReg(null, gp);6512 const second_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6297 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);6513 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
6298 defer self.register_manager.unlockReg(second_lock);6514 defer self.register_manager.unlockReg(second_lock);
62996515
...@@ -6445,7 +6661,7 @@ fn genMulDivBinOp(...@@ -6445,7 +6661,7 @@ fn genMulDivBinOp(
6445 .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,6661 .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
6446 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,6662 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,
6447 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{6663 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{
6448 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),6664 src_ty.fmt(mod), dst_ty.fmt(mod),
6449 });6665 });
6450 const ty = if (dst_abi_size <= 8) dst_ty else src_ty;6666 const ty = if (dst_abi_size <= 8) dst_ty else src_ty;
6451 const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size;6667 const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size;
...@@ -6615,31 +6831,53 @@ fn genBinOp(...@@ -6615,31 +6831,53 @@ fn genBinOp(
6615 const rhs_ty = self.typeOf(rhs_air);6831 const rhs_ty = self.typeOf(rhs_air);
6616 const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));6832 const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));
66176833
6618 if (lhs_ty.isRuntimeFloat() and switch (lhs_ty.floatBits(self.target.*)) {6834 if (lhs_ty.isRuntimeFloat() and (air_tag == .rem or switch (lhs_ty.floatBits(self.target.*)) {
6619 16 => !self.hasFeature(.f16c),6835 16 => !self.hasFeature(.f16c),
6620 32, 64 => false,6836 32, 64 => false,
6621 80, 128 => true,6837 80, 128 => true,
6622 else => unreachable,6838 else => unreachable,
6623 }) {6839 })) {
6624 var callee: ["__add?f3".len]u8 = undefined;6840 var callee: ["__add?f3".len]u8 = undefined;
6625 return self.genCall(.{ .lib = .{6841 const result = try self.genCall(.{ .lib = .{
6626 .return_type = lhs_ty.toIntern(),6842 .return_type = lhs_ty.toIntern(),
6627 .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },6843 .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
6628 .callee = switch (air_tag) {6844 .callee = switch (air_tag) {
6629 .add, .sub, .mul, .div_float => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{6845 .add,
6846 .sub,
6847 .mul,
6848 .div_float,
6849 .div_trunc,
6850 .div_floor,
6851 => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{
6630 @tagName(air_tag)[0..3],6852 @tagName(air_tag)[0..3],
6631 floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)),6853 floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)),
6632 }),6854 }),
6633 .min, .max => std.fmt.bufPrint(&callee, "{s}f{s}{s}", .{6855 .rem, .min, .max => std.fmt.bufPrint(&callee, "{s}f{s}{s}", .{
6634 floatLibcAbiPrefix(lhs_ty),6856 floatLibcAbiPrefix(lhs_ty),
6635 @tagName(air_tag),6857 switch (air_tag) {
6858 .rem => "mod",
6859 .min => "min",
6860 .max => "max",
6861 else => unreachable,
6862 },
6636 floatLibcAbiSuffix(lhs_ty),6863 floatLibcAbiSuffix(lhs_ty),
6637 }),6864 }),
6638 else => return self.fail("TODO implement genBinOp for {s} {}", .{6865 else => return self.fail("TODO implement genBinOp for {s} {}", .{
6639 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),6866 @tagName(air_tag), lhs_ty.fmt(mod),
6640 }),6867 }),
6641 } catch unreachable,6868 } catch unreachable,
6642 } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });6869 } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });
6870 return switch (air_tag) {
6871 .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{
6872 .mode = switch (air_tag) {
6873 .div_trunc => .zero,
6874 .div_floor => .down,
6875 else => unreachable,
6876 },
6877 .precision = .inexact,
6878 }),
6879 else => result,
6880 };
6643 }6881 }
66446882
6645 if ((lhs_ty.scalarType(mod).isRuntimeFloat() and6883 if ((lhs_ty.scalarType(mod).isRuntimeFloat() and
...@@ -6655,11 +6893,11 @@ fn genBinOp(...@@ -6655,11 +6893,11 @@ fn genBinOp(
6655 if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: {6893 if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: {
6656 try self.register_manager.getReg(.xmm0, null);6894 try self.register_manager.getReg(.xmm0, null);
6657 break :mask .xmm0;6895 break :mask .xmm0;
6658 } else try self.register_manager.allocReg(null, sse),6896 } else try self.register_manager.allocReg(null, abi.RegisterClass.sse),
6659 abi_size,6897 abi_size,
6660 ) else null,6898 ) else null,
6661 .rem, .mod => return self.fail("TODO implement genBinOp for {s} {}", .{6899 .rem, .mod => return self.fail("TODO implement genBinOp for {s} {}", .{
6662 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),6900 @tagName(air_tag), lhs_ty.fmt(mod),
6663 }),6901 }),
6664 };6902 };
6665 const mask_lock =6903 const mask_lock =
...@@ -6896,7 +7134,7 @@ fn genBinOp(...@@ -6896,7 +7134,7 @@ fn genBinOp(
6896 },7134 },
68977135
6898 else => return self.fail("TODO implement genBinOp for {s} {}", .{7136 else => return self.fail("TODO implement genBinOp for {s} {}", .{
6899 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7137 @tagName(air_tag), lhs_ty.fmt(mod),
6900 }),7138 }),
6901 }7139 }
6902 return dst_mcv;7140 return dst_mcv;
...@@ -6908,7 +7146,8 @@ fn genBinOp(...@@ -6908,7 +7146,8 @@ fn genBinOp(
6908 .Float => switch (lhs_ty.floatBits(self.target.*)) {7146 .Float => switch (lhs_ty.floatBits(self.target.*)) {
6909 16 => {7147 16 => {
6910 assert(self.hasFeature(.f16c));7148 assert(self.hasFeature(.f16c));
6911 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();7149 const tmp_reg =
7150 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
6912 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7151 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6913 defer self.register_manager.unlockReg(tmp_lock);7152 defer self.register_manager.unlockReg(tmp_lock);
69147153
...@@ -6943,6 +7182,23 @@ fn genBinOp(...@@ -6943,6 +7182,23 @@ fn genBinOp(
6943 dst_reg,7182 dst_reg,
6944 tmp_reg,7183 tmp_reg,
6945 );7184 );
7185 switch (air_tag) {
7186 .div_trunc, .div_floor => try self.asmRegisterRegisterRegisterImmediate(
7187 .{ .v_ss, .round },
7188 dst_reg,
7189 dst_reg,
7190 dst_reg,
7191 Immediate.u(@as(u5, @bitCast(RoundMode{
7192 .mode = switch (air_tag) {
7193 .div_trunc => .zero,
7194 .div_floor => .down,
7195 else => unreachable,
7196 },
7197 .precision = .inexact,
7198 }))),
7199 ),
7200 else => {},
7201 }
6946 try self.asmRegisterRegisterImmediate(7202 try self.asmRegisterRegisterImmediate(
6947 .{ .v_, .cvtps2ph },7203 .{ .v_, .cvtps2ph },
6948 dst_reg,7204 dst_reg,
...@@ -7215,7 +7471,10 @@ fn genBinOp(...@@ -7215,7 +7471,10 @@ fn genBinOp(
7215 assert(self.hasFeature(.f16c));7471 assert(self.hasFeature(.f16c));
7216 switch (lhs_ty.vectorLen(mod)) {7472 switch (lhs_ty.vectorLen(mod)) {
7217 1 => {7473 1 => {
7218 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();7474 const tmp_reg = (try self.register_manager.allocReg(
7475 null,
7476 abi.RegisterClass.sse,
7477 )).to128();
7219 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7478 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7220 defer self.register_manager.unlockReg(tmp_lock);7479 defer self.register_manager.unlockReg(tmp_lock);
72217480
...@@ -7259,7 +7518,10 @@ fn genBinOp(...@@ -7259,7 +7518,10 @@ fn genBinOp(
7259 return dst_mcv;7518 return dst_mcv;
7260 },7519 },
7261 2 => {7520 2 => {
7262 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();7521 const tmp_reg = (try self.register_manager.allocReg(
7522 null,
7523 abi.RegisterClass.sse,
7524 )).to128();
7263 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7525 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7264 defer self.register_manager.unlockReg(tmp_lock);7526 defer self.register_manager.unlockReg(tmp_lock);
72657527
...@@ -7307,7 +7569,10 @@ fn genBinOp(...@@ -7307,7 +7569,10 @@ fn genBinOp(
7307 return dst_mcv;7569 return dst_mcv;
7308 },7570 },
7309 3...4 => {7571 3...4 => {
7310 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();7572 const tmp_reg = (try self.register_manager.allocReg(
7573 null,
7574 abi.RegisterClass.sse,
7575 )).to128();
7311 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7576 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7312 defer self.register_manager.unlockReg(tmp_lock);7577 defer self.register_manager.unlockReg(tmp_lock);
73137578
...@@ -7347,7 +7612,10 @@ fn genBinOp(...@@ -7347,7 +7612,10 @@ fn genBinOp(
7347 return dst_mcv;7612 return dst_mcv;
7348 },7613 },
7349 5...8 => {7614 5...8 => {
7350 const tmp_reg = (try self.register_manager.allocReg(null, sse)).to256();7615 const tmp_reg = (try self.register_manager.allocReg(
7616 null,
7617 abi.RegisterClass.sse,
7618 )).to256();
7351 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7619 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7352 defer self.register_manager.unlockReg(tmp_lock);7620 defer self.register_manager.unlockReg(tmp_lock);
73537621
...@@ -7470,7 +7738,7 @@ fn genBinOp(...@@ -7470,7 +7738,7 @@ fn genBinOp(
7470 },7738 },
7471 },7739 },
7472 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7740 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7473 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7741 @tagName(air_tag), lhs_ty.fmt(mod),
7474 });7742 });
74757743
7476 const lhs_copy_reg = if (maybe_mask_reg) |_| registerAlias(7744 const lhs_copy_reg = if (maybe_mask_reg) |_| registerAlias(
...@@ -7487,7 +7755,10 @@ fn genBinOp(...@@ -7487,7 +7755,10 @@ fn genBinOp(
7487 mir_tag,7755 mir_tag,
7488 dst_reg,7756 dst_reg,
7489 lhs_reg,7757 lhs_reg,
7490 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),7758 src_mcv.mem(switch (lhs_ty.zigTypeTag(mod)) {
7759 else => Memory.PtrSize.fromSize(abi_size),
7760 .Vector => Memory.PtrSize.fromBitSize(dst_reg.bitSize()),
7761 }),
7491 ) else try self.asmRegisterRegisterRegister(7762 ) else try self.asmRegisterRegisterRegister(
7492 mir_tag,7763 mir_tag,
7493 dst_reg,7764 dst_reg,
...@@ -7502,7 +7773,10 @@ fn genBinOp(...@@ -7502,7 +7773,10 @@ fn genBinOp(
7502 if (src_mcv.isMemory()) try self.asmRegisterMemory(7773 if (src_mcv.isMemory()) try self.asmRegisterMemory(
7503 mir_tag,7774 mir_tag,
7504 dst_reg,7775 dst_reg,
7505 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),7776 src_mcv.mem(switch (lhs_ty.zigTypeTag(mod)) {
7777 else => Memory.PtrSize.fromSize(abi_size),
7778 .Vector => Memory.PtrSize.fromBitSize(dst_reg.bitSize()),
7779 }),
7506 ) else try self.asmRegisterRegister(7780 ) else try self.asmRegisterRegister(
7507 mir_tag,7781 mir_tag,
7508 dst_reg,7782 dst_reg,
...@@ -7515,16 +7789,14 @@ fn genBinOp(...@@ -7515,16 +7789,14 @@ fn genBinOp(
75157789
7516 switch (air_tag) {7790 switch (air_tag) {
7517 .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},7791 .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},
7518 .div_trunc, .div_floor => try self.genRound(7792 .div_trunc, .div_floor => try self.genRound(lhs_ty, dst_reg, .{ .register = dst_reg }, .{
7519 lhs_ty,7793 .mode = switch (air_tag) {
7520 dst_reg,
7521 .{ .register = dst_reg },
7522 .{ .mode = switch (air_tag) {
7523 .div_trunc => .zero,7794 .div_trunc => .zero,
7524 .div_floor => .down,7795 .div_floor => .down,
7525 else => unreachable,7796 else => unreachable,
7526 }, .precision = .inexact },7797 },
7527 ),7798 .precision = .inexact,
7799 }),
7528 .bit_and, .bit_or, .xor => {},7800 .bit_and, .bit_or, .xor => {},
7529 .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {7801 .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {
7530 const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size);7802 const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size);
...@@ -7556,7 +7828,7 @@ fn genBinOp(...@@ -7556,7 +7828,7 @@ fn genBinOp(
7556 },7828 },
7557 else => unreachable,7829 else => unreachable,
7558 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7830 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7559 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7831 @tagName(air_tag), lhs_ty.fmt(mod),
7560 }),7832 }),
7561 mask_reg,7833 mask_reg,
7562 rhs_copy_reg,7834 rhs_copy_reg,
...@@ -7588,7 +7860,7 @@ fn genBinOp(...@@ -7588,7 +7860,7 @@ fn genBinOp(
7588 },7860 },
7589 else => unreachable,7861 else => unreachable,
7590 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7862 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7591 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7863 @tagName(air_tag), lhs_ty.fmt(mod),
7592 }),7864 }),
7593 dst_reg,7865 dst_reg,
7594 dst_reg,7866 dst_reg,
...@@ -7624,7 +7896,7 @@ fn genBinOp(...@@ -7624,7 +7896,7 @@ fn genBinOp(
7624 },7896 },
7625 else => unreachable,7897 else => unreachable,
7626 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7898 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7627 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7899 @tagName(air_tag), lhs_ty.fmt(mod),
7628 }),7900 }),
7629 mask_reg,7901 mask_reg,
7630 mask_reg,7902 mask_reg,
...@@ -7655,7 +7927,7 @@ fn genBinOp(...@@ -7655,7 +7927,7 @@ fn genBinOp(
7655 },7927 },
7656 else => unreachable,7928 else => unreachable,
7657 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7929 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7658 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7930 @tagName(air_tag), lhs_ty.fmt(mod),
7659 }),7931 }),
7660 dst_reg,7932 dst_reg,
7661 lhs_copy_reg.?,7933 lhs_copy_reg.?,
...@@ -7686,7 +7958,7 @@ fn genBinOp(...@@ -7686,7 +7958,7 @@ fn genBinOp(
7686 },7958 },
7687 else => unreachable,7959 else => unreachable,
7688 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7960 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7689 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7961 @tagName(air_tag), lhs_ty.fmt(mod),
7690 }),7962 }),
7691 dst_reg,7963 dst_reg,
7692 mask_reg,7964 mask_reg,
...@@ -7716,7 +7988,7 @@ fn genBinOp(...@@ -7716,7 +7988,7 @@ fn genBinOp(
7716 },7988 },
7717 else => unreachable,7989 else => unreachable,
7718 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{7990 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7719 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),7991 @tagName(air_tag), lhs_ty.fmt(mod),
7720 }),7992 }),
7721 mask_reg,7993 mask_reg,
7722 lhs_copy_reg.?,7994 lhs_copy_reg.?,
...@@ -7746,7 +8018,7 @@ fn genBinOp(...@@ -7746,7 +8018,7 @@ fn genBinOp(
7746 },8018 },
7747 else => unreachable,8019 else => unreachable,
7748 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{8020 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
7749 @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),8021 @tagName(air_tag), lhs_ty.fmt(mod),
7750 }),8022 }),
7751 dst_reg,8023 dst_reg,
7752 mask_reg,8024 mask_reg,
...@@ -7940,7 +8212,8 @@ fn genBinOpMir(...@@ -7940,7 +8212,8 @@ fn genBinOpMir(
7940 const dst_info: OpInfo = switch (dst_mcv) {8212 const dst_info: OpInfo = switch (dst_mcv) {
7941 else => unreachable,8213 else => unreachable,
7942 .memory, .load_got, .load_direct, .load_tlv => dst: {8214 .memory, .load_got, .load_direct, .load_tlv => dst: {
7943 const dst_addr_reg = (try self.register_manager.allocReg(null, gp)).to64();8215 const dst_addr_reg =
8216 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
7944 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);8217 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
7945 errdefer self.register_manager.unlockReg(dst_addr_lock);8218 errdefer self.register_manager.unlockReg(dst_addr_lock);
79468219
...@@ -7985,7 +8258,8 @@ fn genBinOpMir(...@@ -7985,7 +8258,8 @@ fn genBinOpMir(
7985 else => unreachable,8258 else => unreachable,
7986 }8259 }
79878260
7988 const src_addr_reg = (try self.register_manager.allocReg(null, gp)).to64();8261 const src_addr_reg =
8262 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
7989 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);8263 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
7990 errdefer self.register_manager.unlockReg(src_addr_lock);8264 errdefer self.register_manager.unlockReg(src_addr_lock);
79918265
...@@ -8428,8 +8702,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -8428,8 +8702,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
8428 const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals);8702 const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals);
84298703
8430 var bt = self.liveness.iterateBigTomb(inst);8704 var bt = self.liveness.iterateBigTomb(inst);
8431 self.feed(&bt, pl_op.operand);8705 try self.feed(&bt, pl_op.operand);
8432 for (arg_refs) |arg_ref| self.feed(&bt, arg_ref);8706 for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref);
84338707
8434 const result = if (self.liveness.isUnused(inst)) .unreach else ret;8708 const result = if (self.liveness.isUnused(inst)) .unreach else ret;
8435 return self.finishAirResult(inst, result);8709 return self.finishAirResult(inst, result);
...@@ -8520,7 +8794,10 @@ fn genCall(self: *Self, info: union(enum) {...@@ -8520,7 +8794,10 @@ fn genCall(self: *Self, info: union(enum) {
8520 try self.spillRegisters(&regs);8794 try self.spillRegisters(&regs);
8521 try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));8795 try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));
8522 },8796 },
8523 .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),8797 .load_frame => {
8798 try self.genCopy(arg_ty, dst_arg, src_arg);
8799 try self.freeValue(src_arg);
8800 },
8524 else => unreachable,8801 else => unreachable,
8525 };8802 };
85268803
...@@ -8546,6 +8823,9 @@ fn genCall(self: *Self, info: union(enum) {...@@ -8546,6 +8823,9 @@ fn genCall(self: *Self, info: union(enum) {
8546 else => unreachable,8823 else => unreachable,
8547 };8824 };
85488825
8826 if (fn_info.is_var_args)
8827 try self.asmRegisterImmediate(.{ ._, .mov }, .al, Immediate.u(call_info.fp_count));
8828
8549 // Due to incremental compilation, how function calls are generated depends8829 // Due to incremental compilation, how function calls are generated depends
8550 // on linking.8830 // on linking.
8551 switch (info) {8831 switch (info) {
...@@ -8611,6 +8891,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -8611,6 +8891,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
8611 const mod = self.bin_file.options.module.?;8891 const mod = self.bin_file.options.module.?;
8612 const un_op = self.air.instructions.items(.data)[inst].un_op;8892 const un_op = self.air.instructions.items(.data)[inst].un_op;
8613 const operand = try self.resolveInst(un_op);8893 const operand = try self.resolveInst(un_op);
8894
8614 const ret_ty = self.fn_type.fnReturnType(mod);8895 const ret_ty = self.fn_type.fnReturnType(mod);
8615 switch (self.ret_mcv.short) {8896 switch (self.ret_mcv.short) {
8616 .none => {},8897 .none => {},
...@@ -8625,6 +8906,8 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -8625,6 +8906,8 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
8625 },8906 },
8626 else => unreachable,8907 else => unreachable,
8627 }8908 }
8909 self.ret_mcv.liveOut(self, inst);
8910
8628 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction8911 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
8629 // which is available if the jump is 127 bytes or less forward.8912 // which is available if the jump is 127 bytes or less forward.
8630 const jmp_reloc = try self.asmJmpReloc(undefined);8913 const jmp_reloc = try self.asmJmpReloc(undefined);
...@@ -8635,6 +8918,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -8635,6 +8918,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
8635fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {8918fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
8636 const un_op = self.air.instructions.items(.data)[inst].un_op;8919 const un_op = self.air.instructions.items(.data)[inst].un_op;
8637 const ptr = try self.resolveInst(un_op);8920 const ptr = try self.resolveInst(un_op);
8921
8638 const ptr_ty = self.typeOf(un_op);8922 const ptr_ty = self.typeOf(un_op);
8639 switch (self.ret_mcv.short) {8923 switch (self.ret_mcv.short) {
8640 .none => {},8924 .none => {},
...@@ -8642,6 +8926,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -8642,6 +8926,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
8642 .indirect => |reg_off| try self.genSetReg(reg_off.reg, ptr_ty, ptr),8926 .indirect => |reg_off| try self.genSetReg(reg_off.reg, ptr_ty, ptr),
8643 else => unreachable,8927 else => unreachable,
8644 }8928 }
8929 self.ret_mcv.liveOut(self, inst);
8930
8645 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction8931 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
8646 // which is available if the jump is 127 bytes or less forward.8932 // which is available if the jump is 127 bytes or less forward.
8647 const jmp_reloc = try self.asmJmpReloc(undefined);8933 const jmp_reloc = try self.asmJmpReloc(undefined);
...@@ -8792,8 +9078,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -8792,8 +9078,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8792 else => unreachable,9078 else => unreachable,
8793 }9079 }
87949080
8795 const dst_addr_reg =9081 const dst_addr_reg = (try self.register_manager.allocReg(
8796 (try self.register_manager.allocReg(null, gp)).to64();9082 null,
9083 abi.RegisterClass.gp,
9084 )).to64();
8797 const dst_addr_lock =9085 const dst_addr_lock =
8798 self.register_manager.lockRegAssumeUnused(dst_addr_reg);9086 self.register_manager.lockRegAssumeUnused(dst_addr_reg);
8799 errdefer self.register_manager.unlockReg(dst_addr_lock);9087 errdefer self.register_manager.unlockReg(dst_addr_lock);
...@@ -8848,8 +9136,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -8848,8 +9136,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8848 else => unreachable,9136 else => unreachable,
8849 }9137 }
88509138
8851 const src_addr_reg =9139 const src_addr_reg = (try self.register_manager.allocReg(
8852 (try self.register_manager.allocReg(null, gp)).to64();9140 null,
9141 abi.RegisterClass.gp,
9142 )).to64();
8853 const src_addr_lock =9143 const src_addr_lock =
8854 self.register_manager.lockRegAssumeUnused(src_addr_reg);9144 self.register_manager.lockRegAssumeUnused(src_addr_reg);
8855 errdefer self.register_manager.unlockReg(src_addr_lock);9145 errdefer self.register_manager.unlockReg(src_addr_lock);
...@@ -8868,8 +9158,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -8868,8 +9158,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8868 defer if (src_info) |info|9158 defer if (src_info) |info|
8869 self.register_manager.unlockReg(info.addr_lock);9159 self.register_manager.unlockReg(info.addr_lock);
88709160
8871 const regs =9161 const regs = try self.register_manager.allocRegs(
8872 try self.register_manager.allocRegs(2, .{ null, null }, gp);9162 2,
9163 .{ null, null },
9164 abi.RegisterClass.gp,
9165 );
8873 const acc_reg = regs[0].to64();9166 const acc_reg = regs[0].to64();
8874 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);9167 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);
8875 defer for (locks) |lock| self.register_manager.unlockReg(lock);9168 defer for (locks) |lock| self.register_manager.unlockReg(lock);
...@@ -8956,12 +9249,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -8956,12 +9249,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8956 switch (ty.floatBits(self.target.*)) {9249 switch (ty.floatBits(self.target.*)) {
8957 16 => {9250 16 => {
8958 assert(self.hasFeature(.f16c));9251 assert(self.hasFeature(.f16c));
8959 const tmp1_reg = (try self.register_manager.allocReg(null, sse)).to128();9252 const tmp1_reg =
9253 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
8960 const tmp1_mcv = MCValue{ .register = tmp1_reg };9254 const tmp1_mcv = MCValue{ .register = tmp1_reg };
8961 const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);9255 const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);
8962 defer self.register_manager.unlockReg(tmp1_lock);9256 defer self.register_manager.unlockReg(tmp1_lock);
89639257
8964 const tmp2_reg = (try self.register_manager.allocReg(null, sse)).to128();9258 const tmp2_reg =
9259 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
8965 const tmp2_mcv = MCValue{ .register = tmp2_reg };9260 const tmp2_mcv = MCValue{ .register = tmp2_reg };
8966 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);9261 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
8967 defer self.register_manager.unlockReg(tmp2_lock);9262 defer self.register_manager.unlockReg(tmp2_lock);
...@@ -9024,7 +9319,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -9024,7 +9319,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
9024 const mod = self.bin_file.options.module.?;9319 const mod = self.bin_file.options.module.?;
9025 const un_op = self.air.instructions.items(.data)[inst].un_op;9320 const un_op = self.air.instructions.items(.data)[inst].un_op;
90269321
9027 const addr_reg = try self.register_manager.allocReg(null, gp);9322 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
9028 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);9323 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
9029 defer self.register_manager.unlockReg(addr_lock);9324 defer self.register_manager.unlockReg(addr_lock);
9030 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));9325 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
...@@ -9086,13 +9381,13 @@ fn genTry(...@@ -9086,13 +9381,13 @@ fn genTry(
9086 const reloc = try self.genCondBrMir(Type.anyerror, is_err_mcv);9381 const reloc = try self.genCondBrMir(Type.anyerror, is_err_mcv);
90879382
9088 if (self.liveness.operandDies(inst, 0)) {9383 if (self.liveness.operandDies(inst, 0)) {
9089 if (Air.refToIndex(err_union)) |err_union_inst| self.processDeath(err_union_inst);9384 if (Air.refToIndex(err_union)) |err_union_inst| try self.processDeath(err_union_inst);
9090 }9385 }
90919386
9092 self.scope_generation += 1;9387 self.scope_generation += 1;
9093 const state = try self.saveState();9388 const state = try self.saveState();
90949389
9095 for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand);9390 for (liveness_cond_br.else_deaths) |operand| try self.processDeath(operand);
9096 try self.genBody(body);9391 try self.genBody(body);
9097 try self.restoreState(state, &.{}, .{9392 try self.restoreState(state, &.{}, .{
9098 .emit_instructions = false,9393 .emit_instructions = false,
...@@ -9103,7 +9398,7 @@ fn genTry(...@@ -9103,7 +9398,7 @@ fn genTry(
91039398
9104 try self.performReloc(reloc);9399 try self.performReloc(reloc);
91059400
9106 for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand);9401 for (liveness_cond_br.then_deaths) |operand| try self.processDeath(operand);
91079402
9108 const result = if (self.liveness.isUnused(inst))9403 const result = if (self.liveness.isUnused(inst))
9109 .unreach9404 .unreach
...@@ -9126,8 +9421,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {...@@ -9126,8 +9421,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
9126}9421}
91279422
9128fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {9423fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
9129 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
9130 const mod = self.bin_file.options.module.?;9424 const mod = self.bin_file.options.module.?;
9425 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
9131 const func = mod.funcInfo(ty_fn.func);9426 const func = mod.funcInfo(ty_fn.func);
9132 // TODO emit debug info for function change9427 // TODO emit debug info for function change
9133 _ = func;9428 _ = func;
...@@ -9153,7 +9448,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -9153,7 +9448,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
9153 return self.finishAir(inst, .unreach, .{ operand, .none, .none });9448 return self.finishAir(inst, .unreach, .{ operand, .none, .none });
9154}9449}
91559450
9156fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {9451fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index {
9157 const mod = self.bin_file.options.module.?;9452 const mod = self.bin_file.options.module.?;
9158 const abi_size = ty.abiSize(mod);9453 const abi_size = ty.abiSize(mod);
9159 switch (mcv) {9454 switch (mcv) {
...@@ -9196,13 +9491,13 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9196,13 +9491,13 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
9196 // that death now instead of later as this has an effect on9491 // that death now instead of later as this has an effect on
9197 // whether it needs to be spilled in the branches9492 // whether it needs to be spilled in the branches
9198 if (self.liveness.operandDies(inst, 0)) {9493 if (self.liveness.operandDies(inst, 0)) {
9199 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);9494 if (Air.refToIndex(pl_op.operand)) |op_inst| try self.processDeath(op_inst);
9200 }9495 }
92019496
9202 self.scope_generation += 1;9497 self.scope_generation += 1;
9203 const state = try self.saveState();9498 const state = try self.saveState();
92049499
9205 for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand);9500 for (liveness_cond_br.then_deaths) |operand| try self.processDeath(operand);
9206 try self.genBody(then_body);9501 try self.genBody(then_body);
9207 try self.restoreState(state, &.{}, .{9502 try self.restoreState(state, &.{}, .{
9208 .emit_instructions = false,9503 .emit_instructions = false,
...@@ -9213,7 +9508,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9213,7 +9508,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
92139508
9214 try self.performReloc(reloc);9509 try self.performReloc(reloc);
92159510
9216 for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand);9511 for (liveness_cond_br.else_deaths) |operand| try self.processDeath(operand);
9217 try self.genBody(else_body);9512 try self.genBody(else_body);
9218 try self.restoreState(state, &.{}, .{9513 try self.restoreState(state, &.{}, .{
9219 .emit_instructions = false,9514 .emit_instructions = false,
...@@ -9285,7 +9580,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -9285,7 +9580,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
9285 .load_direct,9580 .load_direct,
9286 .load_tlv,9581 .load_tlv,
9287 => {9582 => {
9288 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();9583 const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
9289 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);9584 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
9290 defer self.register_manager.unlockReg(addr_reg_lock);9585 defer self.register_manager.unlockReg(addr_reg_lock);
92919586
...@@ -9535,7 +9830,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -9535,7 +9830,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
9535 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9830 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
9536 const loop = self.air.extraData(Air.Block, ty_pl.payload);9831 const loop = self.air.extraData(Air.Block, ty_pl.payload);
9537 const body = self.air.extra[loop.end..][0..loop.data.body_len];9832 const body = self.air.extra[loop.end..][0..loop.data.body_len];
9538 const jmp_target: u32 = @intCast(self.mir_instructions.len);9833 const jmp_target: Mir.Inst.Index = @intCast(self.mir_instructions.len);
95399834
9540 self.scope_generation += 1;9835 self.scope_generation += 1;
9541 const state = try self.saveState();9836 const state = try self.saveState();
...@@ -9580,7 +9875,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {...@@ -9580,7 +9875,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
95809875
9581 if (std.debug.runtime_safety) assert(self.inst_tracking.getIndex(inst).? == inst_tracking_i);9876 if (std.debug.runtime_safety) assert(self.inst_tracking.getIndex(inst).? == inst_tracking_i);
9582 const tracking = &self.inst_tracking.values()[inst_tracking_i];9877 const tracking = &self.inst_tracking.values()[inst_tracking_i];
9583 if (self.liveness.isUnused(inst)) tracking.die(self, inst);9878 if (self.liveness.isUnused(inst)) try tracking.die(self, inst);
9584 self.getValue(tracking.short, inst);9879 self.getValue(tracking.short, inst);
9585 self.finishAirBookkeeping();9880 self.finishAirBookkeeping();
9586}9881}
...@@ -9599,7 +9894,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9599,7 +9894,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
9599 // that death now instead of later as this has an effect on9894 // that death now instead of later as this has an effect on
9600 // whether it needs to be spilled in the branches9895 // whether it needs to be spilled in the branches
9601 if (self.liveness.operandDies(inst, 0)) {9896 if (self.liveness.operandDies(inst, 0)) {
9602 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);9897 if (Air.refToIndex(pl_op.operand)) |op_inst| try self.processDeath(op_inst);
9603 }9898 }
96049899
9605 self.scope_generation += 1;9900 self.scope_generation += 1;
...@@ -9612,7 +9907,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9612,7 +9907,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
9612 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];9907 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
9613 extra_index = case.end + items.len + case_body.len;9908 extra_index = case.end + items.len + case_body.len;
96149909
9615 var relocs = try self.gpa.alloc(u32, items.len);9910 var relocs = try self.gpa.alloc(Mir.Inst.Index, items.len);
9616 defer self.gpa.free(relocs);9911 defer self.gpa.free(relocs);
96179912
9618 try self.spillEflagsIfOccupied();9913 try self.spillEflagsIfOccupied();
...@@ -9622,7 +9917,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9622,7 +9917,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
9622 reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne);9917 reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne);
9623 }9918 }
96249919
9625 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);9920 for (liveness.deaths[case_i]) |operand| try self.processDeath(operand);
96269921
9627 for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc);9922 for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc);
9628 try self.genBody(case_body);9923 try self.genBody(case_body);
...@@ -9640,7 +9935,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9640,7 +9935,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
9640 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];9935 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
96419936
9642 const else_deaths = liveness.deaths.len - 1;9937 const else_deaths = liveness.deaths.len - 1;
9643 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);9938 for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand);
96449939
9645 try self.genBody(else_body);9940 try self.genBody(else_body);
9646 try self.restoreState(state, &.{}, .{9941 try self.restoreState(state, &.{}, .{
...@@ -9704,7 +9999,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9704,7 +9999,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
97049999
9705 // Process operand death so that it is properly accounted for in the State below.10000 // Process operand death so that it is properly accounted for in the State below.
9706 if (self.liveness.operandDies(inst, 0)) {10001 if (self.liveness.operandDies(inst, 0)) {
9707 if (Air.refToIndex(br.operand)) |op_inst| self.processDeath(op_inst);10002 if (Air.refToIndex(br.operand)) |op_inst| try self.processDeath(op_inst);
9708 }10003 }
970910004
9710 if (first_br) {10005 if (first_br) {
...@@ -9718,7 +10013,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -9718,7 +10013,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
9718 });10013 });
971910014
9720 // Stop tracking block result without forgetting tracking info10015 // Stop tracking block result without forgetting tracking info
9721 self.freeValue(block_tracking.short);10016 try self.freeValue(block_tracking.short);
972210017
9723 // Emit a jump with a relocation. It will be patched up after the block ends.10018 // Emit a jump with a relocation. It will be patched up after the block ends.
9724 // Leave the jump offset undefined10019 // Leave the jump offset undefined
...@@ -9754,9 +10049,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9754,9 +10049,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
975410049
9755 var outputs_extra_i = extra_i;10050 var outputs_extra_i = extra_i;
9756 for (outputs) |output| {10051 for (outputs) |output| {
9757 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);10052 const extra_bytes = mem.sliceAsBytes(self.air.extra[extra_i..]);
9758 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);10053 const constraint = mem.sliceTo(mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
9759 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);10054 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
9760 // This equation accounts for the fact that even if we have exactly 4 bytes10055 // This equation accounts for the fact that even if we have exactly 4 bytes
9761 // for the string, we still use the next u32 for the null terminator.10056 // for the string, we still use the next u32 for the null terminator.
9762 extra_i += (constraint.len + name.len + (2 + 3)) / 4;10057 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
...@@ -9769,22 +10064,35 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9769,22 +10064,35 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9769 .none => self.typeOfIndex(inst),10064 .none => self.typeOfIndex(inst),
9770 else => self.typeOf(output).childType(mod),10065 else => self.typeOf(output).childType(mod),
9771 };10066 };
9772 const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint, "=r"))10067 const is_read = switch (constraint[0]) {
9773 self.register_manager.tryAllocReg(maybe_inst, regClassForType(ty, mod)) orelse10068 '=' => false,
10069 '+' => read: {
10070 if (output == .none) return self.fail(
10071 "read-write constraint unsupported for asm result: '{s}'",
10072 .{constraint},
10073 );
10074 break :read true;
10075 },
10076 else => return self.fail("invalid constraint: '{s}'", .{constraint}),
10077 };
10078 const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint[1..], "r"))
10079 self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
9774 return self.fail("ran out of registers lowering inline asm", .{})10080 return self.fail("ran out of registers lowering inline asm", .{})
9775 else if (mem.eql(u8, constraint, "=m"))10081 else if (mem.eql(u8, constraint[1..], "m"))
9776 if (output != .none) null else return self.fail(10082 if (output != .none) null else return self.fail(
9777 "memory constraint unsupported for asm result",10083 "memory constraint unsupported for asm result: '{s}'",
9778 .{},10084 .{constraint},
9779 )
9780 else if (mem.eql(u8, constraint, "=g"))
9781 self.register_manager.tryAllocReg(maybe_inst, regClassForType(ty, mod)) orelse
9782 if (output != .none) null else return self.fail(
9783 "ran out of register lowering inline asm",
9784 .{},
9785 )10085 )
9786 else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}"))10086 else if (mem.eql(u8, constraint[1..], "g") or
9787 parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse10087 mem.eql(u8, constraint[1..], "rm") or mem.eql(u8, constraint[1..], "mr") or
10088 mem.eql(u8, constraint[1..], "r,m") or mem.eql(u8, constraint[1..], "m,r"))
10089 self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
10090 if (output != .none)
10091 null
10092 else
10093 return self.fail("ran out of registers lowering inline asm", .{})
10094 else if (mem.startsWith(u8, constraint[1..], "{") and mem.endsWith(u8, constraint[1..], "}"))
10095 parseRegName(constraint[1 + "{".len .. constraint.len - "}".len]) orelse
9788 return self.fail("invalid register constraint: '{s}'", .{constraint})10096 return self.fail("invalid register constraint: '{s}'", .{constraint})
9789 else10097 else
9790 return self.fail("invalid constraint: '{s}'", .{constraint});10098 return self.fail("invalid constraint: '{s}'", .{constraint});
...@@ -9801,16 +10109,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9801,16 +10109,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9801 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {10109 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
9802 _ = self.register_manager.lockRegAssumeUnused(reg);10110 _ = self.register_manager.lockRegAssumeUnused(reg);
9803 };10111 };
9804 if (!std.mem.eql(u8, name, "_"))10112 if (!mem.eql(u8, name, "_"))
9805 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));10113 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
9806 args.appendAssumeCapacity(arg_mcv);10114 args.appendAssumeCapacity(arg_mcv);
9807 if (output == .none) result = arg_mcv;10115 if (output == .none) result = arg_mcv;
10116 if (is_read) try self.load(arg_mcv, self.typeOf(output), .{ .air_ref = output });
9808 }10117 }
980910118
9810 for (inputs) |input| {10119 for (inputs) |input| {
9811 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);10120 const input_bytes = mem.sliceAsBytes(self.air.extra[extra_i..]);
9812 const constraint = std.mem.sliceTo(input_bytes, 0);10121 const constraint = mem.sliceTo(input_bytes, 0);
9813 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);10122 const name = mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
9814 // This equation accounts for the fact that even if we have exactly 4 bytes10123 // This equation accounts for the fact that even if we have exactly 4 bytes
9815 // for the string, we still use the next u32 for the null terminator.10124 // for the string, we still use the next u32 for the null terminator.
9816 extra_i += (constraint.len + name.len + (2 + 3)) / 4;10125 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
...@@ -9832,14 +10141,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9832,14 +10141,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9832 break :arg temp_mcv;10141 break :arg temp_mcv;
9833 },10142 },
9834 }10143 }
9835 const addr_reg = self.register_manager.tryAllocReg(null, gp) orelse {10144 const addr_reg = self.register_manager.tryAllocReg(null, abi.RegisterClass.gp) orelse {
9836 const temp_mcv = try self.allocTempRegOrMem(ty, false);10145 const temp_mcv = try self.allocTempRegOrMem(ty, false);
9837 try self.genCopy(ty, temp_mcv, input_mcv);10146 try self.genCopy(ty, temp_mcv, input_mcv);
9838 break :arg temp_mcv;10147 break :arg temp_mcv;
9839 };10148 };
9840 try self.genSetReg(addr_reg, Type.usize, input_mcv.address());10149 try self.genSetReg(addr_reg, Type.usize, input_mcv.address());
9841 break :arg .{ .indirect = .{ .reg = addr_reg } };10150 break :arg .{ .indirect = .{ .reg = addr_reg } };
9842 } else if (mem.eql(u8, constraint, "g")) arg: {10151 } else if (mem.eql(u8, constraint, "g") or
10152 mem.eql(u8, constraint, "rm") or mem.eql(u8, constraint, "mr") or
10153 mem.eql(u8, constraint, "r,m") or mem.eql(u8, constraint, "m,r"))
10154 arg: {
9843 switch (input_mcv) {10155 switch (input_mcv) {
9844 .register, .indirect, .load_frame => break :arg input_mcv,10156 .register, .indirect, .load_frame => break :arg input_mcv,
9845 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|10157 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
...@@ -9861,7 +10173,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9861,7 +10173,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9861 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {10173 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
9862 _ = self.register_manager.lockReg(reg);10174 _ = self.register_manager.lockReg(reg);
9863 };10175 };
9864 if (!std.mem.eql(u8, name, "_"))10176 if (!mem.eql(u8, name, "_"))
9865 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));10177 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
9866 args.appendAssumeCapacity(arg_mcv);10178 args.appendAssumeCapacity(arg_mcv);
9867 }10179 }
...@@ -9869,7 +10181,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9869,7 +10181,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9869 {10181 {
9870 var clobber_i: u32 = 0;10182 var clobber_i: u32 = 0;
9871 while (clobber_i < clobbers_len) : (clobber_i += 1) {10183 while (clobber_i < clobbers_len) : (clobber_i += 1) {
9872 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);10184 const clobber = mem.sliceTo(mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
9873 // This equation accounts for the fact that even if we have exactly 4 bytes10185 // This equation accounts for the fact that even if we have exactly 4 bytes
9874 // for the string, we still use the next u32 for the null terminator.10186 // for the string, we still use the next u32 for the null terminator.
9875 extra_i += clobber.len / 4 + 1;10187 extra_i += clobber.len / 4 + 1;
...@@ -9878,44 +10190,141 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9878,44 +10190,141 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9878 }10190 }
9879 }10191 }
988010192
10193 const Label = struct {
10194 target: Mir.Inst.Index = undefined,
10195 pending_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
10196
10197 const Kind = enum { definition, reference };
10198
10199 fn isValid(kind: Kind, name: []const u8) bool {
10200 for (name, 0..) |c, i| switch (c) {
10201 else => return false,
10202 '$' => if (i == 0) return false,
10203 '.' => {},
10204 '0'...'9' => if (i == 0) switch (kind) {
10205 .definition => if (name.len != 1) return false,
10206 .reference => {
10207 if (name.len != 2) return false;
10208 switch (name[1]) {
10209 else => return false,
10210 'B', 'F', 'b', 'f' => {},
10211 }
10212 },
10213 },
10214 '@', 'A'...'Z', '_', 'a'...'z' => {},
10215 };
10216 return name.len > 0;
10217 }
10218 };
10219 var labels: std.StringHashMapUnmanaged(Label) = .{};
10220 defer {
10221 var label_it = labels.valueIterator();
10222 while (label_it.next()) |label| label.pending_relocs.deinit(self.gpa);
10223 labels.deinit(self.gpa);
10224 }
10225
9881 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];10226 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
9882 var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");10227 var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");
9883 while (line_it.next()) |line| {10228 next_line: while (line_it.next()) |line| {
9884 var mnem_it = mem.tokenizeAny(u8, line, " \t");10229 var mnem_it = mem.tokenizeAny(u8, line, " \t");
9885 const mnem_str = mnem_it.next() orelse continue;10230 var prefix: Instruction.Prefix = .none;
9886 if (mem.startsWith(u8, mnem_str, "#")) continue;10231 const mnem_str = while (mnem_it.next()) |mnem_str| {
988710232 if (mem.startsWith(u8, mnem_str, "#")) continue :next_line;
9888 const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b"))10233 if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| {
9889 .byte10234 if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});
9890 else if (mem.endsWith(u8, mnem_str, "w"))10235 prefix = pre;
9891 .word10236 continue;
9892 else if (mem.endsWith(u8, mnem_str, "l"))10237 }
9893 .dword10238 if (!mem.endsWith(u8, mnem_str, ":")) break mnem_str;
9894 else if (mem.endsWith(u8, mnem_str, "q"))10239 const label_name = mnem_str[0 .. mnem_str.len - ":".len];
9895 .qword10240 if (!Label.isValid(.definition, label_name))
9896 else10241 return self.fail("invalid label: '{s}'", .{label_name});
9897 null;10242 const label_gop = try labels.getOrPut(self.gpa, label_name);
9898 const mnem_tag = Mir.Inst.FixedTag{ ._, mnem: {10243 if (!label_gop.found_existing) label_gop.value_ptr.* = .{} else {
9899 if (mnem_size) |_| {10244 const anon = std.ascii.isDigit(label_name[0]);
9900 if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {10245 if (!anon and label_gop.value_ptr.pending_relocs.items.len == 0)
9901 break :mnem mnem;10246 return self.fail("redefined label: '{s}'", .{label_name});
9902 }10247 for (label_gop.value_ptr.pending_relocs.items) |pending_reloc|
10248 try self.performReloc(pending_reloc);
10249 if (anon)
10250 label_gop.value_ptr.pending_relocs.clearRetainingCapacity()
10251 else
10252 label_gop.value_ptr.pending_relocs.clearAndFree(self.gpa);
9903 }10253 }
9904 break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse10254 label_gop.value_ptr.target = @intCast(self.mir_instructions.len);
9905 return self.fail("invalid mnemonic: '{s}'", .{mnem_str});10255 } else continue;
9906 } };10256
990710257 var mnem_size: ?Memory.PtrSize = null;
9908 var op_it = mem.tokenizeScalar(u8, mnem_it.rest(), ',');10258 const mnem_tag = mnem: {
9909 var ops = [1]encoder.Instruction.Operand{.none} ** 4;10259 mnem_size = if (mem.endsWith(u8, mnem_str, "b"))
9910 for (&ops) |*op| {10260 .byte
9911 const op_str = mem.trim(u8, op_it.next() orelse break, " \t");10261 else if (mem.endsWith(u8, mnem_str, "w"))
9912 if (mem.startsWith(u8, op_str, "#")) break;10262 .word
10263 else if (mem.endsWith(u8, mnem_str, "l"))
10264 .dword
10265 else if (mem.endsWith(u8, mnem_str, "q"))
10266 .qword
10267 else if (mem.endsWith(u8, mnem_str, "t"))
10268 .tbyte
10269 else
10270 break :mnem null;
10271 break :mnem std.meta.stringToEnum(Instruction.Mnemonic, mnem_str[0 .. mnem_str.len - 1]);
10272 } orelse mnem: {
10273 mnem_size = null;
10274 break :mnem std.meta.stringToEnum(Instruction.Mnemonic, mnem_str);
10275 } orelse return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
10276 const mnem_name = @tagName(mnem_tag);
10277 const mnem_fixed_tag: Mir.Inst.FixedTag = for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
10278 const fixes_name = @tagName(fixes);
10279 const space_i = mem.indexOfScalar(u8, fixes_name, ' ');
10280 const fixes_prefix = if (space_i) |i|
10281 std.meta.stringToEnum(Instruction.Prefix, fixes_name[0..i]).?
10282 else
10283 .none;
10284 if (fixes_prefix != prefix) continue;
10285 const pattern = fixes_name[if (space_i) |i| i + " ".len else 0..];
10286 const wildcard_i = mem.indexOfScalar(u8, pattern, '_').?;
10287 const mnem_prefix = pattern[0..wildcard_i];
10288 const mnem_suffix = pattern[wildcard_i + "_".len ..];
10289 if (!mem.startsWith(u8, mnem_name, mnem_prefix)) continue;
10290 if (!mem.endsWith(u8, mnem_name, mnem_suffix)) continue;
10291 break .{ fixes, std.meta.stringToEnum(
10292 Mir.Inst.Tag,
10293 mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len],
10294 ) orelse continue };
10295 } else {
10296 assert(prefix != .none);
10297 return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
10298 @tagName(prefix), mnem_str,
10299 });
10300 };
10301
10302 const Operand = union(enum) {
10303 none,
10304 reg: Register,
10305 mem: Memory,
10306 imm: Immediate,
10307 inst: Mir.Inst.Index,
10308 };
10309 var ops: [4]Operand = .{.none} ** 4;
10310
10311 var last_op = false;
10312 var op_it = mem.splitScalar(u8, mnem_it.rest(), ',');
10313 next_op: for (&ops) |*op| {
10314 const op_str = while (!last_op) {
10315 const full_str = op_it.next() orelse break :next_op;
10316 const trim_str = mem.trim(u8, if (mem.indexOfScalar(u8, full_str, '#')) |hash| hash: {
10317 last_op = true;
10318 break :hash full_str[0..hash];
10319 } else full_str, " \t");
10320 if (trim_str.len > 0) break trim_str;
10321 } else break;
9913 if (mem.startsWith(u8, op_str, "%%")) {10322 if (mem.startsWith(u8, op_str, "%%")) {
9914 const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');10323 const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');
9915 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse10324 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse
9916 return self.fail("invalid register: '{s}'", .{op_str});10325 return self.fail("invalid register: '{s}'", .{op_str});
9917 if (colon) |colon_pos| {10326 if (colon) |colon_pos| {
9918 const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch10327 const disp = std.fmt.parseInt(i32, op_str[colon_pos + ":".len ..], 0) catch
9919 return self.fail("invalid displacement: '{s}'", .{op_str});10328 return self.fail("invalid displacement: '{s}'", .{op_str});
9920 op.* = .{ .mem = Memory.sib(10329 op.* = .{ .mem = Memory.sib(
9921 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),10330 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
...@@ -9929,33 +10338,33 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9929,33 +10338,33 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9929 } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) {10338 } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) {
9930 const colon = mem.indexOfScalarPos(u8, op_str, "%[".len, ':');10339 const colon = mem.indexOfScalarPos(u8, op_str, "%[".len, ':');
9931 const modifier = if (colon) |colon_pos|10340 const modifier = if (colon) |colon_pos|
9932 op_str[colon_pos + 1 .. op_str.len - "]".len]10341 op_str[colon_pos + ":".len .. op_str.len - "]".len]
9933 else10342 else
9934 "";10343 "";
9935 op.* = switch (args.items[10344 op.* = switch (args.items[
9936 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse10345 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
9937 return self.fail("no matching constraint: '{s}'", .{op_str})10346 return self.fail("no matching constraint: '{s}'", .{op_str})
9938 ]) {10347 ]) {
9939 .register => |reg| if (std.mem.eql(u8, modifier, ""))10348 .register => |reg| if (mem.eql(u8, modifier, ""))
9940 .{ .reg = reg }10349 .{ .reg = reg }
9941 else10350 else
9942 return self.fail("invalid modifier: '{s}'", .{modifier}),10351 return self.fail("invalid modifier: '{s}'", .{modifier}),
9943 .memory => |addr| if (std.mem.eql(u8, modifier, "") or10352 .memory => |addr| if (mem.eql(u8, modifier, "") or
9944 std.mem.eql(u8, modifier, "P"))10353 mem.eql(u8, modifier, "P"))
9945 .{ .mem = Memory.sib(10354 .{ .mem = Memory.sib(
9946 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),10355 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
9947 .{ .base = .{ .reg = .ds }, .disp = @intCast(@as(i64, @bitCast(addr))) },10356 .{ .base = .{ .reg = .ds }, .disp = @intCast(@as(i64, @bitCast(addr))) },
9948 ) }10357 ) }
9949 else10358 else
9950 return self.fail("invalid modifier: '{s}'", .{modifier}),10359 return self.fail("invalid modifier: '{s}'", .{modifier}),
9951 .indirect => |reg_off| if (std.mem.eql(u8, modifier, ""))10360 .indirect => |reg_off| if (mem.eql(u8, modifier, ""))
9952 .{ .mem = Memory.sib(10361 .{ .mem = Memory.sib(
9953 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),10362 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
9954 .{ .base = .{ .reg = reg_off.reg }, .disp = reg_off.off },10363 .{ .base = .{ .reg = reg_off.reg }, .disp = reg_off.off },
9955 ) }10364 ) }
9956 else10365 else
9957 return self.fail("invalid modifier: '{s}'", .{modifier}),10366 return self.fail("invalid modifier: '{s}'", .{modifier}),
9958 .load_frame => |frame_addr| if (std.mem.eql(u8, modifier, ""))10367 .load_frame => |frame_addr| if (mem.eql(u8, modifier, ""))
9959 .{ .mem = Memory.sib(10368 .{ .mem = Memory.sib(
9960 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),10369 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
9961 .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off },10370 .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off },
...@@ -9980,64 +10389,113 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9980,64 +10389,113 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9980 }10389 }
9981 op.* = .{ .imm = Immediate.u(u) };10390 op.* = .{ .imm = Immediate.u(u) };
9982 } else |_| return self.fail("invalid immediate: '{s}'", .{op_str});10391 } else |_| return self.fail("invalid immediate: '{s}'", .{op_str});
10392 } else if (mem.endsWith(u8, op_str, ")")) {
10393 const open = mem.indexOfScalar(u8, op_str, '(') orelse
10394 return self.fail("invalid operand: '{s}'", .{op_str});
10395 var sib_it = mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ',');
10396 const base_str = sib_it.next() orelse
10397 return self.fail("invalid memory operand: '{s}'", .{op_str});
10398 if (base_str.len > 0 and !mem.startsWith(u8, base_str, "%%"))
10399 return self.fail("invalid memory operand: '{s}'", .{op_str});
10400 const index_str = sib_it.next() orelse "";
10401 if (index_str.len > 0 and !mem.startsWith(u8, base_str, "%%"))
10402 return self.fail("invalid memory operand: '{s}'", .{op_str});
10403 const scale_str = sib_it.next() orelse "";
10404 if (index_str.len == 0 and scale_str.len > 0)
10405 return self.fail("invalid memory operand: '{s}'", .{op_str});
10406 const scale = if (scale_str.len > 0) switch (std.fmt.parseInt(u4, scale_str, 10) catch
10407 return self.fail("invalid scale: '{s}'", .{op_str})) {
10408 1, 2, 4, 8 => |scale| scale,
10409 else => return self.fail("invalid scale: '{s}'", .{op_str}),
10410 } else 1;
10411 if (sib_it.next()) |_| return self.fail("invalid memory operand: '{s}'", .{op_str});
10412 op.* = .{ .mem = Memory.sib(mnem_size orelse
10413 return self.fail("unknown size: '{s}'", .{op_str}), .{
10414 .disp = if (open > 0) std.fmt.parseInt(i32, op_str[0..open], 0) catch
10415 return self.fail("invalid displacement: '{s}'", .{op_str}) else 0,
10416 .base = if (base_str.len > 0) .{ .reg = parseRegName(base_str["%%".len..]) orelse
10417 return self.fail("invalid base register: '{s}'", .{base_str}) } else .none,
10418 .scale_index = if (index_str.len > 0) .{
10419 .index = parseRegName(index_str["%%".len..]) orelse
10420 return self.fail("invalid index register: '{s}'", .{op_str}),
10421 .scale = scale,
10422 } else null,
10423 }) };
10424 } else if (Label.isValid(.reference, op_str)) {
10425 const anon = std.ascii.isDigit(op_str[0]);
10426 const label_gop = try labels.getOrPut(self.gpa, op_str[0..if (anon) 1 else op_str.len]);
10427 if (!label_gop.found_existing) label_gop.value_ptr.* = .{};
10428 if (anon and (op_str[1] == 'b' or op_str[1] == 'B') and !label_gop.found_existing)
10429 return self.fail("undefined label: '{s}'", .{op_str});
10430 const pending_relocs = &label_gop.value_ptr.pending_relocs;
10431 if (if (anon)
10432 op_str[1] == 'f' or op_str[1] == 'F'
10433 else
10434 !label_gop.found_existing or pending_relocs.items.len > 0)
10435 try pending_relocs.append(self.gpa, @intCast(self.mir_instructions.len));
10436 op.* = .{ .inst = label_gop.value_ptr.target };
9983 } else return self.fail("invalid operand: '{s}'", .{op_str});10437 } else return self.fail("invalid operand: '{s}'", .{op_str});
9984 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});10438 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});
998510439
9986 (switch (ops[0]) {10440 (switch (ops[0]) {
9987 .none => self.asmOpOnly(mnem_tag),10441 .none => self.asmOpOnly(mnem_fixed_tag),
9988 .reg => |reg0| switch (ops[1]) {10442 .reg => |reg0| switch (ops[1]) {
9989 .none => self.asmRegister(mnem_tag, reg0),10443 .none => self.asmRegister(mnem_fixed_tag, reg0),
9990 .reg => |reg1| switch (ops[2]) {10444 .reg => |reg1| switch (ops[2]) {
9991 .none => self.asmRegisterRegister(mnem_tag, reg1, reg0),10445 .none => self.asmRegisterRegister(mnem_fixed_tag, reg1, reg0),
9992 .reg => |reg2| switch (ops[3]) {10446 .reg => |reg2| switch (ops[3]) {
9993 .none => self.asmRegisterRegisterRegister(mnem_tag, reg2, reg1, reg0),10447 .none => self.asmRegisterRegisterRegister(mnem_fixed_tag, reg2, reg1, reg0),
9994 else => error.InvalidInstruction,10448 else => error.InvalidInstruction,
9995 },10449 },
9996 .mem => |mem2| switch (ops[3]) {10450 .mem => |mem2| switch (ops[3]) {
9997 .none => self.asmMemoryRegisterRegister(mnem_tag, mem2, reg1, reg0),10451 .none => self.asmMemoryRegisterRegister(mnem_fixed_tag, mem2, reg1, reg0),
9998 else => error.InvalidInstruction,10452 else => error.InvalidInstruction,
9999 },10453 },
10000 else => error.InvalidInstruction,10454 else => error.InvalidInstruction,
10001 },10455 },
10002 .mem => |mem1| switch (ops[2]) {10456 .mem => |mem1| switch (ops[2]) {
10003 .none => self.asmMemoryRegister(mnem_tag, mem1, reg0),10457 .none => self.asmMemoryRegister(mnem_fixed_tag, mem1, reg0),
10004 else => error.InvalidInstruction,10458 else => error.InvalidInstruction,
10005 },10459 },
10006 else => error.InvalidInstruction,10460 else => error.InvalidInstruction,
10007 },10461 },
10008 .mem => |mem0| switch (ops[1]) {10462 .mem => |mem0| switch (ops[1]) {
10009 .none => self.asmMemory(mnem_tag, mem0),10463 .none => self.asmMemory(mnem_fixed_tag, mem0),
10010 .reg => |reg1| switch (ops[2]) {10464 .reg => |reg1| switch (ops[2]) {
10011 .none => self.asmRegisterMemory(mnem_tag, reg1, mem0),10465 .none => self.asmRegisterMemory(mnem_fixed_tag, reg1, mem0),
10012 else => error.InvalidInstruction,10466 else => error.InvalidInstruction,
10013 },10467 },
10014 else => error.InvalidInstruction,10468 else => error.InvalidInstruction,
10015 },10469 },
10016 .imm => |imm0| switch (ops[1]) {10470 .imm => |imm0| switch (ops[1]) {
10017 .none => self.asmImmediate(mnem_tag, imm0),10471 .none => self.asmImmediate(mnem_fixed_tag, imm0),
10018 .reg => |reg1| switch (ops[2]) {10472 .reg => |reg1| switch (ops[2]) {
10019 .none => self.asmRegisterImmediate(mnem_tag, reg1, imm0),10473 .none => self.asmRegisterImmediate(mnem_fixed_tag, reg1, imm0),
10020 .reg => |reg2| switch (ops[3]) {10474 .reg => |reg2| switch (ops[3]) {
10021 .none => self.asmRegisterRegisterImmediate(mnem_tag, reg2, reg1, imm0),10475 .none => self.asmRegisterRegisterImmediate(mnem_fixed_tag, reg2, reg1, imm0),
10022 else => error.InvalidInstruction,10476 else => error.InvalidInstruction,
10023 },10477 },
10024 .mem => |mem2| switch (ops[3]) {10478 .mem => |mem2| switch (ops[3]) {
10025 .none => self.asmMemoryRegisterImmediate(mnem_tag, mem2, reg1, imm0),10479 .none => self.asmMemoryRegisterImmediate(mnem_fixed_tag, mem2, reg1, imm0),
10026 else => error.InvalidInstruction,10480 else => error.InvalidInstruction,
10027 },10481 },
10028 else => error.InvalidInstruction,10482 else => error.InvalidInstruction,
10029 },10483 },
10030 .mem => |mem1| switch (ops[2]) {10484 .mem => |mem1| switch (ops[2]) {
10031 .none => self.asmMemoryImmediate(mnem_tag, mem1, imm0),10485 .none => self.asmMemoryImmediate(mnem_fixed_tag, mem1, imm0),
10032 else => error.InvalidInstruction,10486 else => error.InvalidInstruction,
10033 },10487 },
10034 else => error.InvalidInstruction,10488 else => error.InvalidInstruction,
10035 },10489 },
10490 .inst => |inst0| switch (ops[1]) {
10491 .none => self.asmReloc(mnem_fixed_tag, inst0),
10492 else => error.InvalidInstruction,
10493 },
10036 }) catch |err| switch (err) {10494 }) catch |err| switch (err) {
10037 error.InvalidInstruction => return self.fail(10495 error.InvalidInstruction => return self.fail(
10038 "Invalid instruction: '{s} {s} {s} {s} {s}'",10496 "invalid instruction: '{s} {s} {s} {s} {s}'",
10039 .{10497 .{
10040 @tagName(mnem_tag[1]),10498 mnem_str,
10041 @tagName(ops[0]),10499 @tagName(ops[0]),
10042 @tagName(ops[1]),10500 @tagName(ops[1]),
10043 @tagName(ops[2]),10501 @tagName(ops[2]),
...@@ -10048,18 +10506,22 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -10048,18 +10506,22 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
10048 };10506 };
10049 }10507 }
1005010508
10051 for (outputs, args.items[0..outputs.len]) |output, mcv| {10509 var label_it = labels.iterator();
10052 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);10510 while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)
10511 return self.fail("undefined label: '{s}'", .{label.key_ptr.*});
10512
10513 for (outputs, args.items[0..outputs.len]) |output, arg_mcv| {
10514 const extra_bytes = mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);
10053 const constraint =10515 const constraint =
10054 std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0);10516 mem.sliceTo(mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0);
10055 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);10517 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
10056 // This equation accounts for the fact that even if we have exactly 4 bytes10518 // This equation accounts for the fact that even if we have exactly 4 bytes
10057 // for the string, we still use the next u32 for the null terminator.10519 // for the string, we still use the next u32 for the null terminator.
10058 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;10520 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
1005910521
10060 if (output == .none) continue;10522 if (output == .none) continue;
10061 if (mcv != .register) continue;10523 if (arg_mcv != .register) continue;
10062 try self.store(self.typeOf(output), try self.resolveInst(output), mcv);10524 try self.store(self.typeOf(output), .{ .air_ref = output }, arg_mcv);
10063 }10525 }
1006410526
10065 simple: {10527 simple: {
...@@ -10077,13 +10539,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -10077,13 +10539,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
10077 return self.finishAir(inst, result, buf);10539 return self.finishAir(inst, result, buf);
10078 }10540 }
10079 var bt = self.liveness.iterateBigTomb(inst);10541 var bt = self.liveness.iterateBigTomb(inst);
10080 for (outputs) |output| if (output != .none) self.feed(&bt, output);10542 for (outputs) |output| if (output != .none) try self.feed(&bt, output);
10081 for (inputs) |input| self.feed(&bt, input);10543 for (inputs) |input| try self.feed(&bt, input);
10082 return self.finishAirResult(inst, result);10544 return self.finishAirResult(inst, result);
10083}10545}
1008410546
10085const MoveStrategy = union(enum) {10547const MoveStrategy = union(enum) {
10086 move: Mir.Inst.FixedTag,10548 move: Mir.Inst.FixedTag,
10549 x87_load_store,
10087 insert_extract: InsertExtract,10550 insert_extract: InsertExtract,
10088 vex_insert_extract: InsertExtract,10551 vex_insert_extract: InsertExtract,
1008910552
...@@ -10091,6 +10554,44 @@ const MoveStrategy = union(enum) {...@@ -10091,6 +10554,44 @@ const MoveStrategy = union(enum) {
10091 insert: Mir.Inst.FixedTag,10554 insert: Mir.Inst.FixedTag,
10092 extract: Mir.Inst.FixedTag,10555 extract: Mir.Inst.FixedTag,
10093 };10556 };
10557
10558 pub fn read(strat: MoveStrategy, self: *Self, dst_reg: Register, src_mem: Memory) !void {
10559 switch (strat) {
10560 .move => |tag| try self.asmRegisterMemory(tag, dst_reg, src_mem),
10561 .x87_load_store => {
10562 try self.asmMemory(.{ .f_, .ld }, src_mem);
10563 try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1));
10564 },
10565 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
10566 ie.insert,
10567 dst_reg,
10568 src_mem,
10569 Immediate.u(0),
10570 ),
10571 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
10572 ie.insert,
10573 dst_reg,
10574 dst_reg,
10575 src_mem,
10576 Immediate.u(0),
10577 ),
10578 }
10579 }
10580 pub fn write(strat: MoveStrategy, self: *Self, dst_mem: Memory, src_reg: Register) !void {
10581 switch (strat) {
10582 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_reg),
10583 .x87_load_store => {
10584 try self.asmRegister(.{ .f_, .ld }, src_reg);
10585 try self.asmMemory(.{ .f_p, .st }, dst_mem);
10586 },
10587 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
10588 ie.extract,
10589 dst_mem,
10590 src_reg,
10591 Immediate.u(0),
10592 ),
10593 }
10594 }
10094};10595};
10095fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {10596fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {
10096 const mod = self.bin_file.options.module.?;10597 const mod = self.bin_file.options.module.?;
...@@ -10106,6 +10607,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {...@@ -10106,6 +10607,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {
10106 } },10607 } },
10107 32 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov } },10608 32 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov } },
10108 64 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov } },10609 64 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov } },
10610 80 => return .x87_load_store,
10109 128 => return .{ .move = if (self.hasFeature(.avx))10611 128 => return .{ .move = if (self.hasFeature(.avx))
10110 if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu }10612 if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu }
10111 else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } },10613 else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } },
...@@ -10274,10 +10776,12 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {...@@ -10274,10 +10776,12 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {
10274 else => {},10776 else => {},
10275 },10777 },
10276 }10778 }
10277 return self.fail("TODO moveStrategy for {}", .{ty.fmt(self.bin_file.options.module.?)});10779 return self.fail("TODO moveStrategy for {}", .{ty.fmt(mod)});
10278}10780}
1027910781
10280fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {10782fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
10783 const mod = self.bin_file.options.module.?;
10784
10281 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;10785 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
10282 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);10786 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
1028310787
...@@ -10315,18 +10819,31 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError...@@ -10315,18 +10819,31 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
10315 .off = -dst_reg_off.off,10819 .off = -dst_reg_off.off,
10316 } },10820 } },
10317 }),10821 }),
10318 .register_pair => |dst_regs| for (dst_regs, 0..) |dst_reg, dst_reg_i| switch (src_mcv) {10822 .register_pair => |dst_regs| {
10319 .register_pair => |src_regs| try self.genSetReg(10823 switch (src_mcv) {
10320 dst_reg,10824 .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)),
10321 Type.usize,10825 else => {},
10322 .{ .register = src_regs[dst_reg_i] },10826 }
10323 ),10827 const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, .other), .none);
10324 else => try self.genSetReg(10828 for (dst_regs, classes, 0..) |dst_reg, class, dst_reg_i| {
10325 dst_reg,10829 const class_ty = switch (class) {
10326 Type.usize,10830 .integer => Type.usize,
10327 src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(),10831 .sse => Type.f64,
10328 ),10832 else => unreachable,
10329 .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)),10833 };
10834 switch (src_mcv) {
10835 .register_pair => |src_regs| try self.genSetReg(
10836 dst_reg,
10837 class_ty,
10838 .{ .register = src_regs[dst_reg_i] },
10839 ),
10840 else => try self.genSetReg(
10841 dst_reg,
10842 class_ty,
10843 src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(),
10844 ),
10845 }
10846 }
10330 },10847 },
10331 .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),10848 .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),
10332 .memory, .load_direct, .load_got, .load_tlv => {10849 .memory, .load_direct, .load_got, .load_tlv => {
...@@ -10355,7 +10872,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError...@@ -10355,7 +10872,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
10355fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void {10872fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void {
10356 const mod = self.bin_file.options.module.?;10873 const mod = self.bin_file.options.module.?;
10357 const abi_size: u32 = @intCast(ty.abiSize(mod));10874 const abi_size: u32 = @intCast(ty.abiSize(mod));
10358 if (abi_size * 8 > dst_reg.bitSize())10875 if (ty.bitSize(mod) > dst_reg.bitSize())
10359 return self.fail("genSetReg called with a value larger than dst_reg", .{});10876 return self.fail("genSetReg called with a value larger than dst_reg", .{});
10360 switch (src_mcv) {10877 switch (src_mcv) {
10361 .none,10878 .none,
...@@ -10457,9 +10974,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10457,9 +10974,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10457 80 => null,10974 80 => null,
10458 else => unreachable,10975 else => unreachable,
10459 },10976 },
10460 }) orelse return self.fail("TODO implement genSetReg for {}", .{10977 }) orelse return self.fail("TODO implement genSetReg for {}", .{ty.fmt(mod)}),
10461 ty.fmt(self.bin_file.options.module.?),
10462 }),
10463 registerAlias(dst_reg, abi_size),10978 registerAlias(dst_reg, abi_size),
10464 registerAlias(src_reg, abi_size),10979 registerAlias(src_reg, abi_size),
10465 ),10980 ),
...@@ -10471,9 +10986,21 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10471,9 +10986,21 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10471 .indirect,10986 .indirect,
10472 .load_frame,10987 .load_frame,
10473 .lea_frame,10988 .lea_frame,
10474 => {10989 => try @as(MoveStrategy, switch (src_mcv) {
10475 const dst_alias = registerAlias(dst_reg, abi_size);10990 .register_offset => |reg_off| switch (reg_off.off) {
10476 const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {10991 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
10992 else => .{ .move = .{ ._, .lea } },
10993 },
10994 .indirect => try self.moveStrategy(ty, false),
10995 .load_frame => |frame_addr| try self.moveStrategy(
10996 ty,
10997 self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)),
10998 ),
10999 .lea_frame => .{ .move = .{ ._, .lea } },
11000 else => unreachable,
11001 }).read(self, registerAlias(dst_reg, abi_size), Memory.sib(
11002 self.memPtrSize(ty),
11003 switch (src_mcv) {
10477 .register_offset, .indirect => |reg_off| .{11004 .register_offset, .indirect => |reg_off| .{
10478 .base = .{ .reg = reg_off.reg },11005 .base = .{ .reg = reg_off.reg },
10479 .disp = reg_off.off,11006 .disp = reg_off.off,
...@@ -10483,64 +11010,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10483,64 +11010,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10483 .disp = frame_addr.off,11010 .disp = frame_addr.off,
10484 },11011 },
10485 else => unreachable,11012 else => unreachable,
10486 });11013 },
10487 switch (@as(MoveStrategy, switch (src_mcv) {11014 )),
10488 .register_offset => |reg_off| switch (reg_off.off) {
10489 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
10490 else => .{ .move = .{ ._, .lea } },
10491 },
10492 .indirect => try self.moveStrategy(ty, false),
10493 .load_frame => |frame_addr| try self.moveStrategy(
10494 ty,
10495 self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)),
10496 ),
10497 .lea_frame => .{ .move = .{ ._, .lea } },
10498 else => unreachable,
10499 })) {
10500 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
10501 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
10502 ie.insert,
10503 dst_alias,
10504 src_mem,
10505 Immediate.u(0),
10506 ),
10507 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
10508 ie.insert,
10509 dst_alias,
10510 dst_alias,
10511 src_mem,
10512 Immediate.u(0),
10513 ),
10514 }
10515 },
10516 .memory, .load_direct, .load_got, .load_tlv => {11015 .memory, .load_direct, .load_got, .load_tlv => {
10517 switch (src_mcv) {11016 switch (src_mcv) {
10518 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| {11017 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
10519 const dst_alias = registerAlias(dst_reg, abi_size);11018 return (try self.moveStrategy(
10520 const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), .{11019 ty,
10521 .base = .{ .reg = .ds },11020 ty.abiAlignment(mod).check(@as(u32, @bitCast(small_addr))),
10522 .disp = small_addr,11021 )).read(self, registerAlias(dst_reg, abi_size), Memory.sib(
10523 });11022 self.memPtrSize(ty),
10524 switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check(11023 .{ .base = .{ .reg = .ds }, .disp = small_addr },
10525 @as(u32, @bitCast(small_addr)),11024 )),
10526 ))) {
10527 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
10528 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
10529 ie.insert,
10530 dst_alias,
10531 src_mem,
10532 Immediate.u(0),
10533 ),
10534 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
10535 ie.insert,
10536 dst_alias,
10537 dst_alias,
10538 src_mem,
10539 Immediate.u(0),
10540 ),
10541 }
10542 return;
10543 },
10544 .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) {11025 .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) {
10545 else => {11026 else => {
10546 const atom_index = try self.owner.getSymbolIndex(self);11027 const atom_index = try self.owner.getSymbolIndex(self);
...@@ -10567,26 +11048,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10567,26 +11048,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10567 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);11048 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
10568 defer self.register_manager.unlockReg(addr_lock);11049 defer self.register_manager.unlockReg(addr_lock);
1056911050
10570 const dst_alias = registerAlias(dst_reg, abi_size);11051 try (try self.moveStrategy(ty, false)).read(
10571 const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), .{11052 self,
10572 .base = .{ .reg = addr_reg },11053 registerAlias(dst_reg, abi_size),
10573 });11054 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .{ .reg = addr_reg } }),
10574 switch (try self.moveStrategy(ty, false)) {11055 );
10575 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
10576 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
10577 ie.insert,
10578 dst_alias,
10579 src_mem,
10580 Immediate.u(0),
10581 ),
10582 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
10583 ie.insert,
10584 dst_alias,
10585 dst_alias,
10586 src_mem,
10587 Immediate.u(0),
10588 ),
10589 }
10590 },11056 },
10591 .lea_direct, .lea_got => |sym_index| {11057 .lea_direct, .lea_got => |sym_index| {
10592 const atom_index = try self.owner.getSymbolIndex(self);11058 const atom_index = try self.owner.getSymbolIndex(self);
...@@ -10683,39 +11149,23 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -10683,39 +11149,23 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
10683 },11149 },
10684 },11150 },
10685 .eflags => |cc| try self.asmSetccMemory(Memory.sib(.byte, .{ .base = base, .disp = disp }), cc),11151 .eflags => |cc| try self.asmSetccMemory(Memory.sib(.byte, .{ .base = base, .disp = disp }), cc),
10686 .register => |src_reg| {11152 .register => |src_reg| try (try self.moveStrategy(ty, switch (base) {
10687 const dst_mem = Memory.sib(11153 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10688 Memory.PtrSize.fromSize(abi_size),11154 .reg => |reg| switch (reg) {
10689 .{ .base = base, .disp = disp },11155 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10690 );11156 else => false,
10691 const src_alias = registerAlias(src_reg, abi_size);11157 },
10692 switch (try self.moveStrategy(ty, switch (base) {11158 .frame => |frame_index| self.getFrameAddrAlignment(
10693 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),11159 .{ .index = frame_index, .off = disp },
10694 .reg => |reg| switch (reg) {11160 ).compare(.gte, ty.abiAlignment(mod)),
10695 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),11161 })).write(
10696 else => false,11162 self,
10697 },11163 Memory.sib(self.memPtrSize(ty), .{ .base = base, .disp = disp }),
10698 .frame => |frame_index| self.getFrameAddrAlignment(11164 registerAlias(src_reg, abi_size),
10699 .{ .index = frame_index, .off = disp },11165 ),
10700 ).compare(.gte, ty.abiAlignment(mod)),
10701 })) {
10702 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),
10703 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
10704 ie.extract,
10705 dst_mem,
10706 src_alias,
10707 Immediate.u(0),
10708 ),
10709 }
10710 },
10711 .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| {11166 .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| {
10712 const part_size = @min(abi_size - src_reg_i * 8, 8);11167 const part_size = @min(abi_size - src_reg_i * 8, 8);
10713 const dst_mem = Memory.sib(11168 try (try self.moveStrategy(ty, switch (base) {
10714 Memory.PtrSize.fromSize(part_size),
10715 .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) },
10716 );
10717 const src_alias = registerAlias(src_reg, part_size);
10718 switch (try self.moveStrategy(ty, switch (base) {
10719 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),11169 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10720 .reg => |reg| switch (reg) {11170 .reg => |reg| switch (reg) {
10721 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),11171 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
...@@ -10724,15 +11174,10 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -10724,15 +11174,10 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
10724 .frame => |frame_index| self.getFrameAddrAlignment(11174 .frame => |frame_index| self.getFrameAddrAlignment(
10725 .{ .index = frame_index, .off = disp },11175 .{ .index = frame_index, .off = disp },
10726 ).compare(.gte, ty.abiAlignment(mod)),11176 ).compare(.gte, ty.abiAlignment(mod)),
10727 })) {11177 })).write(self, Memory.sib(
10728 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),11178 Memory.PtrSize.fromSize(part_size),
10729 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(11179 .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) },
10730 ie.extract,11180 ), registerAlias(src_reg, part_size));
10731 dst_mem,
10732 src_alias,
10733 Immediate.u(0),
10734 ),
10735 }
10736 },11181 },
10737 .register_overflow => |ro| {11182 .register_overflow => |ro| {
10738 try self.genSetMem(11183 try self.genSetMem(
...@@ -10953,8 +11398,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -10953,8 +11398,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
10953 const src_ty = self.typeOf(ty_op.operand);11398 const src_ty = self.typeOf(ty_op.operand);
1095411399
10955 const result = result: {11400 const result = result: {
10956 const dst_rc = regClassForType(dst_ty, mod);11401 const dst_rc = self.regClassForType(dst_ty);
10957 const src_rc = regClassForType(src_ty, mod);11402 const src_rc = self.regClassForType(src_ty);
10958 const src_mcv = try self.resolveInst(ty_op.operand);11403 const src_mcv = try self.resolveInst(ty_op.operand);
1095911404
10960 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;11405 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
...@@ -10973,11 +11418,15 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -10973,11 +11418,15 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
10973 break :dst dst_mcv;11418 break :dst dst_mcv;
10974 };11419 };
1097511420
11421 if (dst_ty.isRuntimeFloat()) break :result dst_mcv;
11422
10976 const dst_signedness =11423 const dst_signedness =
10977 if (dst_ty.isAbiInt(mod)) dst_ty.intInfo(mod).signedness else .unsigned;11424 if (dst_ty.isAbiInt(mod)) dst_ty.intInfo(mod).signedness else .unsigned;
10978 const src_signedness =11425 if (!src_ty.isRuntimeFloat() or src_ty.floatBits(self.target.*) != 80) {
10979 if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned;11426 const src_signedness =
10980 if (dst_signedness == src_signedness) break :result dst_mcv;11427 if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned;
11428 if (dst_signedness == src_signedness) break :result dst_mcv;
11429 }
1098111430
10982 const abi_size: u16 = @intCast(dst_ty.abiSize(mod));11431 const abi_size: u16 = @intCast(dst_ty.abiSize(mod));
10983 const bit_size: u16 = @intCast(dst_ty.bitSize(mod));11432 const bit_size: u16 = @intCast(dst_ty.bitSize(mod));
...@@ -11049,9 +11498,13 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -11049,9 +11498,13 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
11049 const result = result: {11498 const result = result: {
11050 if (switch (dst_bits) {11499 if (switch (dst_bits) {
11051 16, 80, 128 => true,11500 16, 80, 128 => true,
11052 32, 64 => src_size > 8 and src_size < 16,11501 32, 64 => src_size > 8,
11053 else => unreachable,11502 else => unreachable,
11054 }) {11503 }) {
11504 if (src_bits > 128) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
11505 src_ty.fmt(mod), dst_ty.fmt(mod),
11506 });
11507
11055 var callee: ["__floatun?i?f".len]u8 = undefined;11508 var callee: ["__floatun?i?f".len]u8 = undefined;
11056 break :result try self.genCall(.{ .lib = .{11509 break :result try self.genCall(.{ .lib = .{
11057 .return_type = dst_ty.toIntern(),11510 .return_type = dst_ty.toIntern(),
...@@ -11067,10 +11520,6 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -11067,10 +11520,6 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
11067 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});11520 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
11068 }11521 }
1106911522
11070 if (src_size > 8) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
11071 src_ty.fmt(mod), dst_ty.fmt(mod),
11072 });
11073
11074 const src_mcv = try self.resolveInst(ty_op.operand);11523 const src_mcv = try self.resolveInst(ty_op.operand);
11075 const src_reg = if (src_mcv.isRegister())11524 const src_reg = if (src_mcv.isRegister())
11076 src_mcv.getReg().?11525 src_mcv.getReg().?
...@@ -11081,7 +11530,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -11081,7 +11530,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
1108111530
11082 if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);11531 if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);
1108311532
11084 const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));11533 const dst_reg = try self.register_manager.allocReg(inst, self.regClassForType(dst_ty));
11085 const dst_mcv = MCValue{ .register = dst_reg };11534 const dst_mcv = MCValue{ .register = dst_reg };
11086 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);11535 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
11087 defer self.register_manager.unlockReg(dst_lock);11536 defer self.register_manager.unlockReg(dst_lock);
...@@ -11128,9 +11577,13 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -11128,9 +11577,13 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
11128 const result = result: {11577 const result = result: {
11129 if (switch (src_bits) {11578 if (switch (src_bits) {
11130 16, 80, 128 => true,11579 16, 80, 128 => true,
11131 32, 64 => dst_size > 8 and dst_size < 16,11580 32, 64 => dst_size > 8,
11132 else => unreachable,11581 else => unreachable,
11133 }) {11582 }) {
11583 if (dst_bits > 128) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
11584 src_ty.fmt(mod), dst_ty.fmt(mod),
11585 });
11586
11134 var callee: ["__fixuns?f?i".len]u8 = undefined;11587 var callee: ["__fixuns?f?i".len]u8 = undefined;
11135 break :result try self.genCall(.{ .lib = .{11588 break :result try self.genCall(.{ .lib = .{
11136 .return_type = dst_ty.toIntern(),11589 .return_type = dst_ty.toIntern(),
...@@ -11146,10 +11599,6 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -11146,10 +11599,6 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
11146 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});11599 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
11147 }11600 }
1114811601
11149 if (dst_size > 8) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
11150 src_ty.fmt(mod), dst_ty.fmt(mod),
11151 });
11152
11153 const src_mcv = try self.resolveInst(ty_op.operand);11602 const src_mcv = try self.resolveInst(ty_op.operand);
11154 const src_reg = if (src_mcv.isRegister())11603 const src_reg = if (src_mcv.isRegister())
11155 src_mcv.getReg().?11604 src_mcv.getReg().?
...@@ -11158,7 +11607,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -11158,7 +11607,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
11158 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);11607 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
11159 defer self.register_manager.unlockReg(src_lock);11608 defer self.register_manager.unlockReg(src_lock);
1116011609
11161 const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));11610 const dst_reg = try self.register_manager.allocReg(inst, self.regClassForType(dst_ty));
11162 const dst_mcv = MCValue{ .register = dst_reg };11611 const dst_mcv = MCValue{ .register = dst_reg };
11163 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);11612 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
11164 defer self.register_manager.unlockReg(dst_lock);11613 defer self.register_manager.unlockReg(dst_lock);
...@@ -11339,7 +11788,7 @@ fn atomicOp(...@@ -11339,7 +11788,7 @@ fn atomicOp(
11339 .SeqCst => .xchg,11788 .SeqCst => .xchg,
11340 };11789 };
1134111790
11342 const dst_reg = try self.register_manager.allocReg(null, gp);11791 const dst_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11343 const dst_mcv = MCValue{ .register = dst_reg };11792 const dst_mcv = MCValue{ .register = dst_reg };
11344 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);11793 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
11345 defer self.register_manager.unlockReg(dst_lock);11794 defer self.register_manager.unlockReg(dst_lock);
...@@ -11361,13 +11810,13 @@ fn atomicOp(...@@ -11361,13 +11810,13 @@ fn atomicOp(
11361 return if (unused) .unreach else dst_mcv;11810 return if (unused) .unreach else dst_mcv;
11362 },11811 },
11363 .loop => _ = if (val_abi_size <= 8) {11812 .loop => _ = if (val_abi_size <= 8) {
11364 const tmp_reg = try self.register_manager.allocReg(null, gp);11813 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11365 const tmp_mcv = MCValue{ .register = tmp_reg };11814 const tmp_mcv = MCValue{ .register = tmp_reg };
11366 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);11815 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
11367 defer self.register_manager.unlockReg(tmp_lock);11816 defer self.register_manager.unlockReg(tmp_lock);
1136811817
11369 try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(.rax, val_abi_size), ptr_mem);11818 try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(.rax, val_abi_size), ptr_mem);
11370 const loop: u32 = @intCast(self.mir_instructions.len);11819 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
11371 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {11820 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
11372 try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax });11821 try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax });
11373 }11822 }
...@@ -11441,7 +11890,7 @@ fn atomicOp(...@@ -11441,7 +11890,7 @@ fn atomicOp(
11441 .scale_index = ptr_mem.scaleIndex(),11890 .scale_index = ptr_mem.scaleIndex(),
11442 .disp = ptr_mem.sib.disp + 8,11891 .disp = ptr_mem.sib.disp + 8,
11443 }));11892 }));
11444 const loop: u32 = @intCast(self.mir_instructions.len);11893 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
11445 const val_mem_mcv: MCValue = switch (val_mcv) {11894 const val_mem_mcv: MCValue = switch (val_mcv) {
11446 .memory, .indirect, .load_frame => val_mcv,11895 .memory, .indirect, .load_frame => val_mcv,
11447 else => .{ .indirect = .{11896 else => .{ .indirect = .{
...@@ -11486,7 +11935,7 @@ fn atomicOp(...@@ -11486,7 +11935,7 @@ fn atomicOp(
11486 try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem);11935 try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem);
11487 },11936 },
11488 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{11937 else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{
11489 val_ty.fmt(self.bin_file.options.module.?), @tagName(op),11938 val_ty.fmt(mod), @tagName(op),
11490 }),11939 }),
11491 };11940 };
11492 try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);11941 try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
...@@ -11635,7 +12084,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -11635,7 +12084,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
1163512084
11636 // Used to store the number of elements for comparison.12085 // Used to store the number of elements for comparison.
11637 // After comparison, updated to store number of bytes needed to copy.12086 // After comparison, updated to store number of bytes needed to copy.
11638 const len_reg = try self.register_manager.allocReg(null, gp);12087 const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11639 const len_mcv: MCValue = .{ .register = len_reg };12088 const len_mcv: MCValue = .{ .register = len_reg };
11640 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);12089 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
11641 defer self.register_manager.unlockReg(len_lock);12090 defer self.register_manager.unlockReg(len_lock);
...@@ -11645,7 +12094,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -11645,7 +12094,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
11645 const skip_reloc = try self.asmJccReloc(undefined, .z);12094 const skip_reloc = try self.asmJccReloc(undefined, .z);
11646 try self.store(slice_ptr_ty, ptr, src_val);12095 try self.store(slice_ptr_ty, ptr, src_val);
1164712096
11648 const second_elem_ptr_reg = try self.register_manager.allocReg(null, gp);12097 const second_elem_ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11649 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };12098 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
11650 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);12099 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
11651 defer self.register_manager.unlockReg(second_elem_ptr_lock);12100 defer self.register_manager.unlockReg(second_elem_ptr_lock);
...@@ -11674,7 +12123,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -11674,7 +12123,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
11674 assert(len != 0); // prevented by Sema12123 assert(len != 0); // prevented by Sema
11675 try self.store(elem_ptr_ty, dst_ptr, src_val);12124 try self.store(elem_ptr_ty, dst_ptr, src_val);
1167612125
11677 const second_elem_ptr_reg = try self.register_manager.allocReg(null, gp);12126 const second_elem_ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11678 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };12127 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
11679 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);12128 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
11680 defer self.register_manager.unlockReg(second_elem_ptr_lock);12129 defer self.register_manager.unlockReg(second_elem_ptr_lock);
...@@ -11781,16 +12230,16 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -11781,16 +12230,16 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
11781 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);12230 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
11782 defer self.register_manager.unlockReg(err_lock);12231 defer self.register_manager.unlockReg(err_lock);
1178312232
11784 const addr_reg = try self.register_manager.allocReg(null, gp);12233 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11785 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);12234 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
11786 defer self.register_manager.unlockReg(addr_lock);12235 defer self.register_manager.unlockReg(addr_lock);
11787 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));12236 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
1178812237
11789 const start_reg = try self.register_manager.allocReg(null, gp);12238 const start_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11790 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);12239 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);
11791 defer self.register_manager.unlockReg(start_lock);12240 defer self.register_manager.unlockReg(start_lock);
1179212241
11793 const end_reg = try self.register_manager.allocReg(null, gp);12242 const end_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
11794 const end_lock = self.register_manager.lockRegAssumeUnused(end_reg);12243 const end_lock = self.register_manager.lockRegAssumeUnused(end_reg);
11795 defer self.register_manager.unlockReg(end_lock);12244 defer self.register_manager.unlockReg(end_lock);
1179612245
...@@ -11858,7 +12307,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -11858,7 +12307,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
11858 const mod = self.bin_file.options.module.?;12307 const mod = self.bin_file.options.module.?;
11859 const ty_op = self.air.instructions.items(.data)[inst].ty_op;12308 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11860 const vector_ty = self.typeOfIndex(inst);12309 const vector_ty = self.typeOfIndex(inst);
11861 const dst_rc = regClassForType(vector_ty, mod);12310 const dst_rc = self.regClassForType(vector_ty);
11862 const scalar_ty = vector_ty.scalarType(mod);12311 const scalar_ty = vector_ty.scalarType(mod);
1186312312
11864 const src_mcv = try self.resolveInst(ty_op.operand);12313 const src_mcv = try self.resolveInst(ty_op.operand);
...@@ -12046,9 +12495,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -12046,9 +12495,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
12046 else => unreachable,12495 else => unreachable,
12047 },12496 },
12048 }12497 }
12049 return self.fail("TODO implement airSplat for {}", .{12498 return self.fail("TODO implement airSplat for {}", .{vector_ty.fmt(mod)});
12050 vector_ty.fmt(self.bin_file.options.module.?),
12051 });
12052 };12499 };
12053 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });12500 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12054}12501}
...@@ -12214,7 +12661,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -12214,7 +12661,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
12214 return self.finishAir(inst, result, buf);12661 return self.finishAir(inst, result, buf);
12215 }12662 }
12216 var bt = self.liveness.iterateBigTomb(inst);12663 var bt = self.liveness.iterateBigTomb(inst);
12217 for (elements) |elem| self.feed(&bt, elem);12664 for (elements) |elem| try self.feed(&bt, elem);
12218 return self.finishAirResult(inst, result);12665 return self.finishAirResult(inst, result);
12219}12666}
1222012667
...@@ -12274,146 +12721,411 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {...@@ -12274,146 +12721,411 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
12274 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;12721 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
12275 const ty = self.typeOfIndex(inst);12722 const ty = self.typeOfIndex(inst);
1227612723
12277 if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{
12278 ty.fmt(self.bin_file.options.module.?),
12279 });
12280
12281 const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand };12724 const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand };
12282 var mcvs: [3]MCValue = undefined;12725 const result = result: {
12283 var locks = [1]?RegisterManager.RegisterLock{null} ** 3;12726 if (switch (ty.scalarType(mod).floatBits(self.target.*)) {
12284 defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);12727 16, 80, 128 => true,
12285 var order = [1]u2{0} ** 3;12728 32, 64 => !self.hasFeature(.fma),
12286 var unused = std.StaticBitSet(3).initFull();12729 else => unreachable,
12287 for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| {12730 }) {
12288 const op_index: u2 = @intCast(op_i);12731 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement airMulAdd for {}", .{
12289 mcv.* = try self.resolveInst(op);12732 ty.fmt(mod),
12290 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {12733 });
12291 order[op_index] = 1;12734
12292 unused.unset(0);12735 var callee: ["__fma?".len]u8 = undefined;
12293 } else if (unused.isSet(2) and mcv.isMemory()) {12736 break :result try self.genCall(.{ .lib = .{
12294 order[op_index] = 3;12737 .return_type = ty.toIntern(),
12295 unused.unset(2);12738 .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() },
12739 .callee = std.fmt.bufPrint(&callee, "{s}fma{s}", .{
12740 floatLibcAbiPrefix(ty),
12741 floatLibcAbiSuffix(ty),
12742 }) catch unreachable,
12743 } }, &.{ ty, ty, ty }, &.{
12744 .{ .air_ref = extra.lhs }, .{ .air_ref = extra.rhs }, .{ .air_ref = pl_op.operand },
12745 });
12296 }12746 }
12297 switch (mcv.*) {12747
12298 .register => |reg| lock.* = self.register_manager.lockReg(reg),12748 var mcvs: [3]MCValue = undefined;
12299 else => {},12749 var locks = [1]?RegisterManager.RegisterLock{null} ** 3;
12750 defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
12751 var order = [1]u2{0} ** 3;
12752 var unused = std.StaticBitSet(3).initFull();
12753 for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| {
12754 const op_index: u2 = @intCast(op_i);
12755 mcv.* = try self.resolveInst(op);
12756 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {
12757 order[op_index] = 1;
12758 unused.unset(0);
12759 } else if (unused.isSet(2) and mcv.isMemory()) {
12760 order[op_index] = 3;
12761 unused.unset(2);
12762 }
12763 switch (mcv.*) {
12764 .register => |reg| lock.* = self.register_manager.lockReg(reg),
12765 else => {},
12766 }
12767 }
12768 for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| {
12769 if (mop_index.* != 0) continue;
12770 mop_index.* = 1 + @as(u2, @intCast(unused.toggleFirstSet().?));
12771 if (mop_index.* > 1 and mcv.isRegister()) continue;
12772 const reg = try self.copyToTmpRegister(ty, mcv.*);
12773 mcv.* = .{ .register = reg };
12774 if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock);
12775 lock.* = self.register_manager.lockRegAssumeUnused(reg);
12300 }12776 }
12301 }
12302 for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| {
12303 if (mop_index.* != 0) continue;
12304 mop_index.* = 1 + @as(u2, @intCast(unused.toggleFirstSet().?));
12305 if (mop_index.* > 1 and mcv.isRegister()) continue;
12306 const reg = try self.copyToTmpRegister(ty, mcv.*);
12307 mcv.* = .{ .register = reg };
12308 if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock);
12309 lock.* = self.register_manager.lockRegAssumeUnused(reg);
12310 }
1231112777
12312 const mir_tag = @as(?Mir.Inst.FixedTag, if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or12778 const mir_tag = @as(?Mir.Inst.FixedTag, if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or
12313 mem.eql(u2, &order, &.{ 3, 1, 2 }))12779 mem.eql(u2, &order, &.{ 3, 1, 2 }))
12314 switch (ty.zigTypeTag(mod)) {12780 switch (ty.zigTypeTag(mod)) {
12315 .Float => switch (ty.floatBits(self.target.*)) {12781 .Float => switch (ty.floatBits(self.target.*)) {
12316 32 => .{ .v_ss, .fmadd132 },12782 32 => .{ .v_ss, .fmadd132 },
12317 64 => .{ .v_sd, .fmadd132 },12783 64 => .{ .v_sd, .fmadd132 },
12318 16, 80, 128 => null,
12319 else => unreachable,
12320 },
12321 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
12322 .Float => switch (ty.childType(mod).floatBits(self.target.*)) {
12323 32 => switch (ty.vectorLen(mod)) {
12324 1 => .{ .v_ss, .fmadd132 },
12325 2...8 => .{ .v_ps, .fmadd132 },
12326 else => null,
12327 },
12328 64 => switch (ty.vectorLen(mod)) {
12329 1 => .{ .v_sd, .fmadd132 },
12330 2...4 => .{ .v_pd, .fmadd132 },
12331 else => null,
12332 },
12333 16, 80, 128 => null,12784 16, 80, 128 => null,
12334 else => unreachable,12785 else => unreachable,
12335 },12786 },
12336 else => unreachable,12787 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
12337 },12788 .Float => switch (ty.childType(mod).floatBits(self.target.*)) {
12338 else => unreachable,12789 32 => switch (ty.vectorLen(mod)) {
12339 }12790 1 => .{ .v_ss, .fmadd132 },
12340 else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 }))12791 2...8 => .{ .v_ps, .fmadd132 },
12341 switch (ty.zigTypeTag(mod)) {12792 else => null,
12342 .Float => switch (ty.floatBits(self.target.*)) {12793 },
12343 32 => .{ .v_ss, .fmadd213 },12794 64 => switch (ty.vectorLen(mod)) {
12344 64 => .{ .v_sd, .fmadd213 },12795 1 => .{ .v_sd, .fmadd132 },
12345 16, 80, 128 => null,12796 2...4 => .{ .v_pd, .fmadd132 },
12346 else => unreachable,12797 else => null,
12347 },12798 },
12348 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {12799 16, 80, 128 => null,
12349 .Float => switch (ty.childType(mod).floatBits(self.target.*)) {12800 else => unreachable,
12350 32 => switch (ty.vectorLen(mod)) {
12351 1 => .{ .v_ss, .fmadd213 },
12352 2...8 => .{ .v_ps, .fmadd213 },
12353 else => null,
12354 },
12355 64 => switch (ty.vectorLen(mod)) {
12356 1 => .{ .v_sd, .fmadd213 },
12357 2...4 => .{ .v_pd, .fmadd213 },
12358 else => null,
12359 },12801 },
12360 16, 80, 128 => null,
12361 else => unreachable,12802 else => unreachable,
12362 },12803 },
12363 else => unreachable,12804 else => unreachable,
12364 },12805 }
12365 else => unreachable,12806 else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 }))
12366 }12807 switch (ty.zigTypeTag(mod)) {
12367 else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 }))12808 .Float => switch (ty.floatBits(self.target.*)) {
12368 switch (ty.zigTypeTag(mod)) {12809 32 => .{ .v_ss, .fmadd213 },
12369 .Float => switch (ty.floatBits(self.target.*)) {12810 64 => .{ .v_sd, .fmadd213 },
12370 32 => .{ .v_ss, .fmadd231 },12811 16, 80, 128 => null,
12371 64 => .{ .v_sd, .fmadd231 },12812 else => unreachable,
12372 16, 80, 128 => null,12813 },
12373 else => unreachable,12814 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
12374 },12815 .Float => switch (ty.childType(mod).floatBits(self.target.*)) {
12375 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {12816 32 => switch (ty.vectorLen(mod)) {
12376 .Float => switch (ty.childType(mod).floatBits(self.target.*)) {12817 1 => .{ .v_ss, .fmadd213 },
12377 32 => switch (ty.vectorLen(mod)) {12818 2...8 => .{ .v_ps, .fmadd213 },
12378 1 => .{ .v_ss, .fmadd231 },12819 else => null,
12379 2...8 => .{ .v_ps, .fmadd231 },12820 },
12380 else => null,12821 64 => switch (ty.vectorLen(mod)) {
12381 },12822 1 => .{ .v_sd, .fmadd213 },
12382 64 => switch (ty.vectorLen(mod)) {12823 2...4 => .{ .v_pd, .fmadd213 },
12383 1 => .{ .v_sd, .fmadd231 },12824 else => null,
12384 2...4 => .{ .v_pd, .fmadd231 },12825 },
12385 else => null,12826 16, 80, 128 => null,
12827 else => unreachable,
12386 },12828 },
12829 else => unreachable,
12830 },
12831 else => unreachable,
12832 }
12833 else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 }))
12834 switch (ty.zigTypeTag(mod)) {
12835 .Float => switch (ty.floatBits(self.target.*)) {
12836 32 => .{ .v_ss, .fmadd231 },
12837 64 => .{ .v_sd, .fmadd231 },
12387 16, 80, 128 => null,12838 16, 80, 128 => null,
12388 else => unreachable,12839 else => unreachable,
12389 },12840 },
12841 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
12842 .Float => switch (ty.childType(mod).floatBits(self.target.*)) {
12843 32 => switch (ty.vectorLen(mod)) {
12844 1 => .{ .v_ss, .fmadd231 },
12845 2...8 => .{ .v_ps, .fmadd231 },
12846 else => null,
12847 },
12848 64 => switch (ty.vectorLen(mod)) {
12849 1 => .{ .v_sd, .fmadd231 },
12850 2...4 => .{ .v_pd, .fmadd231 },
12851 else => null,
12852 },
12853 16, 80, 128 => null,
12854 else => unreachable,
12855 },
12856 else => unreachable,
12857 },
12390 else => unreachable,12858 else => unreachable,
12391 },12859 }
12392 else => unreachable,12860 else
12393 }12861 unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(mod)});
12394 else
12395 unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{
12396 ty.fmt(self.bin_file.options.module.?),
12397 });
1239812862
12399 var mops: [3]MCValue = undefined;12863 var mops: [3]MCValue = undefined;
12400 for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv;12864 for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv;
1240112865
12402 const abi_size: u32 = @intCast(ty.abiSize(mod));12866 const abi_size: u32 = @intCast(ty.abiSize(mod));
12403 const mop1_reg = registerAlias(mops[0].getReg().?, abi_size);12867 const mop1_reg = registerAlias(mops[0].getReg().?, abi_size);
12404 const mop2_reg = registerAlias(mops[1].getReg().?, abi_size);12868 const mop2_reg = registerAlias(mops[1].getReg().?, abi_size);
12405 if (mops[2].isRegister()) try self.asmRegisterRegisterRegister(12869 if (mops[2].isRegister()) try self.asmRegisterRegisterRegister(
12406 mir_tag,12870 mir_tag,
12407 mop1_reg,12871 mop1_reg,
12408 mop2_reg,12872 mop2_reg,
12409 registerAlias(mops[2].getReg().?, abi_size),12873 registerAlias(mops[2].getReg().?, abi_size),
12410 ) else try self.asmRegisterRegisterMemory(12874 ) else try self.asmRegisterRegisterMemory(
12411 mir_tag,12875 mir_tag,
12412 mop1_reg,12876 mop1_reg,
12413 mop2_reg,12877 mop2_reg,
12414 mops[2].mem(Memory.PtrSize.fromSize(abi_size)),12878 mops[2].mem(Memory.PtrSize.fromSize(abi_size)),
12415 );12879 );
12416 return self.finishAir(inst, mops[0], ops);12880 break :result mops[0];
12881 };
12882 return self.finishAir(inst, result, ops);
12883}
12884
12885fn airVaStart(self: *Self, inst: Air.Inst.Index) !void {
12886 const mod = self.bin_file.options.module.?;
12887 const va_list_ty = self.air.instructions.items(.data)[inst].ty;
12888 const ptr_anyopaque_ty = try mod.singleMutPtrType(Type.anyopaque);
12889
12890 const result: MCValue = switch (abi.resolveCallingConvention(
12891 self.fn_type.fnCallingConvention(mod),
12892 self.target.*,
12893 )) {
12894 .SysV => result: {
12895 const info = self.va_info.sysv;
12896 const dst_fi = try self.allocFrameIndex(FrameAlloc.initType(va_list_ty, mod));
12897 var field_off: u31 = 0;
12898 // gp_offset: c_uint,
12899 try self.genSetMem(
12900 .{ .frame = dst_fi },
12901 field_off,
12902 Type.c_uint,
12903 .{ .immediate = info.gp_count * 8 },
12904 );
12905 field_off += @intCast(Type.c_uint.abiSize(mod));
12906 // fp_offset: c_uint,
12907 try self.genSetMem(
12908 .{ .frame = dst_fi },
12909 field_off,
12910 Type.c_uint,
12911 .{ .immediate = abi.SysV.c_abi_int_param_regs.len * 8 + info.fp_count * 16 },
12912 );
12913 field_off += @intCast(Type.c_uint.abiSize(mod));
12914 // overflow_arg_area: *anyopaque,
12915 try self.genSetMem(
12916 .{ .frame = dst_fi },
12917 field_off,
12918 ptr_anyopaque_ty,
12919 .{ .lea_frame = info.overflow_arg_area },
12920 );
12921 field_off += @intCast(ptr_anyopaque_ty.abiSize(mod));
12922 // reg_save_area: *anyopaque,
12923 try self.genSetMem(
12924 .{ .frame = dst_fi },
12925 field_off,
12926 ptr_anyopaque_ty,
12927 .{ .lea_frame = info.reg_save_area },
12928 );
12929 field_off += @intCast(ptr_anyopaque_ty.abiSize(mod));
12930 break :result .{ .load_frame = .{ .index = dst_fi } };
12931 },
12932 .Win64 => return self.fail("TODO implement c_va_start for Win64", .{}),
12933 else => unreachable,
12934 };
12935 return self.finishAir(inst, result, .{ .none, .none, .none });
12936}
12937
12938fn airVaArg(self: *Self, inst: Air.Inst.Index) !void {
12939 const mod = self.bin_file.options.module.?;
12940 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12941 const ty = self.typeOfIndex(inst);
12942 const promote_ty = self.promoteVarArg(ty);
12943 const ptr_anyopaque_ty = try mod.singleMutPtrType(Type.anyopaque);
12944 const unused = self.liveness.isUnused(inst);
12945
12946 const result: MCValue = switch (abi.resolveCallingConvention(
12947 self.fn_type.fnCallingConvention(mod),
12948 self.target.*,
12949 )) {
12950 .SysV => result: {
12951 try self.spillEflagsIfOccupied();
12952
12953 const tmp_regs =
12954 try self.register_manager.allocRegs(2, .{ null, null }, abi.RegisterClass.gp);
12955 const offset_reg = tmp_regs[0].to32();
12956 const addr_reg = tmp_regs[1].to64();
12957 const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
12958 defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
12959
12960 const promote_mcv = try self.allocTempRegOrMem(promote_ty, true);
12961 const promote_lock = switch (promote_mcv) {
12962 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
12963 else => null,
12964 };
12965 defer if (promote_lock) |lock| self.register_manager.unlockReg(lock);
12966
12967 const ptr_arg_list_reg =
12968 try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand });
12969 const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg);
12970 defer self.register_manager.unlockReg(ptr_arg_list_lock);
12971
12972 const gp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 0 } };
12973 const fp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 4 } };
12974 const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } };
12975 const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } };
12976
12977 const classes = mem.sliceTo(&abi.classifySystemV(promote_ty, mod, .arg), .none);
12978 switch (classes[0]) {
12979 .integer => {
12980 assert(classes.len == 1);
12981
12982 try self.genSetReg(offset_reg, Type.c_uint, gp_offset);
12983 try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, Immediate.u(
12984 abi.SysV.c_abi_int_param_regs.len * 8,
12985 ));
12986 const mem_reloc = try self.asmJccReloc(undefined, .ae);
12987
12988 try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area);
12989 if (!unused)
12990 try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, Memory.sib(.qword, .{
12991 .base = .{ .reg = addr_reg },
12992 .scale_index = .{ .scale = 1, .index = offset_reg.to64() },
12993 }));
12994 try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, Memory.sib(.qword, .{
12995 .base = .{ .reg = offset_reg.to64() },
12996 .disp = 8,
12997 }));
12998 try self.genCopy(Type.c_uint, gp_offset, .{ .register = offset_reg });
12999 const done_reloc = try self.asmJmpReloc(undefined);
13000
13001 try self.performReloc(mem_reloc);
13002 try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area);
13003 try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), Memory.sib(.qword, .{
13004 .base = .{ .reg = addr_reg },
13005 .disp = @intCast(@max(promote_ty.abiSize(mod), 8)),
13006 }));
13007 try self.genCopy(
13008 ptr_anyopaque_ty,
13009 overflow_arg_area,
13010 .{ .register = offset_reg.to64() },
13011 );
13012
13013 try self.performReloc(done_reloc);
13014 if (!unused) try self.genCopy(promote_ty, promote_mcv, .{
13015 .indirect = .{ .reg = addr_reg },
13016 });
13017 },
13018 .sse => {
13019 assert(classes.len == 1);
13020
13021 try self.genSetReg(offset_reg, Type.c_uint, fp_offset);
13022 try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, Immediate.u(
13023 abi.SysV.c_abi_int_param_regs.len * 8 + abi.SysV.c_abi_sse_param_regs.len * 16,
13024 ));
13025 const mem_reloc = try self.asmJccReloc(undefined, .ae);
13026
13027 try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area);
13028 if (!unused)
13029 try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, Memory.sib(.qword, .{
13030 .base = .{ .reg = addr_reg },
13031 .scale_index = .{ .scale = 1, .index = offset_reg.to64() },
13032 }));
13033 try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, Memory.sib(.qword, .{
13034 .base = .{ .reg = offset_reg.to64() },
13035 .disp = 16,
13036 }));
13037 try self.genCopy(Type.c_uint, fp_offset, .{ .register = offset_reg });
13038 const done_reloc = try self.asmJmpReloc(undefined);
13039
13040 try self.performReloc(mem_reloc);
13041 try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area);
13042 try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), Memory.sib(.qword, .{
13043 .base = .{ .reg = addr_reg },
13044 .disp = @intCast(@max(promote_ty.abiSize(mod), 8)),
13045 }));
13046 try self.genCopy(
13047 ptr_anyopaque_ty,
13048 overflow_arg_area,
13049 .{ .register = offset_reg.to64() },
13050 );
13051
13052 try self.performReloc(done_reloc);
13053 if (!unused) try self.genCopy(promote_ty, promote_mcv, .{
13054 .indirect = .{ .reg = addr_reg },
13055 });
13056 },
13057 .memory => {
13058 assert(classes.len == 1);
13059 unreachable;
13060 },
13061 else => return self.fail("TODO implement c_va_arg for {} on SysV", .{
13062 promote_ty.fmt(mod),
13063 }),
13064 }
13065
13066 if (unused) break :result .unreach;
13067 if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv;
13068
13069 if (!promote_ty.isRuntimeFloat()) {
13070 const dst_mcv = try self.allocRegOrMem(inst, true);
13071 try self.genCopy(ty, dst_mcv, promote_mcv);
13072 break :result dst_mcv;
13073 }
13074
13075 assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type);
13076 const dst_mcv = if (promote_mcv.isRegister())
13077 promote_mcv
13078 else
13079 try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv);
13080 const dst_reg = dst_mcv.getReg().?.to128();
13081 const dst_lock = self.register_manager.lockReg(dst_reg);
13082 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
13083
13084 if (self.hasFeature(.avx)) if (promote_mcv.isMemory()) try self.asmRegisterRegisterMemory(
13085 .{ .v_ss, .cvtsd2 },
13086 dst_reg,
13087 dst_reg,
13088 promote_mcv.mem(.qword),
13089 ) else try self.asmRegisterRegisterRegister(
13090 .{ .v_ss, .cvtsd2 },
13091 dst_reg,
13092 dst_reg,
13093 (if (promote_mcv.isRegister())
13094 promote_mcv.getReg().?
13095 else
13096 try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(),
13097 ) else if (promote_mcv.isMemory()) try self.asmRegisterMemory(
13098 .{ ._ss, .cvtsd2 },
13099 dst_reg,
13100 promote_mcv.mem(.qword),
13101 ) else try self.asmRegisterRegister(
13102 .{ ._ss, .cvtsd2 },
13103 dst_reg,
13104 (if (promote_mcv.isRegister())
13105 promote_mcv.getReg().?
13106 else
13107 try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(),
13108 );
13109 break :result promote_mcv;
13110 },
13111 .Win64 => return self.fail("TODO implement c_va_arg for Win64", .{}),
13112 else => unreachable,
13113 };
13114 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13115}
13116
13117fn airVaCopy(self: *Self, inst: Air.Inst.Index) !void {
13118 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
13119 const ptr_va_list_ty = self.typeOf(ty_op.operand);
13120
13121 const dst_mcv = try self.allocRegOrMem(inst, true);
13122 try self.load(dst_mcv, ptr_va_list_ty, .{ .air_ref = ty_op.operand });
13123 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
13124}
13125
13126fn airVaEnd(self: *Self, inst: Air.Inst.Index) !void {
13127 const un_op = self.air.instructions.items(.data)[inst].un_op;
13128 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
12417}13129}
1241813130
12419fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {13131fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
...@@ -12494,6 +13206,8 @@ const CallMCValues = struct {...@@ -12494,6 +13206,8 @@ const CallMCValues = struct {
12494 return_value: InstTracking,13206 return_value: InstTracking,
12495 stack_byte_count: u31,13207 stack_byte_count: u31,
12496 stack_align: Alignment,13208 stack_align: Alignment,
13209 gp_count: u32,
13210 fp_count: u32,
1249713211
12498 fn deinit(self: *CallMCValues, func: *Self) void {13212 fn deinit(self: *CallMCValues, func: *Self) void {
12499 func.gpa.free(self.args);13213 func.gpa.free(self.args);
...@@ -12517,8 +13231,8 @@ fn resolveCallingConventionValues(...@@ -12517,8 +13231,8 @@ fn resolveCallingConventionValues(
12517 for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| {13231 for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| {
12518 dest.* = src.toType();13232 dest.* = src.toType();
12519 }13233 }
12520 // TODO: promote var arg types13234 for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty|
12521 for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| param_ty.* = arg_ty;13235 param_ty.* = self.promoteVarArg(arg_ty);
1252213236
12523 var result: CallMCValues = .{13237 var result: CallMCValues = .{
12524 .args = try self.gpa.alloc(MCValue, param_types.len),13238 .args = try self.gpa.alloc(MCValue, param_types.len),
...@@ -12526,6 +13240,8 @@ fn resolveCallingConventionValues(...@@ -12526,6 +13240,8 @@ fn resolveCallingConventionValues(
12526 .return_value = undefined,13240 .return_value = undefined,
12527 .stack_byte_count = 0,13241 .stack_byte_count = 0,
12528 .stack_align = undefined,13242 .stack_align = undefined,
13243 .gp_count = 0,
13244 .fp_count = 0,
12529 };13245 };
12530 errdefer self.gpa.free(result.args);13246 errdefer self.gpa.free(result.args);
1253113247
...@@ -12539,10 +13255,10 @@ fn resolveCallingConventionValues(...@@ -12539,10 +13255,10 @@ fn resolveCallingConventionValues(
12539 result.stack_align = .@"8";13255 result.stack_align = .@"8";
12540 },13256 },
12541 .C, .SysV, .Win64 => {13257 .C, .SysV, .Win64 => {
12542 var ret_int_reg_i: usize = 0;13258 var ret_int_reg_i: u32 = 0;
12543 var ret_sse_reg_i: usize = 0;13259 var ret_sse_reg_i: u32 = 0;
12544 var param_int_reg_i: usize = 0;13260 var param_int_reg_i: u32 = 0;
12545 var param_sse_reg_i: usize = 0;13261 var param_sse_reg_i: u32 = 0;
12546 result.stack_align = .@"16";13262 result.stack_align = .@"16";
1254713263
12548 switch (resolved_cc) {13264 switch (resolved_cc) {
...@@ -12566,7 +13282,7 @@ fn resolveCallingConventionValues(...@@ -12566,7 +13282,7 @@ fn resolveCallingConventionValues(
1256613282
12567 const classes = switch (resolved_cc) {13283 const classes = switch (resolved_cc) {
12568 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),13284 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),
12569 .Win64 => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)},13285 .Win64 => &.{abi.classifyWindows(ret_ty, mod)},
12570 else => unreachable,13286 else => unreachable,
12571 };13287 };
12572 for (classes) |class| switch (class) {13288 for (classes) |class| switch (class) {
...@@ -12639,9 +13355,10 @@ fn resolveCallingConventionValues(...@@ -12639,9 +13355,10 @@ fn resolveCallingConventionValues(
12639 var arg_mcv: [2]MCValue = undefined;13355 var arg_mcv: [2]MCValue = undefined;
12640 var arg_mcv_i: usize = 0;13356 var arg_mcv_i: usize = 0;
1264113357
12642 const classes = switch (self.target.os.tag) {13358 const classes = switch (resolved_cc) {
12643 .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)},13359 .SysV => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),
12644 else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),13360 .Win64 => &.{abi.classifyWindows(ty, mod)},
13361 else => unreachable,
12645 };13362 };
12646 for (classes) |class| switch (class) {13363 for (classes) |class| switch (class) {
12647 .integer => {13364 .integer => {
...@@ -12700,6 +13417,10 @@ fn resolveCallingConventionValues(...@@ -12700,6 +13417,10 @@ fn resolveCallingConventionValues(
12700 } };13417 } };
12701 result.stack_byte_count += param_size;13418 result.stack_byte_count += param_size;
12702 }13419 }
13420 assert(param_int_reg_i <= 6);
13421 result.gp_count = param_int_reg_i;
13422 assert(param_sse_reg_i <= 16);
13423 result.fp_count = param_sse_reg_i;
12703 },13424 },
12704 .Unspecified => {13425 .Unspecified => {
12705 result.stack_align = .@"16";13426 result.stack_align = .@"16";
...@@ -12805,6 +13526,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -12805,6 +13526,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
12805 };13526 };
12806}13527}
1280713528
13529fn memPtrSize(self: *Self, ty: Type) Memory.PtrSize {
13530 const mod = self.bin_file.options.module.?;
13531 return switch (ty.zigTypeTag(mod)) {
13532 .Float => Memory.PtrSize.fromBitSize(ty.floatBits(self.target.*)),
13533 else => Memory.PtrSize.fromSize(@intCast(ty.abiSize(mod))),
13534 };
13535}
13536
12808/// Truncates the value in the register in place.13537/// Truncates the value in the register in place.
12809/// Clobbers any remaining bits.13538/// Clobbers any remaining bits.
12810fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {13539fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
...@@ -12943,3 +13672,35 @@ fn floatLibcAbiSuffix(ty: Type) []const u8 {...@@ -12943,3 +13672,35 @@ fn floatLibcAbiSuffix(ty: Type) []const u8 {
12943 else => unreachable,13672 else => unreachable,
12944 };13673 };
12945}13674}
13675
13676fn promoteVarArg(self: *Self, ty: Type) Type {
13677 const mod = self.bin_file.options.module.?;
13678 switch (ty.zigTypeTag(mod)) {
13679 .Bool => return Type.c_int,
13680 else => {
13681 const int_info = ty.intInfo(mod);
13682 for ([_]Type{
13683 Type.c_int, Type.c_uint,
13684 Type.c_long, Type.c_ulong,
13685 Type.c_longlong, Type.c_ulonglong,
13686 }) |promote_ty| {
13687 const promote_info = promote_ty.intInfo(mod);
13688 if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue;
13689 if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and
13690 promote_info.signedness == .signed) <= promote_info.bits) return promote_ty;
13691 }
13692 unreachable;
13693 },
13694 .Float => switch (ty.floatBits(self.target.*)) {
13695 32, 64 => return Type.f64,
13696 else => |float_bits| {
13697 assert(float_bits == self.target.c_type_bit_size(.longdouble));
13698 return Type.c_longdouble;
13699 },
13700 },
13701 .Pointer => {
13702 assert(!ty.isSlice(mod));
13703 return ty;
13704 },
13705 }
13706}
src/arch/x86_64/Encoding.zig+5-1
...@@ -260,7 +260,7 @@ pub const Mnemonic = enum {...@@ -260,7 +260,7 @@ pub const Mnemonic = enum {
260 ud2,260 ud2,
261 xadd, xchg, xor,261 xadd, xchg, xor,
262 // X87262 // X87
263 fisttp, fld,263 fabs, fchs, ffree, fisttp, fld, fst, fstp,
264 // MMX264 // MMX
265 movd, movq,265 movd, movq,
266 packssdw, packsswb, packuswb,266 packssdw, packsswb, packuswb,
...@@ -316,6 +316,8 @@ pub const Mnemonic = enum {...@@ -316,6 +316,8 @@ pub const Mnemonic = enum {
316 xorpd,316 xorpd,
317 // SSE3317 // SSE3
318 movddup, movshdup, movsldup,318 movddup, movshdup, movsldup,
319 // SSSE3
320 pabsb, pabsd, pabsw,
319 // SSE4.1321 // SSE4.1
320 blendpd, blendps, blendvpd, blendvps,322 blendpd, blendps, blendvpd, blendvps,
321 extractps,323 extractps,
...@@ -353,6 +355,7 @@ pub const Mnemonic = enum {...@@ -353,6 +355,7 @@ pub const Mnemonic = enum {
353 vmovupd, vmovups,355 vmovupd, vmovups,
354 vmulpd, vmulps, vmulsd, vmulss,356 vmulpd, vmulps, vmulsd, vmulss,
355 vorpd, vorps,357 vorpd, vorps,
358 vpabsb, vpabsd, vpabsw,
356 vpackssdw, vpacksswb, vpackusdw, vpackuswb,359 vpackssdw, vpacksswb, vpackusdw, vpackuswb,
357 vpaddb, vpaddd, vpaddq, vpaddsb, vpaddsw, vpaddusb, vpaddusw, vpaddw,360 vpaddb, vpaddd, vpaddq, vpaddsb, vpaddsw, vpaddusb, vpaddusw, vpaddw,
358 vpand, vpandn,361 vpand, vpandn,
...@@ -750,6 +753,7 @@ pub const Feature = enum {...@@ -750,6 +753,7 @@ pub const Feature = enum {
750 sse2,753 sse2,
751 sse3,754 sse3,
752 sse4_1,755 sse4_1,
756 ssse3,
753 x87,757 x87,
754};758};
755759
src/arch/x86_64/Mir.zig+13-4
...@@ -342,14 +342,10 @@ pub const Inst = struct {...@@ -342,14 +342,10 @@ pub const Inst = struct {
342 div,342 div,
343 ///343 ///
344 int3,344 int3,
345 /// Store integer with truncation
346 istt,
347 /// Conditional jump345 /// Conditional jump
348 j,346 j,
349 /// Jump347 /// Jump
350 jmp,348 jmp,
351 /// Load floating-point value
352 ld,
353 /// Load effective address349 /// Load effective address
354 lea,350 lea,
355 /// Load string351 /// Load string
...@@ -446,6 +442,19 @@ pub const Inst = struct {...@@ -446,6 +442,19 @@ pub const Inst = struct {
446 /// Bitwise logical xor of packed double-precision floating-point values442 /// Bitwise logical xor of packed double-precision floating-point values
447 xor,443 xor,
448444
445 /// Absolute value
446 abs,
447 /// Change sign
448 chs,
449 /// Free floating-point register
450 free,
451 /// Store integer with truncation
452 istt,
453 /// Load floating-point value
454 ld,
455 /// Store floating-point value
456 st,
457
449 /// Pack with signed saturation458 /// Pack with signed saturation
450 ackssw,459 ackssw,
451 /// Pack with signed saturation460 /// Pack with signed saturation
src/arch/x86_64/abi.zig+19-17
...@@ -64,7 +64,7 @@ pub fn classifyWindows(ty: Type, mod: *Module) Class {...@@ -64,7 +64,7 @@ pub fn classifyWindows(ty: Type, mod: *Module) Class {
64 }64 }
65}65}
6666
67pub const Context = enum { ret, arg, other };67pub const Context = enum { ret, arg, field, other };
6868
69/// There are a maximum of 8 possible return slots. Returned values are in69/// There are a maximum of 8 possible return slots. Returned values are in
70/// the beginning of the array; unused slots are filled with .none.70/// the beginning of the array; unused slots are filled with .none.
...@@ -120,7 +120,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -120,7 +120,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
120 },120 },
121 .Float => switch (ty.floatBits(target)) {121 .Float => switch (ty.floatBits(target)) {
122 16 => {122 16 => {
123 if (ctx == .other) {123 if (ctx == .field) {
124 result[0] = .memory;124 result[0] = .memory;
125 } else {125 } else {
126 // TODO clang doesn't allow __fp16 as .ret or .arg126 // TODO clang doesn't allow __fp16 as .ret or .arg
...@@ -140,7 +140,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -140,7 +140,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
140 // "Arguments of types __float128, _Decimal128 and __m128 are140 // "Arguments of types __float128, _Decimal128 and __m128 are
141 // split into two halves. The least significant ones belong141 // split into two halves. The least significant ones belong
142 // to class SSE, the most significant one to class SSEUP."142 // to class SSE, the most significant one to class SSEUP."
143 if (ctx == .other) {143 if (ctx == .field) {
144 result[0] = .memory;144 result[0] = .memory;
145 return result;145 return result;
146 }146 }
...@@ -229,7 +229,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -229,7 +229,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
229 if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod)))229 if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod)))
230 return memory_class;230 return memory_class;
231 const field_size = field_ty.abiSize(mod);231 const field_size = field_ty.abiSize(mod);
232 const field_class_array = classifySystemV(field_ty, mod, .other);232 const field_class_array = classifySystemV(field_ty, mod, .field);
233 const field_class = std.mem.sliceTo(&field_class_array, .none);233 const field_class = std.mem.sliceTo(&field_class_array, .none);
234 if (byte_i + field_size <= 8) {234 if (byte_i + field_size <= 8) {
235 // Combine this field with the previous one.235 // Combine this field with the previous one.
...@@ -347,7 +347,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -347,7 +347,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
347 return memory_class;347 return memory_class;
348 }348 }
349 // Combine this field with the previous one.349 // Combine this field with the previous one.
350 const field_class = classifySystemV(field_ty.toType(), mod, .other);350 const field_class = classifySystemV(field_ty.toType(), mod, .field);
351 for (&result, 0..) |*result_item, i| {351 for (&result, 0..) |*result_item, i| {
352 const field_item = field_class[i];352 const field_item = field_class[i];
353 // "If both classes are equal, this is the resulting class."353 // "If both classes are equal, this is the resulting class."
...@@ -444,7 +444,7 @@ pub const SysV = struct {...@@ -444,7 +444,7 @@ pub const SysV = struct {
444 /// These registers need to be preserved (saved on the stack) and restored by the caller before444 /// These registers need to be preserved (saved on the stack) and restored by the caller before
445 /// the caller relinquishes control to a subroutine via call instruction (or similar).445 /// the caller relinquishes control to a subroutine via call instruction (or similar).
446 /// In other words, these registers are free to use by the callee.446 /// In other words, these registers are free to use by the callee.
447 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;447 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
448448
449 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };449 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
450 pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;450 pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
...@@ -459,7 +459,7 @@ pub const Win64 = struct {...@@ -459,7 +459,7 @@ pub const Win64 = struct {
459 /// These registers need to be preserved (saved on the stack) and restored by the caller before459 /// These registers need to be preserved (saved on the stack) and restored by the caller before
460 /// the caller relinquishes control to a subroutine via call instruction (or similar).460 /// the caller relinquishes control to a subroutine via call instruction (or similar).
461 /// In other words, these registers are free to use by the callee.461 /// In other words, these registers are free to use by the callee.
462 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;462 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
463463
464 pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };464 pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
465 pub const c_abi_sse_param_regs = sse_avx_regs[0..4].*;465 pub const c_abi_sse_param_regs = sse_avx_regs[0..4].*;
...@@ -531,30 +531,32 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register...@@ -531,30 +531,32 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register
531const gp_regs = [_]Register{531const gp_regs = [_]Register{
532 .rax, .rcx, .rdx, .rbx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,532 .rax, .rcx, .rdx, .rbx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
533};533};
534const x87_regs = [_]Register{
535 .st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7,
536};
534const sse_avx_regs = [_]Register{537const sse_avx_regs = [_]Register{
535 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,538 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,
536 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,539 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,
537};540};
538const allocatable_regs = gp_regs ++ sse_avx_regs;541const allocatable_regs = gp_regs ++ x87_regs[0 .. x87_regs.len - 1] ++ sse_avx_regs;
539pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs);542pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, allocatable_regs);
540543
541// Register classes544// Register classes
542const RegisterBitSet = RegisterManager.RegisterBitSet;545const RegisterBitSet = RegisterManager.RegisterBitSet;
543pub const RegisterClass = struct {546pub const RegisterClass = struct {
544 pub const gp: RegisterBitSet = blk: {547 pub const gp: RegisterBitSet = blk: {
545 var set = RegisterBitSet.initEmpty();548 var set = RegisterBitSet.initEmpty();
546 set.setRangeValue(.{549 for (allocatable_regs, 0..) |reg, index| if (reg.class() == .general_purpose) set.set(index);
547 .start = 0,550 break :blk set;
548 .end = gp_regs.len,551 };
549 }, true);552 pub const x87: RegisterBitSet = blk: {
553 var set = RegisterBitSet.initEmpty();
554 for (allocatable_regs, 0..) |reg, index| if (reg.class() == .x87) set.set(index);
550 break :blk set;555 break :blk set;
551 };556 };
552 pub const sse: RegisterBitSet = blk: {557 pub const sse: RegisterBitSet = blk: {
553 var set = RegisterBitSet.initEmpty();558 var set = RegisterBitSet.initEmpty();
554 set.setRangeValue(.{559 for (allocatable_regs, 0..) |reg, index| if (reg.class() == .sse) set.set(index);
555 .start = gp_regs.len,
556 .end = allocatable_regs.len,
557 }, true);
558 break :blk set;560 break :blk set;
559 };561 };
560};562};
src/arch/x86_64/encodings.zig+34-3
...@@ -829,13 +829,28 @@ pub const table = [_]Entry{...@@ -829,13 +829,28 @@ pub const table = [_]Entry{
829 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long, .none },829 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long, .none },
830830
831 // X87831 // X87
832 .{ .fabs, .np, &.{}, &.{ 0xd9, 0xe1 }, 0, .none, .x87 },
833
834 .{ .fchs, .np, &.{}, &.{ 0xd9, 0xe0 }, 0, .none, .x87 },
835
836 .{ .ffree, .o, &.{ .st }, &.{ 0xdd, 0xc0 }, 0, .none, .x87 },
837
832 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },838 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },
833 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .none, .x87 },839 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .none, .x87 },
834 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .none, .x87 },840 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .none, .x87 },
835841
836 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .none, .x87 },842 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .none, .x87 },
837 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .none, .x87 },843 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .none, .x87 },
838 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .none, .x87 },844 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .none, .x87 },
845 .{ .fld, .o, &.{ .st }, &.{ 0xd9, 0xc0 }, 0, .none, .x87 },
846
847 .{ .fst, .m, &.{ .m32 }, &.{ 0xd9 }, 2, .none, .x87 },
848 .{ .fst, .m, &.{ .m64 }, &.{ 0xdd }, 2, .none, .x87 },
849 .{ .fst, .o, &.{ .st }, &.{ 0xdd, 0xd0 }, 0, .none, .x87 },
850 .{ .fstp, .m, &.{ .m32 }, &.{ 0xd9 }, 3, .none, .x87 },
851 .{ .fstp, .m, &.{ .m64 }, &.{ 0xdd }, 3, .none, .x87 },
852 .{ .fstp, .m, &.{ .m80 }, &.{ 0xdb }, 7, .none, .x87 },
853 .{ .fstp, .o, &.{ .st }, &.{ 0xdd, 0xd8 }, 0, .none, .x87 },
839854
840 // SSE855 // SSE
841 .{ .addps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x58 }, 0, .none, .sse },856 .{ .addps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x58 }, 0, .none, .sse },
...@@ -1093,6 +1108,14 @@ pub const table = [_]Entry{...@@ -1093,6 +1108,14 @@ pub const table = [_]Entry{
10931108
1094 .{ .movsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .none, .sse3 },1109 .{ .movsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .none, .sse3 },
10951110
1111 // SSSE3
1112 .{ .pabsb, .rm, &.{ .mm, .mm_m64 }, &.{ 0x0f, 0x38, 0x1c }, 0, .none, .ssse3 },
1113 .{ .pabsb, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x1c }, 0, .none, .ssse3 },
1114 .{ .pabsd, .rm, &.{ .mm, .mm_m64 }, &.{ 0x0f, 0x38, 0x1e }, 0, .none, .ssse3 },
1115 .{ .pabsd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x1e }, 0, .none, .ssse3 },
1116 .{ .pabsw, .rm, &.{ .mm, .mm_m64 }, &.{ 0x0f, 0x38, 0x1d }, 0, .none, .ssse3 },
1117 .{ .pabsw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x1d }, 0, .none, .ssse3 },
1118
1096 // SSE4.11119 // SSE4.1
1097 .{ .blendpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0d }, 0, .none, .sse4_1 },1120 .{ .blendpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0d }, 0, .none, .sse4_1 },
10981121
...@@ -1353,6 +1376,10 @@ pub const table = [_]Entry{...@@ -1353,6 +1376,10 @@ pub const table = [_]Entry{
1353 .{ .vorps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x56 }, 0, .vex_128_wig, .avx },1376 .{ .vorps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x0f, 0x56 }, 0, .vex_128_wig, .avx },
1354 .{ .vorps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x56 }, 0, .vex_256_wig, .avx },1377 .{ .vorps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x0f, 0x56 }, 0, .vex_256_wig, .avx },
13551378
1379 .{ .vpabsb, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x1c }, 0, .vex_128_wig, .avx },
1380 .{ .vpabsd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x1e }, 0, .vex_128_wig, .avx },
1381 .{ .vpabsw, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x1d }, 0, .vex_128_wig, .avx },
1382
1356 .{ .vpacksswb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x63 }, 0, .vex_128_wig, .avx },1383 .{ .vpacksswb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x63 }, 0, .vex_128_wig, .avx },
1357 .{ .vpackssdw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6b }, 0, .vex_128_wig, .avx },1384 .{ .vpackssdw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6b }, 0, .vex_128_wig, .avx },
13581385
...@@ -1522,6 +1549,10 @@ pub const table = [_]Entry{...@@ -1522,6 +1549,10 @@ pub const table = [_]Entry{
1522 .{ .vbroadcastss, .rm, &.{ .ymm, .xmm }, &.{ 0x66, 0x0f, 0x38, 0x18 }, 0, .vex_256_w0, .avx2 },1549 .{ .vbroadcastss, .rm, &.{ .ymm, .xmm }, &.{ 0x66, 0x0f, 0x38, 0x18 }, 0, .vex_256_w0, .avx2 },
1523 .{ .vbroadcastsd, .rm, &.{ .ymm, .xmm }, &.{ 0x66, 0x0f, 0x38, 0x19 }, 0, .vex_256_w0, .avx2 },1550 .{ .vbroadcastsd, .rm, &.{ .ymm, .xmm }, &.{ 0x66, 0x0f, 0x38, 0x19 }, 0, .vex_256_w0, .avx2 },
15241551
1552 .{ .vpabsb, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x1c }, 0, .vex_256_wig, .avx2 },
1553 .{ .vpabsd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x1e }, 0, .vex_256_wig, .avx2 },
1554 .{ .vpabsw, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x1d }, 0, .vex_256_wig, .avx2 },
1555
1525 .{ .vpacksswb, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x63 }, 0, .vex_256_wig, .avx2 },1556 .{ .vpacksswb, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x63 }, 0, .vex_256_wig, .avx2 },
1526 .{ .vpackssdw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x6b }, 0, .vex_256_wig, .avx2 },1557 .{ .vpackssdw, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x6b }, 0, .vex_256_wig, .avx2 },
15271558
src/register_manager.zig+4-2
...@@ -91,11 +91,13 @@ pub fn RegisterManager(...@@ -91,11 +91,13 @@ pub fn RegisterManager(
91 return null;91 return null;
92 }92 }
9393
94 pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {94 pub fn indexOfRegIntoTracked(
95 reg: Register,
96 ) ?std.math.IntFittingRange(0, tracked_registers.len) {
95 return indexOfReg(tracked_registers, reg);97 return indexOfReg(tracked_registers, reg);
96 }98 }
9799
98 pub fn regAtTrackedIndex(index: RegisterBitSet.ShiftInt) Register {100 pub fn regAtTrackedIndex(index: std.math.IntFittingRange(0, tracked_registers.len)) Register {
99 return tracked_registers[index];101 return tracked_registers[index];
100 }102 }
101103
test/behavior/abs.zig+2-2
...@@ -95,7 +95,7 @@ test "@abs floats" {...@@ -95,7 +95,7 @@ test "@abs floats" {
95 try comptime testAbsFloats(f64);95 try comptime testAbsFloats(f64);
96 try testAbsFloats(f64);96 try testAbsFloats(f64);
97 try comptime testAbsFloats(f80);97 try comptime testAbsFloats(f80);
98 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);98 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);
99 try comptime testAbsFloats(f128);99 try comptime testAbsFloats(f128);
100 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);100 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);
101}101}
...@@ -280,7 +280,7 @@ test "@abs float vectors" {...@@ -280,7 +280,7 @@ test "@abs float vectors" {
280 try testAbsFloatVectors(f16, 16);280 try testAbsFloatVectors(f16, 16);
281 try comptime testAbsFloatVectors(f16, 17);281 try comptime testAbsFloatVectors(f16, 17);
282282
283 try testAbsFloatVectors(f32, 17);283 try testAbsFloatVectors(f32, 1);
284 try comptime testAbsFloatVectors(f32, 1);284 try comptime testAbsFloatVectors(f32, 1);
285 try testAbsFloatVectors(f32, 1);285 try testAbsFloatVectors(f32, 1);
286 try comptime testAbsFloatVectors(f32, 2);286 try comptime testAbsFloatVectors(f32, 2);
test/behavior/asm.zig+2-4
...@@ -42,7 +42,6 @@ test "module level assembly" {...@@ -42,7 +42,6 @@ test "module level assembly" {
4242
43test "output constraint modifiers" {43test "output constraint modifiers" {
44 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -66,7 +65,6 @@ test "output constraint modifiers" {...@@ -66,7 +65,6 @@ test "output constraint modifiers" {
6665
67test "alternative constraints" {66test "alternative constraints" {
68 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO67 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO70 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -163,8 +161,8 @@ export fn derp() i32 {...@@ -163,8 +161,8 @@ export fn derp() i32 {
163}161}
164162
165test "rw constraint (x86_64)" {163test "rw constraint (x86_64)" {
166 if (builtin.target.cpu.arch != .x86_64 or builtin.zig_backend != .stage2_llvm)164 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
167 return error.SkipZigTest;165 if (builtin.target.cpu.arch != .x86_64) return error.SkipZigTest;
168166
169 var res: i32 = 5;167 var res: i32 = 5;
170 asm ("addl %[b], %[a]"168 asm ("addl %[b], %[a]"
test/behavior/cast.zig+2-2
...@@ -118,11 +118,11 @@ test "@floatFromInt" {...@@ -118,11 +118,11 @@ test "@floatFromInt" {
118118
119test "@floatFromInt(f80)" {119test "@floatFromInt(f80)" {
120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;123 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
125 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;124 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
125 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
126126
127 const S = struct {127 const S = struct {
128 fn doTheTest(comptime Int: type) !void {128 fn doTheTest(comptime Int: type) !void {
...@@ -1476,9 +1476,9 @@ test "pointer to empty struct literal to mutable slice" {...@@ -1476,9 +1476,9 @@ test "pointer to empty struct literal to mutable slice" {
1476test "coerce between pointers of compatible differently-named floats" {1476test "coerce between pointers of compatible differently-named floats" {
1477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1479 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1480 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1481 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1480 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1481 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
14821482
1483 if (builtin.os.tag == .windows) {1483 if (builtin.os.tag == .windows) {
1484 // https://github.com/ziglang/zig/issues/123961484 // https://github.com/ziglang/zig/issues/12396
test/behavior/floatop.zig+17-17
...@@ -28,7 +28,7 @@ test "add f32/f64" {...@@ -28,7 +28,7 @@ test "add f32/f64" {
28}28}
2929
30test "add f80/f128/c_longdouble" {30test "add f80/f128/c_longdouble" {
31 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
3232
33 try testAdd(f80);33 try testAdd(f80);
34 try comptime testAdd(f80);34 try comptime testAdd(f80);
...@@ -59,7 +59,7 @@ test "sub f32/f64" {...@@ -59,7 +59,7 @@ test "sub f32/f64" {
59}59}
6060
61test "sub f80/f128/c_longdouble" {61test "sub f80/f128/c_longdouble" {
62 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;62 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
6363
64 try testSub(f80);64 try testSub(f80);
65 try comptime testSub(f80);65 try comptime testSub(f80);
...@@ -90,7 +90,7 @@ test "mul f32/f64" {...@@ -90,7 +90,7 @@ test "mul f32/f64" {
90}90}
9191
92test "mul f80/f128/c_longdouble" {92test "mul f80/f128/c_longdouble" {
93 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;93 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
9494
95 try testMul(f80);95 try testMul(f80);
96 try comptime testMul(f80);96 try comptime testMul(f80);
...@@ -270,7 +270,7 @@ test "@sqrt f80/f128/c_longdouble" {...@@ -270,7 +270,7 @@ test "@sqrt f80/f128/c_longdouble" {
270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;272 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;273 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
274274
275 if (builtin.os.tag == .freebsd) {275 if (builtin.os.tag == .freebsd) {
276 // TODO https://github.com/ziglang/zig/issues/10875276 // TODO https://github.com/ziglang/zig/issues/10875
...@@ -378,7 +378,7 @@ test "@sin f80/f128/c_longdouble" {...@@ -378,7 +378,7 @@ test "@sin f80/f128/c_longdouble" {
378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
379 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO379 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;380 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
381 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;381 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
382382
383 try testSin(f80);383 try testSin(f80);
384 comptime try testSin(f80);384 comptime try testSin(f80);
...@@ -447,7 +447,7 @@ test "@cos f80/f128/c_longdouble" {...@@ -447,7 +447,7 @@ test "@cos f80/f128/c_longdouble" {
447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;449 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
450 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;450 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
451451
452 try testCos(f80);452 try testCos(f80);
453 try comptime testCos(f80);453 try comptime testCos(f80);
...@@ -516,7 +516,7 @@ test "@tan f80/f128/c_longdouble" {...@@ -516,7 +516,7 @@ test "@tan f80/f128/c_longdouble" {
516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;518 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
519 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;519 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
520520
521 try testTan(f80);521 try testTan(f80);
522 try comptime testTan(f80);522 try comptime testTan(f80);
...@@ -585,7 +585,7 @@ test "@exp f80/f128/c_longdouble" {...@@ -585,7 +585,7 @@ test "@exp f80/f128/c_longdouble" {
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
586 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO586 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
587 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;587 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
588 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;588 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
589589
590 try testExp(f80);590 try testExp(f80);
591 try comptime testExp(f80);591 try comptime testExp(f80);
...@@ -654,7 +654,7 @@ test "@exp2 f80/f128/c_longdouble" {...@@ -654,7 +654,7 @@ test "@exp2 f80/f128/c_longdouble" {
654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
656 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;656 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
657 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;657 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
658658
659 try testExp2(f80);659 try testExp2(f80);
660 try comptime testExp2(f80);660 try comptime testExp2(f80);
...@@ -723,7 +723,7 @@ test "@log f80/f128/c_longdouble" {...@@ -723,7 +723,7 @@ test "@log f80/f128/c_longdouble" {
723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
724 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO724 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
725 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;725 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
726 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;726 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
727727
728 try testLog(f80);728 try testLog(f80);
729 try comptime testLog(f80);729 try comptime testLog(f80);
...@@ -790,7 +790,7 @@ test "@log2 f80/f128/c_longdouble" {...@@ -790,7 +790,7 @@ test "@log2 f80/f128/c_longdouble" {
790 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO790 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO791 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;792 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
793 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;793 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
794794
795 try testLog2(f80);795 try testLog2(f80);
796 try comptime testLog2(f80);796 try comptime testLog2(f80);
...@@ -863,7 +863,7 @@ test "@log10 f80/f128/c_longdouble" {...@@ -863,7 +863,7 @@ test "@log10 f80/f128/c_longdouble" {
863 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO863 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
865 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;865 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
866 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;866 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
867867
868 try testLog10(f80);868 try testLog10(f80);
869 try comptime testLog10(f80);869 try comptime testLog10(f80);
...@@ -929,7 +929,7 @@ test "@abs f80/f128/c_longdouble" {...@@ -929,7 +929,7 @@ test "@abs f80/f128/c_longdouble" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
930 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;930 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;932 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
933933
934 try testFabs(f80);934 try testFabs(f80);
935 try comptime testFabs(f80);935 try comptime testFabs(f80);
...@@ -1029,7 +1029,7 @@ test "@floor f80/f128/c_longdouble" {...@@ -1029,7 +1029,7 @@ test "@floor f80/f128/c_longdouble" {
1029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1030 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1030 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
1031 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1031 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1032 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;1032 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
10331033
1034 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {1034 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1035 // https://github.com/ziglang/zig/issues/126021035 // https://github.com/ziglang/zig/issues/12602
...@@ -1111,7 +1111,7 @@ test "@ceil f80/f128/c_longdouble" {...@@ -1111,7 +1111,7 @@ test "@ceil f80/f128/c_longdouble" {
1111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1112 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1112 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
1113 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1113 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1114 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;1114 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
11151115
1116 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {1116 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1117 // https://github.com/ziglang/zig/issues/126021117 // https://github.com/ziglang/zig/issues/12602
...@@ -1203,7 +1203,7 @@ test "@trunc f80/f128/c_longdouble" {...@@ -1203,7 +1203,7 @@ test "@trunc f80/f128/c_longdouble" {
1203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1204 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1204 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
1205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1206 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;1206 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
12071207
1208 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {1208 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1209 // https://github.com/ziglang/zig/issues/126021209 // https://github.com/ziglang/zig/issues/12602
...@@ -1294,7 +1294,7 @@ test "neg f80/f128/c_longdouble" {...@@ -1294,7 +1294,7 @@ test "neg f80/f128/c_longdouble" {
1294 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1294 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1295 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1295 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1296 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;1296 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1297 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;1297 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
12981298
1299 try testNeg(f80);1299 try testNeg(f80);
1300 try comptime testNeg(f80);1300 try comptime testNeg(f80);
test/behavior/math.zig+3-3
...@@ -495,11 +495,11 @@ fn testDivision() !void {...@@ -495,11 +495,11 @@ fn testDivision() !void {
495}495}
496496
497test "division half-precision floats" {497test "division half-precision floats" {
498 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
502 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;501 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
502 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
503503
504 try testDivisionFP16();504 try testDivisionFP16();
505 try comptime testDivisionFP16();505 try comptime testDivisionFP16();
...@@ -1332,6 +1332,7 @@ test "remainder division" {...@@ -1332,6 +1332,7 @@ test "remainder division" {
1332 try comptime remdiv(f80);1332 try comptime remdiv(f80);
1333 try comptime remdiv(f128);1333 try comptime remdiv(f128);
1334 try remdiv(f16);1334 try remdiv(f16);
1335 try remdiv(f32);
1335 try remdiv(f64);1336 try remdiv(f64);
1336 try remdiv(f80);1337 try remdiv(f80);
1337 try remdiv(f128);1338 try remdiv(f128);
...@@ -1356,7 +1357,7 @@ test "float remainder division using @rem" {...@@ -1356,7 +1357,7 @@ test "float remainder division using @rem" {
1356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1358 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1358 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1359 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1359 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1360 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
13601361
1361 try comptime frem(f16);1362 try comptime frem(f16);
1362 try comptime frem(f32);1363 try comptime frem(f32);
...@@ -1468,7 +1469,6 @@ test "@round f32/f64" {...@@ -1468,7 +1469,6 @@ test "@round f32/f64" {
1468test "@round f80" {1469test "@round f80" {
1469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1471 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1473 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1473 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1474 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1474 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
test/behavior/maximum_minimum.zig+2-1
...@@ -276,7 +276,8 @@ test "@min/@max notices bounds from vector types when element of comptime-known...@@ -276,7 +276,8 @@ test "@min/@max notices bounds from vector types when element of comptime-known
276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_arm) 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
278 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;278 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
279 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;279 if (builtin.zig_backend == .stage2_x86_64 and
280 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
280281
281 var x: @Vector(2, u32) = .{ 1_000_000, 12345 };282 var x: @Vector(2, u32) = .{ 1_000_000, 12345 };
282 const y: @Vector(2, u16) = .{ 10, undefined };283 const y: @Vector(2, u16) = .{ 10, undefined };
test/behavior/muladd.zig+3-3
...@@ -32,11 +32,11 @@ fn testMulAdd() !void {...@@ -32,11 +32,11 @@ fn testMulAdd() !void {
32}32}
3333
34test "@mulAdd f16" {34test "@mulAdd f16" {
35 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;38 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
4040
41 try comptime testMulAdd16();41 try comptime testMulAdd16();
42 try testMulAdd16();42 try testMulAdd16();
...@@ -50,12 +50,12 @@ fn testMulAdd16() !void {...@@ -50,12 +50,12 @@ fn testMulAdd16() !void {
50}50}
5151
52test "@mulAdd f80" {52test "@mulAdd f80" {
53 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;56 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
58 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;57 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
58 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
5959
60 try comptime testMulAdd80();60 try comptime testMulAdd80();
61 try testMulAdd80();61 try testMulAdd80();
...@@ -69,12 +69,12 @@ fn testMulAdd80() !void {...@@ -69,12 +69,12 @@ fn testMulAdd80() !void {
69}69}
7070
71test "@mulAdd f128" {71test "@mulAdd f128" {
72 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;75 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;76 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
7878
79 try comptime testMulAdd128();79 try comptime testMulAdd128();
80 try testMulAdd128();80 try testMulAdd128();
test/behavior/var_args.zig-4
...@@ -108,7 +108,6 @@ test "simple variadic function" {...@@ -108,7 +108,6 @@ test "simple variadic function" {
108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
111 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;111 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
113 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {112 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
114 // https://github.com/ziglang/zig/issues/14096113 // https://github.com/ziglang/zig/issues/14096
...@@ -158,7 +157,6 @@ test "variadic functions" {...@@ -158,7 +157,6 @@ test "variadic functions" {
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;160 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
163 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {161 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
164 // https://github.com/ziglang/zig/issues/14096162 // https://github.com/ziglang/zig/issues/14096
...@@ -202,7 +200,6 @@ test "copy VaList" {...@@ -202,7 +200,6 @@ test "copy VaList" {
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO201 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO202 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;203 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
207 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {204 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
208 // https://github.com/ziglang/zig/issues/14096205 // https://github.com/ziglang/zig/issues/14096
...@@ -235,7 +232,6 @@ test "unused VaList arg" {...@@ -235,7 +232,6 @@ test "unused VaList arg" {
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
237 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO234 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
238 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;235 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
240 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {236 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
241 // https://github.com/ziglang/zig/issues/14096237 // https://github.com/ziglang/zig/issues/14096
test/behavior/widening.zig+3-6
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const mem = std.mem;3const mem = std.mem;
4const builtin = @import("builtin");4const builtin = @import("builtin");
5const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
65
7test "integer widening" {6test "integer widening" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -40,11 +39,11 @@ test "implicit unsigned integer to signed integer" {...@@ -40,11 +39,11 @@ test "implicit unsigned integer to signed integer" {
40}39}
4140
42test "float widening" {41test "float widening" {
43 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;45 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
46 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
4847
49 var a: f16 = 12.34;48 var a: f16 = 12.34;
50 var b: f32 = a;49 var b: f32 = a;
...@@ -53,10 +52,8 @@ test "float widening" {...@@ -53,10 +52,8 @@ test "float widening" {
53 try expect(a == b);52 try expect(a == b);
54 try expect(b == c);53 try expect(b == c);
55 try expect(c == d);54 try expect(c == d);
56 if (has_f80_rt) {55 var e: f80 = c;
57 var e: f80 = c;56 try expect(c == e);
58 try expect(c == e);
59 }
60}57}
6158
62test "float widening f16 to f128" {59test "float widening f16 to f128" {