safe_math_clang_gcc_impl.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
  5. #define BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
  6. #include <cassert>
  7. #include <limits>
  8. #include <type_traits>
  9. #include "base/numerics/safe_conversions.h"
  10. #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__))
  11. #include "base/numerics/safe_math_arm_impl.h"
  12. #define BASE_HAS_ASSEMBLER_SAFE_MATH (1)
  13. #else
  14. #define BASE_HAS_ASSEMBLER_SAFE_MATH (0)
  15. #endif
  16. namespace base {
  17. namespace internal {
  18. // These are the non-functioning boilerplate implementations of the optimized
  19. // safe math routines.
  20. #if !BASE_HAS_ASSEMBLER_SAFE_MATH
  21. template <typename T, typename U>
  22. struct CheckedMulFastAsmOp {
  23. static const bool is_supported = false;
  24. template <typename V>
  25. static constexpr bool Do(T, U, V*) {
  26. // Force a compile failure if instantiated.
  27. return CheckOnFailure::template HandleFailure<bool>();
  28. }
  29. };
  30. template <typename T, typename U>
  31. struct ClampedAddFastAsmOp {
  32. static const bool is_supported = false;
  33. template <typename V>
  34. static constexpr V Do(T, U) {
  35. // Force a compile failure if instantiated.
  36. return CheckOnFailure::template HandleFailure<V>();
  37. }
  38. };
  39. template <typename T, typename U>
  40. struct ClampedSubFastAsmOp {
  41. static const bool is_supported = false;
  42. template <typename V>
  43. static constexpr V Do(T, U) {
  44. // Force a compile failure if instantiated.
  45. return CheckOnFailure::template HandleFailure<V>();
  46. }
  47. };
  48. template <typename T, typename U>
  49. struct ClampedMulFastAsmOp {
  50. static const bool is_supported = false;
  51. template <typename V>
  52. static constexpr V Do(T, U) {
  53. // Force a compile failure if instantiated.
  54. return CheckOnFailure::template HandleFailure<V>();
  55. }
  56. };
  57. #endif // BASE_HAS_ASSEMBLER_SAFE_MATH
  58. #undef BASE_HAS_ASSEMBLER_SAFE_MATH
  59. template <typename T, typename U>
  60. struct CheckedAddFastOp {
  61. static const bool is_supported = true;
  62. template <typename V>
  63. __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
  64. return !__builtin_add_overflow(x, y, result);
  65. }
  66. };
  67. template <typename T, typename U>
  68. struct CheckedSubFastOp {
  69. static const bool is_supported = true;
  70. template <typename V>
  71. __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
  72. return !__builtin_sub_overflow(x, y, result);
  73. }
  74. };
  75. template <typename T, typename U>
  76. struct CheckedMulFastOp {
  77. #if defined(__clang__)
  78. // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
  79. // support full-width, mixed-sign multiply builtins.
  80. // https://crbug.com/613003
  81. // We can support intptr_t, uintptr_t, or a smaller common type.
  82. static const bool is_supported =
  83. (IsTypeInRangeForNumericType<intptr_t, T>::value &&
  84. IsTypeInRangeForNumericType<intptr_t, U>::value) ||
  85. (IsTypeInRangeForNumericType<uintptr_t, T>::value &&
  86. IsTypeInRangeForNumericType<uintptr_t, U>::value);
  87. #else
  88. static const bool is_supported = true;
  89. #endif
  90. template <typename V>
  91. __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
  92. return CheckedMulFastAsmOp<T, U>::is_supported
  93. ? CheckedMulFastAsmOp<T, U>::Do(x, y, result)
  94. : !__builtin_mul_overflow(x, y, result);
  95. }
  96. };
  97. template <typename T, typename U>
  98. struct ClampedAddFastOp {
  99. static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported;
  100. template <typename V>
  101. __attribute__((always_inline)) static V Do(T x, U y) {
  102. return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y);
  103. }
  104. };
  105. template <typename T, typename U>
  106. struct ClampedSubFastOp {
  107. static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported;
  108. template <typename V>
  109. __attribute__((always_inline)) static V Do(T x, U y) {
  110. return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y);
  111. }
  112. };
  113. template <typename T, typename U>
  114. struct ClampedMulFastOp {
  115. static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported;
  116. template <typename V>
  117. __attribute__((always_inline)) static V Do(T x, U y) {
  118. return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y);
  119. }
  120. };
  121. template <typename T>
  122. struct ClampedNegFastOp {
  123. static const bool is_supported = std::is_signed<T>::value;
  124. __attribute__((always_inline)) static T Do(T value) {
  125. // Use this when there is no assembler path available.
  126. if (!ClampedSubFastAsmOp<T, T>::is_supported) {
  127. T result;
  128. return !__builtin_sub_overflow(T(0), value, &result)
  129. ? result
  130. : std::numeric_limits<T>::max();
  131. }
  132. // Fallback to the normal subtraction path.
  133. return ClampedSubFastOp<T, T>::template Do<T>(T(0), value);
  134. }
  135. };
  136. } // namespace internal
  137. } // namespace base
  138. #endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_