| ... | @@ -592,11 +592,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -592,11 +592,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 592 | .sub => try self.airBinOp(inst), | 592 | .sub => try self.airBinOp(inst), |
| 593 | .subwrap => try self.airBinOp(inst), | 593 | .subwrap => try self.airBinOp(inst), |
| 594 | .sub_sat => try self.airSubSat(inst), | 594 | .sub_sat => try self.airSubSat(inst), |
| 595 | .mul => try self.airBinOp(inst), | 595 | .mul => try self.airMulDivBinOp(inst), |
| 596 | .mulwrap => try self.airBinOp(inst), | 596 | .mulwrap => try self.airMulDivBinOp(inst), |
| 597 | .mul_sat => try self.airMulSat(inst), | 597 | .mul_sat => try self.airMulSat(inst), |
| 598 | .rem => try self.airBinOp(inst), | 598 | .rem => try self.airMulDivBinOp(inst), |
| 599 | .mod => try self.airBinOp(inst), | 599 | .mod => try self.airMulDivBinOp(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), |
| ... | @@ -626,7 +626,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -626,7 +626,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 626 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 626 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 627 | .shl_with_overflow => try self.airShlWithOverflow(inst), | 627 | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 628 | | 628 | |
| 629 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), | 629 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airMulDivBinOp(inst), |
| 630 | | 630 | |
| 631 | .cmp_lt => try self.airCmp(inst, .lt), | 631 | .cmp_lt => try self.airCmp(inst, .lt), |
| 632 | .cmp_lte => try self.airCmp(inst, .lte), | 632 | .cmp_lte => try self.airCmp(inst, .lte), |
| ... | @@ -959,6 +959,12 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -959,6 +959,12 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 959 | } | 959 | } |
| 960 | } | 960 | } |
| 961 | | 961 | |
| | 962 | pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [count]Register) !void { |
| | 963 | for (registers) |reg| { |
| | 964 | try self.register_manager.getReg(reg, null); |
| | 965 | } |
| | 966 | } |
| | 967 | |
| 962 | /// Copies a value to a register without tracking the register. The register is not considered | 968 | /// Copies a value to a register without tracking the register. The register is not considered |
| 963 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 969 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 964 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 970 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| ... | @@ -1252,6 +1258,26 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1252,6 +1258,26 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1252 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1258 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1253 | } | 1259 | } |
| 1254 | | 1260 | |
| | 1261 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| | 1262 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 1263 | |
| | 1264 | if (self.liveness.isUnused(inst)) { |
| | 1265 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1266 | } |
| | 1267 | |
| | 1268 | const tag = self.air.instructions.items(.tag)[inst]; |
| | 1269 | const ty = self.air.typeOfIndex(inst); |
| | 1270 | |
| | 1271 | try self.spillRegisters(2, .{ .rax, .rdx }); |
| | 1272 | |
| | 1273 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1274 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1275 | |
| | 1276 | const result = try self.genMulDivBinOp(tag, inst, ty, lhs, rhs); |
| | 1277 | |
| | 1278 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1279 | } |
| | 1280 | |
| 1255 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | 1281 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1256 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1282 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1257 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1283 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| ... | @@ -1339,25 +1365,31 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1339,25 +1365,31 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1339 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); | 1365 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); |
| 1340 | } | 1366 | } |
| 1341 | | 1367 | |
| 1342 | try self.spillCompareFlagsIfOccupied(); | | |
| 1343 | | | |
| 1344 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1345 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1346 | | | |
| 1347 | if (math.isPowerOfTwo(int_info.bits)) { | 1368 | if (math.isPowerOfTwo(int_info.bits)) { |
| | 1369 | try self.spillCompareFlagsIfOccupied(); |
| 1348 | self.compare_flags_inst = inst; | 1370 | self.compare_flags_inst = inst; |
| 1349 | const partial = try self.genBinOp(.mul, null, lhs, rhs, ty, ty); | 1371 | |
| | 1372 | try self.spillRegisters(2, .{ .rax, .rdx }); |
| | 1373 | |
| | 1374 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1375 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1376 | |
| | 1377 | const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs); |
| 1350 | break :result switch (int_info.signedness) { | 1378 | break :result switch (int_info.signedness) { |
| 1351 | .signed => MCValue{ .register_overflow_signed = partial.register }, | 1379 | .signed => MCValue{ .register_overflow_signed = partial.register }, |
| 1352 | .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, | 1380 | .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, |
| 1353 | }; | 1381 | }; |
| 1354 | } | 1382 | } |
| 1355 | | 1383 | |
| | 1384 | try self.spillCompareFlagsIfOccupied(); |
| 1356 | self.compare_flags_inst = null; | 1385 | self.compare_flags_inst = null; |
| 1357 | | 1386 | |
| 1358 | const dst_reg: Register = dst_reg: { | 1387 | const dst_reg: Register = dst_reg: { |
| 1359 | switch (int_info.signedness) { | 1388 | switch (int_info.signedness) { |
| 1360 | .signed => { | 1389 | .signed => { |
| | 1390 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1391 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1392 | |
| 1361 | const rhs_lock: ?RegisterLock = switch (rhs) { | 1393 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1362 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1394 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1363 | else => null, | 1395 | else => null, |
| ... | @@ -1386,7 +1418,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1386,7 +1418,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1386 | break :dst_reg dst_reg; | 1418 | break :dst_reg dst_reg; |
| 1387 | }, | 1419 | }, |
| 1388 | .unsigned => { | 1420 | .unsigned => { |
| 1389 | const dst_mcv = try self.genBinOp(.mul, null, lhs, rhs, ty, ty); | 1421 | try self.spillRegisters(2, .{ .rax, .rdx }); |
| | 1422 | |
| | 1423 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1424 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1425 | |
| | 1426 | const dst_mcv = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs); |
| 1390 | break :dst_reg dst_mcv.register; | 1427 | break :dst_reg dst_mcv.register; |
| 1391 | }, | 1428 | }, |
| 1392 | } | 1429 | } |
| ... | @@ -1487,7 +1524,13 @@ fn genIntMulDivOpMir( | ... | @@ -1487,7 +1524,13 @@ fn genIntMulDivOpMir( |
| 1487 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); | 1524 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); |
| 1488 | } | 1525 | } |
| 1489 | | 1526 | |
| 1490 | try self.genSetReg(ty, .rax, lhs); | 1527 | lhs: { |
| | 1528 | switch (lhs) { |
| | 1529 | .register => |reg| if (reg.to64() == .rax) break :lhs, |
| | 1530 | else => {}, |
| | 1531 | } |
| | 1532 | try self.genSetReg(ty, .rax, lhs); |
| | 1533 | } |
| 1491 | | 1534 | |
| 1492 | switch (signedness) { | 1535 | switch (signedness) { |
| 1493 | .signed => { | 1536 | .signed => { |
| ... | @@ -1609,96 +1652,6 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -1609,96 +1652,6 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1609 | return MCValue{ .register = divisor }; | 1652 | return MCValue{ .register = divisor }; |
| 1610 | } | 1653 | } |
| 1611 | | 1654 | |
| 1612 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1613 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1614 | | | |
| 1615 | if (self.liveness.isUnused(inst)) { | | |
| 1616 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1617 | } | | |
| 1618 | | | |
| 1619 | const tag = self.air.instructions.items(.tag)[inst]; | | |
| 1620 | const ty = self.air.typeOfIndex(inst); | | |
| 1621 | | | |
| 1622 | if (ty.zigTypeTag() != .Int) { | | |
| 1623 | return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() }); | | |
| 1624 | } | | |
| 1625 | | | |
| 1626 | if (tag == .div_float) { | | |
| 1627 | return self.fail("TODO implement {}", .{tag}); | | |
| 1628 | } | | |
| 1629 | | | |
| 1630 | const signedness = ty.intInfo(self.target.*).signedness; | | |
| 1631 | | | |
| 1632 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | | |
| 1633 | const track_rax: ?Air.Inst.Index = blk: { | | |
| 1634 | if (signedness == .unsigned) break :blk inst; | | |
| 1635 | switch (tag) { | | |
| 1636 | .div_exact, .div_trunc => break :blk inst, | | |
| 1637 | else => break :blk null, | | |
| 1638 | } | | |
| 1639 | }; | | |
| 1640 | try self.register_manager.getReg(.rax, track_rax); | | |
| 1641 | try self.register_manager.getReg(.rdx, null); | | |
| 1642 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | | |
| 1643 | defer for (reg_locks) |reg| { | | |
| 1644 | self.register_manager.unlockReg(reg); | | |
| 1645 | }; | | |
| 1646 | | | |
| 1647 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1648 | const lhs_lock: ?RegisterLock = switch (lhs) { | | |
| 1649 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1650 | else => null, | | |
| 1651 | }; | | |
| 1652 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1653 | | | |
| 1654 | const rhs: MCValue = blk: { | | |
| 1655 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1656 | if (signedness == .signed) { | | |
| 1657 | switch (tag) { | | |
| 1658 | .div_floor => { | | |
| 1659 | const rhs_lock: ?RegisterLock = switch (rhs) { | | |
| 1660 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1661 | else => null, | | |
| 1662 | }; | | |
| 1663 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1664 | | | |
| 1665 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); | | |
| 1666 | }, | | |
| 1667 | else => {}, | | |
| 1668 | } | | |
| 1669 | } | | |
| 1670 | break :blk rhs; | | |
| 1671 | }; | | |
| 1672 | const rhs_lock: ?RegisterLock = switch (rhs) { | | |
| 1673 | .register => |reg| self.register_manager.lockReg(reg), | | |
| 1674 | else => null, | | |
| 1675 | }; | | |
| 1676 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1677 | | | |
| 1678 | const result: MCValue = result: { | | |
| 1679 | if (signedness == .unsigned) { | | |
| 1680 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); | | |
| 1681 | break :result MCValue{ .register = .rax }; | | |
| 1682 | } | | |
| 1683 | | | |
| 1684 | switch (tag) { | | |
| 1685 | .div_exact, .div_trunc => { | | |
| 1686 | try self.genIntMulDivOpMir(switch (signedness) { | | |
| 1687 | .signed => .idiv, | | |
| 1688 | .unsigned => .div, | | |
| 1689 | }, ty, signedness, lhs, rhs); | | |
| 1690 | break :result MCValue{ .register = .rax }; | | |
| 1691 | }, | | |
| 1692 | .div_floor => { | | |
| 1693 | break :result try self.genInlineIntDivFloor(ty, lhs, rhs); | | |
| 1694 | }, | | |
| 1695 | else => unreachable, | | |
| 1696 | } | | |
| 1697 | }; | | |
| 1698 | | | |
| 1699 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1700 | } | | |
| 1701 | | | |
| 1702 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | 1655 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1703 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1656 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1704 | if (self.liveness.isUnused(inst)) { | 1657 | if (self.liveness.isUnused(inst)) { |
| ... | @@ -3144,110 +3097,84 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3144,110 +3097,84 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3144 | } | 3097 | } |
| 3145 | | 3098 | |
| 3146 | /// Result is always a register. | 3099 | /// Result is always a register. |
| 3147 | fn genBinOp( | 3100 | /// Clobbers .rax and .rdx therefore care needs to be taken to spill operands upfront. |
| | 3101 | /// Asserts .rax and .rdx are free. |
| | 3102 | fn genMulDivBinOp( |
| 3148 | self: *Self, | 3103 | self: *Self, |
| 3149 | tag: Air.Inst.Tag, | 3104 | tag: Air.Inst.Tag, |
| 3150 | maybe_inst: ?Air.Inst.Index, | 3105 | maybe_inst: ?Air.Inst.Index, |
| | 3106 | ty: Type, |
| 3151 | lhs: MCValue, | 3107 | lhs: MCValue, |
| 3152 | rhs: MCValue, | 3108 | rhs: MCValue, |
| 3153 | lhs_ty: Type, | | |
| 3154 | rhs_ty: Type, | | |
| 3155 | ) !MCValue { | 3109 | ) !MCValue { |
| 3156 | const is_commutative: bool = switch (tag) { | 3110 | if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) { |
| 3157 | .add, | 3111 | return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()}); |
| 3158 | .addwrap, | 3112 | } |
| 3159 | .bool_or, | 3113 | if (ty.abiSize(self.target.*) > 8) { |
| 3160 | .bit_or, | 3114 | return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()}); |
| 3161 | .bool_and, | 3115 | } |
| 3162 | .bit_and, | 3116 | if (tag == .div_float) { |
| 3163 | .xor, | 3117 | return self.fail("TODO implement genMulDivBinOp for div_float", .{}); |
| 3164 | => true, | 3118 | } |
| 3165 | | | |
| 3166 | .sub, | | |
| 3167 | .subwrap, | | |
| 3168 | .mul, | | |
| 3169 | .mulwrap, | | |
| 3170 | .div_exact, | | |
| 3171 | .div_trunc, | | |
| 3172 | .rem, | | |
| 3173 | .mod, | | |
| 3174 | .shl, | | |
| 3175 | .shr, | | |
| 3176 | .ptr_add, | | |
| 3177 | .ptr_sub, | | |
| 3178 | => false, | | |
| 3179 | | 3119 | |
| 3180 | .div_float => return self.fail("TODO implement genBinOp for {}", .{tag}), | 3120 | assert(self.register_manager.isRegFree(.rax)); |
| | 3121 | assert(self.register_manager.isRegFree(.rdx)); |
| 3181 | | 3122 | |
| 3182 | else => unreachable, | 3123 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| | 3124 | defer for (reg_locks) |reg| { |
| | 3125 | self.register_manager.unlockReg(reg); |
| 3183 | }; | 3126 | }; |
| 3184 | | 3127 | |
| 3185 | if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) { | 3128 | const int_info = ty.intInfo(self.target.*); |
| 3186 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); | 3129 | const signedness = int_info.signedness; |
| 3187 | } | | |
| 3188 | if (lhs_ty.abiSize(self.target.*) > 8) { | | |
| 3189 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); | | |
| 3190 | } | | |
| 3191 | | 3130 | |
| 3192 | switch (tag) { | 3131 | switch (tag) { |
| 3193 | .mul, | 3132 | .mul, |
| 3194 | .mulwrap, | 3133 | .mulwrap, |
| 3195 | => { | 3134 | => { |
| 3196 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | | |
| 3197 | try self.register_manager.getReg(.rax, maybe_inst); | 3135 | try self.register_manager.getReg(.rax, maybe_inst); |
| 3198 | try self.register_manager.getReg(.rdx, null); | 3136 | try self.register_manager.getReg(.rdx, null); |
| 3199 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | | |
| 3200 | defer for (reg_locks) |reg| { | | |
| 3201 | self.register_manager.unlockReg(reg); | | |
| 3202 | }; | | |
| 3203 | | 3137 | |
| 3204 | const int_info = lhs_ty.intInfo(self.target.*); | 3138 | try self.genIntMulDivOpMir(switch (signedness) { |
| 3205 | try self.genIntMulDivOpMir(switch (int_info.signedness) { | | |
| 3206 | .signed => .imul, | 3139 | .signed => .imul, |
| 3207 | .unsigned => .mul, | 3140 | .unsigned => .mul, |
| 3208 | }, lhs_ty, int_info.signedness, lhs, rhs); | 3141 | }, ty, signedness, lhs, rhs); |
| 3209 | | 3142 | |
| 3210 | return switch (int_info.signedness) { | 3143 | return switch (signedness) { |
| 3211 | .signed => MCValue{ .register = .rax }, | 3144 | .signed => MCValue{ .register = .rax }, |
| 3212 | .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, lhs_ty.abiSize(self.target.*))) }, | 3145 | .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))) }, |
| 3213 | }; | 3146 | }; |
| 3214 | }, | 3147 | }, |
| 3215 | .mod, | 3148 | .mod, |
| 3216 | .rem, | 3149 | .rem, |
| 3217 | => { | 3150 | => { |
| 3218 | const int_info = lhs_ty.intInfo(self.target.*); | | |
| 3219 | const track_inst_rdx: ?Air.Inst.Index = switch (tag) { | 3151 | const track_inst_rdx: ?Air.Inst.Index = switch (tag) { |
| 3220 | .mod => if (int_info.signedness == .unsigned) maybe_inst else null, | 3152 | .mod => if (signedness == .unsigned) maybe_inst else null, |
| 3221 | .rem => maybe_inst, | 3153 | .rem => maybe_inst, |
| 3222 | else => unreachable, | 3154 | else => unreachable, |
| 3223 | }; | 3155 | }; |
| 3224 | | 3156 | |
| 3225 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | | |
| 3226 | try self.register_manager.getReg(.rax, null); | 3157 | try self.register_manager.getReg(.rax, null); |
| 3227 | try self.register_manager.getReg(.rdx, track_inst_rdx); | 3158 | try self.register_manager.getReg(.rdx, track_inst_rdx); |
| 3228 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | | |
| 3229 | defer for (reg_locks) |reg| { | | |
| 3230 | self.register_manager.unlockReg(reg); | | |
| 3231 | }; | | |
| 3232 | | 3159 | |
| 3233 | switch (int_info.signedness) { | 3160 | switch (signedness) { |
| 3234 | .signed => { | 3161 | .signed => { |
| 3235 | switch (tag) { | 3162 | switch (tag) { |
| 3236 | .rem => { | 3163 | .rem => { |
| 3237 | try self.genIntMulDivOpMir(.idiv, lhs_ty, .signed, lhs, rhs); | 3164 | try self.genIntMulDivOpMir(.idiv, ty, .signed, lhs, rhs); |
| 3238 | return MCValue{ .register = .rdx }; | 3165 | return MCValue{ .register = .rdx }; |
| 3239 | }, | 3166 | }, |
| 3240 | .mod => { | 3167 | .mod => { |
| 3241 | const div_floor = try self.genInlineIntDivFloor(lhs_ty, lhs, rhs); | 3168 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); |
| 3242 | try self.genIntMulComplexOpMir(lhs_ty, div_floor, rhs); | 3169 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 3243 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); | 3170 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); |
| 3244 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); | 3171 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); |
| 3245 | | 3172 | |
| 3246 | const result: MCValue = if (maybe_inst) |inst| | 3173 | const result: MCValue = if (maybe_inst) |inst| |
| 3247 | try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs) | 3174 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) |
| 3248 | else | 3175 | else |
| 3249 | MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) }; | 3176 | MCValue{ .register = try self.copyToTmpRegister(ty, lhs) }; |
| 3250 | try self.genBinOpMir(.sub, lhs_ty, result, div_floor); | 3177 | try self.genBinOpMir(.sub, ty, result, div_floor); |
| 3251 | | 3178 | |
| 3252 | return result; | 3179 | return result; |
| 3253 | }, | 3180 | }, |
| ... | @@ -3255,14 +3182,114 @@ fn genBinOp( | ... | @@ -3255,14 +3182,114 @@ fn genBinOp( |
| 3255 | } | 3182 | } |
| 3256 | }, | 3183 | }, |
| 3257 | .unsigned => { | 3184 | .unsigned => { |
| 3258 | try self.genIntMulDivOpMir(.div, lhs_ty, .unsigned, lhs, rhs); | 3185 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); |
| 3259 | return MCValue{ .register = .rdx }; | 3186 | return MCValue{ .register = .rdx }; |
| 3260 | }, | 3187 | }, |
| 3261 | } | 3188 | } |
| 3262 | }, | 3189 | }, |
| 3263 | else => {}, | 3190 | .div_trunc, |
| | 3191 | .div_floor, |
| | 3192 | .div_exact, |
| | 3193 | => { |
| | 3194 | const track_inst_rax: ?Air.Inst.Index = blk: { |
| | 3195 | if (signedness == .unsigned) break :blk maybe_inst; |
| | 3196 | switch (tag) { |
| | 3197 | .div_exact, .div_trunc => break :blk maybe_inst, |
| | 3198 | else => break :blk null, |
| | 3199 | } |
| | 3200 | }; |
| | 3201 | |
| | 3202 | try self.register_manager.getReg(.rax, track_inst_rax); |
| | 3203 | try self.register_manager.getReg(.rdx, null); |
| | 3204 | |
| | 3205 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| | 3206 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 3207 | else => null, |
| | 3208 | }; |
| | 3209 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3210 | |
| | 3211 | const actual_rhs: MCValue = blk: { |
| | 3212 | if (signedness == .signed) { |
| | 3213 | switch (tag) { |
| | 3214 | .div_floor => { |
| | 3215 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| | 3216 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 3217 | else => null, |
| | 3218 | }; |
| | 3219 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3220 | |
| | 3221 | if (maybe_inst) |inst| { |
| | 3222 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| | 3223 | } |
| | 3224 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; |
| | 3225 | }, |
| | 3226 | else => {}, |
| | 3227 | } |
| | 3228 | } |
| | 3229 | break :blk rhs; |
| | 3230 | }; |
| | 3231 | const rhs_lock: ?RegisterLock = switch (actual_rhs) { |
| | 3232 | .register => |reg| self.register_manager.lockReg(reg), |
| | 3233 | else => null, |
| | 3234 | }; |
| | 3235 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3236 | |
| | 3237 | const result: MCValue = result: { |
| | 3238 | if (signedness == .unsigned) { |
| | 3239 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, actual_rhs); |
| | 3240 | break :result MCValue{ .register = .rax }; |
| | 3241 | } |
| | 3242 | |
| | 3243 | switch (tag) { |
| | 3244 | .div_exact, .div_trunc => { |
| | 3245 | try self.genIntMulDivOpMir(switch (signedness) { |
| | 3246 | .signed => .idiv, |
| | 3247 | .unsigned => .div, |
| | 3248 | }, ty, signedness, lhs, actual_rhs); |
| | 3249 | break :result MCValue{ .register = .rax }; |
| | 3250 | }, |
| | 3251 | .div_floor => { |
| | 3252 | break :result try self.genInlineIntDivFloor(ty, lhs, actual_rhs); |
| | 3253 | }, |
| | 3254 | else => unreachable, |
| | 3255 | } |
| | 3256 | }; |
| | 3257 | return result; |
| | 3258 | }, |
| | 3259 | else => unreachable, |
| | 3260 | } |
| | 3261 | } |
| | 3262 | |
| | 3263 | /// Result is always a register. |
| | 3264 | fn genBinOp( |
| | 3265 | self: *Self, |
| | 3266 | tag: Air.Inst.Tag, |
| | 3267 | maybe_inst: ?Air.Inst.Index, |
| | 3268 | lhs: MCValue, |
| | 3269 | rhs: MCValue, |
| | 3270 | lhs_ty: Type, |
| | 3271 | rhs_ty: Type, |
| | 3272 | ) !MCValue { |
| | 3273 | if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) { |
| | 3274 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| | 3275 | } |
| | 3276 | if (lhs_ty.abiSize(self.target.*) > 8) { |
| | 3277 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 3264 | } | 3278 | } |
| 3265 | | 3279 | |
| | 3280 | const is_commutative: bool = switch (tag) { |
| | 3281 | .add, |
| | 3282 | .addwrap, |
| | 3283 | .bool_or, |
| | 3284 | .bit_or, |
| | 3285 | .bool_and, |
| | 3286 | .bit_and, |
| | 3287 | .xor, |
| | 3288 | => true, |
| | 3289 | |
| | 3290 | else => false, |
| | 3291 | }; |
| | 3292 | |
| 3266 | const lhs_lock: ?RegisterLock = switch (lhs) { | 3293 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 3267 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 3294 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3268 | else => null, | 3295 | else => null, |
| ... | @@ -5460,6 +5487,7 @@ fn genInlineMemcpy( | ... | @@ -5460,6 +5487,7 @@ fn genInlineMemcpy( |
| 5460 | len: MCValue, | 5487 | len: MCValue, |
| 5461 | opts: InlineMemcpyOpts, | 5488 | opts: InlineMemcpyOpts, |
| 5462 | ) InnerError!void { | 5489 | ) InnerError!void { |
| | 5490 | // TODO preserve contents of .rax and .rcx if not free, and then restore |
| 5463 | try self.register_manager.getReg(.rax, null); | 5491 | try self.register_manager.getReg(.rax, null); |
| 5464 | try self.register_manager.getReg(.rcx, null); | 5492 | try self.register_manager.getReg(.rcx, null); |
| 5465 | | 5493 | |
| ... | @@ -5657,6 +5685,7 @@ fn genInlineMemset( | ... | @@ -5657,6 +5685,7 @@ fn genInlineMemset( |
| 5657 | len: MCValue, | 5685 | len: MCValue, |
| 5658 | opts: InlineMemcpyOpts, | 5686 | opts: InlineMemcpyOpts, |
| 5659 | ) InnerError!void { | 5687 | ) InnerError!void { |
| | 5688 | // TODO preserve contents of .rax and then restore |
| 5660 | try self.register_manager.getReg(.rax, null); | 5689 | try self.register_manager.getReg(.rax, null); |
| 5661 | const rax_lock = self.register_manager.lockRegAssumeUnused(.rax); | 5690 | const rax_lock = self.register_manager.lockRegAssumeUnused(.rax); |
| 5662 | defer self.register_manager.unlockReg(rax_lock); | 5691 | defer self.register_manager.unlockReg(rax_lock); |