| ... | ... | @@ -1414,23 +1414,27 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1414 | 1414 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1415 | 1415 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1416 | 1416 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1417 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1418 | const ty = self.air.typeOf(bin_op.lhs); |
| 1417 | 1419 | |
| 1418 | | if (self.liveness.isUnused(inst)) { |
| 1419 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1420 | | } |
| 1420 | switch (ty.zigTypeTag()) { |
| 1421 | .Vector => return self.fail("TODO implement add_with_overflow for Vector type", .{}), |
| 1422 | .Int => { |
| 1423 | const int_info = ty.intInfo(self.target.*); |
| 1421 | 1424 | |
| 1422 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1423 | | const signedness: std.builtin.Signedness = blk: { |
| 1424 | | if (ty.zigTypeTag() != .Int) { |
| 1425 | | return self.fail("TODO implement airAddWithOverflow for type {}", .{ty.fmtDebug()}); |
| 1426 | | } |
| 1427 | | break :blk ty.intInfo(self.target.*).signedness; |
| 1428 | | }; |
| 1425 | if (int_info.bits > 64) { |
| 1426 | return self.fail("TODO implement add_with_overflow for Ints larger than 64bits", .{}); |
| 1427 | } |
| 1429 | 1428 | |
| 1430 | | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1431 | | const result: MCValue = switch (signedness) { |
| 1432 | | .signed => .{ .register_overflow_signed = partial.register }, |
| 1433 | | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| 1429 | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1430 | const result: MCValue = switch (int_info.signedness) { |
| 1431 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1432 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| 1433 | }; |
| 1434 | break :result result; |
| 1435 | }, |
| 1436 | else => unreachable, |
| 1437 | } |
| 1434 | 1438 | }; |
| 1435 | 1439 | |
| 1436 | 1440 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1439,23 +1443,27 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1439 | 1443 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1440 | 1444 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1441 | 1445 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1446 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1447 | const ty = self.air.typeOf(bin_op.lhs); |
| 1442 | 1448 | |
| 1443 | | if (self.liveness.isUnused(inst)) { |
| 1444 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1445 | | } |
| 1449 | switch (ty.zigTypeTag()) { |
| 1450 | .Vector => return self.fail("TODO implement sub_with_overflow for Vector type", .{}), |
| 1451 | .Int => { |
| 1452 | const int_info = ty.intInfo(self.target.*); |
| 1446 | 1453 | |
| 1447 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1448 | | const signedness: std.builtin.Signedness = blk: { |
| 1449 | | if (ty.zigTypeTag() != .Int) { |
| 1450 | | return self.fail("TODO implement airSubWithOverflow for type {}", .{ty.fmtDebug()}); |
| 1451 | | } |
| 1452 | | break :blk ty.intInfo(self.target.*).signedness; |
| 1453 | | }; |
| 1454 | if (int_info.bits > 64) { |
| 1455 | return self.fail("TODO implement sub_with_overflow for Ints larger than 64bits", .{}); |
| 1456 | } |
| 1454 | 1457 | |
| 1455 | | const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs); |
| 1456 | | const result: MCValue = switch (signedness) { |
| 1457 | | .signed => .{ .register_overflow_signed = partial.register }, |
| 1458 | | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| 1458 | const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs); |
| 1459 | const result: MCValue = switch (int_info.signedness) { |
| 1460 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1461 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| 1462 | }; |
| 1463 | break :result result; |
| 1464 | }, |
| 1465 | else => unreachable, |
| 1466 | } |
| 1459 | 1467 | }; |
| 1460 | 1468 | |
| 1461 | 1469 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1466,30 +1474,37 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1466 | 1474 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1467 | 1475 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1468 | 1476 | const ty = self.air.typeOf(bin_op.lhs); |
| 1469 | | const signedness: std.builtin.Signedness = blk: { |
| 1470 | | if (ty.zigTypeTag() != .Int) { |
| 1471 | | return self.fail("TODO implement airMulWithOverflow for type {}", .{ty.fmtDebug()}); |
| 1472 | | } |
| 1473 | | break :blk ty.intInfo(self.target.*).signedness; |
| 1474 | | }; |
| 1475 | 1477 | |
| 1476 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1477 | | try self.register_manager.getReg(.rax, inst); |
| 1478 | | try self.register_manager.getReg(.rdx, null); |
| 1479 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1480 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1478 | switch (ty.zigTypeTag()) { |
| 1479 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 1480 | .Int => { |
| 1481 | const int_info = ty.intInfo(self.target.*); |
| 1481 | 1482 | |
| 1482 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1483 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1483 | if (int_info.bits > 64) { |
| 1484 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); |
| 1485 | } |
| 1484 | 1486 | |
| 1485 | | try self.genIntMulDivOpMir(switch (signedness) { |
| 1486 | | .signed => .imul, |
| 1487 | | .unsigned => .mul, |
| 1488 | | }, ty, signedness, lhs, rhs); |
| 1487 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1488 | try self.register_manager.getReg(.rax, inst); |
| 1489 | try self.register_manager.getReg(.rdx, null); |
| 1490 | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1491 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1489 | 1492 | |
| 1490 | | switch (signedness) { |
| 1491 | | .signed => break :result MCValue{ .register_overflow_signed = .rax }, |
| 1492 | | .unsigned => break :result MCValue{ .register_overflow_unsigned = .rax }, |
| 1493 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1494 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1495 | |
| 1496 | try self.genIntMulDivOpMir(switch (int_info.signedness) { |
| 1497 | .signed => .imul, |
| 1498 | .unsigned => .mul, |
| 1499 | }, ty, int_info.signedness, lhs, rhs); |
| 1500 | |
| 1501 | const result: MCValue = switch (int_info.signedness) { |
| 1502 | .signed => .{ .register_overflow_signed = .rax }, |
| 1503 | .unsigned => .{ .register_overflow_unsigned = .rax }, |
| 1504 | }; |
| 1505 | break :result result; |
| 1506 | }, |
| 1507 | else => unreachable, |
| 1493 | 1508 | } |
| 1494 | 1509 | }; |
| 1495 | 1510 | |