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