tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

safe_math_arm_impl.h (4368B)


      1 // Copyright 2017 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
      6 #define BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
      7 
      8 #include <cassert>
      9 #include <type_traits>
     10 
     11 #include "base/numerics/safe_conversions.h"
     12 
     13 namespace base {
     14 namespace internal {
     15 
     16 template <typename T, typename U>
     17 struct CheckedMulFastAsmOp {
     18  static const bool is_supported =
     19      kEnableAsmCode && FastIntegerArithmeticPromotion<T, U>::is_contained;
     20 
     21  // The following is not an assembler routine and is thus constexpr safe, it
     22  // just emits much more efficient code than the Clang and GCC builtins for
     23  // performing overflow-checked multiplication when a twice wider type is
     24  // available. The below compiles down to 2-3 instructions, depending on the
     25  // width of the types in use.
     26  // As an example, an int32_t multiply compiles to:
     27  //    smull   r0, r1, r0, r1
     28  //    cmp     r1, r1, asr #31
     29  // And an int16_t multiply compiles to:
     30  //    smulbb  r1, r1, r0
     31  //    asr     r2, r1, #16
     32  //    cmp     r2, r1, asr #15
     33  template <typename V>
     34  static constexpr bool Do(T x, U y, V* result) {
     35    using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
     36    Promotion presult;
     37 
     38    presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
     39    if (!IsValueInRangeForNumericType<V>(presult))
     40      return false;
     41    *result = static_cast<V>(presult);
     42    return true;
     43  }
     44 };
     45 
     46 template <typename T, typename U>
     47 struct ClampedAddFastAsmOp {
     48  static const bool is_supported =
     49      kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
     50      IsTypeInRangeForNumericType<
     51          int32_t,
     52          typename BigEnoughPromotion<T, U>::type>::value;
     53 
     54  template <typename V>
     55  __attribute__((always_inline)) static V Do(T x, U y) {
     56    // This will get promoted to an int, so let the compiler do whatever is
     57    // clever and rely on the saturated cast to bounds check.
     58    if (IsIntegerArithmeticSafe<int, T, U>::value)
     59      return saturated_cast<V>(static_cast<int>(x) + static_cast<int>(y));
     60 
     61    int32_t result;
     62    int32_t x_i32 = checked_cast<int32_t>(x);
     63    int32_t y_i32 = checked_cast<int32_t>(y);
     64 
     65    asm("qadd %[result], %[first], %[second]"
     66        : [result] "=r"(result)
     67        : [first] "r"(x_i32), [second] "r"(y_i32));
     68    return saturated_cast<V>(result);
     69  }
     70 };
     71 
     72 template <typename T, typename U>
     73 struct ClampedSubFastAsmOp {
     74  static const bool is_supported =
     75      kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
     76      IsTypeInRangeForNumericType<
     77          int32_t,
     78          typename BigEnoughPromotion<T, U>::type>::value;
     79 
     80  template <typename V>
     81  __attribute__((always_inline)) static V Do(T x, U y) {
     82    // This will get promoted to an int, so let the compiler do whatever is
     83    // clever and rely on the saturated cast to bounds check.
     84    if (IsIntegerArithmeticSafe<int, T, U>::value)
     85      return saturated_cast<V>(static_cast<int>(x) - static_cast<int>(y));
     86 
     87    int32_t result;
     88    int32_t x_i32 = checked_cast<int32_t>(x);
     89    int32_t y_i32 = checked_cast<int32_t>(y);
     90 
     91    asm("qsub %[result], %[first], %[second]"
     92        : [result] "=r"(result)
     93        : [first] "r"(x_i32), [second] "r"(y_i32));
     94    return saturated_cast<V>(result);
     95  }
     96 };
     97 
     98 template <typename T, typename U>
     99 struct ClampedMulFastAsmOp {
    100  static const bool is_supported =
    101      kEnableAsmCode && CheckedMulFastAsmOp<T, U>::is_supported;
    102 
    103  template <typename V>
    104  __attribute__((always_inline)) static V Do(T x, U y) {
    105    // Use the CheckedMulFastAsmOp for full-width 32-bit values, because
    106    // it's fewer instructions than promoting and then saturating.
    107    if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
    108        !IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
    109      V result;
    110      return CheckedMulFastAsmOp<T, U>::Do(x, y, &result)
    111                 ? result
    112                 : CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
    113    }
    114 
    115    assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
    116    using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
    117    return saturated_cast<V>(static_cast<Promotion>(x) *
    118                             static_cast<Promotion>(y));
    119  }
    120 };
    121 
    122 }  // namespace internal
    123 }  // namespace base
    124 
    125 #endif  // BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_