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: *...@@ -125,36 +125,44 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *
125125
126pub fn restore() callconv(.Naked) void {126pub fn restore() callconv(.Naked) void {
127 switch (@import("builtin").zig_backend) {127 switch (@import("builtin").zig_backend) {
128 .stage2_c => return asm volatile (128 .stage2_c => asm volatile (
129 \\ movl %[number], %%eax129 \\ movl %[number], %%eax
130 \\ int $0x80130 \\ int $0x80
131 \\ ret
131 :132 :
132 : [number] "i" (@enumToInt(SYS.sigreturn)),133 : [number] "i" (@enumToInt(SYS.sigreturn)),
133 : "memory"134 : "memory"
134 ),135 ),
135 else => return asm volatile ("int $0x80"136 else => asm volatile (
137 \\ int $0x80
138 \\ ret
136 :139 :
137 : [number] "{eax}" (@enumToInt(SYS.sigreturn)),140 : [number] "{eax}" (@enumToInt(SYS.sigreturn)),
138 : "memory"141 : "memory"
139 ),142 ),
140 }143 }
144 unreachable;
141}145}
142146
143pub fn restore_rt() callconv(.Naked) void {147pub fn restore_rt() callconv(.Naked) void {
144 switch (@import("builtin").zig_backend) {148 switch (@import("builtin").zig_backend) {
145 .stage2_c => return asm volatile (149 .stage2_c => asm volatile (
146 \\ movl %[number], %%eax150 \\ movl %[number], %%eax
147 \\ int $0x80151 \\ int $0x80
152 \\ ret
148 :153 :
149 : [number] "i" (@enumToInt(SYS.rt_sigreturn)),154 : [number] "i" (@enumToInt(SYS.rt_sigreturn)),
150 : "memory"155 : "memory"
151 ),156 ),
152 else => return asm volatile ("int $0x80"157 else => asm volatile (
158 \\ int $0x80
159 \\ ret
153 :160 :
154 : [number] "{eax}" (@enumToInt(SYS.rt_sigreturn)),161 : [number] "{eax}" (@enumToInt(SYS.rt_sigreturn)),
155 : "memory"162 : "memory"
156 ),163 ),
157 }164 }
165 unreachable;
158}166}
159167
160pub const O = struct {168pub const O = struct {
lib/std/os/linux/x86_64.zig+5-2
...@@ -109,7 +109,7 @@ pub const restore = restore_rt;...@@ -109,7 +109,7 @@ pub const restore = restore_rt;
109109
110pub fn restore_rt() callconv(.Naked) void {110pub fn restore_rt() callconv(.Naked) void {
111 switch (@import("builtin").zig_backend) {111 switch (@import("builtin").zig_backend) {
112 .stage2_c => return asm volatile (112 .stage2_c => asm volatile (
113 \\ movl %[number], %%eax113 \\ movl %[number], %%eax
114 \\ syscall114 \\ syscall
115 \\ retq115 \\ retq
...@@ -117,12 +117,15 @@ pub fn restore_rt() callconv(.Naked) void {...@@ -117,12 +117,15 @@ pub fn restore_rt() callconv(.Naked) void {
117 : [number] "i" (@enumToInt(SYS.rt_sigreturn)),117 : [number] "i" (@enumToInt(SYS.rt_sigreturn)),
118 : "rcx", "r11", "memory"118 : "rcx", "r11", "memory"
119 ),119 ),
120 else => return asm volatile ("syscall"120 else => asm volatile (
121 \\ syscall
122 \\ retq
121 :123 :
122 : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)),124 : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)),
123 : "rcx", "r11", "memory"125 : "rcx", "r11", "memory"
124 ),126 ),
125 }127 }
128 unreachable;
126}129}
127130
128pub const mode_t = usize;131pub 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";...@@ -19,7 +19,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
19// self-hosted is capable enough to handle all of the real start.zig logic.19// self-hosted is capable enough to handle all of the real start.zig logic.
20pub const simplified_logic =20pub const simplified_logic =
21 builtin.zig_backend == .stage2_wasm or21 builtin.zig_backend == .stage2_wasm or
22 builtin.zig_backend == .stage2_x86_64 or22 (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or
23 builtin.zig_backend == .stage2_x86 or23 builtin.zig_backend == .stage2_x86 or
24 builtin.zig_backend == .stage2_aarch64 or24 builtin.zig_backend == .stage2_aarch64 or
25 builtin.zig_backend == .stage2_arm or25 builtin.zig_backend == .stage2_arm or
src/Module.zig+1-1
...@@ -555,7 +555,7 @@ pub const Decl = struct {...@@ -555,7 +555,7 @@ pub const Decl = struct {
555 _,555 _,
556556
557 pub fn init(oi: ?Index) OptionalIndex {557 pub fn init(oi: ?Index) OptionalIndex {
558 return oi orelse .none;558 return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none));
559 }559 }
560560
561 pub fn unwrap(oi: OptionalIndex) ?Index {561 pub fn unwrap(oi: OptionalIndex) ?Index {
src/arch/x86_64/CodeGen.zig+326-234
...@@ -28,10 +28,11 @@ const Type = @import("../../type.zig").Type;...@@ -28,10 +28,11 @@ const Type = @import("../../type.zig").Type;
28const TypedValue = @import("../../TypedValue.zig");28const TypedValue = @import("../../TypedValue.zig");
29const Value = @import("../../value.zig").Value;29const Value = @import("../../value.zig").Value;
3030
31const bits = @import("bits.zig");
32const abi = @import("abi.zig");31const abi = @import("abi.zig");
33const errUnionPayloadOffset = codegen.errUnionPayloadOffset;32const bits = @import("bits.zig");
33const encoder = @import("encoder.zig");
34const errUnionErrorOffset = codegen.errUnionErrorOffset;34const errUnionErrorOffset = codegen.errUnionErrorOffset;
35const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
3536
36const Condition = bits.Condition;37const Condition = bits.Condition;
37const Immediate = bits.Immediate;38const Immediate = bits.Immediate;
...@@ -2527,7 +2528,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2527,7 +2528,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2527 const dst_lock = self.register_manager.lockReg(dst_reg);2528 const dst_lock = self.register_manager.lockReg(dst_reg);
2528 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);2529 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.*));
2531 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));2532 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
2532 try self.asmRegisterMemory(2533 try self.asmRegisterMemory(
2533 .lea,2534 .lea,
...@@ -3650,10 +3651,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3650,10 +3651,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3650 .dead => unreachable,3651 .dead => unreachable,
3651 .eflags => unreachable,3652 .eflags => unreachable,
3652 .register_overflow => unreachable,3653 .register_overflow => unreachable,
3653 .immediate => |imm| {3654 .immediate, .stack_offset => {
3654 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
3655 },
3656 .stack_offset => {
3657 const reg = try self.copyToTmpRegister(ptr_ty, ptr);3655 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
3658 try self.store(.{ .register = reg }, value, ptr_ty, value_ty);3656 try self.store(.{ .register = reg }, value, ptr_ty, value_ty);
3659 },3657 },
...@@ -3668,52 +3666,67 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3668,52 +3666,67 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3668 .none => unreachable,3666 .none => unreachable,
3669 .dead => unreachable,3667 .dead => unreachable,
3670 .unreach => unreachable,3668 .unreach => unreachable,
3671 .eflags => |cc| {3669 .eflags => |cc| try self.asmSetccMemory(
3672 try self.asmSetccMemory(Memory.sib(3670 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3673 Memory.PtrSize.fromSize(abi_size),3671 cc,
3674 .{ .base = reg.to64() },3672 ),
3675 ), cc);3673 .undef => if (self.wantSafety()) switch (abi_size) {
3676 },3674 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),
3677 .undef => {3675 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),
3678 if (!self.wantSafety()) return; // The already existing value will do just fine.3676 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty),
3679 switch (abi_size) {3677 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty),
3680 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),3678 else => try self.genInlineMemset(
3681 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),3679 ptr,
3682 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty),3680 .{ .immediate = 0xaa },
3683 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty),3681 .{ .immediate = abi_size },
3684 else => try self.genInlineMemset(ptr, .{ .immediate = 0xaa }, .{ .immediate = abi_size }, .{}),3682 .{},
3685 }3683 ),
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 }
3713 },3684 },
3714 .register => |src_reg| {3685 .immediate => |imm| switch (self.regBitSize(value_ty)) {
3715 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);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,
3716 },3723 },
3724 .register => |src_reg| try self.genInlineMemcpyRegisterRegister(
3725 value_ty,
3726 reg,
3727 src_reg,
3728 0,
3729 ),
3717 .register_overflow => |ro| {3730 .register_overflow => |ro| {
3718 const ro_reg_lock = self.register_manager.lockReg(ro.reg);3731 const ro_reg_lock = self.register_manager.lockReg(ro.reg);
3719 defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock);3732 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...@@ -3732,23 +3745,18 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3732 -@intCast(i32, overflow_bit_offset),3745 -@intCast(i32, overflow_bit_offset),
3733 );3746 );
3734 },3747 },
3735 .linker_load,3748 .linker_load, .memory, .stack_offset => if (abi_size <= 8) {
3736 .memory,3749 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3737 .stack_offset,3750 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3738 => {3751 } else try self.genInlineMemcpy(
3739 if (abi_size <= 8) {3752 .{ .stack_offset = 0 },
3740 const tmp_reg = try self.copyToTmpRegister(value_ty, value);3753 value,
3741 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);3754 .{ .immediate = abi_size },
3742 }3755 .{ .source_stack_base = .rbp, .dest_stack_base = reg.to64() },
37433756 ),
3744 try self.genInlineMemcpy(.{ .stack_offset = 0 }, value, .{ .immediate = abi_size }, .{
3745 .source_stack_base = .rbp,
3746 .dest_stack_base = reg.to64(),
3747 });
3748 },
3749 .ptr_stack_offset => {3757 .ptr_stack_offset => {
3750 const tmp_reg = try self.copyToTmpRegister(value_ty, value);3758 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);
3752 },3760 },
3753 }3761 }
3754 },3762 },
...@@ -3764,8 +3772,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3764,8 +3772,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3764 defer self.register_manager.unlockReg(addr_reg_lock);3772 defer self.register_manager.unlockReg(addr_reg_lock);
37653773
3766 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);3774 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);
37673775 // Load the pointer, which is stored in memory
3768 // To get the actual address of the value we want to modify we have to go through the GOT
3769 try self.asmRegisterMemory(3776 try self.asmRegisterMemory(
3770 .mov,3777 .mov,
3771 addr_reg.to64(),3778 addr_reg.to64(),
...@@ -3773,62 +3780,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3773,62 +3780,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3773 );3780 );
37743781
3775 const new_ptr = MCValue{ .register = addr_reg.to64() };3782 const new_ptr = MCValue{ .register = addr_reg.to64() };
37763783 try self.store(new_ptr, value, ptr_ty, value_ty);
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 }
3832 },3784 },
3833 }3785 }
3834}3786}
...@@ -4886,41 +4838,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -4886,41 +4838,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4886 registerAlias(src_reg, abi_size),4838 registerAlias(src_reg, abi_size),
4887 ),4839 ),
4888 },4840 },
4889 .immediate => |imm| {4841 .immediate => |imm| switch (self.regBitSize(ty)) {
4890 switch (self.regBitSize(ty)) {4842 8 => try self.asmRegisterImmediate(
4891 8 => try self.asmRegisterImmediate(4843 mir_tag,
4892 mir_tag,4844 dst_alias,
4893 dst_alias,4845 if (math.cast(i8, @bitCast(i64, imm))) |small|
4894 if (math.cast(i8, @bitCast(i64, imm))) |small|4846 Immediate.s(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))
4917 else4847 else
4918 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(4848 Immediate.u(@intCast(u8, imm)),
4919 try self.copyToTmpRegister(ty, src_mcv),4849 ),
4920 abi_size,4850 16 => try self.asmRegisterImmediate(
4921 )),4851 mir_tag,
4922 else => unreachable,4852 dst_alias,
4923 }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,
4924 },4874 },
4925 .memory, .linker_load, .eflags => {4875 .memory, .linker_load, .eflags => {
4926 assert(abi_size <= 8);4876 assert(abi_size <= 8);
...@@ -4930,13 +4880,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -4930,13 +4880,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4930 const reg = try self.copyToTmpRegister(ty, src_mcv);4880 const reg = try self.copyToTmpRegister(ty, src_mcv);
4931 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });4881 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
4932 },4882 },
4933 .stack_offset => |off| {4883 .stack_offset => |off| try self.asmRegisterMemory(
4934 try self.asmRegisterMemory(4884 mir_tag,
4935 mir_tag,4885 registerAlias(dst_reg, abi_size),
4936 registerAlias(dst_reg, abi_size),4886 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
4937 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),4887 ),
4938 );
4939 },
4940 }4888 }
4941 },4889 },
4942 .memory, .linker_load, .stack_offset => {4890 .memory, .linker_load, .stack_offset => {
...@@ -5654,7 +5602,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -5654,7 +5602,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
56545602
5655 const rhs_mcv = try self.resolveInst(bin_op.rhs);5603 const rhs_mcv = try self.resolveInst(bin_op.rhs);
5656 const rhs_lock = switch (rhs_mcv) {5604 const rhs_lock = switch (rhs_mcv) {
5657 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),5605 .register => |reg| self.register_manager.lockReg(reg),
5658 else => null,5606 else => null,
5659 };5607 };
5660 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);5608 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -5702,9 +5650,62 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {...@@ -5702,9 +5650,62 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
57025650
5703fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {5651fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
5704 const un_op = self.air.instructions.items(.data)[inst].un_op;5652 const un_op = self.air.instructions.items(.data)[inst].un_op;
5705 const operand = try self.resolveInst(un_op);5653 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
5706 _ = operand;5654 const addr_reg = try self.register_manager.allocReg(null, gp);
5707 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch});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 };
5708 return self.finishAir(inst, result, .{ un_op, .none, .none });5709 return self.finishAir(inst, result, .{ un_op, .none, .none });
5709}5710}
57105711
...@@ -6184,7 +6185,28 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -6184,7 +6185,28 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
6184 const loop = self.air.extraData(Air.Block, ty_pl.payload);6185 const loop = self.air.extraData(Air.Block, ty_pl.payload);
6185 const body = self.air.extra[loop.end..][0..loop.data.body_len];6186 const body = self.air.extra[loop.end..][0..loop.data.body_len];
6186 const jmp_target = @intCast(u32, self.mir_instructions.len);6187 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
6188 _ = try self.asmJmpReloc(jmp_target);6210 _ = try self.asmJmpReloc(jmp_target);
6189 return self.finishAirBookkeeping();6211 return self.finishAirBookkeeping();
6190}6212}
...@@ -6570,7 +6592,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6570,7 +6592,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6570 return self.fail("unrecognized constraint: '{s}'", .{constraint});6592 return self.fail("unrecognized constraint: '{s}'", .{constraint});
6571 args.putAssumeCapacity(name, mcv);6593 args.putAssumeCapacity(name, mcv);
6572 switch (mcv) {6594 switch (mcv) {
6573 .register => |reg| _ = self.register_manager.lockRegAssumeUnused(reg),6595 .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_|
6596 self.register_manager.lockRegAssumeUnused(reg),
6574 else => {},6597 else => {},
6575 }6598 }
6576 if (output == .none) result = mcv;6599 if (output == .none) result = mcv;
...@@ -6609,70 +6632,139 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6609,70 +6632,139 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6609 }6632 }
66106633
6611 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];6634 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;");
6613 while (line_it.next()) |line| {6636 while (line_it.next()) |line| {
6614 var mnem_it = mem.tokenize(u8, line, " \t");6637 var mnem_it = mem.tokenize(u8, line, " \t");
6615 const mnem = mnem_it.next() orelse continue;6638 const mnem_str = mnem_it.next() orelse continue;
6616 if (mem.startsWith(u8, mnem, "#")) continue;6639 if (mem.startsWith(u8, mnem_str, "#")) continue;
6617 var arg_it = mem.tokenize(u8, mnem_it.rest(), ", ");6640
6618 if (std.ascii.eqlIgnoreCase(mnem, "syscall")) {6641 const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b"))
6619 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))6642 .byte
6620 return self.fail("Too many operands: '{s}'", .{line});6643 else if (mem.endsWith(u8, mnem_str, "w"))
6621 try self.asmOpOnly(.syscall);6644 .word
6622 } else if (std.ascii.eqlIgnoreCase(mnem, "push")) {6645 else if (mem.endsWith(u8, mnem_str, "l"))
6623 const src = arg_it.next() orelse6646 .dword
6624 return self.fail("Not enough operands: '{s}'", .{line});6647 else if (mem.endsWith(u8, mnem_str, "q"))
6625 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))6648 .qword
6626 return self.fail("Too many operands: '{s}'", .{line});6649 else
6627 if (mem.startsWith(u8, src, "$")) {6650 null;
6628 const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch6651 const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
6629 return self.fail("Invalid immediate: '{s}'", .{src});6652 (if (mnem_size) |_|
6630 try self.asmImmediate(.push, Immediate.u(imm));6653 std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])
6631 } else if (mem.startsWith(u8, src, "%%")) {6654 else
6632 const reg = parseRegName(src["%%".len..]) orelse6655 null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
6633 return self.fail("Invalid register: '{s}'", .{src});6656
6634 try self.asmRegister(.push, reg);6657 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
6635 } else return self.fail("Unsupported operand: '{s}'", .{src});6658 var ops = [1]encoder.Instruction.Operand{.none} ** 4;
6636 } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) {6659 for (&ops) |*op| {
6637 const dst = arg_it.next() orelse6660 const op_str = mem.trim(u8, op_it.next() orelse break, " \t");
6638 return self.fail("Not enough operands: '{s}'", .{line});6661 if (mem.startsWith(u8, op_str, "#")) break;
6639 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))6662 if (mem.startsWith(u8, op_str, "%%")) {
6640 return self.fail("Too many operands: '{s}'", .{line});6663 const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');
6641 if (mem.startsWith(u8, dst, "%%")) {6664 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse
6642 const reg = parseRegName(dst["%%".len..]) orelse6665 return self.fail("Invalid register: '{s}'", .{op_str});
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});
6657 if (colon) |colon_pos| {6666 if (colon) |colon_pos| {
6658 const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch6667 const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch
6659 return self.fail("Invalid immediate: '{s}'", .{src});6668 return self.fail("Invalid displacement: '{s}'", .{op_str});
6660 if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) {6669 op.* = .{ .mem = Memory.sib(
6661 switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse6670 mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}),
6662 return self.fail("no matching constraint for: '{s}'", .{dst})) {6671 .{ .base = reg, .disp = disp },
6663 .register => |dst_reg| try self.asmRegisterMemory(6672 ) };
6664 .mov,6673 } else {
6665 dst_reg,6674 if (mnem_size) |size| if (reg.bitSize() != size.bitSize())
6666 Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }),6675 return self.fail("Invalid register size: '{s}'", .{op_str});
6667 ),6676 op.* = .{ .reg = reg };
6668 else => return self.fail("Invalid constraint: '{s}'", .{dst}),6677 }
6669 }6678 } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) {
6670 } else return self.fail("Unsupported operand: '{s}'", .{dst});6679 switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse
6671 } else return self.fail("Unsupported operand: '{s}'", .{src});6680 return self.fail("No matching constraint: '{s}'", .{op_str})) {
6672 }6681 .register => |reg| op.* = .{ .reg = reg },
6673 } else {6682 else => return self.fail("Invalid constraint: '{s}'", .{op_str}),
6674 return self.fail("Unsupported instruction: '{s}'", .{mnem});6683 }
6675 }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 };
6676 }6768 }
6677 }6769 }
66786770
...@@ -7988,12 +8080,12 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -7988,12 +8080,12 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
7988 try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{8080 try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{
7989 .base = addr_reg.to64(),8081 .base = addr_reg.to64(),
7990 .scale_index = .{ .scale = 4, .index = err_reg.to64() },8082 .scale_index = .{ .scale = 4, .index = err_reg.to64() },
7991 .disp = 0,8083 .disp = 4,
7992 }));8084 }));
7993 try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{8085 try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{
7994 .base = addr_reg.to64(),8086 .base = addr_reg.to64(),
7995 .scale_index = .{ .scale = 4, .index = err_reg.to64() },8087 .scale_index = .{ .scale = 4, .index = err_reg.to64() },
7996 .disp = 4,8088 .disp = 8,
7997 }));8089 }));
7998 try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32());8090 try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32());
7999 try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{8091 try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{
src/codegen.zig+7-3
...@@ -124,13 +124,17 @@ pub fn generateLazySymbol(...@@ -124,13 +124,17 @@ pub fn generateLazySymbol(
124124
125 if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) {125 if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) {
126 const err_names = mod.error_name_list.items;126 const err_names = mod.error_name_list.items;
127 try code.resize(err_names.len * 4);127 mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian);
128 for (err_names, 0..) |err_name, index| {128 var offset = code.items.len;
129 mem.writeInt(u32, code.items[index * 4 ..][0..4], @intCast(u32, code.items.len), endian);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;
130 try code.ensureUnusedCapacity(err_name.len + 1);133 try code.ensureUnusedCapacity(err_name.len + 1);
131 code.appendSliceAssumeCapacity(err_name);134 code.appendSliceAssumeCapacity(err_name);
132 code.appendAssumeCapacity(0);135 code.appendAssumeCapacity(0);
133 }136 }
137 mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian);
134 return Result.ok;138 return Result.ok;
135 } else return .{ .fail = try ErrorMsg.create(139 } else return .{ .fail = try ErrorMsg.create(
136 bin_file.allocator,140 bin_file.allocator,
src/link.zig+12-14
...@@ -1106,23 +1106,21 @@ pub const File = struct {...@@ -1106,23 +1106,21 @@ pub const File = struct {
1106 };1106 };
11071107
1108 pub const LazySymbol = struct {1108 pub const LazySymbol = struct {
1109 kind: enum { code, const_data },1109 pub const Kind = enum { code, const_data };
1110 ty: Type,
11111110
1112 pub const Context = struct {1111 kind: Kind,
1113 mod: *Module,1112 ty: Type,
11141113
1115 pub fn hash(ctx: @This(), sym: LazySymbol) u32 {1114 pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol {
1116 var hasher = std.hash.Wyhash.init(0);1115 return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index|
1117 std.hash.autoHash(&hasher, sym.kind);1116 mod.declPtr(decl_index).val.castTag(.ty).?.data
1118 sym.ty.hashWithHasher(&hasher, ctx.mod);1117 else
1119 return @truncate(u32, hasher.final());1118 Type.anyerror };
1120 }1119 }
11211120
1122 pub fn eql(ctx: @This(), lhs: LazySymbol, rhs: LazySymbol, _: usize) bool {1121 pub fn getDecl(self: LazySymbol) Module.Decl.OptionalIndex {
1123 return lhs.kind == rhs.kind and lhs.ty.eql(rhs.ty, ctx.mod);1122 return Module.Decl.OptionalIndex.init(self.ty.getOwnerDeclOrNull());
1124 }1123 }
1125 };
1126 };1124 };
11271125
1128 pub const C = @import("link/C.zig");1126 pub const C = @import("link/C.zig");
src/link/Coff.zig+48-51
...@@ -145,16 +145,11 @@ const Section = struct {...@@ -145,16 +145,11 @@ const Section = struct {
145 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},145 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
146};146};
147147
148const LazySymbolTable = std.ArrayHashMapUnmanaged(148const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
149 link.File.LazySymbol,
150 LazySymbolMetadata,
151 link.File.LazySymbol.Context,
152 true,
153);
154149
155const LazySymbolMetadata = struct {150const LazySymbolMetadata = struct {
156 atom: Atom.Index,151 text_atom: ?Atom.Index = null,
157 section: u16,152 rdata_atom: ?Atom.Index = null,
158 alignment: u32,153 alignment: u32,
159};154};
160155
...@@ -1176,10 +1171,28 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1176,10 +1171,28 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1176 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));1171 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1177}1172}
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(
1180 self: *Coff,1191 self: *Coff,
1181 lazy_sym: link.File.LazySymbol,1192 sym: link.File.LazySymbol,
1182 lazy_metadata: LazySymbolMetadata,1193 atom_index: Atom.Index,
1194 section_index: u16,
1195 required_alignment: u32,
1183) !void {1196) !void {
1184 const gpa = self.base.allocator;1197 const gpa = self.base.allocator;
1185 const mod = self.base.options.module.?;1198 const mod = self.base.options.module.?;
...@@ -1188,16 +1201,15 @@ fn updateLazySymbol(...@@ -1188,16 +1201,15 @@ fn updateLazySymbol(
1188 defer code_buffer.deinit();1201 defer code_buffer.deinit();
11891202
1190 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{1203 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1191 @tagName(lazy_sym.kind),1204 @tagName(sym.kind),
1192 lazy_sym.ty.fmt(mod),1205 sym.ty.fmt(mod),
1193 });1206 });
1194 defer gpa.free(name);1207 defer gpa.free(name);
11951208
1196 const atom_index = lazy_metadata.atom;
1197 const atom = self.getAtomPtr(atom_index);1209 const atom = self.getAtomPtr(atom_index);
1198 const local_sym_index = atom.getSymbolIndex().?;1210 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|
1201 mod.declPtr(owner_decl).srcLoc()1213 mod.declPtr(owner_decl).srcLoc()
1202 else1214 else
1203 Module.SrcLoc{1215 Module.SrcLoc{
...@@ -1205,14 +1217,9 @@ fn updateLazySymbol(...@@ -1205,14 +1217,9 @@ fn updateLazySymbol(
1205 .parent_decl_node = undefined,1217 .parent_decl_node = undefined,
1206 .lazy = .unneeded,1218 .lazy = .unneeded,
1207 };1219 };
1208 const res = try codegen.generateLazySymbol(1220 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
1209 &self.base,1221 .parent_atom_index = local_sym_index,
1210 src,1222 });
1211 lazy_sym,
1212 &code_buffer,
1213 .none,
1214 .{ .parent_atom_index = local_sym_index },
1215 );
1216 const code = switch (res) {1223 const code = switch (res) {
1217 .ok => code_buffer.items,1224 .ok => code_buffer.items,
1218 .fail => |em| {1225 .fail => |em| {
...@@ -1221,11 +1228,10 @@ fn updateLazySymbol(...@@ -1221,11 +1228,10 @@ fn updateLazySymbol(
1221 },1228 },
1222 };1229 };
12231230
1224 const required_alignment = lazy_metadata.alignment;
1225 const code_len = @intCast(u32, code.len);1231 const code_len = @intCast(u32, code.len);
1226 const symbol = atom.getSymbolPtr(self);1232 const symbol = atom.getSymbolPtr(self);
1227 try self.setSymbolName(symbol, name);1233 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);
1229 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };1235 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
12301236
1231 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);1237 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
...@@ -1250,24 +1256,18 @@ fn updateLazySymbol(...@@ -1250,24 +1256,18 @@ fn updateLazySymbol(
12501256
1251pub fn getOrCreateAtomForLazySymbol(1257pub fn getOrCreateAtomForLazySymbol(
1252 self: *Coff,1258 self: *Coff,
1253 lazy_sym: link.File.LazySymbol,1259 sym: link.File.LazySymbol,
1254 alignment: u32,1260 alignment: u32,
1255) !Atom.Index {1261) !Atom.Index {
1256 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{1262 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
1257 .mod = self.base.options.module.?,
1258 });
1259 errdefer _ = self.lazy_syms.pop();1263 errdefer _ = self.lazy_syms.pop();
1260 if (!gop.found_existing) {1264 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
1261 gop.value_ptr.* = .{1265 const atom = switch (sym.kind) {
1262 .atom = try self.createAtom(),1266 .code => &gop.value_ptr.text_atom,
1263 .section = switch (lazy_sym.kind) {1267 .const_data => &gop.value_ptr.rdata_atom,
1264 .code => self.text_section_index.?,1268 };
1265 .const_data => self.rdata_section_index.?,1269 if (atom.* == null) atom.* = try self.createAtom();
1266 },1270 return atom.*.?;
1267 .alignment = alignment,
1268 };
1269 }
1270 return gop.value_ptr.atom;
1271}1271}
12721272
1273pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {1273pub 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...@@ -1600,17 +1600,13 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1600 sub_prog_node.activate();1600 sub_prog_node.activate();
1601 defer sub_prog_node.end();1601 defer sub_prog_node.end();
16021602
1603 {1603 // Most lazy symbols can be updated when the corresponding decl is,
1604 var lazy_it = self.lazy_syms.iterator();1604 // so we only have to worry about the one without an associated decl.
1605 while (lazy_it.next()) |lazy_entry| {1605 if (self.lazy_syms.get(.none)) |metadata| {
1606 self.updateLazySymbol(1606 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
1607 lazy_entry.key_ptr.*,1607 error.CodegenFail => return error.FlushFailure,
1608 lazy_entry.value_ptr.*,1608 else => |e| return e,
1609 ) catch |err| switch (err) {1609 };
1610 error.CodegenFail => return error.FlushFailure,
1611 else => |e| return e,
1612 };
1613 }
1614 }1610 }
16151611
1616 const gpa = self.base.allocator;1612 const gpa = self.base.allocator;
...@@ -2489,6 +2485,7 @@ const Module = @import("../Module.zig");...@@ -2489,6 +2485,7 @@ const Module = @import("../Module.zig");
2489const Object = @import("Coff/Object.zig");2485const Object = @import("Coff/Object.zig");
2490const Relocation = @import("Coff/Relocation.zig");2486const Relocation = @import("Coff/Relocation.zig");
2491const StringTable = @import("strtab.zig").StringTable;2487const StringTable = @import("strtab.zig").StringTable;
2488const Type = @import("../type.zig").Type;
2492const TypedValue = @import("../TypedValue.zig");2489const TypedValue = @import("../TypedValue.zig");
24932490
2494pub const base_tag: link.File.Tag = .coff;2491pub const base_tag: link.File.Tag = .coff;
src/link/Elf.zig+119-82
...@@ -64,8 +64,8 @@ const Section = struct {...@@ -64,8 +64,8 @@ const Section = struct {
64};64};
6565
66const LazySymbolMetadata = struct {66const LazySymbolMetadata = struct {
67 atom: Atom.Index,67 text_atom: ?Atom.Index = null,
68 shdr: u16,68 rodata_atom: ?Atom.Index = null,
69 alignment: u32,69 alignment: u32,
70};70};
7171
...@@ -106,7 +106,12 @@ shdr_table_offset: ?u64 = null,...@@ -106,7 +106,12 @@ shdr_table_offset: ?u64 = null,
106/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.106/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
107/// Same order as in the file.107/// Same order as in the file.
108program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},108program_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,
110/// The index into the program headers of a PT_LOAD program header with Read and Execute flags115/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
111phdr_load_re_index: ?u16 = null,116phdr_load_re_index: ?u16 = null,
112/// The index into the program headers of the global offset table.117/// The index into the program headers of the global offset table.
...@@ -203,7 +208,7 @@ relocs: RelocTable = .{},...@@ -203,7 +208,7 @@ relocs: RelocTable = .{},
203208
204const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));209const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
205const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));210const 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
208/// When allocating, the ideal_capacity is calculated by213/// When allocating, the ideal_capacity is calculated by
209/// actual_capacity + (actual_capacity / ideal_factor)214/// actual_capacity + (actual_capacity / ideal_factor)
...@@ -396,16 +401,6 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -396,16 +401,6 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
396 }401 }
397 }402 }
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
409 for (self.sections.items(.shdr)) |section| {404 for (self.sections.items(.shdr)) |section| {
410 const increased_size = padToIdeal(section.sh_size);405 const increased_size = padToIdeal(section.sh_size);
411 const test_end = section.sh_offset + increased_size;406 const test_end = section.sh_offset + increased_size;
...@@ -430,9 +425,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {...@@ -430,9 +425,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
430 if (self.shdr_table_offset) |off| {425 if (self.shdr_table_offset) |off| {
431 if (off > start and off < min_pos) min_pos = off;426 if (off > start and off < min_pos) min_pos = off;
432 }427 }
433 if (self.phdr_table_offset) |off| {
434 if (off > start and off < min_pos) min_pos = off;
435 }
436 for (self.sections.items(.shdr)) |section| {428 for (self.sections.items(.shdr)) |section| {
437 if (section.sh_offset <= start) continue;429 if (section.sh_offset <= start) continue;
438 if (section.sh_offset < min_pos) min_pos = section.sh_offset;430 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
...@@ -462,6 +454,43 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -462,6 +454,43 @@ pub fn populateMissingMetadata(self: *Elf) !void {
462 };454 };
463 const ptr_size: u8 = self.ptrWidthBytes();455 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
465 if (self.phdr_load_re_index == null) {494 if (self.phdr_load_re_index == null) {
466 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);495 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
467 const file_size = self.base.options.program_code_size_hint;496 const file_size = self.base.options.program_code_size_hint;
...@@ -849,19 +878,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -849,19 +878,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
849 self.shdr_table_dirty = true;878 self.shdr_table_dirty = true;
850 }879 }
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
865 {881 {
866 // Iterate over symbols, populating free_list and last_text_block.882 // Iterate over symbols, populating free_list and last_text_block.
867 if (self.local_symbols.items.len != 1) {883 if (self.local_symbols.items.len != 1) {
...@@ -1021,17 +1037,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1021,17 +1037,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1021 sub_prog_node.activate();1037 sub_prog_node.activate();
1022 defer sub_prog_node.end();1038 defer sub_prog_node.end();
10231039
1024 {1040 // Most lazy symbols can be updated when the corresponding decl is,
1025 var lazy_it = self.lazy_syms.iterator();1041 // so we only have to worry about the one without an associated decl.
1026 while (lazy_it.next()) |lazy_entry| {1042 if (self.lazy_syms.get(.none)) |metadata| {
1027 self.updateLazySymbol(1043 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
1028 lazy_entry.key_ptr.*,1044 error.CodegenFail => return error.FlushFailure,
1029 lazy_entry.value_ptr.*,1045 else => |e| return e,
1030 ) catch |err| switch (err) {1046 };
1031 error.CodegenFail => return error.FlushFailure,
1032 else => |e| return e,
1033 };
1034 }
1035 }1047 }
10361048
1037 // TODO This linker code currently assumes there is only 1 compilation unit and it1049 // 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...@@ -1132,18 +1144,29 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1132 .p32 => @sizeOf(elf.Elf32_Phdr),1144 .p32 => @sizeOf(elf.Elf32_Phdr),
1133 .p64 => @sizeOf(elf.Elf64_Phdr),1145 .p64 => @sizeOf(elf.Elf64_Phdr),
1134 };1146 };
1135 const phalign: u16 = switch (self.ptr_width) {1147
1136 .p32 => @alignOf(elf.Elf32_Phdr),1148 const phdr_table_index = self.phdr_table_index.?;
1137 .p64 => @alignOf(elf.Elf64_Phdr),1149 const phdr_table = &self.program_headers.items[phdr_table_index];
1138 };1150 const phdr_table_load = &self.program_headers.items[self.phdr_table_load_index.?];
1139 const allocated_size = self.allocatedSize(self.phdr_table_offset.?);1151
1152 const allocated_size = self.allocatedSize(phdr_table.p_offset);
1140 const needed_size = self.program_headers.items.len * phsize;1153 const needed_size = self.program_headers.items.len * phsize;
11411154
1142 if (needed_size > allocated_size) {1155 if (needed_size > allocated_size) {
1143 self.phdr_table_offset = null; // free the space1156 phdr_table.p_offset = 0; // free the space
1144 self.phdr_table_offset = self.findFreeSpace(needed_size, phalign);1157 phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align));
1145 }1158 }
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
1147 switch (self.ptr_width) {1170 switch (self.ptr_width) {
1148 .p32 => {1171 .p32 => {
1149 const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);1172 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...@@ -1155,7 +1178,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1155 mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);1178 mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
1156 }1179 }
1157 }1180 }
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);
1159 },1182 },
1160 .p64 => {1183 .p64 => {
1161 const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);1184 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...@@ -1167,9 +1190,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1167 mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);1190 mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
1168 }1191 }
1169 }1192 }
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);
1171 },1194 },
1172 }1195 }
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
1173 self.phdr_table_dirty = false;1201 self.phdr_table_dirty = false;
1174 }1202 }
11751203
...@@ -1992,13 +2020,14 @@ fn writeElfHeader(self: *Elf) !void {...@@ -1992,13 +2020,14 @@ fn writeElfHeader(self: *Elf) !void {
19922020
1993 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;2021 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;
1995 switch (self.ptr_width) {2024 switch (self.ptr_width) {
1996 .p32 => {2025 .p32 => {
1997 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);2026 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
1998 index += 4;2027 index += 4;
19992028
2000 // e_phoff2029 // 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);
2002 index += 4;2031 index += 4;
20032032
2004 // e_shoff2033 // e_shoff
...@@ -2011,7 +2040,7 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2011,7 +2040,7 @@ fn writeElfHeader(self: *Elf) !void {
2011 index += 8;2040 index += 8;
20122041
2013 // e_phoff2042 // 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);
2015 index += 8;2044 index += 8;
20162045
2017 // e_shoff2046 // e_shoff
...@@ -2367,22 +2396,16 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2367,22 +2396,16 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2367 }2396 }
2368}2397}
23692398
2370pub fn getOrCreateAtomForLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, alignment: u32) !Atom.Index {2399pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index {
2371 const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{2400 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2372 .mod = self.base.options.module.?,
2373 });
2374 errdefer _ = self.lazy_syms.pop();2401 errdefer _ = self.lazy_syms.pop();
2375 if (!gop.found_existing) {2402 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
2376 gop.value_ptr.* = .{2403 const atom = switch (sym.kind) {
2377 .atom = try self.createAtom(),2404 .code => &gop.value_ptr.text_atom,
2378 .shdr = switch (lazy_sym.kind) {2405 .const_data => &gop.value_ptr.rodata_atom,
2379 .code => self.text_section_index.?,2406 };
2380 .const_data => self.rodata_section_index.?,2407 if (atom.* == null) atom.* = try self.createAtom();
2381 },2408 return atom.*.?;
2382 .alignment = alignment,
2383 };
2384 }
2385 return gop.value_ptr.atom;
2386}2409}
23872410
2388pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {2411pub 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...@@ -2651,7 +2674,29 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2651 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2674 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2652}2675}
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 {
2655 const gpa = self.base.allocator;2700 const gpa = self.base.allocator;
2656 const mod = self.base.options.module.?;2701 const mod = self.base.options.module.?;
26572702
...@@ -2660,19 +2705,18 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy...@@ -2660,19 +2705,18 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
26602705
2661 const name_str_index = blk: {2706 const name_str_index = blk: {
2662 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{2707 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
2663 @tagName(lazy_sym.kind),2708 @tagName(sym.kind),
2664 lazy_sym.ty.fmt(mod),2709 sym.ty.fmt(mod),
2665 });2710 });
2666 defer gpa.free(name);2711 defer gpa.free(name);
2667 break :blk try self.shstrtab.insert(gpa, name);2712 break :blk try self.shstrtab.insert(gpa, name);
2668 };2713 };
2669 const name = self.shstrtab.get(name_str_index).?;2714 const name = self.shstrtab.get(name_str_index).?;
26702715
2671 const atom_index = lazy_metadata.atom;
2672 const atom = self.getAtom(atom_index);2716 const atom = self.getAtom(atom_index);
2673 const local_sym_index = atom.getSymbolIndex().?;2717 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|
2676 mod.declPtr(owner_decl).srcLoc()2720 mod.declPtr(owner_decl).srcLoc()
2677 else2721 else
2678 Module.SrcLoc{2722 Module.SrcLoc{
...@@ -2680,14 +2724,9 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy...@@ -2680,14 +2724,9 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
2680 .parent_decl_node = undefined,2724 .parent_decl_node = undefined,
2681 .lazy = .unneeded,2725 .lazy = .unneeded,
2682 };2726 };
2683 const res = try codegen.generateLazySymbol(2727 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
2684 &self.base,2728 .parent_atom_index = local_sym_index,
2685 src,2729 });
2686 lazy_sym,
2687 &code_buffer,
2688 .none,
2689 .{ .parent_atom_index = local_sym_index },
2690 );
2691 const code = switch (res) {2730 const code = switch (res) {
2692 .ok => code_buffer.items,2731 .ok => code_buffer.items,
2693 .fail => |em| {2732 .fail => |em| {
...@@ -2696,7 +2735,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy...@@ -2696,7 +2735,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
2696 },2735 },
2697 };2736 };
26982737
2699 const shdr_index = lazy_metadata.shdr;
2700 const phdr_index = self.sections.items(.phdr_index)[shdr_index];2738 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2701 const local_sym = atom.getSymbolPtr(self);2739 const local_sym = atom.getSymbolPtr(self);
2702 local_sym.* = .{2740 local_sym.* = .{
...@@ -2707,7 +2745,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy...@@ -2707,7 +2745,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy
2707 .st_value = 0,2745 .st_value = 0,
2708 .st_size = 0,2746 .st_size = 0,
2709 };2747 };
2710 const required_alignment = lazy_metadata.alignment;
2711 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);2748 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
2712 errdefer self.freeAtom(atom_index);2749 errdefer self.freeAtom(atom_index);
2713 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });2750 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) {...@@ -232,16 +232,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
232 else => false,232 else => false,
233};233};
234234
235const LazySymbolTable = std.ArrayHashMapUnmanaged(235const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
236 link.File.LazySymbol,
237 LazySymbolMetadata,
238 link.File.LazySymbol.Context,
239 true,
240);
241236
242const LazySymbolMetadata = struct {237const LazySymbolMetadata = struct {
243 atom: Atom.Index,238 text_atom: ?Atom.Index = null,
244 section: u8,239 data_const_atom: ?Atom.Index = null,
245 alignment: u32,240 alignment: u32,
246};241};
247242
...@@ -513,17 +508,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -513,17 +508,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
513 sub_prog_node.activate();508 sub_prog_node.activate();
514 defer sub_prog_node.end();509 defer sub_prog_node.end();
515510
516 {511 // Most lazy symbols can be updated when the corresponding decl is,
517 var lazy_it = self.lazy_syms.iterator();512 // so we only have to worry about the one without an associated decl.
518 while (lazy_it.next()) |lazy_entry| {513 if (self.lazy_syms.get(.none)) |metadata| {
519 self.updateLazySymbol(514 self.updateLazySymbol(.none, metadata) catch |err| switch (err) {
520 lazy_entry.key_ptr.*,515 error.CodegenFail => return error.FlushFailure,
521 lazy_entry.value_ptr.*,516 else => |e| return e,
522 ) catch |err| switch (err) {517 };
523 error.CodegenFail => return error.FlushFailure,
524 else => |e| return e,
525 };
526 }
527 }518 }
528519
529 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;520 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)...@@ -2309,7 +2300,29 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2309 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2300 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2310}2301}
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 {
2313 const gpa = self.base.allocator;2326 const gpa = self.base.allocator;
2314 const mod = self.base.options.module.?;2327 const mod = self.base.options.module.?;
23152328
...@@ -2318,19 +2331,18 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy...@@ -2318,19 +2331,18 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
23182331
2319 const name_str_index = blk: {2332 const name_str_index = blk: {
2320 const name = try std.fmt.allocPrint(gpa, "___lazy_{s}_{}", .{2333 const name = try std.fmt.allocPrint(gpa, "___lazy_{s}_{}", .{
2321 @tagName(lazy_sym.kind),2334 @tagName(sym.kind),
2322 lazy_sym.ty.fmt(mod),2335 sym.ty.fmt(mod),
2323 });2336 });
2324 defer gpa.free(name);2337 defer gpa.free(name);
2325 break :blk try self.strtab.insert(gpa, name);2338 break :blk try self.strtab.insert(gpa, name);
2326 };2339 };
2327 const name = self.strtab.get(name_str_index).?;2340 const name = self.strtab.get(name_str_index).?;
23282341
2329 const atom_index = lazy_metadata.atom;
2330 const atom = self.getAtomPtr(atom_index);2342 const atom = self.getAtomPtr(atom_index);
2331 const local_sym_index = atom.getSymbolIndex().?;2343 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|
2334 mod.declPtr(owner_decl).srcLoc()2346 mod.declPtr(owner_decl).srcLoc()
2335 else2347 else
2336 Module.SrcLoc{2348 Module.SrcLoc{
...@@ -2338,14 +2350,9 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy...@@ -2338,14 +2350,9 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
2338 .parent_decl_node = undefined,2350 .parent_decl_node = undefined,
2339 .lazy = .unneeded,2351 .lazy = .unneeded,
2340 };2352 };
2341 const res = try codegen.generateLazySymbol(2353 const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{
2342 &self.base,2354 .parent_atom_index = local_sym_index,
2343 src,2355 });
2344 lazy_sym,
2345 &code_buffer,
2346 .none,
2347 .{ .parent_atom_index = local_sym_index },
2348 );
2349 const code = switch (res) {2356 const code = switch (res) {
2350 .ok => code_buffer.items,2357 .ok => code_buffer.items,
2351 .fail => |em| {2358 .fail => |em| {
...@@ -2354,11 +2361,10 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy...@@ -2354,11 +2361,10 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
2354 },2361 },
2355 };2362 };
23562363
2357 const required_alignment = lazy_metadata.alignment;
2358 const symbol = atom.getSymbolPtr(self);2364 const symbol = atom.getSymbolPtr(self);
2359 symbol.n_strx = name_str_index;2365 symbol.n_strx = name_str_index;
2360 symbol.n_type = macho.N_SECT;2366 symbol.n_type = macho.N_SECT;
2361 symbol.n_sect = lazy_metadata.section + 1;2367 symbol.n_sect = section_index + 1;
2362 symbol.n_desc = 0;2368 symbol.n_desc = 0;
23632369
2364 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);2370 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...@@ -2381,26 +2387,16 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy
2381 try self.writeAtom(atom_index, code);2387 try self.writeAtom(atom_index, code);
2382}2388}
23832389
2384pub fn getOrCreateAtomForLazySymbol(2390pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index {
2385 self: *MachO,2391 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
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 });
2392 errdefer _ = self.lazy_syms.pop();2392 errdefer _ = self.lazy_syms.pop();
2393 if (!gop.found_existing) {2393 if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment };
2394 gop.value_ptr.* = .{2394 const atom = switch (sym.kind) {
2395 .atom = try self.createAtom(),2395 .code => &gop.value_ptr.text_atom,
2396 .section = switch (lazy_sym.kind) {2396 .const_data => &gop.value_ptr.data_const_atom,
2397 .code => self.text_section_index.?,2397 };
2398 .const_data => self.data_const_section_index.?,2398 if (atom.* == null) atom.* = try self.createAtom();
2399 },2399 return atom.*.?;
2400 .alignment = alignment,
2401 };
2402 }
2403 return gop.value_ptr.atom;
2404}2400}
24052401
2406pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {2402pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {
src/print_air.zig+1
...@@ -804,6 +804,7 @@ const Writer = struct {...@@ -804,6 +804,7 @@ const Writer = struct {
804 var case_i: u32 = 0;804 var case_i: u32 = 0;
805805
806 try w.writeOperand(s, inst, 0, pl_op.operand);806 try w.writeOperand(s, inst, 0, pl_op.operand);
807 if (w.skip_body) return s.writeAll(", ...");
807 const old_indent = w.indent;808 const old_indent = w.indent;
808 w.indent += 2;809 w.indent += 2;
809810
test/behavior/bugs/12776.zig-1
...@@ -31,7 +31,6 @@ const CPU = packed struct {...@@ -31,7 +31,6 @@ const CPU = packed struct {
31test {31test {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3635
37 var ram = try RAM.new();36 var ram = try RAM.new();
test/behavior/bugs/1442.zig-1
...@@ -9,7 +9,6 @@ const Union = union(enum) {...@@ -9,7 +9,6 @@ const Union = union(enum) {
9test "const error union field alignment" {9test "const error union field alignment" {
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14 var union_or_err: anyerror!Union = Union{ .Color = 1234 };13 var union_or_err: anyerror!Union = Union{ .Color = 1234 };
15 try std.testing.expect((union_or_err catch unreachable).Color == 1234);14 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 {...@@ -21,7 +21,6 @@ fn get_foo() Foo.FooError!*Foo {
21test "fixed" {21test "fixed" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625
27 default_foo = get_foo() catch null; // This Line26 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" {...@@ -402,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" {
402402
403test "explicit cast from integer to error type" {403test "explicit cast from integer to error type" {
404 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;404 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
405 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO406 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO407 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 {...@@ -370,7 +370,6 @@ fn intLiteral(str: []const u8) !?i64 {
370}370}
371371
372test "nested error union function call in optional unwrap" {372test "nested error union function call in optional unwrap" {
373 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO375 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...@@ -499,7 +498,6 @@ test "function pointer with return type that is error union with payload which i
499}498}
500499
501test "return result loc as peer result loc in inferred error set function" {500test "return result loc as peer result loc in inferred error set function" {
502 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO501 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO503 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" {...@@ -531,7 +529,6 @@ test "return result loc as peer result loc in inferred error set function" {
531}529}
532530
533test "error payload type is correctly resolved" {531test "error payload type is correctly resolved" {
534 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
535 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
536 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -665,7 +662,6 @@ test "coerce error set to the current inferred error set" {...@@ -665,7 +662,6 @@ test "coerce error set to the current inferred error set" {
665}662}
666663
667test "error union payload is properly aligned" {664test "error union payload is properly aligned" {
668 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
669 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
670 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO666 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
671 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO667 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" {...@@ -967,7 +967,6 @@ test "closure capture type of runtime-known parameter" {
967}967}
968968
969test "comptime break passing through runtime condition converted to runtime break" {969test "comptime break passing through runtime condition converted to runtime break" {
970 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
971 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO970 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
972971
973 const S = struct {972 const S = struct {
...@@ -999,7 +998,6 @@ test "comptime break passing through runtime condition converted to runtime brea...@@ -999,7 +998,6 @@ test "comptime break passing through runtime condition converted to runtime brea
999}998}
1000999
1001test "comptime break to outer loop passing through runtime condition converted to runtime break" {1000test "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
1003 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1005 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1003 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1218,7 +1216,6 @@ test "storing an array of type in a field" {...@@ -1218,7 +1216,6 @@ test "storing an array of type in a field" {
1218}1216}
12191217
1220test "pass pointer to field of comptime-only type as a runtime parameter" {1218test "pass pointer to field of comptime-only type as a runtime parameter" {
1221 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12241221
test/behavior/inttoptr.zig-1
...@@ -11,7 +11,6 @@ fn addressToFunction() void {...@@ -11,7 +11,6 @@ fn addressToFunction() void {
11}11}
1212
13test "mutate through ptr initialized with constant intToPtr value" {13test "mutate through ptr initialized with constant intToPtr value" {
14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 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" {...@@ -1116,7 +1116,6 @@ test "for loop over pointers to struct, getting field from struct pointer" {
1116}1116}
11171117
1118test "anon init through error unions and optionals" {1118test "anon init through error unions and optionals" {
1119 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1162,7 +1161,6 @@ test "anon init through optional" {...@@ -1162,7 +1161,6 @@ test "anon init through optional" {
1162}1161}
11631162
1164test "anon init through error union" {1163test "anon init through error union" {
1165 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1166 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1168 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1182,7 +1180,6 @@ test "anon init through error union" {...@@ -1182,7 +1180,6 @@ test "anon init through error union" {
1182}1180}
11831181
1184test "typed init through error unions and optionals" {1182test "typed init through error unions and optionals" {
1185 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1186 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1185 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 {...@@ -23,7 +23,6 @@ fn doThing(form_id: u64) anyerror!FormValue {
23test "switch prong returns error enum" {23test "switch prong returns error enum" {
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2827
29 switch (doThing(17) catch unreachable) {28 switch (doThing(17) catch unreachable) {
test/behavior/switch_prong_implicit_cast.zig-1
...@@ -17,7 +17,6 @@ fn foo(id: u64) !FormValue {...@@ -17,7 +17,6 @@ fn foo(id: u64) !FormValue {
17test "switch prong implicit cast" {17test "switch prong implicit cast" {
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221
23 const result = switch (foo(2) catch unreachable) {22 const result = switch (foo(2) catch unreachable) {
test/cases/aarch64-macos/hello_world_with_updates.0.zig+1-1
...@@ -2,4 +2,4 @@...@@ -2,4 +2,4 @@
2// output_mode=Exe2// output_mode=Exe
3// target=aarch64-macos3// target=aarch64-macos
4//4//
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 @@...@@ -2,4 +2,7 @@
2// output_mode=Exe2// output_mode=Exe
3// target=x86_64-linux3// target=x86_64-linux
4//4//
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 @@...@@ -2,4 +2,4 @@
2// output_mode=Exe2// output_mode=Exe
3// target=x86_64-macos3// target=x86_64-macos
4//4//
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 @@...@@ -2,4 +2,6 @@
2// output_mode=Exe2// output_mode=Exe
3// target=x86_64-windows3// target=x86_64-windows
4//4//
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 {...@@ -1045,8 +1045,7 @@ pub fn main() !void {
1045 var ctx = Cases.init(gpa, arena);1045 var ctx = Cases.init(gpa, arena);
10461046
1047 var test_it = TestIterator{ .filenames = filenames.items };1047 var test_it = TestIterator{ .filenames = filenames.items };
1048 while (test_it.next()) |maybe_batch| {1048 while (try test_it.next()) |batch| {
1049 const batch = maybe_batch orelse break;
1050 const strategy: TestStrategy = if (batch.len > 1) .incremental else .independent;1049 const strategy: TestStrategy = if (batch.len > 1) .incremental else .independent;
1051 var cases = std.ArrayList(usize).init(arena);1050 var cases = std.ArrayList(usize).init(arena);
10521051
...@@ -1084,6 +1083,11 @@ pub fn main() !void {...@@ -1084,6 +1083,11 @@ pub fn main() !void {
10841083
1085 for (cases.items) |case_index| {1084 for (cases.items) |case_index| {
1086 const case = &ctx.cases.items[case_index];1085 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
1087 switch (manifest.type) {1091 switch (manifest.type) {
1088 .compile => {1092 .compile => {
1089 case.addCompile(src);1093 case.addCompile(src);
...@@ -1115,8 +1119,6 @@ pub fn main() !void {...@@ -1115,8 +1119,6 @@ pub fn main() !void {
1115 }1119 }
1116 }1120 }
1117 }1121 }
1118 } else |err| {
1119 return err;
1120 }1122 }
11211123
1122 return runCases(&ctx, zig_exe_path);1124 return runCases(&ctx, zig_exe_path);