Home | History | Annotate | Line # | Download | only in bits
      1 // Simd scalar ABI specific implementations -*- C++ -*-
      2 
      3 // Copyright (C) 2020-2024 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     _GLIBCXX_SIMD_INTRINSIC 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     _GLIBCXX_SIMD_INTRINSIC 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     _GLIBCXX_SIMD_INTRINSIC 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     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    184     _S_negate(_Tp __x) noexcept
    185     { return !__x; }
    186 
    187   // _S_reduce {{{2
    188   template <typename _Tp, typename _BinaryOperation>
    189     _GLIBCXX_SIMD_INTRINSIC 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 static constexpr _Tp
    196     _S_min(const _Tp __a, const _Tp __b)
    197     { return std::min(__a, __b); }
    198 
    199   template <typename _Tp>
    200     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp
    207     _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 static constexpr _Tp
    213     _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 static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr _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     _GLIBCXX_SIMD_INTRINSIC static constexpr void
    637     _S_increment(_Tp& __x)
    638     { ++__x; }
    639 
    640   template <typename _Tp>
    641     _GLIBCXX_SIMD_INTRINSIC static constexpr void
    642     _S_decrement(_Tp& __x)
    643     { --__x; }
    644 
    645 
    646   // compares {{{2
    647   template <typename _Tp>
    648     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    649     _S_equal_to(_Tp __x, _Tp __y)
    650     { return __x == __y; }
    651 
    652   template <typename _Tp>
    653     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    654     _S_not_equal_to(_Tp __x, _Tp __y)
    655     { return __x != __y; }
    656 
    657   template <typename _Tp>
    658     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    659     _S_less(_Tp __x, _Tp __y)
    660     { return __x < __y; }
    661 
    662   template <typename _Tp>
    663     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    664     _S_less_equal(_Tp __x, _Tp __y)
    665     { return __x <= __y; }
    666 
    667   // smart_reference access {{{2
    668   template <typename _Tp, typename _Up>
    669     _GLIBCXX_SIMD_INTRINSIC static constexpr void
    670     _S_set(_Tp& __v, [[maybe_unused]] int __i, _Up&& __x) noexcept
    671     {
    672       _GLIBCXX_DEBUG_ASSERT(__i == 0);
    673       __v = static_cast<_Up&&>(__x);
    674     }
    675 
    676   // _S_masked_assign {{{2
    677   template <typename _Tp>
    678     _GLIBCXX_SIMD_INTRINSIC static constexpr void
    679     _S_masked_assign(bool __k, _Tp& __lhs, _Tp __rhs)
    680     { if (__k) __lhs = __rhs; }
    681 
    682   // _S_masked_cassign {{{2
    683   template <typename _Op, typename _Tp>
    684     _GLIBCXX_SIMD_INTRINSIC static constexpr void
    685     _S_masked_cassign(const bool __k, _Tp& __lhs, const _Tp __rhs, _Op __op)
    686     { if (__k) __lhs = __op(_SimdImplScalar{}, __lhs, __rhs); }
    687 
    688   // _S_masked_unary {{{2
    689   template <template <typename> class _Op, typename _Tp>
    690     _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp
    691     _S_masked_unary(const bool __k, const _Tp __v)
    692     { return static_cast<_Tp>(__k ? _Op<_Tp>{}(__v) : __v); }
    693 
    694   // }}}2
    695 };
    696 
    697 // }}}
    698 // _MaskImplScalar {{{
    699 struct _MaskImplScalar
    700 {
    701   // member types {{{
    702   template <typename _Tp>
    703     using _TypeTag = _Tp*;
    704 
    705   // }}}
    706   // _S_broadcast {{{
    707   template <typename>
    708     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    709     _S_broadcast(bool __x)
    710     { return __x; }
    711 
    712   // }}}
    713   // _S_load {{{
    714   template <typename>
    715     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    716     _S_load(const bool* __mem)
    717     { return __mem[0]; }
    718 
    719   // }}}
    720   // _S_to_bits {{{
    721   _GLIBCXX_SIMD_INTRINSIC static constexpr _SanitizedBitMask<1>
    722   _S_to_bits(bool __x)
    723   { return __x; }
    724 
    725   // }}}
    726   // _S_convert {{{
    727   template <typename, bool _Sanitized>
    728     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    729     _S_convert(_BitMask<1, _Sanitized> __x)
    730     { return __x[0]; }
    731 
    732   template <typename, typename _Up, typename _UAbi>
    733     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    734     _S_convert(simd_mask<_Up, _UAbi> __x)
    735     { return __x[0]; }
    736 
    737   // }}}
    738   // _S_from_bitmask {{{2
    739   template <typename _Tp>
    740     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    741     _S_from_bitmask(_SanitizedBitMask<1> __bits, _TypeTag<_Tp>) noexcept
    742     { return __bits[0]; }
    743 
    744   // _S_masked_load {{{2
    745   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    746   _S_masked_load(bool __merge, bool __mask, const bool* __mem) noexcept
    747   {
    748     if (__mask)
    749       __merge = __mem[0];
    750     return __merge;
    751   }
    752 
    753   // _S_store {{{2
    754   _GLIBCXX_SIMD_INTRINSIC static constexpr void
    755   _S_store(bool __v, bool* __mem) noexcept
    756   { __mem[0] = __v; }
    757 
    758   // _S_masked_store {{{2
    759   _GLIBCXX_SIMD_INTRINSIC static constexpr void
    760   _S_masked_store(const bool __v, bool* __mem, const bool __k) noexcept
    761   {
    762     if (__k)
    763       __mem[0] = __v;
    764   }
    765 
    766   // logical and bitwise operators {{{2
    767   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    768   _S_logical_and(bool __x, bool __y)
    769   { return __x && __y; }
    770 
    771   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    772   _S_logical_or(bool __x, bool __y)
    773   { return __x || __y; }
    774 
    775   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    776   _S_bit_not(bool __x)
    777   { return !__x; }
    778 
    779   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    780   _S_bit_and(bool __x, bool __y)
    781   { return __x && __y; }
    782 
    783   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    784   _S_bit_or(bool __x, bool __y)
    785   { return __x || __y; }
    786 
    787   _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    788   _S_bit_xor(bool __x, bool __y)
    789   { return __x != __y; }
    790 
    791   // smart_reference access {{{2
    792   _GLIBCXX_SIMD_INTRINSIC static constexpr void
    793   _S_set(bool& __k, [[maybe_unused]] int __i, bool __x) noexcept
    794   {
    795     _GLIBCXX_DEBUG_ASSERT(__i == 0);
    796     __k = __x;
    797   }
    798 
    799   // _S_masked_assign {{{2
    800   _GLIBCXX_SIMD_INTRINSIC static constexpr void
    801   _S_masked_assign(bool __k, bool& __lhs, bool __rhs)
    802   {
    803     if (__k)
    804       __lhs = __rhs;
    805   }
    806 
    807   // }}}2
    808   // _S_all_of {{{
    809   template <typename _Tp, typename _Abi>
    810     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    811     _S_all_of(simd_mask<_Tp, _Abi> __k)
    812     { return __k._M_data; }
    813 
    814   // }}}
    815   // _S_any_of {{{
    816   template <typename _Tp, typename _Abi>
    817     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    818     _S_any_of(simd_mask<_Tp, _Abi> __k)
    819     { return __k._M_data; }
    820 
    821   // }}}
    822   // _S_none_of {{{
    823   template <typename _Tp, typename _Abi>
    824     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    825     _S_none_of(simd_mask<_Tp, _Abi> __k)
    826     { return !__k._M_data; }
    827 
    828   // }}}
    829   // _S_some_of {{{
    830   template <typename _Tp, typename _Abi>
    831     _GLIBCXX_SIMD_INTRINSIC static constexpr bool
    832     _S_some_of(simd_mask<_Tp, _Abi>)
    833     { return false; }
    834 
    835   // }}}
    836   // _S_popcount {{{
    837   template <typename _Tp, typename _Abi>
    838     _GLIBCXX_SIMD_INTRINSIC static constexpr int
    839     _S_popcount(simd_mask<_Tp, _Abi> __k)
    840     { return __k._M_data; }
    841 
    842   // }}}
    843   // _S_find_first_set {{{
    844   template <typename _Tp, typename _Abi>
    845     _GLIBCXX_SIMD_INTRINSIC static constexpr int
    846     _S_find_first_set(simd_mask<_Tp, _Abi>)
    847     { return 0; }
    848 
    849   // }}}
    850   // _S_find_last_set {{{
    851   template <typename _Tp, typename _Abi>
    852     _GLIBCXX_SIMD_INTRINSIC static constexpr int
    853     _S_find_last_set(simd_mask<_Tp, _Abi>)
    854     { return 0; }
    855 
    856   // }}}
    857 };
    858 
    859 // }}}
    860 
    861 _GLIBCXX_SIMD_END_NAMESPACE
    862 #endif // __cplusplus >= 201703L
    863 #endif // _GLIBCXX_EXPERIMENTAL_SIMD_SCALAR_H_
    864 
    865 // vim: foldmethod=marker sw=2 noet ts=8 sts=2 tw=80
    866