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 5 #ifndef BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_ 6 #define BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_ 7 8 #include <cassert> 9 #include <limits> 10 #include <type_traits> 11 12 #include "base/numerics/safe_conversions.h" 13 14 namespace base { 15 namespace internal { 16 17 template <typename T, typename U> 18 struct CheckedMulFastAsmOp { 19 static const bool is_supported = 20 FastIntegerArithmeticPromotion<T, U>::is_contained; 21 22 // The following is much more efficient 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> DoCheckedMulFastAsmOp34 __attribute__((always_inline)) static 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 *result = static_cast<V>(presult); 40 return IsValueInRangeForNumericType<V>(presult); 41 } 42 }; 43 44 template <typename T, typename U> 45 struct ClampedAddFastAsmOp { 46 static const bool is_supported = 47 BigEnoughPromotion<T, U>::is_contained && 48 IsTypeInRangeForNumericType< 49 int32_t, 50 typename BigEnoughPromotion<T, U>::type>::value; 51 52 template <typename V> DoClampedAddFastAsmOp53 __attribute__((always_inline)) static V Do(T x, U y) { 54 // This will get promoted to an int, so let the compiler do whatever is 55 // clever and rely on the saturated cast to bounds check. 56 if (IsIntegerArithmeticSafe<int, T, U>::value) 57 return saturated_cast<V>(x + y); 58 59 int32_t result; 60 int32_t x_i32 = x; 61 int32_t y_i32 = y; 62 63 asm("qadd %[result], %[first], %[second]" 64 : [result] "=r"(result) 65 : [first] "r"(x_i32), [second] "r"(y_i32)); 66 return saturated_cast<V>(result); 67 } 68 }; 69 70 template <typename T, typename U> 71 struct ClampedSubFastAsmOp { 72 static const bool is_supported = 73 BigEnoughPromotion<T, U>::is_contained && 74 IsTypeInRangeForNumericType< 75 int32_t, 76 typename BigEnoughPromotion<T, U>::type>::value; 77 78 template <typename V> DoClampedSubFastAsmOp79 __attribute__((always_inline)) static V Do(T x, U y) { 80 // This will get promoted to an int, so let the compiler do whatever is 81 // clever and rely on the saturated cast to bounds check. 82 if (IsIntegerArithmeticSafe<int, T, U>::value) 83 return saturated_cast<V>(x - y); 84 85 int32_t result; 86 int32_t x_i32 = x; 87 int32_t y_i32 = y; 88 89 asm("qsub %[result], %[first], %[second]" 90 : [result] "=r"(result) 91 : [first] "r"(x_i32), [second] "r"(y_i32)); 92 return saturated_cast<V>(result); 93 } 94 }; 95 96 template <typename T, typename U> 97 struct ClampedMulFastAsmOp { 98 static const bool is_supported = CheckedMulFastAsmOp<T, U>::is_supported; 99 100 template <typename V> DoClampedMulFastAsmOp101 __attribute__((always_inline)) static V Do(T x, U y) { 102 // Use the CheckedMulFastAsmOp for full-width 32-bit values, because 103 // it's fewer instructions than promoting and then saturating. 104 if (!IsIntegerArithmeticSafe<int32_t, T, U>::value && 105 !IsIntegerArithmeticSafe<uint32_t, T, U>::value) { 106 V result; 107 if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result)) 108 return result; 109 return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)); 110 } 111 112 assert((FastIntegerArithmeticPromotion<T, U>::is_contained)); 113 using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type; 114 return saturated_cast<V>(static_cast<Promotion>(x) * 115 static_cast<Promotion>(y)); 116 } 117 }; 118 119 } // namespace internal 120 } // namespace base 121 122 #endif // BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_ 123