| ... | ... | @@ -1315,7 +1315,13 @@ fn minMax( |
| 1315 | 1315 | // register. |
| 1316 | 1316 | assert(lhs_reg != rhs_reg); // see note above |
| 1317 | 1317 | |
| 1318 | | _ = try self.binOpRegister(.cmp, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty, null); |
| 1318 | _ = try self.addInst(.{ |
| 1319 | .tag = .cmp, |
| 1320 | .data = .{ .r_op_cmp = .{ |
| 1321 | .rn = lhs_reg, |
| 1322 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 1323 | } }, |
| 1324 | }); |
| 1319 | 1325 | |
| 1320 | 1326 | const cond_choose_lhs: Condition = switch (tag) { |
| 1321 | 1327 | .max => switch (int_info.signedness) { |
| ... | ... | @@ -1473,7 +1479,6 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1473 | 1479 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1474 | 1480 | |
| 1475 | 1481 | try self.spillCompareFlagsIfOccupied(); |
| 1476 | | self.cpsr_flags_inst = null; |
| 1477 | 1482 | |
| 1478 | 1483 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 1479 | 1484 | .add_with_overflow => .add, |
| ... | ... | @@ -1493,7 +1498,13 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1493 | 1498 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 1494 | 1499 | |
| 1495 | 1500 | // cmp dest, truncated |
| 1496 | | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); |
| 1501 | _ = try self.addInst(.{ |
| 1502 | .tag = .cmp, |
| 1503 | .data = .{ .r_op_cmp = .{ |
| 1504 | .rn = dest_reg, |
| 1505 | .op = Instruction.Operand.reg(truncated_reg, Instruction.Operand.Shift.none), |
| 1506 | } }, |
| 1507 | }); |
| 1497 | 1508 | |
| 1498 | 1509 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1499 | 1510 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| ... | ... | @@ -1578,7 +1589,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1578 | 1589 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1579 | 1590 | |
| 1580 | 1591 | try self.spillCompareFlagsIfOccupied(); |
| 1581 | | self.cpsr_flags_inst = null; |
| 1582 | 1592 | |
| 1583 | 1593 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 1584 | 1594 | .signed => .smulbb, |
| ... | ... | @@ -1598,7 +1608,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1598 | 1608 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 1599 | 1609 | |
| 1600 | 1610 | // cmp dest, truncated |
| 1601 | | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); |
| 1611 | _ = try self.addInst(.{ |
| 1612 | .tag = .cmp, |
| 1613 | .data = .{ .r_op_cmp = .{ |
| 1614 | .rn = dest_reg, |
| 1615 | .op = Instruction.Operand.reg(truncated_reg, Instruction.Operand.Shift.none), |
| 1616 | } }, |
| 1617 | }); |
| 1602 | 1618 | |
| 1603 | 1619 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1604 | 1620 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| ... | ... | @@ -1608,7 +1624,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1608 | 1624 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1609 | 1625 | |
| 1610 | 1626 | try self.spillCompareFlagsIfOccupied(); |
| 1611 | | self.cpsr_flags_inst = null; |
| 1612 | 1627 | |
| 1613 | 1628 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 1614 | 1629 | .signed => .smull, |
| ... | ... | @@ -1672,7 +1687,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1672 | 1687 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1673 | 1688 | |
| 1674 | 1689 | // cmp truncated, rdlo |
| 1675 | | _ = try self.binOp(.cmp_eq, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize, null); |
| 1690 | _ = try self.addInst(.{ |
| 1691 | .tag = .cmp, |
| 1692 | .data = .{ .r_op_cmp = .{ |
| 1693 | .rn = truncated_reg, |
| 1694 | .op = Instruction.Operand.reg(rdlo, Instruction.Operand.Shift.none), |
| 1695 | } }, |
| 1696 | }); |
| 1676 | 1697 | |
| 1677 | 1698 | // mov rdlo, #0 |
| 1678 | 1699 | _ = try self.addInst(.{ |
| ... | ... | @@ -1694,7 +1715,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1694 | 1715 | }); |
| 1695 | 1716 | |
| 1696 | 1717 | // cmp rdhi, #0 |
| 1697 | | _ = try self.binOp(.cmp_eq, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize, null); |
| 1718 | _ = try self.addInst(.{ |
| 1719 | .tag = .cmp, |
| 1720 | .data = .{ .r_op_cmp = .{ |
| 1721 | .rn = rdhi, |
| 1722 | .op = Instruction.Operand.fromU32(0).?, |
| 1723 | } }, |
| 1724 | }); |
| 1698 | 1725 | |
| 1699 | 1726 | // movne rdlo, #1 |
| 1700 | 1727 | _ = try self.addInst(.{ |
| ... | ... | @@ -1725,8 +1752,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1725 | 1752 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1726 | 1753 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 1727 | 1754 | const result: MCValue = result: { |
| 1728 | | const lhs = try self.resolveInst(extra.lhs); |
| 1729 | | const rhs = try self.resolveInst(extra.rhs); |
| 1730 | 1755 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 1731 | 1756 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 1732 | 1757 | |
| ... | ... | @@ -1742,28 +1767,107 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1742 | 1767 | if (int_info.bits <= 32) { |
| 1743 | 1768 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1744 | 1769 | |
| 1745 | | const lhs_lock: ?RegisterLock = if (lhs == .register) |
| 1746 | | self.register_manager.lockRegAssumeUnused(lhs.register) |
| 1747 | | else |
| 1748 | | null; |
| 1749 | | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 1750 | | |
| 1751 | 1770 | try self.spillCompareFlagsIfOccupied(); |
| 1752 | | self.cpsr_flags_inst = null; |
| 1753 | 1771 | |
| 1754 | | // lsl dest, lhs, rhs |
| 1755 | | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); |
| 1756 | | const dest_reg = dest.register; |
| 1757 | | const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1758 | | defer self.register_manager.unlockReg(dest_lock); |
| 1772 | const shr_mir_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 1773 | .signed => Mir.Inst.Tag.asr, |
| 1774 | .unsigned => Mir.Inst.Tag.lsr, |
| 1775 | }; |
| 1776 | |
| 1777 | var lhs_reg: Register = undefined; |
| 1778 | var rhs_reg: Register = undefined; |
| 1779 | var dest_reg: Register = undefined; |
| 1780 | var reconstructed_reg: Register = undefined; |
| 1781 | |
| 1782 | const rhs_mcv = try self.resolveInst(extra.rhs); |
| 1783 | const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null; |
| 1784 | |
| 1785 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1786 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1787 | |
| 1788 | if (rhs_immediate_ok) { |
| 1789 | const read_args = [_]ReadArg{ |
| 1790 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 1791 | }; |
| 1792 | const write_args = [_]WriteArg{ |
| 1793 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1794 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &reconstructed_reg }, |
| 1795 | }; |
| 1796 | try self.allocRegs( |
| 1797 | &read_args, |
| 1798 | &write_args, |
| 1799 | null, |
| 1800 | ); |
| 1801 | |
| 1802 | // lsl dest, lhs, rhs |
| 1803 | _ = try self.addInst(.{ |
| 1804 | .tag = .lsl, |
| 1805 | .data = .{ .rr_shift = .{ |
| 1806 | .rd = dest_reg, |
| 1807 | .rm = lhs_reg, |
| 1808 | .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_mcv.immediate)), |
| 1809 | } }, |
| 1810 | }); |
| 1759 | 1811 | |
| 1760 | | // asr/lsr reconstructed, dest, rhs |
| 1761 | | const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null); |
| 1812 | try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits); |
| 1813 | |
| 1814 | // asr/lsr reconstructed, dest, rhs |
| 1815 | _ = try self.addInst(.{ |
| 1816 | .tag = shr_mir_tag, |
| 1817 | .data = .{ .rr_shift = .{ |
| 1818 | .rd = reconstructed_reg, |
| 1819 | .rm = dest_reg, |
| 1820 | .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_mcv.immediate)), |
| 1821 | } }, |
| 1822 | }); |
| 1823 | } else { |
| 1824 | const read_args = [_]ReadArg{ |
| 1825 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 1826 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| 1827 | }; |
| 1828 | const write_args = [_]WriteArg{ |
| 1829 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1830 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &reconstructed_reg }, |
| 1831 | }; |
| 1832 | try self.allocRegs( |
| 1833 | &read_args, |
| 1834 | &write_args, |
| 1835 | null, |
| 1836 | ); |
| 1837 | |
| 1838 | // lsl dest, lhs, rhs |
| 1839 | _ = try self.addInst(.{ |
| 1840 | .tag = .lsl, |
| 1841 | .data = .{ .rr_shift = .{ |
| 1842 | .rd = dest_reg, |
| 1843 | .rm = lhs_reg, |
| 1844 | .shift_amount = Instruction.ShiftAmount.reg(rhs_reg), |
| 1845 | } }, |
| 1846 | }); |
| 1847 | |
| 1848 | try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits); |
| 1849 | |
| 1850 | // asr/lsr reconstructed, dest, rhs |
| 1851 | _ = try self.addInst(.{ |
| 1852 | .tag = shr_mir_tag, |
| 1853 | .data = .{ .rr_shift = .{ |
| 1854 | .rd = reconstructed_reg, |
| 1855 | .rm = dest_reg, |
| 1856 | .shift_amount = Instruction.ShiftAmount.reg(rhs_reg), |
| 1857 | } }, |
| 1858 | }); |
| 1859 | } |
| 1762 | 1860 | |
| 1763 | 1861 | // cmp lhs, reconstructed |
| 1764 | | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); |
| 1862 | _ = try self.addInst(.{ |
| 1863 | .tag = .cmp, |
| 1864 | .data = .{ .r_op_cmp = .{ |
| 1865 | .rn = lhs_reg, |
| 1866 | .op = Instruction.Operand.reg(reconstructed_reg, Instruction.Operand.Shift.none), |
| 1867 | } }, |
| 1868 | }); |
| 1765 | 1869 | |
| 1766 | | try self.genSetStack(lhs_ty, stack_offset, dest); |
| 1870 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); |
| 1767 | 1871 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1768 | 1872 | |
| 1769 | 1873 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -2662,8 +2766,8 @@ fn allocRegs( |
| 2662 | 2766 | write_args: []const WriteArg, |
| 2663 | 2767 | reuse_metadata: ?ReuseMetadata, |
| 2664 | 2768 | ) InnerError!void { |
| 2665 | | // Air instructions have either one output or none (cmp) |
| 2666 | | assert(!(reuse_metadata != null and write_args.len > 1)); // see note above |
| 2769 | // Air instructions have exactly one output |
| 2770 | assert(!(reuse_metadata != null and write_args.len != 1)); // see note above |
| 2667 | 2771 | |
| 2668 | 2772 | // The operand mapping is a 1:1 mapping of read args to their |
| 2669 | 2773 | // corresponding operand index in the Air instruction |
| ... | ... | @@ -2714,7 +2818,7 @@ fn allocRegs( |
| 2714 | 2818 | } |
| 2715 | 2819 | } |
| 2716 | 2820 | |
| 2717 | | if (reuse_metadata != null and write_args.len > 0) { |
| 2821 | if (reuse_metadata != null) { |
| 2718 | 2822 | const inst = reuse_metadata.?.corresponding_inst; |
| 2719 | 2823 | const operand_mapping = reuse_metadata.?.operand_mapping; |
| 2720 | 2824 | const arg = write_args[0]; |
| ... | ... | @@ -2826,7 +2930,7 @@ fn binOpRegister( |
| 2826 | 2930 | }; |
| 2827 | 2931 | try self.allocRegs( |
| 2828 | 2932 | &read_args, |
| 2829 | | if (mir_tag == .cmp) &.{} else &write_args, |
| 2933 | &write_args, |
| 2830 | 2934 | if (metadata) |md| .{ |
| 2831 | 2935 | .corresponding_inst = md.inst, |
| 2832 | 2936 | .operand_mapping = &.{ 0, 1 }, |
| ... | ... | @@ -2846,10 +2950,6 @@ fn binOpRegister( |
| 2846 | 2950 | .rn = lhs_reg, |
| 2847 | 2951 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 2848 | 2952 | } }, |
| 2849 | | .cmp => .{ .r_op_cmp = .{ |
| 2850 | | .rn = lhs_reg, |
| 2851 | | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 2852 | | } }, |
| 2853 | 2953 | .lsl, |
| 2854 | 2954 | .asr, |
| 2855 | 2955 | .lsr, |
| ... | ... | @@ -2918,7 +3018,7 @@ fn binOpImmediate( |
| 2918 | 3018 | const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0}; |
| 2919 | 3019 | try self.allocRegs( |
| 2920 | 3020 | &read_args, |
| 2921 | | if (mir_tag == .cmp) &.{} else &write_args, |
| 3021 | &write_args, |
| 2922 | 3022 | if (metadata) |md| .{ |
| 2923 | 3023 | .corresponding_inst = md.inst, |
| 2924 | 3024 | .operand_mapping = operand_mapping, |
| ... | ... | @@ -2938,10 +3038,6 @@ fn binOpImmediate( |
| 2938 | 3038 | .rn = lhs_reg, |
| 2939 | 3039 | .op = Instruction.Operand.fromU32(rhs.immediate).?, |
| 2940 | 3040 | } }, |
| 2941 | | .cmp => .{ .r_op_cmp = .{ |
| 2942 | | .rn = lhs_reg, |
| 2943 | | .op = Instruction.Operand.fromU32(rhs.immediate).?, |
| 2944 | | } }, |
| 2945 | 3041 | .lsl, |
| 2946 | 3042 | .asr, |
| 2947 | 3043 | .lsr, |
| ... | ... | @@ -2991,7 +3087,6 @@ fn binOp( |
| 2991 | 3087 | switch (tag) { |
| 2992 | 3088 | .add, |
| 2993 | 3089 | .sub, |
| 2994 | | .cmp_eq, |
| 2995 | 3090 | => { |
| 2996 | 3091 | switch (lhs_ty.zigTypeTag()) { |
| 2997 | 3092 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| ... | ... | @@ -3006,15 +3101,12 @@ fn binOp( |
| 3006 | 3101 | // operands |
| 3007 | 3102 | const lhs_immediate_ok = switch (tag) { |
| 3008 | 3103 | .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null, |
| 3009 | | .sub, |
| 3010 | | .cmp_eq, |
| 3011 | | => false, |
| 3104 | .sub => false, |
| 3012 | 3105 | else => unreachable, |
| 3013 | 3106 | }; |
| 3014 | 3107 | const rhs_immediate_ok = switch (tag) { |
| 3015 | 3108 | .add, |
| 3016 | 3109 | .sub, |
| 3017 | | .cmp_eq, |
| 3018 | 3110 | => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null, |
| 3019 | 3111 | else => unreachable, |
| 3020 | 3112 | }; |
| ... | ... | @@ -3022,7 +3114,6 @@ fn binOp( |
| 3022 | 3114 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 3023 | 3115 | .add => .add, |
| 3024 | 3116 | .sub => .sub, |
| 3025 | | .cmp_eq => .cmp, |
| 3026 | 3117 | else => unreachable, |
| 3027 | 3118 | }; |
| 3028 | 3119 | |
| ... | ... | @@ -4005,32 +4096,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4005 | 4096 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 4006 | 4097 | |
| 4007 | 4098 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4008 | | const operands: BinOpOperands = .{ .inst = .{ |
| 4009 | | .inst = inst, |
| 4010 | | .lhs = bin_op.lhs, |
| 4011 | | .rhs = bin_op.rhs, |
| 4012 | | } }; |
| 4013 | | break :blk try self.cmp(operands, lhs_ty, op); |
| 4099 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); |
| 4014 | 4100 | }; |
| 4015 | 4101 | |
| 4016 | 4102 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4017 | 4103 | } |
| 4018 | 4104 | |
| 4019 | | const BinOpOperands = union(enum) { |
| 4020 | | inst: struct { |
| 4021 | | inst: Air.Inst.Index, |
| 4022 | | lhs: Air.Inst.Ref, |
| 4023 | | rhs: Air.Inst.Ref, |
| 4024 | | }, |
| 4025 | | mcv: struct { |
| 4026 | | lhs: MCValue, |
| 4027 | | rhs: MCValue, |
| 4028 | | }, |
| 4029 | | }; |
| 4030 | | |
| 4031 | 4105 | fn cmp( |
| 4032 | 4106 | self: *Self, |
| 4033 | | operands: BinOpOperands, |
| 4107 | lhs: ReadArg.Bind, |
| 4108 | rhs: ReadArg.Bind, |
| 4034 | 4109 | lhs_ty: Type, |
| 4035 | 4110 | op: math.CompareOperator, |
| 4036 | 4111 | ) !MCValue { |
| ... | ... | @@ -4060,22 +4135,47 @@ fn cmp( |
| 4060 | 4135 | if (int_info.bits <= 32) { |
| 4061 | 4136 | try self.spillCompareFlagsIfOccupied(); |
| 4062 | 4137 | |
| 4063 | | switch (operands) { |
| 4064 | | .inst => |inst_op| { |
| 4065 | | const metadata: BinOpMetadata = .{ |
| 4066 | | .inst = inst_op.inst, |
| 4067 | | .lhs = inst_op.lhs, |
| 4068 | | .rhs = inst_op.rhs, |
| 4069 | | }; |
| 4070 | | const lhs = try self.resolveInst(inst_op.lhs); |
| 4071 | | const rhs = try self.resolveInst(inst_op.rhs); |
| 4138 | var lhs_reg: Register = undefined; |
| 4139 | var rhs_reg: Register = undefined; |
| 4072 | 4140 | |
| 4073 | | self.cpsr_flags_inst = inst_op.inst; |
| 4074 | | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, metadata); |
| 4075 | | }, |
| 4076 | | .mcv => |mcv_op| { |
| 4077 | | _ = try self.binOp(.cmp_eq, mcv_op.lhs, mcv_op.rhs, int_ty, int_ty, null); |
| 4078 | | }, |
| 4141 | const rhs_mcv = try rhs.resolveToMcv(self); |
| 4142 | const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null; |
| 4143 | |
| 4144 | if (rhs_immediate_ok) { |
| 4145 | const read_args = [_]ReadArg{ |
| 4146 | .{ .ty = int_ty, .bind = lhs, .class = gp, .reg = &lhs_reg }, |
| 4147 | }; |
| 4148 | try self.allocRegs( |
| 4149 | &read_args, |
| 4150 | &.{}, |
| 4151 | null, // we won't be able to reuse a register as there are no write_regs |
| 4152 | ); |
| 4153 | |
| 4154 | _ = try self.addInst(.{ |
| 4155 | .tag = .cmp, |
| 4156 | .data = .{ .r_op_cmp = .{ |
| 4157 | .rn = lhs_reg, |
| 4158 | .op = Instruction.Operand.fromU32(rhs_mcv.immediate).?, |
| 4159 | } }, |
| 4160 | }); |
| 4161 | } else { |
| 4162 | const read_args = [_]ReadArg{ |
| 4163 | .{ .ty = int_ty, .bind = lhs, .class = gp, .reg = &lhs_reg }, |
| 4164 | .{ .ty = int_ty, .bind = rhs, .class = gp, .reg = &rhs_reg }, |
| 4165 | }; |
| 4166 | try self.allocRegs( |
| 4167 | &read_args, |
| 4168 | &.{}, |
| 4169 | null, // we won't be able to reuse a register as there are no write_regs |
| 4170 | ); |
| 4171 | |
| 4172 | _ = try self.addInst(.{ |
| 4173 | .tag = .cmp, |
| 4174 | .data = .{ .r_op_cmp = .{ |
| 4175 | .rn = lhs_reg, |
| 4176 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 4177 | } }, |
| 4178 | }); |
| 4079 | 4179 | } |
| 4080 | 4180 | |
| 4081 | 4181 | return switch (int_info.signedness) { |
| ... | ... | @@ -4349,14 +4449,13 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4349 | 4449 | |
| 4350 | 4450 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4351 | 4451 | const error_type = ty.errorUnionSet(); |
| 4352 | | const error_int_type = Type.initTag(.u16); |
| 4353 | 4452 | |
| 4354 | 4453 | if (error_type.errorSetIsEmpty()) { |
| 4355 | 4454 | return MCValue{ .immediate = 0 }; // always false |
| 4356 | 4455 | } |
| 4357 | 4456 | |
| 4358 | 4457 | const error_mcv = try self.errUnionErr(operand, ty); |
| 4359 | | _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null); |
| 4458 | _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq); |
| 4360 | 4459 | return MCValue{ .cpsr_flags = .hi }; |
| 4361 | 4460 | } |
| 4362 | 4461 | |
| ... | ... | @@ -4587,14 +4686,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4587 | 4686 | defer self.gpa.free(branch_into_prong_relocs); |
| 4588 | 4687 | |
| 4589 | 4688 | for (items) |item, idx| { |
| 4590 | | const condition = try self.resolveInst(pl_op.operand); |
| 4591 | | const item_mcv = try self.resolveInst(item); |
| 4592 | | |
| 4593 | | const operands: BinOpOperands = .{ .mcv = .{ |
| 4594 | | .lhs = condition, |
| 4595 | | .rhs = item_mcv, |
| 4596 | | } }; |
| 4597 | | const cmp_result = try self.cmp(operands, condition_ty, .neq); |
| 4689 | const cmp_result = try self.cmp(.{ .inst = pl_op.operand }, .{ .inst = item }, condition_ty, .neq); |
| 4598 | 4690 | branch_into_prong_relocs[idx] = try self.condBr(cmp_result); |
| 4599 | 4691 | } |
| 4600 | 4692 | |