| ... | ... | @@ -592,11 +592,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 592 | 592 | .sub => try self.airBinOp(inst), |
| 593 | 593 | .subwrap => try self.airBinOp(inst), |
| 594 | 594 | .sub_sat => try self.airSubSat(inst), |
| 595 | | .mul => try self.airBinOp(inst), |
| 596 | | .mulwrap => try self.airBinOp(inst), |
| 595 | .mul => try self.airMulDivBinOp(inst), |
| 596 | .mulwrap => try self.airMulDivBinOp(inst), |
| 597 | 597 | .mul_sat => try self.airMulSat(inst), |
| 598 | | .rem => try self.airBinOp(inst), |
| 599 | | .mod => try self.airBinOp(inst), |
| 598 | .rem => try self.airMulDivBinOp(inst), |
| 599 | .mod => try self.airMulDivBinOp(inst), |
| 600 | 600 | .shl, .shl_exact => try self.airShl(inst), |
| 601 | 601 | .shl_sat => try self.airShlSat(inst), |
| 602 | 602 | .min => try self.airMin(inst), |
| ... | ... | @@ -626,7 +626,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 626 | 626 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 627 | 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 | 631 | .cmp_lt => try self.airCmp(inst, .lt), |
| 632 | 632 | .cmp_lte => try self.airCmp(inst, .lte), |
| ... | ... | @@ -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 | 968 | /// Copies a value to a register without tracking the register. The register is not considered |
| 963 | 969 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 964 | 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 | 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 | 1281 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1256 | 1282 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1257 | 1283 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| ... | ... | @@ -1339,25 +1365,31 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1339 | 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 | 1368 | if (math.isPowerOfTwo(int_info.bits)) { |
| 1369 | try self.spillCompareFlagsIfOccupied(); |
| 1348 | 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 | 1378 | break :result switch (int_info.signedness) { |
| 1351 | 1379 | .signed => MCValue{ .register_overflow_signed = partial.register }, |
| 1352 | 1380 | .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, |
| 1353 | 1381 | }; |
| 1354 | 1382 | } |
| 1355 | 1383 | |
| 1384 | try self.spillCompareFlagsIfOccupied(); |
| 1356 | 1385 | self.compare_flags_inst = null; |
| 1357 | 1386 | |
| 1358 | 1387 | const dst_reg: Register = dst_reg: { |
| 1359 | 1388 | switch (int_info.signedness) { |
| 1360 | 1389 | .signed => { |
| 1390 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1391 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1392 | |
| 1361 | 1393 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1362 | 1394 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1363 | 1395 | else => null, |
| ... | ... | @@ -1386,7 +1418,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1386 | 1418 | break :dst_reg dst_reg; |
| 1387 | 1419 | }, |
| 1388 | 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 | 1427 | break :dst_reg dst_mcv.register; |
| 1391 | 1428 | }, |
| 1392 | 1429 | } |
| ... | ... | @@ -1487,7 +1524,13 @@ fn genIntMulDivOpMir( |
| 1487 | 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 | 1535 | switch (signedness) { |
| 1493 | 1536 | .signed => { |
| ... | ... | @@ -1609,96 +1652,6 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1609 | 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 | 1655 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1703 | 1656 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1704 | 1657 | if (self.liveness.isUnused(inst)) { |
| ... | ... | @@ -3144,110 +3097,84 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3144 | 3097 | } |
| 3145 | 3098 | |
| 3146 | 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 | 3103 | self: *Self, |
| 3149 | 3104 | tag: Air.Inst.Tag, |
| 3150 | 3105 | maybe_inst: ?Air.Inst.Index, |
| 3106 | ty: Type, |
| 3151 | 3107 | lhs: MCValue, |
| 3152 | 3108 | rhs: MCValue, |
| 3153 | | lhs_ty: Type, |
| 3154 | | rhs_ty: Type, |
| 3155 | 3109 | ) !MCValue { |
| 3156 | | const is_commutative: bool = switch (tag) { |
| 3157 | | .add, |
| 3158 | | .addwrap, |
| 3159 | | .bool_or, |
| 3160 | | .bit_or, |
| 3161 | | .bool_and, |
| 3162 | | .bit_and, |
| 3163 | | .xor, |
| 3164 | | => true, |
| 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, |
| 3110 | if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) { |
| 3111 | return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()}); |
| 3112 | } |
| 3113 | if (ty.abiSize(self.target.*) > 8) { |
| 3114 | return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()}); |
| 3115 | } |
| 3116 | if (tag == .div_float) { |
| 3117 | return self.fail("TODO implement genMulDivBinOp for div_float", .{}); |
| 3118 | } |
| 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) { |
| 3186 | | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 3187 | | } |
| 3188 | | if (lhs_ty.abiSize(self.target.*) > 8) { |
| 3189 | | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 3190 | | } |
| 3128 | const int_info = ty.intInfo(self.target.*); |
| 3129 | const signedness = int_info.signedness; |
| 3191 | 3130 | |
| 3192 | 3131 | switch (tag) { |
| 3193 | 3132 | .mul, |
| 3194 | 3133 | .mulwrap, |
| 3195 | 3134 | => { |
| 3196 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 3197 | 3135 | try self.register_manager.getReg(.rax, maybe_inst); |
| 3198 | 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.*); |
| 3205 | | try self.genIntMulDivOpMir(switch (int_info.signedness) { |
| 3138 | try self.genIntMulDivOpMir(switch (signedness) { |
| 3206 | 3139 | .signed => .imul, |
| 3207 | 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 | 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 | 3148 | .mod, |
| 3216 | 3149 | .rem, |
| 3217 | 3150 | => { |
| 3218 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 3219 | 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 | 3153 | .rem => maybe_inst, |
| 3222 | 3154 | else => unreachable, |
| 3223 | 3155 | }; |
| 3224 | 3156 | |
| 3225 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 3226 | 3157 | try self.register_manager.getReg(.rax, null); |
| 3227 | 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 | 3161 | .signed => { |
| 3235 | 3162 | switch (tag) { |
| 3236 | 3163 | .rem => { |
| 3237 | | try self.genIntMulDivOpMir(.idiv, lhs_ty, .signed, lhs, rhs); |
| 3164 | try self.genIntMulDivOpMir(.idiv, ty, .signed, lhs, rhs); |
| 3238 | 3165 | return MCValue{ .register = .rdx }; |
| 3239 | 3166 | }, |
| 3240 | 3167 | .mod => { |
| 3241 | | const div_floor = try self.genInlineIntDivFloor(lhs_ty, lhs, rhs); |
| 3242 | | try self.genIntMulComplexOpMir(lhs_ty, div_floor, rhs); |
| 3168 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); |
| 3169 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 3243 | 3170 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); |
| 3244 | 3171 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); |
| 3245 | 3172 | |
| 3246 | 3173 | const result: MCValue = if (maybe_inst) |inst| |
| 3247 | | try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs) |
| 3174 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) |
| 3248 | 3175 | else |
| 3249 | | MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) }; |
| 3250 | | try self.genBinOpMir(.sub, lhs_ty, result, div_floor); |
| 3176 | MCValue{ .register = try self.copyToTmpRegister(ty, lhs) }; |
| 3177 | try self.genBinOpMir(.sub, ty, result, div_floor); |
| 3251 | 3178 | |
| 3252 | 3179 | return result; |
| 3253 | 3180 | }, |
| ... | ... | @@ -3255,14 +3182,114 @@ fn genBinOp( |
| 3255 | 3182 | } |
| 3256 | 3183 | }, |
| 3257 | 3184 | .unsigned => { |
| 3258 | | try self.genIntMulDivOpMir(.div, lhs_ty, .unsigned, lhs, rhs); |
| 3185 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); |
| 3259 | 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 | 3293 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 3267 | 3294 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3268 | 3295 | else => null, |
| ... | ... | @@ -5460,6 +5487,7 @@ fn genInlineMemcpy( |
| 5460 | 5487 | len: MCValue, |
| 5461 | 5488 | opts: InlineMemcpyOpts, |
| 5462 | 5489 | ) InnerError!void { |
| 5490 | // TODO preserve contents of .rax and .rcx if not free, and then restore |
| 5463 | 5491 | try self.register_manager.getReg(.rax, null); |
| 5464 | 5492 | try self.register_manager.getReg(.rcx, null); |
| 5465 | 5493 | |
| ... | ... | @@ -5657,6 +5685,7 @@ fn genInlineMemset( |
| 5657 | 5685 | len: MCValue, |
| 5658 | 5686 | opts: InlineMemcpyOpts, |
| 5659 | 5687 | ) InnerError!void { |
| 5688 | // TODO preserve contents of .rax and then restore |
| 5660 | 5689 | try self.register_manager.getReg(.rax, null); |
| 5661 | 5690 | const rax_lock = self.register_manager.lockRegAssumeUnused(.rax); |
| 5662 | 5691 | defer self.register_manager.unlockReg(rax_lock); |