| ... | @@ -595,8 +595,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -595,8 +595,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 595 | .mul => try self.airBinOp(inst), | 595 | .mul => try self.airBinOp(inst), |
| 596 | .mulwrap => try self.airBinOp(inst), | 596 | .mulwrap => try self.airBinOp(inst), |
| 597 | .mul_sat => try self.airMulSat(inst), | 597 | .mul_sat => try self.airMulSat(inst), |
| 598 | .rem => try self.airRem(inst), | 598 | .rem => try self.airBinOp(inst), |
| 599 | .mod => try self.airMod(inst), | 599 | .mod => try self.airBinOp(inst), |
| 600 | .shl, .shl_exact => try self.airShl(inst), | 600 | .shl, .shl_exact => try self.airShl(inst), |
| 601 | .shl_sat => try self.airShlSat(inst), | 601 | .shl_sat => try self.airShlSat(inst), |
| 602 | .min => try self.airMin(inst), | 602 | .min => try self.airMin(inst), |
| ... | @@ -1539,6 +1539,7 @@ fn genIntMulDivOpMir( | ... | @@ -1539,6 +1539,7 @@ fn genIntMulDivOpMir( |
| 1539 | } | 1539 | } |
| 1540 | } | 1540 | } |
| 1541 | | 1541 | |
| | 1542 | /// Always returns a register. |
| 1542 | /// Clobbers .rax and .rdx registers. | 1543 | /// Clobbers .rax and .rdx registers. |
| 1543 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { | 1544 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 1544 | const signedness = ty.intInfo(self.target.*).signedness; | 1545 | const signedness = ty.intInfo(self.target.*).signedness; |
| ... | @@ -1687,86 +1688,6 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1687,86 +1688,6 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1687 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1688 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1688 | } | 1689 | } |
| 1689 | | 1690 | |
| 1690 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1691 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1692 | | | |
| 1693 | if (self.liveness.isUnused(inst)) { | | |
| 1694 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1695 | } | | |
| 1696 | const ty = self.air.typeOfIndex(inst); | | |
| 1697 | if (ty.zigTypeTag() != .Int) { | | |
| 1698 | return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()}); | | |
| 1699 | } | | |
| 1700 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | | |
| 1701 | try self.register_manager.getReg(.rax, null); | | |
| 1702 | try self.register_manager.getReg(.rdx, inst); | | |
| 1703 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | | |
| 1704 | defer for (reg_locks) |reg| { | | |
| 1705 | self.register_manager.unlockReg(reg); | | |
| 1706 | }; | | |
| 1707 | | | |
| 1708 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1709 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1710 | | | |
| 1711 | const signedness = ty.intInfo(self.target.*).signedness; | | |
| 1712 | try self.genIntMulDivOpMir(switch (signedness) { | | |
| 1713 | .signed => .idiv, | | |
| 1714 | .unsigned => .div, | | |
| 1715 | }, ty, signedness, lhs, rhs); | | |
| 1716 | | | |
| 1717 | const result: MCValue = .{ .register = .rdx }; | | |
| 1718 | | | |
| 1719 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1720 | } | | |
| 1721 | | | |
| 1722 | fn airMod(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1723 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1724 | | | |
| 1725 | if (self.liveness.isUnused(inst)) { | | |
| 1726 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1727 | } | | |
| 1728 | | | |
| 1729 | const ty = self.air.typeOfIndex(inst); | | |
| 1730 | if (ty.zigTypeTag() != .Int) { | | |
| 1731 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); | | |
| 1732 | } | | |
| 1733 | const signedness = ty.intInfo(self.target.*).signedness; | | |
| 1734 | | | |
| 1735 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | | |
| 1736 | try self.register_manager.getReg(.rax, null); | | |
| 1737 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); | | |
| 1738 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | | |
| 1739 | defer for (reg_locks) |reg| { | | |
| 1740 | self.register_manager.unlockReg(reg); | | |
| 1741 | }; | | |
| 1742 | | | |
| 1743 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1744 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1745 | | | |
| 1746 | const result: MCValue = result: { | | |
| 1747 | switch (signedness) { | | |
| 1748 | .unsigned => { | | |
| 1749 | try self.genIntMulDivOpMir(switch (signedness) { | | |
| 1750 | .signed => .idiv, | | |
| 1751 | .unsigned => .div, | | |
| 1752 | }, ty, signedness, lhs, rhs); | | |
| 1753 | break :result MCValue{ .register = .rdx }; | | |
| 1754 | }, | | |
| 1755 | .signed => { | | |
| 1756 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); | | |
| 1757 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); | | |
| 1758 | | | |
| 1759 | const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); | | |
| 1760 | try self.genBinOpMir(.sub, ty, result, div_floor); | | |
| 1761 | | | |
| 1762 | break :result result; | | |
| 1763 | }, | | |
| 1764 | } | | |
| 1765 | }; | | |
| 1766 | | | |
| 1767 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1768 | } | | |
| 1769 | | | |
| 1770 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | 1691 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1771 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1692 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1772 | if (self.liveness.isUnused(inst)) { | 1693 | if (self.liveness.isUnused(inst)) { |
| ... | @@ -3234,12 +3155,18 @@ fn genBinOp( | ... | @@ -3234,12 +3155,18 @@ fn genBinOp( |
| 3234 | .subwrap, | 3155 | .subwrap, |
| 3235 | .mul, | 3156 | .mul, |
| 3236 | .mulwrap, | 3157 | .mulwrap, |
| | 3158 | .div_exact, |
| | 3159 | .div_trunc, |
| | 3160 | .rem, |
| | 3161 | .mod, |
| 3237 | .shl, | 3162 | .shl, |
| 3238 | .shr, | 3163 | .shr, |
| 3239 | .ptr_add, | 3164 | .ptr_add, |
| 3240 | .ptr_sub, | 3165 | .ptr_sub, |
| 3241 | => false, | 3166 | => false, |
| 3242 | | 3167 | |
| | 3168 | .div_float => return self.fail("TODO implement genBinOp for {}", .{tag}), |
| | 3169 | |
| 3243 | else => unreachable, | 3170 | else => unreachable, |
| 3244 | }; | 3171 | }; |
| 3245 | const dst_ty = self.air.typeOf(op_lhs); | 3172 | const dst_ty = self.air.typeOf(op_lhs); |
| ... | @@ -3278,6 +3205,57 @@ fn genBinOp( | ... | @@ -3278,6 +3205,57 @@ fn genBinOp( |
| 3278 | .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) }, | 3205 | .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) }, |
| 3279 | }; | 3206 | }; |
| 3280 | }, | 3207 | }, |
| | 3208 | .mod, |
| | 3209 | .rem, |
| | 3210 | => { |
| | 3211 | const int_info = dst_ty.intInfo(self.target.*); |
| | 3212 | const track_inst_rdx: ?Air.Inst.Index = switch (tag) { |
| | 3213 | .mod => if (int_info.signedness == .unsigned) maybe_inst else null, |
| | 3214 | .rem => maybe_inst, |
| | 3215 | else => unreachable, |
| | 3216 | }; |
| | 3217 | |
| | 3218 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| | 3219 | try self.register_manager.getReg(.rax, null); |
| | 3220 | try self.register_manager.getReg(.rdx, track_inst_rdx); |
| | 3221 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| | 3222 | defer for (reg_locks) |reg| { |
| | 3223 | self.register_manager.unlockReg(reg); |
| | 3224 | }; |
| | 3225 | |
| | 3226 | const lhs = try self.resolveInst(op_lhs); |
| | 3227 | const rhs = try self.resolveInst(op_rhs); |
| | 3228 | |
| | 3229 | switch (int_info.signedness) { |
| | 3230 | .signed => { |
| | 3231 | switch (tag) { |
| | 3232 | .rem => { |
| | 3233 | try self.genIntMulDivOpMir(.idiv, dst_ty, .signed, lhs, rhs); |
| | 3234 | return MCValue{ .register = .rdx }; |
| | 3235 | }, |
| | 3236 | .mod => { |
| | 3237 | const div_floor = try self.genInlineIntDivFloor(dst_ty, lhs, rhs); |
| | 3238 | try self.genIntMulComplexOpMir(dst_ty, div_floor, rhs); |
| | 3239 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); |
| | 3240 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3241 | |
| | 3242 | const result: MCValue = if (maybe_inst) |inst| |
| | 3243 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs) |
| | 3244 | else |
| | 3245 | MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) }; |
| | 3246 | try self.genBinOpMir(.sub, dst_ty, result, div_floor); |
| | 3247 | |
| | 3248 | return result; |
| | 3249 | }, |
| | 3250 | else => unreachable, |
| | 3251 | } |
| | 3252 | }, |
| | 3253 | .unsigned => { |
| | 3254 | try self.genIntMulDivOpMir(.div, dst_ty, .unsigned, lhs, rhs); |
| | 3255 | return MCValue{ .register = .rdx }; |
| | 3256 | }, |
| | 3257 | } |
| | 3258 | }, |
| 3281 | else => {}, | 3259 | else => {}, |
| 3282 | } | 3260 | } |
| 3283 | | 3261 | |