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