• 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_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
6 #define BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
7 
8 // IWYU pragma: private
9 
10 #include <stdint.h>
11 #include <limits>
12 #include <type_traits>
13 
14 #include "base/numerics/safe_conversions.h"
15 
16 #if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__))
17 #include "base/numerics/safe_math_arm_impl.h"  // IWYU pragma: export
18 #define BASE_HAS_ASSEMBLER_SAFE_MATH (1)
19 #else
20 #define BASE_HAS_ASSEMBLER_SAFE_MATH (0)
21 #endif
22 
23 namespace base {
24 namespace internal {
25 
26 // These are the non-functioning boilerplate implementations of the optimized
27 // safe math routines.
28 #if !BASE_HAS_ASSEMBLER_SAFE_MATH
29 template <typename T, typename U>
30 struct CheckedMulFastAsmOp {
31   static const bool is_supported = false;
32   template <typename V>
DoCheckedMulFastAsmOp33   static constexpr bool Do(T, U, V*) {
34     // Force a compile failure if instantiated.
35     return CheckOnFailure::template HandleFailure<bool>();
36   }
37 };
38 
39 template <typename T, typename U>
40 struct ClampedAddFastAsmOp {
41   static const bool is_supported = false;
42   template <typename V>
DoClampedAddFastAsmOp43   static constexpr V Do(T, U) {
44     // Force a compile failure if instantiated.
45     return CheckOnFailure::template HandleFailure<V>();
46   }
47 };
48 
49 template <typename T, typename U>
50 struct ClampedSubFastAsmOp {
51   static const bool is_supported = false;
52   template <typename V>
DoClampedSubFastAsmOp53   static constexpr V Do(T, U) {
54     // Force a compile failure if instantiated.
55     return CheckOnFailure::template HandleFailure<V>();
56   }
57 };
58 
59 template <typename T, typename U>
60 struct ClampedMulFastAsmOp {
61   static const bool is_supported = false;
62   template <typename V>
DoClampedMulFastAsmOp63   static constexpr V Do(T, U) {
64     // Force a compile failure if instantiated.
65     return CheckOnFailure::template HandleFailure<V>();
66   }
67 };
68 #endif  // BASE_HAS_ASSEMBLER_SAFE_MATH
69 #undef BASE_HAS_ASSEMBLER_SAFE_MATH
70 
71 template <typename T, typename U>
72 struct CheckedAddFastOp {
73   static const bool is_supported = true;
74   template <typename V>
DoCheckedAddFastOp75   __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
76     return !__builtin_add_overflow(x, y, result);
77   }
78 };
79 
80 template <typename T, typename U>
81 struct CheckedSubFastOp {
82   static const bool is_supported = true;
83   template <typename V>
DoCheckedSubFastOp84   __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
85     return !__builtin_sub_overflow(x, y, result);
86   }
87 };
88 
89 template <typename T, typename U>
90 struct CheckedMulFastOp {
91 #if defined(__clang__)
92   // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
93   // support full-width, mixed-sign multiply builtins.
94   // https://crbug.com/613003
95   // We can support intptr_t, uintptr_t, or a smaller common type.
96   static const bool is_supported =
97       (kIsTypeInRangeForNumericType<intptr_t, T> &&
98        kIsTypeInRangeForNumericType<intptr_t, U>) ||
99       (kIsTypeInRangeForNumericType<uintptr_t, T> &&
100        kIsTypeInRangeForNumericType<uintptr_t, U>);
101 #else
102   static const bool is_supported = true;
103 #endif
104   template <typename V>
DoCheckedMulFastOp105   __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
106     return CheckedMulFastAsmOp<T, U>::is_supported
107                ? CheckedMulFastAsmOp<T, U>::Do(x, y, result)
108                : !__builtin_mul_overflow(x, y, result);
109   }
110 };
111 
112 template <typename T, typename U>
113 struct ClampedAddFastOp {
114   static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported;
115   template <typename V>
DoClampedAddFastOp116   __attribute__((always_inline)) static V Do(T x, U y) {
117     return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y);
118   }
119 };
120 
121 template <typename T, typename U>
122 struct ClampedSubFastOp {
123   static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported;
124   template <typename V>
DoClampedSubFastOp125   __attribute__((always_inline)) static V Do(T x, U y) {
126     return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y);
127   }
128 };
129 
130 template <typename T, typename U>
131 struct ClampedMulFastOp {
132   static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported;
133   template <typename V>
DoClampedMulFastOp134   __attribute__((always_inline)) static V Do(T x, U y) {
135     return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y);
136   }
137 };
138 
139 template <typename T>
140 struct ClampedNegFastOp {
141   static const bool is_supported = std::is_signed_v<T>;
DoClampedNegFastOp142   __attribute__((always_inline)) static T Do(T value) {
143     // Use this when there is no assembler path available.
144     if (!ClampedSubFastAsmOp<T, T>::is_supported) {
145       T result;
146       return !__builtin_sub_overflow(T(0), value, &result)
147                  ? result
148                  : std::numeric_limits<T>::max();
149     }
150 
151     // Fallback to the normal subtraction path.
152     return ClampedSubFastOp<T, T>::template Do<T>(T(0), value);
153   }
154 };
155 
156 }  // namespace internal
157 }  // namespace base
158 
159 #endif  // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
160