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 #define BASE_HAS_ASSEMBLER_SAFE_MATH (0) 15 16 namespace base { 17 namespace internal { 18 19 // These are the non-functioning boilerplate implementations of the optimized 20 // safe math routines. 21 #if !BASE_HAS_ASSEMBLER_SAFE_MATH 22 template <typename T, typename U> 23 struct CheckedMulFastAsmOp { 24 static const bool is_supported = false; 25 template <typename V> DoCheckedMulFastAsmOp26 static constexpr bool Do(T, U, V*) { 27 // Force a compile failure if instantiated. 28 return CheckOnFailure::template HandleFailure<bool>(); 29 } 30 }; 31 32 template <typename T, typename U> 33 struct ClampedAddFastAsmOp { 34 static const bool is_supported = false; 35 template <typename V> DoClampedAddFastAsmOp36 static constexpr V Do(T, U) { 37 // Force a compile failure if instantiated. 38 return CheckOnFailure::template HandleFailure<V>(); 39 } 40 }; 41 42 template <typename T, typename U> 43 struct ClampedSubFastAsmOp { 44 static const bool is_supported = false; 45 template <typename V> DoClampedSubFastAsmOp46 static constexpr V Do(T, U) { 47 // Force a compile failure if instantiated. 48 return CheckOnFailure::template HandleFailure<V>(); 49 } 50 }; 51 52 template <typename T, typename U> 53 struct ClampedMulFastAsmOp { 54 static const bool is_supported = false; 55 template <typename V> DoClampedMulFastAsmOp56 static constexpr V Do(T, U) { 57 // Force a compile failure if instantiated. 58 return CheckOnFailure::template HandleFailure<V>(); 59 } 60 }; 61 #endif // BASE_HAS_ASSEMBLER_SAFE_MATH 62 #undef BASE_HAS_ASSEMBLER_SAFE_MATH 63 64 template <typename T, typename U> 65 struct CheckedAddFastOp { 66 static const bool is_supported = true; 67 template <typename V> DoCheckedAddFastOp68 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 69 return !__builtin_add_overflow(x, y, result); 70 } 71 }; 72 73 template <typename T, typename U> 74 struct CheckedSubFastOp { 75 static const bool is_supported = true; 76 template <typename V> DoCheckedSubFastOp77 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 78 return !__builtin_sub_overflow(x, y, result); 79 } 80 }; 81 82 template <typename T, typename U> 83 struct CheckedMulFastOp { 84 #if defined(__clang__) 85 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can 86 // support full-width, mixed-sign multiply builtins. 87 // https://crbug.com/613003 88 // We can support intptr_t, uintptr_t, or a smaller common type. 89 static const bool is_supported = 90 (IsTypeInRangeForNumericType<intptr_t, T>::value && 91 IsTypeInRangeForNumericType<intptr_t, U>::value) || 92 (IsTypeInRangeForNumericType<uintptr_t, T>::value && 93 IsTypeInRangeForNumericType<uintptr_t, U>::value); 94 #else 95 static const bool is_supported = true; 96 #endif 97 template <typename V> DoCheckedMulFastOp98 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 99 return CheckedMulFastAsmOp<T, U>::is_supported 100 ? CheckedMulFastAsmOp<T, U>::Do(x, y, result) 101 : !__builtin_mul_overflow(x, y, result); 102 } 103 }; 104 105 template <typename T, typename U> 106 struct ClampedAddFastOp { 107 static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported; 108 template <typename V> DoClampedAddFastOp109 __attribute__((always_inline)) static V Do(T x, U y) { 110 return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); 111 } 112 }; 113 114 template <typename T, typename U> 115 struct ClampedSubFastOp { 116 static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported; 117 template <typename V> DoClampedSubFastOp118 __attribute__((always_inline)) static V Do(T x, U y) { 119 return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); 120 } 121 }; 122 123 template <typename T, typename U> 124 struct ClampedMulFastOp { 125 static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported; 126 template <typename V> DoClampedMulFastOp127 __attribute__((always_inline)) static V Do(T x, U y) { 128 return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); 129 } 130 }; 131 132 template <typename T> 133 struct ClampedNegFastOp { 134 static const bool is_supported = std::is_signed<T>::value; DoClampedNegFastOp135 __attribute__((always_inline)) static T Do(T value) { 136 // Use this when there is no assembler path available. 137 if (!ClampedSubFastAsmOp<T, T>::is_supported) { 138 T result; 139 return !__builtin_sub_overflow(T(0), value, &result) 140 ? result 141 : std::numeric_limits<T>::max(); 142 } 143 144 // Fallback to the normal subtraction path. 145 return ClampedSubFastOp<T, T>::template Do<T>(T(0), value); 146 } 147 }; 148 149 } // namespace internal 150 } // namespace base 151 152 #endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 153