| 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 | 125 | |
| 126 | 126 | pub fn restore() callconv(.Naked) void { |
| 127 | 127 | switch (@import("builtin").zig_backend) { |
| 128 | .stage2_c => return asm volatile ( | |
| 128 | .stage2_c => asm volatile ( | |
| 129 | 129 | \\ movl %[number], %%eax |
| 130 | 130 | \\ int $0x80 |
| 131 | \\ ret | |
| 131 | 132 | : |
| 132 | 133 | : [number] "i" (@enumToInt(SYS.sigreturn)), |
| 133 | 134 | : "memory" |
| 134 | 135 | ), |
| 135 | else => return asm volatile ("int $0x80" | |
| 136 | else => asm volatile ( | |
| 137 | \\ int $0x80 | |
| 138 | \\ ret | |
| 136 | 139 | : |
| 137 | 140 | : [number] "{eax}" (@enumToInt(SYS.sigreturn)), |
| 138 | 141 | : "memory" |
| 139 | 142 | ), |
| 140 | 143 | } |
| 144 | unreachable; | |
| 141 | 145 | } |
| 142 | 146 | |
| 143 | 147 | pub fn restore_rt() callconv(.Naked) void { |
| 144 | 148 | switch (@import("builtin").zig_backend) { |
| 145 | .stage2_c => return asm volatile ( | |
| 149 | .stage2_c => asm volatile ( | |
| 146 | 150 | \\ movl %[number], %%eax |
| 147 | 151 | \\ int $0x80 |
| 152 | \\ ret | |
| 148 | 153 | : |
| 149 | 154 | : [number] "i" (@enumToInt(SYS.rt_sigreturn)), |
| 150 | 155 | : "memory" |
| 151 | 156 | ), |
| 152 | else => return asm volatile ("int $0x80" | |
| 157 | else => asm volatile ( | |
| 158 | \\ int $0x80 | |
| 159 | \\ ret | |
| 153 | 160 | : |
| 154 | 161 | : [number] "{eax}" (@enumToInt(SYS.rt_sigreturn)), |
| 155 | 162 | : "memory" |
| 156 | 163 | ), |
| 157 | 164 | } |
| 165 | unreachable; | |
| 158 | 166 | } |
| 159 | 167 | |
| 160 | 168 | pub const O = struct { |
lib/std/os/linux/x86_64.zig+5-2| ... | ... | @@ -109,7 +109,7 @@ pub const restore = restore_rt; |
| 109 | 109 | |
| 110 | 110 | pub fn restore_rt() callconv(.Naked) void { |
| 111 | 111 | switch (@import("builtin").zig_backend) { |
| 112 | .stage2_c => return asm volatile ( | |
| 112 | .stage2_c => asm volatile ( | |
| 113 | 113 | \\ movl %[number], %%eax |
| 114 | 114 | \\ syscall |
| 115 | 115 | \\ retq |
| ... | ... | @@ -117,12 +117,15 @@ pub fn restore_rt() callconv(.Naked) void { |
| 117 | 117 | : [number] "i" (@enumToInt(SYS.rt_sigreturn)), |
| 118 | 118 | : "rcx", "r11", "memory" |
| 119 | 119 | ), |
| 120 | else => return asm volatile ("syscall" | |
| 120 | else => asm volatile ( | |
| 121 | \\ syscall | |
| 122 | \\ retq | |
| 121 | 123 | : |
| 122 | 124 | : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)), |
| 123 | 125 | : "rcx", "r11", "memory" |
| 124 | 126 | ), |
| 125 | 127 | } |
| 128 | unreachable; | |
| 126 | 129 | } |
| 127 | 130 | |
| 128 | 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 | 19 | // self-hosted is capable enough to handle all of the real start.zig logic. |
| 20 | 20 | pub const simplified_logic = |
| 21 | 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 | 23 | builtin.zig_backend == .stage2_x86 or |
| 24 | 24 | builtin.zig_backend == .stage2_aarch64 or |
| 25 | 25 | builtin.zig_backend == .stage2_arm or |
src/Module.zig+1-1| ... | ... | @@ -555,7 +555,7 @@ pub const Decl = struct { |
| 555 | 555 | _, |
| 556 | 556 | |
| 557 | 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 | 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 | 28 | const TypedValue = @import("../../TypedValue.zig"); |
| 29 | 29 | const Value = @import("../../value.zig").Value; |
| 30 | 30 | |
| 31 | const bits = @import("bits.zig"); | |
| 32 | 31 | const abi = @import("abi.zig"); |
| 33 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | |
| 32 | const bits = @import("bits.zig"); | |
| 33 | const encoder = @import("encoder.zig"); | |
| 34 | 34 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 35 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | |
| 35 | 36 | |
| 36 | 37 | const Condition = bits.Condition; |
| 37 | 38 | const Immediate = bits.Immediate; |
| ... | ... | @@ -2527,7 +2528,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2527 | 2528 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2528 | 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 | 2532 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 2532 | 2533 | try self.asmRegisterMemory( |
| 2533 | 2534 | .lea, |
| ... | ... | @@ -3650,10 +3651,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3650 | 3651 | .dead => unreachable, |
| 3651 | 3652 | .eflags => unreachable, |
| 3652 | 3653 | .register_overflow => unreachable, |
| 3653 | .immediate => |imm| { | |
| 3654 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | |
| 3655 | }, | |
| 3656 | .stack_offset => { | |
| 3654 | .immediate, .stack_offset => { | |
| 3657 | 3655 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 3658 | 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 | 3666 | .none => unreachable, |
| 3669 | 3667 | .dead => unreachable, |
| 3670 | 3668 | .unreach => unreachable, |
| 3671 | .eflags => |cc| { | |
| 3672 | try self.asmSetccMemory(Memory.sib( | |
| 3673 | Memory.PtrSize.fromSize(abi_size), | |
| 3674 | .{ .base = reg.to64() }, | |
| 3675 | ), cc); | |
| 3676 | }, | |
| 3677 | .undef => { | |
| 3678 | if (!self.wantSafety()) return; // The already existing value will do just fine. | |
| 3679 | switch (abi_size) { | |
| 3680 | 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty), | |
| 3681 | 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty), | |
| 3682 | 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty), | |
| 3683 | 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty), | |
| 3684 | else => try self.genInlineMemset(ptr, .{ .immediate = 0xaa }, .{ .immediate = abi_size }, .{}), | |
| 3685 | } | |
| 3686 | }, | |
| 3687 | .immediate => |imm| { | |
| 3688 | switch (abi_size) { | |
| 3689 | 1, 2, 4 => { | |
| 3690 | const immediate = if (value_ty.isSignedInt()) | |
| 3691 | Immediate.s(@intCast(i32, @bitCast(i64, imm))) | |
| 3692 | else | |
| 3693 | Immediate.u(@truncate(u32, imm)); | |
| 3694 | try self.asmMemoryImmediate(.mov, Memory.sib( | |
| 3695 | Memory.PtrSize.fromSize(abi_size), | |
| 3696 | .{ .base = reg.to64() }, | |
| 3697 | ), immediate); | |
| 3698 | }, | |
| 3699 | 8 => { | |
| 3700 | // TODO: optimization: if the imm is only using the lower | |
| 3701 | // 4 bytes and can be sign extended we can use a normal mov | |
| 3702 | // with indirect addressing (mov [reg64], imm32). | |
| 3703 | ||
| 3704 | // movabs does not support indirect register addressing | |
| 3705 | // so we need an extra register and an extra mov. | |
| 3706 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); | |
| 3707 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | |
| 3708 | }, | |
| 3709 | else => { | |
| 3710 | return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size}); | |
| 3711 | }, | |
| 3712 | } | |
| 3669 | .eflags => |cc| try self.asmSetccMemory( | |
| 3670 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 3671 | cc, | |
| 3672 | ), | |
| 3673 | .undef => if (self.wantSafety()) switch (abi_size) { | |
| 3674 | 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty), | |
| 3675 | 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty), | |
| 3676 | 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty), | |
| 3677 | 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty), | |
| 3678 | else => try self.genInlineMemset( | |
| 3679 | ptr, | |
| 3680 | .{ .immediate = 0xaa }, | |
| 3681 | .{ .immediate = abi_size }, | |
| 3682 | .{}, | |
| 3683 | ), | |
| 3713 | 3684 | }, |
| 3714 | .register => |src_reg| { | |
| 3715 | try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0); | |
| 3685 | .immediate => |imm| switch (self.regBitSize(value_ty)) { | |
| 3686 | 8 => try self.asmMemoryImmediate( | |
| 3687 | .mov, | |
| 3688 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 3689 | if (math.cast(i8, @bitCast(i64, imm))) |small| | |
| 3690 | Immediate.s(small) | |
| 3691 | else | |
| 3692 | Immediate.u(@intCast(u8, imm)), | |
| 3693 | ), | |
| 3694 | 16 => try self.asmMemoryImmediate( | |
| 3695 | .mov, | |
| 3696 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 3697 | if (math.cast(i16, @bitCast(i64, imm))) |small| | |
| 3698 | Immediate.s(small) | |
| 3699 | else | |
| 3700 | Immediate.u(@intCast(u16, imm)), | |
| 3701 | ), | |
| 3702 | 32 => try self.asmMemoryImmediate( | |
| 3703 | .mov, | |
| 3704 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 3705 | if (math.cast(i32, @bitCast(i64, imm))) |small| | |
| 3706 | Immediate.s(small) | |
| 3707 | else | |
| 3708 | Immediate.u(@intCast(u32, imm)), | |
| 3709 | ), | |
| 3710 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| | |
| 3711 | try self.asmMemoryImmediate( | |
| 3712 | .mov, | |
| 3713 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 3714 | Immediate.s(small), | |
| 3715 | ) | |
| 3716 | else | |
| 3717 | try self.asmMemoryRegister( | |
| 3718 | .mov, | |
| 3719 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 3720 | registerAlias(try self.copyToTmpRegister(value_ty, value), abi_size), | |
| 3721 | ), | |
| 3722 | else => unreachable, | |
| 3716 | 3723 | }, |
| 3724 | .register => |src_reg| try self.genInlineMemcpyRegisterRegister( | |
| 3725 | value_ty, | |
| 3726 | reg, | |
| 3727 | src_reg, | |
| 3728 | 0, | |
| 3729 | ), | |
| 3717 | 3730 | .register_overflow => |ro| { |
| 3718 | 3731 | const ro_reg_lock = self.register_manager.lockReg(ro.reg); |
| 3719 | 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 | 3745 | -@intCast(i32, overflow_bit_offset), |
| 3733 | 3746 | ); |
| 3734 | 3747 | }, |
| 3735 | .linker_load, | |
| 3736 | .memory, | |
| 3737 | .stack_offset, | |
| 3738 | => { | |
| 3739 | if (abi_size <= 8) { | |
| 3740 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); | |
| 3741 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | |
| 3742 | } | |
| 3743 | ||
| 3744 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, value, .{ .immediate = abi_size }, .{ | |
| 3745 | .source_stack_base = .rbp, | |
| 3746 | .dest_stack_base = reg.to64(), | |
| 3747 | }); | |
| 3748 | }, | |
| 3748 | .linker_load, .memory, .stack_offset => if (abi_size <= 8) { | |
| 3749 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); | |
| 3750 | try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | |
| 3751 | } else try self.genInlineMemcpy( | |
| 3752 | .{ .stack_offset = 0 }, | |
| 3753 | value, | |
| 3754 | .{ .immediate = abi_size }, | |
| 3755 | .{ .source_stack_base = .rbp, .dest_stack_base = reg.to64() }, | |
| 3756 | ), | |
| 3749 | 3757 | .ptr_stack_offset => { |
| 3750 | 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 | 3772 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 3765 | 3773 | |
| 3766 | 3774 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); |
| 3767 | ||
| 3768 | // To get the actual address of the value we want to modify we have to go through the GOT | |
| 3775 | // Load the pointer, which is stored in memory | |
| 3769 | 3776 | try self.asmRegisterMemory( |
| 3770 | 3777 | .mov, |
| 3771 | 3778 | addr_reg.to64(), |
| ... | ... | @@ -3773,62 +3780,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3773 | 3780 | ); |
| 3774 | 3781 | |
| 3775 | 3782 | const new_ptr = MCValue{ .register = addr_reg.to64() }; |
| 3776 | ||
| 3777 | switch (value) { | |
| 3778 | .immediate => |imm| { | |
| 3779 | if (abi_size > 8) { | |
| 3780 | return self.fail("TODO saving imm to memory for abi_size {}", .{abi_size}); | |
| 3781 | } | |
| 3782 | ||
| 3783 | if (abi_size == 8) { | |
| 3784 | // TODO | |
| 3785 | const top_bits: u32 = @intCast(u32, imm >> 32); | |
| 3786 | const can_extend = if (value_ty.isUnsignedInt()) | |
| 3787 | (top_bits == 0) and (imm & 0x8000_0000) == 0 | |
| 3788 | else | |
| 3789 | top_bits == 0xffff_ffff; | |
| 3790 | ||
| 3791 | if (!can_extend) { | |
| 3792 | return self.fail("TODO imm64 would get incorrectly sign extended", .{}); | |
| 3793 | } | |
| 3794 | } | |
| 3795 | try self.asmMemoryImmediate( | |
| 3796 | .mov, | |
| 3797 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg.to64() }), | |
| 3798 | Immediate.u(@intCast(u32, imm)), | |
| 3799 | ); | |
| 3800 | }, | |
| 3801 | .register => { | |
| 3802 | return self.store(new_ptr, value, ptr_ty, value_ty); | |
| 3803 | }, | |
| 3804 | .linker_load, .memory => { | |
| 3805 | if (abi_size <= 8) { | |
| 3806 | const tmp_reg = try self.register_manager.allocReg(null, gp); | |
| 3807 | const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); | |
| 3808 | defer self.register_manager.unlockReg(tmp_reg_lock); | |
| 3809 | ||
| 3810 | try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value); | |
| 3811 | try self.asmRegisterMemory( | |
| 3812 | .mov, | |
| 3813 | tmp_reg, | |
| 3814 | Memory.sib(.qword, .{ .base = tmp_reg }), | |
| 3815 | ); | |
| 3816 | ||
| 3817 | return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | |
| 3818 | } | |
| 3819 | ||
| 3820 | try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{}); | |
| 3821 | }, | |
| 3822 | .stack_offset => { | |
| 3823 | if (abi_size <= 8) { | |
| 3824 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); | |
| 3825 | return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | |
| 3826 | } | |
| 3827 | ||
| 3828 | try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{}); | |
| 3829 | }, | |
| 3830 | else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}), | |
| 3831 | } | |
| 3783 | try self.store(new_ptr, value, ptr_ty, value_ty); | |
| 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 | 4838 | registerAlias(src_reg, abi_size), |
| 4887 | 4839 | ), |
| 4888 | 4840 | }, |
| 4889 | .immediate => |imm| { | |
| 4890 | switch (self.regBitSize(ty)) { | |
| 4891 | 8 => try self.asmRegisterImmediate( | |
| 4892 | mir_tag, | |
| 4893 | dst_alias, | |
| 4894 | if (math.cast(i8, @bitCast(i64, imm))) |small| | |
| 4895 | Immediate.s(small) | |
| 4896 | else | |
| 4897 | Immediate.u(@intCast(u8, imm)), | |
| 4898 | ), | |
| 4899 | 16 => try self.asmRegisterImmediate( | |
| 4900 | mir_tag, | |
| 4901 | dst_alias, | |
| 4902 | if (math.cast(i16, @bitCast(i64, imm))) |small| | |
| 4903 | Immediate.s(small) | |
| 4904 | else | |
| 4905 | Immediate.u(@intCast(u16, imm)), | |
| 4906 | ), | |
| 4907 | 32 => try self.asmRegisterImmediate( | |
| 4908 | mir_tag, | |
| 4909 | dst_alias, | |
| 4910 | if (math.cast(i32, @bitCast(i64, imm))) |small| | |
| 4911 | Immediate.s(small) | |
| 4912 | else | |
| 4913 | Immediate.u(@intCast(u32, imm)), | |
| 4914 | ), | |
| 4915 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| | |
| 4916 | try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small)) | |
| 4841 | .immediate => |imm| switch (self.regBitSize(ty)) { | |
| 4842 | 8 => try self.asmRegisterImmediate( | |
| 4843 | mir_tag, | |
| 4844 | dst_alias, | |
| 4845 | if (math.cast(i8, @bitCast(i64, imm))) |small| | |
| 4846 | Immediate.s(small) | |
| 4917 | 4847 | else |
| 4918 | try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias( | |
| 4919 | try self.copyToTmpRegister(ty, src_mcv), | |
| 4920 | abi_size, | |
| 4921 | )), | |
| 4922 | else => unreachable, | |
| 4923 | } | |
| 4848 | Immediate.u(@intCast(u8, imm)), | |
| 4849 | ), | |
| 4850 | 16 => try self.asmRegisterImmediate( | |
| 4851 | mir_tag, | |
| 4852 | dst_alias, | |
| 4853 | if (math.cast(i16, @bitCast(i64, imm))) |small| | |
| 4854 | Immediate.s(small) | |
| 4855 | else | |
| 4856 | Immediate.u(@intCast(u16, imm)), | |
| 4857 | ), | |
| 4858 | 32 => try self.asmRegisterImmediate( | |
| 4859 | mir_tag, | |
| 4860 | dst_alias, | |
| 4861 | if (math.cast(i32, @bitCast(i64, imm))) |small| | |
| 4862 | Immediate.s(small) | |
| 4863 | else | |
| 4864 | Immediate.u(@intCast(u32, imm)), | |
| 4865 | ), | |
| 4866 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| | |
| 4867 | try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small)) | |
| 4868 | else | |
| 4869 | try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias( | |
| 4870 | try self.copyToTmpRegister(ty, src_mcv), | |
| 4871 | abi_size, | |
| 4872 | )), | |
| 4873 | else => unreachable, | |
| 4924 | 4874 | }, |
| 4925 | 4875 | .memory, .linker_load, .eflags => { |
| 4926 | 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 | 4880 | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 4931 | 4881 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); |
| 4932 | 4882 | }, |
| 4933 | .stack_offset => |off| { | |
| 4934 | try self.asmRegisterMemory( | |
| 4935 | mir_tag, | |
| 4936 | registerAlias(dst_reg, abi_size), | |
| 4937 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }), | |
| 4938 | ); | |
| 4939 | }, | |
| 4883 | .stack_offset => |off| try self.asmRegisterMemory( | |
| 4884 | mir_tag, | |
| 4885 | registerAlias(dst_reg, abi_size), | |
| 4886 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }), | |
| 4887 | ), | |
| 4940 | 4888 | } |
| 4941 | 4889 | }, |
| 4942 | 4890 | .memory, .linker_load, .stack_offset => { |
| ... | ... | @@ -5654,7 +5602,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 5654 | 5602 | |
| 5655 | 5603 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 5656 | 5604 | const rhs_lock = switch (rhs_mcv) { |
| 5657 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | |
| 5605 | .register => |reg| self.register_manager.lockReg(reg), | |
| 5658 | 5606 | else => null, |
| 5659 | 5607 | }; |
| 5660 | 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 | 5650 | |
| 5703 | 5651 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 5704 | 5652 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5705 | const operand = try self.resolveInst(un_op); | |
| 5706 | _ = operand; | |
| 5707 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch}); | |
| 5653 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 5654 | const addr_reg = try self.register_manager.allocReg(null, gp); | |
| 5655 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | |
| 5656 | defer self.register_manager.unlockReg(addr_lock); | |
| 5657 | ||
| 5658 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 5659 | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( | |
| 5660 | .{ .kind = .const_data, .ty = Type.anyerror }, | |
| 5661 | 4, // dword alignment | |
| 5662 | ); | |
| 5663 | const got_addr = elf_file.getAtom(atom_index).getOffsetTableAddress(elf_file); | |
| 5664 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ | |
| 5665 | .base = .ds, | |
| 5666 | .disp = @intCast(i32, got_addr), | |
| 5667 | })); | |
| 5668 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | |
| 5669 | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( | |
| 5670 | .{ .kind = .const_data, .ty = Type.anyerror }, | |
| 5671 | 4, // dword alignment | |
| 5672 | ); | |
| 5673 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | |
| 5674 | try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{ | |
| 5675 | .type = .got, | |
| 5676 | .sym_index = sym_index, | |
| 5677 | } }); | |
| 5678 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | |
| 5679 | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( | |
| 5680 | .{ .kind = .const_data, .ty = Type.anyerror }, | |
| 5681 | 4, // dword alignment | |
| 5682 | ); | |
| 5683 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | |
| 5684 | try self.genSetReg(Type.usize, addr_reg, .{ .linker_load = .{ | |
| 5685 | .type = .got, | |
| 5686 | .sym_index = sym_index, | |
| 5687 | } }); | |
| 5688 | } else { | |
| 5689 | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); | |
| 5690 | } | |
| 5691 | ||
| 5692 | try self.spillEflagsIfOccupied(); | |
| 5693 | self.eflags_inst = inst; | |
| 5694 | ||
| 5695 | const op_ty = self.air.typeOf(un_op); | |
| 5696 | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); | |
| 5697 | const op_mcv = try self.resolveInst(un_op); | |
| 5698 | const dst_reg = switch (op_mcv) { | |
| 5699 | .register => |reg| reg, | |
| 5700 | else => try self.copyToTmpRegister(op_ty, op_mcv), | |
| 5701 | }; | |
| 5702 | try self.asmRegisterMemory( | |
| 5703 | .cmp, | |
| 5704 | registerAlias(dst_reg, op_abi_size), | |
| 5705 | Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = addr_reg }), | |
| 5706 | ); | |
| 5707 | break :result .{ .eflags = .b }; | |
| 5708 | }; | |
| 5708 | 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 | 6185 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| 6185 | 6186 | const body = self.air.extra[loop.end..][0..loop.data.body_len]; |
| 6186 | 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 | 6210 | _ = try self.asmJmpReloc(jmp_target); |
| 6189 | 6211 | return self.finishAirBookkeeping(); |
| 6190 | 6212 | } |
| ... | ... | @@ -6570,7 +6592,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6570 | 6592 | return self.fail("unrecognized constraint: '{s}'", .{constraint}); |
| 6571 | 6593 | args.putAssumeCapacity(name, mcv); |
| 6572 | 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 | 6597 | else => {}, |
| 6575 | 6598 | } |
| 6576 | 6599 | if (output == .none) result = mcv; |
| ... | ... | @@ -6609,70 +6632,139 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6609 | 6632 | } |
| 6610 | 6633 | |
| 6611 | 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 | 6636 | while (line_it.next()) |line| { |
| 6614 | 6637 | var mnem_it = mem.tokenize(u8, line, " \t"); |
| 6615 | const mnem = mnem_it.next() orelse continue; | |
| 6616 | if (mem.startsWith(u8, mnem, "#")) continue; | |
| 6617 | var arg_it = mem.tokenize(u8, mnem_it.rest(), ", "); | |
| 6618 | if (std.ascii.eqlIgnoreCase(mnem, "syscall")) { | |
| 6619 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | |
| 6620 | return self.fail("Too many operands: '{s}'", .{line}); | |
| 6621 | try self.asmOpOnly(.syscall); | |
| 6622 | } else if (std.ascii.eqlIgnoreCase(mnem, "push")) { | |
| 6623 | const src = arg_it.next() orelse | |
| 6624 | return self.fail("Not enough operands: '{s}'", .{line}); | |
| 6625 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | |
| 6626 | return self.fail("Too many operands: '{s}'", .{line}); | |
| 6627 | if (mem.startsWith(u8, src, "$")) { | |
| 6628 | const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch | |
| 6629 | return self.fail("Invalid immediate: '{s}'", .{src}); | |
| 6630 | try self.asmImmediate(.push, Immediate.u(imm)); | |
| 6631 | } else if (mem.startsWith(u8, src, "%%")) { | |
| 6632 | const reg = parseRegName(src["%%".len..]) orelse | |
| 6633 | return self.fail("Invalid register: '{s}'", .{src}); | |
| 6634 | try self.asmRegister(.push, reg); | |
| 6635 | } else return self.fail("Unsupported operand: '{s}'", .{src}); | |
| 6636 | } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) { | |
| 6637 | const dst = arg_it.next() orelse | |
| 6638 | return self.fail("Not enough operands: '{s}'", .{line}); | |
| 6639 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | |
| 6640 | return self.fail("Too many operands: '{s}'", .{line}); | |
| 6641 | if (mem.startsWith(u8, dst, "%%")) { | |
| 6642 | const reg = parseRegName(dst["%%".len..]) orelse | |
| 6643 | return self.fail("Invalid register: '{s}'", .{dst}); | |
| 6644 | try self.asmRegister(.pop, reg); | |
| 6645 | } else return self.fail("Unsupported operand: '{s}'", .{dst}); | |
| 6646 | } else if (std.ascii.eqlIgnoreCase(mnem, "movq")) { | |
| 6647 | const src = arg_it.next() orelse | |
| 6648 | return self.fail("Not enough operands: '{s}'", .{line}); | |
| 6649 | const dst = arg_it.next() orelse | |
| 6650 | return self.fail("Not enough operands: '{s}'", .{line}); | |
| 6651 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | |
| 6652 | return self.fail("Too many operands: '{s}'", .{line}); | |
| 6653 | if (mem.startsWith(u8, src, "%%")) { | |
| 6654 | const colon = mem.indexOfScalarPos(u8, src, "%%".len + 2, ':'); | |
| 6655 | const src_reg = parseRegName(src["%%".len .. colon orelse src.len]) orelse | |
| 6656 | return self.fail("Invalid register: '{s}'", .{src}); | |
| 6638 | const mnem_str = mnem_it.next() orelse continue; | |
| 6639 | if (mem.startsWith(u8, mnem_str, "#")) continue; | |
| 6640 | ||
| 6641 | const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b")) | |
| 6642 | .byte | |
| 6643 | else if (mem.endsWith(u8, mnem_str, "w")) | |
| 6644 | .word | |
| 6645 | else if (mem.endsWith(u8, mnem_str, "l")) | |
| 6646 | .dword | |
| 6647 | else if (mem.endsWith(u8, mnem_str, "q")) | |
| 6648 | .qword | |
| 6649 | else | |
| 6650 | null; | |
| 6651 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse | |
| 6652 | (if (mnem_size) |_| | |
| 6653 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) | |
| 6654 | else | |
| 6655 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); | |
| 6656 | ||
| 6657 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); | |
| 6658 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; | |
| 6659 | for (&ops) |*op| { | |
| 6660 | const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); | |
| 6661 | if (mem.startsWith(u8, op_str, "#")) break; | |
| 6662 | if (mem.startsWith(u8, op_str, "%%")) { | |
| 6663 | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); | |
| 6664 | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse | |
| 6665 | return self.fail("Invalid register: '{s}'", .{op_str}); | |
| 6657 | 6666 | if (colon) |colon_pos| { |
| 6658 | const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch | |
| 6659 | return self.fail("Invalid immediate: '{s}'", .{src}); | |
| 6660 | if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) { | |
| 6661 | switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse | |
| 6662 | return self.fail("no matching constraint for: '{s}'", .{dst})) { | |
| 6663 | .register => |dst_reg| try self.asmRegisterMemory( | |
| 6664 | .mov, | |
| 6665 | dst_reg, | |
| 6666 | Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }), | |
| 6667 | ), | |
| 6668 | else => return self.fail("Invalid constraint: '{s}'", .{dst}), | |
| 6669 | } | |
| 6670 | } else return self.fail("Unsupported operand: '{s}'", .{dst}); | |
| 6671 | } else return self.fail("Unsupported operand: '{s}'", .{src}); | |
| 6672 | } | |
| 6673 | } else { | |
| 6674 | return self.fail("Unsupported instruction: '{s}'", .{mnem}); | |
| 6675 | } | |
| 6667 | const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch | |
| 6668 | return self.fail("Invalid displacement: '{s}'", .{op_str}); | |
| 6669 | op.* = .{ .mem = Memory.sib( | |
| 6670 | mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}), | |
| 6671 | .{ .base = reg, .disp = disp }, | |
| 6672 | ) }; | |
| 6673 | } else { | |
| 6674 | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) | |
| 6675 | return self.fail("Invalid register size: '{s}'", .{op_str}); | |
| 6676 | op.* = .{ .reg = reg }; | |
| 6677 | } | |
| 6678 | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { | |
| 6679 | switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse | |
| 6680 | return self.fail("No matching constraint: '{s}'", .{op_str})) { | |
| 6681 | .register => |reg| op.* = .{ .reg = reg }, | |
| 6682 | else => return self.fail("Invalid constraint: '{s}'", .{op_str}), | |
| 6683 | } | |
| 6684 | } else if (mem.startsWith(u8, op_str, "$")) { | |
| 6685 | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { | |
| 6686 | if (mnem_size) |size| { | |
| 6687 | const max = @as(u64, std.math.maxInt(u64)) >> | |
| 6688 | @intCast(u6, 64 - (size.bitSize() - 1)); | |
| 6689 | if ((if (s < 0) ~s else s) > max) | |
| 6690 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); | |
| 6691 | } | |
| 6692 | op.* = .{ .imm = Immediate.s(s) }; | |
| 6693 | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { | |
| 6694 | if (mnem_size) |size| { | |
| 6695 | const max = @as(u64, std.math.maxInt(u64)) >> | |
| 6696 | @intCast(u6, 64 - size.bitSize()); | |
| 6697 | if (u > max) | |
| 6698 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); | |
| 6699 | } | |
| 6700 | op.* = .{ .imm = Immediate.u(u) }; | |
| 6701 | } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str}); | |
| 6702 | } else return self.fail("Invalid operand: '{s}'", .{op_str}); | |
| 6703 | } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str}); | |
| 6704 | ||
| 6705 | (switch (ops[0]) { | |
| 6706 | .none => self.asmOpOnly(mnem), | |
| 6707 | .reg => |reg0| switch (ops[1]) { | |
| 6708 | .none => self.asmRegister(mnem, reg0), | |
| 6709 | .reg => |reg1| switch (ops[2]) { | |
| 6710 | .none => self.asmRegisterRegister(mnem, reg1, reg0), | |
| 6711 | .reg => |reg2| switch (ops[3]) { | |
| 6712 | .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0), | |
| 6713 | else => error.InvalidInstruction, | |
| 6714 | }, | |
| 6715 | .mem => |mem2| switch (ops[3]) { | |
| 6716 | .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0), | |
| 6717 | else => error.InvalidInstruction, | |
| 6718 | }, | |
| 6719 | else => error.InvalidInstruction, | |
| 6720 | }, | |
| 6721 | .mem => |mem1| switch (ops[2]) { | |
| 6722 | .none => self.asmMemoryRegister(mnem, mem1, reg0), | |
| 6723 | else => error.InvalidInstruction, | |
| 6724 | }, | |
| 6725 | else => error.InvalidInstruction, | |
| 6726 | }, | |
| 6727 | .mem => |mem0| switch (ops[1]) { | |
| 6728 | .none => self.asmMemory(mnem, mem0), | |
| 6729 | .reg => |reg1| switch (ops[2]) { | |
| 6730 | .none => self.asmRegisterMemory(mnem, reg1, mem0), | |
| 6731 | else => error.InvalidInstruction, | |
| 6732 | }, | |
| 6733 | else => error.InvalidInstruction, | |
| 6734 | }, | |
| 6735 | .imm => |imm0| switch (ops[1]) { | |
| 6736 | .none => self.asmImmediate(mnem, imm0), | |
| 6737 | .reg => |reg1| switch (ops[2]) { | |
| 6738 | .none => self.asmRegisterImmediate(mnem, reg1, imm0), | |
| 6739 | .reg => |reg2| switch (ops[3]) { | |
| 6740 | .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0), | |
| 6741 | else => error.InvalidInstruction, | |
| 6742 | }, | |
| 6743 | .mem => |mem2| switch (ops[3]) { | |
| 6744 | .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0), | |
| 6745 | else => error.InvalidInstruction, | |
| 6746 | }, | |
| 6747 | else => error.InvalidInstruction, | |
| 6748 | }, | |
| 6749 | .mem => |mem1| switch (ops[2]) { | |
| 6750 | .none => self.asmMemoryImmediate(mnem, mem1, imm0), | |
| 6751 | else => error.InvalidInstruction, | |
| 6752 | }, | |
| 6753 | else => error.InvalidInstruction, | |
| 6754 | }, | |
| 6755 | }) catch |err| switch (err) { | |
| 6756 | error.InvalidInstruction => return self.fail( | |
| 6757 | "Invalid instruction: '{s} {s} {s} {s} {s}'", | |
| 6758 | .{ | |
| 6759 | @tagName(mnem), | |
| 6760 | @tagName(ops[0]), | |
| 6761 | @tagName(ops[1]), | |
| 6762 | @tagName(ops[2]), | |
| 6763 | @tagName(ops[3]), | |
| 6764 | }, | |
| 6765 | ), | |
| 6766 | else => |e| return e, | |
| 6767 | }; | |
| 6676 | 6768 | } |
| 6677 | 6769 | } |
| 6678 | 6770 | |
| ... | ... | @@ -7988,12 +8080,12 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 7988 | 8080 | try self.asmRegisterMemory(.mov, start_reg.to32(), Memory.sib(.dword, .{ |
| 7989 | 8081 | .base = addr_reg.to64(), |
| 7990 | 8082 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| 7991 | .disp = 0, | |
| 8083 | .disp = 4, | |
| 7992 | 8084 | })); |
| 7993 | 8085 | try self.asmRegisterMemory(.mov, end_reg.to32(), Memory.sib(.dword, .{ |
| 7994 | 8086 | .base = addr_reg.to64(), |
| 7995 | 8087 | .scale_index = .{ .scale = 4, .index = err_reg.to64() }, |
| 7996 | .disp = 4, | |
| 8088 | .disp = 8, | |
| 7997 | 8089 | })); |
| 7998 | 8090 | try self.asmRegisterRegister(.sub, end_reg.to32(), start_reg.to32()); |
| 7999 | 8091 | try self.asmRegisterMemory(.lea, start_reg.to64(), Memory.sib(.byte, .{ |
src/codegen.zig+7-3| ... | ... | @@ -124,13 +124,17 @@ pub fn generateLazySymbol( |
| 124 | 124 | |
| 125 | 125 | if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) { |
| 126 | 126 | const err_names = mod.error_name_list.items; |
| 127 | try code.resize(err_names.len * 4); | |
| 128 | for (err_names, 0..) |err_name, index| { | |
| 129 | mem.writeInt(u32, code.items[index * 4 ..][0..4], @intCast(u32, code.items.len), endian); | |
| 127 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); | |
| 128 | var offset = code.items.len; | |
| 129 | try code.resize((1 + err_names.len + 1) * 4); | |
| 130 | for (err_names) |err_name| { | |
| 131 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); | |
| 132 | offset += 4; | |
| 130 | 133 | try code.ensureUnusedCapacity(err_name.len + 1); |
| 131 | 134 | code.appendSliceAssumeCapacity(err_name); |
| 132 | 135 | code.appendAssumeCapacity(0); |
| 133 | 136 | } |
| 137 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); | |
| 134 | 138 | return Result.ok; |
| 135 | 139 | } else return .{ .fail = try ErrorMsg.create( |
| 136 | 140 | bin_file.allocator, |
src/link.zig+12-14| ... | ... | @@ -1106,23 +1106,21 @@ pub const File = struct { |
| 1106 | 1106 | }; |
| 1107 | 1107 | |
| 1108 | 1108 | pub const LazySymbol = struct { |
| 1109 | kind: enum { code, const_data }, | |
| 1110 | ty: Type, | |
| 1109 | pub const Kind = enum { code, const_data }; | |
| 1111 | 1110 | |
| 1112 | pub const Context = struct { | |
| 1113 | mod: *Module, | |
| 1111 | kind: Kind, | |
| 1112 | ty: Type, | |
| 1114 | 1113 | |
| 1115 | pub fn hash(ctx: @This(), sym: LazySymbol) u32 { | |
| 1116 | var hasher = std.hash.Wyhash.init(0); | |
| 1117 | std.hash.autoHash(&hasher, sym.kind); | |
| 1118 | sym.ty.hashWithHasher(&hasher, ctx.mod); | |
| 1119 | return @truncate(u32, hasher.final()); | |
| 1120 | } | |
| 1114 | pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol { | |
| 1115 | return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index| | |
| 1116 | mod.declPtr(decl_index).val.castTag(.ty).?.data | |
| 1117 | else | |
| 1118 | Type.anyerror }; | |
| 1119 | } | |
| 1121 | 1120 | |
| 1122 | pub fn eql(ctx: @This(), lhs: LazySymbol, rhs: LazySymbol, _: usize) bool { | |
| 1123 | return lhs.kind == rhs.kind and lhs.ty.eql(rhs.ty, ctx.mod); | |
| 1124 | } | |
| 1125 | }; | |
| 1121 | pub fn getDecl(self: LazySymbol) Module.Decl.OptionalIndex { | |
| 1122 | return Module.Decl.OptionalIndex.init(self.ty.getOwnerDeclOrNull()); | |
| 1123 | } | |
| 1126 | 1124 | }; |
| 1127 | 1125 | |
| 1128 | 1126 | pub const C = @import("link/C.zig"); |
src/link/Coff.zig+48-51| ... | ... | @@ -145,16 +145,11 @@ const Section = struct { |
| 145 | 145 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 146 | 146 | }; |
| 147 | 147 | |
| 148 | const LazySymbolTable = std.ArrayHashMapUnmanaged( | |
| 149 | link.File.LazySymbol, | |
| 150 | LazySymbolMetadata, | |
| 151 | link.File.LazySymbol.Context, | |
| 152 | true, | |
| 153 | ); | |
| 148 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | |
| 154 | 149 | |
| 155 | 150 | const LazySymbolMetadata = struct { |
| 156 | atom: Atom.Index, | |
| 157 | section: u16, | |
| 151 | text_atom: ?Atom.Index = null, | |
| 152 | rdata_atom: ?Atom.Index = null, | |
| 158 | 153 | alignment: u32, |
| 159 | 154 | }; |
| 160 | 155 | |
| ... | ... | @@ -1176,10 +1171,28 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 1176 | 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 | 1191 | self: *Coff, |
| 1181 | lazy_sym: link.File.LazySymbol, | |
| 1182 | lazy_metadata: LazySymbolMetadata, | |
| 1192 | sym: link.File.LazySymbol, | |
| 1193 | atom_index: Atom.Index, | |
| 1194 | section_index: u16, | |
| 1195 | required_alignment: u32, | |
| 1183 | 1196 | ) !void { |
| 1184 | 1197 | const gpa = self.base.allocator; |
| 1185 | 1198 | const mod = self.base.options.module.?; |
| ... | ... | @@ -1188,16 +1201,15 @@ fn updateLazySymbol( |
| 1188 | 1201 | defer code_buffer.deinit(); |
| 1189 | 1202 | |
| 1190 | 1203 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ |
| 1191 | @tagName(lazy_sym.kind), | |
| 1192 | lazy_sym.ty.fmt(mod), | |
| 1204 | @tagName(sym.kind), | |
| 1205 | sym.ty.fmt(mod), | |
| 1193 | 1206 | }); |
| 1194 | 1207 | defer gpa.free(name); |
| 1195 | 1208 | |
| 1196 | const atom_index = lazy_metadata.atom; | |
| 1197 | 1209 | const atom = self.getAtomPtr(atom_index); |
| 1198 | 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 | 1213 | mod.declPtr(owner_decl).srcLoc() |
| 1202 | 1214 | else |
| 1203 | 1215 | Module.SrcLoc{ |
| ... | ... | @@ -1205,14 +1217,9 @@ fn updateLazySymbol( |
| 1205 | 1217 | .parent_decl_node = undefined, |
| 1206 | 1218 | .lazy = .unneeded, |
| 1207 | 1219 | }; |
| 1208 | const res = try codegen.generateLazySymbol( | |
| 1209 | &self.base, | |
| 1210 | src, | |
| 1211 | lazy_sym, | |
| 1212 | &code_buffer, | |
| 1213 | .none, | |
| 1214 | .{ .parent_atom_index = local_sym_index }, | |
| 1215 | ); | |
| 1220 | const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ | |
| 1221 | .parent_atom_index = local_sym_index, | |
| 1222 | }); | |
| 1216 | 1223 | const code = switch (res) { |
| 1217 | 1224 | .ok => code_buffer.items, |
| 1218 | 1225 | .fail => |em| { |
| ... | ... | @@ -1221,11 +1228,10 @@ fn updateLazySymbol( |
| 1221 | 1228 | }, |
| 1222 | 1229 | }; |
| 1223 | 1230 | |
| 1224 | const required_alignment = lazy_metadata.alignment; | |
| 1225 | 1231 | const code_len = @intCast(u32, code.len); |
| 1226 | 1232 | const symbol = atom.getSymbolPtr(self); |
| 1227 | 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 | 1235 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; |
| 1230 | 1236 | |
| 1231 | 1237 | const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); |
| ... | ... | @@ -1250,24 +1256,18 @@ fn updateLazySymbol( |
| 1250 | 1256 | |
| 1251 | 1257 | pub fn getOrCreateAtomForLazySymbol( |
| 1252 | 1258 | self: *Coff, |
| 1253 | lazy_sym: link.File.LazySymbol, | |
| 1259 | sym: link.File.LazySymbol, | |
| 1254 | 1260 | alignment: u32, |
| 1255 | 1261 | ) !Atom.Index { |
| 1256 | const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{ | |
| 1257 | .mod = self.base.options.module.?, | |
| 1258 | }); | |
| 1262 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | |
| 1259 | 1263 | errdefer _ = self.lazy_syms.pop(); |
| 1260 | if (!gop.found_existing) { | |
| 1261 | gop.value_ptr.* = .{ | |
| 1262 | .atom = try self.createAtom(), | |
| 1263 | .section = switch (lazy_sym.kind) { | |
| 1264 | .code => self.text_section_index.?, | |
| 1265 | .const_data => self.rdata_section_index.?, | |
| 1266 | }, | |
| 1267 | .alignment = alignment, | |
| 1268 | }; | |
| 1269 | } | |
| 1270 | return gop.value_ptr.atom; | |
| 1264 | if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; | |
| 1265 | const atom = switch (sym.kind) { | |
| 1266 | .code => &gop.value_ptr.text_atom, | |
| 1267 | .const_data => &gop.value_ptr.rdata_atom, | |
| 1268 | }; | |
| 1269 | if (atom.* == null) atom.* = try self.createAtom(); | |
| 1270 | return atom.*.?; | |
| 1271 | 1271 | } |
| 1272 | 1272 | |
| 1273 | 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 | 1600 | sub_prog_node.activate(); |
| 1601 | 1601 | defer sub_prog_node.end(); |
| 1602 | 1602 | |
| 1603 | { | |
| 1604 | var lazy_it = self.lazy_syms.iterator(); | |
| 1605 | while (lazy_it.next()) |lazy_entry| { | |
| 1606 | self.updateLazySymbol( | |
| 1607 | lazy_entry.key_ptr.*, | |
| 1608 | lazy_entry.value_ptr.*, | |
| 1609 | ) catch |err| switch (err) { | |
| 1610 | error.CodegenFail => return error.FlushFailure, | |
| 1611 | else => |e| return e, | |
| 1612 | }; | |
| 1613 | } | |
| 1603 | // Most lazy symbols can be updated when the corresponding decl is, | |
| 1604 | // so we only have to worry about the one without an associated decl. | |
| 1605 | if (self.lazy_syms.get(.none)) |metadata| { | |
| 1606 | self.updateLazySymbol(.none, metadata) catch |err| switch (err) { | |
| 1607 | error.CodegenFail => return error.FlushFailure, | |
| 1608 | else => |e| return e, | |
| 1609 | }; | |
| 1614 | 1610 | } |
| 1615 | 1611 | |
| 1616 | 1612 | const gpa = self.base.allocator; |
| ... | ... | @@ -2489,6 +2485,7 @@ const Module = @import("../Module.zig"); |
| 2489 | 2485 | const Object = @import("Coff/Object.zig"); |
| 2490 | 2486 | const Relocation = @import("Coff/Relocation.zig"); |
| 2491 | 2487 | const StringTable = @import("strtab.zig").StringTable; |
| 2488 | const Type = @import("../type.zig").Type; | |
| 2492 | 2489 | const TypedValue = @import("../TypedValue.zig"); |
| 2493 | 2490 | |
| 2494 | 2491 | pub const base_tag: link.File.Tag = .coff; |
src/link/Elf.zig+119-82| ... | ... | @@ -64,8 +64,8 @@ const Section = struct { |
| 64 | 64 | }; |
| 65 | 65 | |
| 66 | 66 | const LazySymbolMetadata = struct { |
| 67 | atom: Atom.Index, | |
| 68 | shdr: u16, | |
| 67 | text_atom: ?Atom.Index = null, | |
| 68 | rodata_atom: ?Atom.Index = null, | |
| 69 | 69 | alignment: u32, |
| 70 | 70 | }; |
| 71 | 71 | |
| ... | ... | @@ -106,7 +106,12 @@ shdr_table_offset: ?u64 = null, |
| 106 | 106 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. |
| 107 | 107 | /// Same order as in the file. |
| 108 | 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 | 115 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags |
| 111 | 116 | phdr_load_re_index: ?u16 = null, |
| 112 | 117 | /// The index into the program headers of the global offset table. |
| ... | ... | @@ -203,7 +208,7 @@ relocs: RelocTable = .{}, |
| 203 | 208 | |
| 204 | 209 | const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc)); |
| 205 | 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 | 213 | /// When allocating, the ideal_capacity is calculated by |
| 209 | 214 | /// actual_capacity + (actual_capacity / ideal_factor) |
| ... | ... | @@ -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 | 404 | for (self.sections.items(.shdr)) |section| { |
| 410 | 405 | const increased_size = padToIdeal(section.sh_size); |
| 411 | 406 | const test_end = section.sh_offset + increased_size; |
| ... | ... | @@ -430,9 +425,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 { |
| 430 | 425 | if (self.shdr_table_offset) |off| { |
| 431 | 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 | 428 | for (self.sections.items(.shdr)) |section| { |
| 437 | 429 | if (section.sh_offset <= start) continue; |
| 438 | 430 | if (section.sh_offset < min_pos) min_pos = section.sh_offset; |
| ... | ... | @@ -462,6 +454,43 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 462 | 454 | }; |
| 463 | 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 | 494 | if (self.phdr_load_re_index == null) { |
| 466 | 495 | self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); |
| 467 | 496 | const file_size = self.base.options.program_code_size_hint; |
| ... | ... | @@ -849,19 +878,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 849 | 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 | 882 | // Iterate over symbols, populating free_list and last_text_block. |
| 867 | 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 | 1037 | sub_prog_node.activate(); |
| 1022 | 1038 | defer sub_prog_node.end(); |
| 1023 | 1039 | |
| 1024 | { | |
| 1025 | var lazy_it = self.lazy_syms.iterator(); | |
| 1026 | while (lazy_it.next()) |lazy_entry| { | |
| 1027 | self.updateLazySymbol( | |
| 1028 | lazy_entry.key_ptr.*, | |
| 1029 | lazy_entry.value_ptr.*, | |
| 1030 | ) catch |err| switch (err) { | |
| 1031 | error.CodegenFail => return error.FlushFailure, | |
| 1032 | else => |e| return e, | |
| 1033 | }; | |
| 1034 | } | |
| 1040 | // Most lazy symbols can be updated when the corresponding decl is, | |
| 1041 | // so we only have to worry about the one without an associated decl. | |
| 1042 | if (self.lazy_syms.get(.none)) |metadata| { | |
| 1043 | self.updateLazySymbol(.none, metadata) catch |err| switch (err) { | |
| 1044 | error.CodegenFail => return error.FlushFailure, | |
| 1045 | else => |e| return e, | |
| 1046 | }; | |
| 1035 | 1047 | } |
| 1036 | 1048 | |
| 1037 | 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 | 1144 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| 1133 | 1145 | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 1134 | 1146 | }; |
| 1135 | const phalign: u16 = switch (self.ptr_width) { | |
| 1136 | .p32 => @alignOf(elf.Elf32_Phdr), | |
| 1137 | .p64 => @alignOf(elf.Elf64_Phdr), | |
| 1138 | }; | |
| 1139 | const allocated_size = self.allocatedSize(self.phdr_table_offset.?); | |
| 1147 | ||
| 1148 | const phdr_table_index = self.phdr_table_index.?; | |
| 1149 | const phdr_table = &self.program_headers.items[phdr_table_index]; | |
| 1150 | const phdr_table_load = &self.program_headers.items[self.phdr_table_load_index.?]; | |
| 1151 | ||
| 1152 | const allocated_size = self.allocatedSize(phdr_table.p_offset); | |
| 1140 | 1153 | const needed_size = self.program_headers.items.len * phsize; |
| 1141 | 1154 | |
| 1142 | 1155 | if (needed_size > allocated_size) { |
| 1143 | self.phdr_table_offset = null; // free the space | |
| 1144 | self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); | |
| 1156 | phdr_table.p_offset = 0; // free the space | |
| 1157 | phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align)); | |
| 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 | 1170 | switch (self.ptr_width) { |
| 1148 | 1171 | .p32 => { |
| 1149 | 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 | 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 | 1183 | .p64 => { |
| 1161 | 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 | 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 | 1201 | self.phdr_table_dirty = false; |
| 1174 | 1202 | } |
| 1175 | 1203 | |
| ... | ... | @@ -1992,13 +2020,14 @@ fn writeElfHeader(self: *Elf) !void { |
| 1992 | 2020 | |
| 1993 | 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 | 2024 | switch (self.ptr_width) { |
| 1996 | 2025 | .p32 => { |
| 1997 | 2026 | mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian); |
| 1998 | 2027 | index += 4; |
| 1999 | 2028 | |
| 2000 | 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 | 2031 | index += 4; |
| 2003 | 2032 | |
| 2004 | 2033 | // e_shoff |
| ... | ... | @@ -2011,7 +2040,7 @@ fn writeElfHeader(self: *Elf) !void { |
| 2011 | 2040 | index += 8; |
| 2012 | 2041 | |
| 2013 | 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 | 2044 | index += 8; |
| 2016 | 2045 | |
| 2017 | 2046 | // e_shoff |
| ... | ... | @@ -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 { | |
| 2371 | const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{ | |
| 2372 | .mod = self.base.options.module.?, | |
| 2373 | }); | |
| 2399 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index { | |
| 2400 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | |
| 2374 | 2401 | errdefer _ = self.lazy_syms.pop(); |
| 2375 | if (!gop.found_existing) { | |
| 2376 | gop.value_ptr.* = .{ | |
| 2377 | .atom = try self.createAtom(), | |
| 2378 | .shdr = switch (lazy_sym.kind) { | |
| 2379 | .code => self.text_section_index.?, | |
| 2380 | .const_data => self.rodata_section_index.?, | |
| 2381 | }, | |
| 2382 | .alignment = alignment, | |
| 2383 | }; | |
| 2384 | } | |
| 2385 | return gop.value_ptr.atom; | |
| 2402 | if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; | |
| 2403 | const atom = switch (sym.kind) { | |
| 2404 | .code => &gop.value_ptr.text_atom, | |
| 2405 | .const_data => &gop.value_ptr.rodata_atom, | |
| 2406 | }; | |
| 2407 | if (atom.* == null) atom.* = try self.createAtom(); | |
| 2408 | return atom.*.?; | |
| 2386 | 2409 | } |
| 2387 | 2410 | |
| 2388 | 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 | 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 | 2700 | const gpa = self.base.allocator; |
| 2656 | 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 | 2705 | |
| 2661 | 2706 | const name_str_index = blk: { |
| 2662 | 2707 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ |
| 2663 | @tagName(lazy_sym.kind), | |
| 2664 | lazy_sym.ty.fmt(mod), | |
| 2708 | @tagName(sym.kind), | |
| 2709 | sym.ty.fmt(mod), | |
| 2665 | 2710 | }); |
| 2666 | 2711 | defer gpa.free(name); |
| 2667 | 2712 | break :blk try self.shstrtab.insert(gpa, name); |
| 2668 | 2713 | }; |
| 2669 | 2714 | const name = self.shstrtab.get(name_str_index).?; |
| 2670 | 2715 | |
| 2671 | const atom_index = lazy_metadata.atom; | |
| 2672 | 2716 | const atom = self.getAtom(atom_index); |
| 2673 | 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 | 2720 | mod.declPtr(owner_decl).srcLoc() |
| 2677 | 2721 | else |
| 2678 | 2722 | Module.SrcLoc{ |
| ... | ... | @@ -2680,14 +2724,9 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy |
| 2680 | 2724 | .parent_decl_node = undefined, |
| 2681 | 2725 | .lazy = .unneeded, |
| 2682 | 2726 | }; |
| 2683 | const res = try codegen.generateLazySymbol( | |
| 2684 | &self.base, | |
| 2685 | src, | |
| 2686 | lazy_sym, | |
| 2687 | &code_buffer, | |
| 2688 | .none, | |
| 2689 | .{ .parent_atom_index = local_sym_index }, | |
| 2690 | ); | |
| 2727 | const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ | |
| 2728 | .parent_atom_index = local_sym_index, | |
| 2729 | }); | |
| 2691 | 2730 | const code = switch (res) { |
| 2692 | 2731 | .ok => code_buffer.items, |
| 2693 | 2732 | .fail => |em| { |
| ... | ... | @@ -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 | 2738 | const phdr_index = self.sections.items(.phdr_index)[shdr_index]; |
| 2701 | 2739 | const local_sym = atom.getSymbolPtr(self); |
| 2702 | 2740 | local_sym.* = .{ |
| ... | ... | @@ -2707,7 +2745,6 @@ fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySy |
| 2707 | 2745 | .st_value = 0, |
| 2708 | 2746 | .st_size = 0, |
| 2709 | 2747 | }; |
| 2710 | const required_alignment = lazy_metadata.alignment; | |
| 2711 | 2748 | const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment); |
| 2712 | 2749 | errdefer self.freeAtom(atom_index); |
| 2713 | 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 | 232 | else => false, |
| 233 | 233 | }; |
| 234 | 234 | |
| 235 | const LazySymbolTable = std.ArrayHashMapUnmanaged( | |
| 236 | link.File.LazySymbol, | |
| 237 | LazySymbolMetadata, | |
| 238 | link.File.LazySymbol.Context, | |
| 239 | true, | |
| 240 | ); | |
| 235 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | |
| 241 | 236 | |
| 242 | 237 | const LazySymbolMetadata = struct { |
| 243 | atom: Atom.Index, | |
| 244 | section: u8, | |
| 238 | text_atom: ?Atom.Index = null, | |
| 239 | data_const_atom: ?Atom.Index = null, | |
| 245 | 240 | alignment: u32, |
| 246 | 241 | }; |
| 247 | 242 | |
| ... | ... | @@ -513,17 +508,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 513 | 508 | sub_prog_node.activate(); |
| 514 | 509 | defer sub_prog_node.end(); |
| 515 | 510 | |
| 516 | { | |
| 517 | var lazy_it = self.lazy_syms.iterator(); | |
| 518 | while (lazy_it.next()) |lazy_entry| { | |
| 519 | self.updateLazySymbol( | |
| 520 | lazy_entry.key_ptr.*, | |
| 521 | lazy_entry.value_ptr.*, | |
| 522 | ) catch |err| switch (err) { | |
| 523 | error.CodegenFail => return error.FlushFailure, | |
| 524 | else => |e| return e, | |
| 525 | }; | |
| 526 | } | |
| 511 | // Most lazy symbols can be updated when the corresponding decl is, | |
| 512 | // so we only have to worry about the one without an associated decl. | |
| 513 | if (self.lazy_syms.get(.none)) |metadata| { | |
| 514 | self.updateLazySymbol(.none, metadata) catch |err| switch (err) { | |
| 515 | error.CodegenFail => return error.FlushFailure, | |
| 516 | else => |e| return e, | |
| 517 | }; | |
| 527 | 518 | } |
| 528 | 519 | |
| 529 | 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 | 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 | 2326 | const gpa = self.base.allocator; |
| 2314 | 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 | 2331 | |
| 2319 | 2332 | const name_str_index = blk: { |
| 2320 | 2333 | const name = try std.fmt.allocPrint(gpa, "___lazy_{s}_{}", .{ |
| 2321 | @tagName(lazy_sym.kind), | |
| 2322 | lazy_sym.ty.fmt(mod), | |
| 2334 | @tagName(sym.kind), | |
| 2335 | sym.ty.fmt(mod), | |
| 2323 | 2336 | }); |
| 2324 | 2337 | defer gpa.free(name); |
| 2325 | 2338 | break :blk try self.strtab.insert(gpa, name); |
| 2326 | 2339 | }; |
| 2327 | 2340 | const name = self.strtab.get(name_str_index).?; |
| 2328 | 2341 | |
| 2329 | const atom_index = lazy_metadata.atom; | |
| 2330 | 2342 | const atom = self.getAtomPtr(atom_index); |
| 2331 | 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 | 2346 | mod.declPtr(owner_decl).srcLoc() |
| 2335 | 2347 | else |
| 2336 | 2348 | Module.SrcLoc{ |
| ... | ... | @@ -2338,14 +2350,9 @@ fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: Lazy |
| 2338 | 2350 | .parent_decl_node = undefined, |
| 2339 | 2351 | .lazy = .unneeded, |
| 2340 | 2352 | }; |
| 2341 | const res = try codegen.generateLazySymbol( | |
| 2342 | &self.base, | |
| 2343 | src, | |
| 2344 | lazy_sym, | |
| 2345 | &code_buffer, | |
| 2346 | .none, | |
| 2347 | .{ .parent_atom_index = local_sym_index }, | |
| 2348 | ); | |
| 2353 | const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ | |
| 2354 | .parent_atom_index = local_sym_index, | |
| 2355 | }); | |
| 2349 | 2356 | const code = switch (res) { |
| 2350 | 2357 | .ok => code_buffer.items, |
| 2351 | 2358 | .fail => |em| { |
| ... | ... | @@ -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 | 2364 | const symbol = atom.getSymbolPtr(self); |
| 2359 | 2365 | symbol.n_strx = name_str_index; |
| 2360 | 2366 | symbol.n_type = macho.N_SECT; |
| 2361 | symbol.n_sect = lazy_metadata.section + 1; | |
| 2367 | symbol.n_sect = section_index + 1; | |
| 2362 | 2368 | symbol.n_desc = 0; |
| 2363 | 2369 | |
| 2364 | 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 | 2387 | try self.writeAtom(atom_index, code); |
| 2382 | 2388 | } |
| 2383 | 2389 | |
| 2384 | pub fn getOrCreateAtomForLazySymbol( | |
| 2385 | self: *MachO, | |
| 2386 | lazy_sym: File.LazySymbol, | |
| 2387 | alignment: u32, | |
| 2388 | ) !Atom.Index { | |
| 2389 | const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{ | |
| 2390 | .mod = self.base.options.module.?, | |
| 2391 | }); | |
| 2390 | pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index { | |
| 2391 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | |
| 2392 | 2392 | errdefer _ = self.lazy_syms.pop(); |
| 2393 | if (!gop.found_existing) { | |
| 2394 | gop.value_ptr.* = .{ | |
| 2395 | .atom = try self.createAtom(), | |
| 2396 | .section = switch (lazy_sym.kind) { | |
| 2397 | .code => self.text_section_index.?, | |
| 2398 | .const_data => self.data_const_section_index.?, | |
| 2399 | }, | |
| 2400 | .alignment = alignment, | |
| 2401 | }; | |
| 2402 | } | |
| 2403 | return gop.value_ptr.atom; | |
| 2393 | if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; | |
| 2394 | const atom = switch (sym.kind) { | |
| 2395 | .code => &gop.value_ptr.text_atom, | |
| 2396 | .const_data => &gop.value_ptr.data_const_atom, | |
| 2397 | }; | |
| 2398 | if (atom.* == null) atom.* = try self.createAtom(); | |
| 2399 | return atom.*.?; | |
| 2404 | 2400 | } |
| 2405 | 2401 | |
| 2406 | 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 | 804 | var case_i: u32 = 0; |
| 805 | 805 | |
| 806 | 806 | try w.writeOperand(s, inst, 0, pl_op.operand); |
| 807 | if (w.skip_body) return s.writeAll(", ..."); | |
| 807 | 808 | const old_indent = w.indent; |
| 808 | 809 | w.indent += 2; |
| 809 | 810 |
test/behavior/bugs/12776.zig-1| ... | ... | @@ -31,7 +31,6 @@ const CPU = packed struct { |
| 31 | 31 | test { |
| 32 | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 33 | 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 34 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 35 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 36 | 35 | |
| 37 | 36 | var ram = try RAM.new(); |
test/behavior/bugs/1442.zig-1| ... | ... | @@ -9,7 +9,6 @@ const Union = union(enum) { |
| 9 | 9 | test "const error union field alignment" { |
| 10 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 11 | 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 12 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 13 | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 14 | 13 | var union_or_err: anyerror!Union = Union{ .Color = 1234 }; |
| 15 | 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 | 21 | test "fixed" { |
| 22 | 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 23 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 24 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 25 | 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 26 | 25 | |
| 27 | 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 | 402 | |
| 403 | 403 | test "explicit cast from integer to error type" { |
| 404 | 404 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 405 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 406 | 405 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 407 | 406 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 408 | 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 | 370 | } |
| 371 | 371 | |
| 372 | 372 | test "nested error union function call in optional unwrap" { |
| 373 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 374 | 373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 375 | 374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 376 | 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 | 498 | } |
| 500 | 499 | |
| 501 | 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 | 501 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 504 | 502 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 505 | 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 | 529 | } |
| 532 | 530 | |
| 533 | 531 | test "error payload type is correctly resolved" { |
| 534 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 535 | 532 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 536 | 533 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 537 | 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 | 662 | } |
| 666 | 663 | |
| 667 | 664 | test "error union payload is properly aligned" { |
| 668 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 669 | 665 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 670 | 666 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 671 | 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 | 967 | } |
| 968 | 968 | |
| 969 | 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 | 970 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 972 | 971 | |
| 973 | 972 | const S = struct { |
| ... | ... | @@ -999,7 +998,6 @@ test "comptime break passing through runtime condition converted to runtime brea |
| 999 | 998 | } |
| 1000 | 999 | |
| 1001 | 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 | 1001 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1004 | 1002 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1005 | 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 | 1216 | } |
| 1219 | 1217 | |
| 1220 | 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 | 1219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1223 | 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 | 11 | } |
| 12 | 12 | |
| 13 | 13 | test "mutate through ptr initialized with constant intToPtr value" { |
| 14 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 15 | 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 16 | 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 17 | 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 | 1116 | } |
| 1117 | 1117 | |
| 1118 | 1118 | test "anon init through error unions and optionals" { |
| 1119 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1120 | 1119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1121 | 1120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1122 | 1121 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1162,7 +1161,6 @@ test "anon init through optional" { |
| 1162 | 1161 | } |
| 1163 | 1162 | |
| 1164 | 1163 | test "anon init through error union" { |
| 1165 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1166 | 1164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1167 | 1165 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1168 | 1166 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1182,7 +1180,6 @@ test "anon init through error union" { |
| 1182 | 1180 | } |
| 1183 | 1181 | |
| 1184 | 1182 | test "typed init through error unions and optionals" { |
| 1185 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1186 | 1183 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1187 | 1184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1188 | 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 | 23 | test "switch prong returns error enum" { |
| 24 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 25 | 25 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 26 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 27 | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 28 | 27 | |
| 29 | 28 | switch (doThing(17) catch unreachable) { |
test/behavior/switch_prong_implicit_cast.zig-1| ... | ... | @@ -17,7 +17,6 @@ fn foo(id: u64) !FormValue { |
| 17 | 17 | test "switch prong implicit cast" { |
| 18 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 19 | 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 21 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | 21 | |
| 23 | 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 | 2 | // output_mode=Exe |
| 3 | 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 | 2 | // output_mode=Exe |
| 3 | 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 | 2 | // output_mode=Exe |
| 3 | 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 | 2 | // output_mode=Exe |
| 3 | 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 | 1045 | var ctx = Cases.init(gpa, arena); |
| 1046 | 1046 | |
| 1047 | 1047 | var test_it = TestIterator{ .filenames = filenames.items }; |
| 1048 | while (test_it.next()) |maybe_batch| { | |
| 1049 | const batch = maybe_batch orelse break; | |
| 1048 | while (try test_it.next()) |batch| { | |
| 1050 | 1049 | const strategy: TestStrategy = if (batch.len > 1) .incremental else .independent; |
| 1051 | 1050 | var cases = std.ArrayList(usize).init(arena); |
| 1052 | 1051 | |
| ... | ... | @@ -1084,6 +1083,11 @@ pub fn main() !void { |
| 1084 | 1083 | |
| 1085 | 1084 | for (cases.items) |case_index| { |
| 1086 | 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 | 1091 | switch (manifest.type) { |
| 1088 | 1092 | .compile => { |
| 1089 | 1093 | case.addCompile(src); |
| ... | ... | @@ -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 | 1124 | return runCases(&ctx, zig_exe_path); |