authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-27 03:11:34-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-27 05:58:00-04:00
log65838fcabeee8f0330425156c31a4711d0e026f7
tree7f27182d1ebe908e7564791c8cba832085ae8866
parent3a516433b0cf94e8aa67819acc49c03e0b72f296

x86_64: implement some binary ops for large values


1 files changed, 145 insertions(+), 88 deletions(-)

src/arch/x86_64/CodeGen.zig+145-88
......@@ -4010,9 +4010,6 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
40104010 .register_overflow => unreachable,
40114011 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
40124012 .ptr_stack_offset, .stack_offset => |off| {
4013 if (off > math.maxInt(i32)) {
4014 return self.fail("stack offset too large", .{});
4015 }
40164013 if (abi_size > 8) {
40174014 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
40184015 }
......@@ -4454,9 +4451,6 @@ fn genBinOp(
44544451 if (lhs_ty.zigTypeTag() == .Vector) {
44554452 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
44564453 }
4457 if (lhs_ty.abiSize(self.target.*) > 8) {
4458 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
4459 }
44604454
44614455 switch (lhs) {
44624456 .immediate => |imm| switch (imm) {
......@@ -4686,7 +4680,6 @@ fn genBinOp(
46864680 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
46874681 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
46884682 defer self.register_manager.unlockReg(addr_reg_lock);
4689
46904683 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv);
46914684
46924685 // To get the actual address of the value we want to modify we
......@@ -4801,9 +4794,6 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48014794 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
48024795 },
48034796 .stack_offset => |off| {
4804 if (off > math.maxInt(i32)) {
4805 return self.fail("stack offset too large", .{});
4806 }
48074797 try self.asmRegisterMemory(
48084798 mir_tag,
48094799 registerAlias(dst_reg, abi_size),
......@@ -4812,78 +4802,155 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
48124802 },
48134803 }
48144804 },
4815 .ptr_stack_offset, .stack_offset => |off| {
4816 if (off > math.maxInt(i32)) {
4817 return self.fail("stack offset too large", .{});
4818 }
4819 if (abi_size > 8) {
4820 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
4821 }
4805 .ptr_stack_offset, .stack_offset => |dst_off| {
4806 const src: ?struct {
4807 limb_reg: Register,
4808 limb_lock: RegisterLock,
4809 addr_reg: Register,
4810 addr_lock: RegisterLock,
4811 } = switch (src_mcv) {
4812 else => null,
4813 .memory, .linker_load => addr: {
4814 const src_limb_reg = try self.register_manager.allocReg(null, gp);
4815 const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg);
4816 errdefer self.register_manager.unlockReg(src_limb_lock);
4817
4818 const src_addr_reg = try self.register_manager.allocReg(null, gp);
4819 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
4820 errdefer self.register_manager.unlockReg(src_addr_lock);
4821
4822 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv);
4823 // To get the actual address of the value we want to modify we
4824 // we have to go through the GOT
4825 try self.asmRegisterMemory(
4826 .mov,
4827 src_addr_reg,
4828 Memory.sib(.qword, .{ .base = src_addr_reg }),
4829 );
48224830
4823 switch (src_mcv) {
4824 .none => unreachable,
4825 .undef => unreachable,
4826 .dead, .unreach => unreachable,
4827 .register_overflow => unreachable,
4828 .register => |src_reg| {
4829 try self.asmMemoryRegister(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4830 .base = .rbp,
4831 .disp = -off,
4832 }), registerAlias(src_reg, abi_size));
4831 break :addr .{
4832 .addr_reg = src_addr_reg,
4833 .addr_lock = src_addr_lock,
4834 .limb_reg = src_limb_reg,
4835 .limb_lock = src_limb_lock,
4836 };
48334837 },
4834 .immediate => |imm| {
4835 switch (self.regBitSize(ty)) {
4836 8, 16, 32 => {
4837 try self.asmMemoryImmediate(
4838 mir_tag,
4839 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4840 .base = .rbp,
4841 .disp = -off,
4842 }),
4843 if (math.cast(i32, @bitCast(i64, imm))) |small|
4844 Immediate.s(small)
4845 else
4846 Immediate.u(@intCast(u32, imm)),
4847 );
4848 },
4849 64 => {
4850 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4838 };
4839 defer if (src) |locks| {
4840 self.register_manager.unlockReg(locks.limb_lock);
4841 self.register_manager.unlockReg(locks.addr_lock);
4842 };
4843
4844 const ty_signedness =
4845 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
4846 const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) {
4847 .signed => Type.usize,
4848 .unsigned => Type.isize,
4849 };
4850 const limb_abi_size = @min(abi_size, 8);
4851 var off: i32 = 0;
4852 while (off < abi_size) : (off += 8) {
4853 const mir_limb_tag = switch (off) {
4854 0 => mir_tag,
4855 else => switch (mir_tag) {
4856 .add => .adc,
4857 .sub => .sbb,
4858 .@"or", .@"and", .xor => mir_tag,
4859 else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
4860 @tagName(mir_tag),
4861 }),
4862 },
4863 };
4864 const dst_limb_mem = Memory.sib(
4865 Memory.PtrSize.fromSize(limb_abi_size),
4866 .{ .base = .rbp, .disp = off - dst_off },
4867 );
4868 switch (src_mcv) {
4869 .none => unreachable,
4870 .undef => unreachable,
4871 .dead, .unreach => unreachable,
4872 .register_overflow => unreachable,
4873 .register => |src_reg| {
4874 assert(off == 0);
4875 try self.asmMemoryRegister(
4876 mir_limb_tag,
4877 dst_limb_mem,
4878 registerAlias(src_reg, limb_abi_size),
4879 );
4880 },
4881 .immediate => |src_imm| {
4882 const imm = if (off == 0) src_imm else switch (ty_signedness) {
4883 .signed => @bitCast(u64, @bitCast(i64, src_imm) >> 63),
4884 .unsigned => 0,
4885 };
4886 switch (self.regBitSize(limb_ty)) {
4887 8, 16, 32 => {
48514888 try self.asmMemoryImmediate(
4852 mir_tag,
4853 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4854 .base = .rbp,
4855 .disp = -off,
4856 }),
4857 Immediate.s(small),
4889 mir_limb_tag,
4890 dst_limb_mem,
4891 if (math.cast(i32, @bitCast(i64, imm))) |small|
4892 Immediate.s(small)
4893 else
4894 Immediate.u(@intCast(u32, imm)),
48584895 );
4859 } else {
4860 try self.asmMemoryRegister(
4861 mir_tag,
4862 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4863 .base = .rbp,
4864 .disp = -off,
4865 }),
4866 registerAlias(try self.copyToTmpRegister(ty, src_mcv), abi_size),
4867 );
4868 }
4869 },
4870 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
4871 }
4872 },
4873 .memory,
4874 .linker_load,
4875 .stack_offset,
4876 .ptr_stack_offset,
4877 .eflags,
4878 => {
4879 assert(abi_size <= 8);
4880
4881 const tmp_reg = try self.copyToTmpRegister(ty, src_mcv);
4882 const tmp_lock = self.register_manager.lockReg(tmp_reg);
4883 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
4896 },
4897 64 => {
4898 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4899 try self.asmMemoryImmediate(
4900 mir_limb_tag,
4901 dst_limb_mem,
4902 Immediate.s(small),
4903 );
4904 } else {
4905 try self.asmMemoryRegister(
4906 mir_limb_tag,
4907 dst_limb_mem,
4908 registerAlias(
4909 try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }),
4910 limb_abi_size,
4911 ),
4912 );
4913 }
4914 },
4915 else => unreachable,
4916 }
4917 },
4918 .memory, .linker_load => {
4919 try self.asmRegisterMemory(
4920 .mov,
4921 registerAlias(src.?.limb_reg, limb_abi_size),
4922 Memory.sib(
4923 Memory.PtrSize.fromSize(limb_abi_size),
4924 .{ .base = src.?.addr_reg, .disp = off },
4925 ),
4926 );
4927 try self.asmMemoryRegister(
4928 mir_limb_tag,
4929 dst_limb_mem,
4930 registerAlias(src.?.limb_reg, limb_abi_size),
4931 );
4932 },
4933 .stack_offset, .ptr_stack_offset, .eflags => {
4934 const src_limb_reg = try self.copyToTmpRegister(limb_ty, switch (src_mcv) {
4935 .stack_offset => |src_off| .{ .stack_offset = src_off - off },
4936 .ptr_stack_offset,
4937 .eflags,
4938 => off: {
4939 assert(off == 0);
4940 break :off src_mcv;
4941 },
4942 else => unreachable,
4943 });
4944 const src_limb_lock = self.register_manager.lockReg(src_limb_reg);
4945 defer if (src_limb_lock) |lock| self.register_manager.unlockReg(lock);
48844946
4885 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = tmp_reg });
4886 },
4947 try self.asmMemoryRegister(
4948 mir_limb_tag,
4949 dst_limb_mem,
4950 registerAlias(src_limb_reg, limb_abi_size),
4951 );
4952 },
4953 }
48874954 }
48884955 },
48894956 .memory => {
......@@ -6735,10 +6802,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
67356802 }
67366803 },
67376804 .register => |reg| {
6738 if (stack_offset > math.maxInt(i32)) {
6739 return self.fail("stack offset too large", .{});
6740 }
6741
67426805 const base_reg = opts.dest_stack_base orelse .rbp;
67436806
67446807 switch (ty.zigTypeTag()) {
......@@ -6973,13 +7036,11 @@ fn genInlineMemset(
69737036
69747037fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
69757038 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
7039 if (abi_size > 8) return self.fail("genSetReg called with a value larger than one register", .{});
69767040 switch (mcv) {
69777041 .dead => unreachable,
69787042 .register_overflow => unreachable,
69797043 .ptr_stack_offset => |off| {
6980 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
6981 return self.fail("stack offset too large", .{});
6982 }
69837044 try self.asmRegisterMemory(
69847045 .lea,
69857046 registerAlias(reg, abi_size),
......@@ -7158,10 +7219,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
71587219 },
71597220 },
71607221 .stack_offset => |off| {
7161 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
7162 return self.fail("stack offset too large", .{});
7163 }
7164
71657222 switch (ty.zigTypeTag()) {
71667223 .Int => switch (ty.intInfo(self.target.*).signedness) {
71677224 .signed => {