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 "anglebase/numerics/safe_conversions.h" 13 14 #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__)) 15 # include "anglebase/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 angle 22 { 23 namespace base 24 { 25 namespace internal 26 { 27 28 // These are the non-functioning boilerplate implementations of the optimized 29 // safe math routines. 30 #if !BASE_HAS_ASSEMBLER_SAFE_MATH 31 template <typename T, typename U> 32 struct CheckedMulFastAsmOp 33 { 34 static const bool is_supported = false; 35 template <typename V> DoCheckedMulFastAsmOp36 static constexpr bool Do(T, U, V *) 37 { 38 // Force a compile failure if instantiated. 39 return CheckOnFailure::template HandleFailure<bool>(); 40 } 41 }; 42 43 template <typename T, typename U> 44 struct ClampedAddFastAsmOp 45 { 46 static const bool is_supported = false; 47 template <typename V> DoClampedAddFastAsmOp48 static constexpr V Do(T, U) 49 { 50 // Force a compile failure if instantiated. 51 return CheckOnFailure::template HandleFailure<V>(); 52 } 53 }; 54 55 template <typename T, typename U> 56 struct ClampedSubFastAsmOp 57 { 58 static const bool is_supported = false; 59 template <typename V> DoClampedSubFastAsmOp60 static constexpr V Do(T, U) 61 { 62 // Force a compile failure if instantiated. 63 return CheckOnFailure::template HandleFailure<V>(); 64 } 65 }; 66 67 template <typename T, typename U> 68 struct ClampedMulFastAsmOp 69 { 70 static const bool is_supported = false; 71 template <typename V> DoClampedMulFastAsmOp72 static constexpr V Do(T, U) 73 { 74 // Force a compile failure if instantiated. 75 return CheckOnFailure::template HandleFailure<V>(); 76 } 77 }; 78 #endif // BASE_HAS_ASSEMBLER_SAFE_MATH 79 #undef BASE_HAS_ASSEMBLER_SAFE_MATH 80 81 template <typename T, typename U> 82 struct CheckedAddFastOp 83 { 84 static const bool is_supported = true; 85 template <typename V> DoCheckedAddFastOp86 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V *result) 87 { 88 return !__builtin_add_overflow(x, y, result); 89 } 90 }; 91 92 template <typename T, typename U> 93 struct CheckedSubFastOp 94 { 95 static const bool is_supported = true; 96 template <typename V> DoCheckedSubFastOp97 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V *result) 98 { 99 return !__builtin_sub_overflow(x, y, result); 100 } 101 }; 102 103 template <typename T, typename U> 104 struct CheckedMulFastOp 105 { 106 #if defined(__clang__) 107 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can 108 // support full-width, mixed-sign multiply builtins. 109 // https://crbug.com/613003 110 // We can support intptr_t, uintptr_t, or a smaller common type. 111 static const bool is_supported = (IsTypeInRangeForNumericType<intptr_t, T>::value && 112 IsTypeInRangeForNumericType<intptr_t, U>::value) || 113 (IsTypeInRangeForNumericType<uintptr_t, T>::value && 114 IsTypeInRangeForNumericType<uintptr_t, U>::value); 115 #else 116 static const bool is_supported = true; 117 #endif 118 template <typename V> DoCheckedMulFastOp119 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V *result) 120 { 121 return CheckedMulFastAsmOp<T, U>::is_supported ? CheckedMulFastAsmOp<T, U>::Do(x, y, result) 122 : !__builtin_mul_overflow(x, y, result); 123 } 124 }; 125 126 template <typename T, typename U> 127 struct ClampedAddFastOp 128 { 129 static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported; 130 template <typename V> DoClampedAddFastOp131 __attribute__((always_inline)) static V Do(T x, U y) 132 { 133 return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); 134 } 135 }; 136 137 template <typename T, typename U> 138 struct ClampedSubFastOp 139 { 140 static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported; 141 template <typename V> DoClampedSubFastOp142 __attribute__((always_inline)) static V Do(T x, U y) 143 { 144 return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); 145 } 146 }; 147 148 template <typename T, typename U> 149 struct ClampedMulFastOp 150 { 151 static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported; 152 template <typename V> DoClampedMulFastOp153 __attribute__((always_inline)) static V Do(T x, U y) 154 { 155 return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); 156 } 157 }; 158 159 template <typename T> 160 struct ClampedNegFastOp 161 { 162 static const bool is_supported = std::is_signed<T>::value; DoClampedNegFastOp163 __attribute__((always_inline)) static T Do(T value) 164 { 165 // Use this when there is no assembler path available. 166 if (!ClampedSubFastAsmOp<T, T>::is_supported) 167 { 168 T result; 169 return !__builtin_sub_overflow(T(0), value, &result) ? result 170 : std::numeric_limits<T>::max(); 171 } 172 173 // Fallback to the normal subtraction path. 174 return ClampedSubFastOp<T, T>::template Do<T>(T(0), value); 175 } 176 }; 177 178 } // namespace internal 179 } // namespace base 180 } // namespace angle 181 182 #endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 183