authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-05 19:29:24+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-05 22:51:12+02:00
log0728847ce74aace8fe8e2a8f61da09002cd4ad7e
tree789b9d6f3025e9d4e4ed4cf85c14ce16e6f7450b
parent0fc1e8b54f2022081a642c13eb74dfdda5aad867

x64: handle unsigned mul_with_overflow for non-pow-2 ints


1 files changed, 55 insertions(+), 23 deletions(-)

src/arch/x86_64/CodeGen.zig+55-23
......@@ -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}