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;...@@ -156,7 +156,7 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
156156
157pub usingnamespace if (switch (builtin.zig_backend) {157pub usingnamespace if (switch (builtin.zig_backend) {
158 // Calling extern functions is not yet supported with these backends158 // 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,
160 else => !builtin.link_libc,160 else => !builtin.link_libc,
161}) struct {161}) struct {
162 /// See `std.elf` for the constants.162 /// 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 {...@@ -445,25 +445,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
445 },445 },
446 .plan9 => |dbg_out| {446 .plan9 => |dbg_out| {
447 if (delta_pc <= 0) return; // only do this when the pc changes447 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
451 // increasing the line number449 // 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);
453 // increasing the pc451 // 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;
455 if (d_pc_p9 > 0) {453 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 quanta454 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
457 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant);455 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta);
458 if (dbg_out.pcop_change_index.*) |pci|456 if (dbg_out.pcop_change_index) |pci|
459 dbg_out.dbg_line.items[pci] += 1;457 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));
461 } else if (d_pc_p9 == 0) {459 } else if (d_pc_p9 == 0) {
462 // we don't need to do anything, because adding the quant does it for us460 // we don't need to do anything, because adding the pc quanta does it for us
463 } else unreachable;461 } else unreachable;
464 if (dbg_out.start_line.* == null)462 if (dbg_out.start_line == null)
465 dbg_out.start_line.* = self.prev_di_line;463 dbg_out.start_line = self.prev_di_line;
466 dbg_out.end_line.* = line;464 dbg_out.end_line = line;
467 // only do this if the pc changed465 // only do this if the pc changed
468 self.prev_di_line = line;466 self.prev_di_line = line;
469 self.prev_di_column = column;467 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 {...@@ -362,25 +362,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
362 },362 },
363 .plan9 => |dbg_out| {363 .plan9 => |dbg_out| {
364 if (delta_pc <= 0) return; // only do this when the pc changes364 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
368 // increasing the line number366 // 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);
370 // increasing the pc368 // 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;
372 if (d_pc_p9 > 0) {370 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 quanta371 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
374 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant);372 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta);
375 if (dbg_out.pcop_change_index.*) |pci|373 if (dbg_out.pcop_change_index) |pci|
376 dbg_out.dbg_line.items[pci] += 1;374 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));
378 } else if (d_pc_p9 == 0) {376 } else if (d_pc_p9 == 0) {
379 // we don't need to do anything, because adding the quant does it for us377 // we don't need to do anything, because adding the pc quanta does it for us
380 } else unreachable;378 } else unreachable;
381 if (dbg_out.start_line.* == null)379 if (dbg_out.start_line == null)
382 dbg_out.start_line.* = self.prev_di_line;380 dbg_out.start_line = self.prev_di_line;
383 dbg_out.end_line.* = line;381 dbg_out.end_line = line;
384 // only do this if the pc changed382 // only do this if the pc changed
385 self.prev_di_line = line;383 self.prev_di_line = line;
386 self.prev_di_column = column;384 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 {...@@ -96,25 +96,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
96 },96 },
97 .plan9 => |dbg_out| {97 .plan9 => |dbg_out| {
98 if (delta_pc <= 0) return; // only do this when the pc changes98 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
102 // increasing the line number100 // 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);
104 // increasing the pc102 // 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;
106 if (d_pc_p9 > 0) {104 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 quanta105 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
108 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant);106 try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta);
109 if (dbg_out.pcop_change_index.*) |pci|107 if (dbg_out.pcop_change_index) |pci|
110 dbg_out.dbg_line.items[pci] += 1;108 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));
112 } else if (d_pc_p9 == 0) {110 } else if (d_pc_p9 == 0) {
113 // we don't need to do anything, because adding the quant does it for us111 // we don't need to do anything, because adding the pc quanta does it for us
114 } else unreachable;112 } else unreachable;
115 if (dbg_out.start_line.* == null)113 if (dbg_out.start_line == null)
116 dbg_out.start_line.* = self.prev_di_line;114 dbg_out.start_line = self.prev_di_line;
117 dbg_out.end_line.* = line;115 dbg_out.end_line = line;
118 // only do this if the pc changed116 // only do this if the pc changed
119 self.prev_di_line = line;117 self.prev_di_line = line;
120 self.prev_di_column = column;118 self.prev_di_column = column;
src/arch/x86_64/CodeGen.zig+617-290
...@@ -178,6 +178,8 @@ pub const MCValue = union(enum) {...@@ -178,6 +178,8 @@ pub const MCValue = union(enum) {
178 eflags: Condition,178 eflags: Condition,
179 /// The value is in a register.179 /// The value is in a register.
180 register: Register,180 register: Register,
181 /// The value is split across two registers.
182 register_pair: [2]Register,
181 /// The value is a constant offset from the value in a register.183 /// The value is a constant offset from the value in a register.
182 register_offset: RegisterOffset,184 register_offset: RegisterOffset,
183 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.185 /// 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) {...@@ -255,6 +257,16 @@ pub const MCValue = union(enum) {
255 };257 };
256 }258 }
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
258 fn getCondition(mcv: MCValue) ?Condition {270 fn getCondition(mcv: MCValue) ?Condition {
259 return switch (mcv) {271 return switch (mcv) {
260 .eflags => |cc| cc,272 .eflags => |cc| cc,
...@@ -272,6 +284,7 @@ pub const MCValue = union(enum) {...@@ -272,6 +284,7 @@ pub const MCValue = union(enum) {
272 .immediate,284 .immediate,
273 .eflags,285 .eflags,
274 .register,286 .register,
287 .register_pair,
275 .register_offset,288 .register_offset,
276 .register_overflow,289 .register_overflow,
277 .lea_direct,290 .lea_direct,
...@@ -300,6 +313,7 @@ pub const MCValue = union(enum) {...@@ -300,6 +313,7 @@ pub const MCValue = union(enum) {
300 .dead,313 .dead,
301 .undef,314 .undef,
302 .eflags,315 .eflags,
316 .register_pair,
303 .register_overflow,317 .register_overflow,
304 .memory,318 .memory,
305 .indirect,319 .indirect,
...@@ -326,7 +340,11 @@ pub const MCValue = union(enum) {...@@ -326,7 +340,11 @@ pub const MCValue = union(enum) {
326 .unreach,340 .unreach,
327 .dead,341 .dead,
328 .undef,342 .undef,
343 .reserved_frame,
344 .air_ref,
345 => unreachable, // not valid
329 .eflags,346 .eflags,
347 .register_pair,
330 .register_overflow,348 .register_overflow,
331 .memory,349 .memory,
332 .indirect,350 .indirect,
...@@ -337,9 +355,10 @@ pub const MCValue = union(enum) {...@@ -337,9 +355,10 @@ pub const MCValue = union(enum) {
337 .load_tlv,355 .load_tlv,
338 .lea_tlv,356 .lea_tlv,
339 .load_frame,357 .load_frame,
340 .reserved_frame,358 => switch (off) {
341 .air_ref,359 0 => mcv,
342 => unreachable, // not offsettable360 else => unreachable, // not offsettable
361 },
343 .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },362 .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
344 .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },363 .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
345 .register_offset => |reg_off| .{364 .register_offset => |reg_off| .{
...@@ -360,6 +379,7 @@ pub const MCValue = union(enum) {...@@ -360,6 +379,7 @@ pub const MCValue = union(enum) {
360 .immediate,379 .immediate,
361 .eflags,380 .eflags,
362 .register,381 .register,
382 .register_pair,
363 .register_offset,383 .register_offset,
364 .register_overflow,384 .register_overflow,
365 .load_direct,385 .load_direct,
...@@ -398,8 +418,11 @@ pub const MCValue = union(enum) {...@@ -398,8 +418,11 @@ pub const MCValue = union(enum) {
398 .immediate => |pl| try writer.print("0x{x}", .{pl}),418 .immediate => |pl| try writer.print("0x{x}", .{pl}),
399 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),419 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
400 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),420 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]) }),
401 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),422 .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 }),
403 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),426 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
404 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),427 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
405 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),428 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
...@@ -443,6 +466,7 @@ const InstTracking = struct {...@@ -443,6 +466,7 @@ const InstTracking = struct {
443 => unreachable,466 => unreachable,
444 .eflags,467 .eflags,
445 .register,468 .register,
469 .register_pair,
446 .register_offset,470 .register_offset,
447 .register_overflow,471 .register_overflow,
448 .indirect,472 .indirect,
...@@ -454,6 +478,10 @@ const InstTracking = struct {...@@ -454,6 +478,10 @@ const InstTracking = struct {
454 return self.short.getReg();478 return self.short.getReg();
455 }479 }
456480
481 fn getRegs(self: *const InstTracking) []const Register {
482 return self.short.getRegs();
483 }
484
457 fn getCondition(self: InstTracking) ?Condition {485 fn getCondition(self: InstTracking) ?Condition {
458 return self.short.getCondition();486 return self.short.getCondition();
459 }487 }
...@@ -494,6 +522,7 @@ const InstTracking = struct {...@@ -494,6 +522,7 @@ const InstTracking = struct {
494 .dead,522 .dead,
495 .eflags,523 .eflags,
496 .register,524 .register,
525 .register_pair,
497 .register_offset,526 .register_offset,
498 .register_overflow,527 .register_overflow,
499 .indirect,528 .indirect,
...@@ -536,6 +565,7 @@ const InstTracking = struct {...@@ -536,6 +565,7 @@ const InstTracking = struct {
536 .dead,565 .dead,
537 .eflags,566 .eflags,
538 .register,567 .register,
568 .register_pair,
539 .register_offset,569 .register_offset,
540 .register_overflow,570 .register_overflow,
541 .indirect,571 .indirect,
...@@ -777,7 +807,7 @@ pub fn generate(...@@ -777,7 +807,7 @@ pub fn generate(
777 .lower = .{807 .lower = .{
778 .allocator = bin_file.allocator,808 .allocator = bin_file.allocator,
779 .mir = mir,809 .mir = mir,
780 .target = &bin_file.options.target,810 .cc = abi.resolveCallingConvention(fn_info.cc, function.target.*),
781 .src_loc = src_loc,811 .src_loc = src_loc,
782 },812 },
783 .bin_file = bin_file,813 .bin_file = bin_file,
...@@ -863,7 +893,7 @@ pub fn generateLazy(...@@ -863,7 +893,7 @@ pub fn generateLazy(
863 .lower = .{893 .lower = .{
864 .allocator = bin_file.allocator,894 .allocator = bin_file.allocator,
865 .mir = mir,895 .mir = mir,
866 .target = &bin_file.options.target,896 .cc = abi.resolveCallingConvention(.Unspecified, function.target.*),
867 .src_loc = src_loc,897 .src_loc = src_loc,
868 },898 },
869 .bin_file = bin_file,899 .bin_file = bin_file,
...@@ -950,6 +980,7 @@ fn formatWipMir(...@@ -950,6 +980,7 @@ fn formatWipMir(
950 _: std.fmt.FormatOptions,980 _: std.fmt.FormatOptions,
951 writer: anytype,981 writer: anytype,
952) @TypeOf(writer).Error!void {982) @TypeOf(writer).Error!void {
983 const mod = data.self.bin_file.options.module.?;
953 var lower = Lower{984 var lower = Lower{
954 .allocator = data.self.gpa,985 .allocator = data.self.gpa,
955 .mir = .{986 .mir = .{
...@@ -957,7 +988,7 @@ fn formatWipMir(...@@ -957,7 +988,7 @@ fn formatWipMir(
957 .extra = data.self.mir_extra.items,988 .extra = data.self.mir_extra.items,
958 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),989 .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
959 },990 },
960 .target = data.self.target,991 .cc = mod.typeToFunc(data.self.fn_type).?.cc,
961 .src_loc = data.self.src_loc,992 .src_loc = data.self.src_loc,
962 };993 };
963 for ((lower.lowerMir(data.inst) catch |err| switch (err) {994 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
...@@ -1650,7 +1681,7 @@ fn gen(self: *Self) InnerError!void {...@@ -1650,7 +1681,7 @@ fn gen(self: *Self) InnerError!void {
1650 try self.asmRegister(.{ ._, .pop }, .rbp);1681 try self.asmRegister(.{ ._, .pop }, .rbp);
1651 try self.asmOpOnly(.{ ._, .ret });1682 try self.asmOpOnly(.{ ._, .ret });
16521683
1653 const frame_layout = try self.computeFrameLayout();1684 const frame_layout = try self.computeFrameLayout(cc);
1654 const need_frame_align = frame_layout.stack_mask != math.maxInt(u32);1685 const need_frame_align = frame_layout.stack_mask != math.maxInt(u32);
1655 const need_stack_adjust = frame_layout.stack_adjust > 0;1686 const need_stack_adjust = frame_layout.stack_adjust > 0;
1656 const need_save_reg = frame_layout.save_reg_list.count() > 0;1687 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 {...@@ -2028,7 +2059,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
2028 while (it.next()) |index| {2059 while (it.next()) |index| {
2029 const tracked_inst = self.register_manager.registers[index];2060 const tracked_inst = self.register_manager.registers[index];
2030 const tracking = self.getResolvedInstValue(tracked_inst);2061 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
2032 }2065 }
2033 }2066 }
2034 }2067 }
...@@ -2043,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -2043,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2043 const enum_ty = lazy_sym.ty;2076 const enum_ty = lazy_sym.ty;
2044 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)});2077 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);
2047 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);2081 const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
2048 defer for (param_locks) |lock| self.register_manager.unlockReg(lock);2082 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 {...@@ -2094,27 +2128,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
2094}2128}
20952129
2096fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {2130fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
2097 const reg = value.getReg() orelse return;2131 for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg))
2098 if (self.register_manager.isRegFree(reg)) {
2099 self.register_manager.getRegAssumeFree(reg, inst);2132 self.register_manager.getRegAssumeFree(reg, inst);
2100 }
2101}2133}
21022134
2103fn freeValue(self: *Self, value: MCValue) void {2135fn freeValue(self: *Self, value: MCValue) void {
2104 switch (value) {2136 switch (value) {
2105 .register => |reg| {2137 .register => |reg| self.register_manager.freeReg(reg),
2106 self.register_manager.freeReg(reg);2138 .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg),
2107 },2139 .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg),
2108 .register_offset => |reg_off| {
2109 self.register_manager.freeReg(reg_off.reg);
2110 },
2111 .register_overflow => |reg_ov| {2140 .register_overflow => |reg_ov| {
2112 self.register_manager.freeReg(reg_ov.reg);2141 self.register_manager.freeReg(reg_ov.reg);
2113 self.eflags_inst = null;2142 self.eflags_inst = null;
2114 },2143 },
2115 .eflags => {2144 .eflags => self.eflags_inst = null,
2116 self.eflags_inst = null;
2117 },
2118 else => {}, // TODO process stack allocation death2145 else => {}, // TODO process stack allocation death
2119 }2146 }
2120}2147}
...@@ -2183,7 +2210,7 @@ fn setFrameLoc(...@@ -2183,7 +2210,7 @@ fn setFrameLoc(
2183 offset.* += self.frame_allocs.items(.abi_size)[frame_i];2210 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
2184}2211}
21852212
2186fn computeFrameLayout(self: *Self) !FrameLayout {2213fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout {
2187 const frame_allocs_len = self.frame_allocs.len;2214 const frame_allocs_len = self.frame_allocs.len;
2188 try self.frame_locs.resize(self.gpa, frame_allocs_len);2215 try self.frame_locs.resize(self.gpa, frame_allocs_len);
2189 const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);2216 const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);
...@@ -2215,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout {...@@ -2215,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
2215 // Create list of registers to save in the prologue.2242 // Create list of registers to save in the prologue.
2216 // TODO handle register classes2243 // TODO handle register classes
2217 var save_reg_list = Mir.RegisterList{};2244 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.*));
2219 for (callee_preserved_regs) |reg| {2247 for (callee_preserved_regs) |reg| {
2220 if (self.register_manager.isRegAllocated(reg)) {2248 if (self.register_manager.isRegAllocated(reg)) {
2221 save_reg_list.push(callee_preserved_regs, reg);2249 save_reg_list.push(callee_preserved_regs, reg);
...@@ -2449,7 +2477,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2449,7 +2477,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
24492477
2450pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {2478pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
2451 const tracking = self.inst_tracking.getPtr(inst) orelse return;2479 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
2453 try tracking.spill(self, inst);2483 try tracking.spill(self, inst);
2454 tracking.trackSpill(self, inst);2484 tracking.trackSpill(self, inst);
2455}2485}
...@@ -2465,9 +2495,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {...@@ -2465,9 +2495,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
2465}2495}
24662496
2467pub fn spillRegisters(self: *Self, registers: []const Register) !void {2497pub fn spillRegisters(self: *Self, registers: []const Register) !void {
2468 for (registers) |reg| {2498 for (registers) |reg| try self.register_manager.getReg(reg, null);
2469 try self.register_manager.getReg(reg, null);
2470 }
2471}2499}
24722500
2473/// Copies a value to a register without tracking the register. The register is not considered2501/// Copies a value to a register without tracking the register. The register is not considered
...@@ -5457,8 +5485,8 @@ fn reuseOperandAdvanced(...@@ -5457,8 +5485,8 @@ fn reuseOperandAdvanced(
5457 return false;5485 return false;
54585486
5459 switch (mcv) {5487 switch (mcv) {
5460 .register => |reg| {5488 .register, .register_pair => for (mcv.getRegs()) |reg| {
5461 // If it's in the registers table, need to associate the register with the5489 // If it's in the registers table, need to associate the register(s) with the
5462 // new instruction.5490 // new instruction.
5463 if (!self.register_manager.isRegFree(reg)) {5491 if (!self.register_manager.isRegFree(reg)) {
5464 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {5492 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
...@@ -5561,6 +5589,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro...@@ -5561,6 +5589,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
5561 .dead,5589 .dead,
5562 .undef,5590 .undef,
5563 .eflags,5591 .eflags,
5592 .register_pair,
5564 .register_overflow,5593 .register_overflow,
5565 .reserved_frame,5594 .reserved_frame,
5566 => unreachable, // not a valid pointer5595 => unreachable, // not a valid pointer
...@@ -5585,7 +5614,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro...@@ -5585,7 +5614,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
55855614
5586 try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });5615 try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
5587 },5616 },
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)),
5589 }5618 }
5590}5619}
55915620
...@@ -5707,6 +5736,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr...@@ -5707,6 +5736,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
5707 .dead,5736 .dead,
5708 .undef,5737 .undef,
5709 .eflags,5738 .eflags,
5739 .register_pair,
5710 .register_overflow,5740 .register_overflow,
5711 .reserved_frame,5741 .reserved_frame,
5712 => unreachable, // not a valid pointer5742 => unreachable, // not a valid pointer
...@@ -5731,7 +5761,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr...@@ -5731,7 +5761,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
57315761
5732 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);5762 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
5733 },5763 },
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)),
5735 }5765 }
5736}5766}
57375767
...@@ -6077,6 +6107,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC...@@ -6077,6 +6107,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
6077 .air_ref,6107 .air_ref,
6078 => unreachable, // unmodifiable destination6108 => unreachable, // unmodifiable destination
6079 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),6109 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
6110 .register_pair => unreachable, // unimplemented
6080 .memory, .load_got, .load_direct, .load_tlv => {6111 .memory, .load_got, .load_direct, .load_tlv => {
6081 const addr_reg = try self.register_manager.allocReg(null, gp);6112 const addr_reg = try self.register_manager.allocReg(null, gp);
6082 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);6113 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
...@@ -6764,7 +6795,7 @@ fn genBinOp(...@@ -6764,7 +6795,7 @@ fn genBinOp(
6764 => {6795 => {
6765 const resolved_src_mcv = switch (src_mcv) {6796 const resolved_src_mcv = switch (src_mcv) {
6766 else => src_mcv,6797 else => src_mcv,
6767 .air_ref => |ref| try self.resolveInst(ref),6798 .air_ref => |src_ref| try self.resolveInst(src_ref),
6768 };6799 };
6769 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {6800 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
6770 .immediate,6801 .immediate,
...@@ -6780,6 +6811,9 @@ fn genBinOp(...@@ -6780,6 +6811,9 @@ fn genBinOp(
6780 => true,6811 => true,
6781 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,6812 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
6782 else => false,6813 else => false,
6814 .register_pair,
6815 .register_overflow,
6816 => unreachable,
6783 })6817 })
6784 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }6818 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
6785 else6819 else
...@@ -6820,6 +6854,7 @@ fn genBinOp(...@@ -6820,6 +6854,7 @@ fn genBinOp(
6820 .undef,6854 .undef,
6821 .immediate,6855 .immediate,
6822 .eflags,6856 .eflags,
6857 .register_pair,
6823 .register_offset,6858 .register_offset,
6824 .register_overflow,6859 .register_overflow,
6825 .load_direct,6860 .load_direct,
...@@ -7748,121 +7783,154 @@ fn genBinOpMir(...@@ -7748,121 +7783,154 @@ fn genBinOpMir(
7748 .reserved_frame,7783 .reserved_frame,
7749 .air_ref,7784 .air_ref,
7750 => unreachable, // unmodifiable destination7785 => unreachable, // unmodifiable destination
7751 .register, .register_offset => {7786 .register, .register_pair, .register_offset => {
7752 assert(dst_mcv.isRegister());7787 switch (dst_mcv) {
7753 const dst_reg = dst_mcv.getReg().?;7788 .register, .register_pair => {},
7754 const dst_alias = registerAlias(dst_reg, abi_size);7789 .register_offset => |ro| assert(ro.off == 0),
7755 switch (src_mcv) {7790 else => unreachable,
7756 .none,7791 }
7757 .unreach,7792 for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| {
7758 .dead,7793 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
7759 .undef,7794 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
7760 .register_overflow,7795
7761 .reserved_frame,7796 const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) {
7762 => unreachable,7797 0 => mir_tag,
7763 .register => |src_reg| try self.asmRegisterRegister(7798 1 => switch (mir_tag[1]) {
7764 mir_tag,7799 .add => .{ ._, .adc },
7765 dst_alias,7800 .sub, .cmp => .{ ._, .sbb },
7766 registerAlias(src_reg, abi_size),7801 .@"or", .@"and", .xor => mir_tag,
7767 ),7802 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
7768 .immediate => |imm| switch (self.regBitSize(ty)) {7803 @tagName(mir_tag[1]),
7769 8 => try self.asmRegisterImmediate(7804 }),
7770 mir_tag,7805 },
7771 dst_alias,7806 else => unreachable,
7772 if (math.cast(i8, @as(i64, @bitCast(imm)))) |small|7807 };
7773 Immediate.s(small)7808 const off: u4 = @intCast(dst_reg_i * 8);
7774 else7809 const limb_abi_size = @min(abi_size - off, 8);
7775 Immediate.u(@as(u8, @intCast(imm))),7810 const dst_alias = registerAlias(dst_reg, limb_abi_size);
7776 ),7811 switch (src_mcv) {
7777 16 => try self.asmRegisterImmediate(7812 .none,
7778 mir_tag,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,
7779 dst_alias,7821 dst_alias,
7780 if (math.cast(i16, @as(i64, @bitCast(imm)))) |small|7822 registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),
7781 Immediate.s(small)
7782 else
7783 Immediate.u(@as(u16, @intCast(imm))),
7784 ),7823 ),
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(
7786 mir_tag,7928 mir_tag,
7787 dst_alias,7929 ty,
7788 if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|7930 dst_mcv,
7789 Immediate.s(small)7931 try self.resolveInst(src_ref),
7790 else
7791 Immediate.u(@as(u32, @intCast(imm))),
7792 ),7932 ),
7793 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|7933 }
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)),
7866 }7934 }
7867 },7935 },
7868 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {7936 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
...@@ -7877,10 +7945,7 @@ fn genBinOpMir(...@@ -7877,10 +7945,7 @@ fn genBinOpMir(
7877 errdefer self.register_manager.unlockReg(dst_addr_lock);7945 errdefer self.register_manager.unlockReg(dst_addr_lock);
78787946
7879 try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address());7947 try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address());
7880 break :dst .{7948 break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock };
7881 .addr_reg = dst_addr_reg,
7882 .addr_lock = dst_addr_lock,
7883 };
7884 },7949 },
7885 .load_frame => null,7950 .load_frame => null,
7886 };7951 };
...@@ -7888,7 +7953,7 @@ fn genBinOpMir(...@@ -7888,7 +7953,7 @@ fn genBinOpMir(
78887953
7889 const resolved_src_mcv = switch (src_mcv) {7954 const resolved_src_mcv = switch (src_mcv) {
7890 else => src_mcv,7955 else => src_mcv,
7891 .air_ref => |ref| try self.resolveInst(ref),7956 .air_ref => |src_ref| try self.resolveInst(src_ref),
7892 };7957 };
7893 const src_info: OpInfo = switch (resolved_src_mcv) {7958 const src_info: OpInfo = switch (resolved_src_mcv) {
7894 .none,7959 .none,
...@@ -7900,9 +7965,10 @@ fn genBinOpMir(...@@ -7900,9 +7965,10 @@ fn genBinOpMir(
7900 .air_ref,7965 .air_ref,
7901 => unreachable,7966 => unreachable,
7902 .immediate,7967 .immediate,
7968 .eflags,
7903 .register,7969 .register,
7970 .register_pair,
7904 .register_offset,7971 .register_offset,
7905 .eflags,
7906 .indirect,7972 .indirect,
7907 .lea_direct,7973 .lea_direct,
7908 .lea_got,7974 .lea_got,
...@@ -7924,10 +7990,7 @@ fn genBinOpMir(...@@ -7924,10 +7990,7 @@ fn genBinOpMir(
7924 errdefer self.register_manager.unlockReg(src_addr_lock);7990 errdefer self.register_manager.unlockReg(src_addr_lock);
79257991
7926 try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address());7992 try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address());
7927 break :src .{7993 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
7928 .addr_reg = src_addr_reg,
7929 .addr_lock = src_addr_lock,
7930 };
7931 },7994 },
7932 };7995 };
7933 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);7996 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
...@@ -7938,9 +8001,13 @@ fn genBinOpMir(...@@ -7938,9 +8001,13 @@ fn genBinOpMir(
7938 .signed => Type.usize,8001 .signed => Type.usize,
7939 .unsigned => Type.isize,8002 .unsigned => Type.isize,
7940 };8003 };
8004 var limb_i: usize = 0;
7941 var off: i32 = 0;8005 var off: i32 = 0;
7942 while (off < abi_size) : (off += 8) {8006 while (off < abi_size) : ({
7943 const mir_limb_tag: Mir.Inst.FixedTag = switch (off) {8007 limb_i += 1;
8008 off += 8;
8009 }) {
8010 const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) {
7944 0 => mir_tag,8011 0 => mir_tag,
7945 else => switch (mir_tag[1]) {8012 else => switch (mir_tag[1]) {
7946 .add => .{ ._, .adc },8013 .add => .{ ._, .adc },
...@@ -7979,16 +8046,8 @@ fn genBinOpMir(...@@ -7979,16 +8046,8 @@ fn genBinOpMir(
7979 .reserved_frame,8046 .reserved_frame,
7980 .air_ref,8047 .air_ref,
7981 => unreachable,8048 => 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 },
7990 .immediate => |src_imm| {8049 .immediate => |src_imm| {
7991 const imm: u64 = switch (off) {8050 const imm: u64 = switch (limb_i) {
7992 0 => src_imm,8051 0 => src_imm,
7993 else => switch (ty_signedness) {8052 else => switch (ty_signedness) {
7994 .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63),8053 .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63),
...@@ -8038,6 +8097,8 @@ fn genBinOpMir(...@@ -8038,6 +8097,8 @@ fn genBinOpMir(
8038 else => unreachable,8097 else => unreachable,
8039 }8098 }
8040 },8099 },
8100 .register,
8101 .register_pair,
8041 .register_offset,8102 .register_offset,
8042 .eflags,8103 .eflags,
8043 .memory,8104 .memory,
...@@ -8051,16 +8112,19 @@ fn genBinOpMir(...@@ -8051,16 +8112,19 @@ fn genBinOpMir(
8051 .load_frame,8112 .load_frame,
8052 .lea_frame,8113 .lea_frame,
8053 => {8114 => {
8054 const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{8115 const src_limb_mcv: MCValue = if (src_info) |info| .{
8055 .indirect = .{ .reg = info.addr_reg, .off = off },8116 .indirect = .{ .reg = info.addr_reg, .off = off },
8056 } else switch (resolved_src_mcv) {8117 } else switch (resolved_src_mcv) {
8118 .register, .register_pair => .{
8119 .register = resolved_src_mcv.getRegs()[limb_i],
8120 },
8057 .eflags,8121 .eflags,
8058 .register_offset,8122 .register_offset,
8059 .lea_direct,8123 .lea_direct,
8060 .lea_got,8124 .lea_got,
8061 .lea_tlv,8125 .lea_tlv,
8062 .lea_frame,8126 .lea_frame,
8063 => switch (off) {8127 => switch (limb_i) {
8064 0 => resolved_src_mcv,8128 0 => resolved_src_mcv,
8065 else => .{ .immediate = 0 },8129 else => .{ .immediate = 0 },
8066 },8130 },
...@@ -8074,7 +8138,11 @@ fn genBinOpMir(...@@ -8074,7 +8138,11 @@ fn genBinOpMir(
8074 .off = frame_addr.off + off,8138 .off = frame_addr.off + off,
8075 } },8139 } },
8076 else => unreachable,8140 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);
8078 try self.asmMemoryRegister(8146 try self.asmMemoryRegister(
8079 mir_limb_tag,8147 mir_limb_tag,
8080 dst_limb_mem,8148 dst_limb_mem,
...@@ -8098,8 +8166,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -8098,8 +8166,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
8098 .dead,8166 .dead,
8099 .undef,8167 .undef,
8100 .immediate,8168 .immediate,
8101 .register_offset,
8102 .eflags,8169 .eflags,
8170 .register_offset,
8103 .register_overflow,8171 .register_overflow,
8104 .lea_direct,8172 .lea_direct,
8105 .lea_got,8173 .lea_got,
...@@ -8115,13 +8183,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -8115,13 +8183,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
81158183
8116 const resolved_src_mcv = switch (src_mcv) {8184 const resolved_src_mcv = switch (src_mcv) {
8117 else => src_mcv,8185 else => src_mcv,
8118 .air_ref => |ref| try self.resolveInst(ref),8186 .air_ref => |src_ref| try self.resolveInst(src_ref),
8119 };8187 };
8120 switch (resolved_src_mcv) {8188 switch (resolved_src_mcv) {
8121 .none,8189 .none,
8122 .unreach,8190 .unreach,
8123 .dead,8191 .dead,
8124 .undef,8192 .undef,
8193 .register_pair,
8125 .register_overflow,8194 .register_overflow,
8126 .reserved_frame,8195 .reserved_frame,
8127 .air_ref,8196 .air_ref,
...@@ -8187,6 +8256,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -8187,6 +8256,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
8187 ),8256 ),
8188 }8257 }
8189 },8258 },
8259 .register_pair => unreachable, // unimplemented
8190 .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => {8260 .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => {
8191 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);8261 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
8192 const tmp_mcv = MCValue{ .register = tmp_reg };8262 const tmp_mcv = MCValue{ .register = tmp_reg };
...@@ -8209,8 +8279,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -8209,8 +8279,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
8209 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {8279 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
8210 const dst_mcv = self.args[arg_index];8280 const dst_mcv = self.args[arg_index];
8211 switch (dst_mcv) {8281 switch (dst_mcv) {
8212 .register => |reg| self.register_manager.getRegAssumeFree(reg, inst),8282 .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg|
8213 .load_frame => {},8283 self.register_manager.getRegAssumeFree(reg, inst),
8214 else => return self.fail("TODO implement arg for {}", .{dst_mcv}),8284 else => return self.fail("TODO implement arg for {}", .{dst_mcv}),
8215 }8285 }
82168286
...@@ -8230,6 +8300,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {...@@ -8230,6 +8300,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
8230 .dwarf => |dw| {8300 .dwarf => |dw| {
8231 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {8301 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
8232 .register => |reg| .{ .register = reg.dwarfNum() },8302 .register => |reg| .{ .register = reg.dwarfNum() },
8303 .register_pair => |regs| .{ .register_pair = .{
8304 regs[0].dwarfNum(), regs[1].dwarfNum(),
8305 } },
8233 // TODO use a frame index8306 // TODO use a frame index
8234 .load_frame => return,8307 .load_frame => return,
8235 //.stack_offset => |off| .{8308 //.stack_offset => |off| .{
...@@ -8390,7 +8463,10 @@ fn genCall(self: *Self, info: union(enum) {...@@ -8390,7 +8463,10 @@ fn genCall(self: *Self, info: union(enum) {
8390 };8463 };
8391 const fn_info = mod.typeToFunc(fn_ty).?;8464 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 };
8394 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =8470 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
8395 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);8471 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
8396 const allocator = stack.get();8472 const allocator = stack.get();
...@@ -8399,8 +8475,12 @@ fn genCall(self: *Self, info: union(enum) {...@@ -8399,8 +8475,12 @@ fn genCall(self: *Self, info: union(enum) {
8399 defer allocator.free(var_args);8475 defer allocator.free(var_args);
8400 for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;8476 for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
84018477
8402 var call_info =8478 var arg_locks = std.ArrayList(?RegisterLock).init(allocator);
8403 try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);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);
8404 defer call_info.deinit(self);8484 defer call_info.deinit(self);
84058485
8406 // We need a properly aligned and sized call frame to be able to call this function.8486 // 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) {...@@ -8419,7 +8499,9 @@ fn genCall(self: *Self, info: union(enum) {
8419 }8499 }
84208500
8421 try self.spillEflagsIfOccupied();8501 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
8424 // set stack arguments first because this can clobber registers8506 // set stack arguments first because this can clobber registers
8425 // also clobber spill arguments as we go8507 // also clobber spill arguments as we go
...@@ -8430,7 +8512,14 @@ fn genCall(self: *Self, info: union(enum) {...@@ -8430,7 +8512,14 @@ fn genCall(self: *Self, info: union(enum) {
8430 }8512 }
8431 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {8513 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
8432 .none => {},8514 .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 },
8434 .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),8523 .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),
8435 else => unreachable,8524 else => unreachable,
8436 };8525 };
...@@ -8451,13 +8540,11 @@ fn genCall(self: *Self, info: union(enum) {...@@ -8451,13 +8540,11 @@ fn genCall(self: *Self, info: union(enum) {
8451 };8540 };
8452 defer if (ret_lock) |lock| self.register_manager.unlockReg(lock);8541 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| {8543 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
8455 switch (dst_arg) {8544 .none, .load_frame => {},
8456 .none, .load_frame => {},8545 .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg),
8457 .register => try self.genCopy(arg_ty, dst_arg, src_arg),8546 else => unreachable,
8458 else => unreachable,8547 };
8459 }
8460 }
84618548
8462 // Due to incremental compilation, how function calls are generated depends8549 // Due to incremental compilation, how function calls are generated depends
8463 // on linking.8550 // on linking.
...@@ -8527,7 +8614,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -8527,7 +8614,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
8527 const ret_ty = self.fn_type.fnReturnType(mod);8614 const ret_ty = self.fn_type.fnReturnType(mod);
8528 switch (self.ret_mcv.short) {8615 switch (self.ret_mcv.short) {
8529 .none => {},8616 .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),
8531 .indirect => |reg_off| {8618 .indirect => |reg_off| {
8532 try self.register_manager.getReg(reg_off.reg, null);8619 try self.register_manager.getReg(reg_off.reg, null);
8533 const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg);8620 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 {...@@ -8612,6 +8699,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8612 const lhs_mcv = try self.resolveInst(bin_op.lhs);8699 const lhs_mcv = try self.resolveInst(bin_op.lhs);
8613 const lhs_lock = switch (lhs_mcv) {8700 const lhs_lock = switch (lhs_mcv) {
8614 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),8701 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
8702 .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg),
8615 else => null,8703 else => null,
8616 };8704 };
8617 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);8705 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 {...@@ -8619,6 +8707,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8619 const rhs_mcv = try self.resolveInst(bin_op.rhs);8707 const rhs_mcv = try self.resolveInst(bin_op.rhs);
8620 const rhs_lock = switch (rhs_mcv) {8708 const rhs_lock = switch (rhs_mcv) {
8621 .register => |reg| self.register_manager.lockReg(reg),8709 .register => |reg| self.register_manager.lockReg(reg),
8710 .register_offset => |ro| self.register_manager.lockReg(ro.reg),
8622 else => null,8711 else => null,
8623 };8712 };
8624 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);8713 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 {...@@ -8665,33 +8754,122 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8665 .lt, .gte => {},8754 .lt, .gte => {},
8666 .lte, .gt => unreachable,8755 .lte, .gt => unreachable,
8667 .eq, .neq => {8756 .eq, .neq => {
8668 const dst_addr_mcv: MCValue = switch (dst_mcv) {8757 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
8669 .memory, .indirect, .load_frame => dst_mcv.address(),8758
8670 else => .{ .register = try self.copyToTmpRegister(8759 const resolved_dst_mcv = switch (dst_mcv) {
8671 Type.usize,8760 else => dst_mcv,
8672 dst_mcv.address(),8761 .air_ref => |dst_ref| try self.resolveInst(dst_ref),
8673 ) },
8674 };8762 };
8675 const dst_addr_lock = if (dst_addr_mcv.getReg()) |reg|8763 const dst_info: OpInfo = switch (resolved_dst_mcv) {
8676 self.register_manager.lockReg(reg)8764 .none,
8677 else8765 .unreach,
8678 null;8766 .dead,
8679 defer if (dst_addr_lock) |lock| self.register_manager.unlockReg(lock);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) {8815 const resolved_src_mcv = switch (src_mcv) {
8682 .memory, .indirect, .load_frame => src_mcv.address(),8816 else => src_mcv,
8683 else => .{ .register = try self.copyToTmpRegister(8817 .air_ref => |src_ref| try self.resolveInst(src_ref),
8684 Type.usize,
8685 src_mcv.address(),
8686 ) },
8687 };8818 };
8688 const src_addr_lock = if (src_addr_mcv.getReg()) |reg|8819 const src_info: OpInfo = switch (resolved_src_mcv) {
8689 self.register_manager.lockReg(reg)8820 .none,
8690 else8821 .unreach,
8691 null;8822 .dead,
8692 defer if (src_addr_lock) |lock| self.register_manager.unlockReg(lock);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);
8695 const acc_reg = regs[0].to64();8873 const acc_reg = regs[0].to64();
8696 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);8874 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);
8697 defer for (locks) |lock| self.register_manager.unlockReg(lock);8875 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 {...@@ -8699,18 +8877,52 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
8699 const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable;8877 const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable;
8700 var limb_i: u16 = 0;8878 var limb_i: u16 = 0;
8701 while (limb_i < limbs_len) : (limb_i += 1) {8879 while (limb_i < limbs_len) : (limb_i += 1) {
8880 const off = limb_i * 8;
8702 const tmp_reg = regs[@min(limb_i, 1)].to64();8881 const tmp_reg = regs[@min(limb_i, 1)].to64();
8703 try self.genSetReg(8882
8704 tmp_reg,8883 try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{
8705 Type.usize,8884 .indirect = .{ .reg = info.addr_reg, .off = off },
8706 dst_addr_mcv.offset(limb_i * 8).deref(),8885 } else switch (resolved_dst_mcv) {
8707 );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
8708 try self.genBinOpMir(8901 try self.genBinOpMir(
8709 .{ ._, .xor },8902 .{ ._, .xor },
8710 Type.usize,8903 Type.usize,
8711 .{ .register = tmp_reg },8904 .{ .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 },
8713 );8924 );
8925
8714 if (limb_i > 0) try self.asmRegisterRegister(8926 if (limb_i > 0) try self.asmRegisterRegister(
8715 .{ ._, .@"or" },8927 .{ ._, .@"or" },
8716 acc_reg,8928 acc_reg,
...@@ -9039,6 +9251,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -9039,6 +9251,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
9039 .undef,9251 .undef,
9040 .immediate,9252 .immediate,
9041 .eflags,9253 .eflags,
9254 .register_pair,
9042 .register_offset,9255 .register_offset,
9043 .register_overflow,9256 .register_overflow,
9044 .lea_direct,9257 .lea_direct,
...@@ -9528,13 +9741,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9528,13 +9741,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9528 extra_i += inputs.len;9741 extra_i += inputs.len;
95299742
9530 var result: MCValue = .none;9743 var result: MCValue = .none;
9531 var args = std.StringArrayHashMap(MCValue).init(self.gpa);9744 var args = std.ArrayList(MCValue).init(self.gpa);
9532 try args.ensureTotalCapacity(outputs.len + inputs.len);9745 try args.ensureTotalCapacity(outputs.len + inputs.len);
9533 defer {9746 defer {
9534 for (args.values()) |arg| if (arg.getReg()) |reg|9747 for (args.items) |arg| if (arg.getReg()) |reg|
9535 self.register_manager.unlockReg(.{ .register = reg });9748 self.register_manager.unlockReg(.{ .register = reg });
9536 args.deinit();9749 args.deinit();
9537 }9750 }
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
9539 var outputs_extra_i = extra_i;9755 var outputs_extra_i = extra_i;
9540 for (outputs) |output| {9756 for (outputs) |output| {
...@@ -9585,7 +9801,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9585,7 +9801,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9585 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {9801 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
9586 _ = self.register_manager.lockRegAssumeUnused(reg);9802 _ = self.register_manager.lockRegAssumeUnused(reg);
9587 };9803 };
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);
9589 if (output == .none) result = arg_mcv;9807 if (output == .none) result = arg_mcv;
9590 }9808 }
95919809
...@@ -9643,7 +9861,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9643,7 +9861,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9643 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {9861 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
9644 _ = self.register_manager.lockReg(reg);9862 _ = self.register_manager.lockReg(reg);
9645 };9863 };
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);
9647 }9867 }
96489868
9649 {9869 {
...@@ -9712,8 +9932,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9712,8 +9932,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9712 op_str[colon_pos + 1 .. op_str.len - "]".len]9932 op_str[colon_pos + 1 .. op_str.len - "]".len]
9713 else9933 else
9714 "";9934 "";
9715 op.* = switch (args.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse9935 op.* = switch (args.items[
9716 return self.fail("no matching constraint: '{s}'", .{op_str})) {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 ]) {
9717 .register => |reg| if (std.mem.eql(u8, modifier, ""))9939 .register => |reg| if (std.mem.eql(u8, modifier, ""))
9718 .{ .reg = reg }9940 .{ .reg = reg }
9719 else9941 else
...@@ -9826,7 +10048,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -9826,7 +10048,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9826 };10048 };
9827 }10049 }
982810050
9829 for (outputs, args.values()[0..outputs.len]) |output, mcv| {10051 for (outputs, args.items[0..outputs.len]) |output, mcv| {
9830 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);10052 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);
9831 const constraint =10053 const constraint =
9832 std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0);10054 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...@@ -10093,6 +10315,19 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
10093 .off = -dst_reg_off.off,10315 .off = -dst_reg_off.off,
10094 } },10316 } },
10095 }),10317 }),
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 },
10096 .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),10331 .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),
10097 .memory, .load_direct, .load_got, .load_tlv => {10332 .memory, .load_direct, .load_got, .load_tlv => {
10098 switch (dst_mcv) {10333 switch (dst_mcv) {
...@@ -10126,6 +10361,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10126,6 +10361,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10126 .none,10361 .none,
10127 .unreach,10362 .unreach,
10128 .dead,10363 .dead,
10364 .register_pair,
10129 .register_overflow,10365 .register_overflow,
10130 .reserved_frame,10366 .reserved_frame,
10131 => unreachable,10367 => unreachable,
...@@ -10203,17 +10439,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10203,17 +10439,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10203 .sse => try self.asmRegisterRegister(10439 .sse => try self.asmRegisterRegister(
10204 @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) {10440 @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) {
10205 else => switch (abi_size) {10441 else => switch (abi_size) {
10206 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },10442 1...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa },
10207 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
10208 9...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa },
10209 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null,10443 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null,
10210 else => null,10444 else => null,
10211 },10445 },
10212 .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) {10446 .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) {
10213 16, 128 => switch (abi_size) {10447 16, 128 => switch (abi_size) {
10214 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },10448 2...16 => if (self.hasFeature(.avx))
10215 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
10216 9...16 => if (self.hasFeature(.avx))
10217 .{ .v_, .movdqa }10449 .{ .v_, .movdqa }
10218 else10450 else
10219 .{ ._, .movdqa },10451 .{ ._, .movdqa },
...@@ -10307,6 +10539,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10307,6 +10539,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10307 Immediate.u(0),10539 Immediate.u(0),
10308 ),10540 ),
10309 }10541 }
10542 return;
10310 },10543 },
10311 .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) {10544 .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) {
10312 else => {10545 else => {
...@@ -10398,7 +10631,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -10398,7 +10631,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
10398 @tagName(self.bin_file.tag),10631 @tagName(self.bin_file.tag),
10399 });10632 });
10400 },10633 },
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)),
10402 }10635 }
10403}10636}
1040410637
...@@ -10475,6 +10708,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -10475,6 +10708,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
10475 ),10708 ),
10476 }10709 }
10477 },10710 },
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 },
10478 .register_overflow => |ro| {10737 .register_overflow => |ro| {
10479 try self.genSetMem(10738 try self.genSetMem(
10480 base,10739 base,
...@@ -10511,7 +10770,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -10511,7 +10770,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
10511 },10770 },
10512 else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }),10771 else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }),
10513 },10772 },
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)),
10515 }10774 }
10516}10775}
1051710776
...@@ -11475,6 +11734,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -11475,6 +11734,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
11475 const un_op = self.air.instructions.items(.data)[inst].un_op;11734 const un_op = self.air.instructions.items(.data)[inst].un_op;
11476 const inst_ty = self.typeOfIndex(inst);11735 const inst_ty = self.typeOfIndex(inst);
11477 const enum_ty = self.typeOf(un_op);11736 const enum_ty = self.typeOf(un_op);
11737 const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*);
1147811738
11479 // We need a properly aligned and sized call frame to be able to call this function.11739 // We need a properly aligned and sized call frame to be able to call this function.
11480 {11740 {
...@@ -11492,9 +11752,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -11492,9 +11752,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
11492 }11752 }
1149311753
11494 try self.spillEflagsIfOccupied();11754 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
11499 const dst_mcv = try self.allocRegOrMem(inst, false);11759 const dst_mcv = try self.allocRegOrMem(inst, false);
11500 try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address());11760 try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address());
...@@ -12271,23 +12531,27 @@ fn resolveCallingConventionValues(...@@ -12271,23 +12531,27 @@ fn resolveCallingConventionValues(
1227112531
12272 const ret_ty = fn_info.return_type.toType();12532 const ret_ty = fn_info.return_type.toType();
1227312533
12534 const resolved_cc = abi.resolveCallingConvention(cc, self.target.*);
12274 switch (cc) {12535 switch (cc) {
12275 .Naked => {12536 .Naked => {
12276 assert(result.args.len == 0);12537 assert(result.args.len == 0);
12277 result.return_value = InstTracking.init(.unreach);12538 result.return_value = InstTracking.init(.unreach);
12278 result.stack_align = .@"8";12539 result.stack_align = .@"8";
12279 },12540 },
12280 .C => {12541 .C, .SysV, .Win64 => {
12281 var param_reg_i: usize = 0;12542 var ret_int_reg_i: usize = 0;
12543 var ret_sse_reg_i: usize = 0;
12544 var param_int_reg_i: usize = 0;
12282 var param_sse_reg_i: usize = 0;12545 var param_sse_reg_i: usize = 0;
12283 result.stack_align = .@"16";12546 result.stack_align = .@"16";
1228412547
12285 switch (self.target.os.tag) {12548 switch (resolved_cc) {
12286 .windows => {12549 .SysV => {},
12550 .Win64 => {
12287 // Align the stack to 16bytes before allocating shadow stack space (if any).12551 // Align the stack to 16bytes before allocating shadow stack space (if any).
12288 result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod));12552 result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod));
12289 },12553 },
12290 else => {},12554 else => unreachable,
12291 }12555 }
1229212556
12293 // Return values12557 // Return values
...@@ -12297,71 +12561,133 @@ fn resolveCallingConventionValues(...@@ -12297,71 +12561,133 @@ fn resolveCallingConventionValues(
12297 // TODO: is this even possible for C calling convention?12561 // TODO: is this even possible for C calling convention?
12298 result.return_value = InstTracking.init(.none);12562 result.return_value = InstTracking.init(.none);
12299 } else {12563 } else {
12300 const classes = switch (self.target.os.tag) {12564 var ret_tracking: [2]InstTracking = undefined;
12301 .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)},12565 var ret_tracking_i: usize = 0;
12302 else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),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,
12303 };12571 };
12304 if (classes.len > 1) {12572 for (classes) |class| switch (class) {
12305 return self.fail("TODO handle multiple classes per type", .{});12573 .integer => {
12306 }12574 const ret_int_reg = registerAlias(
12307 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];12575 abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i],
12308 result.return_value = switch (classes[0]) {12576 @intCast(@min(ret_ty.abiSize(mod), 8)),
12309 .integer => InstTracking.init(.{ .register = registerAlias(12577 );
12310 ret_reg,12578 ret_int_reg_i += 1;
12311 @intCast(ret_ty.abiSize(mod)),12579
12312 ) }),12580 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
12313 .float, .sse => InstTracking.init(.{ .register = .xmm0 }),12581 ret_tracking_i += 1;
12314 .memory => ret: {12582 },
12315 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];12583 .sse, .float, .float_combine, .win_i128 => {
12316 param_reg_i += 1;12584 const ret_sse_reg = registerAlias(
12317 break :ret .{12585 abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i],
12318 .short = .{ .indirect = .{ .reg = ret_reg } },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 } },
12319 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },12612 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
12320 };12613 };
12614 ret_tracking_i += 1;
12321 },12615 },
12322 else => |class| return self.fail("TODO handle calling convention class {s}", .{12616 .none => unreachable,
12323 @tagName(class),12617 };
12324 }),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 } }),
12325 };12624 };
12326 }12625 }
1232712626
12328 // Input params12627 // Input params
12329 for (param_types, result.args) |ty, *arg| {12628 for (param_types, result.args) |ty, *arg| {
12330 assert(ty.hasRuntimeBitsIgnoreComptime(mod));12629 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
12332 const classes = switch (self.target.os.tag) {12642 const classes = switch (self.target.os.tag) {
12333 .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)},12643 .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)},
12334 else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),12644 else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),
12335 };12645 };
12336 if (classes.len > 1) {12646 for (classes) |class| switch (class) {
12337 return self.fail("TODO handle multiple classes per type", .{});12647 .integer => {
12338 }12648 const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc);
12339 switch (classes[0]) {12649 if (param_int_reg_i >= param_int_regs.len) break;
12340 .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) {12650
12341 arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] };12651 const param_int_reg = registerAlias(
12342 param_reg_i += 1;12652 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i],
12343 continue;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;
12344 },12659 },
12345 .float, .sse => switch (self.target.os.tag) {12660 .sse, .float, .float_combine => {
12346 .windows => if (param_reg_i < 4) {12661 const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc);
12347 arg.* = .{12662 if (param_sse_reg_i >= param_sse_regs.len) break;
12348 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i),12663
12349 };12664 const param_sse_reg = registerAlias(
12350 param_reg_i += 1;12665 abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i],
12351 continue;12666 @intCast(ty.abiSize(mod)),
12352 },12667 );
12353 else => if (param_sse_reg_i < 8) {12668 param_sse_reg_i += 1;
12354 arg.* = .{12669
12355 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_sse_reg_i),12670 arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };
12356 };12671 arg_mcv_i += 1;
12357 param_sse_reg_i += 1;
12358 continue;
12359 },
12360 },12672 },
12361 .memory => {}, // fallthrough12673 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
12362 else => |class| return self.fail("TODO handle calling convention class {s}", .{12674 .x87, .x87up, .complex_x87, .memory => break,
12363 @tagName(class),12675 .none => unreachable,
12364 }),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;
12365 }12691 }
1236612692
12367 const param_size: u31 = @intCast(ty.abiSize(mod));12693 const param_size: u31 = @intCast(ty.abiSize(mod));
...@@ -12384,13 +12710,13 @@ fn resolveCallingConventionValues(...@@ -12384,13 +12710,13 @@ fn resolveCallingConventionValues(
12384 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {12710 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
12385 result.return_value = InstTracking.init(.none);12711 result.return_value = InstTracking.init(.none);
12386 } else {12712 } else {
12387 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];12713 const ret_reg = abi.getCAbiIntReturnRegs(resolved_cc)[0];
12388 const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod));12714 const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod));
12389 if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) {12715 if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) {
12390 const aliased_reg = registerAlias(ret_reg, ret_ty_size);12716 const aliased_reg = registerAlias(ret_reg, ret_ty_size);
12391 result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none };12717 result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none };
12392 } else {12718 } else {
12393 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[0];12719 const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[0];
12394 result.return_value = .{12720 result.return_value = .{
12395 .short = .{ .indirect = .{ .reg = ret_reg } },12721 .short = .{ .indirect = .{ .reg = ret_reg } },
12396 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },12722 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
...@@ -12462,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -12462,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
12462 reg12788 reg
12463 else12789 else
12464 unreachable,12790 unreachable,
12465 .x87 => unreachable,12791 .x87 => if (size_bytes == 16)
12792 reg
12793 else
12794 unreachable,
12466 .mmx => if (size_bytes <= 8)12795 .mmx => if (size_bytes <= 8)
12467 reg12796 reg
12468 else12797 else
...@@ -12597,9 +12926,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type {...@@ -12597,9 +12926,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type {
1259712926
12598fn floatLibcAbiPrefix(ty: Type) []const u8 {12927fn floatLibcAbiPrefix(ty: Type) []const u8 {
12599 return switch (ty.toIntern()) {12928 return switch (ty.toIntern()) {
12600 .f16_type,12929 .f16_type, .f80_type => "__",
12601 .f80_type,
12602 => "__",
12603 .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",12930 .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",
12604 else => unreachable,12931 else => unreachable,
12605 };12932 };
src/arch/x86_64/Emit.zig+10-12
...@@ -242,16 +242,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {...@@ -242,16 +242,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
242 },242 },
243 .plan9 => |dbg_out| {243 .plan9 => |dbg_out| {
244 if (delta_pc <= 0) return; // only do this when the pc changes244 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
248 // increasing the line number246 // 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);
250 // increasing the pc248 // 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;
252 if (d_pc_p9 > 0) {250 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 quanta251 // minus one because if its the last one, we want to leave space to change the line which is one pc quanta
254 var diff = @divExact(d_pc_p9, quant) - quant;252 var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta;
255 while (diff > 0) {253 while (diff > 0) {
256 if (diff < 64) {254 if (diff < 64) {
257 try dbg_out.dbg_line.append(@as(u8, @intCast(diff + 128)));255 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 {...@@ -261,15 +259,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
261 diff -= 64;259 diff -= 64;
262 }260 }
263 }261 }
264 if (dbg_out.pcop_change_index.*) |pci|262 if (dbg_out.pcop_change_index) |pci|
265 dbg_out.dbg_line.items[pci] += 1;263 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));
267 } else if (d_pc_p9 == 0) {265 } else if (d_pc_p9 == 0) {
268 // we don't need to do anything, because adding the quant does it for us266 // we don't need to do anything, because adding the pc quanta does it for us
269 } else unreachable;267 } else unreachable;
270 if (dbg_out.start_line.* == null)268 if (dbg_out.start_line == null)
271 dbg_out.start_line.* = emit.prev_di_line;269 dbg_out.start_line = emit.prev_di_line;
272 dbg_out.end_line.* = line;270 dbg_out.end_line = line;
273 // only do this if the pc changed271 // only do this if the pc changed
274 emit.prev_di_line = line;272 emit.prev_di_line = line;
275 emit.prev_di_column = column;273 emit.prev_di_column = column;
src/arch/x86_64/Lower.zig+3-5
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
22
3allocator: Allocator,3allocator: Allocator,
4mir: Mir,4mir: Mir,
5target: *const std.Target,5cc: std.builtin.CallingConvention,
6err_msg: ?*ErrorMsg = null,6err_msg: ?*ErrorMsg = null,
7src_loc: Module.SrcLoc,7src_loc: Module.SrcLoc,
8result_insts_len: u8 = undefined,8result_insts_len: u8 = undefined,
...@@ -552,15 +552,13 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -552,15 +552,13 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
552}552}
553553
554fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {554fn 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);
556 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {556 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
557 .push => .reverse,557 .push => .reverse,
558 .pop => .forward,558 .pop => .forward,
559 else => unreachable,559 else => unreachable,
560 } });560 } });
561 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{561 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});
562 .reg = callee_preserved_regs[i],
563 }});
564}562}
565563
566const page_size: i32 = 1 << 12;564const 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 {...@@ -137,7 +137,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
137 return result;137 return result;
138 },138 },
139 128 => {139 128 => {
140 // "Arguments of types__float128, _Decimal128 and__m128 are140 // "Arguments of types __float128, _Decimal128 and __m128 are
141 // split into two halves. The least significant ones belong141 // split into two halves. The least significant ones belong
142 // to class SSE, the most significant one to class SSEUP."142 // to class SSE, the most significant one to class SSEUP."
143 if (ctx == .other) {143 if (ctx == .other) {
...@@ -213,9 +213,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -213,9 +213,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
213 const struct_type = mod.typeToStruct(ty).?;213 const struct_type = mod.typeToStruct(ty).?;
214 const ty_size = ty.abiSize(mod);214 const ty_size = ty.abiSize(mod);
215 if (struct_type.layout == .Packed) {215 if (struct_type.layout == .Packed) {
216 assert(ty_size <= 128);216 assert(ty_size <= 16);
217 result[0] = .integer;217 result[0] = .integer;
218 if (ty_size > 64) result[1] = .integer;218 if (ty_size > 8) result[1] = .integer;
219 return result;219 return result;
220 }220 }
221 if (ty_size > 64)221 if (ty_size > 64)
...@@ -331,9 +331,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -331,9 +331,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
331 const union_obj = mod.typeToUnion(ty).?;331 const union_obj = mod.typeToUnion(ty).?;
332 const ty_size = mod.unionAbiSize(union_obj);332 const ty_size = mod.unionAbiSize(union_obj);
333 if (union_obj.getLayout(ip) == .Packed) {333 if (union_obj.getLayout(ip) == .Packed) {
334 assert(ty_size <= 128);334 assert(ty_size <= 16);
335 result[0] = .integer;335 result[0] = .integer;
336 if (ty_size > 64) result[1] = .integer;336 if (ty_size > 8) result[1] = .integer;
337 return result;337 return result;
338 }338 }
339 if (ty_size > 64)339 if (ty_size > 64)
...@@ -422,11 +422,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -422,11 +422,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
422 },422 },
423 .Array => {423 .Array => {
424 const ty_size = ty.abiSize(mod);424 const ty_size = ty.abiSize(mod);
425 if (ty_size <= 64) {425 if (ty_size <= 8) {
426 result[0] = .integer;426 result[0] = .integer;
427 return result;427 return result;
428 }428 }
429 if (ty_size <= 128) {429 if (ty_size <= 16) {
430 result[0] = .integer;430 result[0] = .integer;
431 result[1] = .integer;431 result[1] = .integer;
432 return result;432 return result;
...@@ -447,7 +447,9 @@ pub const SysV = struct {...@@ -447,7 +447,9 @@ pub const SysV = struct {
447 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;447 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;
448448
449 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };449 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
450 pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
450 pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };451 pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
452 pub const c_abi_sse_return_regs = sse_avx_regs[0..2].*;
451};453};
452454
453pub const Win64 = struct {455pub const Win64 = struct {
...@@ -460,34 +462,69 @@ pub const Win64 = struct {...@@ -460,34 +462,69 @@ pub const Win64 = struct {
460 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;462 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;
461463
462 pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };464 pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
465 pub const c_abi_sse_param_regs = sse_avx_regs[0..4].*;
463 pub const c_abi_int_return_regs = [_]Register{.rax};466 pub const c_abi_int_return_regs = [_]Register{.rax};
467 pub const c_abi_sse_return_regs = sse_avx_regs[0..1].*;
464};468};
465469
466pub fn getCalleePreservedRegs(target: Target) []const Register {470pub fn resolveCallingConvention(
467 return switch (target.os.tag) {471 cc: std.builtin.CallingConvention,
468 .windows => &Win64.callee_preserved_regs,472 target: std.Target,
469 else => &SysV.callee_preserved_regs,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,
470 };504 };
471}505}
472506
473pub fn getCallerPreservedRegs(target: Target) []const Register {507pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention) []const Register {
474 return switch (target.os.tag) {508 return switch (cc) {
475 .windows => &Win64.caller_preserved_regs,509 .SysV => &SysV.c_abi_sse_param_regs,
476 else => &SysV.caller_preserved_regs,510 .Win64 => &Win64.c_abi_sse_param_regs,
511 else => unreachable,
477 };512 };
478}513}
479514
480pub fn getCAbiIntParamRegs(target: Target) []const Register {515pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention) []const Register {
481 return switch (target.os.tag) {516 return switch (cc) {
482 .windows => &Win64.c_abi_int_param_regs,517 .SysV => &SysV.c_abi_int_return_regs,
483 else => &SysV.c_abi_int_param_regs,518 .Win64 => &Win64.c_abi_int_return_regs,
519 else => unreachable,
484 };520 };
485}521}
486522
487pub fn getCAbiIntReturnRegs(target: Target) []const Register {523pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register {
488 return switch (target.os.tag) {524 return switch (cc) {
489 .windows => &Win64.c_abi_int_return_regs,525 .SysV => &SysV.c_abi_sse_return_regs,
490 else => &SysV.c_abi_int_return_regs,526 .Win64 => &Win64.c_abi_sse_return_regs,
527 else => unreachable,
491 };528 };
492}529}
493530
...@@ -524,7 +561,6 @@ pub const RegisterClass = struct {...@@ -524,7 +561,6 @@ pub const RegisterClass = struct {
524561
525const builtin = @import("builtin");562const builtin = @import("builtin");
526const std = @import("std");563const std = @import("std");
527const Target = std.Target;
528const assert = std.debug.assert;564const assert = std.debug.assert;
529const testing = std.testing;565const testing = std.testing;
530566
src/codegen.zig+1-22
...@@ -40,28 +40,7 @@ pub const CodeGenError = error{...@@ -40,28 +40,7 @@ pub const CodeGenError = error{
4040
41pub const DebugInfoOutput = union(enum) {41pub const DebugInfoOutput = union(enum) {
42 dwarf: *link.File.Dwarf.DeclState,42 dwarf: *link.File.Dwarf.DeclState,
43 /// the plan9 debuginfo output is a bytecode with 4 opcodes43 plan9: *link.File.Plan9.DebugInfoOutput,
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 },
65 none,44 none,
66};45};
6746
src/link/Dwarf.zig+74-1
...@@ -566,6 +566,7 @@ pub const DeclState = struct {...@@ -566,6 +566,7 @@ pub const DeclState = struct {
566566
567 pub const DbgInfoLoc = union(enum) {567 pub const DbgInfoLoc = union(enum) {
568 register: u8,568 register: u8,
569 register_pair: [2]u8,
569 stack: struct {570 stack: struct {
570 fp_register: u8,571 fp_register: u8,
571 offset: i32,572 offset: i32,
...@@ -610,6 +611,42 @@ pub const DeclState = struct {...@@ -610,6 +611,42 @@ pub const DeclState = struct {
610 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;611 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
611 }612 }
612 },613 },
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 },
613 .stack => |info| {650 .stack => |info| {
614 try dbg_info.ensureUnusedCapacity(9);651 try dbg_info.ensureUnusedCapacity(9);
615 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));652 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));
...@@ -676,7 +713,7 @@ pub const DeclState = struct {...@@ -676,7 +713,7 @@ pub const DeclState = struct {
676713
677 switch (loc) {714 switch (loc) {
678 .register => |reg| {715 .register => |reg| {
679 try dbg_info.ensureUnusedCapacity(4);716 try dbg_info.ensureUnusedCapacity(3);
680 // DW.AT.location, DW.FORM.exprloc717 // DW.AT.location, DW.FORM.exprloc
681 var expr_len = std.io.countingWriter(std.io.null_writer);718 var expr_len = std.io.countingWriter(std.io.null_writer);
682 if (reg < 32) {719 if (reg < 32) {
...@@ -694,6 +731,42 @@ pub const DeclState = struct {...@@ -694,6 +731,42 @@ pub const DeclState = struct {
694 }731 }
695 },732 },
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
697 .stack => |info| {770 .stack => |info| {
698 try dbg_info.ensureUnusedCapacity(9);771 try dbg_info.ensureUnusedCapacity(9);
699 // DW.AT.location, DW.FORM.exprloc772 // DW.AT.location, DW.FORM.exprloc
src/link/Plan9.zig+38-16
...@@ -211,6 +211,31 @@ pub const Atom = struct {...@@ -211,6 +211,31 @@ pub const Atom = struct {
211 }211 }
212};212};
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
214const DeclMetadata = struct {239const DeclMetadata = struct {
215 index: Atom.Index,240 index: Atom.Index,
216 exports: std.ArrayListUnmanaged(usize) = .{},241 exports: std.ArrayListUnmanaged(usize) = .{},
...@@ -376,11 +401,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:...@@ -376,11 +401,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
376401
377 var code_buffer = std.ArrayList(u8).init(self.base.allocator);402 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
378 defer code_buffer.deinit();403 defer code_buffer.deinit();
379 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);404 var dbg_info_output: DebugInfoOutput = .{
380 defer dbg_line_buffer.deinit();405 .dbg_line = std.ArrayList(u8).init(self.base.allocator),
381 var start_line: ?u32 = null;406 .start_line = null,
382 var end_line: u32 = undefined;407 .end_line = undefined,
383 var pcop_change_index: ?u32 = null;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
385 const res = try codegen.generateFunction(414 const res = try codegen.generateFunction(
386 &self.base,415 &self.base,
...@@ -389,14 +418,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:...@@ -389,14 +418,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
389 air,418 air,
390 liveness,419 liveness,
391 &code_buffer,420 &code_buffer,
392 .{421 .{ .plan9 = &dbg_info_output },
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 },
400 );422 );
401 const code = switch (res) {423 const code = switch (res) {
402 .ok => try code_buffer.toOwnedSlice(),424 .ok => try code_buffer.toOwnedSlice(),
...@@ -412,9 +434,9 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:...@@ -412,9 +434,9 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
412 };434 };
413 const out: FnDeclOutput = .{435 const out: FnDeclOutput = .{
414 .code = code,436 .code = code,
415 .lineinfo = try dbg_line_buffer.toOwnedSlice(),437 .lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(),
416 .start_line = start_line.?,438 .start_line = dbg_info_output.start_line.?,
417 .end_line = end_line,439 .end_line = dbg_info_output.end_line,
418 };440 };
419 try self.putFn(decl_index, out);441 try self.putFn(decl_index, out);
420 return self.updateFinish(decl_index);442 return self.updateFinish(decl_index);
test/behavior/abs.zig+1-1
...@@ -97,7 +97,7 @@ test "@abs floats" {...@@ -97,7 +97,7 @@ test "@abs floats" {
97 try comptime testAbsFloats(f80);97 try comptime testAbsFloats(f80);
98 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);98 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);
99 try comptime testAbsFloats(f128);99 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);
101}101}
102102
103fn testAbsFloats(comptime T: type) !void {103fn 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...@@ -297,11 +297,11 @@ test "triple level result location with bitcast sandwich passed as tuple element
297test "@bitCast packed struct of floats" {297test "@bitCast packed struct of floats" {
298 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;298 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;299 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
300 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;303 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
306 const Foo = packed struct {306 const Foo = packed struct {
307 a: f16 = 0,307 a: f16 = 0,
...@@ -375,11 +375,11 @@ test "comptime @bitCast packed struct to int and back" {...@@ -375,11 +375,11 @@ test "comptime @bitCast packed struct to int and back" {
375375
376test "comptime bitcast with fields following f80" {376test "comptime bitcast with fields following f80" {
377 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;377 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
381 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;381 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
384 const FloatT = extern struct { f: f80, x: u128 align(16) };384 const FloatT = extern struct { f: f80, x: u128 align(16) };
385 const x: FloatT = .{ .f = 0.5, .x = 123 };385 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 {...@@ -18,7 +18,6 @@ const wuffs_base__slice_u8 = extern struct {
18};18};
19test {19test {
20 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO23 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 {...@@ -1369,10 +1369,10 @@ fn boolToStr(b: bool) []const u8 {
1369test "cast f16 to wider types" {1369test "cast f16 to wider types" {
1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1372 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1373 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1374 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1373 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1375 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1374 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
1377 const S = struct {1377 const S = struct {
1378 fn doTheTest() !void {1378 fn doTheTest() !void {
...@@ -1389,9 +1389,9 @@ test "cast f16 to wider types" {...@@ -1389,9 +1389,9 @@ test "cast f16 to wider types" {
1389test "cast f128 to narrower types" {1389test "cast f128 to narrower types" {
1390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1392 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1394 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1393 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
1396 const S = struct {1396 const S = struct {
1397 fn doTheTest() !void {1397 fn doTheTest() !void {
test/behavior/floatop.zig+2-2
...@@ -130,7 +130,7 @@ test "cmp f128" {...@@ -130,7 +130,7 @@ test "cmp f128" {
130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;131 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
132 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;132 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
135 try testCmp(f128);135 try testCmp(f128);
136 try comptime testCmp(f128);136 try comptime testCmp(f128);
...@@ -1379,7 +1379,7 @@ test "comptime fixed-width float zero divided by zero produces NaN" {...@@ -1379,7 +1379,7 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
1379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1381 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1381 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
1384 inline for (.{ f16, f32, f64, f80, f128 }) |F| {1384 inline for (.{ f16, f32, f64, f80, f128 }) |F| {
1385 try expect(math.isNan(@as(F, 0) / @as(F, 0)));1385 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 {...@@ -637,11 +637,11 @@ fn testShrTrunc(x: u16) !void {
637}637}
638638
639test "f128" {639test "f128" {
640 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
641 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO640 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
642 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO641 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
643 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO642 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
644 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;643 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
646 try test_f128();646 try test_f128();
647 try comptime test_f128();647 try comptime test_f128();
...@@ -1481,7 +1481,6 @@ test "@round f80" {...@@ -1481,7 +1481,6 @@ test "@round f80" {
1481test "@round f128" {1481test "@round f128" {
1482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1484 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1486 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1485 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1487 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1486 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
...@@ -1522,9 +1521,9 @@ test "vector integer addition" {...@@ -1522,9 +1521,9 @@ test "vector integer addition" {
1522test "NaN comparison" {1521test "NaN comparison" {
1523 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1522 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1527 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1525 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
1529 try testNanEqNan(f16);1528 try testNanEqNan(f16);
1530 try testNanEqNan(f32);1529 try testNanEqNan(f32);
...@@ -1539,9 +1538,9 @@ test "NaN comparison" {...@@ -1539,9 +1538,9 @@ test "NaN comparison" {
1539test "NaN comparison f80" {1538test "NaN comparison f80" {
1540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1539 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1540 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1542 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1544 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1542 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
1546 try testNanEqNan(f80);1545 try testNanEqNan(f80);
1547 try comptime testNanEqNan(f80);1546 try comptime testNanEqNan(f80);
test/behavior/maximum_minimum.zig+4-3
...@@ -10,7 +10,6 @@ test "@max" {...@@ -10,7 +10,6 @@ test "@max" {
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1413
15 const S = struct {14 const S = struct {
16 fn doTheTest() !void {15 fn doTheTest() !void {
...@@ -30,7 +29,8 @@ test "@max on vectors" {...@@ -30,7 +29,8 @@ test "@max on vectors" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;31 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
35 const S = struct {35 const S = struct {
36 fn doTheTest() !void {36 fn doTheTest() !void {
...@@ -78,7 +78,8 @@ test "@min for vectors" {...@@ -78,7 +78,8 @@ test "@min for vectors" {
78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;80 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
83 const S = struct {84 const S = struct {
84 fn doTheTest() !void {85 fn doTheTest() !void {
test/behavior/packed-struct.zig-1
...@@ -258,7 +258,6 @@ test "nested packed struct unaligned" {...@@ -258,7 +258,6 @@ test "nested packed struct unaligned" {
258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
261 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
262 if (native_endian != .Little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet261 if (native_endian != .Little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
263262
264 const S1 = packed struct {263 const S1 = packed struct {
test/behavior/widening.zig+1-1
...@@ -60,11 +60,11 @@ test "float widening" {...@@ -60,11 +60,11 @@ test "float widening" {
60}60}
6161
62test "float widening f16 to f128" {62test "float widening f16 to f128" {
63 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;66 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
69 var x: f16 = 12.34;69 var x: f16 = 12.34;
70 var y: f128 = x;70 var y: f128 = x;