123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- // 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_
|