1 // Simd scalar ABI specific implementations -*- C++ -*- 2 3 // Copyright (C) 2020-2022 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 _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 _GLIBCXX_SIMD_INTRINSIC 159 static _Tp _S_masked_load(_Tp __merge, bool __k, 160 const _Up* __mem) noexcept 161 { 162 if (__k) 163 __merge = static_cast<_Tp>(__mem[0]); 164 return __merge; 165 } 166 167 // _S_store {{{2 168 template <typename _Tp, typename _Up> 169 _GLIBCXX_SIMD_INTRINSIC 170 static void _S_store(_Tp __v, _Up* __mem, _TypeTag<_Tp>) noexcept 171 { __mem[0] = static_cast<_Up>(__v); } 172 173 // _S_masked_store {{{2 174 template <typename _Tp, typename _Up> 175 _GLIBCXX_SIMD_INTRINSIC 176 static void _S_masked_store(const _Tp __v, _Up* __mem, 177 const bool __k) noexcept 178 { if (__k) __mem[0] = __v; } 179 180 // _S_negate {{{2 181 template <typename _Tp> 182 _GLIBCXX_SIMD_INTRINSIC 183 static constexpr bool _S_negate(_Tp __x) noexcept 184 { return !__x; } 185 186 // _S_reduce {{{2 187 template <typename _Tp, typename _BinaryOperation> 188 _GLIBCXX_SIMD_INTRINSIC 189 static constexpr _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 _GLIBCXX_SIMD_INTRINSIC 196 static constexpr _Tp _S_min(const _Tp __a, const _Tp __b) 197 { return std::min(__a, __b); } 198 199 template <typename _Tp> 200 _GLIBCXX_SIMD_INTRINSIC 201 static constexpr _Tp _S_max(const _Tp __a, const _Tp __b) 202 { return std::max(__a, __b); } 203 204 // _S_complement {{{2 205 template <typename _Tp> 206 _GLIBCXX_SIMD_INTRINSIC 207 static constexpr _Tp _S_complement(_Tp __x) noexcept 208 { return static_cast<_Tp>(~__x); } 209 210 // _S_unary_minus {{{2 211 template <typename _Tp> 212 _GLIBCXX_SIMD_INTRINSIC 213 static constexpr _Tp _S_unary_minus(_Tp __x) noexcept 214 { return static_cast<_Tp>(-__x); } 215 216 // arithmetic operators {{{2 217 template <typename _Tp> 218 _GLIBCXX_SIMD_INTRINSIC 219 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 227 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 235 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 243 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 251 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 259 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 273 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 287 static constexpr _Tp _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 _GLIBCXX_SIMD_INTRINSIC 301 static constexpr _Tp _S_bit_shift_left(_Tp __x, int __y) 302 { return static_cast<_Tp>(__promote_preserving_unsigned(__x) << __y); } 303 304 template <typename _Tp> 305 _GLIBCXX_SIMD_INTRINSIC 306 static constexpr _Tp _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 _S_acos(_Tp __x) 316 { return std::acos(__x); } 317 318 template <typename _Tp> 319 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_asin(_Tp __x) 320 { return std::asin(__x); } 321 322 template <typename _Tp> 323 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_atan(_Tp __x) 324 { return std::atan(__x); } 325 326 template <typename _Tp> 327 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_cos(_Tp __x) 328 { return std::cos(__x); } 329 330 template <typename _Tp> 331 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_sin(_Tp __x) 332 { return std::sin(__x); } 333 334 template <typename _Tp> 335 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_tan(_Tp __x) 336 { return std::tan(__x); } 337 338 template <typename _Tp> 339 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_acosh(_Tp __x) 340 { return std::acosh(__x); } 341 342 template <typename _Tp> 343 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_asinh(_Tp __x) 344 { return std::asinh(__x); } 345 346 template <typename _Tp> 347 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_atanh(_Tp __x) 348 { return std::atanh(__x); } 349 350 template <typename _Tp> 351 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_cosh(_Tp __x) 352 { return std::cosh(__x); } 353 354 template <typename _Tp> 355 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_sinh(_Tp __x) 356 { return std::sinh(__x); } 357 358 template <typename _Tp> 359 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_tanh(_Tp __x) 360 { return std::tanh(__x); } 361 362 template <typename _Tp> 363 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_atan2(_Tp __x, _Tp __y) 364 { return std::atan2(__x, __y); } 365 366 template <typename _Tp> 367 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_exp(_Tp __x) 368 { return std::exp(__x); } 369 370 template <typename _Tp> 371 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_exp2(_Tp __x) 372 { return std::exp2(__x); } 373 374 template <typename _Tp> 375 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_expm1(_Tp __x) 376 { return std::expm1(__x); } 377 378 template <typename _Tp> 379 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log(_Tp __x) 380 { return std::log(__x); } 381 382 template <typename _Tp> 383 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log10(_Tp __x) 384 { return std::log10(__x); } 385 386 template <typename _Tp> 387 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log1p(_Tp __x) 388 { return std::log1p(__x); } 389 390 template <typename _Tp> 391 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_log2(_Tp __x) 392 { return std::log2(__x); } 393 394 template <typename _Tp> 395 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_logb(_Tp __x) 396 { return std::logb(__x); } 397 398 template <typename _Tp> 399 _GLIBCXX_SIMD_INTRINSIC static _ST<int> _S_ilogb(_Tp __x) 400 { return {std::ilogb(__x)}; } 401 402 template <typename _Tp> 403 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_pow(_Tp __x, _Tp __y) 404 { return std::pow(__x, __y); } 405 406 template <typename _Tp> 407 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_abs(_Tp __x) 408 { return std::abs(__x); } 409 410 template <typename _Tp> 411 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fabs(_Tp __x) 412 { return std::fabs(__x); } 413 414 template <typename _Tp> 415 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_sqrt(_Tp __x) 416 { return std::sqrt(__x); } 417 418 template <typename _Tp> 419 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_cbrt(_Tp __x) 420 { return std::cbrt(__x); } 421 422 template <typename _Tp> 423 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_erf(_Tp __x) 424 { return std::erf(__x); } 425 426 template <typename _Tp> 427 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_erfc(_Tp __x) 428 { return std::erfc(__x); } 429 430 template <typename _Tp> 431 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_lgamma(_Tp __x) 432 { return std::lgamma(__x); } 433 434 template <typename _Tp> 435 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_tgamma(_Tp __x) 436 { return std::tgamma(__x); } 437 438 template <typename _Tp> 439 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_trunc(_Tp __x) 440 { return std::trunc(__x); } 441 442 template <typename _Tp> 443 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_floor(_Tp __x) 444 { return std::floor(__x); } 445 446 template <typename _Tp> 447 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_ceil(_Tp __x) 448 { return std::ceil(__x); } 449 450 template <typename _Tp> 451 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_nearbyint(_Tp __x) 452 { return std::nearbyint(__x); } 453 454 template <typename _Tp> 455 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_rint(_Tp __x) 456 { return std::rint(__x); } 457 458 template <typename _Tp> 459 _GLIBCXX_SIMD_INTRINSIC static _ST<long> _S_lrint(_Tp __x) 460 { return {std::lrint(__x)}; } 461 462 template <typename _Tp> 463 _GLIBCXX_SIMD_INTRINSIC static _ST<long long> _S_llrint(_Tp __x) 464 { return {std::llrint(__x)}; } 465 466 template <typename _Tp> 467 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_round(_Tp __x) 468 { return std::round(__x); } 469 470 template <typename _Tp> 471 _GLIBCXX_SIMD_INTRINSIC static _ST<long> _S_lround(_Tp __x) 472 { return {std::lround(__x)}; } 473 474 template <typename _Tp> 475 _GLIBCXX_SIMD_INTRINSIC static _ST<long long> _S_llround(_Tp __x) 476 { return {std::llround(__x)}; } 477 478 template <typename _Tp> 479 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_ldexp(_Tp __x, _ST<int> __y) 480 { return std::ldexp(__x, __y.first); } 481 482 template <typename _Tp> 483 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_scalbn(_Tp __x, _ST<int> __y) 484 { return std::scalbn(__x, __y.first); } 485 486 template <typename _Tp> 487 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_scalbln(_Tp __x, _ST<long> __y) 488 { return std::scalbln(__x, __y.first); } 489 490 template <typename _Tp> 491 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fmod(_Tp __x, _Tp __y) 492 { return std::fmod(__x, __y); } 493 494 template <typename _Tp> 495 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_remainder(_Tp __x, _Tp __y) 496 { return std::remainder(__x, __y); } 497 498 template <typename _Tp> 499 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_nextafter(_Tp __x, _Tp __y) 500 { return std::nextafter(__x, __y); } 501 502 template <typename _Tp> 503 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fdim(_Tp __x, _Tp __y) 504 { return std::fdim(__x, __y); } 505 506 template <typename _Tp> 507 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fmax(_Tp __x, _Tp __y) 508 { return std::fmax(__x, __y); } 509 510 template <typename _Tp> 511 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fmin(_Tp __x, _Tp __y) 512 { return std::fmin(__x, __y); } 513 514 template <typename _Tp> 515 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_fma(_Tp __x, _Tp __y, _Tp __z) 516 { return std::fma(__x, __y, __z); } 517 518 template <typename _Tp> 519 _GLIBCXX_SIMD_INTRINSIC static _Tp _S_remquo(_Tp __x, _Tp __y, _ST<int>* __z) 520 { return std::remquo(__x, __y, &__z->first); } 521 522 template <typename _Tp> 523 _GLIBCXX_SIMD_INTRINSIC constexpr static _ST<int> _S_fpclassify(_Tp __x) 524 { return {std::fpclassify(__x)}; } 525 526 template <typename _Tp> 527 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isfinite(_Tp __x) 528 { return std::isfinite(__x); } 529 530 template <typename _Tp> 531 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isinf(_Tp __x) 532 { return std::isinf(__x); } 533 534 template <typename _Tp> 535 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isnan(_Tp __x) 536 { return std::isnan(__x); } 537 538 template <typename _Tp> 539 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isnormal(_Tp __x) 540 { return std::isnormal(__x); } 541 542 template <typename _Tp> 543 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_signbit(_Tp __x) 544 { return std::signbit(__x); } 545 546 template <typename _Tp> 547 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isgreater(_Tp __x, _Tp __y) 548 { return std::isgreater(__x, __y); } 549 550 template <typename _Tp> 551 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isgreaterequal(_Tp __x, 552 _Tp __y) 553 { return std::isgreaterequal(__x, __y); } 554 555 template <typename _Tp> 556 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isless(_Tp __x, _Tp __y) 557 { return std::isless(__x, __y); } 558 559 template <typename _Tp> 560 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_islessequal(_Tp __x, _Tp __y) 561 { return std::islessequal(__x, __y); } 562 563 template <typename _Tp> 564 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_islessgreater(_Tp __x, 565 _Tp __y) 566 { return std::islessgreater(__x, __y); } 567 568 template <typename _Tp> 569 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_isunordered(_Tp __x, 570 _Tp __y) 571 { return std::isunordered(__x, __y); } 572 573 // _S_increment & _S_decrement{{{2 574 template <typename _Tp> 575 _GLIBCXX_SIMD_INTRINSIC 576 constexpr static void _S_increment(_Tp& __x) 577 { ++__x; } 578 579 template <typename _Tp> 580 _GLIBCXX_SIMD_INTRINSIC 581 constexpr static void _S_decrement(_Tp& __x) 582 { --__x; } 583 584 585 // compares {{{2 586 template <typename _Tp> 587 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_equal_to(_Tp __x, _Tp __y) 588 { return __x == __y; } 589 590 template <typename _Tp> 591 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_not_equal_to(_Tp __x, 592 _Tp __y) 593 { return __x != __y; } 594 595 template <typename _Tp> 596 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_less(_Tp __x, _Tp __y) 597 { return __x < __y; } 598 599 template <typename _Tp> 600 _GLIBCXX_SIMD_INTRINSIC constexpr static bool _S_less_equal(_Tp __x, 601 _Tp __y) 602 { return __x <= __y; } 603 604 // smart_reference access {{{2 605 template <typename _Tp, typename _Up> 606 _GLIBCXX_SIMD_INTRINSIC 607 constexpr static void _S_set(_Tp& __v, [[maybe_unused]] int __i, 608 _Up&& __x) noexcept 609 { 610 _GLIBCXX_DEBUG_ASSERT(__i == 0); 611 __v = static_cast<_Up&&>(__x); 612 } 613 614 // _S_masked_assign {{{2 615 template <typename _Tp> 616 _GLIBCXX_SIMD_INTRINSIC constexpr static void 617 _S_masked_assign(bool __k, _Tp& __lhs, _Tp __rhs) 618 { if (__k) __lhs = __rhs; } 619 620 // _S_masked_cassign {{{2 621 template <typename _Op, typename _Tp> 622 _GLIBCXX_SIMD_INTRINSIC constexpr static void 623 _S_masked_cassign(const bool __k, _Tp& __lhs, const _Tp __rhs, _Op __op) 624 { if (__k) __lhs = __op(_SimdImplScalar{}, __lhs, __rhs); } 625 626 // _S_masked_unary {{{2 627 template <template <typename> class _Op, typename _Tp> 628 _GLIBCXX_SIMD_INTRINSIC constexpr static _Tp _S_masked_unary(const bool __k, 629 const _Tp __v) 630 { return static_cast<_Tp>(__k ? _Op<_Tp>{}(__v) : __v); } 631 632 // }}}2 633 }; 634 635 // }}} 636 // _MaskImplScalar {{{ 637 struct _MaskImplScalar 638 { 639 // member types {{{ 640 template <typename _Tp> 641 using _TypeTag = _Tp*; 642 643 // }}} 644 // _S_broadcast {{{ 645 template <typename> 646 _GLIBCXX_SIMD_INTRINSIC static constexpr bool _S_broadcast(bool __x) 647 { return __x; } 648 649 // }}} 650 // _S_load {{{ 651 template <typename> 652 _GLIBCXX_SIMD_INTRINSIC static constexpr bool _S_load(const bool* __mem) 653 { return __mem[0]; } 654 655 // }}} 656 // _S_to_bits {{{ 657 _GLIBCXX_SIMD_INTRINSIC static constexpr _SanitizedBitMask<1> 658 _S_to_bits(bool __x) 659 { return __x; } 660 661 // }}} 662 // _S_convert {{{ 663 template <typename, bool _Sanitized> 664 _GLIBCXX_SIMD_INTRINSIC static constexpr bool 665 _S_convert(_BitMask<1, _Sanitized> __x) 666 { return __x[0]; } 667 668 template <typename, typename _Up, typename _UAbi> 669 _GLIBCXX_SIMD_INTRINSIC static constexpr bool 670 _S_convert(simd_mask<_Up, _UAbi> __x) 671 { return __x[0]; } 672 673 // }}} 674 // _S_from_bitmask {{{2 675 template <typename _Tp> 676 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 677 _S_from_bitmask(_SanitizedBitMask<1> __bits, _TypeTag<_Tp>) noexcept 678 { return __bits[0]; } 679 680 // _S_masked_load {{{2 681 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 682 _S_masked_load(bool __merge, bool __mask, const bool* __mem) noexcept 683 { 684 if (__mask) 685 __merge = __mem[0]; 686 return __merge; 687 } 688 689 // _S_store {{{2 690 _GLIBCXX_SIMD_INTRINSIC static void _S_store(bool __v, bool* __mem) noexcept 691 { __mem[0] = __v; } 692 693 // _S_masked_store {{{2 694 _GLIBCXX_SIMD_INTRINSIC static void 695 _S_masked_store(const bool __v, bool* __mem, const bool __k) noexcept 696 { 697 if (__k) 698 __mem[0] = __v; 699 } 700 701 // logical and bitwise operators {{{2 702 _GLIBCXX_SIMD_INTRINSIC 703 static constexpr bool _S_logical_and(bool __x, bool __y) 704 { return __x && __y; } 705 706 _GLIBCXX_SIMD_INTRINSIC 707 static constexpr bool _S_logical_or(bool __x, bool __y) 708 { return __x || __y; } 709 710 _GLIBCXX_SIMD_INTRINSIC 711 static constexpr bool _S_bit_not(bool __x) 712 { return !__x; } 713 714 _GLIBCXX_SIMD_INTRINSIC 715 static constexpr bool _S_bit_and(bool __x, bool __y) 716 { return __x && __y; } 717 718 _GLIBCXX_SIMD_INTRINSIC 719 static constexpr bool _S_bit_or(bool __x, bool __y) 720 { return __x || __y; } 721 722 _GLIBCXX_SIMD_INTRINSIC 723 static constexpr bool _S_bit_xor(bool __x, bool __y) 724 { return __x != __y; } 725 726 // smart_reference access {{{2 727 _GLIBCXX_SIMD_INTRINSIC 728 constexpr static void _S_set(bool& __k, [[maybe_unused]] int __i, 729 bool __x) noexcept 730 { 731 _GLIBCXX_DEBUG_ASSERT(__i == 0); 732 __k = __x; 733 } 734 735 // _S_masked_assign {{{2 736 _GLIBCXX_SIMD_INTRINSIC static void _S_masked_assign(bool __k, bool& __lhs, 737 bool __rhs) 738 { 739 if (__k) 740 __lhs = __rhs; 741 } 742 743 // }}}2 744 // _S_all_of {{{ 745 template <typename _Tp, typename _Abi> 746 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 747 _S_all_of(simd_mask<_Tp, _Abi> __k) 748 { return __k._M_data; } 749 750 // }}} 751 // _S_any_of {{{ 752 template <typename _Tp, typename _Abi> 753 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 754 _S_any_of(simd_mask<_Tp, _Abi> __k) 755 { return __k._M_data; } 756 757 // }}} 758 // _S_none_of {{{ 759 template <typename _Tp, typename _Abi> 760 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 761 _S_none_of(simd_mask<_Tp, _Abi> __k) 762 { return !__k._M_data; } 763 764 // }}} 765 // _S_some_of {{{ 766 template <typename _Tp, typename _Abi> 767 _GLIBCXX_SIMD_INTRINSIC constexpr static bool 768 _S_some_of(simd_mask<_Tp, _Abi>) 769 { return false; } 770 771 // }}} 772 // _S_popcount {{{ 773 template <typename _Tp, typename _Abi> 774 _GLIBCXX_SIMD_INTRINSIC constexpr static int 775 _S_popcount(simd_mask<_Tp, _Abi> __k) 776 { return __k._M_data; } 777 778 // }}} 779 // _S_find_first_set {{{ 780 template <typename _Tp, typename _Abi> 781 _GLIBCXX_SIMD_INTRINSIC constexpr static int 782 _S_find_first_set(simd_mask<_Tp, _Abi>) 783 { return 0; } 784 785 // }}} 786 // _S_find_last_set {{{ 787 template <typename _Tp, typename _Abi> 788 _GLIBCXX_SIMD_INTRINSIC constexpr static int 789 _S_find_last_set(simd_mask<_Tp, _Abi>) 790 { return 0; } 791 792 // }}} 793 }; 794 795 // }}} 796 797 _GLIBCXX_SIMD_END_NAMESPACE 798 #endif // __cplusplus >= 201703L 799 #endif // _GLIBCXX_EXPERIMENTAL_SIMD_SCALAR_H_ 800 801 // vim: foldmethod=marker sw=2 noet ts=8 sts=2 tw=80 802