authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-05 03:02:42+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-05 03:02:42+02:00
log5ea6e78943453e145366c8860cb9c8f9684f9b31
treec9fc4b4ffe6636ce839fa3f24328667d4aed8ee1
parent3a8362e751d210f1cecfce7c33cae2e582bd4b94
parent83b7dbe52f75161a2ac6f5d8f39b275fd9473c15
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15162 from jacobly0/x86_64-start

x86_64: get enough things working to enable full `start.zig` logic

26 files changed, 596 insertions(+), 470 deletions(-)

lib/std/os/linux/x86.zig+12-4
......@@ -125,36 +125,44 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *
125125
126126pub fn restore() callconv(.Naked) void {
127127 switch (@import("builtin").zig_backend) {
128 .stage2_c => return asm volatile (
128 .stage2_c => asm volatile (
129129 \\ movl %[number], %%eax
130130 \\ int $0x80
131 \\ ret
131132 :
132133 : [number] "i" (@enumToInt(SYS.sigreturn)),
133134 : "memory"
134135 ),
135 else => return asm volatile ("int $0x80"
136 else => asm volatile (
137 \\ int $0x80
138 \\ ret
136139 :
137140 : [number] "{eax}" (@enumToInt(SYS.sigreturn)),
138141 : "memory"
139142 ),
140143 }
144 unreachable;
141145}
142146
143147pub fn restore_rt() callconv(.Naked) void {
144148 switch (@import("builtin").zig_backend) {
145 .stage2_c => return asm volatile (
149 .stage2_c => asm volatile (
146150 \\ movl %[number], %%eax
147151 \\ int $0x80
152 \\ ret
148153 :
149154 : [number] "i" (@enumToInt(SYS.rt_sigreturn)),
150155 : "memory"
151156 ),
152 else => return asm volatile ("int $0x80"
157 else => asm volatile (
158 \\ int $0x80
159 \\ ret
153160 :
154161 : [number] "{eax}" (@enumToInt(SYS.rt_sigreturn)),
155162 : "memory"
156163 ),
157164 }
165 unreachable;
158166}
159167
160168pub const O = struct {
lib/std/os/linux/x86_64.zig+5-2
......@@ -109,7 +109,7 @@ pub const restore = restore_rt;
109109
110110pub fn restore_rt() callconv(.Naked) void {
111111 switch (@import("builtin").zig_backend) {
112 .stage2_c => return asm volatile (
112 .stage2_c => asm volatile (
113113 \\ movl %[number], %%eax
114114 \\ syscall
115115 \\ retq
......@@ -117,12 +117,15 @@ pub fn restore_rt() callconv(.Naked) void {
117117 : [number] "i" (@enumToInt(SYS.rt_sigreturn)),
118118 : "rcx", "r11", "memory"
119119 ),
120 else => return asm volatile ("syscall"
120 else => asm volatile (
121 \\ syscall
122 \\ retq
121123 :
122124 : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)),
123125 : "rcx", "r11", "memory"
124126 ),
125127 }
128 unreachable;
126129}
127130
128131pub const mode_t = usize;
lib/std/start.zig+1-1
......@@ -19,7 +19,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
1919// self-hosted is capable enough to handle all of the real start.zig logic.
2020pub const simplified_logic =
2121 builtin.zig_backend == .stage2_wasm or
22 builtin.zig_backend == .stage2_x86_64 or
22 (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or
2323 builtin.zig_backend == .stage2_x86 or
2424 builtin.zig_backend == .stage2_aarch64 or
2525 builtin.zig_backend == .stage2_arm or
src/Module.zig+1-1
......@@ -555,7 +555,7 @@ pub const Decl = struct {
555555 _,
556556
557557 pub fn init(oi: ?Index) OptionalIndex {
558 return oi orelse .none;
558 return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none));
559559 }
560560
561561 pub fn unwrap(oi: OptionalIndex) ?Index {
src/arch/x86_64/CodeGen.zig+326-234
......@@ -28,10 +28,11 @@ const Type = @import("../../type.zig").Type;
2828const TypedValue = @import("../../TypedValue.zig");
2929const Value = @import("../../value.zig").Value;
3030
31const bits = @import("bits.zig");
3231const abi = @import("abi.zig");
33const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
32const bits = @import("bits.zig");
33const encoder = @import("encoder.zig");
3434const errUnionErrorOffset = codegen.errUnionErrorOffset;
35const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
3536
3637const Condition = bits.Condition;
3738const Immediate = bits.Immediate;
......@@ -2527,7 +2528,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
25272528 const dst_lock = self.register_manager.lockReg(dst_reg);
25282529 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
25292530
2530 const pl_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
2531 const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));
25312532 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
25322533 try self.asmRegisterMemory(
25332534 .lea,
......@@ -3650,10 +3651,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
36503651 .dead => unreachable,
36513652 .eflags => unreachable,
36523653 .register_overflow => unreachable,
3653 .immediate => |imm| {
3654 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
3655 },
3656 .stack_offset => {
3654 .immediate, .stack_offset => {
36573655 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
36583656 try self.store(.{ .register = reg }, value, ptr_ty, value_ty);
36593657 },
......@@ -3668,52 +3666,67 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
36683666 .none => unreachable,
36693667 .dead => unreachable,
36703668 .unreach => unreachable,
3671 .eflags => |cc| {
3672 try self.asmSetccMemory(Memory.sib(
3673 Memory.PtrSize.fromSize(abi_size),
3674 .{ .base = reg.to64() },
3675 ), cc);
3676 },
3677 .undef => {
3678 if (!self.wantSafety()) return; // The already existing value will do just fine.
3679 switch (abi_size) {
3680 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),
3681 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),
3682 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty),
3683 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty),
3684 else => try self.genInlineMemset(ptr, .{ .immediate = 0xaa }, .{ .immediate = abi_size }, .{}),
3685 }
3686 },
3687 .immediate => |imm| {
3688 switch (abi_size) {
3689 1, 2, 4 => {
3690 const immediate = if (value_ty.isSignedInt())
3691 Immediate.s(@intCast(i32, @bitCast(i64, imm)))
3692 else
3693 Immediate.u(@truncate(u32, imm));
3694 try self.asmMemoryImmediate(.mov, Memory.sib(
3695 Memory.PtrSize.fromSize(abi_size),
3696 .{ .base = reg.to64() },
3697 ), immediate);
3698 },
3699 8 => {
3700 // TODO: optimization: if the imm is only using the lower
3701 // 4 bytes and can be sign extended we can use a normal mov
3702 // with indirect addressing (mov [reg64], imm32).
3703
3704 // movabs does not support indirect register addressing
3705 // so we need an extra register and an extra mov.
3706 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3707 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3708 },
3709 else => {
3710 return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size});
3711 },
3712 }
3669 .eflags => |cc| try self.asmSetccMemory(
3670 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3671 cc,
3672 ),
3673 .undef => if (self.wantSafety()) switch (abi_size) {
3674 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),
3675 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),
3676 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty),
3677 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty),
3678 else => try self.genInlineMemset(
3679 ptr,
3680 .{ .immediate = 0xaa },
3681 .{ .immediate = abi_size },
3682 .{},
3683 ),
37133684 },
3714 .register => |src_reg| {
3715 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);
3685 .immediate => |imm| switch (self.regBitSize(value_ty)) {
3686 8 => try self.asmMemoryImmediate(
3687 .mov,
3688 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3689 if (math.cast(i8, @bitCast(i64, imm))) |small|
3690 Immediate.s(small)
3691 else
3692 Immediate.u(@intCast(u8, imm)),
3693 ),
3694 16 => try self.asmMemoryImmediate(
3695 .mov,
3696 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3697 if (math.cast(i16, @bitCast(i64, imm))) |small|
3698 Immediate.s(small)
3699 else
3700 Immediate.u(@intCast(u16, imm)),
3701 ),
3702 32 => try self.asmMemoryImmediate(
3703 .mov,
3704 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3705 if (math.cast(i32, @bitCast(i64, imm))) |small|
3706 Immediate.s(small)
3707 else
3708 Immediate.u(@intCast(u32, imm)),
3709 ),
3710 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
3711 try self.asmMemoryImmediate(
3712 .mov,
3713 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3714 Immediate.s(small),
3715 )
3716 else
3717 try self.asmMemoryRegister(
3718 .mov,
3719 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3720 registerAlias(try self.copyToTmpRegister(value_ty, value), abi_size),
3721 ),
3722 else => unreachable,
37163723 },
3724 .register => |src_reg| try self.genInlineMemcpyRegisterRegister(
3725 value_ty,
3726 reg,
3727 src_reg,
3728 0,
3729 ),
37173730 .register_overflow => |ro| {
37183731 const ro_reg_lock = self.register_manager.lockReg(ro.reg);
37193732 defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -3732,23 +3745,18 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37323745 -@intCast(i32, overflow_bit_offset),
37333746 );
37343747 },
3735 .linker_load,
3736 .memory,
3737 .stack_offset,
3738 => {
3739 if (abi_size <= 8) {
3740 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3741 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3742 }
3743
3744 try self.genInlineMemcpy(.{ .stack_offset = 0 }, value, .{ .immediate = abi_size }, .{
3745 .source_stack_base = .rbp,
3746 .dest_stack_base = reg.to64(),
3747 });
3748 },
3748 .linker_load, .memory, .stack_offset => if (abi_size <= 8) {
3749 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3750 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3751 } else try self.genInlineMemcpy(
3752 .{ .stack_offset = 0 },
3753 value,
3754 .{ .immediate = abi_size },
3755 .{ .source_stack_base = .rbp, .dest_stack_base = reg.to64() },
3756 ),
37493757 .ptr_stack_offset => {
37503758 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3751 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3759 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
37523760 },
37533761 }
37543762 },
......@@ -3764,8 +3772,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37643772 defer self.register_manager.unlockReg(addr_reg_lock);
37653773
37663774 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);
3767
3768 // To get the actual address of the value we want to modify we have to go through the GOT
3775 // Load the pointer, which is stored in memory
37693776 try self.asmRegisterMemory(
37703777 .mov,
37713778 addr_reg.to64(),
......@@ -3773,62 +3780,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37733780 );
37743781
37753782 const new_ptr = MCValue{ .register = addr_reg.to64() };
3776
3777 switch (value) {
3778 .immediate => |imm| {
3779 if (abi_size > 8) {
3780 return self.fail("TODO saving imm to memory for abi_size {}", .{abi_size});
3781 }
3782
3783 if (abi_size == 8) {
3784 // TODO
3785 const top_bits: u32 = @intCast(u32, imm >> 32);
3786 const can_extend = if (value_ty.isUnsignedInt())
3787 (top_bits == 0) and (imm & 0x8000_0000) == 0
3788 else
3789 top_bits == 0xffff_ffff;
3790
3791 if (!can_extend) {
3792 return self.fail("TODO imm64 would get incorrectly sign extended", .{});
3793 }
3794 }
3795 try self.asmMemoryImmediate(
3796 .mov,
3797 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg.to64() }),
3798 Immediate.u(@intCast(u32, imm)),
3799 );
3800 },
3801 .register => {
3802 return self.store(new_ptr, value, ptr_ty, value_ty);
3803 },
3804 .linker_load, .memory => {
3805 if (abi_size <= 8) {
3806 const tmp_reg = try self.register_manager.allocReg(null, gp);
3807 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
3808 defer self.register_manager.unlockReg(tmp_reg_lock);
3809
3810 try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value);
3811 try self.asmRegisterMemory(
3812 .mov,
3813 tmp_reg,
3814 Memory.sib(.qword, .{ .base = tmp_reg }),
3815 );
3816
3817 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3818 }
3819
3820 try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{});
3821 },
3822 .stack_offset => {
3823 if (abi_size <= 8) {
3824 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3825 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3826 }
3827
3828 try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{});
3829 },
3830 else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}),
3831 }
3783 try self.store(new_ptr, value, ptr_ty, value_ty);
38323784 },
38333785 }
38343786}
......@@ -4886,41 +4838,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48864838 registerAlias(src_reg, abi_size),
48874839 ),
48884840 },
4889 .immediate => |imm| {
4890 switch (self.regBitSize(ty)) {
4891 8 => try self.asmRegisterImmediate(
4892 mir_tag,
4893 dst_alias,
4894 if (math.cast(i8, @bitCast(i64, imm))) |small|
4895 Immediate.s(small)
4896 else
4897 Immediate.u(@intCast(u8, imm)),
4898 ),
4899 16 => try self.asmRegisterImmediate(
4900 mir_tag,
4901 dst_alias,
4902 if (math.cast(i16, @bitCast(i64, imm))) |small|
4903 Immediate.s(small)
4904 else
4905 Immediate.u(@intCast(u16, imm)),
4906 ),
4907 32 => try self.asmRegisterImmediate(
4908 mir_tag,
4909 dst_alias,
4910 if (math.cast(i32, @bitCast(i64, imm))) |small|
4911 Immediate.s(small)
4912 else
4913 Immediate.u(@intCast(u32, imm)),
4914 ),
4915 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
4916 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
4841 .immediate => |imm| switch (self.regBitSize(ty)) {
4842 8 => try self.asmRegisterImmediate(
4843 mir_tag,
4844 dst_alias,
4845 if (math.cast(i8, @bitCast(i64, imm))) |small|
4846 Immediate.s(small)
49174847 else
4918 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
4919 try self.copyToTmpRegister(ty, src_mcv),
4920 abi_size,
4921 )),
4922 else => unreachable,
4923 }
4848 Immediate.u(@intCast(u8, imm)),
4849 ),
4850 16 => try self.asmRegisterImmediate(
4851 mir_tag,
4852 dst_alias,
4853 if (math.cast(i16, @bitCast(i64, imm))) |small|
4854 Immediate.s(small)
4855 else
4856 Immediate.u(@intCast(u16, imm)),
4857 ),
4858 32 => try self.asmRegisterImmediate(
4859 mir_tag,
4860 dst_alias,
4861 if (math.cast(i32, @bitCast(i64, imm))) |small|
4862 Immediate.s(small)
4863 else
4864 Immediate.u(@intCast(u32, imm)),
4865 ),
4866 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
4867 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
4868 else
4869 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
4870 try self.copyToTmpRegister(ty, src_mcv),
4871 abi_size,
4872 )),
4873 else => unreachable,
49244874 },
49254875 .memory, .linker_load, .eflags => {
49264876 assert(abi_size <= 8);
......@@ -4930,13 +4880,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
49304880 const reg = try self.copyToTmpRegister(ty, src_mcv);
49314881 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
49324882 },
4933 .stack_offset => |off| {
4934 try self.asmRegisterMemory(
4935 mir_tag,
4936 registerAlias(dst_reg, abi_size),
4937 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
4938 );
4939 },
4883 .stack_offset => |off| try self.asmRegisterMemory(
4884 mir_tag,
4885 registerAlias(dst_reg, abi_size),
4886 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
4887 ),
49404888 }
49414889 },
49424890 .memory, .linker_load, .stack_offset => {
......@@ -5654,7 +5602,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
56545602
56555603 const rhs_mcv = try self.resolveInst(bin_op.rhs);
56565604 const rhs_lock = switch (rhs_mcv) {
5657 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
5605 .register => |reg| self.register_manager.lockReg(reg),
56585606 else => null,
56595607 };
56605608 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -5702,9 +5650,62 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
57025650
57035651fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
57045652 const un_op = self.air.instructions.items(.data)[inst].un_op;
5705 const operand = try self.resolveInst(un_op);
5706 _ = operand;
5707 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch});
5653 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
5654 const addr_reg = try self.register_manager.allocReg(null, gp);
5655 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
5656 defer self.register_manager.unlockReg(addr_lock);
5657
5658 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
5659 const atom_index = try elf_file.getOrCreateAtomForLazySymbol(
5660 .{ .kind = .const_data, .ty = Type.anyerror },
5661 4, // dword alignment
5662 );
5663 const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file);
5664 try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
5665 .base = .ds,
5666 .disp = @intCast(i32, got_addr),
5667 }));
5668 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5669 const atom_index = try coff_file.getOrCreateAtomForLazySymbol(
5670 .{ .kind = .const_data, .ty = Type.anyerror },
5671 4, // dword alignment
5672 );
5673 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
5674 try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{
5675 .type = .got,
5676 .sym_index = sym_index,
5677 } });
5678 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
5679 const atom_index = try macho_file.getOrCreateAtomForLazySymbol(
5680 .{ .kind = .const_data, .ty = Type.anyerror },
5681 4, // dword alignment
5682 );
5683 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
5684 try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{
5685 .type = .got,
5686 .sym_index = sym_index,
5687 } });
5688 } else {
5689 return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)});
5690 }
5691
5692 try self.spillEflagsIfOccupied();
5693 self.eflags_inst = inst;
5694
5695 const op_ty = self.air.typeOf(un_op);
5696 const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*));
5697 const op_mcv = try self.resolveInst(un_op);
5698 const dst_reg = switch (op_mcv) {
5699 .register => |reg| reg,
5700 else => try self.copyToTmpRegister(op_ty, op_mcv),
5701 };
5702 try self.asmRegisterMemory(
5703 .cmp,
5704 registerAlias(dst_reg, op_abi_size),
5705 Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = addr_reg }),
5706 );
5707 break :result .{ .eflags = .b };
5708 };
57085709 return self.finishAir(inst, result, .{ un_op, .none, .none });
57095710}
57105711
......@@ -6184,7 +6185,28 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
61846185 const loop = self.air.extraData(Air.Block, ty_pl.payload);
61856186 const body = self.air.extra[loop.end..][0..loop.data.body_len];
61866187 const jmp_target = @intCast(u32, self.mir_instructions.len);
6187 try self.genBody(body);
6188
6189 {
6190 try self.branch_stack.append(.{});
6191 errdefer _ = self.branch_stack.pop();
6192
6193 try self.genBody(body);
6194 }
6195
6196 var branch = self.branch_stack.pop();
6197 defer branch.deinit(self.gpa);
6198
6199 log.debug("airLoop: %{d}", .{inst});
6200 log.debug("Upper branches:", .{});
6201 for (self.branch_stack.items) |bs| {
6202 log.debug("{}", .{bs.fmtDebug()});
6203 }
6204 log.debug("Loop branch: {}", .{branch.fmtDebug()});
6205
6206 var dummy_branch = Branch{};
6207 defer dummy_branch.deinit(self.gpa);
6208 try self.canonicaliseBranches(true, &dummy_branch, &branch, true, false);
6209
61886210 _ = try self.asmJmpReloc(jmp_target);
61896211 return self.finishAirBookkeeping();
61906212}
......@@ -6570,7 +6592,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
65706592 return self.fail("unrecognized constraint: '{s}'", .{constraint});
65716593 args.putAssumeCapacity(name, mcv);
65726594 switch (mcv) {
6573 .register => |reg| _ = self.register_manager.lockRegAssumeUnused(reg),
6595 .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_|
6596 self.register_manager.lockRegAssumeUnused(reg),
65746597 else => {},
65756598 }
65766599 if (output == .none) result = mcv;
......@@ -6609,70 +6632,139 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
66096632 }
66106633
66116634 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
6612 var line_it = mem.tokenize(u8, asm_source, "\n\r");
6635 var line_it = mem.tokenize(u8, asm_source, "\n\r;");
66136636 while (line_it.next()) |line| {
66146637 var mnem_it = mem.tokenize(u8, line, " \t");
6615 const mnem = mnem_it.next() orelse continue;
6616 if (mem.startsWith(u8, mnem, "#")) continue;
6617 var arg_it = mem.tokenize(u8, mnem_it.rest(), ", ");
6618 if (std.ascii.eqlIgnoreCase(mnem, "syscall")) {
6619 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6620 return self.fail("Too many operands: '{s}'", .{line});
6621 try self.asmOpOnly(.syscall);
6622 } else if (std.ascii.eqlIgnoreCase(mnem, "push")) {
6623 const src = arg_it.next() orelse
6624 return self.fail("Not enough operands: '{s}'", .{line});
6625 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6626 return self.fail("Too many operands: '{s}'", .{line});
6627 if (mem.startsWith(u8, src, "$")) {
6628 const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch
6629 return self.fail("Invalid immediate: '{s}'", .{src});
6630 try self.asmImmediate(.push, Immediate.u(imm));
6631 } else if (mem.startsWith(u8, src, "%%")) {
6632 const reg = parseRegName(src["%%".len..]) orelse
6633 return self.fail("Invalid register: '{s}'", .{src});
6634 try self.asmRegister(.push, reg);
6635 } else return self.fail("Unsupported operand: '{s}'", .{src});
6636 } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) {
6637 const dst = arg_it.next() orelse
6638 return self.fail("Not enough operands: '{s}'", .{line});
6639 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6640 return self.fail("Too many operands: '{s}'", .{line});
6641 if (mem.startsWith(u8, dst, "%%")) {
6642 const reg = parseRegName(dst["%%".len..]) orelse
6643 return self.fail("Invalid register: '{s}'", .{dst});
6644 try self.asmRegister(.pop, reg);
6645 } else return self.fail("Unsupported operand: '{s}'", .{dst});
6646 } else if (std.ascii.eqlIgnoreCase(mnem, "movq")) {
6647 const src = arg_it.next() orelse
6648 return self.fail("Not enough operands: '{s}'", .{line});
6649 const dst = arg_it.next() orelse
6650 return self.fail("Not enough operands: '{s}'", .{line});
6651 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6652 return self.fail("Too many operands: '{s}'", .{line});
6653 if (mem.startsWith(u8, src, "%%")) {
6654 const colon = mem.indexOfScalarPos(u8, src, "%%".len + 2, ':');
6655 const src_reg = parseRegName(src["%%".len .. colon orelse src.len]) orelse
6656 return self.fail("Invalid register: '{s}'", .{src});
6638 const mnem_str = mnem_it.next() orelse continue;
6639 if (mem.startsWith(u8, mnem_str, "#")) continue;
6640
6641 const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b"))
6642 .byte
6643 else if (mem.endsWith(u8, mnem_str, "w"))
6644 .word
6645 else if (mem.endsWith(u8, mnem_str, "l"))
6646 .dword
6647 else if (mem.endsWith(u8, mnem_str, "q"))
6648 .qword
6649 else
6650 null;
6651 const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
6652 (if (mnem_size) |_|
6653 std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])
6654 else
6655 null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
6656
6657 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
6658 var ops = [1]encoder.Instruction.Operand{.none} ** 4;
6659 for (&ops) |*op| {
6660 const op_str = mem.trim(u8, op_it.next() orelse break, " \t");
6661 if (mem.startsWith(u8, op_str, "#")) break;
6662 if (mem.startsWith(u8, op_str, "%%")) {
6663 const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');
6664 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse
6665 return self.fail("Invalid register: '{s}'", .{op_str});
66576666 if (colon) |colon_pos| {
6658 const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch
6659 return self.fail("Invalid immediate: '{s}'", .{src});
6660 if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) {
6661 switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse
6662 return self.fail("no matching constraint for: '{s}'", .{dst})) {
6663 .register => |dst_reg| try self.asmRegisterMemory(
6664 .mov,
6665 dst_reg,
6666 Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }),
6667 ),
6668 else => return self.fail("Invalid constraint: '{s}'", .{dst}),
6669 }
6670 } else return self.fail("Unsupported operand: '{s}'", .{dst});
6671 } else return self.fail("Unsupported operand: '{s}'", .{src});
6672 }
6673 } else {
6674 return self.fail("Unsupported instruction: '{s}'", .{mnem});
6675 }
6667 const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch
6668 return self.fail("Invalid displacement: '{s}'", .{op_str});
6669 op.* = .{ .mem = Memory.sib(
6670 mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}),
6671 .{ .base = reg, .disp = disp },
6672 ) };
6673 } else {
6674 if (mnem_size) |size| if (reg.bitSize() != size.bitSize())
6675 return self.fail("Invalid register size: '{s}'", .{op_str});
6676 op.* = .{ .reg = reg };
6677 }
6678 } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) {
6679 switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse
6680 return self.fail("No matching constraint: '{s}'", .{op_str})) {
6681 .register => |reg| op.* = .{ .reg = reg },
6682 else => return self.fail("Invalid constraint: '{s}'", .{op_str}),
6683 }
6684 } else if (mem.startsWith(u8, op_str, "$")) {
6685 if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| {
6686 if (mnem_size) |size| {
6687 const max = @as(u64, std.math.maxInt(u64)) >>
6688 @intCast(u6, 64 - (size.bitSize() - 1));
6689 if ((if (s < 0) ~s else s) > max)
6690 return self.fail("Invalid immediate size: '{s}'", .{op_str});
6691 }
6692 op.* = .{ .imm = Immediate.s(s) };
6693 } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| {
6694 if (mnem_size) |size| {
6695 const max = @as(u64, std.math.maxInt(u64)) >>
6696 @intCast(u6, 64 - size.bitSize());
6697 if (u > max)
6698 return self.fail("Invalid immediate size: '{s}'", .{op_str});
6699 }
6700 op.* = .{ .imm = Immediate.u(u) };
6701 } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str});
6702 } else return self.fail("Invalid operand: '{s}'", .{op_str});
6703 } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str});
6704
6705 (switch (ops[0]) {
6706 .none => self.asmOpOnly(mnem),
6707 .reg => |reg0| switch (ops[1]) {
6708 .none => self.asmRegister(mnem, reg0),
6709 .reg => |reg1| switch (ops[2]) {
6710 .none => self.asmRegisterRegister(mnem, reg1, reg0),
6711 .reg => |reg2| switch (ops[3]) {
6712 .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0),
6713 else => error.InvalidInstruction,
6714 },
6715 .mem => |mem2| switch (ops[3]) {
6716 .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0),
6717 else => error.InvalidInstruction,
6718 },
6719 else => error.InvalidInstruction,
6720 },
6721 .mem => |mem1| switch (ops[2]) {
6722 .none => self.asmMemoryRegister(mnem, mem1, reg0),
6723 else => error.InvalidInstruction,
6724 },
6725 else => error.InvalidInstruction,
6726 },
6727 .mem => |mem0| switch (ops[1]) {
6728 .none => self.asmMemory(mnem, mem0),
6729 .reg => |reg1| switch (ops[2]) {
6730 .none => self.asmRegisterMemory(mnem, reg1, mem0),
6731 else => error.InvalidInstruction,
6732 },
6733 else => error.InvalidInstruction,
6734 },
6735 .imm => |imm0| switch (ops[1]) {
6736 .none => self.asmImmediate(mnem, imm0),
6737 .reg => |reg1| switch (ops[2]) {
6738 .none => self.asmRegisterImmediate(mnem, reg1, imm0),
6739 .reg => |reg2| switch (ops[3]) {
6740 .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0),
6741 else => error.InvalidInstruction,
6742 },
6743 .mem => |mem2| switch (ops[3]) {
6744 .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0),
6745 else => error.InvalidInstruction,
6746 },
6747 else => error.InvalidInstruction,
6748 },
6749 .mem => |mem1| switch (ops[2]) {
6750 .none => self.asmMemoryImmediate(mnem, mem1, imm0),
6751 else => error.InvalidInstruction,
6752 },
6753 else => error.InvalidInstruction,
6754 },
6755 }) catch |err| switch (err) {
6756 error.InvalidInstruction => return self.fail(
6757 "Invalid instruction: '{s} {s} {s} {s} {s}'",
6758 .{
6759 @tagName(mnem),
6760 @tagName(ops[0]),
6761 @tagName(ops[1]),
6762 @tagName(ops[2]),
6763 @tagName(ops[3]),
6764 },
6765 ),
6766 else => |e| return e,
6767 };
66766768 }
66776769 }
66786770
......@@ -7988,12 +8080,12 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
79888080 try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{
79898081 .base = addr_reg.to64(),
79908082 .scale_index = .{ .scale = 4, .index = err_reg.to64() },
7991 .disp = 0,
8083 .disp = 4,
79928084 }));
79938085 try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{
79948086 .base = addr_reg.to64(),
79958087 .scale_index = .{ .scale = 4, .index = err_reg.to64() },
7996 .disp = 4,
8088 .disp = 8,
79978089 }));
79988090 try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32());
79998091 try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{
src/codegen.zig+7-3
......@@ -124,13 +124,17 @@ pub fn generateLazySymbol(
124124
125125 if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) {
126126 const err_names = mod.error_name_list.items;
127 try code.resize(err_names.len * 4);
128 for (err_names, 0..) |err_name, index| {
129 mem.writeInt(u32, code.items[index * 4 ..][0..4], @intCast(u32, code.items.len), endian);
127 mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian);
128 var offset = code.items.len;
129 try code.resize((1 + err_names.len + 1) * 4);
130 for (err_names) |err_name| {
131 mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian);
132 offset += 4;
130133 try code.ensureUnusedCapacity(err_name.len + 1);
131134 code.appendSliceAssumeCapacity(err_name);
132135 code.appendAssumeCapacity(0);
133136 }
137 mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian);
134138 return Result.ok;
135139 } else return .{ .fail = try ErrorMsg.create(
136140 bin_file.allocator,
src/link.zig+12-14
......@@ -1106,23 +1106,21 @@ pub const File = struct {
11061106 };
11071107
11081108 pub const LazySymbol = struct {
1109 kind: enum { code, const_data },
1110 ty: Type,
1109 pub const Kind = enum { code, const_data };
11111110
1112 pub const Context = struct {
1113 mod: *Module,
1111 kind: Kind,
1112 ty: Type,
11141113
1115 pub fn hash(ctx: @This(), sym: LazySymbol) u32 {
1116 var hasher = std.hash.Wyhash.init(0);
1117 std.hash.autoHash(&hasher, sym.kind);
1118 sym.ty.hashWithHasher(&hasher, ctx.mod);
1119 return @truncate(u32, hasher.final());
1120 }
1114 pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol {
1115 return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index|
1116 mod.declPtr(decl_index).val.castTag(.ty).?.data
1117 else
1118 Type.anyerror };
1119 }
11211120
1122 pub fn eql(ctx: @This(), lhs: LazySymbol, rhs: LazySymbol, _: usize) bool {
1123 return lhs.kind == rhs.kind and lhs.ty.eql(rhs.ty, ctx.mod);
1124 }
1125 };
1121 pub fn getDecl(self: LazySymbol) Module.Decl.OptionalIndex {
1122 return Module.Decl.OptionalIndex.init(self.ty.getOwnerDeclOrNull());
1123 }
11261124 };
11271125
11281126 pub const C = @import("link/C.zig");
src/link/Coff.zig+48-51
......@@ -145,16 +145,11 @@ const Section = struct {
145145 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
146146};
147147
148const LazySymbolTable = std.ArrayHashMapUnmanaged(
149 link.File.LazySymbol,
150 LazySymbolMetadata,
151 link.File.LazySymbol.Context,
152 true,
153);
148const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
154149
155150const LazySymbolMetadata = struct {
156 atom: Atom.Index,
157 section: u16,
151 text_atom: ?Atom.Index = null,
152 rdata_atom: ?Atom.Index = null,
158153 alignment: u32,
159154};
160155
......@@ -1176,10 +1171,28 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
11761171 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
11771172}
11781173
1179fn updateLazySymbol(
1174fn updateLazySymbol(self: *Coff, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void {
1175 const mod = self.base.options.module.?;
1176 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
1177 link.File.LazySymbol.initDecl(.code, decl, mod),
1178 atom,
1179 self.text_section_index.?,
1180 metadata.alignment,
1181 );
1182 if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom(
1183 link.File.LazySymbol.initDecl(.const_data, decl, mod),
1184 atom,
1185 self.rdata_section_index.?,
1186 metadata.alignment,
1187 );
1188}
1189
1190fn updateLazySymbolAtom(
11801191 self: *Coff,
1181 lazy_sym: link.File.LazySymbol,
1182 lazy_metadata: LazySymbolMetadata,
1192 sym: link.File.LazySymbol,
1193 atom_index: Atom.Index,
1194 section_index: u16,
1195 required_alignment: u32,
11831196) !void {
11841197 const gpa = self.base.allocator;
11851198 const mod = self.base.options.module.?;
......@@ -1188,16 +1201,15 @@ fn updateLazySymbol(
11881201 defer code_buffer.deinit();
11891202
11901203 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1191 @tagName(lazy_sym.kind),
1192 lazy_sym.ty.fmt(mod),
1204 @tagName(sym.kind),
1205 sym.ty.fmt(mod),
11931206 });
11941207 defer gpa.free(name);
11951208
1196 const atom_index = lazy_metadata.atom;
11971209 const atom = self.getAtomPtr(atom_index);
11981210 const local_sym_index = atom.getSymbolIndex().?;
11991211
1200 const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
1212 const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl|
12011213 mod.declPtr(owner_decl).srcLoc()
12021214 else
12031215 Module.SrcLoc{
......@@ -1205,14 +1217,9 @@ fn updateLazySymbol(
12051217 .parent_decl_node = undefined,
12061218 .lazy = .unneeded,
12071219 };
1208 const res = try codegen.generateLazySymbol(
1209 &self.base,
1210 src,
1211 lazy_sym,
1212 &code_buffer,
1213 .none,
1214 .{ .parent_atom_index = local_sym_index },
1215 );
1220 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
1221 .parent_atom_index = local_sym_index,
1222 });
12161223 const code = switch (res) {
12171224 .ok => code_buffer.items,
12181225 .fail => |em| {
......@@ -1221,11 +1228,10 @@ fn updateLazySymbol(
12211228 },
12221229 };
12231230
1224 const required_alignment = lazy_metadata.alignment;
12251231 const code_len = @intCast(u32, code.len);
12261232 const symbol = atom.getSymbolPtr(self);
12271233 try self.setSymbolName(symbol, name);
1228 symbol.section_number = @intToEnum(coff.SectionNumber, lazy_metadata.section + 1);
1234 symbol.section_number = @intToEnum(coff.SectionNumber, section_index + 1);
12291235 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
12301236
12311237 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
......@@ -1250,24 +1256,18 @@ fn updateLazySymbol(
12501256
12511257pub fn getOrCreateAtomForLazySymbol(
12521258 self: *Coff,
1253 lazy_sym: link.File.LazySymbol,
1259 sym: link.File.LazySymbol,
12541260 alignment: u32,
12551261) !Atom.Index {
1256 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
1257 .mod = self.base.options.module.?,
1258 });
1262 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
12591263 errdefer _ = self.lazy_syms.pop();
1260 if (!gop.found_existing) {
1261 gop.value_ptr.* = .{
1262 .atom = try self.createAtom(),
1263 .section = switch (lazy_sym.kind) {
1264 .code => self.text_section_index.?,
1265 .const_data => self.rdata_section_index.?,
1266 },
1267 .alignment = alignment,
1268 };
1269 }
1270 return gop.value_ptr.atom;
1264 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
1265 const atom = switch (sym.kind) {
1266 .code => &gop.value_ptr.text_atom,
1267 .const_data => &gop.value_ptr.rdata_atom,
1268 };
1269 if (atom.* == null) atom.* = try self.createAtom();
1270 return atom.*.?;
12711271}
12721272
12731273pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
......@@ -1600,17 +1600,13 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
16001600 sub_prog_node.activate();
16011601 defer sub_prog_node.end();
16021602
1603 {
1604 var lazy_it = self.lazy_syms.iterator();
1605 while (lazy_it.next()) |lazy_entry| {
1606 self.updateLazySymbol(
1607 lazy_entry.key_ptr.*,
1608 lazy_entry.value_ptr.*,
1609 ) catch |err| switch (err) {
1610 error.CodegenFail => return error.FlushFailure,
1611 else => |e| return e,
1612 };
1613 }
1603 // Most lazy symbols can be updated when the corresponding decl is,
1604 // so we only have to worry about the one without an associated decl.
1605 if (self.lazy_syms.get(.none)) |metadata| {
1606 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
1607 error.CodegenFail => return error.FlushFailure,
1608 else => |e| return e,
1609 };
16141610 }
16151611
16161612 const gpa = self.base.allocator;
......@@ -2489,6 +2485,7 @@ const Module = @import("../Module.zig");
24892485const Object = @import("Coff/Object.zig");
24902486const Relocation = @import("Coff/Relocation.zig");
24912487const StringTable = @import("strtab.zig").StringTable;
2488const Type = @import("../type.zig").Type;
24922489const TypedValue = @import("../TypedValue.zig");
24932490
24942491pub const base_tag: link.File.Tag = .coff;
src/link/Elf.zig+119-82
......@@ -64,8 +64,8 @@ const Section = struct {
6464};
6565
6666const LazySymbolMetadata = struct {
67 atom: Atom.Index,
68 shdr: u16,
67 text_atom: ?Atom.Index = null,
68 rodata_atom: ?Atom.Index = null,
6969 alignment: u32,
7070};
7171
......@@ -106,7 +106,12 @@ shdr_table_offset: ?u64 = null,
106106/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
107107/// Same order as in the file.
108108program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
109phdr_table_offset: ?u64 = null,
109/// The index into the program headers of the PT_PHDR program header
110phdr_table_index: ?u16 = null,
111/// The index into the program headers of the PT_LOAD program header containing the phdr
112/// Most linkers would merge this with phdr_load_ro_index,
113/// but incremental linking means we can't ensure they are consecutive.
114phdr_table_load_index: ?u16 = null,
110115/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
111116phdr_load_re_index: ?u16 = null,
112117/// The index into the program headers of the global offset table.
......@@ -203,7 +208,7 @@ relocs: RelocTable = .{},
203208
204209const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
205210const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
206const LazySymbolTable = std.ArrayHashMapUnmanaged(File.LazySymbol, LazySymbolMetadata, File.LazySymbol.Context, true);
211const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
207212
208213/// When allocating, the ideal_capacity is calculated by
209214/// actual_capacity + (actual_capacity / ideal_factor)
......@@ -396,16 +401,6 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
396401 }
397402 }
398403
399 if (self.phdr_table_offset) |off| {
400 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
401 const tight_size = self.sections.slice().len * phdr_size;
402 const increased_size = padToIdeal(tight_size);
403 const test_end = off + increased_size;
404 if (end > off and start < test_end) {
405 return test_end;
406 }
407 }
408
409404 for (self.sections.items(.shdr)) |section| {
410405 const increased_size = padToIdeal(section.sh_size);
411406 const test_end = section.sh_offset + increased_size;
......@@ -430,9 +425,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
430425 if (self.shdr_table_offset) |off| {
431426 if (off > start and off < min_pos) min_pos = off;
432427 }
433 if (self.phdr_table_offset) |off| {
434 if (off > start and off < min_pos) min_pos = off;
435 }
436428 for (self.sections.items(.shdr)) |section| {
437429 if (section.sh_offset <= start) continue;
438430 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
......@@ -462,6 +454,43 @@ pub fn populateMissingMetadata(self: *Elf) !void {
462454 };
463455 const ptr_size: u8 = self.ptrWidthBytes();
464456
457 if (self.phdr_table_index == null) {
458 self.phdr_table_index = @intCast(u16, self.program_headers.items.len);
459 const p_align: u16 = switch (self.ptr_width) {
460 .p32 => @alignOf(elf.Elf32_Phdr),
461 .p64 => @alignOf(elf.Elf64_Phdr),
462 };
463 try self.program_headers.append(gpa, .{
464 .p_type = elf.PT_PHDR,
465 .p_offset = 0,
466 .p_filesz = 0,
467 .p_vaddr = 0,
468 .p_paddr = 0,
469 .p_memsz = 0,
470 .p_align = p_align,
471 .p_flags = elf.PF_R,
472 });
473 self.phdr_table_dirty = true;
474 }
475
476 if (self.phdr_table_load_index == null) {
477 self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);
478 // TODO Same as for GOT
479 const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
480 const p_align = self.page_size;
481 try self.program_headers.append(gpa, .{
482 .p_type = elf.PT_LOAD,
483 .p_offset = 0,
484 .p_filesz = 0,
485 .p_vaddr = phdr_addr,
486 .p_paddr = phdr_addr,
487 .p_memsz = 0,
488 .p_align = p_align,
489 .p_flags = elf.PF_R,
490 });
491 self.phdr_table_dirty = true;
492 }
493
465494 if (self.phdr_load_re_index == null) {
466495 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
467496 const file_size = self.base.options.program_code_size_hint;
......@@ -849,19 +878,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
849878 self.shdr_table_dirty = true;
850879 }
851880
852 const phsize: u64 = switch (self.ptr_width) {
853 .p32 => @sizeOf(elf.Elf32_Phdr),
854 .p64 => @sizeOf(elf.Elf64_Phdr),
855 };
856 const phalign: u16 = switch (self.ptr_width) {
857 .p32 => @alignOf(elf.Elf32_Phdr),
858 .p64 => @alignOf(elf.Elf64_Phdr),
859 };
860 if (self.phdr_table_offset == null) {
861 self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign);
862 self.phdr_table_dirty = true;
863 }
864
865881 {
866882 // Iterate over symbols, populating free_list and last_text_block.
867883 if (self.local_symbols.items.len != 1) {
......@@ -1021,17 +1037,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10211037 sub_prog_node.activate();
10221038 defer sub_prog_node.end();
10231039
1024 {
1025 var lazy_it = self.lazy_syms.iterator();
1026 while (lazy_it.next()) |lazy_entry| {
1027 self.updateLazySymbol(
1028 lazy_entry.key_ptr.*,
1029 lazy_entry.value_ptr.*,
1030 ) catch |err| switch (err) {
1031 error.CodegenFail => return error.FlushFailure,
1032 else => |e| return e,
1033 };
1034 }
1040 // Most lazy symbols can be updated when the corresponding decl is,
1041 // so we only have to worry about the one without an associated decl.
1042 if (self.lazy_syms.get(.none)) |metadata| {
1043 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
1044 error.CodegenFail => return error.FlushFailure,
1045 else => |e| return e,
1046 };
10351047 }
10361048
10371049 // TODO This linker code currently assumes there is only 1 compilation unit and it
......@@ -1132,18 +1144,29 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11321144 .p32 => @sizeOf(elf.Elf32_Phdr),
11331145 .p64 => @sizeOf(elf.Elf64_Phdr),
11341146 };
1135 const phalign: u16 = switch (self.ptr_width) {
1136 .p32 => @alignOf(elf.Elf32_Phdr),
1137 .p64 => @alignOf(elf.Elf64_Phdr),
1138 };
1139 const allocated_size = self.allocatedSize(self.phdr_table_offset.?);
1147
1148 const phdr_table_index = self.phdr_table_index.?;
1149 const phdr_table = &self.program_headers.items[phdr_table_index];
1150 const phdr_table_load = &self.program_headers.items[self.phdr_table_load_index.?];
1151
1152 const allocated_size = self.allocatedSize(phdr_table.p_offset);
11401153 const needed_size = self.program_headers.items.len * phsize;
11411154
11421155 if (needed_size > allocated_size) {
1143 self.phdr_table_offset = null; // free the space
1144 self.phdr_table_offset = self.findFreeSpace(needed_size, phalign);
1156 phdr_table.p_offset = 0; // free the space
1157 phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align));
11451158 }
11461159
1160 phdr_table_load.p_offset = mem.alignBackwardGeneric(u64, phdr_table.p_offset, phdr_table_load.p_align);
1161 const load_align_offset = phdr_table.p_offset - phdr_table_load.p_offset;
1162 phdr_table_load.p_filesz = load_align_offset + needed_size;
1163 phdr_table_load.p_memsz = load_align_offset + needed_size;
1164
1165 phdr_table.p_filesz = needed_size;
1166 phdr_table.p_vaddr = phdr_table_load.p_vaddr + load_align_offset;
1167 phdr_table.p_paddr = phdr_table_load.p_paddr + load_align_offset;
1168 phdr_table.p_memsz = needed_size;
1169
11471170 switch (self.ptr_width) {
11481171 .p32 => {
11491172 const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
......@@ -1155,7 +1178,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11551178 mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
11561179 }
11571180 }
1158 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1181 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
11591182 },
11601183 .p64 => {
11611184 const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
......@@ -1167,9 +1190,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11671190 mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
11681191 }
11691192 }
1170 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1193 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
11711194 },
11721195 }
1196
1197 // We don't actually care if the phdr load section overlaps, only the phdr section matters.
1198 phdr_table_load.p_offset = 0;
1199 phdr_table_load.p_filesz = 0;
1200
11731201 self.phdr_table_dirty = false;
11741202 }
11751203
......@@ -1992,13 +2020,14 @@ fn writeElfHeader(self: *Elf) !void {
19922020
19932021 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
19942022
2023 const phdr_table_offset = self.program_headers.items[self.phdr_table_index.?].p_offset;
19952024 switch (self.ptr_width) {
19962025 .p32 => {
19972026 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
19982027 index += 4;
19992028
20002029 // e_phoff
2001 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.phdr_table_offset.?), endian);
2030 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, phdr_table_offset), endian);
20022031 index += 4;
20032032
20042033 // e_shoff
......@@ -2011,7 +2040,7 @@ fn writeElfHeader(self: *Elf) !void {
20112040 index += 8;
20122041
20132042 // e_phoff
2014 mem.writeInt(u64, hdr_buf[index..][0..8], self.phdr_table_offset.?, endian);
2043 mem.writeInt(u64, hdr_buf[index..][0..8], phdr_table_offset, endian);
20152044 index += 8;
20162045
20172046 // e_shoff
......@@ -2367,22 +2396,16 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
23672396 }
23682397}
23692398
2370pub fn getOrCreateAtomForLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, alignment: u32) !Atom.Index {
2371 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
2372 .mod = self.base.options.module.?,
2373 });
2399pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index {
2400 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
23742401 errdefer _ = self.lazy_syms.pop();
2375 if (!gop.found_existing) {
2376 gop.value_ptr.* = .{
2377 .atom = try self.createAtom(),
2378 .shdr = switch (lazy_sym.kind) {
2379 .code => self.text_section_index.?,
2380 .const_data => self.rodata_section_index.?,
2381 },
2382 .alignment = alignment,
2383 };
2384 }
2385 return gop.value_ptr.atom;
2402 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
2403 const atom = switch (sym.kind) {
2404 .code => &gop.value_ptr.text_atom,
2405 .const_data => &gop.value_ptr.rodata_atom,
2406 };
2407 if (atom.* == null) atom.* = try self.createAtom();
2408 return atom.*.?;
23862409}
23872410
23882411pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
......@@ -2651,7 +2674,29 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
26512674 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
26522675}
26532676
2654fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void {
2677fn updateLazySymbol(self: *Elf, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void {
2678 const mod = self.base.options.module.?;
2679 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
2680 File.LazySymbol.initDecl(.code, decl, mod),
2681 atom,
2682 self.text_section_index.?,
2683 metadata.alignment,
2684 );
2685 if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom(
2686 File.LazySymbol.initDecl(.const_data, decl, mod),
2687 atom,
2688 self.rodata_section_index.?,
2689 metadata.alignment,
2690 );
2691}
2692
2693fn updateLazySymbolAtom(
2694 self: *Elf,
2695 sym: File.LazySymbol,
2696 atom_index: Atom.Index,
2697 shdr_index: u16,
2698 required_alignment: u32,
2699) !void {
26552700 const gpa = self.base.allocator;
26562701 const mod = self.base.options.module.?;
26572702
......@@ -2660,19 +2705,18 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
26602705
26612706 const name_str_index = blk: {
26622707 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
2663 @tagName(lazy_sym.kind),
2664 lazy_sym.ty.fmt(mod),
2708 @tagName(sym.kind),
2709 sym.ty.fmt(mod),
26652710 });
26662711 defer gpa.free(name);
26672712 break :blk try self.shstrtab.insert(gpa, name);
26682713 };
26692714 const name = self.shstrtab.get(name_str_index).?;
26702715
2671 const atom_index = lazy_metadata.atom;
26722716 const atom = self.getAtom(atom_index);
26732717 const local_sym_index = atom.getSymbolIndex().?;
26742718
2675 const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
2719 const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl|
26762720 mod.declPtr(owner_decl).srcLoc()
26772721 else
26782722 Module.SrcLoc{
......@@ -2680,14 +2724,9 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
26802724 .parent_decl_node = undefined,
26812725 .lazy = .unneeded,
26822726 };
2683 const res = try codegen.generateLazySymbol(
2684 &self.base,
2685 src,
2686 lazy_sym,
2687 &code_buffer,
2688 .none,
2689 .{ .parent_atom_index = local_sym_index },
2690 );
2727 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
2728 .parent_atom_index = local_sym_index,
2729 });
26912730 const code = switch (res) {
26922731 .ok => code_buffer.items,
26932732 .fail => |em| {
......@@ -2696,7 +2735,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
26962735 },
26972736 };
26982737
2699 const shdr_index = lazy_metadata.shdr;
27002738 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
27012739 const local_sym = atom.getSymbolPtr(self);
27022740 local_sym.* = .{
......@@ -2707,7 +2745,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
27072745 .st_value = 0,
27082746 .st_size = 0,
27092747 };
2710 const required_alignment = lazy_metadata.alignment;
27112748 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
27122749 errdefer self.freeAtom(atom_index);
27132750 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
src/link/MachO.zig+49-53
......@@ -232,16 +232,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
232232 else => false,
233233};
234234
235const LazySymbolTable = std.ArrayHashMapUnmanaged(
236 link.File.LazySymbol,
237 LazySymbolMetadata,
238 link.File.LazySymbol.Context,
239 true,
240);
235const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
241236
242237const LazySymbolMetadata = struct {
243 atom: Atom.Index,
244 section: u8,
238 text_atom: ?Atom.Index = null,
239 data_const_atom: ?Atom.Index = null,
245240 alignment: u32,
246241};
247242
......@@ -513,17 +508,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
513508 sub_prog_node.activate();
514509 defer sub_prog_node.end();
515510
516 {
517 var lazy_it = self.lazy_syms.iterator();
518 while (lazy_it.next()) |lazy_entry| {
519 self.updateLazySymbol(
520 lazy_entry.key_ptr.*,
521 lazy_entry.value_ptr.*,
522 ) catch |err| switch (err) {
523 error.CodegenFail => return error.FlushFailure,
524 else => |e| return e,
525 };
526 }
511 // Most lazy symbols can be updated when the corresponding decl is,
512 // so we only have to worry about the one without an associated decl.
513 if (self.lazy_syms.get(.none)) |metadata| {
514 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
515 error.CodegenFail => return error.FlushFailure,
516 else => |e| return e,
517 };
527518 }
528519
529520 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
......@@ -2309,7 +2300,29 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
23092300 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
23102301}
23112302
2312fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void {
2303fn updateLazySymbol(self: *MachO, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void {
2304 const mod = self.base.options.module.?;
2305 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
2306 File.LazySymbol.initDecl(.code, decl, mod),
2307 atom,
2308 self.text_section_index.?,
2309 metadata.alignment,
2310 );
2311 if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom(
2312 File.LazySymbol.initDecl(.const_data, decl, mod),
2313 atom,
2314 self.data_const_section_index.?,
2315 metadata.alignment,
2316 );
2317}
2318
2319fn updateLazySymbolAtom(
2320 self: *MachO,
2321 sym: File.LazySymbol,
2322 atom_index: Atom.Index,
2323 section_index: u8,
2324 required_alignment: u32,
2325) !void {
23132326 const gpa = self.base.allocator;
23142327 const mod = self.base.options.module.?;
23152328
......@@ -2318,19 +2331,18 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
23182331
23192332 const name_str_index = blk: {
23202333 const name = try std.fmt.allocPrint(gpa, "___lazy_{s}_{}", .{
2321 @tagName(lazy_sym.kind),
2322 lazy_sym.ty.fmt(mod),
2334 @tagName(sym.kind),
2335 sym.ty.fmt(mod),
23232336 });
23242337 defer gpa.free(name);
23252338 break :blk try self.strtab.insert(gpa, name);
23262339 };
23272340 const name = self.strtab.get(name_str_index).?;
23282341
2329 const atom_index = lazy_metadata.atom;
23302342 const atom = self.getAtomPtr(atom_index);
23312343 const local_sym_index = atom.getSymbolIndex().?;
23322344
2333 const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
2345 const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl|
23342346 mod.declPtr(owner_decl).srcLoc()
23352347 else
23362348 Module.SrcLoc{
......@@ -2338,14 +2350,9 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
23382350 .parent_decl_node = undefined,
23392351 .lazy = .unneeded,
23402352 };
2341 const res = try codegen.generateLazySymbol(
2342 &self.base,
2343 src,
2344 lazy_sym,
2345 &code_buffer,
2346 .none,
2347 .{ .parent_atom_index = local_sym_index },
2348 );
2353 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
2354 .parent_atom_index = local_sym_index,
2355 });
23492356 const code = switch (res) {
23502357 .ok => code_buffer.items,
23512358 .fail => |em| {
......@@ -2354,11 +2361,10 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
23542361 },
23552362 };
23562363
2357 const required_alignment = lazy_metadata.alignment;
23582364 const symbol = atom.getSymbolPtr(self);
23592365 symbol.n_strx = name_str_index;
23602366 symbol.n_type = macho.N_SECT;
2361 symbol.n_sect = lazy_metadata.section + 1;
2367 symbol.n_sect = section_index + 1;
23622368 symbol.n_desc = 0;
23632369
23642370 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
......@@ -2381,26 +2387,16 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
23812387 try self.writeAtom(atom_index, code);
23822388}
23832389
2384pub fn getOrCreateAtomForLazySymbol(
2385 self: *MachO,
2386 lazy_sym: File.LazySymbol,
2387 alignment: u32,
2388) !Atom.Index {
2389 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
2390 .mod = self.base.options.module.?,
2391 });
2390pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index {
2391 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
23922392 errdefer _ = self.lazy_syms.pop();
2393 if (!gop.found_existing) {
2394 gop.value_ptr.* = .{
2395 .atom = try self.createAtom(),
2396 .section = switch (lazy_sym.kind) {
2397 .code => self.text_section_index.?,
2398 .const_data => self.data_const_section_index.?,
2399 },
2400 .alignment = alignment,
2401 };
2402 }
2403 return gop.value_ptr.atom;
2393 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
2394 const atom = switch (sym.kind) {
2395 .code => &gop.value_ptr.text_atom,
2396 .const_data => &gop.value_ptr.data_const_atom,
2397 };
2398 if (atom.* == null) atom.* = try self.createAtom();
2399 return atom.*.?;
24042400}
24052401
24062402pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {
src/print_air.zig+1
......@@ -804,6 +804,7 @@ const Writer = struct {
804804 var case_i: u32 = 0;
805805
806806 try w.writeOperand(s, inst, 0, pl_op.operand);
807 if (w.skip_body) return s.writeAll(", ...");
807808 const old_indent = w.indent;
808809 w.indent += 2;
809810
test/behavior/bugs/12776.zig-1
......@@ -31,7 +31,6 @@ const CPU = packed struct {
3131test {
3232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3635
3736 var ram = try RAM.new();
test/behavior/bugs/1442.zig-1
......@@ -9,7 +9,6 @@ const Union = union(enum) {
99test "const error union field alignment" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1413 var union_or_err: anyerror!Union = Union{ .Color = 1234 };
1514 try std.testing.expect((union_or_err catch unreachable).Color == 1234);
test/behavior/bugs/3007.zig-1
......@@ -21,7 +21,6 @@ fn get_foo() Foo.FooError!*Foo {
2121test "fixed" {
2222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625
2726 default_foo = get_foo() catch null; // This Line
test/behavior/cast.zig-1
......@@ -402,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" {
402402
403403test "explicit cast from integer to error type" {
404404 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
405 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
406405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407406 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
408407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/error.zig-4
......@@ -370,7 +370,6 @@ fn intLiteral(str: []const u8) !?i64 {
370370}
371371
372372test "nested error union function call in optional unwrap" {
373 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
374373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
375374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
376375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -499,7 +498,6 @@ test "function pointer with return type that is error union with payload which i
499498}
500499
501500test "return result loc as peer result loc in inferred error set function" {
502 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
503501 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
504502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
505503 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -531,7 +529,6 @@ test "return result loc as peer result loc in inferred error set function" {
531529}
532530
533531test "error payload type is correctly resolved" {
534 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
535532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
536533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
537534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -665,7 +662,6 @@ test "coerce error set to the current inferred error set" {
665662}
666663
667664test "error union payload is properly aligned" {
668 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
669665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
670666 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
671667 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/eval.zig-3
......@@ -967,7 +967,6 @@ test "closure capture type of runtime-known parameter" {
967967}
968968
969969test "comptime break passing through runtime condition converted to runtime break" {
970 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
971970 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
972971
973972 const S = struct {
......@@ -999,7 +998,6 @@ test "comptime break passing through runtime condition converted to runtime brea
999998}
1000999
10011000test "comptime break to outer loop passing through runtime condition converted to runtime break" {
1002 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10031001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10041002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10051003 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1218,7 +1216,6 @@ test "storing an array of type in a field" {
12181216}
12191217
12201218test "pass pointer to field of comptime-only type as a runtime parameter" {
1221 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12221219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12231220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12241221
test/behavior/inttoptr.zig-1
......@@ -11,7 +11,6 @@ fn addressToFunction() void {
1111}
1212
1313test "mutate through ptr initialized with constant intToPtr value" {
14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1716 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/struct.zig-3
......@@ -1116,7 +1116,6 @@ test "for loop over pointers to struct, getting field from struct pointer" {
11161116}
11171117
11181118test "anon init through error unions and optionals" {
1119 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11201119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11211120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11221121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1162,7 +1161,6 @@ test "anon init through optional" {
11621161}
11631162
11641163test "anon init through error union" {
1165 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11661164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11671165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11681166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1182,7 +1180,6 @@ test "anon init through error union" {
11821180}
11831181
11841182test "typed init through error unions and optionals" {
1185 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11861183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11871184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11881185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/switch_prong_err_enum.zig-1
......@@ -23,7 +23,6 @@ fn doThing(form_id: u64) anyerror!FormValue {
2323test "switch prong returns error enum" {
2424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2827
2928 switch (doThing(17) catch unreachable) {
test/behavior/switch_prong_implicit_cast.zig-1
......@@ -17,7 +17,6 @@ fn foo(id: u64) !FormValue {
1717test "switch prong implicit cast" {
1818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221
2322 const result = switch (foo(2) catch unreachable) {
test/cases/aarch64-macos/hello_world_with_updates.0.zig+1-1
......@@ -2,4 +2,4 @@
22// output_mode=Exe
33// target=aarch64-macos
44//
5// :110:9: error: root struct of file 'tmp' has no member named 'main'
5// :?:?: error: root struct of file 'tmp' has no member named 'main'
test/cases/x86_64-linux/hello_world_with_updates.0.zig+4-1
......@@ -2,4 +2,7 @@
22// output_mode=Exe
33// target=x86_64-linux
44//
5// :110:9: error: root struct of file 'tmp' has no member named 'main'
5// :?:?: error: root struct of file 'tmp' has no member named 'main'
6// :?:?: note: called from here
7// :?:?: note: called from here
8// :?:?: note: called from here
test/cases/x86_64-macos/hello_world_with_updates.0.zig+1-1
......@@ -2,4 +2,4 @@
22// output_mode=Exe
33// target=x86_64-macos
44//
5// :110:9: error: root struct of file 'tmp' has no member named 'main'
5// :?:?: error: root struct of file 'tmp' has no member named 'main'
test/cases/x86_64-windows/hello_world_with_updates.0.zig+3-1
......@@ -2,4 +2,6 @@
22// output_mode=Exe
33// target=x86_64-windows
44//
5// :131:9: error: root struct of file 'tmp' has no member named 'main'
5// :?:?: error: root struct of file 'tmp' has no member named 'main'
6// :?:?: note: called from here
7// :?:?: note: called from here
test/src/Cases.zig+6-4
......@@ -1045,8 +1045,7 @@ pub fn main() !void {
10451045 var ctx = Cases.init(gpa, arena);
10461046
10471047 var test_it = TestIterator{ .filenames = filenames.items };
1048 while (test_it.next()) |maybe_batch| {
1049 const batch = maybe_batch orelse break;
1048 while (try test_it.next()) |batch| {
10501049 const strategy: TestStrategy = if (batch.len > 1) .incremental else .independent;
10511050 var cases = std.ArrayList(usize).init(arena);
10521051
......@@ -1084,6 +1083,11 @@ pub fn main() !void {
10841083
10851084 for (cases.items) |case_index| {
10861085 const case = &ctx.cases.items[case_index];
1086 if (strategy == .incremental and case.backend == .stage2 and case.target.getCpuArch() == .x86_64 and !case.link_libc and case.target.getOsTag() != .plan9) {
1087 // https://github.com/ziglang/zig/issues/15174
1088 continue;
1089 }
1090
10871091 switch (manifest.type) {
10881092 .compile => {
10891093 case.addCompile(src);
......@@ -1115,8 +1119,6 @@ pub fn main() !void {
11151119 }
11161120 }
11171121 }
1118 } else |err| {
1119 return err;
11201122 }
11211123
11221124 return runCases(&ctx, zig_exe_path);