| ... | ... | @@ -534,7 +534,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 534 | 534 | |
| 535 | 535 | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 536 | 536 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| 537 | | .mul_with_overflow => @panic("TODO try self.airMulWithOverflow(inst)"), |
| 537 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 538 | 538 | .shl_with_overflow => @panic("TODO try self.airShlWithOverflow(inst)"), |
| 539 | 539 | |
| 540 | 540 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| ... | ... | @@ -1792,6 +1792,73 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1792 | 1792 | return self.finishAir(inst, .{ .register = mod_reg }, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1793 | 1793 | } |
| 1794 | 1794 | |
| 1795 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1796 | //const tag = self.air.instructions.items(.tag)[inst]; |
| 1797 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1798 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1799 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1800 | const lhs = try self.resolveInst(extra.lhs); |
| 1801 | const rhs = try self.resolveInst(extra.rhs); |
| 1802 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 1803 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 1804 | |
| 1805 | switch (lhs_ty.zigTypeTag()) { |
| 1806 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 1807 | .Int => { |
| 1808 | const mod = self.bin_file.options.module.?; |
| 1809 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1810 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1811 | switch (int_info.bits) { |
| 1812 | 1...32 => { |
| 1813 | try self.spillConditionFlagsIfOccupied(); |
| 1814 | self.condition_flags_inst = inst; |
| 1815 | |
| 1816 | const dest = try self.binOp(.mul, lhs, rhs, lhs_ty, rhs_ty, null); |
| 1817 | |
| 1818 | const dest_reg = dest.register; |
| 1819 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1820 | defer self.register_manager.unlockReg(dest_reg_lock); |
| 1821 | |
| 1822 | const truncated_reg = try self.register_manager.allocReg(null, gp); |
| 1823 | const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg); |
| 1824 | defer self.register_manager.unlockReg(truncated_reg_lock); |
| 1825 | |
| 1826 | try self.truncRegister( |
| 1827 | dest_reg, |
| 1828 | truncated_reg, |
| 1829 | int_info.signedness, |
| 1830 | int_info.bits, |
| 1831 | ); |
| 1832 | |
| 1833 | _ = try self.addInst(.{ |
| 1834 | .tag = .cmp, |
| 1835 | .data = .{ .arithmetic_2op = .{ |
| 1836 | .is_imm = false, |
| 1837 | .rs1 = dest_reg, |
| 1838 | .rs2_or_imm = .{ .rs2 = truncated_reg }, |
| 1839 | } }, |
| 1840 | }); |
| 1841 | |
| 1842 | const cond = Instruction.ICondition.ne; |
| 1843 | const ccr = Instruction.CCR.xcc; |
| 1844 | |
| 1845 | break :result MCValue{ .register_with_overflow = .{ |
| 1846 | .reg = truncated_reg, |
| 1847 | .flag = .{ .cond = cond, .ccr = ccr }, |
| 1848 | } }; |
| 1849 | }, |
| 1850 | // XXX DO NOT call __multi3 directly as it'll result in us doing six multiplications, |
| 1851 | // which is far more than strictly necessary |
| 1852 | 33...64 => return self.fail("TODO copy compiler-rt's mulddi3 for a 64x64->128 multiply", .{}), |
| 1853 | else => return self.fail("TODO overflow operations on other integer sizes", .{}), |
| 1854 | } |
| 1855 | }, |
| 1856 | else => unreachable, |
| 1857 | } |
| 1858 | }; |
| 1859 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1860 | } |
| 1861 | |
| 1795 | 1862 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1796 | 1863 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1797 | 1864 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |