• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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