| // 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" | |
| #define BASE_HAS_ASSEMBLER_SAFE_MATH (0) | |
| 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_ |