| ... | ... | @@ -169,7 +169,11 @@ fn addWithOverflowScalar( |
| 169 | 169 | .overflow_bit = .undef_u1, |
| 170 | 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 | } |
| 174 | 178 | |
| 175 | 179 | /// `lhs` and `rhs` are of type `ty`. |
| ... | ... | @@ -227,7 +231,12 @@ fn subWithOverflowScalar( |
| 227 | 231 | .overflow_bit = .undef_u1, |
| 228 | 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 | } |
| 232 | 241 | |
| 233 | 242 | /// `lhs` and `rhs` are of type `ty`. |
| ... | ... | @@ -285,7 +294,11 @@ fn mulWithOverflowScalar( |
| 285 | 294 | .overflow_bit = .undef_u1, |
| 286 | 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 | } |
| 290 | 303 | |
| 291 | 304 | /// Applies the `+` operator to comptime-known values. |
| ... | ... | @@ -1108,7 +1121,7 @@ fn shlWithOverflowScalar( |
| 1108 | 1121 | .int => { |
| 1109 | 1122 | const result = try intShlWithOverflow(sema, block, lhs_ty, lhs_val, rhs_val, rhs_src, true, vec_idx); |
| 1110 | 1123 | return .{ |
| 1111 | | .overflow_bit = try pt.intValue(.u1, @intFromBool(result.overflow)), |
| 1124 | .overflow_bit = if (result.overflow) .one_u1 else .zero_u1, |
| 1112 | 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 | 1403 | /// If the value overflowed the type, returns a comptime_int instead. |
| 1391 | 1404 | /// Only supports scalars. |
| 1392 | 1405 | fn 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 | 1406 | switch (ty.toIntern()) { |
| 1396 | 1407 | .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntAdd(sema, lhs, rhs) }, |
| 1397 | 1408 | else => { |
| 1398 | 1409 | const res = try intAddWithOverflowInner(sema, lhs, rhs, ty); |
| 1399 | | return switch (res.overflow_bit.toUnsignedInt(zcu)) { |
| 1400 | | 0 => .{ .overflow = false, .val = res.wrapped_result }, |
| 1401 | | 1 => .{ .overflow = true, .val = try comptimeIntAdd(sema, lhs, rhs) }, |
| 1402 | | else => unreachable, |
| 1403 | | }; |
| 1410 | if (res.overflow) return .{ .overflow = true, .val = try comptimeIntAdd(sema, lhs, rhs) }; |
| 1411 | return .{ .overflow = false, .val = res.wrapped_result }; |
| 1404 | 1412 | }, |
| 1405 | 1413 | } |
| 1406 | 1414 | } |
| ... | ... | @@ -1408,8 +1416,19 @@ fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo |
| 1408 | 1416 | fn comptimeIntAdd(sema: *Sema, lhs: Value, rhs: Value) !Value { |
| 1409 | 1417 | const pt = sema.pt; |
| 1410 | 1418 | const zcu = pt.zcu; |
| 1411 | | // TODO is this a performance issue? maybe we should try the operation without |
| 1412 | | // resorting to BigInt first. |
| 1419 | |
| 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 | 1432 | var lhs_space: Value.BigIntSpace = undefined; |
| 1414 | 1433 | var rhs_space: Value.BigIntSpace = undefined; |
| 1415 | 1434 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| ... | ... | @@ -1422,17 +1441,17 @@ fn comptimeIntAdd(sema: *Sema, lhs: Value, rhs: Value) !Value { |
| 1422 | 1441 | result_bigint.add(lhs_bigint, rhs_bigint); |
| 1423 | 1442 | return pt.intValue_big(.comptime_int, result_bigint.toConst()); |
| 1424 | 1443 | } |
| 1425 | | fn intAddWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult { |
| 1444 | fn intAddWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt { |
| 1426 | 1445 | switch (ty.toIntern()) { |
| 1427 | 1446 | .comptime_int_type => return .{ |
| 1428 | | .overflow_bit = .zero_u1, |
| 1447 | .overflow = false, |
| 1429 | 1448 | .wrapped_result = try comptimeIntAdd(sema, lhs, rhs), |
| 1430 | 1449 | }, |
| 1431 | 1450 | else => return intAddWithOverflowInner(sema, lhs, rhs, ty), |
| 1432 | 1451 | } |
| 1433 | 1452 | } |
| 1434 | 1453 | /// Like `intAddWithOverflow`, but asserts that `ty` is not `Type.comptime_int`. |
| 1435 | | fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult { |
| 1454 | fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt { |
| 1436 | 1455 | assert(ty.toIntern() != .comptime_int_type); |
| 1437 | 1456 | const pt = sema.pt; |
| 1438 | 1457 | const zcu = pt.zcu; |
| ... | ... | @@ -1448,7 +1467,7 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value |
| 1448 | 1467 | var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1449 | 1468 | const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); |
| 1450 | 1469 | return .{ |
| 1451 | | .overflow_bit = try pt.intValue(.u1, @intFromBool(overflowed)), |
| 1470 | .overflow = overflowed, |
| 1452 | 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 | 1491 | /// If the value overflowed the type, returns a comptime_int instead. |
| 1473 | 1492 | /// Only supports scalars. |
| 1474 | 1493 | fn 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 | 1494 | switch (ty.toIntern()) { |
| 1478 | 1495 | .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntSub(sema, lhs, rhs) }, |
| 1479 | 1496 | else => { |
| 1480 | 1497 | const res = try intSubWithOverflowInner(sema, lhs, rhs, ty); |
| 1481 | | return switch (res.overflow_bit.toUnsignedInt(zcu)) { |
| 1482 | | 0 => .{ .overflow = false, .val = res.wrapped_result }, |
| 1483 | | 1 => .{ .overflow = true, .val = try comptimeIntSub(sema, lhs, rhs) }, |
| 1484 | | else => unreachable, |
| 1485 | | }; |
| 1498 | if (res.overflow) return .{ .overflow = true, .val = try comptimeIntSub(sema, lhs, rhs) }; |
| 1499 | return .{ .overflow = false, .val = res.wrapped_result }; |
| 1486 | 1500 | }, |
| 1487 | 1501 | } |
| 1488 | 1502 | } |
| ... | ... | @@ -1490,8 +1504,19 @@ fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo |
| 1490 | 1504 | fn comptimeIntSub(sema: *Sema, lhs: Value, rhs: Value) !Value { |
| 1491 | 1505 | const pt = sema.pt; |
| 1492 | 1506 | const zcu = pt.zcu; |
| 1493 | | // TODO is this a performance issue? maybe we should try the operation without |
| 1494 | | // resorting to BigInt first. |
| 1507 | |
| 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 | 1520 | var lhs_space: Value.BigIntSpace = undefined; |
| 1496 | 1521 | var rhs_space: Value.BigIntSpace = undefined; |
| 1497 | 1522 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| ... | ... | @@ -1504,17 +1529,17 @@ fn comptimeIntSub(sema: *Sema, lhs: Value, rhs: Value) !Value { |
| 1504 | 1529 | result_bigint.sub(lhs_bigint, rhs_bigint); |
| 1505 | 1530 | return pt.intValue_big(.comptime_int, result_bigint.toConst()); |
| 1506 | 1531 | } |
| 1507 | | fn intSubWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult { |
| 1532 | fn intSubWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt { |
| 1508 | 1533 | switch (ty.toIntern()) { |
| 1509 | 1534 | .comptime_int_type => return .{ |
| 1510 | | .overflow_bit = .zero_u1, |
| 1535 | .overflow = false, |
| 1511 | 1536 | .wrapped_result = try comptimeIntSub(sema, lhs, rhs), |
| 1512 | 1537 | }, |
| 1513 | 1538 | else => return intSubWithOverflowInner(sema, lhs, rhs, ty), |
| 1514 | 1539 | } |
| 1515 | 1540 | } |
| 1516 | 1541 | /// Like `intSubWithOverflow`, but asserts that `ty` is not `Type.comptime_int`. |
| 1517 | | fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult { |
| 1542 | fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt { |
| 1518 | 1543 | assert(ty.toIntern() != .comptime_int_type); |
| 1519 | 1544 | const pt = sema.pt; |
| 1520 | 1545 | const zcu = pt.zcu; |
| ... | ... | @@ -1530,7 +1555,7 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value |
| 1530 | 1555 | var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1531 | 1556 | const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); |
| 1532 | 1557 | return .{ |
| 1533 | | .overflow_bit = try pt.intValue(.u1, @intFromBool(overflowed)), |
| 1558 | .overflow = overflowed, |
| 1534 | 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 | 1579 | /// If the value overflowed the type, returns a comptime_int instead. |
| 1555 | 1580 | /// Only supports scalars. |
| 1556 | 1581 | fn 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 | 1582 | switch (ty.toIntern()) { |
| 1560 | 1583 | .comptime_int_type => return .{ .overflow = false, .val = try comptimeIntMul(sema, lhs, rhs) }, |
| 1561 | 1584 | else => { |
| 1562 | 1585 | const res = try intMulWithOverflowInner(sema, lhs, rhs, ty); |
| 1563 | | return switch (res.overflow_bit.toUnsignedInt(zcu)) { |
| 1564 | | 0 => .{ .overflow = false, .val = res.wrapped_result }, |
| 1565 | | 1 => .{ .overflow = true, .val = try comptimeIntMul(sema, lhs, rhs) }, |
| 1566 | | else => unreachable, |
| 1567 | | }; |
| 1586 | if (res.overflow) return .{ .overflow = true, .val = try comptimeIntMul(sema, lhs, rhs) }; |
| 1587 | return .{ .overflow = false, .val = res.wrapped_result }; |
| 1568 | 1588 | }, |
| 1569 | 1589 | } |
| 1570 | 1590 | } |
| ... | ... | @@ -1572,8 +1592,19 @@ fn intMul(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: boo |
| 1572 | 1592 | fn comptimeIntMul(sema: *Sema, lhs: Value, rhs: Value) !Value { |
| 1573 | 1593 | const pt = sema.pt; |
| 1574 | 1594 | const zcu = pt.zcu; |
| 1575 | | // TODO is this a performance issue? maybe we should try the operation without |
| 1576 | | // resorting to BigInt first. |
| 1595 | |
| 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 | 1608 | var lhs_space: Value.BigIntSpace = undefined; |
| 1578 | 1609 | var rhs_space: Value.BigIntSpace = undefined; |
| 1579 | 1610 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| ... | ... | @@ -1590,17 +1621,17 @@ fn comptimeIntMul(sema: *Sema, lhs: Value, rhs: Value) !Value { |
| 1590 | 1621 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, sema.arena); |
| 1591 | 1622 | return pt.intValue_big(.comptime_int, result_bigint.toConst()); |
| 1592 | 1623 | } |
| 1593 | | fn intMulWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult { |
| 1624 | fn intMulWithOverflow(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt { |
| 1594 | 1625 | switch (ty.toIntern()) { |
| 1595 | 1626 | .comptime_int_type => return .{ |
| 1596 | | .overflow_bit = .zero_u1, |
| 1627 | .overflow = false, |
| 1597 | 1628 | .wrapped_result = try comptimeIntMul(sema, lhs, rhs), |
| 1598 | 1629 | }, |
| 1599 | 1630 | else => return intMulWithOverflowInner(sema, lhs, rhs, ty), |
| 1600 | 1631 | } |
| 1601 | 1632 | } |
| 1602 | 1633 | /// Like `intMulWithOverflow`, but asserts that `ty` is not `Type.comptime_int`. |
| 1603 | | fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResult { |
| 1634 | fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value.OverflowArithmeticResultInt { |
| 1604 | 1635 | const pt = sema.pt; |
| 1605 | 1636 | const zcu = pt.zcu; |
| 1606 | 1637 | const info = ty.intInfo(zcu); |
| ... | ... | @@ -1617,7 +1648,7 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value |
| 1617 | 1648 | const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits); |
| 1618 | 1649 | if (overflowed) result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); |
| 1619 | 1650 | return .{ |
| 1620 | | .overflow_bit = try pt.intValue(.u1, @intFromBool(overflowed)), |
| 1651 | .overflow = overflowed, |
| 1621 | 1652 | .wrapped_result = try pt.intValue_big(ty, result_bigint.toConst()), |
| 1622 | 1653 | }; |
| 1623 | 1654 | } |