1 | // Simd scalar ABI specific implementations -*- C++ -*- |
2 | |
3 | // Copyright (C) 2020-2021 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | #ifndef _GLIBCXX_EXPERIMENTAL_SIMD_SCALAR_H_ |
26 | #define _GLIBCXX_EXPERIMENTAL_SIMD_SCALAR_H_ |
27 | #if __cplusplus >= 201703L |
28 | |
29 | #include <cmath> |
30 | |
31 | _GLIBCXX_SIMD_BEGIN_NAMESPACE |
32 | |
33 | // __promote_preserving_unsigned{{{ |
34 | // work around crazy semantics of unsigned integers of lower rank than int: |
35 | // Before applying an operator the operands are promoted to int. In which case |
36 | // over- or underflow is UB, even though the operand types were unsigned. |
37 | template <typename _Tp> |
38 | _GLIBCXX_SIMD_INTRINSIC constexpr decltype(auto) |
39 | __promote_preserving_unsigned(const _Tp& __x) |
40 | { |
41 | if constexpr (is_signed_v<decltype(+__x)> && is_unsigned_v<_Tp>) |
42 | return static_cast<unsigned int>(__x); |
43 | else |
44 | return __x; |
45 | } |
46 | |
47 | // }}} |
48 | |
49 | struct _CommonImplScalar; |
50 | struct _CommonImplBuiltin; |
51 | struct _SimdImplScalar; |
52 | struct _MaskImplScalar; |
53 | |
54 | // simd_abi::_Scalar {{{ |
55 | struct simd_abi::_Scalar |
56 | { |
57 | template <typename _Tp> |
58 | static constexpr size_t _S_size = 1; |
59 | |
60 | template <typename _Tp> |
61 | static constexpr size_t _S_full_size = 1; |
62 | |
63 | template <typename _Tp> |
64 | static constexpr bool _S_is_partial = false; |
65 | |
66 | struct _IsValidAbiTag : true_type {}; |
67 | |
68 | template <typename _Tp> |
69 | struct _IsValidSizeFor : true_type {}; |
70 | |
71 | template <typename _Tp> |
72 | struct _IsValid : __is_vectorizable<_Tp> {}; |
73 | |
74 | template <typename _Tp> |
75 | static constexpr bool _S_is_valid_v = _IsValid<_Tp>::value; |
76 | |
77 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
78 | _S_masked(bool __x) |
79 | { return __x; } |
80 | |
81 | using _CommonImpl = _CommonImplScalar; |
82 | using _SimdImpl = _SimdImplScalar; |
83 | using _MaskImpl = _MaskImplScalar; |
84 | |
85 | template <typename _Tp, bool = _S_is_valid_v<_Tp>> |
86 | struct __traits : _InvalidTraits {}; |
87 | |
88 | template <typename _Tp> |
89 | struct __traits<_Tp, true> |
90 | { |
91 | using _IsValid = true_type; |
92 | using _SimdImpl = _SimdImplScalar; |
93 | using _MaskImpl = _MaskImplScalar; |
94 | using _SimdMember = _Tp; |
95 | using _MaskMember = bool; |
96 | |
97 | static constexpr size_t _S_simd_align = alignof(_SimdMember); |
98 | static constexpr size_t _S_mask_align = alignof(_MaskMember); |
99 | |
100 | // nothing the user can spell converts to/from simd/simd_mask |
101 | struct _SimdCastType { _SimdCastType() = delete; }; |
102 | struct _MaskCastType { _MaskCastType() = delete; }; |
103 | struct _SimdBase {}; |
104 | struct _MaskBase {}; |
105 | }; |
106 | }; |
107 | |
108 | // }}} |
109 | // _CommonImplScalar {{{ |
110 | struct _CommonImplScalar |
111 | { |
112 | // _S_store {{{ |
113 | template <typename _Tp> |
114 | _GLIBCXX_SIMD_INTRINSIC static void |
115 | _S_store(_Tp __x, void* __addr) |
116 | { __builtin_memcpy(__addr, &__x, sizeof(_Tp)); } |
117 | |
118 | // }}} |
119 | // _S_store_bool_array(_BitMask) {{{ |
120 | template <size_t _Np, bool _Sanitized> |
121 | _GLIBCXX_SIMD_INTRINSIC static constexpr void |
122 | _S_store_bool_array(_BitMask<_Np, _Sanitized> __x, bool* __mem) |
123 | { |
124 | __make_dependent_t<decltype(__x), _CommonImplBuiltin>::_S_store_bool_array( |
125 | __x, __mem); |
126 | } |
127 | |
128 | // }}} |
129 | }; |
130 | |
131 | // }}} |
132 | // _SimdImplScalar {{{ |
133 | struct _SimdImplScalar |
134 | { |
135 | // member types {{{2 |
136 | using abi_type = simd_abi::scalar; |
137 | |
138 | template <typename _Tp> |
139 | using _TypeTag = _Tp*; |
140 | |
141 | // _S_broadcast {{{2 |
142 | template <typename _Tp> |
143 | _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp |
144 | _S_broadcast(_Tp __x) noexcept |
145 | { return __x; } |
146 | |
147 | // _S_generator {{{2 |
148 | template <typename _Fp, typename _Tp> |
149 | _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp |
150 | _S_generator(_Fp&& __gen, _TypeTag<_Tp>) |
151 | { return __gen(_SizeConstant<0>()); } |
152 | |
153 | // _S_load {{{2 |
154 | template <typename _Tp, typename _Up> |
155 | _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp |
156 | _S_load(const _Up* __mem, _TypeTag<_Tp>) noexcept |
157 | { return static_cast<_Tp>(__mem[0]); } |
158 | |
159 | // _S_masked_load {{{2 |
160 | template <typename _Tp, typename _Up> |
161 | static constexpr _Tp |
162 | _S_masked_load(_Tp __merge, bool __k, const _Up* __mem) noexcept |
163 | { |
164 | if (__k) |
165 | __merge = static_cast<_Tp>(__mem[0]); |
166 | return __merge; |
167 | } |
168 | |
169 | // _S_store {{{2 |
170 | template <typename _Tp, typename _Up> |
171 | static constexpr void |
172 | _S_store(_Tp __v, _Up* __mem, _TypeTag<_Tp>) noexcept |
173 | { __mem[0] = static_cast<_Up>(__v); } |
174 | |
175 | // _S_masked_store {{{2 |
176 | template <typename _Tp, typename _Up> |
177 | static constexpr void |
178 | _S_masked_store(const _Tp __v, _Up* __mem, const bool __k) noexcept |
179 | { if (__k) __mem[0] = __v; } |
180 | |
181 | // _S_negate {{{2 |
182 | template <typename _Tp> |
183 | static constexpr inline bool |
184 | _S_negate(_Tp __x) noexcept |
185 | { return !__x; } |
186 | |
187 | // _S_reduce {{{2 |
188 | template <typename _Tp, typename _BinaryOperation> |
189 | static constexpr inline _Tp |
190 | _S_reduce(const simd<_Tp, simd_abi::scalar>& __x, const _BinaryOperation&) |
191 | { return __x._M_data; } |
192 | |
193 | // _S_min, _S_max {{{2 |
194 | template <typename _Tp> |
195 | static constexpr inline _Tp |
196 | _S_min(const _Tp __a, const _Tp __b) |
197 | { return std::min(__a, __b); } |
198 | |
199 | template <typename _Tp> |
200 | static constexpr inline _Tp |
201 | _S_max(const _Tp __a, const _Tp __b) |
202 | { return std::max(__a, __b); } |
203 | |
204 | // _S_complement {{{2 |
205 | template <typename _Tp> |
206 | static constexpr inline _Tp |
207 | _S_complement(_Tp __x) noexcept |
208 | { return static_cast<_Tp>(~__x); } |
209 | |
210 | // _S_unary_minus {{{2 |
211 | template <typename _Tp> |
212 | static constexpr inline _Tp |
213 | _S_unary_minus(_Tp __x) noexcept |
214 | { return static_cast<_Tp>(-__x); } |
215 | |
216 | // arithmetic operators {{{2 |
217 | template <typename _Tp> |
218 | static constexpr inline _Tp |
219 | _S_plus(_Tp __x, _Tp __y) |
220 | { |
221 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
222 | + __promote_preserving_unsigned(__y)); |
223 | } |
224 | |
225 | template <typename _Tp> |
226 | static constexpr inline _Tp |
227 | _S_minus(_Tp __x, _Tp __y) |
228 | { |
229 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
230 | - __promote_preserving_unsigned(__y)); |
231 | } |
232 | |
233 | template <typename _Tp> |
234 | static constexpr inline _Tp |
235 | _S_multiplies(_Tp __x, _Tp __y) |
236 | { |
237 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
238 | * __promote_preserving_unsigned(__y)); |
239 | } |
240 | |
241 | template <typename _Tp> |
242 | static constexpr inline _Tp |
243 | _S_divides(_Tp __x, _Tp __y) |
244 | { |
245 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
246 | / __promote_preserving_unsigned(__y)); |
247 | } |
248 | |
249 | template <typename _Tp> |
250 | static constexpr inline _Tp |
251 | _S_modulus(_Tp __x, _Tp __y) |
252 | { |
253 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
254 | % __promote_preserving_unsigned(__y)); |
255 | } |
256 | |
257 | template <typename _Tp> |
258 | static constexpr inline _Tp |
259 | _S_bit_and(_Tp __x, _Tp __y) |
260 | { |
261 | if constexpr (is_floating_point_v<_Tp>) |
262 | { |
263 | using _Ip = __int_for_sizeof_t<_Tp>; |
264 | return __bit_cast<_Tp>(__bit_cast<_Ip>(__x) & __bit_cast<_Ip>(__y)); |
265 | } |
266 | else |
267 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
268 | & __promote_preserving_unsigned(__y)); |
269 | } |
270 | |
271 | template <typename _Tp> |
272 | static constexpr inline _Tp |
273 | _S_bit_or(_Tp __x, _Tp __y) |
274 | { |
275 | if constexpr (is_floating_point_v<_Tp>) |
276 | { |
277 | using _Ip = __int_for_sizeof_t<_Tp>; |
278 | return __bit_cast<_Tp>(__bit_cast<_Ip>(__x) | __bit_cast<_Ip>(__y)); |
279 | } |
280 | else |
281 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
282 | | __promote_preserving_unsigned(__y)); |
283 | } |
284 | |
285 | template <typename _Tp> |
286 | static constexpr inline _Tp |
287 | _S_bit_xor(_Tp __x, _Tp __y) |
288 | { |
289 | if constexpr (is_floating_point_v<_Tp>) |
290 | { |
291 | using _Ip = __int_for_sizeof_t<_Tp>; |
292 | return __bit_cast<_Tp>(__bit_cast<_Ip>(__x) ^ __bit_cast<_Ip>(__y)); |
293 | } |
294 | else |
295 | return static_cast<_Tp>(__promote_preserving_unsigned(__x) |
296 | ^ __promote_preserving_unsigned(__y)); |
297 | } |
298 | |
299 | template <typename _Tp> |
300 | static constexpr inline _Tp |
301 | _S_bit_shift_left(_Tp __x, int __y) |
302 | { return static_cast<_Tp>(__promote_preserving_unsigned(__x) << __y); } |
303 | |
304 | template <typename _Tp> |
305 | static constexpr inline _Tp |
306 | _S_bit_shift_right(_Tp __x, int __y) |
307 | { return static_cast<_Tp>(__promote_preserving_unsigned(__x) >> __y); } |
308 | |
309 | // math {{{2 |
310 | // frexp, modf and copysign implemented in simd_math.h |
311 | template <typename _Tp> |
312 | using _ST = _SimdTuple<_Tp, simd_abi::scalar>; |
313 | |
314 | template <typename _Tp> |
315 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
316 | _S_acos(_Tp __x) |
317 | { return std::acos(__x); } |
318 | |
319 | template <typename _Tp> |
320 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
321 | _S_asin(_Tp __x) |
322 | { return std::asin(__x); } |
323 | |
324 | template <typename _Tp> |
325 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
326 | _S_atan(_Tp __x) |
327 | { return std::atan(__x); } |
328 | |
329 | template <typename _Tp> |
330 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
331 | _S_cos(_Tp __x) |
332 | { return std::cos(__x); } |
333 | |
334 | template <typename _Tp> |
335 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
336 | _S_sin(_Tp __x) |
337 | { return std::sin(__x); } |
338 | |
339 | template <typename _Tp> |
340 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
341 | _S_tan(_Tp __x) |
342 | { return std::tan(__x); } |
343 | |
344 | template <typename _Tp> |
345 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
346 | _S_acosh(_Tp __x) |
347 | { return std::acosh(__x); } |
348 | |
349 | template <typename _Tp> |
350 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
351 | _S_asinh(_Tp __x) |
352 | { return std::asinh(__x); } |
353 | |
354 | template <typename _Tp> |
355 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
356 | _S_atanh(_Tp __x) |
357 | { return std::atanh(__x); } |
358 | |
359 | template <typename _Tp> |
360 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
361 | _S_cosh(_Tp __x) |
362 | { return std::cosh(__x); } |
363 | |
364 | template <typename _Tp> |
365 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
366 | _S_sinh(_Tp __x) |
367 | { return std::sinh(__x); } |
368 | |
369 | template <typename _Tp> |
370 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
371 | _S_tanh(_Tp __x) |
372 | { return std::tanh(__x); } |
373 | |
374 | template <typename _Tp> |
375 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
376 | _S_atan2(_Tp __x, _Tp __y) |
377 | { return std::atan2(__x, __y); } |
378 | |
379 | template <typename _Tp> |
380 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
381 | _S_exp(_Tp __x) |
382 | { return std::exp(__x); } |
383 | |
384 | template <typename _Tp> |
385 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
386 | _S_exp2(_Tp __x) |
387 | { return std::exp2(__x); } |
388 | |
389 | template <typename _Tp> |
390 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
391 | _S_expm1(_Tp __x) |
392 | { return std::expm1(__x); } |
393 | |
394 | template <typename _Tp> |
395 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
396 | _S_log(_Tp __x) |
397 | { return std::log(__x); } |
398 | |
399 | template <typename _Tp> |
400 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
401 | _S_log10(_Tp __x) |
402 | { return std::log10(__x); } |
403 | |
404 | template <typename _Tp> |
405 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
406 | _S_log1p(_Tp __x) |
407 | { return std::log1p(__x); } |
408 | |
409 | template <typename _Tp> |
410 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
411 | _S_log2(_Tp __x) |
412 | { return std::log2(__x); } |
413 | |
414 | template <typename _Tp> |
415 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
416 | _S_logb(_Tp __x) |
417 | { return std::logb(__x); } |
418 | |
419 | template <typename _Tp> |
420 | _GLIBCXX_SIMD_INTRINSIC static _ST<int> |
421 | _S_ilogb(_Tp __x) |
422 | { return {std::ilogb(__x)}; } |
423 | |
424 | template <typename _Tp> |
425 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
426 | _S_pow(_Tp __x, _Tp __y) |
427 | { return std::pow(__x, __y); } |
428 | |
429 | template <typename _Tp> |
430 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
431 | _S_abs(_Tp __x) |
432 | { return std::abs(__x); } |
433 | |
434 | template <typename _Tp> |
435 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
436 | _S_fabs(_Tp __x) |
437 | { return std::fabs(__x); } |
438 | |
439 | template <typename _Tp> |
440 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
441 | _S_sqrt(_Tp __x) |
442 | { return std::sqrt(__x); } |
443 | |
444 | template <typename _Tp> |
445 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
446 | _S_cbrt(_Tp __x) |
447 | { return std::cbrt(__x); } |
448 | |
449 | template <typename _Tp> |
450 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
451 | _S_erf(_Tp __x) |
452 | { return std::erf(__x); } |
453 | |
454 | template <typename _Tp> |
455 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
456 | _S_erfc(_Tp __x) |
457 | { return std::erfc(__x); } |
458 | |
459 | template <typename _Tp> |
460 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
461 | _S_lgamma(_Tp __x) |
462 | { return std::lgamma(__x); } |
463 | |
464 | template <typename _Tp> |
465 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
466 | _S_tgamma(_Tp __x) |
467 | { return std::tgamma(__x); } |
468 | |
469 | template <typename _Tp> |
470 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
471 | _S_trunc(_Tp __x) |
472 | { return std::trunc(__x); } |
473 | |
474 | template <typename _Tp> |
475 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
476 | _S_floor(_Tp __x) |
477 | { return std::floor(__x); } |
478 | |
479 | template <typename _Tp> |
480 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
481 | _S_ceil(_Tp __x) |
482 | { return std::ceil(__x); } |
483 | |
484 | template <typename _Tp> |
485 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
486 | _S_nearbyint(_Tp __x) |
487 | { return std::nearbyint(__x); } |
488 | |
489 | template <typename _Tp> |
490 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
491 | _S_rint(_Tp __x) |
492 | { return std::rint(__x); } |
493 | |
494 | template <typename _Tp> |
495 | _GLIBCXX_SIMD_INTRINSIC static _ST<long> |
496 | _S_lrint(_Tp __x) |
497 | { return {std::lrint(__x)}; } |
498 | |
499 | template <typename _Tp> |
500 | _GLIBCXX_SIMD_INTRINSIC static _ST<long long> |
501 | _S_llrint(_Tp __x) |
502 | { return {std::llrint(__x)}; } |
503 | |
504 | template <typename _Tp> |
505 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
506 | _S_round(_Tp __x) |
507 | { return std::round(__x); } |
508 | |
509 | template <typename _Tp> |
510 | _GLIBCXX_SIMD_INTRINSIC static _ST<long> |
511 | _S_lround(_Tp __x) |
512 | { return {std::lround(__x)}; } |
513 | |
514 | template <typename _Tp> |
515 | _GLIBCXX_SIMD_INTRINSIC static _ST<long long> |
516 | _S_llround(_Tp __x) |
517 | { return {std::llround(__x)}; } |
518 | |
519 | template <typename _Tp> |
520 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
521 | _S_ldexp(_Tp __x, _ST<int> __y) |
522 | { return std::ldexp(__x, __y.first); } |
523 | |
524 | template <typename _Tp> |
525 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
526 | _S_scalbn(_Tp __x, _ST<int> __y) |
527 | { return std::scalbn(__x, __y.first); } |
528 | |
529 | template <typename _Tp> |
530 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
531 | _S_scalbln(_Tp __x, _ST<long> __y) |
532 | { return std::scalbln(__x, __y.first); } |
533 | |
534 | template <typename _Tp> |
535 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
536 | _S_fmod(_Tp __x, _Tp __y) |
537 | { return std::fmod(__x, __y); } |
538 | |
539 | template <typename _Tp> |
540 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
541 | _S_remainder(_Tp __x, _Tp __y) |
542 | { return std::remainder(__x, __y); } |
543 | |
544 | template <typename _Tp> |
545 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
546 | _S_nextafter(_Tp __x, _Tp __y) |
547 | { return std::nextafter(__x, __y); } |
548 | |
549 | template <typename _Tp> |
550 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
551 | _S_fdim(_Tp __x, _Tp __y) |
552 | { return std::fdim(__x, __y); } |
553 | |
554 | template <typename _Tp> |
555 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
556 | _S_fmax(_Tp __x, _Tp __y) |
557 | { return std::fmax(__x, __y); } |
558 | |
559 | template <typename _Tp> |
560 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
561 | _S_fmin(_Tp __x, _Tp __y) |
562 | { return std::fmin(__x, __y); } |
563 | |
564 | template <typename _Tp> |
565 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
566 | _S_fma(_Tp __x, _Tp __y, _Tp __z) |
567 | { return std::fma(__x, __y, __z); } |
568 | |
569 | template <typename _Tp> |
570 | _GLIBCXX_SIMD_INTRINSIC static _Tp |
571 | _S_remquo(_Tp __x, _Tp __y, _ST<int>* __z) |
572 | { return std::remquo(__x, __y, &__z->first); } |
573 | |
574 | template <typename _Tp> |
575 | _GLIBCXX_SIMD_INTRINSIC static constexpr _ST<int> |
576 | _S_fpclassify(_Tp __x) |
577 | { return {std::fpclassify(__x)}; } |
578 | |
579 | template <typename _Tp> |
580 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
581 | _S_isfinite(_Tp __x) |
582 | { return std::isfinite(__x); } |
583 | |
584 | template <typename _Tp> |
585 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
586 | _S_isinf(_Tp __x) |
587 | { return std::isinf(__x); } |
588 | |
589 | template <typename _Tp> |
590 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
591 | _S_isnan(_Tp __x) |
592 | { return std::isnan(__x); } |
593 | |
594 | template <typename _Tp> |
595 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
596 | _S_isnormal(_Tp __x) |
597 | { return std::isnormal(__x); } |
598 | |
599 | template <typename _Tp> |
600 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
601 | _S_signbit(_Tp __x) |
602 | { return std::signbit(__x); } |
603 | |
604 | template <typename _Tp> |
605 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
606 | _S_isgreater(_Tp __x, _Tp __y) |
607 | { return std::isgreater(__x, __y); } |
608 | |
609 | template <typename _Tp> |
610 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
611 | _S_isgreaterequal(_Tp __x, _Tp __y) |
612 | { return std::isgreaterequal(__x, __y); } |
613 | |
614 | template <typename _Tp> |
615 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
616 | _S_isless(_Tp __x, _Tp __y) |
617 | { return std::isless(__x, __y); } |
618 | |
619 | template <typename _Tp> |
620 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
621 | _S_islessequal(_Tp __x, _Tp __y) |
622 | { return std::islessequal(__x, __y); } |
623 | |
624 | template <typename _Tp> |
625 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
626 | _S_islessgreater(_Tp __x, _Tp __y) |
627 | { return std::islessgreater(__x, __y); } |
628 | |
629 | template <typename _Tp> |
630 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
631 | _S_isunordered(_Tp __x, _Tp __y) |
632 | { return std::isunordered(__x, __y); } |
633 | |
634 | // _S_increment & _S_decrement{{{2 |
635 | template <typename _Tp> |
636 | static constexpr void |
637 | _S_increment(_Tp& __x) |
638 | { ++__x; } |
639 | |
640 | template <typename _Tp> |
641 | static constexpr void |
642 | _S_decrement(_Tp& __x) |
643 | { --__x; } |
644 | |
645 | // compares {{{2 |
646 | template <typename _Tp> |
647 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
648 | _S_equal_to(_Tp __x, _Tp __y) |
649 | { return __x == __y; } |
650 | |
651 | template <typename _Tp> |
652 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
653 | _S_not_equal_to(_Tp __x, _Tp __y) |
654 | { return __x != __y; } |
655 | |
656 | template <typename _Tp> |
657 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
658 | _S_less(_Tp __x, _Tp __y) |
659 | { return __x < __y; } |
660 | |
661 | template <typename _Tp> |
662 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
663 | _S_less_equal(_Tp __x, _Tp __y) |
664 | { return __x <= __y; } |
665 | |
666 | // smart_reference access {{{2 |
667 | template <typename _Tp, typename _Up> |
668 | static constexpr void |
669 | _S_set(_Tp& __v, [[maybe_unused]] int __i, _Up&& __x) noexcept |
670 | { |
671 | _GLIBCXX_DEBUG_ASSERT(__i == 0); |
672 | __v = static_cast<_Up&&>(__x); |
673 | } |
674 | |
675 | // _S_masked_assign {{{2 |
676 | template <typename _Tp> |
677 | _GLIBCXX_SIMD_INTRINSIC static constexpr void |
678 | _S_masked_assign(bool __k, _Tp& __lhs, _Tp __rhs) |
679 | { if (__k) __lhs = __rhs; } |
680 | |
681 | // _S_masked_cassign {{{2 |
682 | template <typename _Op, typename _Tp> |
683 | _GLIBCXX_SIMD_INTRINSIC static constexpr void |
684 | _S_masked_cassign(const bool __k, _Tp& __lhs, const _Tp __rhs, _Op __op) |
685 | { if (__k) __lhs = __op(_SimdImplScalar{}, __lhs, __rhs); } |
686 | |
687 | // _S_masked_unary {{{2 |
688 | template <template <typename> class _Op, typename _Tp> |
689 | _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp |
690 | _S_masked_unary(const bool __k, const _Tp __v) |
691 | { return static_cast<_Tp>(__k ? _Op<_Tp>{}(__v) : __v); } |
692 | |
693 | // }}}2 |
694 | }; |
695 | |
696 | // }}} |
697 | // _MaskImplScalar {{{ |
698 | struct _MaskImplScalar |
699 | { |
700 | // member types {{{ |
701 | template <typename _Tp> |
702 | using _TypeTag = _Tp*; |
703 | |
704 | // }}} |
705 | // _S_broadcast {{{ |
706 | template <typename> |
707 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
708 | _S_broadcast(bool __x) |
709 | { return __x; } |
710 | |
711 | // }}} |
712 | // _S_load {{{ |
713 | template <typename> |
714 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
715 | _S_load(const bool* __mem) |
716 | { return __mem[0]; } |
717 | |
718 | // }}} |
719 | // _S_to_bits {{{ |
720 | _GLIBCXX_SIMD_INTRINSIC static constexpr _SanitizedBitMask<1> |
721 | _S_to_bits(bool __x) |
722 | { return __x; } |
723 | |
724 | // }}} |
725 | // _S_convert {{{ |
726 | template <typename, bool _Sanitized> |
727 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
728 | _S_convert(_BitMask<1, _Sanitized> __x) |
729 | { return __x[0]; } |
730 | |
731 | template <typename, typename _Up, typename _UAbi> |
732 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
733 | _S_convert(simd_mask<_Up, _UAbi> __x) |
734 | { return __x[0]; } |
735 | |
736 | // }}} |
737 | // _S_from_bitmask {{{2 |
738 | template <typename _Tp> |
739 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
740 | _S_from_bitmask(_SanitizedBitMask<1> __bits, _TypeTag<_Tp>) noexcept |
741 | { return __bits[0]; } |
742 | |
743 | // _S_masked_load {{{2 |
744 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
745 | _S_masked_load(bool __merge, bool __mask, const bool* __mem) noexcept |
746 | { |
747 | if (__mask) |
748 | __merge = __mem[0]; |
749 | return __merge; |
750 | } |
751 | |
752 | // _S_store {{{2 |
753 | _GLIBCXX_SIMD_INTRINSIC static constexpr void |
754 | _S_store(bool __v, bool* __mem) noexcept |
755 | { __mem[0] = __v; } |
756 | |
757 | // _S_masked_store {{{2 |
758 | _GLIBCXX_SIMD_INTRINSIC static constexpr void |
759 | _S_masked_store(const bool __v, bool* __mem, const bool __k) noexcept |
760 | { |
761 | if (__k) |
762 | __mem[0] = __v; |
763 | } |
764 | |
765 | // logical and bitwise operators {{{2 |
766 | static constexpr bool |
767 | _S_logical_and(bool __x, bool __y) |
768 | { return __x && __y; } |
769 | |
770 | static constexpr bool |
771 | _S_logical_or(bool __x, bool __y) |
772 | { return __x || __y; } |
773 | |
774 | static constexpr bool |
775 | _S_bit_not(bool __x) |
776 | { return !__x; } |
777 | |
778 | static constexpr bool |
779 | _S_bit_and(bool __x, bool __y) |
780 | { return __x && __y; } |
781 | |
782 | static constexpr bool |
783 | _S_bit_or(bool __x, bool __y) |
784 | { return __x || __y; } |
785 | |
786 | static constexpr bool |
787 | _S_bit_xor(bool __x, bool __y) |
788 | { return __x != __y; } |
789 | |
790 | // smart_reference access {{{2 |
791 | static constexpr void |
792 | _S_set(bool& __k, [[maybe_unused]] int __i, bool __x) noexcept |
793 | { |
794 | _GLIBCXX_DEBUG_ASSERT(__i == 0); |
795 | __k = __x; |
796 | } |
797 | |
798 | // _S_masked_assign {{{2 |
799 | _GLIBCXX_SIMD_INTRINSIC static constexpr void |
800 | _S_masked_assign(bool __k, bool& __lhs, bool __rhs) |
801 | { |
802 | if (__k) |
803 | __lhs = __rhs; |
804 | } |
805 | |
806 | // }}}2 |
807 | // _S_all_of {{{ |
808 | template <typename _Tp, typename _Abi> |
809 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
810 | _S_all_of(simd_mask<_Tp, _Abi> __k) |
811 | { return __k._M_data; } |
812 | |
813 | // }}} |
814 | // _S_any_of {{{ |
815 | template <typename _Tp, typename _Abi> |
816 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
817 | _S_any_of(simd_mask<_Tp, _Abi> __k) |
818 | { return __k._M_data; } |
819 | |
820 | // }}} |
821 | // _S_none_of {{{ |
822 | template <typename _Tp, typename _Abi> |
823 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
824 | _S_none_of(simd_mask<_Tp, _Abi> __k) |
825 | { return !__k._M_data; } |
826 | |
827 | // }}} |
828 | // _S_some_of {{{ |
829 | template <typename _Tp, typename _Abi> |
830 | _GLIBCXX_SIMD_INTRINSIC static constexpr bool |
831 | _S_some_of(simd_mask<_Tp, _Abi>) |
832 | { return false; } |
833 | |
834 | // }}} |
835 | // _S_popcount {{{ |
836 | template <typename _Tp, typename _Abi> |
837 | _GLIBCXX_SIMD_INTRINSIC static constexpr int |
838 | _S_popcount(simd_mask<_Tp, _Abi> __k) |
839 | { return __k._M_data; } |
840 | |
841 | // }}} |
842 | // _S_find_first_set {{{ |
843 | template <typename _Tp, typename _Abi> |
844 | _GLIBCXX_SIMD_INTRINSIC static constexpr int |
845 | _S_find_first_set(simd_mask<_Tp, _Abi>) |
846 | { return 0; } |
847 | |
848 | // }}} |
849 | // _S_find_last_set {{{ |
850 | template <typename _Tp, typename _Abi> |
851 | _GLIBCXX_SIMD_INTRINSIC static constexpr int |
852 | _S_find_last_set(simd_mask<_Tp, _Abi>) |
853 | { return 0; } |
854 | |
855 | // }}} |
856 | }; |
857 | |
858 | // }}} |
859 | |
860 | _GLIBCXX_SIMD_END_NAMESPACE |
861 | #endif // __cplusplus >= 201703L |
862 | #endif // _GLIBCXX_EXPERIMENTAL_SIMD_SCALAR_H_ |
863 | |
864 | // vim: foldmethod=marker sw=2 noet ts=8 sts=2 tw=80 |
865 | |