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