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