• 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 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 #define BASE_HAS_ASSEMBLER_SAFE_MATH (0)
15 
16 namespace base {
17 namespace internal {
18 
19 // These are the non-functioning boilerplate implementations of the optimized
20 // safe math routines.
21 #if !BASE_HAS_ASSEMBLER_SAFE_MATH
22 template <typename T, typename U>
23 struct CheckedMulFastAsmOp {
24   static const bool is_supported = false;
25   template <typename V>
DoCheckedMulFastAsmOp26   static constexpr bool Do(T, U, V*) {
27     // Force a compile failure if instantiated.
28     return CheckOnFailure::template HandleFailure<bool>();
29   }
30 };
31 
32 template <typename T, typename U>
33 struct ClampedAddFastAsmOp {
34   static const bool is_supported = false;
35   template <typename V>
DoClampedAddFastAsmOp36   static constexpr V Do(T, U) {
37     // Force a compile failure if instantiated.
38     return CheckOnFailure::template HandleFailure<V>();
39   }
40 };
41 
42 template <typename T, typename U>
43 struct ClampedSubFastAsmOp {
44   static const bool is_supported = false;
45   template <typename V>
DoClampedSubFastAsmOp46   static constexpr V Do(T, U) {
47     // Force a compile failure if instantiated.
48     return CheckOnFailure::template HandleFailure<V>();
49   }
50 };
51 
52 template <typename T, typename U>
53 struct ClampedMulFastAsmOp {
54   static const bool is_supported = false;
55   template <typename V>
DoClampedMulFastAsmOp56   static constexpr V Do(T, U) {
57     // Force a compile failure if instantiated.
58     return CheckOnFailure::template HandleFailure<V>();
59   }
60 };
61 #endif  // BASE_HAS_ASSEMBLER_SAFE_MATH
62 #undef BASE_HAS_ASSEMBLER_SAFE_MATH
63 
64 template <typename T, typename U>
65 struct CheckedAddFastOp {
66   static const bool is_supported = true;
67   template <typename V>
DoCheckedAddFastOp68   __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
69     return !__builtin_add_overflow(x, y, result);
70   }
71 };
72 
73 template <typename T, typename U>
74 struct CheckedSubFastOp {
75   static const bool is_supported = true;
76   template <typename V>
DoCheckedSubFastOp77   __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
78     return !__builtin_sub_overflow(x, y, result);
79   }
80 };
81 
82 template <typename T, typename U>
83 struct CheckedMulFastOp {
84 #if defined(__clang__)
85   // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
86   // support full-width, mixed-sign multiply builtins.
87   // https://crbug.com/613003
88   // We can support intptr_t, uintptr_t, or a smaller common type.
89   static const bool is_supported =
90       (IsTypeInRangeForNumericType<intptr_t, T>::value &&
91        IsTypeInRangeForNumericType<intptr_t, U>::value) ||
92       (IsTypeInRangeForNumericType<uintptr_t, T>::value &&
93        IsTypeInRangeForNumericType<uintptr_t, U>::value);
94 #else
95   static const bool is_supported = true;
96 #endif
97   template <typename V>
DoCheckedMulFastOp98   __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
99     return CheckedMulFastAsmOp<T, U>::is_supported
100                ? CheckedMulFastAsmOp<T, U>::Do(x, y, result)
101                : !__builtin_mul_overflow(x, y, result);
102   }
103 };
104 
105 template <typename T, typename U>
106 struct ClampedAddFastOp {
107   static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported;
108   template <typename V>
DoClampedAddFastOp109   __attribute__((always_inline)) static V Do(T x, U y) {
110     return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y);
111   }
112 };
113 
114 template <typename T, typename U>
115 struct ClampedSubFastOp {
116   static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported;
117   template <typename V>
DoClampedSubFastOp118   __attribute__((always_inline)) static V Do(T x, U y) {
119     return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y);
120   }
121 };
122 
123 template <typename T, typename U>
124 struct ClampedMulFastOp {
125   static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported;
126   template <typename V>
DoClampedMulFastOp127   __attribute__((always_inline)) static V Do(T x, U y) {
128     return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y);
129   }
130 };
131 
132 template <typename T>
133 struct ClampedNegFastOp {
134   static const bool is_supported = std::is_signed<T>::value;
DoClampedNegFastOp135   __attribute__((always_inline)) static T Do(T value) {
136     // Use this when there is no assembler path available.
137     if (!ClampedSubFastAsmOp<T, T>::is_supported) {
138       T result;
139       return !__builtin_sub_overflow(T(0), value, &result)
140                  ? result
141                  : std::numeric_limits<T>::max();
142     }
143 
144     // Fallback to the normal subtraction path.
145     return ClampedSubFastOp<T, T>::template Do<T>(T(0), value);
146   }
147 };
148 
149 }  // namespace internal
150 }  // namespace base
151 
152 #endif  // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
153