| // 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 (!IsCompileTimeConstant(x) && !IsCompileTimeConstant(y)) && |
| 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 = true; |
| template <typename V> |
| static V Do(T x, U y) { |
| if ((!IsCompileTimeConstant(x) || !IsCompileTimeConstant(y)) && |
| ClampedAddFastAsmOp<T, U>::is_supported) { |
| return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y); |
| } |
| |
| V result; |
| return !__builtin_add_overflow(x, y, &result) |
| ? result |
| : GetMaxOrMin<V>(IsCompileTimeConstant(x) ? IsValueNegative(x) |
| : IsValueNegative(y)); |
| } |
| }; |
| |
| template <typename T, typename U> |
| struct ClampedSubFastOp { |
| static const bool is_supported = true; |
| template <typename V> |
| static V Do(T x, U y) { |
| if ((!IsCompileTimeConstant(x) || !IsCompileTimeConstant(y)) && |
| ClampedSubFastAsmOp<T, U>::is_supported) { |
| return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y); |
| } |
| |
| V result; |
| return !__builtin_sub_overflow(x, y, &result) |
| ? result |
| : GetMaxOrMin<V>(IsCompileTimeConstant(x) ? IsValueNegative(x) |
| : !IsValueNegative(y)); |
| } |
| }; |
| |
| template <typename T, typename U> |
| struct ClampedMulFastOp { |
| static const bool is_supported = CheckedMulFastOp<T, U>::is_supported; |
| template <typename V> |
| static V Do(T x, U y) { |
| if ((!IsCompileTimeConstant(x) && !IsCompileTimeConstant(y)) && |
| ClampedMulFastAsmOp<T, U>::is_supported) { |
| return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y); |
| } |
| |
| V result; |
| return CheckedMulFastOp<T, U>::Do(x, y, &result) |
| ? result |
| : GetMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)); |
| } |
| }; |
| |
| } // namespace internal |
| } // namespace base |
| |
| #endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_ |