Line data Source code
1 : #pragma once 2 : 3 : #include <c10/macros/Macros.h> 4 : #include <c10/util/TypeSafeSignMath.h> 5 : #include <c10/util/complex.h> 6 : 7 : #include <cmath> 8 : #include <limits> 9 : #include <type_traits> 10 : 11 : namespace c10 { 12 : // In some versions of MSVC, there will be a compiler error when building. 13 : // C4146: unary minus operator applied to unsigned type, result still unsigned 14 : // C4804: unsafe use of type 'bool' in operation 15 : // It can be addressed by disabling the following warning. 16 : #ifdef _MSC_VER 17 : #pragma warning(push) 18 : #pragma warning(disable : 4146) 19 : #pragma warning(disable : 4804) 20 : #pragma warning(disable : 4018) 21 : #endif 22 : 23 : // The overflow checks may involve float to int conversion which may 24 : // trigger precision loss warning. Re-enable the warning once the code 25 : // is fixed. See T58053069. 26 : C10_CLANG_DIAGNOSTIC_PUSH() 27 : #if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion") 28 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion") 29 : #endif 30 : 31 : // bool can be converted to any type. 32 : // Without specializing on bool, in pytorch_linux_trusty_py2_7_9_build: 33 : // `error: comparison of constant '255' with boolean expression is always false` 34 : // for `f > limit::max()` below 35 : template <typename To, typename From> 36 0 : std::enable_if_t<std::is_same_v<From, bool>, bool> overflows( 37 : From /*f*/, 38 : bool strict_unsigned [[maybe_unused]] = false) { 39 0 : return false; 40 : } 41 : 42 : // skip isnan and isinf check for integral types 43 : template <typename To, typename From> 44 : std::enable_if_t<std::is_integral_v<From> && !std::is_same_v<From, bool>, bool> 45 0 : overflows(From f, bool strict_unsigned = false) { 46 : using limit = std::numeric_limits<typename scalar_value_type<To>::type>; 47 : if constexpr (!limit::is_signed && std::numeric_limits<From>::is_signed) { 48 : // allow for negative numbers to wrap using two's complement arithmetic. 49 : // For example, with uint8, this allows for `a - b` to be treated as 50 : // `a + 255 * b`. 51 0 : if (!strict_unsigned) { 52 0 : return greater_than_max<To>(f) || 53 0 : (c10::is_negative(f) && 54 0 : -static_cast<uint64_t>(f) > static_cast<uint64_t>(limit::max())); 55 : } 56 : } 57 0 : return c10::less_than_lowest<To>(f) || greater_than_max<To>(f); 58 : } 59 : 60 : template <typename To, typename From> 61 0 : std::enable_if_t<std::is_floating_point_v<From>, bool> overflows( 62 : From f, 63 : bool strict_unsigned [[maybe_unused]] = false) { 64 : using limit = std::numeric_limits<typename scalar_value_type<To>::type>; 65 0 : if (limit::has_infinity && std::isinf(static_cast<double>(f))) { 66 : return false; 67 : } 68 0 : if (!limit::has_quiet_NaN && (f != f)) { 69 : return true; 70 : } 71 0 : return f < limit::lowest() || f > limit::max(); 72 : } 73 : 74 : C10_CLANG_DIAGNOSTIC_POP() 75 : 76 : #ifdef _MSC_VER 77 : #pragma warning(pop) 78 : #endif 79 : 80 : template <typename To, typename From> 81 0 : std::enable_if_t<is_complex<From>::value, bool> overflows( 82 : From f, 83 : bool strict_unsigned = false) { 84 : // casts from complex to real are considered to overflow if the 85 : // imaginary component is non-zero 86 0 : if (!is_complex<To>::value && f.imag() != 0) { 87 : return true; 88 : } 89 : // Check for overflow componentwise 90 : // (Technically, the imag overflow check is guaranteed to be false 91 : // when !is_complex<To>, but any optimizer worth its salt will be 92 : // able to figure it out.) 93 : return overflows< 94 : typename scalar_value_type<To>::type, 95 0 : typename From::value_type>(f.real(), strict_unsigned) || 96 : overflows< 97 : typename scalar_value_type<To>::type, 98 0 : typename From::value_type>(f.imag(), strict_unsigned); 99 : } 100 : } // namespace c10