1 // Copyright 2017 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 6 #define BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 7 8 // IWYU pragma: private 9 10 #include <stdint.h> 11 #include <limits> 12 #include <type_traits> 13 14 #include "base/numerics/safe_conversions.h" 15 16 #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__)) 17 #include "base/numerics/safe_math_arm_impl.h" // IWYU pragma: export 18 #define BASE_HAS_ASSEMBLER_SAFE_MATH (1) 19 #else 20 #define BASE_HAS_ASSEMBLER_SAFE_MATH (0) 21 #endif 22 23 namespace base { 24 namespace internal { 25 26 // These are the non-functioning boilerplate implementations of the optimized 27 // safe math routines. 28 #if !BASE_HAS_ASSEMBLER_SAFE_MATH 29 template <typename T, typename U> 30 struct CheckedMulFastAsmOp { 31 static const bool is_supported = false; 32 template <typename V> DoCheckedMulFastAsmOp33 static constexpr bool Do(T, U, V*) { 34 // Force a compile failure if instantiated. 35 return CheckOnFailure::template HandleFailure<bool>(); 36 } 37 }; 38 39 template <typename T, typename U> 40 struct ClampedAddFastAsmOp { 41 static const bool is_supported = false; 42 template <typename V> DoClampedAddFastAsmOp43 static constexpr V Do(T, U) { 44 // Force a compile failure if instantiated. 45 return CheckOnFailure::template HandleFailure<V>(); 46 } 47 }; 48 49 template <typename T, typename U> 50 struct ClampedSubFastAsmOp { 51 static const bool is_supported = false; 52 template <typename V> DoClampedSubFastAsmOp53 static constexpr V Do(T, U) { 54 // Force a compile failure if instantiated. 55 return CheckOnFailure::template HandleFailure<V>(); 56 } 57 }; 58 59 template <typename T, typename U> 60 struct ClampedMulFastAsmOp { 61 static const bool is_supported = false; 62 template <typename V> DoClampedMulFastAsmOp63 static constexpr V Do(T, U) { 64 // Force a compile failure if instantiated. 65 return CheckOnFailure::template HandleFailure<V>(); 66 } 67 }; 68 #endif // BASE_HAS_ASSEMBLER_SAFE_MATH 69 #undef BASE_HAS_ASSEMBLER_SAFE_MATH 70 71 template <typename T, typename U> 72 struct CheckedAddFastOp { 73 static const bool is_supported = true; 74 template <typename V> DoCheckedAddFastOp75 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 76 return !__builtin_add_overflow(x, y, result); 77 } 78 }; 79 80 template <typename T, typename U> 81 struct CheckedSubFastOp { 82 static const bool is_supported = true; 83 template <typename V> DoCheckedSubFastOp84 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 85 return !__builtin_sub_overflow(x, y, result); 86 } 87 }; 88 89 template <typename T, typename U> 90 struct CheckedMulFastOp { 91 #if defined(__clang__) 92 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can 93 // support full-width, mixed-sign multiply builtins. 94 // https://crbug.com/613003 95 // We can support intptr_t, uintptr_t, or a smaller common type. 96 static const bool is_supported = 97 (kIsTypeInRangeForNumericType<intptr_t, T> && 98 kIsTypeInRangeForNumericType<intptr_t, U>) || 99 (kIsTypeInRangeForNumericType<uintptr_t, T> && 100 kIsTypeInRangeForNumericType<uintptr_t, U>); 101 #else 102 static const bool is_supported = true; 103 #endif 104 template <typename V> DoCheckedMulFastOp105 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 106 return CheckedMulFastAsmOp<T, U>::is_supported 107 ? CheckedMulFastAsmOp<T, U>::Do(x, y, result) 108 : !__builtin_mul_overflow(x, y, result); 109 } 110 }; 111 112 template <typename T, typename U> 113 struct ClampedAddFastOp { 114 static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported; 115 template <typename V> DoClampedAddFastOp116 __attribute__((always_inline)) static V Do(T x, U y) { 117 return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); 118 } 119 }; 120 121 template <typename T, typename U> 122 struct ClampedSubFastOp { 123 static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported; 124 template <typename V> DoClampedSubFastOp125 __attribute__((always_inline)) static V Do(T x, U y) { 126 return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); 127 } 128 }; 129 130 template <typename T, typename U> 131 struct ClampedMulFastOp { 132 static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported; 133 template <typename V> DoClampedMulFastOp134 __attribute__((always_inline)) static V Do(T x, U y) { 135 return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); 136 } 137 }; 138 139 template <typename T> 140 struct ClampedNegFastOp { 141 static const bool is_supported = std::is_signed_v<T>; DoClampedNegFastOp142 __attribute__((always_inline)) static T Do(T value) { 143 // Use this when there is no assembler path available. 144 if (!ClampedSubFastAsmOp<T, T>::is_supported) { 145 T result; 146 return !__builtin_sub_overflow(T(0), value, &result) 147 ? result 148 : std::numeric_limits<T>::max(); 149 } 150 151 // Fallback to the normal subtraction path. 152 return ClampedSubFastOp<T, T>::template Do<T>(T(0), value); 153 } 154 }; 155 156 } // namespace internal 157 } // namespace base 158 159 #endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 160