1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159

base / numerics / safe_math_clang_gcc_impl.h [blame]

// Copyright 2017 The Chromium Authors
// 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_

// IWYU pragma: private

#include <stdint.h>
#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"  // IWYU pragma: export
#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 =
      (kIsTypeInRangeForNumericType<intptr_t, T> &&
       kIsTypeInRangeForNumericType<intptr_t, U>) ||
      (kIsTypeInRangeForNumericType<uintptr_t, T> &&
       kIsTypeInRangeForNumericType<uintptr_t, U>);
#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_v<T>;
  __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_