authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-04 03:42:59-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-04 14:42:35-04:00
log2a5335d7b6628115ce29c3c712b55c661181e1d1
treed5586d99c167e9da12f02f5fa4a6d82ea5c36e44
parent9748096992620a9b1a2169ed3be34616fe417a99

x86_64: implement C abi for 128-bit integers


4 files changed, 449 insertions(+), 230 deletions(-)

lib/std/os/linux.zig+1-1
......@@ -156,7 +156,7 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
156156
157157pub usingnamespace if (switch (builtin.zig_backend) {
158158 // Calling extern functions is not yet supported with these backends
159 .stage2_x86_64, .stage2_aarch64, .stage2_arm, .stage2_riscv64, .stage2_sparc64 => false,
159 .stage2_aarch64, .stage2_arm, .stage2_riscv64, .stage2_sparc64 => false,
160160 else => !builtin.link_libc,
161161}) struct {
162162 /// See `std.elf` for the constants.
src/arch/x86_64/CodeGen.zig+374-227
......@@ -178,6 +178,8 @@ pub const MCValue = union(enum) {
178178 eflags: Condition,
179179 /// The value is in a register.
180180 register: Register,
181 /// The value is split across two registers.
182 register_pair: [2]Register,
181183 /// The value is a constant offset from the value in a register.
182184 register_offset: RegisterOffset,
183185 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
......@@ -255,6 +257,16 @@ pub const MCValue = union(enum) {
255257 };
256258 }
257259
260 fn getRegs(mcv: *const MCValue) []const Register {
261 return switch (mcv.*) {
262 .register => |*reg| @as(*const [1]Register, reg),
263 .register_pair => |*regs| regs,
264 .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg),
265 .register_overflow => |*ro| @as(*const [1]Register, &ro.reg),
266 else => &.{},
267 };
268 }
269
258270 fn getCondition(mcv: MCValue) ?Condition {
259271 return switch (mcv) {
260272 .eflags => |cc| cc,
......@@ -272,6 +284,7 @@ pub const MCValue = union(enum) {
272284 .immediate,
273285 .eflags,
274286 .register,
287 .register_pair,
275288 .register_offset,
276289 .register_overflow,
277290 .lea_direct,
......@@ -300,6 +313,7 @@ pub const MCValue = union(enum) {
300313 .dead,
301314 .undef,
302315 .eflags,
316 .register_pair,
303317 .register_overflow,
304318 .memory,
305319 .indirect,
......@@ -326,7 +340,11 @@ pub const MCValue = union(enum) {
326340 .unreach,
327341 .dead,
328342 .undef,
343 .reserved_frame,
344 .air_ref,
345 => unreachable, // not valid
329346 .eflags,
347 .register_pair,
330348 .register_overflow,
331349 .memory,
332350 .indirect,
......@@ -337,9 +355,10 @@ pub const MCValue = union(enum) {
337355 .load_tlv,
338356 .lea_tlv,
339357 .load_frame,
340 .reserved_frame,
341 .air_ref,
342 => unreachable, // not offsettable
358 => switch (off) {
359 0 => mcv,
360 else => unreachable, // not offsettable
361 },
343362 .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
344363 .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
345364 .register_offset => |reg_off| .{
......@@ -360,6 +379,7 @@ pub const MCValue = union(enum) {
360379 .immediate,
361380 .eflags,
362381 .register,
382 .register_pair,
363383 .register_offset,
364384 .register_overflow,
365385 .load_direct,
......@@ -398,8 +418,11 @@ pub const MCValue = union(enum) {
398418 .immediate => |pl| try writer.print("0x{x}", .{pl}),
399419 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
400420 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
421 .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
401422 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
402 .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg) }),
423 .register_overflow => |pl| try writer.print("{s}:{s}", .{
424 @tagName(pl.eflags), @tagName(pl.reg),
425 }),
403426 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
404427 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
405428 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
......@@ -443,6 +466,7 @@ const InstTracking = struct {
443466 => unreachable,
444467 .eflags,
445468 .register,
469 .register_pair,
446470 .register_offset,
447471 .register_overflow,
448472 .indirect,
......@@ -454,6 +478,10 @@ const InstTracking = struct {
454478 return self.short.getReg();
455479 }
456480
481 fn getRegs(self: *const InstTracking) []const Register {
482 return self.short.getRegs();
483 }
484
457485 fn getCondition(self: InstTracking) ?Condition {
458486 return self.short.getCondition();
459487 }
......@@ -494,6 +522,7 @@ const InstTracking = struct {
494522 .dead,
495523 .eflags,
496524 .register,
525 .register_pair,
497526 .register_offset,
498527 .register_overflow,
499528 .indirect,
......@@ -536,6 +565,7 @@ const InstTracking = struct {
536565 .dead,
537566 .eflags,
538567 .register,
568 .register_pair,
539569 .register_offset,
540570 .register_overflow,
541571 .indirect,
......@@ -2028,7 +2058,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
20282058 while (it.next()) |index| {
20292059 const tracked_inst = self.register_manager.registers[index];
20302060 const tracking = self.getResolvedInstValue(tracked_inst);
2031 assert(RegisterManager.indexOfRegIntoTracked(tracking.getReg().?).? == index);
2061 for (tracking.getRegs()) |reg| {
2062 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
2063 } else unreachable; // tracked register not in use
20322064 }
20332065 }
20342066 }
......@@ -2094,27 +2126,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
20942126}
20952127
20962128fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
2097 const reg = value.getReg() orelse return;
2098 if (self.register_manager.isRegFree(reg)) {
2129 for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg))
20992130 self.register_manager.getRegAssumeFree(reg, inst);
2100 }
21012131}
21022132
21032133fn freeValue(self: *Self, value: MCValue) void {
21042134 switch (value) {
2105 .register => |reg| {
2106 self.register_manager.freeReg(reg);
2107 },
2108 .register_offset => |reg_off| {
2109 self.register_manager.freeReg(reg_off.reg);
2110 },
2135 .register => |reg| self.register_manager.freeReg(reg),
2136 .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg),
2137 .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg),
21112138 .register_overflow => |reg_ov| {
21122139 self.register_manager.freeReg(reg_ov.reg);
21132140 self.eflags_inst = null;
21142141 },
2115 .eflags => {
2116 self.eflags_inst = null;
2117 },
2142 .eflags => self.eflags_inst = null,
21182143 else => {}, // TODO process stack allocation death
21192144 }
21202145}
......@@ -2449,7 +2474,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
24492474
24502475pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
24512476 const tracking = self.inst_tracking.getPtr(inst) orelse return;
2452 assert(tracking.getReg().?.id() == reg.id());
2477 for (tracking.getRegs()) |tracked_reg| {
2478 if (tracked_reg.id() == reg.id()) break;
2479 } else unreachable; // spilled reg not tracked with spilled instruciton
24532480 try tracking.spill(self, inst);
24542481 tracking.trackSpill(self, inst);
24552482}
......@@ -2465,9 +2492,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
24652492}
24662493
24672494pub fn spillRegisters(self: *Self, registers: []const Register) !void {
2468 for (registers) |reg| {
2469 try self.register_manager.getReg(reg, null);
2470 }
2495 for (registers) |reg| try self.register_manager.getReg(reg, null);
24712496}
24722497
24732498/// Copies a value to a register without tracking the register. The register is not considered
......@@ -5457,8 +5482,8 @@ fn reuseOperandAdvanced(
54575482 return false;
54585483
54595484 switch (mcv) {
5460 .register => |reg| {
5461 // If it's in the registers table, need to associate the register with the
5485 .register, .register_pair => for (mcv.getRegs()) |reg| {
5486 // If it's in the registers table, need to associate the register(s) with the
54625487 // new instruction.
54635488 if (!self.register_manager.isRegFree(reg)) {
54645489 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
......@@ -5561,6 +5586,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
55615586 .dead,
55625587 .undef,
55635588 .eflags,
5589 .register_pair,
55645590 .register_overflow,
55655591 .reserved_frame,
55665592 => unreachable, // not a valid pointer
......@@ -5585,7 +5611,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
55855611
55865612 try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
55875613 },
5588 .air_ref => |ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ref)),
5614 .air_ref => |ptr_ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ptr_ref)),
55895615 }
55905616}
55915617
......@@ -5707,6 +5733,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
57075733 .dead,
57085734 .undef,
57095735 .eflags,
5736 .register_pair,
57105737 .register_overflow,
57115738 .reserved_frame,
57125739 => unreachable, // not a valid pointer
......@@ -5731,7 +5758,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
57315758
57325759 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
57335760 },
5734 .air_ref => |ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ref)),
5761 .air_ref => |ptr_ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ptr_ref)),
57355762 }
57365763}
57375764
......@@ -6077,6 +6104,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
60776104 .air_ref,
60786105 => unreachable, // unmodifiable destination
60796106 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
6107 .register_pair => unreachable, // unimplemented
60806108 .memory, .load_got, .load_direct, .load_tlv => {
60816109 const addr_reg = try self.register_manager.allocReg(null, gp);
60826110 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -6764,7 +6792,7 @@ fn genBinOp(
67646792 => {
67656793 const resolved_src_mcv = switch (src_mcv) {
67666794 else => src_mcv,
6767 .air_ref => |ref| try self.resolveInst(ref),
6795 .air_ref => |src_ref| try self.resolveInst(src_ref),
67686796 };
67696797 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
67706798 .immediate,
......@@ -6780,6 +6808,9 @@ fn genBinOp(
67806808 => true,
67816809 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
67826810 else => false,
6811 .register_pair,
6812 .register_overflow,
6813 => unreachable,
67836814 })
67846815 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
67856816 else
......@@ -6820,6 +6851,7 @@ fn genBinOp(
68206851 .undef,
68216852 .immediate,
68226853 .eflags,
6854 .register_pair,
68236855 .register_offset,
68246856 .register_overflow,
68256857 .load_direct,
......@@ -7748,121 +7780,154 @@ fn genBinOpMir(
77487780 .reserved_frame,
77497781 .air_ref,
77507782 => unreachable, // unmodifiable destination
7751 .register, .register_offset => {
7752 assert(dst_mcv.isRegister());
7753 const dst_reg = dst_mcv.getReg().?;
7754 const dst_alias = registerAlias(dst_reg, abi_size);
7755 switch (src_mcv) {
7756 .none,
7757 .unreach,
7758 .dead,
7759 .undef,
7760 .register_overflow,
7761 .reserved_frame,
7762 => unreachable,
7763 .register => |src_reg| try self.asmRegisterRegister(
7764 mir_tag,
7765 dst_alias,
7766 registerAlias(src_reg, abi_size),
7767 ),
7768 .immediate => |imm| switch (self.regBitSize(ty)) {
7769 8 => try self.asmRegisterImmediate(
7770 mir_tag,
7771 dst_alias,
7772 if (math.cast(i8, @as(i64, @bitCast(imm)))) |small|
7773 Immediate.s(small)
7774 else
7775 Immediate.u(@as(u8, @intCast(imm))),
7776 ),
7777 16 => try self.asmRegisterImmediate(
7778 mir_tag,
7783 .register, .register_pair, .register_offset => {
7784 switch (dst_mcv) {
7785 .register, .register_pair => {},
7786 .register_offset => |ro| assert(ro.off == 0),
7787 else => unreachable,
7788 }
7789 for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| {
7790 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
7791 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
7792
7793 const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) {
7794 0 => mir_tag,
7795 1 => switch (mir_tag[1]) {
7796 .add => .{ ._, .adc },
7797 .sub, .cmp => .{ ._, .sbb },
7798 .@"or", .@"and", .xor => mir_tag,
7799 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
7800 @tagName(mir_tag[1]),
7801 }),
7802 },
7803 else => unreachable,
7804 };
7805 const off: u4 = @intCast(dst_reg_i * 8);
7806 const limb_abi_size = @min(abi_size - off, 8);
7807 const dst_alias = registerAlias(dst_reg, limb_abi_size);
7808 switch (src_mcv) {
7809 .none,
7810 .unreach,
7811 .dead,
7812 .undef,
7813 .register_overflow,
7814 .reserved_frame,
7815 => unreachable,
7816 .register, .register_pair => try self.asmRegisterRegister(
7817 mir_limb_tag,
77797818 dst_alias,
7780 if (math.cast(i16, @as(i64, @bitCast(imm)))) |small|
7781 Immediate.s(small)
7782 else
7783 Immediate.u(@as(u16, @intCast(imm))),
7819 registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),
77847820 ),
7785 32 => try self.asmRegisterImmediate(
7821 .immediate => |imm| {
7822 assert(off == 0);
7823 switch (self.regBitSize(ty)) {
7824 8 => try self.asmRegisterImmediate(
7825 mir_limb_tag,
7826 dst_alias,
7827 if (math.cast(i8, @as(i64, @bitCast(imm)))) |small|
7828 Immediate.s(small)
7829 else
7830 Immediate.u(@as(u8, @intCast(imm))),
7831 ),
7832 16 => try self.asmRegisterImmediate(
7833 mir_limb_tag,
7834 dst_alias,
7835 if (math.cast(i16, @as(i64, @bitCast(imm)))) |small|
7836 Immediate.s(small)
7837 else
7838 Immediate.u(@as(u16, @intCast(imm))),
7839 ),
7840 32 => try self.asmRegisterImmediate(
7841 mir_limb_tag,
7842 dst_alias,
7843 if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7844 Immediate.s(small)
7845 else
7846 Immediate.u(@as(u32, @intCast(imm))),
7847 ),
7848 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7849 try self.asmRegisterImmediate(mir_limb_tag, dst_alias, Immediate.s(small))
7850 else
7851 try self.asmRegisterRegister(mir_limb_tag, dst_alias, registerAlias(
7852 try self.copyToTmpRegister(ty, src_mcv),
7853 limb_abi_size,
7854 )),
7855 else => unreachable,
7856 }
7857 },
7858 .eflags,
7859 .register_offset,
7860 .memory,
7861 .indirect,
7862 .load_direct,
7863 .lea_direct,
7864 .load_got,
7865 .lea_got,
7866 .load_tlv,
7867 .lea_tlv,
7868 .load_frame,
7869 .lea_frame,
7870 => {
7871 blk: {
7872 return self.asmRegisterMemory(
7873 mir_limb_tag,
7874 dst_alias,
7875 Memory.sib(Memory.PtrSize.fromSize(limb_abi_size), switch (src_mcv) {
7876 .memory => |addr| .{
7877 .base = .{ .reg = .ds },
7878 .disp = math.cast(i32, addr + off) orelse break :blk,
7879 },
7880 .indirect => |reg_off| .{
7881 .base = .{ .reg = reg_off.reg },
7882 .disp = reg_off.off + off,
7883 },
7884 .load_frame => |frame_addr| .{
7885 .base = .{ .frame = frame_addr.index },
7886 .disp = frame_addr.off + off,
7887 },
7888 else => break :blk,
7889 }),
7890 );
7891 }
7892
7893 switch (src_mcv) {
7894 .eflags,
7895 .register_offset,
7896 .lea_direct,
7897 .lea_got,
7898 .lea_tlv,
7899 .lea_frame,
7900 => {
7901 assert(off == 0);
7902 const reg = try self.copyToTmpRegister(ty, src_mcv);
7903 return self.genBinOpMir(
7904 mir_limb_tag,
7905 ty,
7906 dst_mcv,
7907 .{ .register = reg },
7908 );
7909 },
7910 .memory,
7911 .load_direct,
7912 .load_got,
7913 .load_tlv,
7914 => {
7915 const ptr_ty = try mod.singleConstPtrType(ty);
7916 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
7917 return self.genBinOpMir(mir_limb_tag, ty, dst_mcv, .{
7918 .indirect = .{ .reg = addr_reg, .off = off },
7919 });
7920 },
7921 else => unreachable,
7922 }
7923 },
7924 .air_ref => |src_ref| return self.genBinOpMir(
77867925 mir_tag,
7787 dst_alias,
7788 if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7789 Immediate.s(small)
7790 else
7791 Immediate.u(@as(u32, @intCast(imm))),
7926 ty,
7927 dst_mcv,
7928 try self.resolveInst(src_ref),
77927929 ),
7793 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small|
7794 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
7795 else
7796 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
7797 try self.copyToTmpRegister(ty, src_mcv),
7798 abi_size,
7799 )),
7800 else => unreachable,
7801 },
7802 .eflags,
7803 .register_offset,
7804 .memory,
7805 .indirect,
7806 .load_direct,
7807 .lea_direct,
7808 .load_got,
7809 .lea_got,
7810 .load_tlv,
7811 .lea_tlv,
7812 .load_frame,
7813 .lea_frame,
7814 => {
7815 blk: {
7816 return self.asmRegisterMemory(
7817 mir_tag,
7818 registerAlias(dst_reg, abi_size),
7819 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
7820 .memory => |addr| .{
7821 .base = .{ .reg = .ds },
7822 .disp = math.cast(i32, addr) orelse break :blk,
7823 },
7824 .indirect => |reg_off| .{
7825 .base = .{ .reg = reg_off.reg },
7826 .disp = reg_off.off,
7827 },
7828 .load_frame => |frame_addr| .{
7829 .base = .{ .frame = frame_addr.index },
7830 .disp = frame_addr.off,
7831 },
7832 else => break :blk,
7833 }),
7834 );
7835 }
7836
7837 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
7838 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
7839
7840 switch (src_mcv) {
7841 .eflags,
7842 .register_offset,
7843 .lea_direct,
7844 .lea_got,
7845 .lea_tlv,
7846 .lea_frame,
7847 => {
7848 const reg = try self.copyToTmpRegister(ty, src_mcv);
7849 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
7850 },
7851 .memory,
7852 .load_direct,
7853 .load_got,
7854 .load_tlv,
7855 => {
7856 const ptr_ty = try mod.singleConstPtrType(ty);
7857 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
7858 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{
7859 .indirect = .{ .reg = addr_reg },
7860 });
7861 },
7862 else => unreachable,
7863 }
7864 },
7865 .air_ref => |ref| try self.genBinOpMir(mir_tag, ty, dst_mcv, try self.resolveInst(ref)),
7930 }
78667931 }
78677932 },
78687933 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
......@@ -7877,10 +7942,7 @@ fn genBinOpMir(
78777942 errdefer self.register_manager.unlockReg(dst_addr_lock);
78787943
78797944 try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address());
7880 break :dst .{
7881 .addr_reg = dst_addr_reg,
7882 .addr_lock = dst_addr_lock,
7883 };
7945 break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock };
78847946 },
78857947 .load_frame => null,
78867948 };
......@@ -7888,7 +7950,7 @@ fn genBinOpMir(
78887950
78897951 const resolved_src_mcv = switch (src_mcv) {
78907952 else => src_mcv,
7891 .air_ref => |ref| try self.resolveInst(ref),
7953 .air_ref => |src_ref| try self.resolveInst(src_ref),
78927954 };
78937955 const src_info: OpInfo = switch (resolved_src_mcv) {
78947956 .none,
......@@ -7901,6 +7963,7 @@ fn genBinOpMir(
79017963 => unreachable,
79027964 .immediate,
79037965 .register,
7966 .register_pair,
79047967 .register_offset,
79057968 .eflags,
79067969 .indirect,
......@@ -7924,10 +7987,7 @@ fn genBinOpMir(
79247987 errdefer self.register_manager.unlockReg(src_addr_lock);
79257988
79267989 try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address());
7927 break :src .{
7928 .addr_reg = src_addr_reg,
7929 .addr_lock = src_addr_lock,
7930 };
7990 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
79317991 },
79327992 };
79337993 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
......@@ -7938,9 +7998,13 @@ fn genBinOpMir(
79387998 .signed => Type.usize,
79397999 .unsigned => Type.isize,
79408000 };
8001 var limb_i: usize = 0;
79418002 var off: i32 = 0;
7942 while (off < abi_size) : (off += 8) {
7943 const mir_limb_tag: Mir.Inst.FixedTag = switch (off) {
8003 while (off < abi_size) : ({
8004 limb_i += 1;
8005 off += 8;
8006 }) {
8007 const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) {
79448008 0 => mir_tag,
79458009 else => switch (mir_tag[1]) {
79468010 .add => .{ ._, .adc },
......@@ -7979,16 +8043,8 @@ fn genBinOpMir(
79798043 .reserved_frame,
79808044 .air_ref,
79818045 => 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 },
79908046 .immediate => |src_imm| {
7991 const imm: u64 = switch (off) {
8047 const imm: u64 = switch (limb_i) {
79928048 0 => src_imm,
79938049 else => switch (ty_signedness) {
79948050 .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63),
......@@ -8038,6 +8094,8 @@ fn genBinOpMir(
80388094 else => unreachable,
80398095 }
80408096 },
8097 .register,
8098 .register_pair,
80418099 .register_offset,
80428100 .eflags,
80438101 .memory,
......@@ -8051,16 +8109,19 @@ fn genBinOpMir(
80518109 .load_frame,
80528110 .lea_frame,
80538111 => {
8054 const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{
8112 const src_limb_mcv: MCValue = if (src_info) |info| .{
80558113 .indirect = .{ .reg = info.addr_reg, .off = off },
80568114 } else switch (resolved_src_mcv) {
8115 .register, .register_pair => .{
8116 .register = resolved_src_mcv.getRegs()[limb_i],
8117 },
80578118 .eflags,
80588119 .register_offset,
80598120 .lea_direct,
80608121 .lea_got,
80618122 .lea_tlv,
80628123 .lea_frame,
8063 => switch (off) {
8124 => switch (limb_i) {
80648125 0 => resolved_src_mcv,
80658126 else => .{ .immediate = 0 },
80668127 },
......@@ -8074,7 +8135,11 @@ fn genBinOpMir(
80748135 .off = frame_addr.off + off,
80758136 } },
80768137 else => unreachable,
8077 });
8138 };
8139 const src_limb_reg = if (src_limb_mcv.isRegister())
8140 src_limb_mcv.getReg().?
8141 else
8142 try self.copyToTmpRegister(limb_ty, src_limb_mcv);
80788143 try self.asmMemoryRegister(
80798144 mir_limb_tag,
80808145 dst_limb_mem,
......@@ -8098,8 +8163,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
80988163 .dead,
80998164 .undef,
81008165 .immediate,
8101 .register_offset,
81028166 .eflags,
8167 .register_offset,
81038168 .register_overflow,
81048169 .lea_direct,
81058170 .lea_got,
......@@ -8115,13 +8180,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
81158180
81168181 const resolved_src_mcv = switch (src_mcv) {
81178182 else => src_mcv,
8118 .air_ref => |ref| try self.resolveInst(ref),
8183 .air_ref => |src_ref| try self.resolveInst(src_ref),
81198184 };
81208185 switch (resolved_src_mcv) {
81218186 .none,
81228187 .unreach,
81238188 .dead,
81248189 .undef,
8190 .register_pair,
81258191 .register_overflow,
81268192 .reserved_frame,
81278193 .air_ref,
......@@ -8187,6 +8253,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
81878253 ),
81888254 }
81898255 },
8256 .register_pair => unreachable, // unimplemented
81908257 .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => {
81918258 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
81928259 const tmp_mcv = MCValue{ .register = tmp_reg };
......@@ -8209,8 +8276,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
82098276 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
82108277 const dst_mcv = self.args[arg_index];
82118278 switch (dst_mcv) {
8212 .register => |reg| self.register_manager.getRegAssumeFree(reg, inst),
8213 .load_frame => {},
8279 .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg|
8280 self.register_manager.getRegAssumeFree(reg, inst),
82148281 else => return self.fail("TODO implement arg for {}", .{dst_mcv}),
82158282 }
82168283
......@@ -8230,6 +8297,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
82308297 .dwarf => |dw| {
82318298 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
82328299 .register => |reg| .{ .register = reg.dwarfNum() },
8300 .register_pair => |regs| .{ .register_pair = .{
8301 regs[0].dwarfNum(), regs[1].dwarfNum(),
8302 } },
82338303 // TODO use a frame index
82348304 .load_frame => return,
82358305 //.stack_offset => |off| .{
......@@ -8390,7 +8460,10 @@ fn genCall(self: *Self, info: union(enum) {
83908460 };
83918461 const fn_info = mod.typeToFunc(fn_ty).?;
83928462
8393 const ExpectedContents = [16]Type;
8463 const ExpectedContents = extern struct {
8464 var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)),
8465 arg_regs: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)),
8466 };
83948467 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
83958468 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
83968469 const allocator = stack.get();
......@@ -8399,6 +8472,11 @@ fn genCall(self: *Self, info: union(enum) {
83998472 defer allocator.free(var_args);
84008473 for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
84018474
8475 var arg_locks = std.ArrayList(?RegisterLock).init(allocator);
8476 defer arg_locks.deinit();
8477 try arg_locks.ensureTotalCapacity(16);
8478 defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock);
8479
84028480 var call_info =
84038481 try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);
84048482 defer call_info.deinit(self);
......@@ -8430,7 +8508,14 @@ fn genCall(self: *Self, info: union(enum) {
84308508 }
84318509 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
84328510 .none => {},
8433 .register => |reg| try self.spillRegisters(&.{reg}),
8511 .register => |reg| {
8512 try self.spillRegisters(&.{reg});
8513 try arg_locks.append(self.register_manager.lockReg(reg));
8514 },
8515 .register_pair => |regs| {
8516 try self.spillRegisters(&regs);
8517 try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));
8518 },
84348519 .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),
84358520 else => unreachable,
84368521 };
......@@ -8451,13 +8536,11 @@ fn genCall(self: *Self, info: union(enum) {
84518536 };
84528537 defer if (ret_lock) |lock| self.register_manager.unlockReg(lock);
84538538
8454 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| {
8455 switch (dst_arg) {
8456 .none, .load_frame => {},
8457 .register => try self.genCopy(arg_ty, dst_arg, src_arg),
8458 else => unreachable,
8459 }
8460 }
8539 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
8540 .none, .load_frame => {},
8541 .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg),
8542 else => unreachable,
8543 };
84618544
84628545 // Due to incremental compilation, how function calls are generated depends
84638546 // on linking.
......@@ -8527,7 +8610,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
85278610 const ret_ty = self.fn_type.fnReturnType(mod);
85288611 switch (self.ret_mcv.short) {
85298612 .none => {},
8530 .register => try self.genCopy(ret_ty, self.ret_mcv.short, operand),
8613 .register, .register_pair => try self.genCopy(ret_ty, self.ret_mcv.short, operand),
85318614 .indirect => |reg_off| {
85328615 try self.register_manager.getReg(reg_off.reg, null);
85338616 const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg);
......@@ -8612,6 +8695,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
86128695 const lhs_mcv = try self.resolveInst(bin_op.lhs);
86138696 const lhs_lock = switch (lhs_mcv) {
86148697 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
8698 .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg),
86158699 else => null,
86168700 };
86178701 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -8619,6 +8703,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
86198703 const rhs_mcv = try self.resolveInst(bin_op.rhs);
86208704 const rhs_lock = switch (rhs_mcv) {
86218705 .register => |reg| self.register_manager.lockReg(reg),
8706 .register_offset => |ro| self.register_manager.lockReg(ro.reg),
86228707 else => null,
86238708 };
86248709 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -9039,6 +9124,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
90399124 .undef,
90409125 .immediate,
90419126 .eflags,
9127 .register_pair,
90429128 .register_offset,
90439129 .register_overflow,
90449130 .lea_direct,
......@@ -10102,6 +10188,16 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
1010210188 .off = -dst_reg_off.off,
1010310189 } },
1010410190 }),
10191 .register_pair => |dst_regs| switch (src_mcv) {
10192 .register_pair => |src_regs| for (dst_regs, src_regs) |dst_reg, src_reg|
10193 try self.genSetReg(dst_reg, Type.usize, .{ .register = src_reg }),
10194 else => for (dst_regs, 0..) |dst_reg, dst_reg_i| try self.genSetReg(
10195 dst_reg,
10196 Type.usize,
10197 src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(),
10198 ),
10199 .air_ref => |src_ref| try self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)),
10200 },
1010510201 .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),
1010610202 .memory, .load_direct, .load_got, .load_tlv => {
1010710203 switch (dst_mcv) {
......@@ -10135,6 +10231,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1013510231 .none,
1013610232 .unreach,
1013710233 .dead,
10234 .register_pair,
1013810235 .register_overflow,
1013910236 .reserved_frame,
1014010237 => unreachable,
......@@ -10312,6 +10409,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1031210409 Immediate.u(0),
1031310410 ),
1031410411 }
10412 return;
1031510413 },
1031610414 .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) {
1031710415 else => {
......@@ -10403,7 +10501,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1040310501 @tagName(self.bin_file.tag),
1040410502 });
1040510503 },
10406 .air_ref => |ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(ref)),
10504 .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref)),
1040710505 }
1040810506}
1040910507
......@@ -10480,6 +10578,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
1048010578 ),
1048110579 }
1048210580 },
10581 .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| {
10582 const part_size = @min(abi_size - src_reg_i * 8, 8);
10583 const dst_mem = Memory.sib(
10584 Memory.PtrSize.fromSize(part_size),
10585 .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) },
10586 );
10587 const src_alias = registerAlias(src_reg, part_size);
10588 switch (try self.moveStrategy(ty, switch (base) {
10589 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10590 .reg => |reg| switch (reg) {
10591 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10592 else => false,
10593 },
10594 .frame => |frame_index| self.getFrameAddrAlignment(
10595 .{ .index = frame_index, .off = disp },
10596 ).compare(.gte, ty.abiAlignment(mod)),
10597 })) {
10598 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),
10599 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
10600 ie.extract,
10601 dst_mem,
10602 src_alias,
10603 Immediate.u(0),
10604 ),
10605 }
10606 },
1048310607 .register_overflow => |ro| {
1048410608 try self.genSetMem(
1048510609 base,
......@@ -10516,7 +10640,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
1051610640 },
1051710641 else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }),
1051810642 },
10519 .air_ref => |ref| try self.genSetMem(base, disp, ty, try self.resolveInst(ref)),
10643 .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref)),
1052010644 }
1052110645}
1052210646
......@@ -12306,68 +12430,93 @@ fn resolveCallingConventionValues(
1230612430 .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)},
1230712431 else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none),
1230812432 };
12309 if (classes.len > 1) {
12310 return self.fail("TODO handle multiple classes per type", .{});
12433 for (
12434 classes,
12435 abi.getCAbiIntReturnRegs(self.target.*)[0..classes.len],
12436 0..,
12437 ) |class, ret_reg, ret_reg_i| {
12438 result.return_value = switch (classes[0]) {
12439 .integer => switch (ret_reg_i) {
12440 0 => InstTracking.init(.{ .register = registerAlias(
12441 ret_reg,
12442 @intCast(@min(ret_ty.abiSize(mod), 8)),
12443 ) }),
12444 1 => InstTracking.init(.{ .register_pair = .{
12445 result.return_value.short.register,
12446 registerAlias(ret_reg, @intCast(ret_ty.abiSize(mod) - 8)),
12447 } }),
12448 else => return self.fail("TODO handle multiple classes per type", .{}),
12449 },
12450 .float, .sse => switch (ret_reg_i) {
12451 0 => InstTracking.init(.{ .register = .xmm0 }),
12452 else => return self.fail("TODO handle multiple classes per type", .{}),
12453 },
12454 .memory => switch (ret_reg_i) {
12455 0 => ret: {
12456 const ret_indirect_reg =
12457 abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
12458 param_reg_i += 1;
12459 break :ret .{
12460 .short = .{ .indirect = .{ .reg = ret_reg } },
12461 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
12462 };
12463 },
12464 else => return self.fail("TODO handle multiple classes per type", .{}),
12465 },
12466 else => return self.fail("TODO handle calling convention class {s}", .{
12467 @tagName(class),
12468 }),
12469 };
1231112470 }
12312 const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0];
12313 result.return_value = switch (classes[0]) {
12314 .integer => InstTracking.init(.{ .register = registerAlias(
12315 ret_reg,
12316 @intCast(ret_ty.abiSize(mod)),
12317 ) }),
12318 .float, .sse => InstTracking.init(.{ .register = .xmm0 }),
12319 .memory => ret: {
12320 const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
12321 param_reg_i += 1;
12322 break :ret .{
12323 .short = .{ .indirect = .{ .reg = ret_reg } },
12324 .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
12325 };
12326 },
12327 else => |class| return self.fail("TODO handle calling convention class {s}", .{
12328 @tagName(class),
12329 }),
12330 };
1233112471 }
1233212472
1233312473 // Input params
12334 for (param_types, result.args) |ty, *arg| {
12474 next_param: for (param_types, result.args) |ty, *arg| {
1233512475 assert(ty.hasRuntimeBitsIgnoreComptime(mod));
1233612476
1233712477 const classes = switch (self.target.os.tag) {
1233812478 .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)},
1233912479 else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none),
1234012480 };
12341 if (classes.len > 1) {
12342 return self.fail("TODO handle multiple classes per type", .{});
12343 }
12344 switch (classes[0]) {
12345 .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) {
12346 arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] };
12347 param_reg_i += 1;
12348 continue;
12349 },
12350 .float, .sse => switch (self.target.os.tag) {
12351 .windows => if (param_reg_i < 4) {
12352 arg.* = .{
12353 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i),
12354 };
12481 for (classes, 0..) |class, class_i| {
12482 switch (class) {
12483 .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) {
12484 const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i];
1235512485 param_reg_i += 1;
12356 continue;
12357 },
12358 else => if (param_sse_reg_i < 8) {
12359 arg.* = .{
12360 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_sse_reg_i),
12486
12487 arg.* = switch (class_i) {
12488 0 => .{ .register = param_reg },
12489 1 => .{ .register_pair = .{ arg.register, param_reg } },
12490 else => return self.fail("TODO handle multiple classes per type", .{}),
1236112491 };
12362 param_sse_reg_i += 1;
1236312492 continue;
12493 } else break,
12494 .float, .sse => switch (self.target.os.tag) {
12495 .windows => if (param_reg_i < 4) {
12496 if (class_i > 0)
12497 return self.fail("TODO handle multiple classes per type", .{});
12498 arg.* = .{
12499 .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i),
12500 };
12501 param_reg_i += 1;
12502 continue;
12503 } else break,
12504 else => if (param_sse_reg_i < 8) {
12505 if (class_i > 0)
12506 return self.fail("TODO handle multiple classes per type", .{});
12507 arg.* = .{ .register = @enumFromInt(
12508 @intFromEnum(Register.xmm0) + param_sse_reg_i,
12509 ) };
12510 param_sse_reg_i += 1;
12511 continue;
12512 } else break,
1236412513 },
12365 },
12366 .memory => {}, // fallthrough
12367 else => |class| return self.fail("TODO handle calling convention class {s}", .{
12368 @tagName(class),
12369 }),
12370 }
12514 .memory => break,
12515 else => return self.fail("TODO handle calling convention class {s}", .{
12516 @tagName(class),
12517 }),
12518 }
12519 } else continue :next_param;
1237112520
1237212521 const param_size: u31 = @intCast(ty.abiSize(mod));
1237312522 const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?);
......@@ -12602,9 +12751,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type {
1260212751
1260312752fn floatLibcAbiPrefix(ty: Type) []const u8 {
1260412753 return switch (ty.toIntern()) {
12605 .f16_type,
12606 .f80_type,
12607 => "__",
12754 .f16_type, .f80_type => "__",
1260812755 .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",
1260912756 else => unreachable,
1261012757 };
src/link/Dwarf.zig+74-1
......@@ -566,6 +566,7 @@ pub const DeclState = struct {
566566
567567 pub const DbgInfoLoc = union(enum) {
568568 register: u8,
569 register_pair: [2]u8,
569570 stack: struct {
570571 fp_register: u8,
571572 offset: i32,
......@@ -610,6 +611,42 @@ pub const DeclState = struct {
610611 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
611612 }
612613 },
614 .register_pair => |regs| {
615 const reg_bits = self.mod.getTarget().ptrBitWidth();
616 const reg_bytes = @as(u8, @intCast(@divExact(reg_bits, 8)));
617 const abi_size = ty.abiSize(self.mod);
618 try dbg_info.ensureUnusedCapacity(10);
619 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));
620 // DW.AT.location, DW.FORM.exprloc
621 var expr_len = std.io.countingWriter(std.io.null_writer);
622 for (regs, 0..) |reg, reg_i| {
623 if (reg < 32) {
624 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
625 } else {
626 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
627 leb128.writeULEB128(expr_len.writer(), reg) catch unreachable;
628 }
629 expr_len.writer().writeByte(DW.OP.piece) catch unreachable;
630 leb128.writeULEB128(
631 expr_len.writer(),
632 @min(abi_size - reg_i * reg_bytes, reg_bytes),
633 ) catch unreachable;
634 }
635 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
636 for (regs, 0..) |reg, reg_i| {
637 if (reg < 32) {
638 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
639 } else {
640 dbg_info.appendAssumeCapacity(DW.OP.regx);
641 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
642 }
643 dbg_info.appendAssumeCapacity(DW.OP.piece);
644 leb128.writeULEB128(
645 dbg_info.writer(),
646 @min(abi_size - reg_i * reg_bytes, reg_bytes),
647 ) catch unreachable;
648 }
649 },
613650 .stack => |info| {
614651 try dbg_info.ensureUnusedCapacity(9);
615652 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));
......@@ -676,7 +713,7 @@ pub const DeclState = struct {
676713
677714 switch (loc) {
678715 .register => |reg| {
679 try dbg_info.ensureUnusedCapacity(4);
716 try dbg_info.ensureUnusedCapacity(3);
680717 // DW.AT.location, DW.FORM.exprloc
681718 var expr_len = std.io.countingWriter(std.io.null_writer);
682719 if (reg < 32) {
......@@ -694,6 +731,42 @@ pub const DeclState = struct {
694731 }
695732 },
696733
734 .register_pair => |regs| {
735 const reg_bits = self.mod.getTarget().ptrBitWidth();
736 const reg_bytes = @as(u8, @intCast(@divExact(reg_bits, 8)));
737 const abi_size = child_ty.abiSize(self.mod);
738 try dbg_info.ensureUnusedCapacity(9);
739 // DW.AT.location, DW.FORM.exprloc
740 var expr_len = std.io.countingWriter(std.io.null_writer);
741 for (regs, 0..) |reg, reg_i| {
742 if (reg < 32) {
743 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
744 } else {
745 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
746 leb128.writeULEB128(expr_len.writer(), reg) catch unreachable;
747 }
748 expr_len.writer().writeByte(DW.OP.piece) catch unreachable;
749 leb128.writeULEB128(
750 expr_len.writer(),
751 @min(abi_size - reg_i * reg_bytes, reg_bytes),
752 ) catch unreachable;
753 }
754 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
755 for (regs, 0..) |reg, reg_i| {
756 if (reg < 32) {
757 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
758 } else {
759 dbg_info.appendAssumeCapacity(DW.OP.regx);
760 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
761 }
762 dbg_info.appendAssumeCapacity(DW.OP.piece);
763 leb128.writeULEB128(
764 dbg_info.writer(),
765 @min(abi_size - reg_i * reg_bytes, reg_bytes),
766 ) catch unreachable;
767 }
768 },
769
697770 .stack => |info| {
698771 try dbg_info.ensureUnusedCapacity(9);
699772 // DW.AT.location, DW.FORM.exprloc
test/behavior/bugs/11995.zig-1
......@@ -18,7 +18,6 @@ const wuffs_base__slice_u8 = extern struct {
1818};
1919test {
2020 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO