| ... | @@ -1497,7 +1497,7 @@ fn allocRegs( | ... | @@ -1497,7 +1497,7 @@ fn allocRegs( |
| 1497 | /// instructions which are binary operations acting on two registers | 1497 | /// instructions which are binary operations acting on two registers |
| 1498 | /// | 1498 | /// |
| 1499 | /// Returns the destination register | 1499 | /// Returns the destination register |
| 1500 | fn binOpRegisterNew( | 1500 | fn binOpRegister( |
| 1501 | self: *Self, | 1501 | self: *Self, |
| 1502 | mir_tag: Mir.Inst.Tag, | 1502 | mir_tag: Mir.Inst.Tag, |
| 1503 | lhs_bind: ReadArg.Bind, | 1503 | lhs_bind: ReadArg.Bind, |
| ... | @@ -1582,7 +1582,7 @@ fn binOpRegisterNew( | ... | @@ -1582,7 +1582,7 @@ fn binOpRegisterNew( |
| 1582 | /// an immediate | 1582 | /// an immediate |
| 1583 | /// | 1583 | /// |
| 1584 | /// Returns the destination register | 1584 | /// Returns the destination register |
| 1585 | fn binOpImmediateNew( | 1585 | fn binOpImmediate( |
| 1586 | self: *Self, | 1586 | self: *Self, |
| 1587 | mir_tag: Mir.Inst.Tag, | 1587 | mir_tag: Mir.Inst.Tag, |
| 1588 | lhs_bind: ReadArg.Bind, | 1588 | lhs_bind: ReadArg.Bind, |
| ... | @@ -1639,258 +1639,6 @@ fn binOpImmediateNew( | ... | @@ -1639,258 +1639,6 @@ fn binOpImmediateNew( |
| 1639 | return MCValue{ .register = dest_reg }; | 1639 | return MCValue{ .register = dest_reg }; |
| 1640 | } | 1640 | } |
| 1641 | | 1641 | |
| 1642 | /// Don't call this function directly. Use binOp instead. | | |
| 1643 | /// | | |
| 1644 | /// Calling this function signals an intention to generate a Mir | | |
| 1645 | /// instruction of the form | | |
| 1646 | /// | | |
| 1647 | /// op dest, lhs, rhs | | |
| 1648 | /// | | |
| 1649 | /// Asserts that generating an instruction of that form is possible. | | |
| 1650 | fn binOpRegister( | | |
| 1651 | self: *Self, | | |
| 1652 | mir_tag: Mir.Inst.Tag, | | |
| 1653 | lhs: MCValue, | | |
| 1654 | rhs: MCValue, | | |
| 1655 | lhs_ty: Type, | | |
| 1656 | rhs_ty: Type, | | |
| 1657 | metadata: ?BinOpMetadata, | | |
| 1658 | ) !MCValue { | | |
| 1659 | const lhs_is_register = lhs == .register; | | |
| 1660 | const rhs_is_register = rhs == .register; | | |
| 1661 | | | |
| 1662 | if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty)); | | |
| 1663 | if (rhs_is_register) assert(rhs.register == self.registerAlias(rhs.register, rhs_ty)); | | |
| 1664 | | | |
| 1665 | const lhs_lock: ?RegisterLock = if (lhs_is_register) | | |
| 1666 | self.register_manager.lockReg(lhs.register) | | |
| 1667 | else | | |
| 1668 | null; | | |
| 1669 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1670 | | | |
| 1671 | const rhs_lock: ?RegisterLock = if (rhs_is_register) | | |
| 1672 | self.register_manager.lockReg(rhs.register) | | |
| 1673 | else | | |
| 1674 | null; | | |
| 1675 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1676 | | | |
| 1677 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | | |
| 1678 | | | |
| 1679 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { | | |
| 1680 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | | |
| 1681 | break :inst Air.refToIndex(md.lhs).?; | | |
| 1682 | } else null; | | |
| 1683 | | | |
| 1684 | const raw_reg = try self.register_manager.allocReg(track_inst, gp); | | |
| 1685 | const reg = self.registerAlias(raw_reg, lhs_ty); | | |
| 1686 | | | |
| 1687 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | | |
| 1688 | | | |
| 1689 | break :blk reg; | | |
| 1690 | }; | | |
| 1691 | const new_lhs_lock = self.register_manager.lockReg(lhs_reg); | | |
| 1692 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1693 | | | |
| 1694 | const rhs_reg = if (rhs_is_register) | | |
| 1695 | // lhs is almost always equal to rhs, except in shifts. In | | |
| 1696 | // order to guarantee that registers will have equal sizes, we | | |
| 1697 | // use the register alias of rhs corresponding to the size of | | |
| 1698 | // lhs. | | |
| 1699 | self.registerAlias(rhs.register, lhs_ty) | | |
| 1700 | else blk: { | | |
| 1701 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | | |
| 1702 | break :inst Air.refToIndex(md.rhs).?; | | |
| 1703 | } else null; | | |
| 1704 | | | |
| 1705 | const raw_reg = try self.register_manager.allocReg(track_inst, gp); | | |
| 1706 | | | |
| 1707 | // Here, we deliberately use lhs as lhs and rhs may differ in | | |
| 1708 | // the case of shifts. See comment above. | | |
| 1709 | const reg = self.registerAlias(raw_reg, lhs_ty); | | |
| 1710 | | | |
| 1711 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | | |
| 1712 | | | |
| 1713 | break :blk reg; | | |
| 1714 | }; | | |
| 1715 | const new_rhs_lock = self.register_manager.lockReg(rhs_reg); | | |
| 1716 | defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1717 | | | |
| 1718 | const dest_reg = switch (mir_tag) { | | |
| 1719 | else => if (metadata) |md| blk: { | | |
| 1720 | if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) { | | |
| 1721 | break :blk lhs_reg; | | |
| 1722 | } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) { | | |
| 1723 | break :blk rhs_reg; | | |
| 1724 | } else { | | |
| 1725 | const raw_reg = try self.register_manager.allocReg(md.inst, gp); | | |
| 1726 | break :blk self.registerAlias(raw_reg, lhs_ty); | | |
| 1727 | } | | |
| 1728 | } else blk: { | | |
| 1729 | const raw_reg = try self.register_manager.allocReg(null, gp); | | |
| 1730 | break :blk self.registerAlias(raw_reg, lhs_ty); | | |
| 1731 | }, | | |
| 1732 | }; | | |
| 1733 | | | |
| 1734 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 1735 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 1736 | | | |
| 1737 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | | |
| 1738 | .add_shifted_register, | | |
| 1739 | .adds_shifted_register, | | |
| 1740 | .sub_shifted_register, | | |
| 1741 | .subs_shifted_register, | | |
| 1742 | => .{ .rrr_imm6_shift = .{ | | |
| 1743 | .rd = dest_reg, | | |
| 1744 | .rn = lhs_reg, | | |
| 1745 | .rm = rhs_reg, | | |
| 1746 | .imm6 = 0, | | |
| 1747 | .shift = .lsl, | | |
| 1748 | } }, | | |
| 1749 | .mul, | | |
| 1750 | .lsl_register, | | |
| 1751 | .asr_register, | | |
| 1752 | .lsr_register, | | |
| 1753 | .sdiv, | | |
| 1754 | .udiv, | | |
| 1755 | => .{ .rrr = .{ | | |
| 1756 | .rd = dest_reg, | | |
| 1757 | .rn = lhs_reg, | | |
| 1758 | .rm = rhs_reg, | | |
| 1759 | } }, | | |
| 1760 | .smull, | | |
| 1761 | .umull, | | |
| 1762 | => .{ .rrr = .{ | | |
| 1763 | .rd = dest_reg.toX(), | | |
| 1764 | .rn = lhs_reg, | | |
| 1765 | .rm = rhs_reg, | | |
| 1766 | } }, | | |
| 1767 | .and_shifted_register, | | |
| 1768 | .orr_shifted_register, | | |
| 1769 | .eor_shifted_register, | | |
| 1770 | => .{ .rrr_imm6_logical_shift = .{ | | |
| 1771 | .rd = dest_reg, | | |
| 1772 | .rn = lhs_reg, | | |
| 1773 | .rm = rhs_reg, | | |
| 1774 | .imm6 = 0, | | |
| 1775 | .shift = .lsl, | | |
| 1776 | } }, | | |
| 1777 | else => unreachable, | | |
| 1778 | }; | | |
| 1779 | | | |
| 1780 | _ = try self.addInst(.{ | | |
| 1781 | .tag = mir_tag, | | |
| 1782 | .data = mir_data, | | |
| 1783 | }); | | |
| 1784 | | | |
| 1785 | return MCValue{ .register = dest_reg }; | | |
| 1786 | } | | |
| 1787 | | | |
| 1788 | /// Don't call this function directly. Use binOp instead. | | |
| 1789 | /// | | |
| 1790 | /// Calling this function signals an intention to generate a Mir | | |
| 1791 | /// instruction of the form | | |
| 1792 | /// | | |
| 1793 | /// op dest, lhs, #rhs_imm | | |
| 1794 | /// | | |
| 1795 | /// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to | | |
| 1796 | /// rhs and vice versa. This parameter is only used when maybe_inst != | | |
| 1797 | /// null. | | |
| 1798 | /// | | |
| 1799 | /// Asserts that generating an instruction of that form is possible. | | |
| 1800 | fn binOpImmediate( | | |
| 1801 | self: *Self, | | |
| 1802 | mir_tag: Mir.Inst.Tag, | | |
| 1803 | lhs: MCValue, | | |
| 1804 | rhs: MCValue, | | |
| 1805 | lhs_ty: Type, | | |
| 1806 | lhs_and_rhs_swapped: bool, | | |
| 1807 | metadata: ?BinOpMetadata, | | |
| 1808 | ) !MCValue { | | |
| 1809 | const lhs_is_register = lhs == .register; | | |
| 1810 | | | |
| 1811 | if (lhs_is_register) assert(lhs.register == self.registerAlias(lhs.register, lhs_ty)); | | |
| 1812 | | | |
| 1813 | const lhs_lock: ?RegisterLock = if (lhs_is_register) | | |
| 1814 | self.register_manager.lockReg(lhs.register) | | |
| 1815 | else | | |
| 1816 | null; | | |
| 1817 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1818 | | | |
| 1819 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | | |
| 1820 | | | |
| 1821 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { | | |
| 1822 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | | |
| 1823 | break :inst Air.refToIndex( | | |
| 1824 | if (lhs_and_rhs_swapped) md.rhs else md.lhs, | | |
| 1825 | ).?; | | |
| 1826 | } else null; | | |
| 1827 | | | |
| 1828 | const raw_reg = try self.register_manager.allocReg(track_inst, gp); | | |
| 1829 | const reg = self.registerAlias(raw_reg, lhs_ty); | | |
| 1830 | | | |
| 1831 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | | |
| 1832 | | | |
| 1833 | break :blk reg; | | |
| 1834 | }; | | |
| 1835 | const new_lhs_lock = self.register_manager.lockReg(lhs_reg); | | |
| 1836 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1837 | | | |
| 1838 | const dest_reg = switch (mir_tag) { | | |
| 1839 | else => if (metadata) |md| blk: { | | |
| 1840 | if (lhs_is_register and self.reuseOperand( | | |
| 1841 | md.inst, | | |
| 1842 | if (lhs_and_rhs_swapped) md.rhs else md.lhs, | | |
| 1843 | if (lhs_and_rhs_swapped) 1 else 0, | | |
| 1844 | lhs, | | |
| 1845 | )) { | | |
| 1846 | break :blk lhs_reg; | | |
| 1847 | } else { | | |
| 1848 | const raw_reg = try self.register_manager.allocReg(md.inst, gp); | | |
| 1849 | break :blk self.registerAlias(raw_reg, lhs_ty); | | |
| 1850 | } | | |
| 1851 | } else blk: { | | |
| 1852 | const raw_reg = try self.register_manager.allocReg(null, gp); | | |
| 1853 | break :blk self.registerAlias(raw_reg, lhs_ty); | | |
| 1854 | }, | | |
| 1855 | }; | | |
| 1856 | | | |
| 1857 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 1858 | | | |
| 1859 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | | |
| 1860 | .add_immediate, | | |
| 1861 | .adds_immediate, | | |
| 1862 | .sub_immediate, | | |
| 1863 | .subs_immediate, | | |
| 1864 | => .{ .rr_imm12_sh = .{ | | |
| 1865 | .rd = dest_reg, | | |
| 1866 | .rn = lhs_reg, | | |
| 1867 | .imm12 = @intCast(u12, rhs.immediate), | | |
| 1868 | } }, | | |
| 1869 | .lsl_immediate, | | |
| 1870 | .asr_immediate, | | |
| 1871 | .lsr_immediate, | | |
| 1872 | => .{ .rr_shift = .{ | | |
| 1873 | .rd = dest_reg, | | |
| 1874 | .rn = lhs_reg, | | |
| 1875 | .shift = @intCast(u6, rhs.immediate), | | |
| 1876 | } }, | | |
| 1877 | else => unreachable, | | |
| 1878 | }; | | |
| 1879 | | | |
| 1880 | _ = try self.addInst(.{ | | |
| 1881 | .tag = mir_tag, | | |
| 1882 | .data = mir_data, | | |
| 1883 | }); | | |
| 1884 | | | |
| 1885 | return MCValue{ .register = dest_reg }; | | |
| 1886 | } | | |
| 1887 | | | |
| 1888 | const BinOpMetadata = struct { | | |
| 1889 | inst: Air.Inst.Index, | | |
| 1890 | lhs: Air.Inst.Ref, | | |
| 1891 | rhs: Air.Inst.Ref, | | |
| 1892 | }; | | |
| 1893 | | | |
| 1894 | fn addSub( | 1642 | fn addSub( |
| 1895 | self: *Self, | 1643 | self: *Self, |
| 1896 | tag: Air.Inst.Tag, | 1644 | tag: Air.Inst.Tag, |
| ... | @@ -1938,12 +1686,12 @@ fn addSub( | ... | @@ -1938,12 +1686,12 @@ fn addSub( |
| 1938 | }; | 1686 | }; |
| 1939 | | 1687 | |
| 1940 | if (rhs_immediate_ok) { | 1688 | if (rhs_immediate_ok) { |
| 1941 | return try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); | 1689 | return try self.binOpImmediate(mir_tag_immediate, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 1942 | } else if (lhs_immediate_ok) { | 1690 | } else if (lhs_immediate_ok) { |
| 1943 | // swap lhs and rhs | 1691 | // swap lhs and rhs |
| 1944 | return try self.binOpImmediateNew(mir_tag_immediate, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); | 1692 | return try self.binOpImmediate(mir_tag_immediate, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 1945 | } else { | 1693 | } else { |
| 1946 | return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1694 | return try self.binOpRegister(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 1947 | } | 1695 | } |
| 1948 | } else { | 1696 | } else { |
| 1949 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1697 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | @@ -1971,7 +1719,7 @@ fn mul( | ... | @@ -1971,7 +1719,7 @@ fn mul( |
| 1971 | // TODO add optimisations for multiplication | 1719 | // TODO add optimisations for multiplication |
| 1972 | // with immediates, for example a * 2 can be | 1720 | // with immediates, for example a * 2 can be |
| 1973 | // lowered to a << 1 | 1721 | // lowered to a << 1 |
| 1974 | return try self.binOpRegisterNew(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1722 | return try self.binOpRegister(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 1975 | } else { | 1723 | } else { |
| 1976 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1724 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1977 | } | 1725 | } |
| ... | @@ -2019,11 +1767,11 @@ fn divTrunc( | ... | @@ -2019,11 +1767,11 @@ fn divTrunc( |
| 2019 | switch (int_info.signedness) { | 1767 | switch (int_info.signedness) { |
| 2020 | .signed => { | 1768 | .signed => { |
| 2021 | // TODO optimize integer division by constants | 1769 | // TODO optimize integer division by constants |
| 2022 | return try self.binOpRegisterNew(.sdiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1770 | return try self.binOpRegister(.sdiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2023 | }, | 1771 | }, |
| 2024 | .unsigned => { | 1772 | .unsigned => { |
| 2025 | // TODO optimize integer division by constants | 1773 | // TODO optimize integer division by constants |
| 2026 | return try self.binOpRegisterNew(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1774 | return try self.binOpRegister(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2027 | }, | 1775 | }, |
| 2028 | } | 1776 | } |
| 2029 | } else { | 1777 | } else { |
| ... | @@ -2056,7 +1804,7 @@ fn divFloor( | ... | @@ -2056,7 +1804,7 @@ fn divFloor( |
| 2056 | }, | 1804 | }, |
| 2057 | .unsigned => { | 1805 | .unsigned => { |
| 2058 | // TODO optimize integer division by constants | 1806 | // TODO optimize integer division by constants |
| 2059 | return try self.binOpRegisterNew(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1807 | return try self.binOpRegister(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2060 | }, | 1808 | }, |
| 2061 | } | 1809 | } |
| 2062 | } else { | 1810 | } else { |
| ... | @@ -2086,11 +1834,11 @@ fn divExact( | ... | @@ -2086,11 +1834,11 @@ fn divExact( |
| 2086 | switch (int_info.signedness) { | 1834 | switch (int_info.signedness) { |
| 2087 | .signed => { | 1835 | .signed => { |
| 2088 | // TODO optimize integer division by constants | 1836 | // TODO optimize integer division by constants |
| 2089 | return try self.binOpRegisterNew(.sdiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1837 | return try self.binOpRegister(.sdiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2090 | }, | 1838 | }, |
| 2091 | .unsigned => { | 1839 | .unsigned => { |
| 2092 | // TODO optimize integer division by constants | 1840 | // TODO optimize integer division by constants |
| 2093 | return try self.binOpRegisterNew(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1841 | return try self.binOpRegister(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2094 | }, | 1842 | }, |
| 2095 | } | 1843 | } |
| 2096 | } else { | 1844 | } else { |
| ... | @@ -2248,7 +1996,7 @@ fn bitwise( | ... | @@ -2248,7 +1996,7 @@ fn bitwise( |
| 2248 | else => unreachable, | 1996 | else => unreachable, |
| 2249 | }; | 1997 | }; |
| 2250 | | 1998 | |
| 2251 | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 1999 | return try self.binOpRegister(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2252 | } else { | 2000 | } else { |
| 2253 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 2001 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 2254 | } | 2002 | } |
| ... | @@ -2293,12 +2041,12 @@ fn shiftExact( | ... | @@ -2293,12 +2041,12 @@ fn shiftExact( |
| 2293 | }; | 2041 | }; |
| 2294 | | 2042 | |
| 2295 | if (rhs_immediate) |imm| { | 2043 | if (rhs_immediate) |imm| { |
| 2296 | return try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, imm, lhs_ty, false, maybe_inst); | 2044 | return try self.binOpImmediate(mir_tag_immediate, lhs_bind, imm, lhs_ty, false, maybe_inst); |
| 2297 | } else { | 2045 | } else { |
| 2298 | // We intentionally pass lhs_ty here in order to | 2046 | // We intentionally pass lhs_ty here in order to |
| 2299 | // prevent using the 32-bit register alias when | 2047 | // prevent using the 32-bit register alias when |
| 2300 | // lhs_ty is > 32 bits. | 2048 | // lhs_ty is > 32 bits. |
| 2301 | return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, lhs_ty, maybe_inst); | 2049 | return try self.binOpRegister(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, lhs_ty, maybe_inst); |
| 2302 | } | 2050 | } |
| 2303 | } else { | 2051 | } else { |
| 2304 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 2052 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | @@ -2367,7 +2115,7 @@ fn booleanOp( | ... | @@ -2367,7 +2115,7 @@ fn booleanOp( |
| 2367 | else => unreachable, | 2115 | else => unreachable, |
| 2368 | }; | 2116 | }; |
| 2369 | | 2117 | |
| 2370 | return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | 2118 | return try self.binOpRegister(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2371 | }, | 2119 | }, |
| 2372 | else => unreachable, | 2120 | else => unreachable, |
| 2373 | } | 2121 | } |
| ... | @@ -2598,12 +2346,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2598,12 +2346,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2598 | | 2346 | |
| 2599 | const dest = blk: { | 2347 | const dest = blk: { |
| 2600 | if (rhs_immediate_ok) { | 2348 | if (rhs_immediate_ok) { |
| 2601 | break :blk try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, rhs_immediate.?, lhs_ty, false, null); | 2349 | break :blk try self.binOpImmediate(mir_tag_immediate, lhs_bind, rhs_immediate.?, lhs_ty, false, null); |
| 2602 | } else if (lhs_immediate_ok) { | 2350 | } else if (lhs_immediate_ok) { |
| 2603 | // swap lhs and rhs | 2351 | // swap lhs and rhs |
| 2604 | break :blk try self.binOpImmediateNew(mir_tag_immediate, rhs_bind, lhs_immediate.?, rhs_ty, true, null); | 2352 | break :blk try self.binOpImmediate(mir_tag_immediate, rhs_bind, lhs_immediate.?, rhs_ty, true, null); |
| 2605 | } else { | 2353 | } else { |
| 2606 | break :blk try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); | 2354 | break :blk try self.binOpRegister(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 2607 | } | 2355 | } |
| 2608 | }; | 2356 | }; |
| 2609 | | 2357 | |
| ... | @@ -2634,8 +2382,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2634,8 +2382,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2634 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2382 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2635 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 2383 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 2636 | const result: MCValue = result: { | 2384 | const result: MCValue = result: { |
| 2637 | const lhs = try self.resolveInst(extra.lhs); | 2385 | const mod = self.bin_file.options.module.?; |
| 2638 | const rhs = try self.resolveInst(extra.rhs); | 2386 | |
| | 2387 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| | 2388 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2639 | const lhs_ty = self.air.typeOf(extra.lhs); | 2389 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 2640 | const rhs_ty = self.air.typeOf(extra.rhs); | 2390 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 2641 | | 2391 | |
| ... | @@ -2647,20 +2397,19 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2647,20 +2397,19 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2647 | switch (lhs_ty.zigTypeTag()) { | 2397 | switch (lhs_ty.zigTypeTag()) { |
| 2648 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), | 2398 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2649 | .Int => { | 2399 | .Int => { |
| | 2400 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2650 | const int_info = lhs_ty.intInfo(self.target.*); | 2401 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2651 | | | |
| 2652 | if (int_info.bits <= 32) { | 2402 | if (int_info.bits <= 32) { |
| 2653 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2403 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2654 | | 2404 | |
| 2655 | try self.spillCompareFlagsIfOccupied(); | 2405 | try self.spillCompareFlagsIfOccupied(); |
| 2656 | self.condition_flags_inst = null; | | |
| 2657 | | 2406 | |
| 2658 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { | 2407 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 2659 | .signed => .smull, | 2408 | .signed => .smull, |
| 2660 | .unsigned => .umull, | 2409 | .unsigned => .umull, |
| 2661 | }; | 2410 | }; |
| 2662 | | 2411 | |
| 2663 | const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null); | 2412 | const dest = try self.binOpRegister(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 2664 | const dest_reg = dest.register; | 2413 | const dest_reg = dest.register; |
| 2665 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); | 2414 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 2666 | defer self.register_manager.unlockReg(dest_reg_lock); | 2415 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | @@ -2709,50 +2458,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2709,50 +2458,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2709 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2458 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2710 | | 2459 | |
| 2711 | try self.spillCompareFlagsIfOccupied(); | 2460 | try self.spillCompareFlagsIfOccupied(); |
| 2712 | self.condition_flags_inst = null; | | |
| 2713 | | | |
| 2714 | // TODO this should really be put in a helper similar to `binOpRegister` | | |
| 2715 | const lhs_is_register = lhs == .register; | | |
| 2716 | const rhs_is_register = rhs == .register; | | |
| 2717 | | | |
| 2718 | const lhs_lock: ?RegisterLock = if (lhs_is_register) | | |
| 2719 | self.register_manager.lockRegAssumeUnused(lhs.register) | | |
| 2720 | else | | |
| 2721 | null; | | |
| 2722 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2723 | | | |
| 2724 | const rhs_lock: ?RegisterLock = if (rhs_is_register) | | |
| 2725 | self.register_manager.lockRegAssumeUnused(rhs.register) | | |
| 2726 | else | | |
| 2727 | null; | | |
| 2728 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2729 | | | |
| 2730 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { | | |
| 2731 | const raw_reg = try self.register_manager.allocReg(null, gp); | | |
| 2732 | const reg = self.registerAlias(raw_reg, lhs_ty); | | |
| 2733 | break :blk reg; | | |
| 2734 | }; | | |
| 2735 | const new_lhs_lock = self.register_manager.lockReg(lhs_reg); | | |
| 2736 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2737 | | 2461 | |
| 2738 | const rhs_reg = if (rhs_is_register) rhs.register else blk: { | 2462 | var lhs_reg: Register = undefined; |
| 2739 | const raw_reg = try self.register_manager.allocReg(null, gp); | 2463 | var rhs_reg: Register = undefined; |
| 2740 | const reg = self.registerAlias(raw_reg, rhs_ty); | 2464 | var dest_reg: Register = undefined; |
| 2741 | break :blk reg; | 2465 | var dest_high_reg: Register = undefined; |
| 2742 | }; | 2466 | var truncated_reg: Register = undefined; |
| 2743 | const new_rhs_lock = self.register_manager.lockReg(rhs_reg); | | |
| 2744 | defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2745 | | | |
| 2746 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 2747 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 2748 | | 2467 | |
| 2749 | const dest_reg = blk: { | 2468 | const read_args = [_]ReadArg{ |
| 2750 | const raw_reg = try self.register_manager.allocReg(null, gp); | 2469 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 2751 | const reg = self.registerAlias(raw_reg, lhs_ty); | 2470 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| 2752 | break :blk reg; | | |
| 2753 | }; | 2471 | }; |
| 2754 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); | 2472 | const write_args = [_]WriteArg{ |
| 2755 | defer self.register_manager.unlockReg(dest_reg_lock); | 2473 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| | 2474 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_high_reg }, |
| | 2475 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &truncated_reg }, |
| | 2476 | }; |
| | 2477 | try self.allocRegs( |
| | 2478 | &read_args, |
| | 2479 | &write_args, |
| | 2480 | null, |
| | 2481 | ); |
| 2756 | | 2482 | |
| 2757 | switch (int_info.signedness) { | 2483 | switch (int_info.signedness) { |
| 2758 | .signed => { | 2484 | .signed => { |
| ... | @@ -2766,10 +2492,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2766,10 +2492,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2766 | } }, | 2492 | } }, |
| 2767 | }); | 2493 | }); |
| 2768 | | 2494 | |
| 2769 | const dest_high_reg = try self.register_manager.allocReg(null, gp); | | |
| 2770 | const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg); | | |
| 2771 | defer self.register_manager.unlockReg(dest_high_reg_lock); | | |
| 2772 | | | |
| 2773 | // smulh dest_high, lhs, rhs | 2495 | // smulh dest_high, lhs, rhs |
| 2774 | _ = try self.addInst(.{ | 2496 | _ = try self.addInst(.{ |
| 2775 | .tag = .smulh, | 2497 | .tag = .smulh, |
| ... | @@ -2816,10 +2538,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2816,10 +2538,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2816 | } | 2538 | } |
| 2817 | }, | 2539 | }, |
| 2818 | .unsigned => { | 2540 | .unsigned => { |
| 2819 | const dest_high_reg = try self.register_manager.allocReg(null, gp); | | |
| 2820 | const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg); | | |
| 2821 | defer self.register_manager.unlockReg(dest_high_reg_lock); | | |
| 2822 | | | |
| 2823 | // umulh dest_high, lhs, rhs | 2541 | // umulh dest_high, lhs, rhs |
| 2824 | _ = try self.addInst(.{ | 2542 | _ = try self.addInst(.{ |
| 2825 | .tag = .umulh, | 2543 | .tag = .umulh, |
| ... | @@ -2870,10 +2588,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2870,10 +2588,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2870 | }, | 2588 | }, |
| 2871 | } | 2589 | } |
| 2872 | | 2590 | |
| 2873 | const truncated_reg = try self.register_manager.allocReg(null, gp); | | |
| 2874 | const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg); | | |
| 2875 | defer self.register_manager.unlockReg(truncated_reg_lock); | | |
| 2876 | | | |
| 2877 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); | 2591 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2878 | | 2592 | |
| 2879 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2593 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| ... | @@ -2893,6 +2607,8 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2893,6 +2607,8 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2893 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2607 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2894 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 2608 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 2895 | const result: MCValue = result: { | 2609 | const result: MCValue = result: { |
| | 2610 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| | 2611 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2896 | const lhs_ty = self.air.typeOf(extra.lhs); | 2612 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 2897 | const rhs_ty = self.air.typeOf(extra.rhs); | 2613 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 2898 | | 2614 | |
| ... | @@ -2910,9 +2626,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2910,9 +2626,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2910 | | 2626 | |
| 2911 | try self.spillCompareFlagsIfOccupied(); | 2627 | try self.spillCompareFlagsIfOccupied(); |
| 2912 | | 2628 | |
| 2913 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | | |
| 2914 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | | |
| 2915 | | | |
| 2916 | var lhs_reg: Register = undefined; | 2629 | var lhs_reg: Register = undefined; |
| 2917 | var rhs_reg: Register = undefined; | 2630 | var rhs_reg: Register = undefined; |
| 2918 | var dest_reg: Register = undefined; | 2631 | var dest_reg: Register = undefined; |