safe_math_arm_impl.h 4.1 KB

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