(root)/
gcc-13.2.0/
libstdc++-v3/
include/
experimental/
bits/
simd_scalar.h
       1  // Simd scalar ABI specific implementations -*- C++ -*-
       2  
       3  // Copyright (C) 2020-2023 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