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 THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 6 #define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 7 8 #include <cassert> 9 #include <limits> 10 #include <type_traits> 11 12 #include "third_party/base/numerics/safe_conversions.h" 13 14 #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__)) 15 #include "third_party/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 pdfium { 22 namespace base { 23 namespace internal { 24 25 // These are the non-functioning boilerplate implementations of the optimized 26 // safe math routines. 27 #if !BASE_HAS_ASSEMBLER_SAFE_MATH 28 template <typename T, typename U> 29 struct CheckedMulFastAsmOp { 30 static const bool is_supported = false; 31 template <typename V> DoCheckedMulFastAsmOp32 static constexpr bool Do(T, U, V*) { 33 // Force a compile failure if instantiated. 34 return CheckOnFailure::template HandleFailure<bool>(); 35 } 36 }; 37 38 template <typename T, typename U> 39 struct ClampedAddFastAsmOp { 40 static const bool is_supported = false; 41 template <typename V> DoClampedAddFastAsmOp42 static constexpr V Do(T, U) { 43 // Force a compile failure if instantiated. 44 return CheckOnFailure::template HandleFailure<V>(); 45 } 46 }; 47 48 template <typename T, typename U> 49 struct ClampedSubFastAsmOp { 50 static const bool is_supported = false; 51 template <typename V> DoClampedSubFastAsmOp52 static constexpr V Do(T, U) { 53 // Force a compile failure if instantiated. 54 return CheckOnFailure::template HandleFailure<V>(); 55 } 56 }; 57 58 template <typename T, typename U> 59 struct ClampedMulFastAsmOp { 60 static const bool is_supported = false; 61 template <typename V> DoClampedMulFastAsmOp62 static constexpr V Do(T, U) { 63 // Force a compile failure if instantiated. 64 return CheckOnFailure::template HandleFailure<V>(); 65 } 66 }; 67 #endif // BASE_HAS_ASSEMBLER_SAFE_MATH 68 #undef BASE_HAS_ASSEMBLER_SAFE_MATH 69 70 template <typename T, typename U> 71 struct CheckedAddFastOp { 72 static const bool is_supported = true; 73 template <typename V> DoCheckedAddFastOp74 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 75 return !__builtin_add_overflow(x, y, result); 76 } 77 }; 78 79 template <typename T, typename U> 80 struct CheckedSubFastOp { 81 static const bool is_supported = true; 82 template <typename V> DoCheckedSubFastOp83 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 84 return !__builtin_sub_overflow(x, y, result); 85 } 86 }; 87 88 template <typename T, typename U> 89 struct CheckedMulFastOp { 90 #if defined(__clang__) 91 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can 92 // support full-width, mixed-sign multiply builtins. 93 // https://crbug.com/613003 94 // We can support intptr_t, uintptr_t, or a smaller common type. 95 static const bool is_supported = 96 (IsTypeInRangeForNumericType<intptr_t, T>::value && 97 IsTypeInRangeForNumericType<intptr_t, U>::value) || 98 (IsTypeInRangeForNumericType<uintptr_t, T>::value && 99 IsTypeInRangeForNumericType<uintptr_t, U>::value); 100 #else 101 static const bool is_supported = true; 102 #endif 103 template <typename V> DoCheckedMulFastOp104 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { 105 return CheckedMulFastAsmOp<T, U>::is_supported 106 ? CheckedMulFastAsmOp<T, U>::Do(x, y, result) 107 : !__builtin_mul_overflow(x, y, result); 108 } 109 }; 110 111 template <typename T, typename U> 112 struct ClampedAddFastOp { 113 static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported; 114 template <typename V> DoClampedAddFastOp115 __attribute__((always_inline)) static V Do(T x, U y) { 116 return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); 117 } 118 }; 119 120 template <typename T, typename U> 121 struct ClampedSubFastOp { 122 static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported; 123 template <typename V> DoClampedSubFastOp124 __attribute__((always_inline)) static V Do(T x, U y) { 125 return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); 126 } 127 }; 128 129 template <typename T, typename U> 130 struct ClampedMulFastOp { 131 static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported; 132 template <typename V> DoClampedMulFastOp133 __attribute__((always_inline)) static V Do(T x, U y) { 134 return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); 135 } 136 }; 137 138 template <typename T> 139 struct ClampedNegFastOp { 140 static const bool is_supported = std::is_signed<T>::value; DoClampedNegFastOp141 __attribute__((always_inline)) static T Do(T value) { 142 // Use this when there is no assembler path available. 143 if (!ClampedSubFastAsmOp<T, T>::is_supported) { 144 T result; 145 return !__builtin_sub_overflow(T(0), value, &result) 146 ? result 147 : std::numeric_limits<T>::max(); 148 } 149 150 // Fallback to the normal subtraction path. 151 return ClampedSubFastOp<T, T>::template Do<T>(T(0), value); 152 } 153 }; 154 155 } // namespace internal 156 } // namespace base 157 } // namespace pdfium 158 159 #endif // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ 160