| /* | |
| * Copyright 2016 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <cassert> | |
| #include <cmath> | |
| #include <limits> | |
| #include "support/safe_integer.h" | |
| using namespace wasm; | |
| bool wasm::isInteger(double x) { return trunc(x) == x && !std::isinf(x); } | |
| bool wasm::isUInteger32(double x) { | |
| return !std::signbit(x) && isInteger(x) && | |
| x <= std::numeric_limits<uint32_t>::max(); | |
| } | |
| bool wasm::isSInteger32(double x) { | |
| return isInteger(x) && x >= std::numeric_limits<int32_t>::min() && | |
| x <= std::numeric_limits<int32_t>::max(); | |
| } | |
| uint32_t wasm::toUInteger32(double x) { | |
| return std::signbit(x) ? 0 | |
| : (x < std::numeric_limits<uint32_t>::max() | |
| ? (uint32_t)x | |
| : std::numeric_limits<uint32_t>::max()); | |
| } | |
| int32_t wasm::toSInteger32(double x) { | |
| return (x > std::numeric_limits<int32_t>::min() && | |
| x < std::numeric_limits<int32_t>::max()) | |
| ? (int32_t)x | |
| : (std::signbit(x) ? std::numeric_limits<int32_t>::min() | |
| : std::numeric_limits<int32_t>::max()); | |
| } | |
| bool wasm::isUInteger64(double x) { | |
| return !std::signbit(x) && isInteger(x) && | |
| x <= static_cast<double>(std::numeric_limits<uint64_t>::max()); | |
| } | |
| bool wasm::isSInteger64(double x) { | |
| return isInteger(x) && x >= std::numeric_limits<int64_t>::min() && | |
| x <= static_cast<double>(std::numeric_limits<int64_t>::max()); | |
| } | |
| uint64_t wasm::toUInteger64(double x) { | |
| return std::signbit(x) ? 0 | |
| : (x < (double)std::numeric_limits<uint64_t>::max() | |
| ? (uint64_t)x | |
| : std::numeric_limits<uint64_t>::max()); | |
| } | |
| int64_t wasm::toSInteger64(double x) { | |
| return (x > (double)std::numeric_limits<int64_t>::min() && | |
| x < (double)std::numeric_limits<int64_t>::max()) | |
| ? (int64_t)x | |
| : (std::signbit(x) ? std::numeric_limits<int64_t>::min() | |
| : std::numeric_limits<int64_t>::max()); | |
| } | |
| /* 3 32222222 222...00 | |
| * 1 09876543 210...10 | |
| * ------------------- | |
| * 0 00000000 000...00 => 0x00000000 => 0 | |
| * 0 10011101 111...11 => 0x4effffff => 2147483520 (~INT32_MAX) | |
| * 0 10011110 000...00 => 0x4f000000 => 2147483648 | |
| * 0 10011110 111...11 => 0x4f7fffff => 4294967040 (~UINT32_MAX) | |
| * 0 10111110 111...11 => 0x5effffff => 9223371487098961920 (~INT64_MAX) | |
| * 0 10111110 000...00 => 0x5f000000 => 9223372036854775808 | |
| * 0 10111111 111...11 => 0x5f7fffff => 18446742974197923840 (~UINT64_MAX) | |
| * 0 10111111 000...00 => 0x5f800000 => 18446744073709551616 | |
| * 0 11111111 000...00 => 0x7f800000 => inf | |
| * 0 11111111 000...01 => 0x7f800001 => nan(0x1) | |
| * 0 11111111 111...11 => 0x7fffffff => nan(0x7fffff) | |
| * 1 00000000 000...00 => 0x80000000 => -0 | |
| * 1 01111110 111...11 => 0xbf7fffff => -1 + ulp (~UINT32_MIN, ~UINT64_MIN) | |
| * 1 01111111 000...00 => 0xbf800000 => -1 | |
| * 1 10011110 000...00 => 0xcf000000 => -2147483648 (INT32_MIN) | |
| * 1 10111110 000...00 => 0xdf000000 => -9223372036854775808 (INT64_MIN) | |
| * 1 11111111 000...00 => 0xff800000 => -inf | |
| * 1 11111111 000...01 => 0xff800001 => -nan(0x1) | |
| * 1 11111111 111...11 => 0xffffffff => -nan(0x7fffff) | |
| */ | |
| bool wasm::isInRangeI16TruncS(int32_t i) { | |
| uint32_t u = i; | |
| return (u < 0x47000000U) || (u >= 0x80000000U && u <= 0xc7000000U); | |
| } | |
| bool wasm::isInRangeI32TruncS(int32_t i) { | |
| uint32_t u = i; | |
| return (u < 0x4f000000U) || (u >= 0x80000000U && u <= 0xcf000000U); | |
| } | |
| bool wasm::isInRangeI64TruncS(int32_t i) { | |
| uint32_t u = i; | |
| return (u < 0x5f000000U) || (u >= 0x80000000U && u <= 0xdf000000U); | |
| } | |
| bool wasm::isInRangeI16TruncU(int32_t i) { | |
| uint32_t u = i; | |
| return (u < 0x47800000) || (u >= 0x80000000U && u < 0xbf800000U); | |
| } | |
| bool wasm::isInRangeI32TruncU(int32_t i) { | |
| uint32_t u = i; | |
| return (u < 0x4f800000U) || (u >= 0x80000000U && u < 0xbf800000U); | |
| } | |
| bool wasm::isInRangeI64TruncU(int32_t i) { | |
| uint32_t u = i; | |
| return (u < 0x5f800000U) || (u >= 0x80000000U && u < 0xbf800000U); | |
| } | |
| /* clang-format off */ | |
| /* | |
| * 6 66655555555 5544...222221...000 | |
| * 3 21098765432 1098...432109...210 | |
| * --------------------------------- | |
| * 0 00000000000 0000...000000...000 0x0000000000000000 => 0 | |
| * 0 10000011101 1111...111000...111 0x41dfffffffffffff => 2147483647.9999998 (rounds down to INT32_MAX) | |
| * 0 10000011110 1111...111111...111 0x41efffffffffffff => 4294967295.9999995 (rounds down to UINT32_MAX) | |
| * 0 10000111101 1111...111111...111 0x43dfffffffffffff => 9223372036854774784 (~INT64_MAX) | |
| * 0 10000111110 0000...000000...000 0x43e0000000000000 => 9223372036854775808 | |
| * 0 10000111110 1111...111111...111 0x43efffffffffffff => 18446744073709549568 (~UINT64_MAX) | |
| * 0 10000111111 0000...000000...000 0x43f0000000000000 => 18446744073709551616 | |
| * 0 11111111111 0000...000000...000 0x7ff0000000000000 => inf | |
| * 0 11111111111 0000...000000...001 0x7ff0000000000001 => nan(0x1) | |
| * 0 11111111111 1111...111111...111 0x7fffffffffffffff => nan(0xfff...) | |
| * 1 00000000000 0000...000000...000 0x8000000000000000 => -0 | |
| * 1 01111111110 1111...111111...111 0xbfefffffffffffff => -1 + ulp (~UINT32_MIN, ~UINT64_MIN) | |
| * 1 01111111111 0000...000000...000 0xbff0000000000000 => -1 | |
| * 1 10000011110 0000...000000...111 0xc1e00000001fffff => -2147483648.9999995 (rounds up to INT32_MIN) | |
| * 1 10000111110 0000...000000...000 0xc3e0000000000000 => -9223372036854775808 (INT64_MIN) | |
| * 1 11111111111 0000...000000...000 0xfff0000000000000 => -inf | |
| * 1 11111111111 0000...000000...001 0xfff0000000000001 => -nan(0x1) | |
| * 1 11111111111 1111...111111...111 0xffffffffffffffff => -nan(0xfff...) | |
| */ | |
| /* clang-format on */ | |
| bool wasm::isInRangeI32TruncS(int64_t i) { | |
| uint64_t u = i; | |
| return (u <= 0x41dfffffffffffffULL) || | |
| (u >= 0x8000000000000000ULL && u <= 0xc1e00000001fffffULL); | |
| } | |
| bool wasm::isInRangeI32TruncU(int64_t i) { | |
| uint64_t u = i; | |
| return (u <= 0x41efffffffffffffULL) || | |
| (u >= 0x8000000000000000ULL && u <= 0xbfefffffffffffffULL); | |
| } | |
| bool wasm::isInRangeI64TruncS(int64_t i) { | |
| uint64_t u = i; | |
| return (u < 0x43e0000000000000ULL) || | |
| (u >= 0x8000000000000000ULL && u <= 0xc3e0000000000000ULL); | |
| } | |
| bool wasm::isInRangeI64TruncU(int64_t i) { | |
| uint64_t u = i; | |
| return (u < 0x43f0000000000000ULL) || | |
| (u >= 0x8000000000000000ULL && u <= 0xbfefffffffffffffULL); | |
| } |