|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ | 
|  | #define BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ | 
|  |  | 
|  | #include <cassert> | 
|  | #include <limits> | 
|  | #include <type_traits> | 
|  |  | 
|  | #include "base/numerics/safe_conversions.h" | 
|  |  | 
|  | #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__)) | 
|  | #include "base/numerics/safe_math_arm_impl.h" | 
|  | #define BASE_HAS_ASSEMBLER_SAFE_MATH (1) | 
|  | #else | 
|  | #define BASE_HAS_ASSEMBLER_SAFE_MATH (0) | 
|  | #endif | 
|  |  | 
|  | namespace base { | 
|  | namespace internal { | 
|  |  | 
|  | // These are the non-functioning boilerplate implementations of the optimized | 
|  | // safe math routines. | 
|  | #if !BASE_HAS_ASSEMBLER_SAFE_MATH | 
|  | template <typename T, typename U> | 
|  | struct CheckedMulFastAsmOp { | 
|  | static const bool is_supported = false; | 
|  | template <typename V> | 
|  | static constexpr bool Do(T, U, V*) { | 
|  | // Force a compile failure if instantiated. | 
|  | return CheckOnFailure::template HandleFailure<bool>(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct ClampedAddFastAsmOp { | 
|  | static const bool is_supported = false; | 
|  | template <typename V> | 
|  | static constexpr V Do(T, U) { | 
|  | // Force a compile failure if instantiated. | 
|  | return CheckOnFailure::template HandleFailure<V>(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct ClampedSubFastAsmOp { | 
|  | static const bool is_supported = false; | 
|  | template <typename V> | 
|  | static constexpr V Do(T, U) { | 
|  | // Force a compile failure if instantiated. | 
|  | return CheckOnFailure::template HandleFailure<V>(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct ClampedMulFastAsmOp { | 
|  | static const bool is_supported = false; | 
|  | template <typename V> | 
|  | static constexpr V Do(T, U) { | 
|  | // Force a compile failure if instantiated. | 
|  | return CheckOnFailure::template HandleFailure<V>(); | 
|  | } | 
|  | }; | 
|  | #endif  // BASE_HAS_ASSEMBLER_SAFE_MATH | 
|  | #undef BASE_HAS_ASSEMBLER_SAFE_MATH | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct CheckedAddFastOp { | 
|  | static const bool is_supported = true; | 
|  | template <typename V> | 
|  | __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { | 
|  | return !__builtin_add_overflow(x, y, result); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct CheckedSubFastOp { | 
|  | static const bool is_supported = true; | 
|  | template <typename V> | 
|  | __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { | 
|  | return !__builtin_sub_overflow(x, y, result); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct CheckedMulFastOp { | 
|  | #if defined(__clang__) | 
|  | // TODO(jschuh): Get the Clang runtime library issues sorted out so we can | 
|  | // support full-width, mixed-sign multiply builtins. | 
|  | // https://crbug.com/613003 | 
|  | // We can support intptr_t, uintptr_t, or a smaller common type. | 
|  | static const bool is_supported = | 
|  | (IsTypeInRangeForNumericType<intptr_t, T>::value && | 
|  | IsTypeInRangeForNumericType<intptr_t, U>::value) || | 
|  | (IsTypeInRangeForNumericType<uintptr_t, T>::value && | 
|  | IsTypeInRangeForNumericType<uintptr_t, U>::value); | 
|  | #else | 
|  | static const bool is_supported = true; | 
|  | #endif | 
|  | template <typename V> | 
|  | __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) { | 
|  | return CheckedMulFastAsmOp<T, U>::is_supported | 
|  | ? CheckedMulFastAsmOp<T, U>::Do(x, y, result) | 
|  | : !__builtin_mul_overflow(x, y, result); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct ClampedAddFastOp { | 
|  | static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported; | 
|  | template <typename V> | 
|  | __attribute__((always_inline)) static V Do(T x, U y) { | 
|  | return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct ClampedSubFastOp { | 
|  | static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported; | 
|  | template <typename V> | 
|  | __attribute__((always_inline)) static V Do(T x, U y) { | 
|  | return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T, typename U> | 
|  | struct ClampedMulFastOp { | 
|  | static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported; | 
|  | template <typename V> | 
|  | __attribute__((always_inline)) static V Do(T x, U y) { | 
|  | return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | struct ClampedNegFastOp { | 
|  | static const bool is_supported = std::is_signed<T>::value; | 
|  | __attribute__((always_inline)) static T Do(T value) { | 
|  | // Use this when there is no assembler path available. | 
|  | if (!ClampedSubFastAsmOp<T, T>::is_supported) { | 
|  | T result; | 
|  | return !__builtin_sub_overflow(T(0), value, &result) | 
|  | ? result | 
|  | : std::numeric_limits<T>::max(); | 
|  | } | 
|  |  | 
|  | // Fallback to the normal subtraction path. | 
|  | return ClampedSubFastOp<T, T>::template Do<T>(T(0), value); | 
|  | } | 
|  | }; | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ |