authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-02 21:39:20-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-03 17:45:16+02:00
log272acb7ee5368a32d9f4bc559e93d96759b80173
tree77875a38a3f1cfa8c6f062bb9472f7314c82f9f2
parentf5f0d95f0e882ce43146b269f994c6c242f9ed3b

x86_64: implement storing large immediates


3 files changed, 98 insertions(+), 147 deletions(-)

src/arch/x86_64/CodeGen.zig+98-143
......@@ -3669,52 +3669,67 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
36693669 .none => unreachable,
36703670 .dead => unreachable,
36713671 .unreach => unreachable,
3672 .eflags => |cc| {
3673 try self.asmSetccMemory(Memory.sib(
3674 Memory.PtrSize.fromSize(abi_size),
3675 .{ .base = reg.to64() },
3676 ), cc);
3677 },
3678 .undef => {
3679 if (!self.wantSafety()) return; // The already existing value will do just fine.
3680 switch (abi_size) {
3681 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),
3682 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),
3683 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty),
3684 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty),
3685 else => try self.genInlineMemset(ptr, .{ .immediate = 0xaa }, .{ .immediate = abi_size }, .{}),
3686 }
3687 },
3688 .immediate => |imm| {
3689 switch (abi_size) {
3690 1, 2, 4 => {
3691 const immediate = if (value_ty.isSignedInt())
3692 Immediate.s(@intCast(i32, @bitCast(i64, imm)))
3693 else
3694 Immediate.u(@truncate(u32, imm));
3695 try self.asmMemoryImmediate(.mov, Memory.sib(
3696 Memory.PtrSize.fromSize(abi_size),
3697 .{ .base = reg.to64() },
3698 ), immediate);
3699 },
3700 8 => {
3701 // TODO: optimization: if the imm is only using the lower
3702 // 4 bytes and can be sign extended we can use a normal mov
3703 // with indirect addressing (mov [reg64], imm32).
3704
3705 // movabs does not support indirect register addressing
3706 // so we need an extra register and an extra mov.
3707 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3708 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3709 },
3710 else => {
3711 return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size});
3712 },
3713 }
3672 .eflags => |cc| try self.asmSetccMemory(
3673 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3674 cc,
3675 ),
3676 .undef => if (self.wantSafety()) switch (abi_size) {
3677 1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),
3678 2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),
3679 4 => try self.store(ptr, .{ .immediate = 0xaaaaaaaa }, ptr_ty, value_ty),
3680 8 => try self.store(ptr, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, ptr_ty, value_ty),
3681 else => try self.genInlineMemset(
3682 ptr,
3683 .{ .immediate = 0xaa },
3684 .{ .immediate = abi_size },
3685 .{},
3686 ),
37143687 },
3715 .register => |src_reg| {
3716 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);
3688 .immediate => |imm| switch (self.regBitSize(value_ty)) {
3689 8 => try self.asmMemoryImmediate(
3690 .mov,
3691 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3692 if (math.cast(i8, @bitCast(i64, imm))) |small|
3693 Immediate.s(small)
3694 else
3695 Immediate.u(@intCast(u8, imm)),
3696 ),
3697 16 => try self.asmMemoryImmediate(
3698 .mov,
3699 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3700 if (math.cast(i16, @bitCast(i64, imm))) |small|
3701 Immediate.s(small)
3702 else
3703 Immediate.u(@intCast(u16, imm)),
3704 ),
3705 32 => try self.asmMemoryImmediate(
3706 .mov,
3707 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3708 if (math.cast(i32, @bitCast(i64, imm))) |small|
3709 Immediate.s(small)
3710 else
3711 Immediate.u(@intCast(u32, imm)),
3712 ),
3713 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
3714 try self.asmMemoryImmediate(
3715 .mov,
3716 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3717 Immediate.s(small),
3718 )
3719 else
3720 try self.asmMemoryRegister(
3721 .mov,
3722 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
3723 registerAlias(try self.copyToTmpRegister(value_ty, value), abi_size),
3724 ),
3725 else => unreachable,
37173726 },
3727 .register => |src_reg| try self.genInlineMemcpyRegisterRegister(
3728 value_ty,
3729 reg,
3730 src_reg,
3731 0,
3732 ),
37183733 .register_overflow => |ro| {
37193734 const ro_reg_lock = self.register_manager.lockReg(ro.reg);
37203735 defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -3765,8 +3780,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37653780 defer self.register_manager.unlockReg(addr_reg_lock);
37663781
37673782 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);
3768
3769 // To get the actual address of the value we want to modify we have to go through the GOT
3783 // Load the pointer, which is stored in memory
37703784 try self.asmRegisterMemory(
37713785 .mov,
37723786 addr_reg.to64(),
......@@ -3774,62 +3788,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37743788 );
37753789
37763790 const new_ptr = MCValue{ .register = addr_reg.to64() };
3777
3778 switch (value) {
3779 .immediate => |imm| {
3780 if (abi_size > 8) {
3781 return self.fail("TODO saving imm to memory for abi_size {}", .{abi_size});
3782 }
3783
3784 if (abi_size == 8) {
3785 // TODO
3786 const top_bits: u32 = @intCast(u32, imm >> 32);
3787 const can_extend = if (value_ty.isUnsignedInt())
3788 (top_bits == 0) and (imm & 0x8000_0000) == 0
3789 else
3790 top_bits == 0xffff_ffff;
3791
3792 if (!can_extend) {
3793 return self.fail("TODO imm64 would get incorrectly sign extended", .{});
3794 }
3795 }
3796 try self.asmMemoryImmediate(
3797 .mov,
3798 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg.to64() }),
3799 Immediate.u(@intCast(u32, imm)),
3800 );
3801 },
3802 .register => {
3803 return self.store(new_ptr, value, ptr_ty, value_ty);
3804 },
3805 .linker_load, .memory => {
3806 if (abi_size <= 8) {
3807 const tmp_reg = try self.register_manager.allocReg(null, gp);
3808 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
3809 defer self.register_manager.unlockReg(tmp_reg_lock);
3810
3811 try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value);
3812 try self.asmRegisterMemory(
3813 .mov,
3814 tmp_reg,
3815 Memory.sib(.qword, .{ .base = tmp_reg }),
3816 );
3817
3818 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3819 }
3820
3821 try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{});
3822 },
3823 .stack_offset => {
3824 if (abi_size <= 8) {
3825 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3826 return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3827 }
3828
3829 try self.genInlineMemcpy(new_ptr, value, .{ .immediate = abi_size }, .{});
3830 },
3831 else => return self.fail("TODO implement storing {} to MCValue.memory", .{value}),
3832 }
3791 return self.store(new_ptr, value, ptr_ty, value_ty);
38333792 },
38343793 }
38353794}
......@@ -4887,41 +4846,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48874846 registerAlias(src_reg, abi_size),
48884847 ),
48894848 },
4890 .immediate => |imm| {
4891 switch (self.regBitSize(ty)) {
4892 8 => try self.asmRegisterImmediate(
4893 mir_tag,
4894 dst_alias,
4895 if (math.cast(i8, @bitCast(i64, imm))) |small|
4896 Immediate.s(small)
4897 else
4898 Immediate.u(@intCast(u8, imm)),
4899 ),
4900 16 => try self.asmRegisterImmediate(
4901 mir_tag,
4902 dst_alias,
4903 if (math.cast(i16, @bitCast(i64, imm))) |small|
4904 Immediate.s(small)
4905 else
4906 Immediate.u(@intCast(u16, imm)),
4907 ),
4908 32 => try self.asmRegisterImmediate(
4909 mir_tag,
4910 dst_alias,
4911 if (math.cast(i32, @bitCast(i64, imm))) |small|
4912 Immediate.s(small)
4913 else
4914 Immediate.u(@intCast(u32, imm)),
4915 ),
4916 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
4917 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
4849 .immediate => |imm| switch (self.regBitSize(ty)) {
4850 8 => try self.asmRegisterImmediate(
4851 mir_tag,
4852 dst_alias,
4853 if (math.cast(i8, @bitCast(i64, imm))) |small|
4854 Immediate.s(small)
49184855 else
4919 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
4920 try self.copyToTmpRegister(ty, src_mcv),
4921 abi_size,
4922 )),
4923 else => unreachable,
4924 }
4856 Immediate.u(@intCast(u8, imm)),
4857 ),
4858 16 => try self.asmRegisterImmediate(
4859 mir_tag,
4860 dst_alias,
4861 if (math.cast(i16, @bitCast(i64, imm))) |small|
4862 Immediate.s(small)
4863 else
4864 Immediate.u(@intCast(u16, imm)),
4865 ),
4866 32 => try self.asmRegisterImmediate(
4867 mir_tag,
4868 dst_alias,
4869 if (math.cast(i32, @bitCast(i64, imm))) |small|
4870 Immediate.s(small)
4871 else
4872 Immediate.u(@intCast(u32, imm)),
4873 ),
4874 64 => if (math.cast(i32, @bitCast(i64, imm))) |small|
4875 try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small))
4876 else
4877 try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias(
4878 try self.copyToTmpRegister(ty, src_mcv),
4879 abi_size,
4880 )),
4881 else => unreachable,
49254882 },
49264883 .memory, .linker_load, .eflags => {
49274884 assert(abi_size <= 8);
......@@ -4931,13 +4888,11 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
49314888 const reg = try self.copyToTmpRegister(ty, src_mcv);
49324889 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
49334890 },
4934 .stack_offset => |off| {
4935 try self.asmRegisterMemory(
4936 mir_tag,
4937 registerAlias(dst_reg, abi_size),
4938 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
4939 );
4940 },
4891 .stack_offset => |off| try self.asmRegisterMemory(
4892 mir_tag,
4893 registerAlias(dst_reg, abi_size),
4894 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
4895 ),
49414896 }
49424897 },
49434898 .memory, .linker_load, .stack_offset => {
test/behavior/bugs/3007.zig-1
......@@ -21,7 +21,6 @@ fn get_foo() Foo.FooError!*Foo {
2121test "fixed" {
2222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625
2726 default_foo = get_foo() catch null; // This Line
test/behavior/eval.zig-3
......@@ -967,7 +967,6 @@ test "closure capture type of runtime-known parameter" {
967967}
968968
969969test "comptime break passing through runtime condition converted to runtime break" {
970 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
971970 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
972971
973972 const S = struct {
......@@ -999,7 +998,6 @@ test "comptime break passing through runtime condition converted to runtime brea
999998}
1000999
10011000test "comptime break to outer loop passing through runtime condition converted to runtime break" {
1002 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10031001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10041002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10051003 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1218,7 +1216,6 @@ test "storing an array of type in a field" {
12181216}
12191217
12201218test "pass pointer to field of comptime-only type as a runtime parameter" {
1221 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12221219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12231220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12241221