authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 15:59:02+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 16:14:52+02:00
log67941926b25e1adfdc47d22f7223af12cf3f5b01
treea03c7f044da3c415f8fa9fa67c6d99a743d47440
parentdd62d5941ea77f2ae226b28b0da71abeb92f6140
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: Remove remaining legacy binOp code


1 files changed, 44 insertions(+), 331 deletions(-)

src/arch/aarch64/CodeGen.zig+44-331
......@@ -1497,7 +1497,7 @@ fn allocRegs(
14971497/// instructions which are binary operations acting on two registers
14981498///
14991499/// Returns the destination register
1500fn binOpRegisterNew(
1500fn binOpRegister(
15011501 self: *Self,
15021502 mir_tag: Mir.Inst.Tag,
15031503 lhs_bind: ReadArg.Bind,
......@@ -1582,7 +1582,7 @@ fn binOpRegisterNew(
15821582/// an immediate
15831583///
15841584/// Returns the destination register
1585fn binOpImmediateNew(
1585fn binOpImmediate(
15861586 self: *Self,
15871587 mir_tag: Mir.Inst.Tag,
15881588 lhs_bind: ReadArg.Bind,
......@@ -1639,258 +1639,6 @@ fn binOpImmediateNew(
16391639 return MCValue{ .register = dest_reg };
16401640}
16411641
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.
1650fn 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.
1800fn 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
1888const BinOpMetadata = struct {
1889 inst: Air.Inst.Index,
1890 lhs: Air.Inst.Ref,
1891 rhs: Air.Inst.Ref,
1892};
1893
18941642fn addSub(
18951643 self: *Self,
18961644 tag: Air.Inst.Tag,
......@@ -1938,12 +1686,12 @@ fn addSub(
19381686 };
19391687
19401688 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);
19421690 } else if (lhs_immediate_ok) {
19431691 // 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);
19451693 } 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);
19471695 }
19481696 } else {
19491697 return self.fail("TODO binary operations on int with bits > 64", .{});
......@@ -1971,7 +1719,7 @@ fn mul(
19711719 // TODO add optimisations for multiplication
19721720 // with immediates, for example a * 2 can be
19731721 // 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);
19751723 } else {
19761724 return self.fail("TODO binary operations on int with bits > 64", .{});
19771725 }
......@@ -2019,11 +1767,11 @@ fn divTrunc(
20191767 switch (int_info.signedness) {
20201768 .signed => {
20211769 // 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);
20231771 },
20241772 .unsigned => {
20251773 // 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);
20271775 },
20281776 }
20291777 } else {
......@@ -2056,7 +1804,7 @@ fn divFloor(
20561804 },
20571805 .unsigned => {
20581806 // 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);
20601808 },
20611809 }
20621810 } else {
......@@ -2086,11 +1834,11 @@ fn divExact(
20861834 switch (int_info.signedness) {
20871835 .signed => {
20881836 // 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);
20901838 },
20911839 .unsigned => {
20921840 // 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);
20941842 },
20951843 }
20961844 } else {
......@@ -2248,7 +1996,7 @@ fn bitwise(
22481996 else => unreachable,
22491997 };
22501998
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);
22522000 } else {
22532001 return self.fail("TODO binary operations on int with bits > 64", .{});
22542002 }
......@@ -2293,12 +2041,12 @@ fn shiftExact(
22932041 };
22942042
22952043 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);
22972045 } else {
22982046 // We intentionally pass lhs_ty here in order to
22992047 // prevent using the 32-bit register alias when
23002048 // 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);
23022050 }
23032051 } else {
23042052 return self.fail("TODO binary operations on int with bits > 64", .{});
......@@ -2367,7 +2115,7 @@ fn booleanOp(
23672115 else => unreachable,
23682116 };
23692117
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);
23712119 },
23722120 else => unreachable,
23732121 }
......@@ -2598,12 +2346,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
25982346
25992347 const dest = blk: {
26002348 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);
26022350 } else if (lhs_immediate_ok) {
26032351 // 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);
26052353 } 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);
26072355 }
26082356 };
26092357
......@@ -2634,8 +2382,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
26342382 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
26352383 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
26362384 const result: MCValue = result: {
2637 const lhs = try self.resolveInst(extra.lhs);
2638 const rhs = try self.resolveInst(extra.rhs);
2385 const mod = self.bin_file.options.module.?;
2386
2387 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
2388 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
26392389 const lhs_ty = self.air.typeOf(extra.lhs);
26402390 const rhs_ty = self.air.typeOf(extra.rhs);
26412391
......@@ -2647,20 +2397,19 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
26472397 switch (lhs_ty.zigTypeTag()) {
26482398 .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}),
26492399 .Int => {
2400 assert(lhs_ty.eql(rhs_ty, mod));
26502401 const int_info = lhs_ty.intInfo(self.target.*);
2651
26522402 if (int_info.bits <= 32) {
26532403 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
26542404
26552405 try self.spillCompareFlagsIfOccupied();
2656 self.condition_flags_inst = null;
26572406
26582407 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
26592408 .signed => .smull,
26602409 .unsigned => .umull,
26612410 };
26622411
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);
26642413 const dest_reg = dest.register;
26652414 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
26662415 defer self.register_manager.unlockReg(dest_reg_lock);
......@@ -2709,50 +2458,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
27092458 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
27102459
27112460 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);
27372461
2738 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2739 const raw_reg = try self.register_manager.allocReg(null, gp);
2740 const reg = self.registerAlias(raw_reg, rhs_ty);
2741 break :blk reg;
2742 };
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);
2462 var lhs_reg: Register = undefined;
2463 var rhs_reg: Register = undefined;
2464 var dest_reg: Register = undefined;
2465 var dest_high_reg: Register = undefined;
2466 var truncated_reg: Register = undefined;
27482467
2749 const dest_reg = blk: {
2750 const raw_reg = try self.register_manager.allocReg(null, gp);
2751 const reg = self.registerAlias(raw_reg, lhs_ty);
2752 break :blk reg;
2468 const read_args = [_]ReadArg{
2469 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
2470 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
27532471 };
2754 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
2755 defer self.register_manager.unlockReg(dest_reg_lock);
2472 const write_args = [_]WriteArg{
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 );
27562482
27572483 switch (int_info.signedness) {
27582484 .signed => {
......@@ -2766,10 +2492,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
27662492 } },
27672493 });
27682494
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
27732495 // smulh dest_high, lhs, rhs
27742496 _ = try self.addInst(.{
27752497 .tag = .smulh,
......@@ -2816,10 +2538,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
28162538 }
28172539 },
28182540 .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
28232541 // umulh dest_high, lhs, rhs
28242542 _ = try self.addInst(.{
28252543 .tag = .umulh,
......@@ -2870,10 +2588,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
28702588 },
28712589 }
28722590
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
28772591 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
28782592
28792593 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
......@@ -2893,6 +2607,8 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
28932607 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
28942608 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
28952609 const result: MCValue = result: {
2610 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
2611 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
28962612 const lhs_ty = self.air.typeOf(extra.lhs);
28972613 const rhs_ty = self.air.typeOf(extra.rhs);
28982614
......@@ -2910,9 +2626,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
29102626
29112627 try self.spillCompareFlagsIfOccupied();
29122628
2913 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
2914 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
2915
29162629 var lhs_reg: Register = undefined;
29172630 var rhs_reg: Register = undefined;
29182631 var dest_reg: Register = undefined;