| ... | ... | @@ -1404,8 +1404,10 @@ fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 1404 | 1404 | } |
| 1405 | 1405 | |
| 1406 | 1406 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1407 | | try self.register_manager.getReg(.rax, null); |
| 1407 | try self.register_manager.getReg(.rax, inst); |
| 1408 | 1408 | try self.register_manager.getReg(.rdx, null); |
| 1409 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1410 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1409 | 1411 | |
| 1410 | 1412 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1411 | 1413 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1501,8 +1503,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1501 | 1503 | }; |
| 1502 | 1504 | |
| 1503 | 1505 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1504 | | try self.register_manager.getReg(.rax, null); |
| 1506 | try self.register_manager.getReg(.rax, inst); |
| 1505 | 1507 | try self.register_manager.getReg(.rdx, null); |
| 1508 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1509 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1506 | 1510 | |
| 1507 | 1511 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1508 | 1512 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1527,7 +1531,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1527 | 1531 | } |
| 1528 | 1532 | |
| 1529 | 1533 | /// Generates signed or unsigned integer multiplication/division. |
| 1530 | | /// Requires use of .rax and .rdx registers. Spills them if necessary. |
| 1534 | /// Clobbers .rax and .rdx registers. |
| 1531 | 1535 | /// Quotient is saved in .rax and remainder in .rdx. |
| 1532 | 1536 | fn genIntMulDivOpMir( |
| 1533 | 1537 | self: *Self, |
| ... | ... | @@ -1542,11 +1546,6 @@ fn genIntMulDivOpMir( |
| 1542 | 1546 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); |
| 1543 | 1547 | } |
| 1544 | 1548 | |
| 1545 | | try self.register_manager.getReg(.rax, null); |
| 1546 | | try self.register_manager.getReg(.rdx, null); |
| 1547 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1548 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1549 | | |
| 1550 | 1549 | try self.genSetReg(ty, .rax, lhs); |
| 1551 | 1550 | |
| 1552 | 1551 | switch (signedness) { |
| ... | ... | @@ -1610,6 +1609,7 @@ fn genIntMulDivOpMir( |
| 1610 | 1609 | } |
| 1611 | 1610 | } |
| 1612 | 1611 | |
| 1612 | /// Clobbers .rax and .rdx registers. |
| 1613 | 1613 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 1614 | 1614 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1615 | 1615 | const dividend = switch (lhs) { |
| ... | ... | @@ -1680,14 +1680,42 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1680 | 1680 | return self.fail("TODO implement {}", .{tag}); |
| 1681 | 1681 | } |
| 1682 | 1682 | |
| 1683 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1684 | |
| 1683 | 1685 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1684 | | try self.register_manager.getReg(.rax, null); |
| 1686 | const track_rax: ?Air.Inst.Index = blk: { |
| 1687 | if (signedness == .unsigned) break :blk inst; |
| 1688 | switch (tag) { |
| 1689 | .div_exact, .div_trunc => break :blk inst, |
| 1690 | else => break :blk null, |
| 1691 | } |
| 1692 | }; |
| 1693 | try self.register_manager.getReg(.rax, track_rax); |
| 1685 | 1694 | try self.register_manager.getReg(.rdx, null); |
| 1695 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1696 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1686 | 1697 | |
| 1687 | 1698 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1688 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1699 | lhs.freezeIfRegister(&self.register_manager); |
| 1700 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 1701 | |
| 1702 | const rhs = blk: { |
| 1703 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1704 | if (signedness == .signed) { |
| 1705 | switch (tag) { |
| 1706 | .div_floor => { |
| 1707 | rhs.freezeIfRegister(&self.register_manager); |
| 1708 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1709 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| 1710 | }, |
| 1711 | else => {}, |
| 1712 | } |
| 1713 | } |
| 1714 | break :blk rhs; |
| 1715 | }; |
| 1716 | rhs.freezeIfRegister(&self.register_manager); |
| 1717 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1689 | 1718 | |
| 1690 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1691 | 1719 | if (signedness == .unsigned) { |
| 1692 | 1720 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); |
| 1693 | 1721 | break :result MCValue{ .register = .rax }; |
| ... | ... | @@ -1719,9 +1747,13 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1719 | 1747 | } |
| 1720 | 1748 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1721 | 1749 | try self.register_manager.getReg(.rax, null); |
| 1722 | | try self.register_manager.getReg(.rdx, null); |
| 1750 | try self.register_manager.getReg(.rdx, inst); |
| 1751 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1752 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1753 | |
| 1723 | 1754 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1724 | 1755 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1756 | |
| 1725 | 1757 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1726 | 1758 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1727 | 1759 | .signed => .idiv, |
| ... | ... | @@ -1739,12 +1771,17 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1739 | 1771 | if (ty.zigTypeTag() != .Int) { |
| 1740 | 1772 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1741 | 1773 | } |
| 1774 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1775 | |
| 1742 | 1776 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1743 | 1777 | try self.register_manager.getReg(.rax, null); |
| 1744 | | try self.register_manager.getReg(.rdx, null); |
| 1778 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); |
| 1779 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1780 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1781 | |
| 1745 | 1782 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1746 | 1783 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1747 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1784 | |
| 1748 | 1785 | switch (signedness) { |
| 1749 | 1786 | .unsigned => { |
| 1750 | 1787 | try self.genIntMulDivOpMir(switch (signedness) { |
| ... | ... | @@ -1757,10 +1794,10 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1757 | 1794 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); |
| 1758 | 1795 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 1759 | 1796 | |
| 1760 | | const reg = try self.copyToTmpRegister(ty, lhs); |
| 1761 | | try self.genBinMathOpMir(.sub, ty, .{ .register = reg }, div_floor); |
| 1797 | const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); |
| 1798 | try self.genBinMathOpMir(.sub, ty, result, div_floor); |
| 1762 | 1799 | |
| 1763 | | break :result MCValue{ .register = reg }; |
| 1800 | break :result result; |
| 1764 | 1801 | }, |
| 1765 | 1802 | } |
| 1766 | 1803 | }; |