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