safe_math_arm_impl.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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 <type_traits>
  8. #include "base/numerics/safe_conversions.h"
  9. namespace base {
  10. namespace internal {
  11. template <typename T, typename U>
  12. struct CheckedMulFastAsmOp {
  13. static const bool is_supported =
  14. kEnableAsmCode && FastIntegerArithmeticPromotion<T, U>::is_contained;
  15. // The following is not an assembler routine and is thus constexpr safe, it
  16. // just emits much more efficient code 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. static constexpr 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. if (!IsValueInRangeForNumericType<V>(presult))
  33. return false;
  34. *result = static_cast<V>(presult);
  35. return true;
  36. }
  37. };
  38. template <typename T, typename U>
  39. struct ClampedAddFastAsmOp {
  40. static const bool is_supported =
  41. kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
  42. IsTypeInRangeForNumericType<
  43. int32_t,
  44. typename BigEnoughPromotion<T, U>::type>::value;
  45. template <typename V>
  46. __attribute__((always_inline)) static V Do(T x, U y) {
  47. // This will get promoted to an int, so let the compiler do whatever is
  48. // clever and rely on the saturated cast to bounds check.
  49. if (IsIntegerArithmeticSafe<int, T, U>::value)
  50. return saturated_cast<V>(static_cast<int>(x) + static_cast<int>(y));
  51. int32_t result;
  52. int32_t x_i32 = checked_cast<int32_t>(x);
  53. int32_t y_i32 = checked_cast<int32_t>(y);
  54. asm("qadd %[result], %[first], %[second]"
  55. : [result] "=r"(result)
  56. : [first] "r"(x_i32), [second] "r"(y_i32));
  57. return saturated_cast<V>(result);
  58. }
  59. };
  60. template <typename T, typename U>
  61. struct ClampedSubFastAsmOp {
  62. static const bool is_supported =
  63. kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
  64. IsTypeInRangeForNumericType<
  65. int32_t,
  66. typename BigEnoughPromotion<T, U>::type>::value;
  67. template <typename V>
  68. __attribute__((always_inline)) static V Do(T x, U y) {
  69. // This will get promoted to an int, so let the compiler do whatever is
  70. // clever and rely on the saturated cast to bounds check.
  71. if (IsIntegerArithmeticSafe<int, T, U>::value)
  72. return saturated_cast<V>(static_cast<int>(x) - static_cast<int>(y));
  73. int32_t result;
  74. int32_t x_i32 = checked_cast<int32_t>(x);
  75. int32_t y_i32 = checked_cast<int32_t>(y);
  76. asm("qsub %[result], %[first], %[second]"
  77. : [result] "=r"(result)
  78. : [first] "r"(x_i32), [second] "r"(y_i32));
  79. return saturated_cast<V>(result);
  80. }
  81. };
  82. template <typename T, typename U>
  83. struct ClampedMulFastAsmOp {
  84. static const bool is_supported =
  85. kEnableAsmCode && CheckedMulFastAsmOp<T, U>::is_supported;
  86. template <typename V>
  87. __attribute__((always_inline)) static V Do(T x, U y) {
  88. // Use the CheckedMulFastAsmOp for full-width 32-bit values, because
  89. // it's fewer instructions than promoting and then saturating.
  90. if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
  91. !IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
  92. V result;
  93. return CheckedMulFastAsmOp<T, U>::Do(x, y, &result)
  94. ? result
  95. : CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
  96. }
  97. assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
  98. using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
  99. return saturated_cast<V>(static_cast<Promotion>(x) *
  100. static_cast<Promotion>(y));
  101. }
  102. };
  103. } // namespace internal
  104. } // namespace base
  105. #endif // BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_