Skip to content

Commit 8540fea

Browse files
committed
x64: handle unsigned mul_with_overflow for non-pow-2 ints
1 parent 33c27d8 commit 8540fea

File tree

1 file changed

+55
-23
lines changed

1 file changed

+55
-23
lines changed

src/arch/x86_64/CodeGen.zig

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,28 +1487,52 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14871487
break :result result;
14881488
}
14891489

1490-
const lhs = try self.resolveInst(bin_op.lhs);
1491-
const rhs = try self.resolveInst(bin_op.rhs);
1490+
const dst_reg: Register = dst_reg: {
1491+
switch (int_info.signedness) {
1492+
.signed => {
1493+
const lhs = try self.resolveInst(bin_op.lhs);
1494+
const rhs = try self.resolveInst(bin_op.rhs);
1495+
1496+
rhs.freezeIfRegister(&self.register_manager);
1497+
defer rhs.unfreezeIfRegister(&self.register_manager);
1498+
1499+
// TODO check if we could reuse rhs instead, and swap the values out.
1500+
const dst_reg: Register = blk: {
1501+
if (self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1502+
if (lhs.isRegister()) break :blk lhs.register;
1503+
}
1504+
break :blk try self.copyToTmpRegister(ty, lhs);
1505+
};
1506+
self.register_manager.freezeRegs(&.{dst_reg});
1507+
1508+
const rhs_mcv = blk: {
1509+
if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
1510+
break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
1511+
};
1512+
rhs_mcv.freezeIfRegister(&self.register_manager);
1513+
defer rhs_mcv.unfreezeIfRegister(&self.register_manager);
1514+
1515+
try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv);
1516+
1517+
break :dst_reg dst_reg;
1518+
},
1519+
.unsigned => {
1520+
// Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1521+
try self.register_manager.getReg(.rax, null);
1522+
try self.register_manager.getReg(.rdx, null);
1523+
self.register_manager.freezeRegs(&.{ .rax, .rdx });
1524+
defer self.register_manager.unfreezeRegs(&.{.rdx});
14921525

1493-
rhs.freezeIfRegister(&self.register_manager);
1494-
defer rhs.unfreezeIfRegister(&self.register_manager);
1526+
const lhs = try self.resolveInst(bin_op.lhs);
1527+
const rhs = try self.resolveInst(bin_op.rhs);
14951528

1496-
// TODO check if we could reuse rhs instead, and swap the values out.
1497-
const dst_mcv = blk: {
1498-
if (self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1499-
if (lhs.isRegister()) break :blk lhs;
1500-
}
1501-
break :blk MCValue{ .register = try self.copyToTmpRegister(ty, lhs) };
1502-
};
1503-
dst_mcv.freezeIfRegister(&self.register_manager);
1504-
defer dst_mcv.unfreezeIfRegister(&self.register_manager);
1529+
try self.genIntMulDivOpMir(.mul, ty, .unsigned, lhs, rhs);
15051530

1506-
const rhs_mcv = blk: {
1507-
if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
1508-
break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
1531+
break :dst_reg registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*)));
1532+
},
1533+
}
15091534
};
1510-
rhs_mcv.freezeIfRegister(&self.register_manager);
1511-
defer rhs_mcv.unfreezeIfRegister(&self.register_manager);
1535+
defer self.register_manager.unfreezeRegs(&.{dst_reg});
15121536

15131537
const tuple_ty = self.air.typeOfIndex(inst);
15141538
const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
@@ -1521,8 +1545,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15211545
.unsigned => ty,
15221546
};
15231547

1524-
try self.genIntMulComplexOpMir(extended_ty, dst_mcv, rhs_mcv);
1525-
15261548
const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null });
15271549
self.register_manager.freezeRegs(&temp_regs);
15281550
defer self.register_manager.unfreezeRegs(&temp_regs);
@@ -1542,9 +1564,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15421564
});
15431565

15441566
const scratch_reg = temp_regs[1];
1545-
try self.genSetReg(extended_ty, scratch_reg, dst_mcv);
1567+
try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg });
15461568
try self.truncateRegister(ty, scratch_reg);
1547-
try self.genBinMathOpMir(.cmp, extended_ty, dst_mcv, .{ .register = scratch_reg });
1569+
try self.genBinMathOpMir(
1570+
.cmp,
1571+
extended_ty,
1572+
.{ .register = dst_reg },
1573+
.{ .register = scratch_reg },
1574+
);
15481575

15491576
const eq_reg = temp_regs[2];
15501577
_ = try self.addInst(.{
@@ -6626,7 +6653,12 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
66266653
.unsigned => {
66276654
const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
66286655
const mask = (~@as(u64, 0)) >> shift;
6629-
try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
6656+
if (int_info.bits <= 32) {
6657+
try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask });
6658+
} else {
6659+
const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
6660+
try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg });
6661+
}
66306662
},
66316663
}
66326664
}

0 commit comments

Comments
 (0)