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