/src/abseil-cpp/absl/numeric/int128_have_intrinsic.inc
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Copyright 2017 The Abseil Authors. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | // you may not use this file except in compliance with the License. |
6 | | // You may obtain a copy of the License at |
7 | | // |
8 | | // https://www.apache.org/licenses/LICENSE-2.0 |
9 | | // |
10 | | // Unless required by applicable law or agreed to in writing, software |
11 | | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | // See the License for the specific language governing permissions and |
14 | | // limitations under the License. |
15 | | |
16 | | // This file contains :int128 implementation details that depend on internal |
17 | | // representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is |
18 | | // included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. |
19 | | |
20 | | namespace int128_internal { |
21 | | |
22 | | // Casts from unsigned to signed while preserving the underlying binary |
23 | | // representation. |
24 | 0 | constexpr __int128 BitCastToSigned(unsigned __int128 v) { |
25 | | // Casting an unsigned integer to a signed integer of the same |
26 | | // width is implementation defined behavior if the source value would not fit |
27 | | // in the destination type. We step around it with a roundtrip bitwise not |
28 | | // operation to make sure this function remains constexpr. Clang and GCC |
29 | | // optimize this to a no-op on x86-64. |
30 | 0 | return v & (static_cast<unsigned __int128>(1) << 127) |
31 | 0 | ? ~static_cast<__int128>(~v) |
32 | 0 | : static_cast<__int128>(v); |
33 | 0 | } |
34 | | |
35 | | } // namespace int128_internal |
36 | | |
37 | 0 | inline int128& int128::operator=(__int128 v) { |
38 | 0 | v_ = v; |
39 | 0 | return *this; |
40 | 0 | } |
41 | | |
42 | 0 | constexpr uint64_t Int128Low64(int128 v) { |
43 | 0 | return static_cast<uint64_t>(v.v_ & ~uint64_t{0}); |
44 | 0 | } |
45 | | |
46 | 0 | constexpr int64_t Int128High64(int128 v) { |
47 | | // Initially cast to unsigned to prevent a right shift on a negative value. |
48 | 0 | return int128_internal::BitCastToSigned( |
49 | 0 | static_cast<uint64_t>(static_cast<unsigned __int128>(v.v_) >> 64)); |
50 | 0 | } |
51 | | |
52 | | constexpr int128::int128(int64_t high, uint64_t low) |
53 | | // Initially cast to unsigned to prevent a left shift that overflows. |
54 | | : v_(int128_internal::BitCastToSigned(static_cast<unsigned __int128>(high) |
55 | | << 64) | |
56 | 0 | low) {} |
57 | | |
58 | | |
59 | 0 | constexpr int128::int128(int v) : v_{v} {} |
60 | | |
61 | | constexpr int128::int128(long v) : v_{v} {} // NOLINT(runtime/int) |
62 | | |
63 | | constexpr int128::int128(long long v) : v_{v} {} // NOLINT(runtime/int) |
64 | | |
65 | 0 | constexpr int128::int128(__int128 v) : v_{v} {} |
66 | | |
67 | | constexpr int128::int128(unsigned int v) : v_{v} {} |
68 | | |
69 | | constexpr int128::int128(unsigned long v) : v_{v} {} // NOLINT(runtime/int) |
70 | | |
71 | | // NOLINTNEXTLINE(runtime/int) |
72 | | constexpr int128::int128(unsigned long long v) : v_{v} {} |
73 | | |
74 | | constexpr int128::int128(unsigned __int128 v) : v_{static_cast<__int128>(v)} {} |
75 | | |
76 | | inline int128::int128(float v) { |
77 | | v_ = static_cast<__int128>(v); |
78 | | } |
79 | | |
80 | | inline int128::int128(double v) { |
81 | | v_ = static_cast<__int128>(v); |
82 | | } |
83 | | |
84 | | inline int128::int128(long double v) { |
85 | | v_ = static_cast<__int128>(v); |
86 | | } |
87 | | |
88 | | constexpr int128::int128(uint128 v) : v_{static_cast<__int128>(v)} {} |
89 | | |
90 | 0 | constexpr int128::operator bool() const { return static_cast<bool>(v_); } |
91 | | |
92 | 0 | constexpr int128::operator char() const { return static_cast<char>(v_); } |
93 | | |
94 | 0 | constexpr int128::operator signed char() const { |
95 | 0 | return static_cast<signed char>(v_); |
96 | 0 | } |
97 | | |
98 | 0 | constexpr int128::operator unsigned char() const { |
99 | 0 | return static_cast<unsigned char>(v_); |
100 | 0 | } |
101 | | |
102 | 0 | constexpr int128::operator char16_t() const { |
103 | 0 | return static_cast<char16_t>(v_); |
104 | 0 | } |
105 | | |
106 | 0 | constexpr int128::operator char32_t() const { |
107 | 0 | return static_cast<char32_t>(v_); |
108 | 0 | } |
109 | | |
110 | 0 | constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const { |
111 | 0 | return static_cast<ABSL_INTERNAL_WCHAR_T>(v_); |
112 | 0 | } |
113 | | |
114 | 0 | constexpr int128::operator short() const { // NOLINT(runtime/int) |
115 | 0 | return static_cast<short>(v_); // NOLINT(runtime/int) |
116 | 0 | } |
117 | | |
118 | 0 | constexpr int128::operator unsigned short() const { // NOLINT(runtime/int) |
119 | 0 | return static_cast<unsigned short>(v_); // NOLINT(runtime/int) |
120 | 0 | } |
121 | | |
122 | 0 | constexpr int128::operator int() const { |
123 | 0 | return static_cast<int>(v_); |
124 | 0 | } |
125 | | |
126 | 0 | constexpr int128::operator unsigned int() const { |
127 | 0 | return static_cast<unsigned int>(v_); |
128 | 0 | } |
129 | | |
130 | 0 | constexpr int128::operator long() const { // NOLINT(runtime/int) |
131 | 0 | return static_cast<long>(v_); // NOLINT(runtime/int) |
132 | 0 | } |
133 | | |
134 | 0 | constexpr int128::operator unsigned long() const { // NOLINT(runtime/int) |
135 | 0 | return static_cast<unsigned long>(v_); // NOLINT(runtime/int) |
136 | 0 | } |
137 | | |
138 | 0 | constexpr int128::operator long long() const { // NOLINT(runtime/int) |
139 | 0 | return static_cast<long long>(v_); // NOLINT(runtime/int) |
140 | 0 | } |
141 | | |
142 | 0 | constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int) |
143 | 0 | return static_cast<unsigned long long>(v_); // NOLINT(runtime/int) |
144 | 0 | } |
145 | | |
146 | 0 | constexpr int128::operator __int128() const { return v_; } |
147 | | |
148 | 0 | constexpr int128::operator unsigned __int128() const { |
149 | 0 | return static_cast<unsigned __int128>(v_); |
150 | 0 | } |
151 | | |
152 | | // Clang on PowerPC sometimes produces incorrect __int128 to floating point |
153 | | // conversions. In that case, we do the conversion with a similar implementation |
154 | | // to the conversion operators in int128_no_intrinsic.inc. |
155 | | #if defined(__clang__) && !defined(__ppc64__) |
156 | 0 | inline int128::operator float() const { return static_cast<float>(v_); } |
157 | | |
158 | 0 | inline int128::operator double() const { return static_cast<double>(v_); } |
159 | | |
160 | 0 | inline int128::operator long double() const { |
161 | 0 | return static_cast<long double>(v_); |
162 | 0 | } |
163 | | |
164 | | #else // Clang on PowerPC |
165 | | |
166 | | inline int128::operator float() const { |
167 | | // We must convert the absolute value and then negate as needed, because |
168 | | // floating point types are typically sign-magnitude. Otherwise, the |
169 | | // difference between the high and low 64 bits when interpreted as two's |
170 | | // complement overwhelms the precision of the mantissa. |
171 | | // |
172 | | // Also check to make sure we don't negate Int128Min() |
173 | | return v_ < 0 && *this != Int128Min() |
174 | | ? -static_cast<float>(-*this) |
175 | | : static_cast<float>(Int128Low64(*this)) + |
176 | | std::ldexp(static_cast<float>(Int128High64(*this)), 64); |
177 | | } |
178 | | |
179 | | inline int128::operator double() const { |
180 | | // See comment in int128::operator float() above. |
181 | | return v_ < 0 && *this != Int128Min() |
182 | | ? -static_cast<double>(-*this) |
183 | | : static_cast<double>(Int128Low64(*this)) + |
184 | | std::ldexp(static_cast<double>(Int128High64(*this)), 64); |
185 | | } |
186 | | |
187 | | inline int128::operator long double() const { |
188 | | // See comment in int128::operator float() above. |
189 | | return v_ < 0 && *this != Int128Min() |
190 | | ? -static_cast<long double>(-*this) |
191 | | : static_cast<long double>(Int128Low64(*this)) + |
192 | | std::ldexp(static_cast<long double>(Int128High64(*this)), |
193 | | 64); |
194 | | } |
195 | | #endif // Clang on PowerPC |
196 | | |
197 | | // Comparison operators. |
198 | | |
199 | 0 | constexpr bool operator==(int128 lhs, int128 rhs) { |
200 | 0 | return static_cast<__int128>(lhs) == static_cast<__int128>(rhs); |
201 | 0 | } |
202 | | |
203 | 0 | constexpr bool operator!=(int128 lhs, int128 rhs) { |
204 | 0 | return static_cast<__int128>(lhs) != static_cast<__int128>(rhs); |
205 | 0 | } |
206 | | |
207 | 0 | constexpr bool operator<(int128 lhs, int128 rhs) { |
208 | 0 | return static_cast<__int128>(lhs) < static_cast<__int128>(rhs); |
209 | 0 | } |
210 | | |
211 | 0 | constexpr bool operator>(int128 lhs, int128 rhs) { |
212 | 0 | return static_cast<__int128>(lhs) > static_cast<__int128>(rhs); |
213 | 0 | } |
214 | | |
215 | 0 | constexpr bool operator<=(int128 lhs, int128 rhs) { |
216 | 0 | return static_cast<__int128>(lhs) <= static_cast<__int128>(rhs); |
217 | 0 | } |
218 | | |
219 | 0 | constexpr bool operator>=(int128 lhs, int128 rhs) { |
220 | 0 | return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs); |
221 | 0 | } |
222 | | |
223 | | // Unary operators. |
224 | | |
225 | 0 | constexpr int128 operator-(int128 v) { return -static_cast<__int128>(v); } |
226 | | |
227 | 0 | constexpr bool operator!(int128 v) { return !static_cast<__int128>(v); } |
228 | | |
229 | 0 | constexpr int128 operator~(int128 val) { return ~static_cast<__int128>(val); } |
230 | | |
231 | | // Arithmetic operators. |
232 | | |
233 | 0 | constexpr int128 operator+(int128 lhs, int128 rhs) { |
234 | 0 | return static_cast<__int128>(lhs) + static_cast<__int128>(rhs); |
235 | 0 | } |
236 | | |
237 | 0 | constexpr int128 operator-(int128 lhs, int128 rhs) { |
238 | 0 | return static_cast<__int128>(lhs) - static_cast<__int128>(rhs); |
239 | 0 | } |
240 | | |
241 | 0 | inline int128 operator*(int128 lhs, int128 rhs) { |
242 | 0 | return static_cast<__int128>(lhs) * static_cast<__int128>(rhs); |
243 | 0 | } |
244 | | |
245 | 0 | inline int128 operator/(int128 lhs, int128 rhs) { |
246 | 0 | return static_cast<__int128>(lhs) / static_cast<__int128>(rhs); |
247 | 0 | } |
248 | | |
249 | 0 | inline int128 operator%(int128 lhs, int128 rhs) { |
250 | 0 | return static_cast<__int128>(lhs) % static_cast<__int128>(rhs); |
251 | 0 | } |
252 | | |
253 | 0 | inline int128 int128::operator++(int) { |
254 | 0 | int128 tmp(*this); |
255 | 0 | ++v_; |
256 | 0 | return tmp; |
257 | 0 | } |
258 | | |
259 | 0 | inline int128 int128::operator--(int) { |
260 | 0 | int128 tmp(*this); |
261 | 0 | --v_; |
262 | 0 | return tmp; |
263 | 0 | } |
264 | | |
265 | 0 | inline int128& int128::operator++() { |
266 | 0 | ++v_; |
267 | 0 | return *this; |
268 | 0 | } |
269 | | |
270 | 0 | inline int128& int128::operator--() { |
271 | 0 | --v_; |
272 | 0 | return *this; |
273 | 0 | } |
274 | | |
275 | 0 | constexpr int128 operator|(int128 lhs, int128 rhs) { |
276 | 0 | return static_cast<__int128>(lhs) | static_cast<__int128>(rhs); |
277 | 0 | } |
278 | | |
279 | 0 | constexpr int128 operator&(int128 lhs, int128 rhs) { |
280 | 0 | return static_cast<__int128>(lhs) & static_cast<__int128>(rhs); |
281 | 0 | } |
282 | | |
283 | 0 | constexpr int128 operator^(int128 lhs, int128 rhs) { |
284 | 0 | return static_cast<__int128>(lhs) ^ static_cast<__int128>(rhs); |
285 | 0 | } |
286 | | |
287 | 0 | constexpr int128 operator<<(int128 lhs, int amount) { |
288 | 0 | return static_cast<__int128>(lhs) << amount; |
289 | 0 | } |
290 | | |
291 | 0 | constexpr int128 operator>>(int128 lhs, int amount) { |
292 | 0 | return static_cast<__int128>(lhs) >> amount; |
293 | 0 | } |