authorgravatar for abbix@riseup.netlg <abbix@riseup.net> 2026-08-31 11:48:29+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-31 11:48:29+02:00
log749ed5fc7f4afd7a42830f77f69245f1abcdd9a0
treecd34e3987a5188f8a05c9bb98002f91bf05cbedd
parentaad8da82a5cfd9b7602ee3adbff340c9c15d9165

Sema: comptime arithmetic optimizations (#36495)

Tests heavy on comptime arithmetic show a ~7% improvement in wall-clock time, and a ~11% improvement in peak RSS. There are two optimizations: 1. Avoid interning the overflow bit Previously, the overflow bit was being interned and immediately read back. Instead, a new OverflowArithmeticResultInt type is introduced that contains the overflow result as a boolean directly. When converted, that boolean points to the already existing zero_u1 and one_u1 interned values. 2. Try arithmetic operations without BigInt first. This did not show significant performance improvements, but it did show a significant memory usage improvement, almost going 0.5x! Instead of resorting to BigInt first, arithmetic operations are tried in a u64. Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36495 Reviewed-by: mlugg <mlugg@mlugg.co.uk>

2 files changed, 79 insertions(+), 43 deletions(-)

src/Sema/arith.zig+74-43
...@@ -169,7 +169,11 @@ fn addWithOverflowScalar(...@@ -169,7 +169,11 @@ fn addWithOverflowScalar(
169 .overflow_bit = .undef_u1,169 .overflow_bit = .undef_u1,
170 .wrapped_result = try pt.undefValue(ty),170 .wrapped_result = try pt.undefValue(ty),
171 };171 };
172 return intAddWithOverflow(sema, lhs, rhs, ty);172 const res = try intAddWithOverflow(sema, lhs, rhs, ty);
173 return .{
174 .overflow_bit = if (res.overflow) .one_u1 else .zero_u1,
175 .wrapped_result = res.wrapped_result,
176 };
173}177}
174178
175/// `lhs` and `rhs` are of type `ty`.179/// `lhs` and `rhs` are of type `ty`.
...@@ -227,7 +231,12 @@ fn subWithOverflowScalar(...@@ -227,7 +231,12 @@ fn subWithOverflowScalar(
227 .overflow_bit = .undef_u1,231 .overflow_bit = .undef_u1,
228 .wrapped_result = try pt.undefValue(ty),232 .wrapped_result = try pt.undefValue(ty),
229 };233 };
230 return intSubWithOverflow(sema, lhs, rhs, ty);234
235 const res = try intSubWithOverflow(sema, lhs, rhs, ty);
236 return .{
237 .overflow_bit = if (res.overflow) .one_u1 else .zero_u1,
238 .wrapped_result = res.wrapped_result,
239 };
231}240}
232241
233/// `lhs` and `rhs` are of type `ty`.242/// `lhs` and `rhs` are of type `ty`.
...@@ -285,7 +294,11 @@ fn mulWithOverflowScalar(...@@ -285,7 +294,11 @@ fn mulWithOverflowScalar(
285 .overflow_bit = .undef_u1,294 .overflow_bit = .undef_u1,
286 .wrapped_result = try pt.undefValue(ty),295 .wrapped_result = try pt.undefValue(ty),
287 };296 };
288 return intMulWithOverflow(sema, lhs, rhs, ty);297 const res = try intMulWithOverflow(sema, lhs, rhs, ty);
298 return .{
299 .overflow_bit = if (res.overflow) .one_u1 else .zero_u1,
300 .wrapped_result = res.wrapped_result,
301 };
289}302}
290303
291/// Applies the `+` operator to comptime-known values.304/// Applies the `+` operator to comptime-known values.
...@@ -1108,7 +1121,7 @@ fn shlWithOverflowScalar(...@@ -1108,7 +1121,7 @@ fn shlWithOverflowScalar(
1108 .int => {1121 .int => {
1109 const result = try intShlWithOverflow(sema, block, lhs_ty, lhs_val, rhs_val, rhs_src, true, vec_idx);1122 const result = try intShlWithOverflow(sema, block, lhs_ty, lhs_val, rhs_val, rhs_src, true, vec_idx);
1110 return .{1123 return .{
1111 .overflow_bit = try pt.intValue(.u1, @intFromBool(result.overflow)),1124 .overflow_bit = if (result.overflow) .one_u1 else .zero_u1,
1112 .wrapped_result = result.val,1125 .wrapped_result = result.val,
1113 };1126 };
1114 },1127 },
...@@ -1390,17 +1403,12 @@ pub fn byteSwap(sema: *Sema, val: Value, ty: Type) CompileError!Value {...@@ -1390,17 +1403,12 @@ pub fn byteSwap(sema: *Sema, val: Value, ty: Type) CompileError!Value {
1390/// If the value overflowed the type, returns a comptime_int instead.1403/// If the value overflowed the type, returns a comptime_int instead.
1391/// Only supports scalars.1404/// Only supports scalars.
1392fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } {1405fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } {
1393 const pt = sema.pt;
1394 const zcu = pt.zcu;
1395 switch (ty.toIntern()) {1406 switch (ty.toIntern()) {
1396 .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntAdd(sema, lhs, rhs) },1407 .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntAdd(sema, lhs, rhs) },
1397 else => {1408 else => {
1398 const res = try intAddWithOverflowInner(sema, lhs, rhs, ty);1409 const res = try intAddWithOverflowInner(sema, lhs, rhs, ty);
1399 return switch (res.overflow_bit.toUnsignedInt(zcu)) {1410 if (res.overflow) return .{ .overflow = true, .val = try comptimeIntAdd(sema, lhs, rhs) };
1400 0 => .{ .overflow = false, .val = res.wrapped_result },1411 return .{ .overflow = false, .val = res.wrapped_result };
1401 1 => .{ .overflow = true, .val = try comptimeIntAdd(sema, lhs, rhs) },
1402 else => unreachable,
1403 };
1404 },1412 },
1405 }1413 }
1406}1414}
...@@ -1408,8 +1416,19 @@ fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo...@@ -1408,8 +1416,19 @@ fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo
1408fn comptimeIntAdd(sema: *Sema, lhs: Value, rhs: Value) !Value {1416fn comptimeIntAdd(sema: *Sema, lhs: Value, rhs: Value) !Value {
1409 const pt = sema.pt;1417 const pt = sema.pt;
1410 const zcu = pt.zcu;1418 const zcu = pt.zcu;
1411 // TODO is this a performance issue? maybe we should try the operation without1419
1412 // resorting to BigInt first.1420 // Try the operation without resorting to BigInt first.
1421 if (lhs.getUnsignedInt(zcu)) |lhs_val| {
1422 if (rhs.getUnsignedInt(zcu)) |rhs_val| {
1423 const result, const overflow = @addWithOverflow(lhs_val, rhs_val);
1424
1425 if (overflow == 0) {
1426 return pt.intValue(.comptime_int, result);
1427 }
1428 // It would overflow, fall back to BigInt.
1429 }
1430 }
1431
1413 var lhs_space: Value.BigIntSpace = undefined;1432 var lhs_space: Value.BigIntSpace = undefined;
1414 var rhs_space: Value.BigIntSpace = undefined;1433 var rhs_space: Value.BigIntSpace = undefined;
1415 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);1434 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
...@@ -1422,17 +1441,17 @@ fn comptimeIntAdd(sema: *Sema, lhs: Value, rhs: Value) !Value {...@@ -1422,17 +1441,17 @@ fn comptimeIntAdd(sema: *Sema, lhs: Value, rhs: Value) !Value {
1422 result_bigint.add(lhs_bigint, rhs_bigint);1441 result_bigint.add(lhs_bigint, rhs_bigint);
1423 return pt.intValue_big(.comptime_int, result_bigint.toConst());1442 return pt.intValue_big(.comptime_int, result_bigint.toConst());
1424}1443}
1425fn intAddWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult {1444fn intAddWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt {
1426 switch (ty.toIntern()) {1445 switch (ty.toIntern()) {
1427 .comptime_int_type => return .{1446 .comptime_int_type => return .{
1428 .overflow_bit = .zero_u1,1447 .overflow = false,
1429 .wrapped_result = try comptimeIntAdd(sema, lhs, rhs),1448 .wrapped_result = try comptimeIntAdd(sema, lhs, rhs),
1430 },1449 },
1431 else => return intAddWithOverflowInner(sema, lhs, rhs, ty),1450 else => return intAddWithOverflowInner(sema, lhs, rhs, ty),
1432 }1451 }
1433}1452}
1434/// Like `intAddWithOverflow`, but asserts that `ty` is not `Type.comptime_int`.1453/// Like `intAddWithOverflow`, but asserts that `ty` is not `Type.comptime_int`.
1435fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult {1454fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt {
1436 assert(ty.toIntern() != .comptime_int_type);1455 assert(ty.toIntern() != .comptime_int_type);
1437 const pt = sema.pt;1456 const pt = sema.pt;
1438 const zcu = pt.zcu;1457 const zcu = pt.zcu;
...@@ -1448,7 +1467,7 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value...@@ -1448,7 +1467,7 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
1448 var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };1467 var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
1449 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);1468 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
1450 return .{1469 return .{
1451 .overflow_bit = try pt.intValue(.u1, @intFromBool(overflowed)),1470 .overflow = overflowed,
1452 .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()),1471 .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()),
1453 };1472 };
1454}1473}
...@@ -1472,17 +1491,12 @@ fn intAddSat(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {...@@ -1472,17 +1491,12 @@ fn intAddSat(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {
1472/// If the value overflowed the type, returns a comptime_int instead.1491/// If the value overflowed the type, returns a comptime_int instead.
1473/// Only supports scalars.1492/// Only supports scalars.
1474fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } {1493fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } {
1475 const pt = sema.pt;
1476 const zcu = pt.zcu;
1477 switch (ty.toIntern()) {1494 switch (ty.toIntern()) {
1478 .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntSub(sema, lhs, rhs) },1495 .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntSub(sema, lhs, rhs) },
1479 else => {1496 else => {
1480 const res = try intSubWithOverflowInner(sema, lhs, rhs, ty);1497 const res = try intSubWithOverflowInner(sema, lhs, rhs, ty);
1481 return switch (res.overflow_bit.toUnsignedInt(zcu)) {1498 if (res.overflow) return .{ .overflow = true, .val = try comptimeIntSub(sema, lhs, rhs) };
1482 0 => .{ .overflow = false, .val = res.wrapped_result },1499 return .{ .overflow = false, .val = res.wrapped_result };
1483 1 => .{ .overflow = true, .val = try comptimeIntSub(sema, lhs, rhs) },
1484 else => unreachable,
1485 };
1486 },1500 },
1487 }1501 }
1488}1502}
...@@ -1490,8 +1504,19 @@ fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo...@@ -1490,8 +1504,19 @@ fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo
1490fn comptimeIntSub(sema: *Sema, lhs: Value, rhs: Value) !Value {1504fn comptimeIntSub(sema: *Sema, lhs: Value, rhs: Value) !Value {
1491 const pt = sema.pt;1505 const pt = sema.pt;
1492 const zcu = pt.zcu;1506 const zcu = pt.zcu;
1493 // TODO is this a performance issue? maybe we should try the operation without1507
1494 // resorting to BigInt first.1508 // Try the operation without resorting to BigInt first.
1509 if (lhs.getUnsignedInt(zcu)) |lhs_val| {
1510 if (rhs.getUnsignedInt(zcu)) |rhs_val| {
1511 const result, const overflow = @subWithOverflow(lhs_val, rhs_val);
1512
1513 if (overflow == 0) {
1514 return pt.intValue(.comptime_int, result);
1515 }
1516 // It would overflow, fall back to BigInt.
1517 }
1518 }
1519
1495 var lhs_space: Value.BigIntSpace = undefined;1520 var lhs_space: Value.BigIntSpace = undefined;
1496 var rhs_space: Value.BigIntSpace = undefined;1521 var rhs_space: Value.BigIntSpace = undefined;
1497 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);1522 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
...@@ -1504,17 +1529,17 @@ fn comptimeIntSub(sema: *Sema, lhs: Value, rhs: Value) !Value {...@@ -1504,17 +1529,17 @@ fn comptimeIntSub(sema: *Sema, lhs: Value, rhs: Value) !Value {
1504 result_bigint.sub(lhs_bigint, rhs_bigint);1529 result_bigint.sub(lhs_bigint, rhs_bigint);
1505 return pt.intValue_big(.comptime_int, result_bigint.toConst());1530 return pt.intValue_big(.comptime_int, result_bigint.toConst());
1506}1531}
1507fn intSubWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult {1532fn intSubWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt {
1508 switch (ty.toIntern()) {1533 switch (ty.toIntern()) {
1509 .comptime_int_type => return .{1534 .comptime_int_type => return .{
1510 .overflow_bit = .zero_u1,1535 .overflow = false,
1511 .wrapped_result = try comptimeIntSub(sema, lhs, rhs),1536 .wrapped_result = try comptimeIntSub(sema, lhs, rhs),
1512 },1537 },
1513 else => return intSubWithOverflowInner(sema, lhs, rhs, ty),1538 else => return intSubWithOverflowInner(sema, lhs, rhs, ty),
1514 }1539 }
1515}1540}
1516/// Like `intSubWithOverflow`, but asserts that `ty` is not `Type.comptime_int`.1541/// Like `intSubWithOverflow`, but asserts that `ty` is not `Type.comptime_int`.
1517fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult {1542fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt {
1518 assert(ty.toIntern() != .comptime_int_type);1543 assert(ty.toIntern() != .comptime_int_type);
1519 const pt = sema.pt;1544 const pt = sema.pt;
1520 const zcu = pt.zcu;1545 const zcu = pt.zcu;
...@@ -1530,7 +1555,7 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value...@@ -1530,7 +1555,7 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
1530 var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };1555 var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
1531 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);1556 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
1532 return .{1557 return .{
1533 .overflow_bit = try pt.intValue(.u1, @intFromBool(overflowed)),1558 .overflow = overflowed,
1534 .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()),1559 .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()),
1535 };1560 };
1536}1561}
...@@ -1554,17 +1579,12 @@ fn intSubSat(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {...@@ -1554,17 +1579,12 @@ fn intSubSat(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {
1554/// If the value overflowed the type, returns a comptime_int instead.1579/// If the value overflowed the type, returns a comptime_int instead.
1555/// Only supports scalars.1580/// Only supports scalars.
1556fn intMul(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } {1581fn intMul(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } {
1557 const pt = sema.pt;
1558 const zcu = pt.zcu;
1559 switch (ty.toIntern()) {1582 switch (ty.toIntern()) {
1560 .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntMul(sema, lhs, rhs) },1583 .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntMul(sema, lhs, rhs) },
1561 else => {1584 else => {
1562 const res = try intMulWithOverflowInner(sema, lhs, rhs, ty);1585 const res = try intMulWithOverflowInner(sema, lhs, rhs, ty);
1563 return switch (res.overflow_bit.toUnsignedInt(zcu)) {1586 if (res.overflow) return .{ .overflow = true, .val = try comptimeIntMul(sema, lhs, rhs) };
1564 0 => .{ .overflow = false, .val = res.wrapped_result },1587 return .{ .overflow = false, .val = res.wrapped_result };
1565 1 => .{ .overflow = true, .val = try comptimeIntMul(sema, lhs, rhs) },
1566 else => unreachable,
1567 };
1568 },1588 },
1569 }1589 }
1570}1590}
...@@ -1572,8 +1592,19 @@ fn intMul(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo...@@ -1572,8 +1592,19 @@ fn intMul(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo
1572fn comptimeIntMul(sema: *Sema, lhs: Value, rhs: Value) !Value {1592fn comptimeIntMul(sema: *Sema, lhs: Value, rhs: Value) !Value {
1573 const pt = sema.pt;1593 const pt = sema.pt;
1574 const zcu = pt.zcu;1594 const zcu = pt.zcu;
1575 // TODO is this a performance issue? maybe we should try the operation without1595
1576 // resorting to BigInt first.1596 // Try the operation without resorting to BigInt first.
1597 if (lhs.getUnsignedInt(zcu)) |lhs_val| {
1598 if (rhs.getUnsignedInt(zcu)) |rhs_val| {
1599 const result, const overflow = @mulWithOverflow(lhs_val, rhs_val);
1600
1601 if (overflow == 0) {
1602 return pt.intValue(.comptime_int, result);
1603 }
1604 // It would overflow, fall back to BigInt.
1605 }
1606 }
1607
1577 var lhs_space: Value.BigIntSpace = undefined;1608 var lhs_space: Value.BigIntSpace = undefined;
1578 var rhs_space: Value.BigIntSpace = undefined;1609 var rhs_space: Value.BigIntSpace = undefined;
1579 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);1610 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
...@@ -1590,17 +1621,17 @@ fn comptimeIntMul(sema: *Sema, lhs: Value, rhs: Value) !Value {...@@ -1590,17 +1621,17 @@ fn comptimeIntMul(sema: *Sema, lhs: Value, rhs: Value) !Value {
1590 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, sema.arena);1621 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, sema.arena);
1591 return pt.intValue_big(.comptime_int, result_bigint.toConst());1622 return pt.intValue_big(.comptime_int, result_bigint.toConst());
1592}1623}
1593fn intMulWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult {1624fn intMulWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt {
1594 switch (ty.toIntern()) {1625 switch (ty.toIntern()) {
1595 .comptime_int_type => return .{1626 .comptime_int_type => return .{
1596 .overflow_bit = .zero_u1,1627 .overflow = false,
1597 .wrapped_result = try comptimeIntMul(sema, lhs, rhs),1628 .wrapped_result = try comptimeIntMul(sema, lhs, rhs),
1598 },1629 },
1599 else => return intMulWithOverflowInner(sema, lhs, rhs, ty),1630 else => return intMulWithOverflowInner(sema, lhs, rhs, ty),
1600 }1631 }
1601}1632}
1602/// Like `intMulWithOverflow`, but asserts that `ty` is not `Type.comptime_int`.1633/// Like `intMulWithOverflow`, but asserts that `ty` is not `Type.comptime_int`.
1603fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult {1634fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt {
1604 const pt = sema.pt;1635 const pt = sema.pt;
1605 const zcu = pt.zcu;1636 const zcu = pt.zcu;
1606 const info = ty.intInfo(zcu);1637 const info = ty.intInfo(zcu);
...@@ -1617,7 +1648,7 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value...@@ -1617,7 +1648,7 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
1617 const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits);1648 const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits);
1618 if (overflowed) result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);1649 if (overflowed) result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
1619 return .{1650 return .{
1620 .overflow_bit = try pt.intValue(.u1, @intFromBool(overflowed)),1651 .overflow = overflowed,
1621 .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()),1652 .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()),
1622 };1653 };
1623}1654}
src/Value.zig+5
...@@ -1051,6 +1051,11 @@ pub const OverflowArithmeticResult = struct {...@@ -1051,6 +1051,11 @@ pub const OverflowArithmeticResult = struct {
1051 wrapped_result: Value,1051 wrapped_result: Value,
1052};1052};
10531053
1054pub const OverflowArithmeticResultInt = struct {
1055 overflow: bool,
1056 wrapped_result: Value,
1057};
1058
1054/// Supports both floats and ints; handles undefined.1059/// Supports both floats and ints; handles undefined.
1055pub fn numberMax(lhs: Value, rhs: Value, zcu: *Zcu) Value {1060pub fn numberMax(lhs: Value, rhs: Value, zcu: *Zcu) Value {
1056 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;1061 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;