testInt128.cpp (17262B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifdef JS_HAS_INTL_API 6 7 # include "mozilla/Compiler.h" 8 # include "mozilla/TextUtils.h" 9 10 # include <array> 11 # include <climits> 12 # include <cstdlib> 13 # include <limits> 14 # include <optional> 15 # include <stdint.h> 16 17 # include "jsapi-tests/tests.h" 18 # include "vm/Int128.h" 19 20 // Use static_assert in compilers which support CWG2518. In all other cases 21 // fall back to std::abort(). 22 // 23 // https://cplusplus.github.io/CWG/issues/2518.html 24 # if defined(__clang__) 25 # define UINT128_PARSE_ERROR(...) static_assert(false, __VA_ARGS__) 26 # elif MOZ_IS_GCC 27 # if MOZ_GCC_VERSION_AT_LEAST(13, 1, 0) 28 # define UINT128_PARSE_ERROR(...) static_assert(false, __VA_ARGS__) 29 # endif 30 # endif 31 # ifndef UINT128_PARSE_ERROR 32 # define UINT128_PARSE_ERROR(...) std::abort() 33 # endif 34 35 using namespace js; 36 37 // Simple Uint128 parser. 38 template <char... DIGITS> 39 constexpr Uint128 operator""_u128() { 40 static_assert(sizeof...(DIGITS) > 0); 41 42 constexpr auto digits = std::array{DIGITS...}; 43 44 constexpr auto isBinaryDigit = [](auto c) { 45 return (c >= '0' && c <= '1') || c == '\''; 46 }; 47 48 constexpr auto isOctalDigit = [](auto c) { 49 return (c >= '0' && c <= '7') || c == '\''; 50 }; 51 52 constexpr auto isDigit = [](auto c) { 53 return mozilla::IsAsciiDigit(c) || c == '\''; 54 }; 55 56 constexpr auto isHexDigit = [](auto c) { 57 return mozilla::IsAsciiHexDigit(c) || c == '\''; 58 }; 59 60 constexpr auto isBinary = [isBinaryDigit](auto zero, auto prefix, 61 auto... rest) { 62 return zero == '0' && (prefix == 'b' || prefix == 'B') && 63 (isBinaryDigit(rest) && ...); 64 }; 65 66 constexpr auto isHex = [isHexDigit](auto zero, auto prefix, auto... rest) { 67 return zero == '0' && (prefix == 'x' || prefix == 'X') && 68 (isHexDigit(rest) && ...); 69 }; 70 71 constexpr auto binary = [digits]() -> std::optional<Uint128> { 72 auto value = Uint128{}; 73 for (size_t i = 2; i < digits.size(); ++i) { 74 auto digit = digits[i]; 75 if (digit == '\'') { 76 continue; 77 } 78 79 // Detect overflow. 80 if (((value << 1) >> 1) != value) { 81 return std::nullopt; 82 } 83 value = (value << 1) | Uint128{uint64_t(digit - '0')}; 84 } 85 return value; 86 }; 87 88 constexpr auto octal = [digits]() -> std::optional<Uint128> { 89 auto value = Uint128{}; 90 for (size_t i = 1; i < digits.size(); ++i) { 91 auto digit = digits[i]; 92 if (digit == '\'') { 93 continue; 94 } 95 96 // Detect overflow. 97 if (((value << 3) >> 3) != value) { 98 return std::nullopt; 99 } 100 value = (value << 3) | Uint128{uint64_t(digit - '0')}; 101 } 102 return value; 103 }; 104 105 constexpr auto decimal = [digits]() -> std::optional<Uint128> { 106 auto value = Uint128{}; 107 for (size_t i = 0; i < digits.size(); ++i) { 108 auto digit = digits[i]; 109 if (digit == '\'') { 110 continue; 111 } 112 113 // NB: Overflow check not implemented. 114 value = (value * Uint128{10}) + Uint128{uint64_t(digit - '0')}; 115 } 116 return value; 117 }; 118 119 constexpr auto hexadecimal = [digits]() -> std::optional<Uint128> { 120 auto value = Uint128{}; 121 for (size_t i = 2; i < digits.size(); ++i) { 122 auto digit = digits[i]; 123 if (digit == '\'') { 124 continue; 125 } 126 127 // Detect overflow. 128 if (((value << 4) >> 4) != value) { 129 return std::nullopt; 130 } 131 value = 132 (value << 4) | Uint128{uint64_t(digit >= 'a' ? (digit - 'a') + 10 133 : digit >= 'A' ? (digit - 'A') + 10 134 : digit - '0')}; 135 } 136 return value; 137 }; 138 139 if constexpr (digits.size() > 2 && digits[0] == '0' && 140 !mozilla::IsAsciiDigit(digits[1])) { 141 if constexpr (isBinary(DIGITS...)) { 142 if constexpr (constexpr auto value = binary()) { 143 return *value; 144 } else { 145 UINT128_PARSE_ERROR("binary literal too large"); 146 } 147 } else if constexpr (isHex(DIGITS...)) { 148 if constexpr (constexpr auto value = hexadecimal()) { 149 return *value; 150 } else { 151 UINT128_PARSE_ERROR("hexadecimal literal too large"); 152 } 153 } else { 154 UINT128_PARSE_ERROR("invalid prefix literal"); 155 } 156 } else if constexpr (digits.size() > 1 && digits[0] == '0') { 157 if constexpr ((isOctalDigit(DIGITS) && ...)) { 158 if constexpr (constexpr auto value = octal()) { 159 return *value; 160 } else { 161 UINT128_PARSE_ERROR("octal literal too large"); 162 } 163 } else { 164 UINT128_PARSE_ERROR("invalid octal literal"); 165 } 166 } else if constexpr ((isDigit(DIGITS) && ...)) { 167 if constexpr (constexpr auto value = decimal()) { 168 return *value; 169 } else { 170 UINT128_PARSE_ERROR("decimal literal too large"); 171 } 172 } else { 173 UINT128_PARSE_ERROR("invalid literal"); 174 } 175 } 176 177 template <char... DIGITS> 178 constexpr Int128 operator""_i128() { 179 return Int128{operator""_u128 < DIGITS...>()}; 180 } 181 182 class ConversionFixture : public JSAPIRuntimeTest { 183 public: 184 virtual ~ConversionFixture() = default; 185 186 template <typename T, typename U, size_t N> 187 bool testConversion(const std::array<U, N>& values); 188 }; 189 190 template <typename T, typename U, size_t N> 191 bool ConversionFixture::testConversion(const std::array<U, N>& values) { 192 for (auto v : values) { 193 // Conversion to signed int. 194 CHECK_EQUAL(int64_t(T{v}), int64_t(v)); 195 CHECK_EQUAL(int32_t(T{v}), int32_t(v)); 196 CHECK_EQUAL(int16_t(T{v}), int16_t(v)); 197 CHECK_EQUAL(int8_t(T{v}), int8_t(v)); 198 199 // Conversion to unsigned int. 200 CHECK_EQUAL(uint64_t(T{v}), uint64_t(v)); 201 CHECK_EQUAL(uint32_t(T{v}), uint32_t(v)); 202 CHECK_EQUAL(uint16_t(T{v}), uint16_t(v)); 203 CHECK_EQUAL(uint8_t(T{v}), uint8_t(v)); 204 205 // Conversion to double. 206 CHECK_EQUAL(double(T{v}), double(v)); 207 208 // Conversion to bool. 209 CHECK_EQUAL(bool(T{v}), bool(v)); 210 } 211 return true; 212 } 213 214 BEGIN_FIXTURE_TEST(ConversionFixture, testInt128_conversion) { 215 auto values = std::array{ 216 INT64_MIN, 217 INT64_MIN + 1, 218 int64_t(INT32_MIN) - 1, 219 int64_t(INT32_MIN), 220 int64_t(INT32_MIN) + 1, 221 int64_t(-1), 222 int64_t(0), 223 int64_t(1), 224 int64_t(INT32_MAX) - 1, 225 int64_t(INT32_MAX), 226 int64_t(INT32_MAX) + 1, 227 INT64_MAX - 1, 228 INT64_MAX, 229 }; 230 231 CHECK(testConversion<Int128>(values)); 232 233 return true; 234 } 235 END_FIXTURE_TEST(ConversionFixture, testInt128_conversion) 236 237 BEGIN_FIXTURE_TEST(ConversionFixture, testUint128_conversion) { 238 auto values = std::array{ 239 uint64_t(0), 240 uint64_t(1), 241 uint64_t(UINT32_MAX) - 1, 242 uint64_t(UINT32_MAX), 243 uint64_t(UINT32_MAX) + 1, 244 UINT64_MAX - 1, 245 UINT64_MAX, 246 }; 247 248 CHECK(testConversion<Uint128>(values)); 249 250 return true; 251 } 252 END_FIXTURE_TEST(ConversionFixture, testUint128_conversion) 253 254 class OperatorFixture : public JSAPIRuntimeTest { 255 public: 256 virtual ~OperatorFixture() = default; 257 258 template <typename T, typename U, size_t N> 259 bool testOperator(const std::array<U, N>& values); 260 }; 261 262 template <typename T, typename U, size_t N> 263 bool OperatorFixture::testOperator(const std::array<U, N>& values) { 264 // Unary operators. 265 for (auto x : values) { 266 // Sign operators. 267 CHECK_EQUAL(U(+T{x}), +x); 268 CHECK_EQUAL(U(-T{x}), -x); 269 270 // Bitwise operators. 271 CHECK_EQUAL(U(~T{x}), ~x); 272 273 // Increment/Decrement operators. 274 auto y = T{x}; 275 CHECK_EQUAL(U(++y), x + 1); 276 CHECK_EQUAL(U(y), x + 1); 277 278 y = T{x}; 279 CHECK_EQUAL(U(y++), x); 280 CHECK_EQUAL(U(y), x + 1); 281 282 y = T{x}; 283 CHECK_EQUAL(U(--y), x - 1); 284 CHECK_EQUAL(U(y), x - 1); 285 286 y = T{x}; 287 CHECK_EQUAL(U(y--), x); 288 CHECK_EQUAL(U(y), x - 1); 289 } 290 291 // Binary operators. 292 for (auto x : values) { 293 for (auto y : values) { 294 // Comparison operators. 295 CHECK_EQUAL((T{x} == T{y}), (x == y)); 296 CHECK_EQUAL((T{x} != T{y}), (x != y)); 297 CHECK_EQUAL((T{x} < T{y}), (x < y)); 298 CHECK_EQUAL((T{x} <= T{y}), (x <= y)); 299 CHECK_EQUAL((T{x} > T{y}), (x > y)); 300 CHECK_EQUAL((T{x} >= T{y}), (x >= y)); 301 302 // Add/Sub/Mul operators. 303 CHECK_EQUAL(U(T{x} + T{y}), (x + y)); 304 CHECK_EQUAL(U(T{x} - T{y}), (x - y)); 305 CHECK_EQUAL(U(T{x} * T{y}), (x * y)); 306 307 // Division operators. 308 if (y != 0) { 309 CHECK_EQUAL(U(T{x} / T{y}), (x / y)); 310 CHECK_EQUAL(U(T{x} % T{y}), (x % y)); 311 } 312 313 // Shift operators. 314 if (y >= 0) { 315 CHECK_EQUAL(U(T{x} << y), (x << y)); 316 CHECK_EQUAL(U(T{x} >> y), (x >> y)); 317 } 318 319 // Bitwise operators. 320 CHECK_EQUAL(U(T{x} & T{y}), (x & y)); 321 CHECK_EQUAL(U(T{x} | T{y}), (x | y)); 322 CHECK_EQUAL(U(T{x} ^ T{y}), (x ^ y)); 323 } 324 } 325 326 // Compound assignment operators. 327 for (auto x : values) { 328 for (auto y : values) { 329 auto z = T{x}; 330 z += T{y}; 331 CHECK_EQUAL(U(z), x + y); 332 333 z = T{x}; 334 z -= T{y}; 335 CHECK_EQUAL(U(z), x - y); 336 337 z = T{x}; 338 z *= T{y}; 339 CHECK_EQUAL(U(z), x * y); 340 341 if (y != 0) { 342 z = T{x}; 343 z /= T{y}; 344 CHECK_EQUAL(U(z), x / y); 345 346 z = T{x}; 347 z %= T{y}; 348 CHECK_EQUAL(U(z), x % y); 349 } 350 351 if (y >= 0) { 352 z = T{x}; 353 z <<= y; 354 CHECK_EQUAL(U(z), x << y); 355 356 z = T{x}; 357 z >>= y; 358 CHECK_EQUAL(U(z), x >> y); 359 } 360 361 z = T{x}; 362 z &= T{y}; 363 CHECK_EQUAL(U(z), x & y); 364 365 z = T{x}; 366 z |= T{y}; 367 CHECK_EQUAL(U(z), x | y); 368 369 z = T{x}; 370 z ^= T{y}; 371 CHECK_EQUAL(U(z), x ^ y); 372 } 373 } 374 return true; 375 } 376 377 BEGIN_FIXTURE_TEST(OperatorFixture, testInt128_operator) { 378 auto values = std::array{ 379 int64_t(-3), int64_t(-2), int64_t(-1), int64_t(0), 380 int64_t(1), int64_t(2), int64_t(3), int64_t(63), 381 }; 382 383 CHECK(testOperator<Int128>(values)); 384 385 // Values larger than INT64_MAX. 386 CHECK((Int128{INT64_MAX} * Int128{2}) == 387 (Int128{INT64_MAX} + Int128{INT64_MAX})); 388 CHECK((Int128{INT64_MAX} * Int128{3}) == 389 (Int128{INT64_MAX} * Int128{4} - Int128{INT64_MAX})); 390 CHECK((Int128{INT64_MAX} * Int128{2}) == (Int128{INT64_MAX} << 1)); 391 CHECK((Int128{INT64_MAX} * Int128{8}) == (Int128{INT64_MAX} << 3)); 392 CHECK((Int128{INT64_MAX} * Int128{8} / Int128{2}) == 393 (Int128{INT64_MAX} << 2)); 394 CHECK((Int128{INT64_MAX} * Int128{23} % Int128{13}) == (Int128{5})); 395 396 // Values smaller than INT64_MIN. 397 CHECK((Int128{INT64_MIN} * Int128{2}) == 398 (Int128{INT64_MIN} + Int128{INT64_MIN})); 399 CHECK((Int128{INT64_MIN} * Int128{3}) == 400 (Int128{INT64_MIN} * Int128{4} - Int128{INT64_MIN})); 401 CHECK((Int128{INT64_MIN} * Int128{2}) == (Int128{INT64_MIN} << 1)); 402 CHECK((Int128{INT64_MIN} * Int128{8}) == (Int128{INT64_MIN} << 3)); 403 CHECK((Int128{INT64_MIN} * Int128{8} / Int128{2}) == 404 (Int128{INT64_MIN} << 2)); 405 CHECK((Int128{INT64_MIN} * Int128{23} % Int128{13}) == (Int128{-2})); 406 407 return true; 408 } 409 END_FIXTURE_TEST(OperatorFixture, testInt128_operator) 410 411 BEGIN_FIXTURE_TEST(OperatorFixture, testUint128_operator) { 412 auto values = std::array{ 413 uint64_t(0), uint64_t(1), uint64_t(2), 414 uint64_t(3), uint64_t(5), uint64_t(63), 415 }; 416 417 CHECK(testOperator<Uint128>(values)); 418 419 // Values larger than UINT64_MAX. 420 CHECK((Uint128{UINT64_MAX} * Uint128{2}) == 421 (Uint128{UINT64_MAX} + Uint128{UINT64_MAX})); 422 CHECK((Uint128{UINT64_MAX} * Uint128{3}) == 423 (Uint128{UINT64_MAX} * Uint128{4} - Uint128{UINT64_MAX})); 424 CHECK((Uint128{UINT64_MAX} * Uint128{2}) == (Uint128{UINT64_MAX} << 1)); 425 CHECK((Uint128{UINT64_MAX} * Uint128{8}) == (Uint128{UINT64_MAX} << 3)); 426 CHECK((Uint128{UINT64_MAX} * Uint128{8} / Uint128{2}) == 427 (Uint128{UINT64_MAX} << 2)); 428 CHECK((Uint128{UINT64_MAX} * Uint128{23} % Uint128{13}) == (Uint128{7})); 429 430 return true; 431 } 432 END_FIXTURE_TEST(OperatorFixture, testUint128_operator) 433 434 BEGIN_TEST(testInt128_literal) { 435 CHECK_EQUAL(int64_t(0x7fff'ffff'ffff'ffff_i128), INT64_MAX); 436 CHECK_EQUAL(int64_t(-0x8000'0000'0000'0000_i128), INT64_MIN); 437 438 CHECK(std::numeric_limits<Int128>::max() == 439 0x7fff'ffff'ffff'ffff'ffff'ffff'ffff'ffff_i128); 440 CHECK(std::numeric_limits<Int128>::min() == 441 -0x8000'0000'0000'0000'0000'0000'0000'0000_i128); 442 443 auto x = (Int128{INT64_MAX} + Int128{1}) * Int128{3}; 444 CHECK(x == 27670116110564327424_i128); 445 CHECK(x == 0x1'8000'0000'0000'0000_i128); 446 447 auto y = Int128{0} - (Int128{5} * Int128{INT64_MAX}); 448 CHECK(y == -46116860184273879035_i128); 449 CHECK(y == -0x2'7fff'ffff'ffff'fffb_i128); 450 451 // NB: This shift expression overflows. 452 auto z = Int128{0x1122'3344} << 100; 453 CHECK(z == 0x1223'3440'0000'0000'0000'0000'0000'0000_i128); 454 CHECK(z == 0221063210000000000000000000000000000000000_i128); 455 CHECK(z == 24108894070078995479046745700448600064_i128); 456 CHECK( 457 z == 458 0b10010001000110011010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_i128); 459 460 z >>= 80; 461 CHECK(z == 0X1223'3440'0000_i128); 462 CHECK(z == 0442146420000000_i128); 463 CHECK(z == 19942409764864_i128); 464 CHECK(z == 0B100100010001100110100010000000000000000000000_i128); 465 466 auto v = Int128{INT64_MAX} * Int128{INT64_MAX}; 467 CHECK(v == 0x3fff'ffff'ffff'ffff'0000'0000'0000'0001_i128); 468 CHECK((v + v) == 0x7fff'ffff'ffff'fffe'0000'0000'0000'0002_i128); 469 CHECK((v * v) == 0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128); 470 CHECK((v * -v) == -0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128); 471 CHECK((-v * v) == -0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128); 472 CHECK((-v * -v) == 0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128); 473 474 auto w = Int128{INT64_MIN} * Int128{INT64_MIN}; 475 CHECK(w == 0x4000'0000'0000'0000'0000'0000'0000'0000_i128); 476 CHECK((w + w) == -0x8000'0000'0000'0000'0000'0000'0000'0000_i128); 477 CHECK((w * w) == 0_i128); 478 479 CHECK((Int128{1} << 120) == 0x100'0000'0000'0000'0000'0000'0000'0000_i128); 480 481 return true; 482 } 483 END_TEST(testInt128_literal) 484 485 BEGIN_TEST(testUint128_literal) { 486 CHECK_EQUAL(uint64_t(0xffff'ffff'ffff'ffff_u128), UINT64_MAX); 487 488 CHECK(std::numeric_limits<Uint128>::max() == 489 0xffff'ffff'ffff'ffff'ffff'ffff'ffff'ffff_u128); 490 491 auto x = (Uint128{UINT64_MAX} + Uint128{3}) * Uint128{3}; 492 CHECK(x == 55340232221128654854_u128); 493 CHECK(x == 0x3'0000'0000'0000'0006_u128); 494 495 // NB: This shift expression overflows. 496 auto z = Uint128{0x1122'3344} << 100; 497 CHECK(z == 0x1223'3440'0000'0000'0000'0000'0000'0000_u128); 498 CHECK(z == 0221063210000000000000000000000000000000000_u128); 499 CHECK(z == 24108894070078995479046745700448600064_u128); 500 CHECK( 501 z == 502 0b10010001000110011010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128); 503 504 z >>= 80; 505 CHECK(z == 0X1223'3440'0000_u128); 506 CHECK(z == 0442146420000000_u128); 507 CHECK(z == 19942409764864_u128); 508 CHECK(z == 0B100100010001100110100010000000000000000000000_u128); 509 510 auto v = Uint128{UINT64_MAX} * Uint128{UINT64_MAX}; 511 CHECK(v == 0xffff'ffff'ffff'fffe'0000'0000'0000'0001_u128); 512 CHECK((v + v) == 0xffff'ffff'ffff'fffc'0000'0000'0000'0002_u128); 513 CHECK((v * v) == 0xffff'ffff'ffff'fffc'0000'0000'0000'0001_u128); 514 CHECK((v * -v) == 0x3'ffff'ffff'ffff'ffff_u128); 515 CHECK((-v * v) == 0x3'ffff'ffff'ffff'ffff_u128); 516 CHECK((-v * -v) == 0xffff'ffff'ffff'fffc'0000'0000'0000'0001_u128); 517 518 CHECK((Uint128{1} << 120) == 0x100'0000'0000'0000'0000'0000'0000'0000_u128); 519 520 return true; 521 } 522 END_TEST(testUint128_literal) 523 524 BEGIN_TEST(testInt128_division) { 525 auto x = Int128{INT64_MAX} * Int128{4}; 526 CHECK((x / Int128{2}) == 0xffff'ffff'ffff'fffe_i128); 527 CHECK((x / Int128{2}) == (x >> 1)); 528 529 auto y = Int128{INT64_MAX} * Int128{16}; 530 CHECK((y / Int128{2}) == 0x3'ffff'ffff'ffff'fff8_i128); 531 CHECK((y / Int128{2}) == (y >> 1)); 532 533 CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 / 7_i128) == 534 0x272'999c'0c33'35a5'cf3f'6668'db4b'be55_i128); 535 CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 / 536 0x1'2345'6789'abcd'ef11'abcd'ef11_i128) == 0xf0f0f0f_i128); 537 CHECK((7_i128 / 0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128) == 0_i128); 538 539 CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 % 7_i128) == 3_i128); 540 CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 % 541 0x1'2345'6789'abcd'ef11'abcd'ef11_i128) == 542 0x1122'3353'7d8e'9fb0'dc00'3357_i128); 543 CHECK((7_i128 % 0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128) == 7_i128); 544 545 return true; 546 } 547 END_TEST(testInt128_division) 548 549 BEGIN_TEST(testInt128_abs) { 550 CHECK((0_i128).abs() == 0_u128); 551 552 CHECK((0x1122'3344_i128).abs() == 0x1122'3344_u128); 553 CHECK((-0x1122'3344_i128).abs() == 0x1122'3344_u128); 554 555 CHECK((0x1111'2222'3333'4444'5555'6666'7777'8888_i128).abs() == 556 0x1111'2222'3333'4444'5555'6666'7777'8888_u128); 557 CHECK((-0x1111'2222'3333'4444'5555'6666'7777'8888_i128).abs() == 558 0x1111'2222'3333'4444'5555'6666'7777'8888_u128); 559 560 CHECK(std::numeric_limits<Int128>::min().abs() == 561 0x8000'0000'0000'0000'0000'0000'0000'0000_u128); 562 CHECK(std::numeric_limits<Int128>::max().abs() == 563 0x7fff'ffff'ffff'ffff'ffff'ffff'ffff'ffff_u128); 564 565 return true; 566 } 567 END_TEST(testInt128_abs) 568 569 #endif