| author | |
| committer | |
| log | 5ea6e78943453e145366c8860cb9c8f9684f9b31 |
| tree | c9fc4b4ffe6636ce839fa3f24328667d4aed8ee1 |
| parent | 3a8362e751d210f1cecfce7c33cae2e582bd4b94 |
| parent | 83b7dbe52f75161a2ac6f5d8f39b275fd9473c15 |
| signature |
x86_64: get enough things working to enable full `start.zig` logic26 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: * |
| 125 | 125 | ||
| 126 | pub fn restore() callconv(.Naked) void { | 126 | pub 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], %%eax | 129 | \\ movl %[number], %%eax |
| 130 | \\ int $0x80 | 130 | \\ 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 | } |
| 142 | 146 | ||
| 143 | pub fn restore_rt() callconv(.Naked) void { | 147 | pub 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], %%eax | 150 | \\ movl %[number], %%eax |
| 147 | \\ int $0x80 | 151 | \\ 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 | } |
| 159 | 167 | ||
| 160 | pub const O = struct { | 168 | pub 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; |
| 109 | 109 | ||
| 110 | pub fn restore_rt() callconv(.Naked) void { | 110 | pub 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], %%eax | 113 | \\ movl %[number], %%eax |
| 114 | \\ syscall | 114 | \\ syscall |
| 115 | \\ retq | 115 | \\ 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 | } |
| 127 | 130 | ||
| 128 | pub const mode_t = usize; | 131 | pub 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. |
| 20 | pub const simplified_logic = | 20 | pub const simplified_logic = |
| 21 | builtin.zig_backend == .stage2_wasm or | 21 | builtin.zig_backend == .stage2_wasm or |
| 22 | builtin.zig_backend == .stage2_x86_64 or | 22 | (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or |
| 23 | builtin.zig_backend == .stage2_x86 or | 23 | builtin.zig_backend == .stage2_x86 or |
| 24 | builtin.zig_backend == .stage2_aarch64 or | 24 | builtin.zig_backend == .stage2_aarch64 or |
| 25 | builtin.zig_backend == .stage2_arm or | 25 | 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 | _, |
| 556 | 556 | ||
| 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 | } |
| 560 | 560 | ||
| 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; |
| 28 | const TypedValue = @import("../../TypedValue.zig"); | 28 | const TypedValue = @import("../../TypedValue.zig"); |
| 29 | const Value = @import("../../value.zig").Value; | 29 | const Value = @import("../../value.zig").Value; |
| 30 | 30 | ||
| 31 | const bits = @import("bits.zig"); | ||
| 32 | const abi = @import("abi.zig"); | 31 | const abi = @import("abi.zig"); |
| 33 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | 32 | const bits = @import("bits.zig"); |
| 33 | const encoder = @import("encoder.zig"); | ||
| 34 | const errUnionErrorOffset = codegen.errUnionErrorOffset; | 34 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 35 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | ||
| 35 | 36 | ||
| 36 | const Condition = bits.Condition; | 37 | const Condition = bits.Condition; |
| 37 | const Immediate = bits.Immediate; | 38 | const 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); |
| 2529 | 2530 | ||
| 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() }, |
| 3743 | 3756 | ), | |
| 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); |
| 3765 | 3773 | ||
| 3766 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); | 3774 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); |
| 3767 | 3775 | // 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 | ); |
| 3774 | 3781 | ||
| 3775 | const new_ptr = MCValue{ .register = addr_reg.to64() }; | 3782 | const new_ptr = MCValue{ .register = addr_reg.to64() }; |
| 3776 | 3783 | 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 | else | 4847 | 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 { |
| 5654 | 5602 | ||
| 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 { |
| 5702 | 5650 | ||
| 5703 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { | 5651 | fn 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 | } |
| 5710 | 5711 | ||
| ... | @@ -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 | } |
| 6610 | 6633 | ||
| 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() orelse | 6646 | .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) catch | 6651 | 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..]) orelse | 6655 | 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() orelse | 6660 | 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..]) orelse | 6665 | 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) catch | 6667 | 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]) orelse | 6670 | 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 | } |
| 6678 | 6770 | ||
| ... | @@ -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( |
| 124 | 124 | ||
| 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 | }; |
| 1107 | 1107 | ||
| 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, | ||
| 1111 | 1110 | ||
| 1112 | pub const Context = struct { | 1111 | kind: Kind, |
| 1113 | mod: *Module, | 1112 | ty: Type, |
| 1114 | 1113 | ||
| 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 | } |
| 1121 | 1120 | ||
| 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 | }; |
| 1127 | 1125 | ||
| 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 | }; |
| 147 | 147 | ||
| 148 | const LazySymbolTable = std.ArrayHashMapUnmanaged( | 148 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 149 | link.File.LazySymbol, | ||
| 150 | LazySymbolMetadata, | ||
| 151 | link.File.LazySymbol.Context, | ||
| 152 | true, | ||
| 153 | ); | ||
| 154 | 149 | ||
| 155 | const LazySymbolMetadata = struct { | 150 | const 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 | }; |
| 160 | 155 | ||
| ... | @@ -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 | } |
| 1178 | 1173 | ||
| 1179 | fn updateLazySymbol( | 1174 | fn 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 | |||
| 1190 | fn 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(); |
| 1189 | 1202 | ||
| 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); |
| 1195 | 1208 | ||
| 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().?; |
| 1199 | 1211 | ||
| 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 | else | 1214 | 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 | }; |
| 1223 | 1230 | ||
| 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 }; |
| 1230 | 1236 | ||
| 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( |
| 1250 | 1256 | ||
| 1251 | pub fn getOrCreateAtomForLazySymbol( | 1257 | pub 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 | } |
| 1272 | 1272 | ||
| 1273 | pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { | 1273 | pub 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(); |
| 1602 | 1602 | ||
| 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 | } |
| 1615 | 1611 | ||
| 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"); |
| 2489 | const Object = @import("Coff/Object.zig"); | 2485 | const Object = @import("Coff/Object.zig"); |
| 2490 | const Relocation = @import("Coff/Relocation.zig"); | 2486 | const Relocation = @import("Coff/Relocation.zig"); |
| 2491 | const StringTable = @import("strtab.zig").StringTable; | 2487 | const StringTable = @import("strtab.zig").StringTable; |
| 2488 | const Type = @import("../type.zig").Type; | ||
| 2492 | const TypedValue = @import("../TypedValue.zig"); | 2489 | const TypedValue = @import("../TypedValue.zig"); |
| 2493 | 2490 | ||
| 2494 | pub const base_tag: link.File.Tag = .coff; | 2491 | pub 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 | }; |
| 65 | 65 | ||
| 66 | const LazySymbolMetadata = struct { | 66 | const 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 | }; |
| 71 | 71 | ||
| ... | @@ -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. |
| 108 | program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, | 108 | program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, |
| 109 | phdr_table_offset: ?u64 = null, | 109 | /// The index into the program headers of the PT_PHDR program header |
| 110 | phdr_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. | ||
| 114 | phdr_table_load_index: ?u16 = null, | ||
| 110 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags | 115 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags |
| 111 | phdr_load_re_index: ?u16 = null, | 116 | phdr_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 = .{}, |
| 203 | 208 | ||
| 204 | const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); | 209 | const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); |
| 205 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); | 210 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| 206 | const LazySymbolTable = std.ArrayHashMapUnmanaged(File.LazySymbol, LazySymbolMetadata, File.LazySymbol.Context, true); | 211 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 207 | 212 | ||
| 208 | /// When allocating, the ideal_capacity is calculated by | 213 | /// 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 | } |
| 398 | 403 | ||
| 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(); |
| 464 | 456 | ||
| 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 | } |
| 851 | 880 | ||
| 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(); |
| 1023 | 1039 | ||
| 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 | } |
| 1036 | 1048 | ||
| 1037 | // TODO This linker code currently assumes there is only 1 compilation unit and it | 1049 | // 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; |
| 1141 | 1154 | ||
| 1142 | if (needed_size > allocated_size) { | 1155 | if (needed_size > allocated_size) { |
| 1143 | self.phdr_table_offset = null; // free the space | 1156 | 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 | } |
| 1146 | 1159 | ||
| 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 | } |
| 1175 | 1203 | ||
| ... | @@ -1992,13 +2020,14 @@ fn writeElfHeader(self: *Elf) !void { | ... | @@ -1992,13 +2020,14 @@ fn writeElfHeader(self: *Elf) !void { |
| 1992 | 2020 | ||
| 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.?; |
| 1994 | 2022 | ||
| 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; |
| 1999 | 2028 | ||
| 2000 | // e_phoff | 2029 | // 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; |
| 2003 | 2032 | ||
| 2004 | // e_shoff | 2033 | // 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; |
| 2012 | 2041 | ||
| 2013 | // e_phoff | 2042 | // 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; |
| 2016 | 2045 | ||
| 2017 | // e_shoff | 2046 | // 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 | } |
| 2369 | 2398 | ||
| 2370 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, alignment: u32) !Atom.Index { | 2399 | pub 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 | } |
| 2387 | 2410 | ||
| 2388 | pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { | 2411 | pub 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 | } |
| 2653 | 2676 | ||
| 2654 | fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void { | 2677 | fn 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 | |||
| 2693 | fn 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.?; |
| 2657 | 2702 | ||
| ... | @@ -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 |
| 2660 | 2705 | ||
| 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).?; |
| 2670 | 2715 | ||
| 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().?; |
| 2674 | 2718 | ||
| 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 | else | 2721 | 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 | }; |
| 2698 | 2737 | ||
| 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 | }; |
| 234 | 234 | ||
| 235 | const LazySymbolTable = std.ArrayHashMapUnmanaged( | 235 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 236 | link.File.LazySymbol, | ||
| 237 | LazySymbolMetadata, | ||
| 238 | link.File.LazySymbol.Context, | ||
| 239 | true, | ||
| 240 | ); | ||
| 241 | 236 | ||
| 242 | const LazySymbolMetadata = struct { | 237 | const 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 | }; |
| 247 | 242 | ||
| ... | @@ -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(); |
| 515 | 510 | ||
| 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 | } |
| 528 | 519 | ||
| 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 | } |
| 2311 | 2302 | ||
| 2312 | fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void { | 2303 | fn 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 | |||
| 2319 | fn 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.?; |
| 2315 | 2328 | ||
| ... | @@ -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 |
| 2318 | 2331 | ||
| 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).?; |
| 2328 | 2341 | ||
| 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().?; |
| 2332 | 2344 | ||
| 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 | else | 2347 | 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 | }; |
| 2356 | 2363 | ||
| 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; |
| 2363 | 2369 | ||
| 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 | } |
| 2383 | 2389 | ||
| 2384 | pub fn getOrCreateAtomForLazySymbol( | 2390 | pub 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 | } |
| 2405 | 2401 | ||
| 2406 | pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index { | 2402 | pub 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; |
| 805 | 805 | ||
| 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; |
| 809 | 810 |
test/behavior/bugs/12776.zig-1| ... | @@ -31,7 +31,6 @@ const CPU = packed struct { | ... | @@ -31,7 +31,6 @@ const CPU = packed struct { |
| 31 | test { | 31 | test { |
| 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; |
| 36 | 35 | ||
| 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) { |
| 9 | test "const error union field alignment" { | 9 | test "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; // TODO | 12 | 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 { |
| 21 | test "fixed" { | 21 | test "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; // TODO | 23 | 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; // TODO | 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 26 | 25 | ||
| 27 | default_foo = get_foo() catch null; // This Line | 26 | 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" { |
| 402 | 402 | ||
| 403 | test "explicit cast from integer to error type" { | 403 | test "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; // TODO | 406 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 408 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 407 | 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 | } |
| 371 | 371 | ||
| 372 | test "nested error union function call in optional unwrap" { | 372 | test "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; // TODO | 373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 375 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 376 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 375 | 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 | } |
| 500 | 499 | ||
| 501 | test "return result loc as peer result loc in inferred error set function" { | 500 | test "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; // TODO | 501 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 504 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 502 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 505 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 503 | 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 | } |
| 532 | 530 | ||
| 533 | test "error payload type is correctly resolved" { | 531 | test "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; // TODO | 532 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 536 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 533 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 534 | 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 | } |
| 666 | 663 | ||
| 667 | test "error union payload is properly aligned" { | 664 | test "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; // TODO | 665 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 670 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 666 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 671 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 667 | 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 | } |
| 968 | 968 | ||
| 969 | test "comptime break passing through runtime condition converted to runtime break" { | 969 | test "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; // TODO | 970 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 972 | 971 | ||
| 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 | } |
| 1000 | 999 | ||
| 1001 | test "comptime break to outer loop passing through runtime condition converted to runtime break" { | 1000 | test "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; // TODO | 1001 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1004 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1002 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1005 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1003 | 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 | } |
| 1219 | 1217 | ||
| 1220 | test "pass pointer to field of comptime-only type as a runtime parameter" { | 1218 | test "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; // TODO | 1219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1223 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1220 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1224 | 1221 |
test/behavior/inttoptr.zig-1| ... | @@ -11,7 +11,6 @@ fn addressToFunction() void { | ... | @@ -11,7 +11,6 @@ fn addressToFunction() void { |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | test "mutate through ptr initialized with constant intToPtr value" { | 13 | test "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; // TODO | 16 | 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 | } |
| 1117 | 1117 | ||
| 1118 | test "anon init through error unions and optionals" { | 1118 | test "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; // TODO | 1119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1121 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1122 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1121 | 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 | } |
| 1163 | 1162 | ||
| 1164 | test "anon init through error union" { | 1163 | test "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; // TODO | 1164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1167 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1165 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1168 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1166 | 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 | } |
| 1183 | 1181 | ||
| 1184 | test "typed init through error unions and optionals" { | 1182 | test "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; // TODO | 1183 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1187 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1188 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1185 | 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 { |
| 23 | test "switch prong returns error enum" { | 23 | test "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; // TODO | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 28 | 27 | ||
| 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 { |
| 17 | test "switch prong implicit cast" { | 17 | test "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; // TODO | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | 21 | ||
| 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=Exe | 2 | // output_mode=Exe |
| 3 | // target=aarch64-macos | 3 | // 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=Exe | 2 | // output_mode=Exe |
| 3 | // target=x86_64-linux | 3 | // 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=Exe | 2 | // output_mode=Exe |
| 3 | // target=x86_64-macos | 3 | // 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=Exe | 2 | // output_mode=Exe |
| 3 | // target=x86_64-windows | 3 | // 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); |
| 1046 | 1046 | ||
| 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); |
| 1052 | 1051 | ||
| ... | @@ -1084,6 +1083,11 @@ pub fn main() !void { | ... | @@ -1084,6 +1083,11 @@ pub fn main() !void { |
| 1084 | 1083 | ||
| 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 | } |
| 1121 | 1123 | ||
| 1122 | return runCases(&ctx, zig_exe_path); | 1124 | return runCases(&ctx, zig_exe_path); |