blob: 660a57f2e7f33c9a1d912b5fa88743143506c036 [file] [log] [blame]
Scott Graham66962112018-06-08 12:42:08 -07001// 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
Scott Graham66962112018-06-08 12:42:08 -070014#define BASE_HAS_ASSEMBLER_SAFE_MATH (0)
Scott Graham66962112018-06-08 12:42:08 -070015
16namespace base {
17namespace internal {
18
19// These are the non-functioning boilerplate implementations of the optimized
20// safe math routines.
21#if !BASE_HAS_ASSEMBLER_SAFE_MATH
22template <typename T, typename U>
23struct CheckedMulFastAsmOp {
24 static const bool is_supported = false;
25 template <typename V>
26 static constexpr bool Do(T, U, V*) {
27 // Force a compile failure if instantiated.
28 return CheckOnFailure::template HandleFailure<bool>();
29 }
30};
31
32template <typename T, typename U>
33struct ClampedAddFastAsmOp {
34 static const bool is_supported = false;
35 template <typename V>
36 static constexpr V Do(T, U) {
37 // Force a compile failure if instantiated.
38 return CheckOnFailure::template HandleFailure<V>();
39 }
40};
41
42template <typename T, typename U>
43struct ClampedSubFastAsmOp {
44 static const bool is_supported = false;
45 template <typename V>
46 static constexpr V Do(T, U) {
47 // Force a compile failure if instantiated.
48 return CheckOnFailure::template HandleFailure<V>();
49 }
50};
51
52template <typename T, typename U>
53struct ClampedMulFastAsmOp {
54 static const bool is_supported = false;
55 template <typename V>
56 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
64template <typename T, typename U>
65struct CheckedAddFastOp {
66 static const bool is_supported = true;
67 template <typename V>
68 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
69 return !__builtin_add_overflow(x, y, result);
70 }
71};
72
73template <typename T, typename U>
74struct CheckedSubFastOp {
75 static const bool is_supported = true;
76 template <typename V>
77 __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
78 return !__builtin_sub_overflow(x, y, result);
79 }
80};
81
82template <typename T, typename U>
83struct 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>
98 __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
105template <typename T, typename U>
106struct ClampedAddFastOp {
107 static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported;
108 template <typename V>
109 __attribute__((always_inline)) static V Do(T x, U y) {
110 return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y);
111 }
112};
113
114template <typename T, typename U>
115struct ClampedSubFastOp {
116 static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported;
117 template <typename V>
118 __attribute__((always_inline)) static V Do(T x, U y) {
119 return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y);
120 }
121};
122
123template <typename T, typename U>
124struct ClampedMulFastOp {
125 static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported;
126 template <typename V>
127 __attribute__((always_inline)) static V Do(T x, U y) {
128 return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y);
129 }
130};
131
132template <typename T>
133struct ClampedNegFastOp {
134 static const bool is_supported = std::is_signed<T>::value;
135 __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_