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> decltype(auto)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 _S_masked_Scalar77 _GLIBCXX_SIMD_INTRINSIC static constexpr bool _S_masked(bool __x) 78 { return __x; } 79 80 using _CommonImpl = _CommonImplScalar; 81 using _SimdImpl = _SimdImplScalar; 82 using _MaskImpl = _MaskImplScalar; 83 84 template <typename _Tp, bool = _S_is_valid_v<_Tp>> 85 struct __traits : _InvalidTraits {}; 86 87 template <typename _Tp> 88 struct __traits<_Tp, true> 89 { 90 using _IsValid = true_type; 91 using _SimdImpl = _SimdImplScalar; 92 using _MaskImpl = _MaskImplScalar; 93 using _SimdMember = _Tp; 94 using _MaskMember = bool; 95 96 static constexpr size_t _S_simd_align = alignof(_SimdMember); 97 static constexpr size_t _S_mask_align = alignof(_MaskMember); 98 99 // nothing the user can spell converts to/from simd/simd_mask 100 struct _SimdCastType { _SimdCastType() = delete; }; 101 struct _MaskCastType { _MaskCastType() = delete; }; 102 struct _SimdBase {}; 103 struct _MaskBase {}; 104 }; 105 }; 106 107 // }}} 108 // _CommonImplScalar {{{ 109 struct _CommonImplScalar 110 { 111 // _S_store {{{ 112 template <typename _Tp> 113 _GLIBCXX_SIMD_INTRINSIC static void _S_store(_Tp __x, void* __addr) 114 { __builtin_memcpy(__addr, &__x, sizeof(_Tp)); } 115 116 // }}} 117 // _S_store_bool_array(_BitMask) {{{ 118 template <size_t _Np, bool _Sanitized> 119 _GLIBCXX_SIMD_INTRINSIC static constexpr void 120 _S_store_bool_array(_BitMask<_Np, _Sanitized> __x, bool* __mem) 121 { 122 __make_dependent_t<decltype(__x), _CommonImplBuiltin>::_S_store_bool_array( 123 __x, __mem); 124 } 125 126 // }}} 127 }; 128 129 // }}} 130 // _SimdImplScalar {{{ 131 struct _SimdImplScalar 132 { 133 // member types {{{2 134 using abi_type = simd_abi::scalar; 135 136 template <typename _Tp> 137 using _TypeTag = _Tp*; 138 139 // _S_broadcast {{{2 140 template <typename _Tp> 141 _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp _S_broadcast(_Tp __x) noexcept 142 { return __x; } 143 144 // _S_generator {{{2 145 template <typename _Fp, typename _Tp> 146 _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp _S_generator(_Fp&& __gen, 147 _TypeTag<_Tp>) 148 { return __gen(_SizeConstant<0>()); } 149 150 // _S_load {{{2 151 template <typename _Tp, typename _Up> 152 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_load(const _Up* __mem, 153 _TypeTag<_Tp>) noexcept 154 { return static_cast<_Tp>(__mem[0]); } 155 156 // _S_masked_load {{{2 157 template <typename _Tp, typename _Up> 158 static inline _Tp _S_masked_load(_Tp __merge, bool __k, 159 const _Up* __mem) noexcept 160 { 161 if (__k) 162 __merge = static_cast<_Tp>(__mem[0]); 163 return __merge; 164 } 165 166 // _S_store {{{2 167 template <typename _Tp, typename _Up> 168 static inline void _S_store(_Tp __v, _Up* __mem, _TypeTag<_Tp>) noexcept 169 { __mem[0] = static_cast<_Up>(__v); } 170 171 // _S_masked_store {{{2 172 template <typename _Tp, typename _Up> 173 static inline void _S_masked_store(const _Tp __v, _Up* __mem, 174 const bool __k) noexcept 175 { if (__k) __mem[0] = __v; } 176 177 // _S_negate {{{2 178 template <typename _Tp> 179 static constexpr inline bool _S_negate(_Tp __x) noexcept 180 { return !__x; } 181 182 // _S_reduce {{{2 183 template <typename _Tp, typename _BinaryOperation> 184 static constexpr inline _Tp 185 _S_reduce(const simd<_Tp, simd_abi::scalar>& __x, const _BinaryOperation&) 186 { return __x._M_data; } 187 188 // _S_min, _S_max {{{2 189 template <typename _Tp> 190 static constexpr inline _Tp _S_min(const _Tp __a, const _Tp __b) 191 { return std::min(__a, __b); } 192 193 template <typename _Tp> 194 static constexpr inline _Tp _S_max(const _Tp __a, const _Tp __b) 195 { return std::max(__a, __b); } 196 197 // _S_complement {{{2 198 template <typename _Tp> 199 static constexpr inline _Tp _S_complement(_Tp __x) noexcept 200 { return static_cast<_Tp>(~__x); } 201 202 // _S_unary_minus {{{2 203 template <typename _Tp> 204 static constexpr inline _Tp _S_unary_minus(_Tp __x) noexcept 205 { return static_cast<_Tp>(-__x); } 206 207 // arithmetic operators {{{2 208 template <typename _Tp> 209 static constexpr inline _Tp _S_plus(_Tp __x, _Tp __y) 210 { 211 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 212 + __promote_preserving_unsigned(__y)); 213 } 214 215 template <typename _Tp> 216 static constexpr inline _Tp _S_minus(_Tp __x, _Tp __y) 217 { 218 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 219 - __promote_preserving_unsigned(__y)); 220 } 221 222 template <typename _Tp> 223 static constexpr inline _Tp _S_multiplies(_Tp __x, _Tp __y) 224 { 225 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 226 * __promote_preserving_unsigned(__y)); 227 } 228 229 template <typename _Tp> 230 static constexpr inline _Tp _S_divides(_Tp __x, _Tp __y) 231 { 232 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 233 / __promote_preserving_unsigned(__y)); 234 } 235 236 template <typename _Tp> 237 static constexpr inline _Tp _S_modulus(_Tp __x, _Tp __y) 238 { 239 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 240 % __promote_preserving_unsigned(__y)); 241 } 242 243 template <typename _Tp> 244 static constexpr inline _Tp _S_bit_and(_Tp __x, _Tp __y) 245 { 246 if constexpr (is_floating_point_v<_Tp>) 247 { 248 using _Ip = __int_for_sizeof_t<_Tp>; 249 return __bit_cast<_Tp>(__bit_cast<_Ip>(__x) & __bit_cast<_Ip>(__y)); 250 } 251 else 252 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 253 & __promote_preserving_unsigned(__y)); 254 } 255 256 template <typename _Tp> 257 static constexpr inline _Tp _S_bit_or(_Tp __x, _Tp __y) 258 { 259 if constexpr (is_floating_point_v<_Tp>) 260 { 261 using _Ip = __int_for_sizeof_t<_Tp>; 262 return __bit_cast<_Tp>(__bit_cast<_Ip>(__x) | __bit_cast<_Ip>(__y)); 263 } 264 else 265 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 266 | __promote_preserving_unsigned(__y)); 267 } 268 269 template <typename _Tp> 270 static constexpr inline _Tp _S_bit_xor(_Tp __x, _Tp __y) 271 { 272 if constexpr (is_floating_point_v<_Tp>) 273 { 274 using _Ip = __int_for_sizeof_t<_Tp>; 275 return __bit_cast<_Tp>(__bit_cast<_Ip>(__x) ^ __bit_cast<_Ip>(__y)); 276 } 277 else 278 return static_cast<_Tp>(__promote_preserving_unsigned(__x) 279 ^ __promote_preserving_unsigned(__y)); 280 } 281 282 template <typename _Tp> 283 static constexpr inline _Tp _S_bit_shift_left(_Tp __x, int __y) 284 { return static_cast<_Tp>(__promote_preserving_unsigned(__x) << __y); } 285 286 template <typename _Tp> 287 static constexpr inline _Tp _S_bit_shift_right(_Tp __x, int __y) 288 { return static_cast<_Tp>(__promote_preserving_unsigned(__x) >> __y); } 289 290 // math {{{2 291 // frexp, modf and copysign implemented in simd_math.h 292 template <typename _Tp> 293 using _ST = _SimdTuple<_Tp, simd_abi::scalar>; 294 295 template <typename _Tp> 296 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_acos(_Tp __x) 297 { return std::acos(__x); } 298 299 template <typename _Tp> 300 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_asin(_Tp __x) 301 { return std::asin(__x); } 302 303 template <typename _Tp> 304 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_atan(_Tp __x) 305 { return std::atan(__x); } 306 307 template <typename _Tp> 308 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_cos(_Tp __x) 309 { return std::cos(__x); } 310 311 template <typename _Tp> 312 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_sin(_Tp __x) 313 { return std::sin(__x); } 314 315 template <typename _Tp> 316 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_tan(_Tp __x) 317 { return std::tan(__x); } 318 319 template <typename _Tp> 320 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_acosh(_Tp __x) 321 { return std::acosh(__x); } 322 323 template <typename _Tp> 324 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_asinh(_Tp __x) 325 { return std::asinh(__x); } 326 327 template <typename _Tp> 328 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_atanh(_Tp __x) 329 { return std::atanh(__x); } 330 331 template <typename _Tp> 332 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_cosh(_Tp __x) 333 { return std::cosh(__x); } 334 335 template <typename _Tp> 336 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_sinh(_Tp __x) 337 { return std::sinh(__x); } 338 339 template <typename _Tp> 340 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_tanh(_Tp __x) 341 { return std::tanh(__x); } 342 343 template <typename _Tp> 344 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_atan2(_Tp __x, _Tp __y) 345 { return std::atan2(__x, __y); } 346 347 template <typename _Tp> 348 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_exp(_Tp __x) 349 { return std::exp(__x); } 350 351 template <typename _Tp> 352 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_exp2(_Tp __x) 353 { return std::exp2(__x); } 354 355 template <typename _Tp> 356 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_expm1(_Tp __x) 357 { return std::expm1(__x); } 358 359 template <typename _Tp> 360 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log(_Tp __x) 361 { return std::log(__x); } 362 363 template <typename _Tp> 364 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log10(_Tp __x) 365 { return std::log10(__x); } 366 367 template <typename _Tp> 368 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log1p(_Tp __x) 369 { return std::log1p(__x); } 370 371 template <typename _Tp> 372 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log2(_Tp __x) 373 { return std::log2(__x); } 374 375 template <typename _Tp> 376 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_logb(_Tp __x) 377 { return std::logb(__x); } 378 379 template <typename _Tp> 380 _GLIBCXX_SIMD_INTRINSIC static _ST<int> _S_ilogb(_Tp __x) 381 { return {std::ilogb(__x)}; } 382 383 template <typename _Tp> 384 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_pow(_Tp __x, _Tp __y) 385 { return std::pow(__x, __y); } 386 387 template <typename _Tp> 388 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_abs(_Tp __x) 389 { return std::abs(__x); } 390 391 template <typename _Tp> 392 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fabs(_Tp __x) 393 { return std::fabs(__x); } 394 395 template <typename _Tp> 396 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_sqrt(_Tp __x) 397 { return std::sqrt(__x); } 398 399 template <typename _Tp> 400 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_cbrt(_Tp __x) 401 { return std::cbrt(__x); } 402 403 template <typename _Tp> 404 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_erf(_Tp __x) 405 { return std::erf(__x); } 406 407 template <typename _Tp> 408 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_erfc(_Tp __x) 409 { return std::erfc(__x); } 410 411 template <typename _Tp> 412 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_lgamma(_Tp __x) 413 { return std::lgamma(__x); } 414 415 template <typename _Tp> 416 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_tgamma(_Tp __x) 417 { return std::tgamma(__x); } 418 419 template <typename _Tp> 420 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_trunc(_Tp __x) 421 { return std::trunc(__x); } 422 423 template <typename _Tp> 424 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_floor(_Tp __x) 425 { return std::floor(__x); } 426 427 template <typename _Tp> 428 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_ceil(_Tp __x) 429 { return std::ceil(__x); } 430 431 template <typename _Tp> 432 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_nearbyint(_Tp __x) 433 { return std::nearbyint(__x); } 434 435 template <typename _Tp> 436 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_rint(_Tp __x) 437 { return std::rint(__x); } 438 439 template <typename _Tp> 440 _GLIBCXX_SIMD_INTRINSIC static _ST<long> _S_lrint(_Tp __x) 441 { return {std::lrint(__x)}; } 442 443 template <typename _Tp> 444 _GLIBCXX_SIMD_INTRINSIC static _ST<long long> _S_llrint(_Tp __x) 445 { return {std::llrint(__x)}; } 446 447 template <typename _Tp> 448 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_round(_Tp __x) 449 { return std::round(__x); } 450 451 template <typename _Tp> 452 _GLIBCXX_SIMD_INTRINSIC static _ST<long> _S_lround(_Tp __x) 453 { return {std::lround(__x)}; } 454 455 template <typename _Tp> 456 _GLIBCXX_SIMD_INTRINSIC static _ST<long long> _S_llround(_Tp __x) 457 { return {std::llround(__x)}; } 458 459 template <typename _Tp> 460 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_ldexp(_Tp __x, _ST<int> __y) 461 { return std::ldexp(__x, __y.first); } 462 463 template <typename _Tp> 464 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_scalbn(_Tp __x, _ST<int> __y) 465 { return std::scalbn(__x, __y.first); } 466 467 template <typename _Tp> 468 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_scalbln(_Tp __x, _ST<long> __y) 469 { return std::scalbln(__x, __y.first); } 470 471 template <typename _Tp> 472 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fmod(_Tp __x, _Tp __y) 473 { return std::fmod(__x, __y); } 474 475 template <typename _Tp> 476 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_remainder(_Tp __x, _Tp __y) 477 { return std::remainder(__x, __y); } 478 479 template <typename _Tp> 480 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_nextafter(_Tp __x, _Tp __y) 481 { return std::nextafter(__x, __y); } 482 483 template <typename _Tp> 484 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fdim(_Tp __x, _Tp __y) 485 { return std::fdim(__x, __y); } 486 487 template <typename _Tp> 488 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fmax(_Tp __x, _Tp __y) 489 { return std::fmax(__x, __y); } 490 491 template <typename _Tp> 492 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fmin(_Tp __x, _Tp __y) 493 { return std::fmin(__x, __y); } 494 495 template <typename _Tp> 496 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fma(_Tp __x, _Tp __y, _Tp __z) 497 { return std::fma(__x, __y, __z); } 498 499 template <typename _Tp> 500 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_remquo(_Tp __x, _Tp __y, _ST<int>* __z) 501 { return std::remquo(__x, __y, &__z->first); } 502 503 template <typename _Tp> 504 _GLIBCXX_SIMD_INTRINSIC constexpr static _ST<int> _S_fpclassify(_Tp __x) 505 { return {std::fpclassify(__x)}; } 506 507 template <typename _Tp> 508 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isfinite(_Tp __x) 509 { return std::isfinite(__x); } 510 511 template <typename _Tp> 512 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isinf(_Tp __x) 513 { return std::isinf(__x); } 514 515 template <typename _Tp> 516 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isnan(_Tp __x) 517 { return std::isnan(__x); } 518 519 template <typename _Tp> 520 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isnormal(_Tp __x) 521 { return std::isnormal(__x); } 522 523 template <typename _Tp> 524 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_signbit(_Tp __x) 525 { return std::signbit(__x); } 526 527 template <typename _Tp> 528 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isgreater(_Tp __x, _Tp __y) 529 { return std::isgreater(__x, __y); } 530 531 template <typename _Tp> 532 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isgreaterequal(_Tp __x, 533 _Tp __y) 534 { return std::isgreaterequal(__x, __y); } 535 536 template <typename _Tp> 537 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isless(_Tp __x, _Tp __y) 538 { return std::isless(__x, __y); } 539 540 template <typename _Tp> 541 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_islessequal(_Tp __x, _Tp __y) 542 { return std::islessequal(__x, __y); } 543 544 template <typename _Tp> 545 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_islessgreater(_Tp __x, 546 _Tp __y) 547 { return std::islessgreater(__x, __y); } 548 549 template <typename _Tp> 550 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isunordered(_Tp __x, 551 _Tp __y) 552 { return std::isunordered(__x, __y); } 553 554 // _S_increment & _S_decrement{{{2 555 template <typename _Tp> 556 constexpr static inline void _S_increment(_Tp& __x) 557 { ++__x; } 558 559 template <typename _Tp> 560 constexpr static inline void _S_decrement(_Tp& __x) 561 { --__x; } 562 563 564 // compares {{{2 565 template <typename _Tp> 566 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_equal_to(_Tp __x, _Tp __y) 567 { return __x == __y; } 568 569 template <typename _Tp> 570 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_not_equal_to(_Tp __x, 571 _Tp __y) 572 { return __x != __y; } 573 574 template <typename _Tp> 575 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_less(_Tp __x, _Tp __y) 576 { return __x < __y; } 577 578 template <typename _Tp> 579 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_less_equal(_Tp __x, 580 _Tp __y) 581 { return __x <= __y; } 582 583 // smart_reference access {{{2 584 template <typename _Tp, typename _Up> 585 constexpr static void _S_set(_Tp& __v, [[maybe_unused]] int __i, 586 _Up&& __x) noexcept 587 { 588 _GLIBCXX_DEBUG_ASSERT(__i == 0); 589 __v = static_cast<_Up&&>(__x); 590 } 591 592 // _S_masked_assign {{{2 593 template <typename _Tp> 594 _GLIBCXX_SIMD_INTRINSIC constexpr static void 595 _S_masked_assign(bool __k, _Tp& __lhs, _Tp __rhs) 596 { if (__k) __lhs = __rhs; } 597 598 // _S_masked_cassign {{{2 599 template <typename _Op, typename _Tp> 600 _GLIBCXX_SIMD_INTRINSIC constexpr static void 601 _S_masked_cassign(const bool __k, _Tp& __lhs, const _Tp __rhs, _Op __op) 602 { if (__k) __lhs = __op(_SimdImplScalar{}, __lhs, __rhs); } 603 604 // _S_masked_unary {{{2 605 template <template <typename> class _Op, typename _Tp> 606 _GLIBCXX_SIMD_INTRINSIC constexpr static _Tp _S_masked_unary(const bool __k, 607 const _Tp __v) 608 { return static_cast<_Tp>(__k ? _Op<_Tp>{}(__v) : __v); } 609 610 // }}}2 611 }; 612 613 // }}} 614 // _MaskImplScalar {{{ 615 struct _MaskImplScalar 616 { 617 // member types {{{ 618 template <typename _Tp> 619 using _TypeTag = _Tp*; 620 621 // }}} 622 // _S_broadcast {{{ 623 template <typename> 624 _GLIBCXX_SIMD_INTRINSIC static constexpr bool _S_broadcast(bool __x) 625 { return __x; } 626 627 // }}} 628 // _S_load {{{ 629 template <typename> 630 _GLIBCXX_SIMD_INTRINSIC static constexpr bool _S_load(const bool* __mem) 631 { return __mem[0]; } 632 633 // }}} 634 // _S_to_bits {{{ 635 _GLIBCXX_SIMD_INTRINSIC static constexpr _SanitizedBitMask<1> 636 _S_to_bits(bool __x) 637 { return __x; } 638 639 // }}} 640 // _S_convert {{{ 641 template <typename, bool _Sanitized> 642 _GLIBCXX_SIMD_INTRINSIC static constexpr bool 643 _S_convert(_BitMask<1, _Sanitized> __x) 644 { return __x[0]; } 645 646 template <typename, typename _Up, typename _UAbi> 647 _GLIBCXX_SIMD_INTRINSIC static constexpr bool 648 _S_convert(simd_mask<_Up, _UAbi> __x) 649 { return __x[0]; } 650 651 // }}} 652 // _S_from_bitmask {{{2 653 template <typename _Tp> 654 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 655 _S_from_bitmask(_SanitizedBitMask<1> __bits, _TypeTag<_Tp>) noexcept 656 { return __bits[0]; } 657 658 // _S_masked_load {{{2 659 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 660 _S_masked_load(bool __merge, bool __mask, const bool* __mem) noexcept 661 { 662 if (__mask) 663 __merge = __mem[0]; 664 return __merge; 665 } 666 667 // _S_store {{{2 668 _GLIBCXX_SIMD_INTRINSIC static void _S_store(bool __v, bool* __mem) noexcept 669 { __mem[0] = __v; } 670 671 // _S_masked_store {{{2 672 _GLIBCXX_SIMD_INTRINSIC static void 673 _S_masked_store(const bool __v, bool* __mem, const bool __k) noexcept 674 { 675 if (__k) 676 __mem[0] = __v; 677 } 678 679 // logical and bitwise operators {{{2 680 static constexpr bool _S_logical_and(bool __x, bool __y) 681 { return __x && __y; } 682 683 static constexpr bool _S_logical_or(bool __x, bool __y) 684 { return __x || __y; } 685 686 static constexpr bool _S_bit_not(bool __x) 687 { return !__x; } 688 689 static constexpr bool _S_bit_and(bool __x, bool __y) 690 { return __x && __y; } 691 692 static constexpr bool _S_bit_or(bool __x, bool __y) 693 { return __x || __y; } 694 695 static constexpr bool _S_bit_xor(bool __x, bool __y) 696 { return __x != __y; } 697 698 // smart_reference access {{{2 699 constexpr static void _S_set(bool& __k, [[maybe_unused]] int __i, 700 bool __x) noexcept 701 { 702 _GLIBCXX_DEBUG_ASSERT(__i == 0); 703 __k = __x; 704 } 705 706 // _S_masked_assign {{{2 707 _GLIBCXX_SIMD_INTRINSIC static void _S_masked_assign(bool __k, bool& __lhs, 708 bool __rhs) 709 { 710 if (__k) 711 __lhs = __rhs; 712 } 713 714 // }}}2 715 // _S_all_of {{{ 716 template <typename _Tp, typename _Abi> 717 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 718 _S_all_of(simd_mask<_Tp, _Abi> __k) 719 { return __k._M_data; } 720 721 // }}} 722 // _S_any_of {{{ 723 template <typename _Tp, typename _Abi> 724 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 725 _S_any_of(simd_mask<_Tp, _Abi> __k) 726 { return __k._M_data; } 727 728 // }}} 729 // _S_none_of {{{ 730 template <typename _Tp, typename _Abi> 731 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 732 _S_none_of(simd_mask<_Tp, _Abi> __k) 733 { return !__k._M_data; } 734 735 // }}} 736 // _S_some_of {{{ 737 template <typename _Tp, typename _Abi> 738 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 739 _S_some_of(simd_mask<_Tp, _Abi>) 740 { return false; } 741 742 // }}} 743 // _S_popcount {{{ 744 template <typename _Tp, typename _Abi> 745 _GLIBCXX_SIMD_INTRINSIC constexpr static int 746 _S_popcount(simd_mask<_Tp, _Abi> __k) 747 { return __k._M_data; } 748 749 // }}} 750 // _S_find_first_set {{{ 751 template <typename _Tp, typename _Abi> 752 _GLIBCXX_SIMD_INTRINSIC constexpr static int 753 _S_find_first_set(simd_mask<_Tp, _Abi>) 754 { return 0; } 755 756 // }}} 757 // _S_find_last_set {{{ 758 template <typename _Tp, typename _Abi> 759 _GLIBCXX_SIMD_INTRINSIC constexpr static int 760 _S_find_last_set(simd_mask<_Tp, _Abi>) 761 { return 0; } 762 763 // }}} 764 }; 765 766 // }}} 767 768 _GLIBCXX_SIMD_END_NAMESPACE 769 #endif // __cplusplus >= 201703L 770 #endif // _GLIBCXX_EXPERIMENTAL_SIMD_SCALAR_H_ 771 772 // vim: foldmethod=marker sw=2 noet ts=8 sts=2 tw=80 773