1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 #include <cassert> 9 #include <limits> 10 #include <type_traits> 11 12 #include "base/numerics/safe_conversions.h" 13 14 #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__)) 15 #include "base/numerics/safe_math_arm_impl.h" 16 #define BASE_HAS_ASSEMBLER_SAFE_MATH (1) 17 #else 18 #define BASE_HAS_ASSEMBLER_SAFE_MATH (0) 19 #endif 20 21 namespace base { 22 namespace internal { 23 24 // These are the non-functioning boilerplate implementations of the optimized 25 // safe math routines. 26 #if !BASE_HAS_ASSEMBLER_SAFE_MATH 27 template <typename T, typename U> 28 struct CheckedMulFastAsmOp { 29 static const bool is_supported = false; 30 template <typename V> DoCheckedMulFastAsmOp31 static constexpr bool Do(T, U, V*) { 32 // Force a compile failure if instantiated. 33 return CheckOnFailure::template HandleFailure<bool>(); 34 } 35 }; 36 37 template <typename T, typename U> 38 struct ClampedAddFastAsmOp { 39 static const bool is_supported = false; 40 template <typename V> DoClampedAddFastAsmOp41 static constexpr V Do(T, U) { 42 // Force a compile failure if instantiated. 43 return CheckOnFailure::template HandleFailure<V>(); 44 } 45 }; 46 47 template <typename T, typename U> 48 struct ClampedSubFastAsmOp { 49 static const bool is_supported = false; 50 template <typename V> DoClampedSubFastAsmOp51 static constexpr V Do(T, U) { 52 // Force a compile failure if instantiated. 53 return CheckOnFailure::template HandleFailure<V>(); 54 } 55 }; 56 57 template <typename T, typename U> 58 struct ClampedMulFastAsmOp { 59 static const bool is_supported = false; 60 template <typename V> DoClampedMulFastAsmOp61 static constexpr V Do(T, U) { 62 // Force a compile failure if instantiated. 63 return CheckOnFailure::template HandleFailure<V>(); 64 } 65 }; 66 #endif // BASE_HAS_ASSEMBLER_SAFE_MATH 67 #undef BASE_HAS_ASSEMBLER_SAFE_MATH 68 69 template <typename T, typename U> 70 struct CheckedAddFastOp { 71 static const bool is_supported = true; 72 template <typename V> DoCheckedAddFastOp73 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 74 return !__builtin_add_overflow(x, y, result); 75 } 76 }; 77 78 template <typename T, typename U> 79 struct CheckedSubFastOp { 80 static const bool is_supported = true; 81 template <typename V> DoCheckedSubFastOp82 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 83 return !__builtin_sub_overflow(x, y, result); 84 } 85 }; 86 87 template <typename T, typename U> 88 struct CheckedMulFastOp { 89 #if defined(__clang__) 90 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can 91 // support full-width, mixed-sign multiply builtins. 92 // https://crbug.com/613003 93 // We can support intptr_t, uintptr_t, or a smaller common type. 94 static const bool is_supported = 95 (IsTypeInRangeForNumericType<intptr_t, T>::value && 96 IsTypeInRangeForNumericType<intptr_t, U>::value) || 97 (IsTypeInRangeForNumericType<uintptr_t, T>::value && 98 IsTypeInRangeForNumericType<uintptr_t, U>::value); 99 #else 100 static const bool is_supported = true; 101 #endif 102 template <typename V> DoCheckedMulFastOp103 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 104 return CheckedMulFastAsmOp<T, U>::is_supported 105 ? CheckedMulFastAsmOp<T, U>::Do(x, y, result) 106 : !__builtin_mul_overflow(x, y, result); 107 } 108 }; 109 110 template <typename T, typename U> 111 struct ClampedAddFastOp { 112 static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported; 113 template <typename V> DoClampedAddFastOp114 __attribute__((always_inline)) static V Do(T x, U y) { 115 return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); 116 } 117 }; 118 119 template <typename T, typename U> 120 struct ClampedSubFastOp { 121 static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported; 122 template <typename V> DoClampedSubFastOp123 __attribute__((always_inline)) static V Do(T x, U y) { 124 return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); 125 } 126 }; 127 128 template <typename T, typename U> 129 struct ClampedMulFastOp { 130 static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported; 131 template <typename V> DoClampedMulFastOp132 __attribute__((always_inline)) static V Do(T x, U y) { 133 return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); 134 } 135 }; 136 137 template <typename T> 138 struct ClampedNegFastOp { 139 static const bool is_supported = std::is_signed<T>::value; DoClampedNegFastOp140 __attribute__((always_inline)) static T Do(T value) { 141 // Use this when there is no assembler path available. 142 if (!ClampedSubFastAsmOp<T, T>::is_supported) { 143 T result; 144 return !__builtin_sub_overflow(T(0), value, &result) 145 ? result 146 : std::numeric_limits<T>::max(); 147 } 148 149 // Fallback to the normal subtraction path. 150 return ClampedSubFastOp<T, T>::template Do<T>(T(0), value); 151 } 152 }; 153 154 } // namespace internal 155 } // namespace base 156 157 #endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 158