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...@@ -4010,9 +4010,6 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
4010 .register_overflow => unreachable,4010 .register_overflow => unreachable,
4011 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),4011 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
4012 .ptr_stack_offset, .stack_offset => |off| {4012 .ptr_stack_offset, .stack_offset => |off| {
4013 if (off > math.maxInt(i32)) {
4014 return self.fail("stack offset too large", .{});
4015 }
4016 if (abi_size > 8) {4013 if (abi_size > 8) {
4017 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});4014 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
4018 }4015 }
...@@ -4454,9 +4451,6 @@ fn genBinOp(...@@ -4454,9 +4451,6 @@ fn genBinOp(
4454 if (lhs_ty.zigTypeTag() == .Vector) {4451 if (lhs_ty.zigTypeTag() == .Vector) {
4455 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});4452 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
4456 }4453 }
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
4461 switch (lhs) {4455 switch (lhs) {
4462 .immediate => |imm| switch (imm) {4456 .immediate => |imm| switch (imm) {
...@@ -4686,7 +4680,6 @@ fn genBinOp(...@@ -4686,7 +4680,6 @@ fn genBinOp(
4686 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();4680 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4687 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);4681 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
4688 defer self.register_manager.unlockReg(addr_reg_lock);4682 defer self.register_manager.unlockReg(addr_reg_lock);
4689
4690 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv);4683 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv);
46914684
4692 // To get the actual address of the value we want to modify we4685 // 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...@@ -4801,9 +4794,6 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4801 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });4794 return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg });
4802 },4795 },
4803 .stack_offset => |off| {4796 .stack_offset => |off| {
4804 if (off > math.maxInt(i32)) {
4805 return self.fail("stack offset too large", .{});
4806 }
4807 try self.asmRegisterMemory(4797 try self.asmRegisterMemory(
4808 mir_tag,4798 mir_tag,
4809 registerAlias(dst_reg, abi_size),4799 registerAlias(dst_reg, abi_size),
...@@ -4812,78 +4802,155 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -4812,78 +4802,155 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4812 },4802 },
4813 }4803 }
4814 },4804 },
4815 .ptr_stack_offset, .stack_offset => |off| {4805 .ptr_stack_offset, .stack_offset => |dst_off| {
4816 if (off > math.maxInt(i32)) {4806 const src: ?struct {
4817 return self.fail("stack offset too large", .{});4807 limb_reg: Register,
4818 }4808 limb_lock: RegisterLock,
4819 if (abi_size > 8) {4809 addr_reg: Register,
4820 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});4810 addr_lock: RegisterLock,
4821 }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) {4831 break :addr .{
4824 .none => unreachable,4832 .addr_reg = src_addr_reg,
4825 .undef => unreachable,4833 .addr_lock = src_addr_lock,
4826 .dead, .unreach => unreachable,4834 .limb_reg = src_limb_reg,
4827 .register_overflow => unreachable,4835 .limb_lock = src_limb_lock,
4828 .register => |src_reg| {4836 };
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));
4833 },4837 },
4834 .immediate => |imm| {4838 };
4835 switch (self.regBitSize(ty)) {4839 defer if (src) |locks| {
4836 8, 16, 32 => {4840 self.register_manager.unlockReg(locks.limb_lock);
4837 try self.asmMemoryImmediate(4841 self.register_manager.unlockReg(locks.addr_lock);
4838 mir_tag,4842 };
4839 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{4843
4840 .base = .rbp,4844 const ty_signedness =
4841 .disp = -off,4845 if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned;
4842 }),4846 const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) {
4843 if (math.cast(i32, @bitCast(i64, imm))) |small|4847 .signed => Type.usize,
4844 Immediate.s(small)4848 .unsigned => Type.isize,
4845 else4849 };
4846 Immediate.u(@intCast(u32, imm)),4850 const limb_abi_size = @min(abi_size, 8);
4847 );4851 var off: i32 = 0;
4848 },4852 while (off < abi_size) : (off += 8) {
4849 64 => {4853 const mir_limb_tag = switch (off) {
4850 if (math.cast(i32, @bitCast(i64, imm))) |small| {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 => {
4851 try self.asmMemoryImmediate(4888 try self.asmMemoryImmediate(
4852 mir_tag,4889 mir_limb_tag,
4853 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{4890 dst_limb_mem,
4854 .base = .rbp,4891 if (math.cast(i32, @bitCast(i64, imm))) |small|
4855 .disp = -off,4892 Immediate.s(small)
4856 }),4893 else
4857 Immediate.s(small),4894 Immediate.u(@intCast(u32, imm)),
4858 );4895 );
4859 } else {4896 },
4860 try self.asmMemoryRegister(4897 64 => {
4861 mir_tag,4898 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4862 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{4899 try self.asmMemoryImmediate(
4863 .base = .rbp,4900 mir_limb_tag,
4864 .disp = -off,4901 dst_limb_mem,
4865 }),4902 Immediate.s(small),
4866 registerAlias(try self.copyToTmpRegister(ty, src_mcv), abi_size),4903 );
4867 );4904 } else {
4868 }4905 try self.asmMemoryRegister(
4869 },4906 mir_limb_tag,
4870 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),4907 dst_limb_mem,
4871 }4908 registerAlias(
4872 },4909 try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }),
4873 .memory,4910 limb_abi_size,
4874 .linker_load,4911 ),
4875 .stack_offset,4912 );
4876 .ptr_stack_offset,4913 }
4877 .eflags,4914 },
4878 => {4915 else => unreachable,
4879 assert(abi_size <= 8);4916 }
48804917 },
4881 const tmp_reg = try self.copyToTmpRegister(ty, src_mcv);4918 .memory, .linker_load => {
4882 const tmp_lock = self.register_manager.lockReg(tmp_reg);4919 try self.asmRegisterMemory(
4883 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);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 });4947 try self.asmMemoryRegister(
4886 },4948 mir_limb_tag,
4949 dst_limb_mem,
4950 registerAlias(src_limb_reg, limb_abi_size),
4951 );
4952 },
4953 }
4887 }4954 }
4888 },4955 },
4889 .memory => {4956 .memory => {
...@@ -6735,10 +6802,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -6735,10 +6802,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
6735 }6802 }
6736 },6803 },
6737 .register => |reg| {6804 .register => |reg| {
6738 if (stack_offset > math.maxInt(i32)) {
6739 return self.fail("stack offset too large", .{});
6740 }
6741
6742 const base_reg = opts.dest_stack_base orelse .rbp;6805 const base_reg = opts.dest_stack_base orelse .rbp;
67436806
6744 switch (ty.zigTypeTag()) {6807 switch (ty.zigTypeTag()) {
...@@ -6973,13 +7036,11 @@ fn genInlineMemset(...@@ -6973,13 +7036,11 @@ fn genInlineMemset(
69737036
6974fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {7037fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
6975 const abi_size = @intCast(u32, ty.abiSize(self.target.*));7038 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", .{});
6976 switch (mcv) {7040 switch (mcv) {
6977 .dead => unreachable,7041 .dead => unreachable,
6978 .register_overflow => unreachable,7042 .register_overflow => unreachable,
6979 .ptr_stack_offset => |off| {7043 .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 }
6983 try self.asmRegisterMemory(7044 try self.asmRegisterMemory(
6984 .lea,7045 .lea,
6985 registerAlias(reg, abi_size),7046 registerAlias(reg, abi_size),
...@@ -7158,10 +7219,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7158,10 +7219,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
7158 },7219 },
7159 },7220 },
7160 .stack_offset => |off| {7221 .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
7165 switch (ty.zigTypeTag()) {7222 switch (ty.zigTypeTag()) {
7166 .Int => switch (ty.intInfo(self.target.*).signedness) {7223 .Int => switch (ty.intInfo(self.target.*).signedness) {
7167 .signed => {7224 .signed => {