authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-05 14:47:15-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-05 14:47:15-04:00
loge6590fea19e3eab94b35bfd3c36e29b53cefcaaf
tree11fb8283d25a1175895233332720cf68504f2544
parent8b4e3b6aee61a26e7229ea30728e6c5e31c7cd0b
parent54b2d6f072bde7f85c44bbcc4795bd980d79d45e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17359 from jacobly0/x86_64

x86_64: improve C abi support

20 files changed, 849 insertions(+), 424 deletions(-)

lib/std/os/linux.zig+1-1
......@@ -156,7 +156,7 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
156156
157157pub usingnamespace if (switch (builtin.zig_backend) {
158158 // Calling extern functions is not yet supported with these backends
159 .stage2_x86_64, .stage2_aarch64, .stage2_arm, .stage2_riscv64, .stage2_sparc64 => false,
159 .stage2_aarch64, .stage2_arm, .stage2_riscv64, .stage2_sparc64 => false,
160160 else => !builtin.link_libc,
161161}) struct {
162162 /// See `std.elf` for the constants.
src/arch/aarch64/Emit.zig+10-12
......@@ -445,25 +445,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
445445 },
446446 .plan9 => |dbg_out| {
447447 if (delta_pc <= 0) return; // only do this when the pc changes
448 // we have already checked the target in the linker to make sure it is compatable
449 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
450448
451449 // increasing the line number
452 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
450 try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line);
453451 // increasing the pc
454 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant;
452 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta;
455453 if (d_pc_p9 > 0) {
456 // minus one because if its the last one, we want to leave space to change the line which is one quanta
457 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant);
458 if (dbg_out.pcop_change_index.*) |pci|
454 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
455 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta);
456 if (dbg_out.pcop_change_index) |pci|
459457 dbg_out.dbg_line.items[pci] += 1;
460 dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
458 dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
461459 } else if (d_pc_p9 == 0) {
462 // we don't need to do anything, because adding the quant does it for us
460 // we don't need to do anything, because adding the pc quanta does it for us
463461 } else unreachable;
464 if (dbg_out.start_line.* == null)
465 dbg_out.start_line.* = self.prev_di_line;
466 dbg_out.end_line.* = line;
462 if (dbg_out.start_line == null)
463 dbg_out.start_line = self.prev_di_line;
464 dbg_out.end_line = line;
467465 // only do this if the pc changed
468466 self.prev_di_line = line;
469467 self.prev_di_column = column;
src/arch/arm/Emit.zig+10-12
......@@ -362,25 +362,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
362362 },
363363 .plan9 => |dbg_out| {
364364 if (delta_pc <= 0) return; // only do this when the pc changes
365 // we have already checked the target in the linker to make sure it is compatable
366 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
367365
368366 // increasing the line number
369 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
367 try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line);
370368 // increasing the pc
371 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant;
369 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta;
372370 if (d_pc_p9 > 0) {
373 // minus one because if its the last one, we want to leave space to change the line which is one quanta
374 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant);
375 if (dbg_out.pcop_change_index.*) |pci|
371 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
372 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta);
373 if (dbg_out.pcop_change_index) |pci|
376374 dbg_out.dbg_line.items[pci] += 1;
377 dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
375 dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
378376 } else if (d_pc_p9 == 0) {
379 // we don't need to do anything, because adding the quant does it for us
377 // we don't need to do anything, because adding the pc quanta does it for us
380378 } else unreachable;
381 if (dbg_out.start_line.* == null)
382 dbg_out.start_line.* = self.prev_di_line;
383 dbg_out.end_line.* = line;
379 if (dbg_out.start_line == null)
380 dbg_out.start_line = self.prev_di_line;
381 dbg_out.end_line = line;
384382 // only do this if the pc changed
385383 self.prev_di_line = line;
386384 self.prev_di_column = column;
src/arch/riscv64/Emit.zig+10-12
......@@ -96,25 +96,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
9696 },
9797 .plan9 => |dbg_out| {
9898 if (delta_pc <= 0) return; // only do this when the pc changes
99 // we have already checked the target in the linker to make sure it is compatable
100 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
10199
102100 // increasing the line number
103 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
101 try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line);
104102 // increasing the pc
105 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant;
103 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta;
106104 if (d_pc_p9 > 0) {
107 // minus one because if its the last one, we want to leave space to change the line which is one quanta
108 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant);
109 if (dbg_out.pcop_change_index.*) |pci|
105 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
106 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta);
107 if (dbg_out.pcop_change_index) |pci|
110108 dbg_out.dbg_line.items[pci] += 1;
111 dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
109 dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
112110 } else if (d_pc_p9 == 0) {
113 // we don't need to do anything, because adding the quant does it for us
111 // we don't need to do anything, because adding the pc quanta does it for us
114112 } else unreachable;
115 if (dbg_out.start_line.* == null)
116 dbg_out.start_line.* = self.prev_di_line;
117 dbg_out.end_line.* = line;
113 if (dbg_out.start_line == null)
114 dbg_out.start_line = self.prev_di_line;
115 dbg_out.end_line = line;
118116 // only do this if the pc changed
119117 self.prev_di_line = line;
120118 self.prev_di_column = column;
src/arch/x86_64/CodeGen.zig+617-290
......@@ -178,6 +178,8 @@ pub const MCValue = union(enum) {
178178 eflags: Condition,
179179 /// The value is in a register.
180180 register: Register,
181 /// The value is split across two registers.
182 register_pair: [2]Register,
181183 /// The value is a constant offset from the value in a register.
182184 register_offset: RegisterOffset,
183185 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
......@@ -255,6 +257,16 @@ pub const MCValue = union(enum) {
255257 };
256258 }
257259
260 fn getRegs(mcv: *const MCValue) []const Register {
261 return switch (mcv.*) {
262 .register => |*reg| @as(*const [1]Register, reg),
263 .register_pair => |*regs| regs,
264 .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg),
265 .register_overflow => |*ro| @as(*const [1]Register, &ro.reg),
266 else => &.{},
267 };
268 }
269
258270 fn getCondition(mcv: MCValue) ?Condition {
259271 return switch (mcv) {
260272 .eflags => |cc| cc,
......@@ -272,6 +284,7 @@ pub const MCValue = union(enum) {
272284 .immediate,
273285 .eflags,
274286 .register,
287 .register_pair,
275288 .register_offset,
276289 .register_overflow,
277290 .lea_direct,
......@@ -300,6 +313,7 @@ pub const MCValue = union(enum) {
300313 .dead,
301314 .undef,
302315 .eflags,
316 .register_pair,
303317 .register_overflow,
304318 .memory,
305319 .indirect,
......@@ -326,7 +340,11 @@ pub const MCValue = union(enum) {
326340 .unreach,
327341 .dead,
328342 .undef,
343 .reserved_frame,
344 .air_ref,
345 => unreachable, // not valid
329346 .eflags,
347 .register_pair,
330348 .register_overflow,
331349 .memory,
332350 .indirect,
......@@ -337,9 +355,10 @@ pub const MCValue = union(enum) {
337355 .load_tlv,
338356 .lea_tlv,
339357 .load_frame,
340 .reserved_frame,
341 .air_ref,
342 => unreachable, // not offsettable
358 => switch (off) {
359 0 => mcv,
360 else => unreachable, // not offsettable
361 },
343362 .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
344363 .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
345364 .register_offset => |reg_off| .{
......@@ -360,6 +379,7 @@ pub const MCValue = union(enum) {
360379 .immediate,
361380 .eflags,
362381 .register,
382 .register_pair,
363383 .register_offset,
364384 .register_overflow,
365385 .load_direct,
......@@ -398,8 +418,11 @@ pub const MCValue = union(enum) {
398418 .immediate => |pl| try writer.print("0x{x}", .{pl}),
399419 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
400420 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
421 .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
401422 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
402 .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg) }),
423 .register_overflow => |pl| try writer.print("{s}:{s}", .{
424 @tagName(pl.eflags), @tagName(pl.reg),
425 }),
403426 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
404427 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
405428 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
......@@ -443,6 +466,7 @@ const InstTracking = struct {
443466 => unreachable,
444467 .eflags,
445468 .register,
469 .register_pair,
446470 .register_offset,
447471 .register_overflow,
448472 .indirect,
......@@ -454,6 +478,10 @@ const InstTracking = struct {
454478 return self.short.getReg();
455479 }
456480
481 fn getRegs(self: *const InstTracking) []const Register {
482 return self.short.getRegs();
483 }
484
457485 fn getCondition(self: InstTracking) ?Condition {
458486 return self.short.getCondition();
459487 }
......@@ -494,6 +522,7 @@ const InstTracking = struct {
494522 .dead,
495523 .eflags,
496524 .register,
525 .register_pair,
497526 .register_offset,
498527 .register_overflow,
499528 .indirect,
......@@ -536,6 +565,7 @@ const InstTracking = struct {
536565 .dead,
537566 .eflags,
538567 .register,
568 .register_pair,
539569 .register_offset,
540570 .register_overflow,
541571 .indirect,
......@@ -777,7 +807,7 @@ pub fn generate(
777807 .lower = .{
778808 .allocator = bin_file.allocator,
779809 .mir = mir,
780 .target = &bin_file.options.target,
810 .cc = abi.resolveCallingConvention(fn_info.cc, function.target.*),
781811 .src_loc = src_loc,
782812 },
783813 .bin_file = bin_file,
......@@ -863,7 +893,7 @@ pub fn generateLazy(
863893 .lower = .{
864894 .allocator = bin_file.allocator,
865895 .mir = mir,
866 .target = &bin_file.options.target,
896 .cc = abi.resolveCallingConvention(.Unspecified, function.target.*),
867897 .src_loc = src_loc,
868898 },
869899 .bin_file = bin_file,
......@@ -950,6 +980,7 @@ fn formatWipMir(
950980 _: std.fmt.FormatOptions,
951981 writer: anytype,
952982) @TypeOf(writer).Error!void {
983 const mod = data.self.bin_file.options.module.?;
953984 var lower = Lower{
954985 .allocator = data.self.gpa,
955986 .mir = .{
......@@ -957,7 +988,7 @@ fn formatWipMir(
957988 .extra = data.self.mir_extra.items,
958989 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
959990 },
960 .target = data.self.target,
991 .cc = mod.typeToFunc(data.self.fn_type).?.cc,
961992 .src_loc = data.self.src_loc,
962993 };
963994 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
......@@ -1650,7 +1681,7 @@ fn gen(self: *Self) InnerError!void {
16501681 try self.asmRegister(.{ ._, .pop }, .rbp);
16511682 try self.asmOpOnly(.{ ._, .ret });
16521683
1653 const frame_layout = try self.computeFrameLayout();
1684 const frame_layout = try self.computeFrameLayout(cc);
16541685 const need_frame_align = frame_layout.stack_mask != math.maxInt(u32);
16551686 const need_stack_adjust = frame_layout.stack_adjust > 0;
16561687 const need_save_reg = frame_layout.save_reg_list.count() > 0;
......@@ -2028,7 +2059,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
20282059 while (it.next()) |index| {
20292060 const tracked_inst = self.register_manager.registers[index];
20302061 const tracking = self.getResolvedInstValue(tracked_inst);
2031 assert(RegisterManager.indexOfRegIntoTracked(tracking.getReg().?).? == index);
2062 for (tracking.getRegs()) |reg| {
2063 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
2064 } else unreachable; // tracked register not in use
20322065 }
20332066 }
20342067 }
......@@ -2043,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
20432076 const enum_ty = lazy_sym.ty;
20442077 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)});
20452078
2046 const param_regs = abi.getCAbiIntParamRegs(self.target.*);
2079 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);
2080 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);
20472081 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
20482082 defer for (param_locks) |lock| self.register_manager.unlockReg(lock);
20492083
......@@ -2094,27 +2128,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
20942128}
20952129
20962130fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
2097 const reg = value.getReg() orelse return;
2098 if (self.register_manager.isRegFree(reg)) {
2131 for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg))
20992132 self.register_manager.getRegAssumeFree(reg, inst);
2100 }
21012133}
21022134
21032135fn freeValue(self: *Self, value: MCValue) void {
21042136 switch (value) {
2105 .register => |reg| {
2106 self.register_manager.freeReg(reg);
2107 },
2108 .register_offset => |reg_off| {
2109 self.register_manager.freeReg(reg_off.reg);
2110 },
2137 .register => |reg| self.register_manager.freeReg(reg),
2138 .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg),
2139 .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg),
21112140 .register_overflow => |reg_ov| {
21122141 self.register_manager.freeReg(reg_ov.reg);
21132142 self.eflags_inst = null;
21142143 },
2115 .eflags => {
2116 self.eflags_inst = null;
2117 },
2144 .eflags => self.eflags_inst = null,
21182145 else => {}, // TODO process stack allocation death
21192146 }
21202147}
......@@ -2183,7 +2210,7 @@ fn setFrameLoc(
21832210 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
21842211}
21852212
2186fn computeFrameLayout(self: *Self) !FrameLayout {
2213fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout {
21872214 const frame_allocs_len = self.frame_allocs.len;
21882215 try self.frame_locs.resize(self.gpa, frame_allocs_len);
21892216 const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);
......@@ -2215,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
22152242 // Create list of registers to save in the prologue.
22162243 // TODO handle register classes
22172244 var save_reg_list = Mir.RegisterList{};
2218 const callee_preserved_regs = abi.getCalleePreservedRegs(self.target.*);
2245 const callee_preserved_regs =
2246 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));
22192247 for (callee_preserved_regs) |reg| {
22202248 if (self.register_manager.isRegAllocated(reg)) {
22212249 save_reg_list.push(callee_preserved_regs, reg);
......@@ -2449,7 +2477,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
24492477
24502478pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
24512479 const tracking = self.inst_tracking.getPtr(inst) orelse return;
2452 assert(tracking.getReg().?.id() == reg.id());
2480 for (tracking.getRegs()) |tracked_reg| {
2481 if (tracked_reg.id() == reg.id()) break;
2482 } else unreachable; // spilled reg not tracked with spilled instruciton
24532483 try tracking.spill(self, inst);
24542484 tracking.trackSpill(self, inst);
24552485}
......@@ -2465,9 +2495,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
24652495}
24662496
24672497pub fn spillRegisters(self: *Self, registers: []const Register) !void {
2468 for (registers) |reg| {
2469 try self.register_manager.getReg(reg, null);
2470 }
2498 for (registers) |reg| try self.register_manager.getReg(reg, null);
24712499}
24722500
24732501/// Copies a value to a register without tracking the register. The register is not considered
......@@ -5457,8 +5485,8 @@ fn reuseOperandAdvanced(
54575485 return false;
54585486
54595487 switch (mcv) {
5460 .register => |reg| {
5461 // If it's in the registers table, need to associate the register with the
5488 .register, .register_pair => for (mcv.getRegs()) |reg| {
5489 // If it's in the registers table, need to associate the register(s) with the
54625490 // new instruction.
54635491 if (!self.register_manager.isRegFree(reg)) {
54645492 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
......@@ -5561,6 +5589,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
55615589 .dead,
55625590 .undef,
55635591 .eflags,
5592 .register_pair,
55645593 .register_overflow,
55655594 .reserved_frame,
55665595 => unreachable, // not a valid pointer
......@@ -5585,7 +5614,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
55855614
55865615 try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
55875616 },
5588 .air_ref => |ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ref)),
5617 .air_ref => |ptr_ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ptr_ref)),
55895618 }
55905619}
55915620
......@@ -5707,6 +5736,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
57075736 .dead,
57085737 .undef,
57095738 .eflags,
5739 .register_pair,
57105740 .register_overflow,
57115741 .reserved_frame,
57125742 => unreachable, // not a valid pointer
......@@ -5731,7 +5761,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
57315761
57325762 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
57335763 },
5734 .air_ref => |ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ref)),
5764 .air_ref => |ptr_ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ptr_ref)),
57355765 }
57365766}
57375767
......@@ -6077,6 +6107,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
60776107 .air_ref,
60786108 => unreachable, // unmodifiable destination
60796109 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
6110 .register_pair => unreachable, // unimplemented
60806111 .memory, .load_got, .load_direct, .load_tlv => {
60816112 const addr_reg = try self.register_manager.allocReg(null, gp);
60826113 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -6764,7 +6795,7 @@ fn genBinOp(
67646795 => {
67656796 const resolved_src_mcv = switch (src_mcv) {
67666797 else => src_mcv,
6767 .air_ref => |ref| try self.resolveInst(ref),
6798 .air_ref => |src_ref| try self.resolveInst(src_ref),
67686799 };
67696800 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
67706801 .immediate,
......@@ -6780,6 +6811,9 @@ fn genBinOp(
67806811 => true,
67816812 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
67826813 else => false,
6814 .register_pair,
6815 .register_overflow,
6816 => unreachable,
67836817 })
67846818 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
67856819 else
......@@ -6820,6 +6854,7 @@ fn genBinOp(
68206854 .undef,
68216855 .immediate,
68226856 .eflags,
6857 .register_pair,
68236858 .register_offset,
68246859 .register_overflow,
68256860 .load_direct,
......@@ -7748,121 +7783,154 @@ fn genBinOpMir(
77487783 .reserved_frame,
77497784 .air_ref,
77507785 => unreachable, // unmodifiable destination
7751 .register, .register_offset => {
7752 assert(dst_mcv.isRegister());
7753 const dst_reg = dst_mcv.getReg().?;
7754 const dst_alias = registerAlias(dst_reg, abi_size);
7755 switch (src_mcv) {
7756 .none,
7757 .unreach,
7758 .dead,
7759 .undef,
7760 .register_overflow,
7761 .reserved_frame,
7762 => unreachable,
7763 .register => |src_reg| try self.asmRegisterRegister(
7764 mir_tag,
7765 dst_alias,
7766 registerAlias(src_reg, abi_size),
7767 ),
7768 .immediate => |imm| switch (self.regBitSize(ty)) {
7769 8 => try self.asmRegisterImmediate(
7770 mir_tag,
7771 dst_alias,
7772 if (math.cast(i8, @as(i64, @bitCast(imm)))) |small|
7773 Immediate.s(small)
7774 else
7775 Immediate.u(@as(u8, @intCast(imm))),
7776 ),
7777 16 => try self.asmRegisterImmediate(
7778 mir_tag,
7786 .register, .register_pair, .register_offset => {
7787 switch (dst_mcv) {
7788 .register, .register_pair => {},
7789 .register_offset => |ro| assert(ro.off == 0),
7790 else => unreachable,
7791 }
7792 for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| {
7793 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
7794 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
7795
7796 const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) {
7797 0 => mir_tag,
7798 1 => switch (mir_tag[1]) {
7799 .add => .{ ._, .adc },
7800 .sub, .cmp => .{ ._, .sbb },
7801 .@"or", .@"and", .xor => mir_tag,
7802 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
7803 @tagName(mir_tag[1]),
7804 }),
7805 },
7806 else => unreachable,
7807 };
7808 const off: u4 = @intCast(dst_reg_i * 8);
7809 const limb_abi_size = @min(abi_size - off, 8);
7810 const dst_alias = registerAlias(dst_reg, limb_abi_size);
7811 switch (src_mcv) {
7812 .none,
7813 .unreach,
7814 .dead,
7815 .undef,
7816 .register_overflow,
7817 .reserved_frame,
7818 => unreachable,
7819 .register, .register_pair => try self.asmRegisterRegister(
7820 mir_limb_tag,
77797821 dst_alias,
7780 if (math.cast(i16, @as(i64, @bitCast(imm)))) |small|
7781 Immediate.s(small)
7782 else
7783 Immediate.u(@as(u16, @intCast(imm))),
7822 registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),
77847823 ),
7785 32 => try self.asmRegisterImmediate(
7824 .immediate => |imm| {
7825 assert(off == 0);
7826 switch (self.regBitSize(ty)) {
7827 8 => try self.asmRegisterImmediate(
7828 mir_limb_tag,
7829 dst_alias,
7830 if (math.cast(i8, @as(i64, @bitCast(imm)))) |small|
7831 Immediate.s(small)
7832 else
7833 Immediate.u(@as(u8, @intCast(imm))),
7834 ),
7835 16 => try self.asmRegisterImmediate(
7836 mir_limb_tag,
7837 dst_alias,
7838 if (math.cast(i16, @as(i64, @bitCast(imm)))) |small|
7839 Immediate.s(small)
7840 else
7841 Immediate.u(@as(u16, @intCast(imm))),
7842 ),
7843 32 => try self.asmRegisterImmediate(
7844 mir_limb_tag,
7845 dst_alias,
7846 if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7847 Immediate.s(small)
7848 else
7849 Immediate.u(@as(u32, @intCast(imm))),
7850 ),
7851 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7852 try self.asmRegisterImmediate(mir_limb_tag, dst_alias, Immediate.s(small))
7853 else
7854 try self.asmRegisterRegister(mir_limb_tag, dst_alias, registerAlias(
7855 try self.copyToTmpRegister(ty, src_mcv),
7856 limb_abi_size,
7857 )),
7858 else => unreachable,
7859 }
7860 },
7861 .eflags,
7862 .register_offset,
7863 .memory,
7864 .indirect,
7865 .load_direct,
7866 .lea_direct,
7867 .load_got,
7868 .lea_got,
7869 .load_tlv,
7870 .lea_tlv,
7871 .load_frame,
7872 .lea_frame,
7873 => {
7874 blk: {
7875 return self.asmRegisterMemory(
7876 mir_limb_tag,
7877 dst_alias,
7878 Memory.sib(Memory.PtrSize.fromSize(limb_abi_size), switch (src_mcv) {
7879 .memory => |addr| .{
7880 .base = .{ .reg = .ds },
7881 .disp = math.cast(i32, addr + off) orelse break :blk,
7882 },
7883 .indirect => |reg_off| .{
7884 .base = .{ .reg = reg_off.reg },
7885 .disp = reg_off.off + off,
7886 },
7887 .load_frame => |frame_addr| .{
7888 .base = .{ .frame = frame_addr.index },
7889 .disp = frame_addr.off + off,
7890 },
7891 else => break :blk,
7892 }),
7893 );
7894 }
7895
7896 switch (src_mcv) {
7897 .eflags,
7898 .register_offset,
7899 .lea_direct,
7900 .lea_got,
7901 .lea_tlv,
7902 .lea_frame,
7903 => {
7904 assert(off == 0);
7905 const reg = try self.copyToTmpRegister(ty, src_mcv);
7906 return self.genBinOpMir(
7907 mir_limb_tag,
7908 ty,
7909 dst_mcv,
7910 .{ .register = reg },
7911 );
7912 },
7913 .memory,
7914 .load_direct,
7915 .load_got,
7916 .load_tlv,
7917 => {
7918 const ptr_ty = try mod.singleConstPtrType(ty);
7919 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
7920 return self.genBinOpMir(mir_limb_tag, ty, dst_mcv, .{
7921 .indirect = .{ .reg = addr_reg, .off = off },
7922 });
7923 },
7924 else => unreachable,
7925 }
7926 },
7927 .air_ref => |src_ref| return self.genBinOpMir(
77867928 mir_tag,
7787 dst_alias,
7788 if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7789 Immediate.s(small)
7790 else
7791 Immediate.u(@as(u32, @intCast(imm))),
7929 ty,
7930 dst_mcv,
7931 try self.resolveInst(src_ref),
77927932 ),
7793 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7794 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
7795 else
7796 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
7797 try self.copyToTmpRegister(ty, src_mcv),
7798 abi_size,
7799 )),
7800 else => unreachable,
7801 },
7802 .eflags,
7803 .register_offset,
7804 .memory,
7805 .indirect,
7806 .load_direct,
7807 .lea_direct,
7808 .load_got,
7809 .lea_got,
7810 .load_tlv,
7811 .lea_tlv,
7812 .load_frame,
7813 .lea_frame,
7814 => {
7815 blk: {
7816 return self.asmRegisterMemory(
7817 mir_tag,
7818 registerAlias(dst_reg, abi_size),
7819 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
7820 .memory => |addr| .{
7821 .base = .{ .reg = .ds },
7822 .disp = math.cast(i32, addr) orelse break :blk,
7823 },
7824 .indirect => |reg_off| .{
7825 .base = .{ .reg = reg_off.reg },
7826 .disp = reg_off.off,
7827 },
7828 .load_frame => |frame_addr| .{
7829 .base = .{ .frame = frame_addr.index },
7830 .disp = frame_addr.off,
7831 },
7832 else => break :blk,
7833 }),
7834 );
7835 }
7836
7837 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
7838 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
7839
7840 switch (src_mcv) {
7841 .eflags,
7842 .register_offset,
7843 .lea_direct,
7844 .lea_got,
7845 .lea_tlv,
7846 .lea_frame,
7847 => {
7848 const reg = try self.copyToTmpRegister(ty, src_mcv);
7849 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
7850 },
7851 .memory,
7852 .load_direct,
7853 .load_got,
7854 .load_tlv,
7855 => {
7856 const ptr_ty = try mod.singleConstPtrType(ty);
7857 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
7858 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{
7859 .indirect = .{ .reg = addr_reg },
7860 });
7861 },
7862 else => unreachable,
7863 }
7864 },
7865 .air_ref => |ref| try self.genBinOpMir(mir_tag, ty, dst_mcv, try self.resolveInst(ref)),
7933 }
78667934 }
78677935 },
78687936 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
......@@ -7877,10 +7945,7 @@ fn genBinOpMir(
78777945 errdefer self.register_manager.unlockReg(dst_addr_lock);
78787946
78797947 try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address());
7880 break :dst .{
7881 .addr_reg = dst_addr_reg,
7882 .addr_lock = dst_addr_lock,
7883 };
7948 break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock };
78847949 },
78857950 .load_frame => null,
78867951 };
......@@ -7888,7 +7953,7 @@ fn genBinOpMir(
78887953
78897954 const resolved_src_mcv = switch (src_mcv) {
78907955 else => src_mcv,
7891 .air_ref => |ref| try self.resolveInst(ref),
7956 .air_ref => |src_ref| try self.resolveInst(src_ref),
78927957 };
78937958 const src_info: OpInfo = switch (resolved_src_mcv) {
78947959 .none,
......@@ -7900,9 +7965,10 @@ fn genBinOpMir(
79007965 .air_ref,
79017966 => unreachable,
79027967 .immediate,
7968 .eflags,
79037969 .register,
7970 .register_pair,
79047971 .register_offset,
7905 .eflags,
79067972 .indirect,
79077973 .lea_direct,
79087974 .lea_got,
......@@ -7924,10 +7990,7 @@ fn genBinOpMir(
79247990 errdefer self.register_manager.unlockReg(src_addr_lock);
79257991
79267992 try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address());
7927 break :src .{
7928 .addr_reg = src_addr_reg,
7929 .addr_lock = src_addr_lock,
7930 };
7993 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
79317994 },
79327995 };
79337996 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
......@@ -7938,9 +8001,13 @@ fn genBinOpMir(
79388001 .signed => Type.usize,
79398002 .unsigned => Type.isize,
79408003 };
8004 var limb_i: usize = 0;
79418005 var off: i32 = 0;
7942 while (off < abi_size) : (off += 8) {
7943 const mir_limb_tag: Mir.Inst.FixedTag = switch (off) {
8006 while (off < abi_size) : ({
8007 limb_i += 1;
8008 off += 8;
8009 }) {
8010 const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) {
79448011 0 => mir_tag,
79458012 else => switch (mir_tag[1]) {
79468013 .add => .{ ._, .adc },
......@@ -7979,16 +8046,8 @@ fn genBinOpMir(
79798046 .reserved_frame,
79808047 .air_ref,
79818048 => unreachable,
7982 .register => |src_reg| switch (off) {
7983 0 => try self.asmMemoryRegister(
7984 mir_limb_tag,
7985 dst_limb_mem,
7986 registerAlias(src_reg, limb_abi_size),
7987 ),
7988 else => unreachable,
7989 },
79908049 .immediate => |src_imm| {
7991 const imm: u64 = switch (off) {
8050 const imm: u64 = switch (limb_i) {
79928051 0 => src_imm,
79938052 else => switch (ty_signedness) {
79948053 .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63),
......@@ -8038,6 +8097,8 @@ fn genBinOpMir(
80388097 else => unreachable,
80398098 }
80408099 },
8100 .register,
8101 .register_pair,
80418102 .register_offset,
80428103 .eflags,
80438104 .memory,
......@@ -8051,16 +8112,19 @@ fn genBinOpMir(
80518112 .load_frame,
80528113 .lea_frame,
80538114 => {
8054 const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{
8115 const src_limb_mcv: MCValue = if (src_info) |info| .{
80558116 .indirect = .{ .reg = info.addr_reg, .off = off },
80568117 } else switch (resolved_src_mcv) {
8118 .register, .register_pair => .{
8119 .register = resolved_src_mcv.getRegs()[limb_i],
8120 },
80578121 .eflags,
80588122 .register_offset,
80598123 .lea_direct,
80608124 .lea_got,
80618125 .lea_tlv,
80628126 .lea_frame,
8063 => switch (off) {
8127 => switch (limb_i) {
80648128 0 => resolved_src_mcv,
80658129 else => .{ .immediate = 0 },
80668130 },
......@@ -8074,7 +8138,11 @@ fn genBinOpMir(
80748138 .off = frame_addr.off + off,
80758139 } },
80768140 else => unreachable,
8077 });
8141 };
8142 const src_limb_reg = if (src_limb_mcv.isRegister())
8143 src_limb_mcv.getReg().?
8144 else
8145 try self.copyToTmpRegister(limb_ty, src_limb_mcv);
80788146 try self.asmMemoryRegister(
80798147 mir_limb_tag,
80808148 dst_limb_mem,
......@@ -8098,8 +8166,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
80988166 .dead,
80998167 .undef,
81008168 .immediate,
8101 .register_offset,
81028169 .eflags,
8170 .register_offset,
81038171 .register_overflow,
81048172 .lea_direct,
81058173 .lea_got,
......@@ -8115,13 +8183,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
81158183
81168184 const resolved_src_mcv = switch (src_mcv) {
81178185 else => src_mcv,
8118 .air_ref => |ref| try self.resolveInst(ref),
8186 .air_ref => |src_ref| try self.resolveInst(src_ref),
81198187 };
81208188 switch (resolved_src_mcv) {
81218189 .none,
81228190 .unreach,
81238191 .dead,
81248192 .undef,
8193 .register_pair,
81258194 .register_overflow,
81268195 .reserved_frame,
81278196 .air_ref,
......@@ -8187,6 +8256,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
81878256 ),
81888257 }
81898258 },
8259 .register_pair => unreachable, // unimplemented
81908260 .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => {
81918261 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
81928262 const tmp_mcv = MCValue{ .register = tmp_reg };
......@@ -8209,8 +8279,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
82098279 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
82108280 const dst_mcv = self.args[arg_index];
82118281 switch (dst_mcv) {
8212 .register => |reg| self.register_manager.getRegAssumeFree(reg, inst),
8213 .load_frame => {},
8282 .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg|
8283 self.register_manager.getRegAssumeFree(reg, inst),
82148284 else => return self.fail("TODO implement arg for {}", .{dst_mcv}),
82158285 }
82168286
......@@ -8230,6 +8300,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
82308300 .dwarf => |dw| {
82318301 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
82328302 .register => |reg| .{ .register = reg.dwarfNum() },
8303 .register_pair => |regs| .{ .register_pair = .{
8304 regs[0].dwarfNum(), regs[1].dwarfNum(),
8305 } },
82338306 // TODO use a frame index
82348307 .load_frame => return,
82358308 //.stack_offset => |off| .{
......@@ -8390,7 +8463,10 @@ fn genCall(self: *Self, info: union(enum) {
83908463 };
83918464 const fn_info = mod.typeToFunc(fn_ty).?;
83928465
8393 const ExpectedContents = [16]Type;
8466 const ExpectedContents = extern struct {
8467 var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)),
8468 arg_regs: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)),
8469 };
83948470 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
83958471 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
83968472 const allocator = stack.get();
......@@ -8399,8 +8475,12 @@ fn genCall(self: *Self, info: union(enum) {
83998475 defer allocator.free(var_args);
84008476 for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
84018477
8402 var call_info =
8403 try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);
8478 var arg_locks = std.ArrayList(?RegisterLock).init(allocator);
8479 defer arg_locks.deinit();
8480 try arg_locks.ensureTotalCapacity(16);
8481 defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock);
8482
8483 var call_info = try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);
84048484 defer call_info.deinit(self);
84058485
84068486 // We need a properly aligned and sized call frame to be able to call this function.
......@@ -8419,7 +8499,9 @@ fn genCall(self: *Self, info: union(enum) {
84198499 }
84208500
84218501 try self.spillEflagsIfOccupied();
8422 try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*));
8502 try self.spillRegisters(abi.getCallerPreservedRegs(
8503 abi.resolveCallingConvention(fn_info.cc, self.target.*),
8504 ));
84238505
84248506 // set stack arguments first because this can clobber registers
84258507 // also clobber spill arguments as we go
......@@ -8430,7 +8512,14 @@ fn genCall(self: *Self, info: union(enum) {
84308512 }
84318513 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
84328514 .none => {},
8433 .register => |reg| try self.spillRegisters(&.{reg}),
8515 .register => |reg| {
8516 try self.spillRegisters(&.{reg});
8517 try arg_locks.append(self.register_manager.lockReg(reg));
8518 },
8519 .register_pair => |regs| {
8520 try self.spillRegisters(&regs);
8521 try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));
8522 },
84348523 .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),
84358524 else => unreachable,
84368525 };
......@@ -8451,13 +8540,11 @@ fn genCall(self: *Self, info: union(enum) {
84518540 };
84528541 defer if (ret_lock) |lock| self.register_manager.unlockReg(lock);
84538542
8454 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| {
8455 switch (dst_arg) {
8456 .none, .load_frame => {},
8457 .register => try self.genCopy(arg_ty, dst_arg, src_arg),
8458 else => unreachable,
8459 }
8460 }
8543 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
8544 .none, .load_frame => {},
8545 .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg),
8546 else => unreachable,
8547 };
84618548
84628549 // Due to incremental compilation, how function calls are generated depends
84638550 // on linking.
......@@ -8527,7 +8614,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
85278614 const ret_ty = self.fn_type.fnReturnType(mod);
85288615 switch (self.ret_mcv.short) {
85298616 .none => {},
8530 .register => try self.genCopy(ret_ty, self.ret_mcv.short, operand),
8617 .register, .register_pair => try self.genCopy(ret_ty, self.ret_mcv.short, operand),
85318618 .indirect => |reg_off| {
85328619 try self.register_manager.getReg(reg_off.reg, null);
85338620 const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg);
......@@ -8612,6 +8699,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
86128699 const lhs_mcv = try self.resolveInst(bin_op.lhs);
86138700 const lhs_lock = switch (lhs_mcv) {
86148701 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
8702 .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg),
86158703 else => null,
86168704 };
86178705 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -8619,6 +8707,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
86198707 const rhs_mcv = try self.resolveInst(bin_op.rhs);
86208708 const rhs_lock = switch (rhs_mcv) {
86218709 .register => |reg| self.register_manager.lockReg(reg),
8710 .register_offset => |ro| self.register_manager.lockReg(ro.reg),
86228711 else => null,
86238712 };
86248713 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -8665,33 +8754,122 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
86658754 .lt, .gte => {},
86668755 .lte, .gt => unreachable,
86678756 .eq, .neq => {
8668 const dst_addr_mcv: MCValue = switch (dst_mcv) {
8669 .memory, .indirect, .load_frame => dst_mcv.address(),
8670 else => .{ .register = try self.copyToTmpRegister(
8671 Type.usize,
8672 dst_mcv.address(),
8673 ) },
8757 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
8758
8759 const resolved_dst_mcv = switch (dst_mcv) {
8760 else => dst_mcv,
8761 .air_ref => |dst_ref| try self.resolveInst(dst_ref),
86748762 };
8675 const dst_addr_lock = if (dst_addr_mcv.getReg()) |reg|
8676 self.register_manager.lockReg(reg)
8677 else
8678 null;
8679 defer if (dst_addr_lock) |lock| self.register_manager.unlockReg(lock);
8763 const dst_info: OpInfo = switch (resolved_dst_mcv) {
8764 .none,
8765 .unreach,
8766 .dead,
8767 .undef,
8768 .immediate,
8769 .eflags,
8770 .register,
8771 .register_offset,
8772 .register_overflow,
8773 .indirect,
8774 .lea_direct,
8775 .lea_got,
8776 .lea_tlv,
8777 .lea_frame,
8778 .reserved_frame,
8779 .air_ref,
8780 => unreachable,
8781 .register_pair, .load_frame => null,
8782 .memory, .load_got, .load_direct, .load_tlv => dst: {
8783 switch (resolved_dst_mcv) {
8784 .memory => |addr| if (math.cast(
8785 i32,
8786 @as(i64, @bitCast(addr)),
8787 ) != null and math.cast(
8788 i32,
8789 @as(i64, @bitCast(addr)) + abi_size - 8,
8790 ) != null) break :dst null,
8791 .load_got, .load_direct, .load_tlv => {},
8792 else => unreachable,
8793 }
8794
8795 const dst_addr_reg =
8796 (try self.register_manager.allocReg(null, gp)).to64();
8797 const dst_addr_lock =
8798 self.register_manager.lockRegAssumeUnused(dst_addr_reg);
8799 errdefer self.register_manager.unlockReg(dst_addr_lock);
8800
8801 try self.genSetReg(
8802 dst_addr_reg,
8803 Type.usize,
8804 resolved_dst_mcv.address(),
8805 );
8806 break :dst .{
8807 .addr_reg = dst_addr_reg,
8808 .addr_lock = dst_addr_lock,
8809 };
8810 },
8811 };
8812 defer if (dst_info) |info|
8813 self.register_manager.unlockReg(info.addr_lock);
86808814
8681 const src_addr_mcv: MCValue = switch (src_mcv) {
8682 .memory, .indirect, .load_frame => src_mcv.address(),
8683 else => .{ .register = try self.copyToTmpRegister(
8684 Type.usize,
8685 src_mcv.address(),
8686 ) },
8815 const resolved_src_mcv = switch (src_mcv) {
8816 else => src_mcv,
8817 .air_ref => |src_ref| try self.resolveInst(src_ref),
86878818 };
8688 const src_addr_lock = if (src_addr_mcv.getReg()) |reg|
8689 self.register_manager.lockReg(reg)
8690 else
8691 null;
8692 defer if (src_addr_lock) |lock| self.register_manager.unlockReg(lock);
8819 const src_info: OpInfo = switch (resolved_src_mcv) {
8820 .none,
8821 .unreach,
8822 .dead,
8823 .undef,
8824 .immediate,
8825 .eflags,
8826 .register,
8827 .register_offset,
8828 .register_overflow,
8829 .indirect,
8830 .lea_direct,
8831 .lea_got,
8832 .lea_tlv,
8833 .lea_frame,
8834 .reserved_frame,
8835 .air_ref,
8836 => unreachable,
8837 .register_pair, .load_frame => null,
8838 .memory, .load_got, .load_direct, .load_tlv => src: {
8839 switch (resolved_src_mcv) {
8840 .memory => |addr| if (math.cast(
8841 i32,
8842 @as(i64, @bitCast(addr)),
8843 ) != null and math.cast(
8844 i32,
8845 @as(i64, @bitCast(addr)) + abi_size - 8,
8846 ) != null) break :src null,
8847 .load_got, .load_direct, .load_tlv => {},
8848 else => unreachable,
8849 }
8850
8851 const src_addr_reg =
8852 (try self.register_manager.allocReg(null, gp)).to64();
8853 const src_addr_lock =
8854 self.register_manager.lockRegAssumeUnused(src_addr_reg);
8855 errdefer self.register_manager.unlockReg(src_addr_lock);
8856
8857 try self.genSetReg(
8858 src_addr_reg,
8859 Type.usize,
8860 resolved_src_mcv.address(),
8861 );
8862 break :src .{
8863 .addr_reg = src_addr_reg,
8864 .addr_lock = src_addr_lock,
8865 };
8866 },
8867 };
8868 defer if (src_info) |info|
8869 self.register_manager.unlockReg(info.addr_lock);
86938870
8694 const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
8871 const regs =
8872 try self.register_manager.allocRegs(2, .{ null, null }, gp);
86958873 const acc_reg = regs[0].to64();
86968874 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);
86978875 defer for (locks) |lock| self.register_manager.unlockReg(lock);
......@@ -8699,18 +8877,52 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
86998877 const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable;
87008878 var limb_i: u16 = 0;
87018879 while (limb_i < limbs_len) : (limb_i += 1) {
8880 const off = limb_i * 8;
87028881 const tmp_reg = regs[@min(limb_i, 1)].to64();
8703 try self.genSetReg(
8704 tmp_reg,
8705 Type.usize,
8706 dst_addr_mcv.offset(limb_i * 8).deref(),
8707 );
8882
8883 try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{
8884 .indirect = .{ .reg = info.addr_reg, .off = off },
8885 } else switch (resolved_dst_mcv) {
8886 .register_pair => |dst_regs| .{ .register = dst_regs[limb_i] },
8887 .memory => |dst_addr| .{
8888 .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off),
8889 },
8890 .indirect => |reg_off| .{ .indirect = .{
8891 .reg = reg_off.reg,
8892 .off = reg_off.off + off,
8893 } },
8894 .load_frame => |frame_addr| .{ .load_frame = .{
8895 .index = frame_addr.index,
8896 .off = frame_addr.off + off,
8897 } },
8898 else => unreachable,
8899 });
8900
87088901 try self.genBinOpMir(
87098902 .{ ._, .xor },
87108903 Type.usize,
87118904 .{ .register = tmp_reg },
8712 src_addr_mcv.offset(limb_i * 8).deref(),
8905 if (src_info) |info| .{
8906 .indirect = .{ .reg = info.addr_reg, .off = off },
8907 } else switch (resolved_src_mcv) {
8908 .register_pair => |src_regs| .{
8909 .register = src_regs[limb_i],
8910 },
8911 .memory => |src_addr| .{
8912 .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off),
8913 },
8914 .indirect => |reg_off| .{ .indirect = .{
8915 .reg = reg_off.reg,
8916 .off = reg_off.off + off,
8917 } },
8918 .load_frame => |frame_addr| .{ .load_frame = .{
8919 .index = frame_addr.index,
8920 .off = frame_addr.off + off,
8921 } },
8922 else => unreachable,
8923 },
87138924 );
8925
87148926 if (limb_i > 0) try self.asmRegisterRegister(
87158927 .{ ._, .@"or" },
87168928 acc_reg,
......@@ -9039,6 +9251,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
90399251 .undef,
90409252 .immediate,
90419253 .eflags,
9254 .register_pair,
90429255 .register_offset,
90439256 .register_overflow,
90449257 .lea_direct,
......@@ -9528,13 +9741,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
95289741 extra_i += inputs.len;
95299742
95309743 var result: MCValue = .none;
9531 var args = std.StringArrayHashMap(MCValue).init(self.gpa);
9744 var args = std.ArrayList(MCValue).init(self.gpa);
95329745 try args.ensureTotalCapacity(outputs.len + inputs.len);
95339746 defer {
9534 for (args.values()) |arg| if (arg.getReg()) |reg|
9747 for (args.items) |arg| if (arg.getReg()) |reg|
95359748 self.register_manager.unlockReg(.{ .register = reg });
95369749 args.deinit();
95379750 }
9751 var arg_map = std.StringHashMap(u8).init(self.gpa);
9752 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
9753 defer arg_map.deinit();
95389754
95399755 var outputs_extra_i = extra_i;
95409756 for (outputs) |output| {
......@@ -9585,7 +9801,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
95859801 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
95869802 _ = self.register_manager.lockRegAssumeUnused(reg);
95879803 };
9588 args.putAssumeCapacity(name, arg_mcv);
9804 if (!std.mem.eql(u8, name, "_"))
9805 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
9806 args.appendAssumeCapacity(arg_mcv);
95899807 if (output == .none) result = arg_mcv;
95909808 }
95919809
......@@ -9643,7 +9861,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
96439861 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
96449862 _ = self.register_manager.lockReg(reg);
96459863 };
9646 args.putAssumeCapacity(name, arg_mcv);
9864 if (!std.mem.eql(u8, name, "_"))
9865 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
9866 args.appendAssumeCapacity(arg_mcv);
96479867 }
96489868
96499869 {
......@@ -9712,8 +9932,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
97129932 op_str[colon_pos + 1 .. op_str.len - "]".len]
97139933 else
97149934 "";
9715 op.* = switch (args.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
9716 return self.fail("no matching constraint: '{s}'", .{op_str})) {
9935 op.* = switch (args.items[
9936 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
9937 return self.fail("no matching constraint: '{s}'", .{op_str})
9938 ]) {
97179939 .register => |reg| if (std.mem.eql(u8, modifier, ""))
97189940 .{ .reg = reg }
97199941 else
......@@ -9826,7 +10048,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
982610048 };
982710049 }
982810050
9829 for (outputs, args.values()[0..outputs.len]) |output, mcv| {
10051 for (outputs, args.items[0..outputs.len]) |output, mcv| {
983010052 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);
983110053 const constraint =
983210054 std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0);
......@@ -10093,6 +10315,19 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
1009310315 .off = -dst_reg_off.off,
1009410316 } },
1009510317 }),
10318 .register_pair => |dst_regs| for (dst_regs, 0..) |dst_reg, dst_reg_i| switch (src_mcv) {
10319 .register_pair => |src_regs| try self.genSetReg(
10320 dst_reg,
10321 Type.usize,
10322 .{ .register = src_regs[dst_reg_i] },
10323 ),
10324 else => try self.genSetReg(
10325 dst_reg,
10326 Type.usize,
10327 src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(),
10328 ),
10329 .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)),
10330 },
1009610331 .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),
1009710332 .memory, .load_direct, .load_got, .load_tlv => {
1009810333 switch (dst_mcv) {
......@@ -10126,6 +10361,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1012610361 .none,
1012710362 .unreach,
1012810363 .dead,
10364 .register_pair,
1012910365 .register_overflow,
1013010366 .reserved_frame,
1013110367 => unreachable,
......@@ -10203,17 +10439,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1020310439 .sse => try self.asmRegisterRegister(
1020410440 @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) {
1020510441 else => switch (abi_size) {
10206 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
10207 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
10208 9...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa },
10442 1...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa },
1020910443 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null,
1021010444 else => null,
1021110445 },
1021210446 .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) {
1021310447 16, 128 => switch (abi_size) {
10214 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
10215 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
10216 9...16 => if (self.hasFeature(.avx))
10448 2...16 => if (self.hasFeature(.avx))
1021710449 .{ .v_, .movdqa }
1021810450 else
1021910451 .{ ._, .movdqa },
......@@ -10307,6 +10539,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1030710539 Immediate.u(0),
1030810540 ),
1030910541 }
10542 return;
1031010543 },
1031110544 .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) {
1031210545 else => {
......@@ -10398,7 +10631,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1039810631 @tagName(self.bin_file.tag),
1039910632 });
1040010633 },
10401 .air_ref => |ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(ref)),
10634 .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref)),
1040210635 }
1040310636}
1040410637
......@@ -10475,6 +10708,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
1047510708 ),
1047610709 }
1047710710 },
10711 .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);
10713 const dst_mem = Memory.sib(
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))),
10720 .reg => |reg| switch (reg) {
10721 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10722 else => false,
10723 },
10724 .frame => |frame_index| self.getFrameAddrAlignment(
10725 .{ .index = frame_index, .off = disp },
10726 ).compare(.gte, ty.abiAlignment(mod)),
10727 })) {
10728 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),
10729 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
10730 ie.extract,
10731 dst_mem,
10732 src_alias,
10733 Immediate.u(0),
10734 ),
10735 }
10736 },
1047810737 .register_overflow => |ro| {
1047910738 try self.genSetMem(
1048010739 base,
......@@ -10511,7 +10770,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
1051110770 },
1051210771 else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }),
1051310772 },
10514 .air_ref => |ref| try self.genSetMem(base, disp, ty, try self.resolveInst(ref)),
10773 .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref)),
1051510774 }
1051610775}
1051710776
......@@ -11475,6 +11734,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
1147511734 const un_op = self.air.instructions.items(.data)[inst].un_op;
1147611735 const inst_ty = self.typeOfIndex(inst);
1147711736 const enum_ty = self.typeOf(un_op);
11737 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);
1147811738
1147911739 // We need a properly aligned and sized call frame to be able to call this function.
1148011740 {
......@@ -11492,9 +11752,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
1149211752 }
1149311753
1149411754 try self.spillEflagsIfOccupied();
11495 try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*));
11755 try self.spillRegisters(abi.getCallerPreservedRegs(resolved_cc));
1149611756
11497 const param_regs = abi.getCAbiIntParamRegs(self.target.*);
11757 const param_regs = abi.getCAbiIntParamRegs(resolved_cc);
1149811758
1149911759 const dst_mcv = try self.allocRegOrMem(inst, false);
1150011760 try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address());
......@@ -12271,23 +12531,27 @@ fn resolveCallingConventionValues(
1227112531
1227212532 const ret_ty = fn_info.return_type.toType();
1227312533
12534 const resolved_cc = abi.resolveCallingConvention(cc, self.target.*);
1227412535 switch (cc) {
1227512536 .Naked => {
1227612537 assert(result.args.len == 0);
1227712538 result.return_value = InstTracking.init(.unreach);
1227812539 result.stack_align = .@"8";
1227912540 },
12280 .C => {
12281 var param_reg_i: usize = 0;
12541 .C, .SysV, .Win64 => {
12542 var ret_int_reg_i: usize = 0;
12543 var ret_sse_reg_i: usize = 0;
12544 var param_int_reg_i: usize = 0;
1228212545 var param_sse_reg_i: usize = 0;
1228312546 result.stack_align = .@"16";
1228412547
12285 switch (self.target.os.tag) {
12286 .windows => {
12548 switch (resolved_cc) {
12549 .SysV => {},
12550 .Win64 => {
1228712551 // Align the stack to 16bytes before allocating shadow stack space (if any).
1228812552 result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod));
1228912553 },
12290 else => {},
12554 else => unreachable,
1229112555 }
1229212556
1229312557 // Return values
......@@ -12297,71 +12561,133 @@ fn resolveCallingConventionValues(
1229712561 // TODO: is this even possible for C calling convention?
1229812562 result.return_value = InstTracking.init(.none);
1229912563 } else {
12300 const classes = switch (self.target.os.tag) {
12301 .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)},
12302 else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),
12564 var ret_tracking: [2]InstTracking = undefined;
12565 var ret_tracking_i: usize = 0;
12566
12567 const classes = switch (resolved_cc) {
12568 .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),
12569 .Win64 => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)},
12570 else => unreachable,
1230312571 };
12304 if (classes.len > 1) {
12305 return self.fail("TODO handle multiple classes per type", .{});
12306 }
12307 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];
12308 result.return_value = switch (classes[0]) {
12309 .integer => InstTracking.init(.{ .register = registerAlias(
12310 ret_reg,
12311 @intCast(ret_ty.abiSize(mod)),
12312 ) }),
12313 .float, .sse => InstTracking.init(.{ .register = .xmm0 }),
12314 .memory => ret: {
12315 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
12316 param_reg_i += 1;
12317 break :ret .{
12318 .short = .{ .indirect = .{ .reg = ret_reg } },
12572 for (classes) |class| switch (class) {
12573 .integer => {
12574 const ret_int_reg = registerAlias(
12575 abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i],
12576 @intCast(@min(ret_ty.abiSize(mod), 8)),
12577 );
12578 ret_int_reg_i += 1;
12579
12580 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
12581 ret_tracking_i += 1;
12582 },
12583 .sse, .float, .float_combine, .win_i128 => {
12584 const ret_sse_reg = registerAlias(
12585 abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i],
12586 @intCast(ret_ty.abiSize(mod)),
12587 );
12588 ret_sse_reg_i += 1;
12589
12590 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_sse_reg });
12591 ret_tracking_i += 1;
12592 },
12593 .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse),
12594 .x87 => {
12595 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = .st0 });
12596 ret_tracking_i += 1;
12597 },
12598 .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87),
12599 .complex_x87 => {
12600 ret_tracking[ret_tracking_i] =
12601 InstTracking.init(.{ .register_pair = .{ .st0, .st1 } });
12602 ret_tracking_i += 1;
12603 },
12604 .memory => {
12605 const ret_int_reg = abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i].to64();
12606 ret_int_reg_i += 1;
12607 const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i];
12608 param_int_reg_i += 1;
12609
12610 ret_tracking[ret_tracking_i] = .{
12611 .short = .{ .indirect = .{ .reg = ret_int_reg } },
1231912612 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
1232012613 };
12614 ret_tracking_i += 1;
1232112615 },
12322 else => |class| return self.fail("TODO handle calling convention class {s}", .{
12323 @tagName(class),
12324 }),
12616 .none => unreachable,
12617 };
12618 result.return_value = switch (ret_tracking_i) {
12619 else => unreachable,
12620 1 => ret_tracking[0],
12621 2 => InstTracking.init(.{ .register_pair = .{
12622 ret_tracking[0].short.register, ret_tracking[1].short.register,
12623 } }),
1232512624 };
1232612625 }
1232712626
1232812627 // Input params
1232912628 for (param_types, result.args) |ty, *arg| {
1233012629 assert(ty.hasRuntimeBitsIgnoreComptime(mod));
12630 switch (resolved_cc) {
12631 .SysV => {},
12632 .Win64 => {
12633 param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i);
12634 param_sse_reg_i = param_int_reg_i;
12635 },
12636 else => unreachable,
12637 }
12638
12639 var arg_mcv: [2]MCValue = undefined;
12640 var arg_mcv_i: usize = 0;
1233112641
1233212642 const classes = switch (self.target.os.tag) {
1233312643 .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)},
1233412644 else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),
1233512645 };
12336 if (classes.len > 1) {
12337 return self.fail("TODO handle multiple classes per type", .{});
12338 }
12339 switch (classes[0]) {
12340 .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) {
12341 arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] };
12342 param_reg_i += 1;
12343 continue;
12646 for (classes) |class| switch (class) {
12647 .integer => {
12648 const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc);
12649 if (param_int_reg_i >= param_int_regs.len) break;
12650
12651 const param_int_reg = registerAlias(
12652 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i],
12653 @intCast(@min(ty.abiSize(mod), 8)),
12654 );
12655 param_int_reg_i += 1;
12656
12657 arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
12658 arg_mcv_i += 1;
1234412659 },
12345 .float, .sse => switch (self.target.os.tag) {
12346 .windows => if (param_reg_i < 4) {
12347 arg.* = .{
12348 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i),
12349 };
12350 param_reg_i += 1;
12351 continue;
12352 },
12353 else => if (param_sse_reg_i < 8) {
12354 arg.* = .{
12355 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_sse_reg_i),
12356 };
12357 param_sse_reg_i += 1;
12358 continue;
12359 },
12660 .sse, .float, .float_combine => {
12661 const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc);
12662 if (param_sse_reg_i >= param_sse_regs.len) break;
12663
12664 const param_sse_reg = registerAlias(
12665 abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i],
12666 @intCast(ty.abiSize(mod)),
12667 );
12668 param_sse_reg_i += 1;
12669
12670 arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };
12671 arg_mcv_i += 1;
1236012672 },
12361 .memory => {}, // fallthrough
12362 else => |class| return self.fail("TODO handle calling convention class {s}", .{
12363 @tagName(class),
12364 }),
12673 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
12674 .x87, .x87up, .complex_x87, .memory => break,
12675 .none => unreachable,
12676 .win_i128 => {
12677 const param_int_reg =
12678 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64();
12679 param_int_reg_i += 1;
12680
12681 arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } };
12682 arg_mcv_i += 1;
12683 },
12684 } else {
12685 arg.* = switch (arg_mcv_i) {
12686 else => unreachable,
12687 1 => arg_mcv[0],
12688 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } },
12689 };
12690 continue;
1236512691 }
1236612692
1236712693 const param_size: u31 = @intCast(ty.abiSize(mod));
......@@ -12384,13 +12710,13 @@ fn resolveCallingConventionValues(
1238412710 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1238512711 result.return_value = InstTracking.init(.none);
1238612712 } else {
12387 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];
12713 const ret_reg = abi.getCAbiIntReturnRegs(resolved_cc)[0];
1238812714 const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod));
1238912715 if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) {
1239012716 const aliased_reg = registerAlias(ret_reg, ret_ty_size);
1239112717 result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none };
1239212718 } else {
12393 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[0];
12719 const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[0];
1239412720 result.return_value = .{
1239512721 .short = .{ .indirect = .{ .reg = ret_reg } },
1239612722 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
......@@ -12462,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
1246212788 reg
1246312789 else
1246412790 unreachable,
12465 .x87 => unreachable,
12791 .x87 => if (size_bytes == 16)
12792 reg
12793 else
12794 unreachable,
1246612795 .mmx => if (size_bytes <= 8)
1246712796 reg
1246812797 else
......@@ -12597,9 +12926,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type {
1259712926
1259812927fn floatLibcAbiPrefix(ty: Type) []const u8 {
1259912928 return switch (ty.toIntern()) {
12600 .f16_type,
12601 .f80_type,
12602 => "__",
12929 .f16_type, .f80_type => "__",
1260312930 .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",
1260412931 else => unreachable,
1260512932 };
src/arch/x86_64/Emit.zig+10-12
......@@ -242,16 +242,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
242242 },
243243 .plan9 => |dbg_out| {
244244 if (delta_pc <= 0) return; // only do this when the pc changes
245 // we have already checked the target in the linker to make sure it is compatable
246 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.lower.target.cpu.arch) catch unreachable;
247245
248246 // increasing the line number
249 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
247 try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line);
250248 // increasing the pc
251 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant;
249 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta;
252250 if (d_pc_p9 > 0) {
253 // minus one because if its the last one, we want to leave space to change the line which is one quanta
254 var diff = @divExact(d_pc_p9, quant) - quant;
251 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
252 var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta;
255253 while (diff > 0) {
256254 if (diff < 64) {
257255 try dbg_out.dbg_line.append(@as(u8, @intCast(diff + 128)));
......@@ -261,15 +259,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
261259 diff -= 64;
262260 }
263261 }
264 if (dbg_out.pcop_change_index.*) |pci|
262 if (dbg_out.pcop_change_index) |pci|
265263 dbg_out.dbg_line.items[pci] += 1;
266 dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
264 dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
267265 } else if (d_pc_p9 == 0) {
268 // we don't need to do anything, because adding the quant does it for us
266 // we don't need to do anything, because adding the pc quanta does it for us
269267 } else unreachable;
270 if (dbg_out.start_line.* == null)
271 dbg_out.start_line.* = emit.prev_di_line;
272 dbg_out.end_line.* = line;
268 if (dbg_out.start_line == null)
269 dbg_out.start_line = emit.prev_di_line;
270 dbg_out.end_line = line;
273271 // only do this if the pc changed
274272 emit.prev_di_line = line;
275273 emit.prev_di_column = column;
src/arch/x86_64/Lower.zig+3-5
......@@ -2,7 +2,7 @@
22
33allocator: Allocator,
44mir: Mir,
5target: *const std.Target,
5cc: std.builtin.CallingConvention,
66err_msg: ?*ErrorMsg = null,
77src_loc: Module.SrcLoc,
88result_insts_len: u8 = undefined,
......@@ -552,15 +552,13 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
552552}
553553
554554fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
555 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);
555 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.cc);
556556 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
557557 .push => .reverse,
558558 .pop => .forward,
559559 else => unreachable,
560560 } });
561 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{
562 .reg = callee_preserved_regs[i],
563 }});
561 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});
564562}
565563
566564const page_size: i32 = 1 << 12;
src/arch/x86_64/abi.zig+60-24
......@@ -137,7 +137,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
137137 return result;
138138 },
139139 128 => {
140 // "Arguments of types__float128, _Decimal128 and__m128 are
140 // "Arguments of types __float128, _Decimal128 and __m128 are
141141 // split into two halves. The least significant ones belong
142142 // to class SSE, the most significant one to class SSEUP."
143143 if (ctx == .other) {
......@@ -213,9 +213,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
213213 const struct_type = mod.typeToStruct(ty).?;
214214 const ty_size = ty.abiSize(mod);
215215 if (struct_type.layout == .Packed) {
216 assert(ty_size <= 128);
216 assert(ty_size <= 16);
217217 result[0] = .integer;
218 if (ty_size > 64) result[1] = .integer;
218 if (ty_size > 8) result[1] = .integer;
219219 return result;
220220 }
221221 if (ty_size > 64)
......@@ -331,9 +331,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
331331 const union_obj = mod.typeToUnion(ty).?;
332332 const ty_size = mod.unionAbiSize(union_obj);
333333 if (union_obj.getLayout(ip) == .Packed) {
334 assert(ty_size <= 128);
334 assert(ty_size <= 16);
335335 result[0] = .integer;
336 if (ty_size > 64) result[1] = .integer;
336 if (ty_size > 8) result[1] = .integer;
337337 return result;
338338 }
339339 if (ty_size > 64)
......@@ -422,11 +422,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
422422 },
423423 .Array => {
424424 const ty_size = ty.abiSize(mod);
425 if (ty_size <= 64) {
425 if (ty_size <= 8) {
426426 result[0] = .integer;
427427 return result;
428428 }
429 if (ty_size <= 128) {
429 if (ty_size <= 16) {
430430 result[0] = .integer;
431431 result[1] = .integer;
432432 return result;
......@@ -447,7 +447,9 @@ pub const SysV = struct {
447447 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;
448448
449449 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].*;
450451 pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
452 pub const c_abi_sse_return_regs = sse_avx_regs[0..2].*;
451453};
452454
453455pub const Win64 = struct {
......@@ -460,34 +462,69 @@ pub const Win64 = struct {
460462 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;
461463
462464 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].*;
463466 pub const c_abi_int_return_regs = [_]Register{.rax};
467 pub const c_abi_sse_return_regs = sse_avx_regs[0..1].*;
464468};
465469
466pub fn getCalleePreservedRegs(target: Target) []const Register {
467 return switch (target.os.tag) {
468 .windows => &Win64.callee_preserved_regs,
469 else => &SysV.callee_preserved_regs,
470pub fn resolveCallingConvention(
471 cc: std.builtin.CallingConvention,
472 target: std.Target,
473) std.builtin.CallingConvention {
474 return switch (cc) {
475 .Unspecified, .C => switch (target.os.tag) {
476 else => .SysV,
477 .windows => .Win64,
478 },
479 else => cc,
480 };
481}
482
483pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention) []const Register {
484 return switch (cc) {
485 .SysV => &SysV.callee_preserved_regs,
486 .Win64 => &Win64.callee_preserved_regs,
487 else => unreachable,
488 };
489}
490
491pub fn getCallerPreservedRegs(cc: std.builtin.CallingConvention) []const Register {
492 return switch (cc) {
493 .SysV => &SysV.caller_preserved_regs,
494 .Win64 => &Win64.caller_preserved_regs,
495 else => unreachable,
496 };
497}
498
499pub fn getCAbiIntParamRegs(cc: std.builtin.CallingConvention) []const Register {
500 return switch (cc) {
501 .SysV => &SysV.c_abi_int_param_regs,
502 .Win64 => &Win64.c_abi_int_param_regs,
503 else => unreachable,
470504 };
471505}
472506
473pub fn getCallerPreservedRegs(target: Target) []const Register {
474 return switch (target.os.tag) {
475 .windows => &Win64.caller_preserved_regs,
476 else => &SysV.caller_preserved_regs,
507pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention) []const Register {
508 return switch (cc) {
509 .SysV => &SysV.c_abi_sse_param_regs,
510 .Win64 => &Win64.c_abi_sse_param_regs,
511 else => unreachable,
477512 };
478513}
479514
480pub fn getCAbiIntParamRegs(target: Target) []const Register {
481 return switch (target.os.tag) {
482 .windows => &Win64.c_abi_int_param_regs,
483 else => &SysV.c_abi_int_param_regs,
515pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention) []const Register {
516 return switch (cc) {
517 .SysV => &SysV.c_abi_int_return_regs,
518 .Win64 => &Win64.c_abi_int_return_regs,
519 else => unreachable,
484520 };
485521}
486522
487pub fn getCAbiIntReturnRegs(target: Target) []const Register {
488 return switch (target.os.tag) {
489 .windows => &Win64.c_abi_int_return_regs,
490 else => &SysV.c_abi_int_return_regs,
523pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register {
524 return switch (cc) {
525 .SysV => &SysV.c_abi_sse_return_regs,
526 .Win64 => &Win64.c_abi_sse_return_regs,
527 else => unreachable,
491528 };
492529}
493530
......@@ -524,7 +561,6 @@ pub const RegisterClass = struct {
524561
525562const builtin = @import("builtin");
526563const std = @import("std");
527const Target = std.Target;
528564const assert = std.debug.assert;
529565const testing = std.testing;
530566
src/codegen.zig+1-22
......@@ -40,28 +40,7 @@ pub const CodeGenError = error{
4040
4141pub const DebugInfoOutput = union(enum) {
4242 dwarf: *link.File.Dwarf.DeclState,
43 /// the plan9 debuginfo output is a bytecode with 4 opcodes
44 /// assume all numbers/variables are bytes
45 /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset
46 /// x when x < 65 -> add x to line offset
47 /// x when x < 129 -> subtract 64 from x and subtract it from the line offset
48 /// x -> subtract 129 from x, multiply it by the quanta of the instruction size
49 /// (1 on x86_64), and add it to the pc
50 /// after every opcode, add the quanta of the instruction size to the pc
51 plan9: struct {
52 /// the actual opcodes
53 dbg_line: *std.ArrayList(u8),
54 /// what line the debuginfo starts on
55 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
56 start_line: *?u32,
57 /// what the line count ends on after codegen
58 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
59 end_line: *u32,
60 /// the last pc change op
61 /// This is very useful for adding quanta
62 /// to it if its not actually the last one.
63 pcop_change_index: *?u32,
64 },
43 plan9: *link.File.Plan9.DebugInfoOutput,
6544 none,
6645};
6746
src/link/Dwarf.zig+74-1
......@@ -566,6 +566,7 @@ pub const DeclState = struct {
566566
567567 pub const DbgInfoLoc = union(enum) {
568568 register: u8,
569 register_pair: [2]u8,
569570 stack: struct {
570571 fp_register: u8,
571572 offset: i32,
......@@ -610,6 +611,42 @@ pub const DeclState = struct {
610611 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
611612 }
612613 },
614 .register_pair => |regs| {
615 const reg_bits = self.mod.getTarget().ptrBitWidth();
616 const reg_bytes = @as(u8, @intCast(@divExact(reg_bits, 8)));
617 const abi_size = ty.abiSize(self.mod);
618 try dbg_info.ensureUnusedCapacity(10);
619 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));
620 // DW.AT.location, DW.FORM.exprloc
621 var expr_len = std.io.countingWriter(std.io.null_writer);
622 for (regs, 0..) |reg, reg_i| {
623 if (reg < 32) {
624 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
625 } else {
626 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
627 leb128.writeULEB128(expr_len.writer(), reg) catch unreachable;
628 }
629 expr_len.writer().writeByte(DW.OP.piece) catch unreachable;
630 leb128.writeULEB128(
631 expr_len.writer(),
632 @min(abi_size - reg_i * reg_bytes, reg_bytes),
633 ) catch unreachable;
634 }
635 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
636 for (regs, 0..) |reg, reg_i| {
637 if (reg < 32) {
638 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
639 } else {
640 dbg_info.appendAssumeCapacity(DW.OP.regx);
641 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
642 }
643 dbg_info.appendAssumeCapacity(DW.OP.piece);
644 leb128.writeULEB128(
645 dbg_info.writer(),
646 @min(abi_size - reg_i * reg_bytes, reg_bytes),
647 ) catch unreachable;
648 }
649 },
613650 .stack => |info| {
614651 try dbg_info.ensureUnusedCapacity(9);
615652 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));
......@@ -676,7 +713,7 @@ pub const DeclState = struct {
676713
677714 switch (loc) {
678715 .register => |reg| {
679 try dbg_info.ensureUnusedCapacity(4);
716 try dbg_info.ensureUnusedCapacity(3);
680717 // DW.AT.location, DW.FORM.exprloc
681718 var expr_len = std.io.countingWriter(std.io.null_writer);
682719 if (reg < 32) {
......@@ -694,6 +731,42 @@ pub const DeclState = struct {
694731 }
695732 },
696733
734 .register_pair => |regs| {
735 const reg_bits = self.mod.getTarget().ptrBitWidth();
736 const reg_bytes = @as(u8, @intCast(@divExact(reg_bits, 8)));
737 const abi_size = child_ty.abiSize(self.mod);
738 try dbg_info.ensureUnusedCapacity(9);
739 // DW.AT.location, DW.FORM.exprloc
740 var expr_len = std.io.countingWriter(std.io.null_writer);
741 for (regs, 0..) |reg, reg_i| {
742 if (reg < 32) {
743 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
744 } else {
745 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
746 leb128.writeULEB128(expr_len.writer(), reg) catch unreachable;
747 }
748 expr_len.writer().writeByte(DW.OP.piece) catch unreachable;
749 leb128.writeULEB128(
750 expr_len.writer(),
751 @min(abi_size - reg_i * reg_bytes, reg_bytes),
752 ) catch unreachable;
753 }
754 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
755 for (regs, 0..) |reg, reg_i| {
756 if (reg < 32) {
757 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
758 } else {
759 dbg_info.appendAssumeCapacity(DW.OP.regx);
760 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
761 }
762 dbg_info.appendAssumeCapacity(DW.OP.piece);
763 leb128.writeULEB128(
764 dbg_info.writer(),
765 @min(abi_size - reg_i * reg_bytes, reg_bytes),
766 ) catch unreachable;
767 }
768 },
769
697770 .stack => |info| {
698771 try dbg_info.ensureUnusedCapacity(9);
699772 // DW.AT.location, DW.FORM.exprloc
src/link/Plan9.zig+38-16
......@@ -211,6 +211,31 @@ pub const Atom = struct {
211211 }
212212};
213213
214/// the plan9 debuginfo output is a bytecode with 4 opcodes
215/// assume all numbers/variables are bytes
216/// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset
217/// x when x < 65 -> add x to line offset
218/// x when x < 129 -> subtract 64 from x and subtract it from the line offset
219/// x -> subtract 129 from x, multiply it by the quanta of the instruction size
220/// (1 on x86_64), and add it to the pc
221/// after every opcode, add the quanta of the instruction size to the pc
222pub const DebugInfoOutput = struct {
223 /// the actual opcodes
224 dbg_line: std.ArrayList(u8),
225 /// what line the debuginfo starts on
226 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
227 start_line: ?u32,
228 /// what the line count ends on after codegen
229 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
230 end_line: u32,
231 /// the last pc change op
232 /// This is very useful for adding quanta
233 /// to it if its not actually the last one.
234 pcop_change_index: ?u32,
235 /// cached pc quanta
236 pc_quanta: u8,
237};
238
214239const DeclMetadata = struct {
215240 index: Atom.Index,
216241 exports: std.ArrayListUnmanaged(usize) = .{},
......@@ -376,11 +401,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
376401
377402 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
378403 defer code_buffer.deinit();
379 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
380 defer dbg_line_buffer.deinit();
381 var start_line: ?u32 = null;
382 var end_line: u32 = undefined;
383 var pcop_change_index: ?u32 = null;
404 var dbg_info_output: DebugInfoOutput = .{
405 .dbg_line = std.ArrayList(u8).init(self.base.allocator),
406 .start_line = null,
407 .end_line = undefined,
408 .pcop_change_index = null,
409 // we have already checked the target in the linker to make sure it is compatable
410 .pc_quanta = aout.getPCQuant(self.base.options.target.cpu.arch) catch unreachable,
411 };
412 defer dbg_info_output.dbg_line.deinit();
384413
385414 const res = try codegen.generateFunction(
386415 &self.base,
......@@ -389,14 +418,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
389418 air,
390419 liveness,
391420 &code_buffer,
392 .{
393 .plan9 = .{
394 .dbg_line = &dbg_line_buffer,
395 .end_line = &end_line,
396 .start_line = &start_line,
397 .pcop_change_index = &pcop_change_index,
398 },
399 },
421 .{ .plan9 = &dbg_info_output },
400422 );
401423 const code = switch (res) {
402424 .ok => try code_buffer.toOwnedSlice(),
......@@ -412,9 +434,9 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
412434 };
413435 const out: FnDeclOutput = .{
414436 .code = code,
415 .lineinfo = try dbg_line_buffer.toOwnedSlice(),
416 .start_line = start_line.?,
417 .end_line = end_line,
437 .lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(),
438 .start_line = dbg_info_output.start_line.?,
439 .end_line = dbg_info_output.end_line,
418440 };
419441 try self.putFn(decl_index, out);
420442 return self.updateFinish(decl_index);
test/behavior/abs.zig+1-1
......@@ -97,7 +97,7 @@ test "@abs floats" {
9797 try comptime testAbsFloats(f80);
9898 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);
9999 try comptime testAbsFloats(f128);
100 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);
100 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);
101101}
102102
103103fn testAbsFloats(comptime T: type) !void {
test/behavior/bitcast.zig+2-2
......@@ -297,11 +297,11 @@ test "triple level result location with bitcast sandwich passed as tuple element
297297test "@bitCast packed struct of floats" {
298298 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
299299 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
300 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
301300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
303302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
304303 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
305305
306306 const Foo = packed struct {
307307 a: f16 = 0,
......@@ -375,11 +375,11 @@ test "comptime @bitCast packed struct to int and back" {
375375
376376test "comptime bitcast with fields following f80" {
377377 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
379378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
381380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382381 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
383383
384384 const FloatT = extern struct { f: f80, x: u128 align(16) };
385385 const x: FloatT = .{ .f = 0.5, .x = 123 };
test/behavior/bugs/11995.zig-1
......@@ -18,7 +18,6 @@ const wuffs_base__slice_u8 = extern struct {
1818};
1919test {
2020 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/cast.zig+2-2
......@@ -1369,10 +1369,10 @@ fn boolToStr(b: bool) []const u8 {
13691369test "cast f16 to wider types" {
13701370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13711371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1372 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
13731372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13741373 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13751374 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
1375 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
13761376
13771377 const S = struct {
13781378 fn doTheTest() !void {
......@@ -1389,9 +1389,9 @@ test "cast f16 to wider types" {
13891389test "cast f128 to narrower types" {
13901390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13911391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1392 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
13931392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13941393 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1394 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
13951395
13961396 const S = struct {
13971397 fn doTheTest() !void {
test/behavior/floatop.zig+2-2
......@@ -130,7 +130,7 @@ test "cmp f128" {
130130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131131 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
132132 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
133 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
133 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
134134
135135 try testCmp(f128);
136136 try comptime testCmp(f128);
......@@ -1379,7 +1379,7 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
13791379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13801380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13811381 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1382 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1382 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
13831383
13841384 inline for (.{ f16, f32, f64, f80, f128 }) |F| {
13851385 try expect(math.isNan(@as(F, 0) / @as(F, 0)));
test/behavior/math.zig+3-4
......@@ -637,11 +637,11 @@ fn testShrTrunc(x: u16) !void {
637637}
638638
639639test "f128" {
640 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
641640 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
642641 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
643642 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
644643 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
644 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
645645
646646 try test_f128();
647647 try comptime test_f128();
......@@ -1481,7 +1481,6 @@ test "@round f80" {
14811481test "@round f128" {
14821482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14831483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1484 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14851484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14861485 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
14871486 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
......@@ -1522,9 +1521,9 @@ test "vector integer addition" {
15221521test "NaN comparison" {
15231522 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15241523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
15261524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15271525 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1526 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
15281527
15291528 try testNanEqNan(f16);
15301529 try testNanEqNan(f32);
......@@ -1539,9 +1538,9 @@ test "NaN comparison" {
15391538test "NaN comparison f80" {
15401539 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15411540 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1542 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
15431541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15441542 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1543 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
15451544
15461545 try testNanEqNan(f80);
15471546 try comptime testNanEqNan(f80);
test/behavior/maximum_minimum.zig+4-3
......@@ -10,7 +10,6 @@ test "@max" {
1010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1413
1514 const S = struct {
1615 fn doTheTest() !void {
......@@ -30,7 +29,8 @@ test "@max on vectors" {
3029 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_x86_64 and
33 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
3434
3535 const S = struct {
3636 fn doTheTest() !void {
......@@ -78,7 +78,8 @@ test "@min for vectors" {
7878 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7979 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8080 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_x86_64 and
82 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
8283
8384 const S = struct {
8485 fn doTheTest() !void {
test/behavior/packed-struct.zig-1
......@@ -258,7 +258,6 @@ test "nested packed struct unaligned" {
258258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
259259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
261 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
262261 if (native_endian != .Little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
263262
264263 const S1 = packed struct {
test/behavior/widening.zig+1-1
......@@ -60,11 +60,11 @@ test "float widening" {
6060}
6161
6262test "float widening f16 to f128" {
63 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6665 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
6868
6969 var x: f16 = 12.34;
7070 var y: f128 = x;