@@ -3586,7 +3586,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
3586
3586
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
3587
3587
const dst_ty = self.typeOf(bin_op.lhs);
3588
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
3590
.Int => result: {
3591
3591
try self.spillEflagsIfOccupied();
3592
3592
try self.spillRegisters(&.{ .rax, .rdx });
@@ -6847,29 +6847,99 @@ fn genMulDivBinOp(
6847
6847
maybe_inst: ?Air.Inst.Index,
6848
6848
dst_ty: Type,
6849
6849
src_ty: Type,
6850
- lhs : MCValue,
6851
- rhs : MCValue,
6850
+ lhs_mcv : MCValue,
6851
+ rhs_mcv : MCValue,
6852
6852
) !MCValue {
6853
6853
const mod = self.bin_file.options.module.?;
6854
6854
if (dst_ty.zigTypeTag(mod) == .Vector or dst_ty.zigTypeTag(mod) == .Float) return self.fail(
6855
- "TODO implement genMulDivBinOp for {}",
6856
- .{dst_ty.fmt(mod)},
6855
+ "TODO implement genMulDivBinOp for {s} from {} to { }",
6856
+ .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) },
6857
6857
);
6858
6858
const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod));
6859
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
6932
if (switch (tag) {
6861
6933
else => unreachable,
6862
6934
.mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
6863
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 {}", .{
6865
- src_ty.fmt(mod), dst_ty.fmt(mod),
6866
- });
6936
+ } or src_abi_size > 8) return self.fail(
6937
+ "TODO implement genMulDivBinOp for {s} from {} to {}",
6938
+ .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) },
6939
+ );
6867
6940
const ty = if (dst_abi_size <= 8) dst_ty else src_ty;
6868
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
6943
const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
6874
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
6974
.div_trunc, .div_exact, .rem => .{ ._, .div },
6905
6975
else => unreachable,
6906
6976
},
6907
- }, ty, lhs, rhs );
6977
+ }, ty, lhs_mcv, rhs_mcv );
6908
6978
6909
6979
if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
6910
6980
.mul, .mul_wrap, .div_trunc, .div_exact => .rax,
@@ -6938,37 +7008,37 @@ fn genMulDivBinOp(
6938
7008
6939
7009
switch (signedness) {
6940
7010
.signed => {
6941
- const lhs_lock = switch (lhs ) {
7011
+ const lhs_lock = switch (lhs_mcv ) {
6942
7012
.register => |reg| self.register_manager.lockReg(reg),
6943
7013
else => null,
6944
7014
};
6945
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
7017
.register => |reg| self.register_manager.lockReg(reg),
6948
7018
else => null,
6949
7019
};
6950
7020
defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
6951
7021
6952
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
7024
const rhs_copy_lock = self.register_manager.lockRegAssumeUnused(rhs_copy);
6955
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
7028
try self.genIntMulComplexOpMir(ty, div_floor, .{ .register = rhs_copy });
6959
7029
const div_floor_lock = self.register_manager.lockReg(div_floor.register);
6960
7030
defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);
6961
7031
6962
7032
const result: MCValue = if (maybe_inst) |inst|
6963
- try self.copyToRegisterWithInstTracking(inst, ty, lhs )
7033
+ try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv )
6964
7034
else
6965
- .{ .register = try self.copyToTmpRegister(ty, lhs ) };
7035
+ .{ .register = try self.copyToTmpRegister(ty, lhs_mcv ) };
6966
7036
try self.genBinOpMir(.{ ._, .sub }, ty, result, div_floor);
6967
7037
6968
7038
return result;
6969
7039
},
6970
7040
.unsigned => {
6971
- try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, rhs );
7041
+ try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, rhs_mcv );
6972
7042
return .{ .register = registerAlias(.rdx, abi_size) };
6973
7043
},
6974
7044
}
@@ -6978,39 +7048,39 @@ fn genMulDivBinOp(
6978
7048
try self.register_manager.getReg(.rax, if (signedness == .unsigned) maybe_inst else null);
6979
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
7052
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
6983
7053
else => null,
6984
7054
};
6985
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
7058
switch (signedness) {
6989
7059
.signed => {
6990
- const rhs_lock: ?RegisterLock = switch (rhs ) {
7060
+ const rhs_lock: ?RegisterLock = switch (rhs_mcv ) {
6991
7061
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
6992
7062
else => null,
6993
7063
};
6994
7064
defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
6995
7065
6996
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
7075
.register => |reg| self.register_manager.lockReg(reg),
7006
7076
else => null,
7007
7077
};
7008
7078
defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
7009
7079
7010
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
7082
.unsigned => {
7013
- try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, actual_rhs );
7083
+ try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, actual_rhs_mcv );
7014
7084
return .{ .register = registerAlias(.rax, abi_size) };
7015
7085
},
7016
7086
}
@@ -7038,7 +7108,7 @@ fn genBinOp(
7038
7108
80, 128 => true,
7039
7109
else => unreachable,
7040
7110
})) {
7041
- var callee: ["__add ?f3".len]u8 = undefined;
7111
+ var callee: ["__mod ?f3".len]u8 = undefined;
7042
7112
const result = try self.genCall(.{ .lib = .{
7043
7113
.return_type = lhs_ty.toIntern(),
7044
7114
.param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
@@ -7259,15 +7329,15 @@ fn genBinOp(
7259
7329
abi.RegisterClass.gp,
7260
7330
);
7261
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
7333
self.register_manager.unlockReg(lock);
7264
7334
7265
7335
try self.genCopy(lhs_ty, .{ .register_pair = dst_regs }, dst_mcv);
7266
7336
break :dst dst_regs;
7267
7337
},
7268
7338
};
7269
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
7341
self.register_manager.unlockReg(lock);
7272
7342
7273
7343
const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
0 commit comments