123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- // 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_ARM_IMPL_H_
- #define BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
- #include <cassert>
- #include <limits>
- #include <type_traits>
- #include "base/numerics/safe_conversions.h"
- namespace base {
- namespace internal {
- template <typename T, typename U>
- struct CheckedMulFastAsmOp {
- static const bool is_supported =
- FastIntegerArithmeticPromotion<T, U>::is_contained;
- // The following is much more efficient than the Clang and GCC builtins for
- // performing overflow-checked multiplication when a twice wider type is
- // available. The below compiles down to 2-3 instructions, depending on the
- // width of the types in use.
- // As an example, an int32_t multiply compiles to:
- // smull r0, r1, r0, r1
- // cmp r1, r1, asr #31
- // And an int16_t multiply compiles to:
- // smulbb r1, r1, r0
- // asr r2, r1, #16
- // cmp r2, r1, asr #15
- template <typename V>
- __attribute__((always_inline)) static bool Do(T x, U y, V* result) {
- using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
- Promotion presult;
- presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
- *result = static_cast<V>(presult);
- return IsValueInRangeForNumericType<V>(presult);
- }
- };
- template <typename T, typename U>
- struct ClampedAddFastAsmOp {
- static const bool is_supported =
- BigEnoughPromotion<T, U>::is_contained &&
- IsTypeInRangeForNumericType<
- int32_t,
- typename BigEnoughPromotion<T, U>::type>::value;
- template <typename V>
- __attribute__((always_inline)) static V Do(T x, U y) {
- // This will get promoted to an int, so let the compiler do whatever is
- // clever and rely on the saturated cast to bounds check.
- if (IsIntegerArithmeticSafe<int, T, U>::value)
- return saturated_cast<V>(x + y);
- int32_t result;
- int32_t x_i32 = checked_cast<int32_t>(x);
- int32_t y_i32 = checked_cast<int32_t>(y);
- asm("qadd %[result], %[first], %[second]"
- : [result] "=r"(result)
- : [first] "r"(x_i32), [second] "r"(y_i32));
- return saturated_cast<V>(result);
- }
- };
- template <typename T, typename U>
- struct ClampedSubFastAsmOp {
- static const bool is_supported =
- BigEnoughPromotion<T, U>::is_contained &&
- IsTypeInRangeForNumericType<
- int32_t,
- typename BigEnoughPromotion<T, U>::type>::value;
- template <typename V>
- __attribute__((always_inline)) static V Do(T x, U y) {
- // This will get promoted to an int, so let the compiler do whatever is
- // clever and rely on the saturated cast to bounds check.
- if (IsIntegerArithmeticSafe<int, T, U>::value)
- return saturated_cast<V>(x - y);
- int32_t result;
- int32_t x_i32 = checked_cast<int32_t>(x);
- int32_t y_i32 = checked_cast<int32_t>(y);
- asm("qsub %[result], %[first], %[second]"
- : [result] "=r"(result)
- : [first] "r"(x_i32), [second] "r"(y_i32));
- return saturated_cast<V>(result);
- }
- };
- template <typename T, typename U>
- struct ClampedMulFastAsmOp {
- static const bool is_supported = CheckedMulFastAsmOp<T, U>::is_supported;
- template <typename V>
- __attribute__((always_inline)) static V Do(T x, U y) {
- // Use the CheckedMulFastAsmOp for full-width 32-bit values, because
- // it's fewer instructions than promoting and then saturating.
- if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
- !IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
- V result;
- if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result))
- return result;
- return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
- }
- assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
- using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
- return saturated_cast<V>(static_cast<Promotion>(x) *
- static_cast<Promotion>(y));
- }
- };
- } // namespace internal
- } // namespace base
- #endif // BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
|