| ... | @@ -3586,7 +3586,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3586,7 +3586,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3586 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 3586 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3587 | const dst_ty = self.typeOf(bin_op.lhs); | 3587 | const dst_ty = self.typeOf(bin_op.lhs); |
| 3588 | const result: MCValue = switch (dst_ty.zigTypeTag(mod)) { | 3588 | const result: MCValue = switch (dst_ty.zigTypeTag(mod)) { |
| 3589 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 3589 | .Vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(mod)}), |
| 3590 | .Int => result: { | 3590 | .Int => result: { |
| 3591 | try self.spillEflagsIfOccupied(); | 3591 | try self.spillEflagsIfOccupied(); |
| 3592 | try self.spillRegisters(&.{ .rax, .rdx }); | 3592 | try self.spillRegisters(&.{ .rax, .rdx }); |
| ... | @@ -6847,29 +6847,99 @@ fn genMulDivBinOp( | ... | @@ -6847,29 +6847,99 @@ fn genMulDivBinOp( |
| 6847 | maybe_inst: ?Air.Inst.Index, | 6847 | maybe_inst: ?Air.Inst.Index, |
| 6848 | dst_ty: Type, | 6848 | dst_ty: Type, |
| 6849 | src_ty: Type, | 6849 | src_ty: Type, |
| 6850 | lhs: MCValue, | 6850 | lhs_mcv: MCValue, |
| 6851 | rhs: MCValue, | 6851 | rhs_mcv: MCValue, |
| 6852 | ) !MCValue { | 6852 | ) !MCValue { |
| 6853 | const mod = self.bin_file.options.module.?; | 6853 | const mod = self.bin_file.options.module.?; |
| 6854 | if (dst_ty.zigTypeTag(mod) == .Vector or dst_ty.zigTypeTag(mod) == .Float) return self.fail( | 6854 | if (dst_ty.zigTypeTag(mod) == .Vector or dst_ty.zigTypeTag(mod) == .Float) return self.fail( |
| 6855 | "TODO implement genMulDivBinOp for {}", | 6855 | "TODO implement genMulDivBinOp for {s} from {} to {}", |
| 6856 | .{dst_ty.fmt(mod)}, | 6856 | .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) }, |
| 6857 | ); | 6857 | ); |
| 6858 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod)); | 6858 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 6859 | const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); | 6859 | const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); |
| | 6860 | |
| | 6861 | assert(self.register_manager.isRegFree(.rax)); |
| | 6862 | assert(self.register_manager.isRegFree(.rdx)); |
| | 6863 | assert(self.eflags_inst == null); |
| | 6864 | |
| | 6865 | if (dst_abi_size == 16 and src_abi_size == 16) { |
| | 6866 | switch (tag) { |
| | 6867 | else => unreachable, |
| | 6868 | .mul, .mul_wrap => {}, |
| | 6869 | .div_trunc, .div_floor, .div_exact, .rem, .mod => { |
| | 6870 | const signed = dst_ty.isSignedInt(mod); |
| | 6871 | if (signed) switch (tag) { |
| | 6872 | .div_floor, .mod => return self.fail( |
| | 6873 | "TODO implement genMulDivBinOp for {s} from {} to {}", |
| | 6874 | .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) }, |
| | 6875 | ), |
| | 6876 | else => {}, |
| | 6877 | }; |
| | 6878 | var callee: ["__udiv?i3".len]u8 = undefined; |
| | 6879 | return try self.genCall(.{ .lib = .{ |
| | 6880 | .return_type = dst_ty.toIntern(), |
| | 6881 | .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() }, |
| | 6882 | .callee = std.fmt.bufPrint(&callee, "__{s}{s}{c}i3", .{ |
| | 6883 | if (signed) "" else "u", |
| | 6884 | switch (tag) { |
| | 6885 | .div_trunc, .div_exact => "div", |
| | 6886 | .div_floor => if (signed) unreachable else "div", |
| | 6887 | .rem => "mod", |
| | 6888 | .mod => if (signed) unreachable else "mod", |
| | 6889 | else => unreachable, |
| | 6890 | }, |
| | 6891 | intCompilerRtAbiName(@intCast(dst_ty.bitSize(mod))), |
| | 6892 | }) catch unreachable, |
| | 6893 | } }, &.{ src_ty, src_ty }, &.{ lhs_mcv, rhs_mcv }); |
| | 6894 | }, |
| | 6895 | } |
| | 6896 | |
| | 6897 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| | 6898 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| | 6899 | |
| | 6900 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| | 6901 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| | 6902 | defer self.register_manager.unlockReg(tmp_lock); |
| | 6903 | |
| | 6904 | if (lhs_mcv.isMemory()) |
| | 6905 | try self.asmRegisterMemory(.{ ._, .mov }, .rax, lhs_mcv.mem(.qword)) |
| | 6906 | else |
| | 6907 | try self.asmRegisterRegister(.{ ._, .mov }, .rax, lhs_mcv.register_pair[0]); |
| | 6908 | if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| | 6909 | .{ ._, .mov }, |
| | 6910 | tmp_reg, |
| | 6911 | rhs_mcv.address().offset(8).deref().mem(.qword), |
| | 6912 | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, rhs_mcv.register_pair[1]); |
| | 6913 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax); |
| | 6914 | if (rhs_mcv.isMemory()) |
| | 6915 | try self.asmMemory(.{ ._, .mul }, rhs_mcv.mem(.qword)) |
| | 6916 | else |
| | 6917 | try self.asmRegister(.{ ._, .mul }, rhs_mcv.register_pair[0]); |
| | 6918 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg); |
| | 6919 | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| | 6920 | .{ ._, .mov }, |
| | 6921 | tmp_reg, |
| | 6922 | lhs_mcv.address().offset(8).deref().mem(.qword), |
| | 6923 | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_mcv.register_pair[1]); |
| | 6924 | if (rhs_mcv.isMemory()) |
| | 6925 | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, rhs_mcv.mem(.qword)) |
| | 6926 | else |
| | 6927 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, rhs_mcv.register_pair[0]); |
| | 6928 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg); |
| | 6929 | return .{ .register_pair = .{ .rax, .rdx } }; |
| | 6930 | } |
| | 6931 | |
| 6860 | if (switch (tag) { | 6932 | if (switch (tag) { |
| 6861 | else => unreachable, | 6933 | else => unreachable, |
| 6862 | .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, | 6934 | .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, |
| 6863 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, | 6935 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, |
| 6864 | } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{ | 6936 | } or src_abi_size > 8) return self.fail( |
| 6865 | src_ty.fmt(mod), dst_ty.fmt(mod), | 6937 | "TODO implement genMulDivBinOp for {s} from {} to {}", |
| 6866 | }); | 6938 | .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) }, |
| | 6939 | ); |
| 6867 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; | 6940 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; |
| 6868 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; | 6941 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; |
| 6869 | | 6942 | |
| 6870 | assert(self.register_manager.isRegFree(.rax)); | | |
| 6871 | assert(self.register_manager.isRegFree(.rdx)); | | |
| 6872 | | | |
| 6873 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); | 6943 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 6874 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 6944 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 6875 | | 6945 | |
| ... | @@ -6904,7 +6974,7 @@ fn genMulDivBinOp( | ... | @@ -6904,7 +6974,7 @@ fn genMulDivBinOp( |
| 6904 | .div_trunc, .div_exact, .rem => .{ ._, .div }, | 6974 | .div_trunc, .div_exact, .rem => .{ ._, .div }, |
| 6905 | else => unreachable, | 6975 | else => unreachable, |
| 6906 | }, | 6976 | }, |
| 6907 | }, ty, lhs, rhs); | 6977 | }, ty, lhs_mcv, rhs_mcv); |
| 6908 | | 6978 | |
| 6909 | if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) { | 6979 | if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) { |
| 6910 | .mul, .mul_wrap, .div_trunc, .div_exact => .rax, | 6980 | .mul, .mul_wrap, .div_trunc, .div_exact => .rax, |
| ... | @@ -6938,37 +7008,37 @@ fn genMulDivBinOp( | ... | @@ -6938,37 +7008,37 @@ fn genMulDivBinOp( |
| 6938 | | 7008 | |
| 6939 | switch (signedness) { | 7009 | switch (signedness) { |
| 6940 | .signed => { | 7010 | .signed => { |
| 6941 | const lhs_lock = switch (lhs) { | 7011 | const lhs_lock = switch (lhs_mcv) { |
| 6942 | .register => |reg| self.register_manager.lockReg(reg), | 7012 | .register => |reg| self.register_manager.lockReg(reg), |
| 6943 | else => null, | 7013 | else => null, |
| 6944 | }; | 7014 | }; |
| 6945 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 7015 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 6946 | const rhs_lock = switch (rhs) { | 7016 | const rhs_lock = switch (rhs_mcv) { |
| 6947 | .register => |reg| self.register_manager.lockReg(reg), | 7017 | .register => |reg| self.register_manager.lockReg(reg), |
| 6948 | else => null, | 7018 | else => null, |
| 6949 | }; | 7019 | }; |
| 6950 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 7020 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 6951 | | 7021 | |
| 6952 | // hack around hazard between rhs and div_floor by copying rhs to another register | 7022 | // hack around hazard between rhs and div_floor by copying rhs to another register |
| 6953 | const rhs_copy = try self.copyToTmpRegister(ty, rhs); | 7023 | const rhs_copy = try self.copyToTmpRegister(ty, rhs_mcv); |
| 6954 | const rhs_copy_lock = self.register_manager.lockRegAssumeUnused(rhs_copy); | 7024 | const rhs_copy_lock = self.register_manager.lockRegAssumeUnused(rhs_copy); |
| 6955 | defer self.register_manager.unlockReg(rhs_copy_lock); | 7025 | defer self.register_manager.unlockReg(rhs_copy_lock); |
| 6956 | | 7026 | |
| 6957 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); | 7027 | const div_floor = try self.genInlineIntDivFloor(ty, lhs_mcv, rhs_mcv); |
| 6958 | try self.genIntMulComplexOpMir(ty, div_floor, .{ .register = rhs_copy }); | 7028 | try self.genIntMulComplexOpMir(ty, div_floor, .{ .register = rhs_copy }); |
| 6959 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); | 7029 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); |
| 6960 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); | 7030 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); |
| 6961 | | 7031 | |
| 6962 | const result: MCValue = if (maybe_inst) |inst| | 7032 | const result: MCValue = if (maybe_inst) |inst| |
| 6963 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) | 7033 | try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv) |
| 6964 | else | 7034 | else |
| 6965 | .{ .register = try self.copyToTmpRegister(ty, lhs) }; | 7035 | .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; |
| 6966 | try self.genBinOpMir(.{ ._, .sub }, ty, result, div_floor); | 7036 | try self.genBinOpMir(.{ ._, .sub }, ty, result, div_floor); |
| 6967 | | 7037 | |
| 6968 | return result; | 7038 | return result; |
| 6969 | }, | 7039 | }, |
| 6970 | .unsigned => { | 7040 | .unsigned => { |
| 6971 | try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, rhs); | 7041 | try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, rhs_mcv); |
| 6972 | return .{ .register = registerAlias(.rdx, abi_size) }; | 7042 | return .{ .register = registerAlias(.rdx, abi_size) }; |
| 6973 | }, | 7043 | }, |
| 6974 | } | 7044 | } |
| ... | @@ -6978,39 +7048,39 @@ fn genMulDivBinOp( | ... | @@ -6978,39 +7048,39 @@ fn genMulDivBinOp( |
| 6978 | try self.register_manager.getReg(.rax, if (signedness == .unsigned) maybe_inst else null); | 7048 | try self.register_manager.getReg(.rax, if (signedness == .unsigned) maybe_inst else null); |
| 6979 | try self.register_manager.getReg(.rdx, null); | 7049 | try self.register_manager.getReg(.rdx, null); |
| 6980 | | 7050 | |
| 6981 | const lhs_lock: ?RegisterLock = switch (lhs) { | 7051 | const lhs_lock: ?RegisterLock = switch (lhs_mcv) { |
| 6982 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 7052 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6983 | else => null, | 7053 | else => null, |
| 6984 | }; | 7054 | }; |
| 6985 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 7055 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 6986 | | 7056 | |
| 6987 | const actual_rhs: MCValue = blk: { | 7057 | const actual_rhs_mcv: MCValue = blk: { |
| 6988 | switch (signedness) { | 7058 | switch (signedness) { |
| 6989 | .signed => { | 7059 | .signed => { |
| 6990 | const rhs_lock: ?RegisterLock = switch (rhs) { | 7060 | const rhs_lock: ?RegisterLock = switch (rhs_mcv) { |
| 6991 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 7061 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6992 | else => null, | 7062 | else => null, |
| 6993 | }; | 7063 | }; |
| 6994 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 7064 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 6995 | | 7065 | |
| 6996 | if (maybe_inst) |inst| { | 7066 | if (maybe_inst) |inst| { |
| 6997 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); | 7067 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); |
| 6998 | } | 7068 | } |
| 6999 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; | 7069 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs_mcv) }; |
| 7000 | }, | 7070 | }, |
| 7001 | .unsigned => break :blk rhs, | 7071 | .unsigned => break :blk rhs_mcv, |
| 7002 | } | 7072 | } |
| 7003 | }; | 7073 | }; |
| 7004 | const rhs_lock: ?RegisterLock = switch (actual_rhs) { | 7074 | const rhs_lock: ?RegisterLock = switch (actual_rhs_mcv) { |
| 7005 | .register => |reg| self.register_manager.lockReg(reg), | 7075 | .register => |reg| self.register_manager.lockReg(reg), |
| 7006 | else => null, | 7076 | else => null, |
| 7007 | }; | 7077 | }; |
| 7008 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 7078 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 7009 | | 7079 | |
| 7010 | switch (signedness) { | 7080 | switch (signedness) { |
| 7011 | .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs), | 7081 | .signed => return try self.genInlineIntDivFloor(ty, lhs_mcv, actual_rhs_mcv), |
| 7012 | .unsigned => { | 7082 | .unsigned => { |
| 7013 | try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, actual_rhs); | 7083 | try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, actual_rhs_mcv); |
| 7014 | return .{ .register = registerAlias(.rax, abi_size) }; | 7084 | return .{ .register = registerAlias(.rax, abi_size) }; |
| 7015 | }, | 7085 | }, |
| 7016 | } | 7086 | } |
| ... | @@ -7038,7 +7108,7 @@ fn genBinOp( | ... | @@ -7038,7 +7108,7 @@ fn genBinOp( |
| 7038 | 80, 128 => true, | 7108 | 80, 128 => true, |
| 7039 | else => unreachable, | 7109 | else => unreachable, |
| 7040 | })) { | 7110 | })) { |
| 7041 | var callee: ["__add?f3".len]u8 = undefined; | 7111 | var callee: ["__mod?f3".len]u8 = undefined; |
| 7042 | const result = try self.genCall(.{ .lib = .{ | 7112 | const result = try self.genCall(.{ .lib = .{ |
| 7043 | .return_type = lhs_ty.toIntern(), | 7113 | .return_type = lhs_ty.toIntern(), |
| 7044 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, | 7114 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, |
| ... | @@ -7259,7 +7329,7 @@ fn genBinOp( | ... | @@ -7259,7 +7329,7 @@ fn genBinOp( |
| 7259 | abi.RegisterClass.gp, | 7329 | abi.RegisterClass.gp, |
| 7260 | ); | 7330 | ); |
| 7261 | const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs); | 7331 | const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs); |
| 7262 | for (dst_regs_locks) |dst_lock| if (dst_lock) |lock| | 7332 | defer for (dst_regs_locks) |dst_lock| if (dst_lock) |lock| |
| 7263 | self.register_manager.unlockReg(lock); | 7333 | self.register_manager.unlockReg(lock); |
| 7264 | | 7334 | |
| 7265 | try self.genCopy(lhs_ty, .{ .register_pair = dst_regs }, dst_mcv); | 7335 | try self.genCopy(lhs_ty, .{ .register_pair = dst_regs }, dst_mcv); |
| ... | @@ -7267,7 +7337,7 @@ fn genBinOp( | ... | @@ -7267,7 +7337,7 @@ fn genBinOp( |
| 7267 | }, | 7337 | }, |
| 7268 | }; | 7338 | }; |
| 7269 | const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs); | 7339 | const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs); |
| 7270 | for (dst_regs_locks) |dst_lock| if (dst_lock) |lock| | 7340 | defer for (dst_regs_locks) |dst_lock| if (dst_lock) |lock| |
| 7271 | self.register_manager.unlockReg(lock); | 7341 | self.register_manager.unlockReg(lock); |
| 7272 | | 7342 | |
| 7273 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); | 7343 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |