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