libstdc++
simd.h
1 // Definition of the public simd interfaces -*- C++ -*-
2 
3 // Copyright (C) 2020-2026 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_H
26 #define _GLIBCXX_EXPERIMENTAL_SIMD_H
27 
28 #if __cplusplus >= 201703L
29 
30 #include "simd_detail.h"
31 #include "numeric_traits.h"
32 #include <bit>
33 #include <bitset>
34 #ifdef _GLIBCXX_DEBUG_UB
35 #include <cstdio> // for stderr
36 #endif
37 #include <cstring>
38 #include <cmath>
39 #include <functional>
40 #include <iosfwd>
41 #include <utility>
42 #include <algorithm>
43 
44 #if _GLIBCXX_SIMD_X86INTRIN
45 #include <x86intrin.h>
46 #elif _GLIBCXX_SIMD_HAVE_NEON
47 #pragma GCC diagnostic push
48 // narrowing conversion of '__a' from 'uint64_t' {aka 'long long unsigned int'} to
49 // 'int64x1_t' {aka 'long long int'} [-Wnarrowing]
50 #pragma GCC diagnostic ignored "-Wnarrowing"
51 #include <arm_neon.h>
52 #pragma GCC diagnostic pop
53 #endif
54 #if _GLIBCXX_SIMD_HAVE_SVE
55 #include <arm_sve.h>
56 #endif
57 
58 /** @ingroup ts_simd
59  * @{
60  */
61 /* There are several closely related types, with the following naming
62  * convention:
63  * _Tp: vectorizable (arithmetic) type (or any type)
64  * _TV: __vector_type_t<_Tp, _Np>
65  * _TW: _SimdWrapper<_Tp, _Np>
66  * _TI: __intrinsic_type_t<_Tp, _Np>
67  * _TVT: _VectorTraits<_TV> or _VectorTraits<_TW>
68  * If one additional type is needed use _U instead of _T.
69  * Otherwise use _T\d, _TV\d, _TW\d, TI\d, _TVT\d.
70  *
71  * More naming conventions:
72  * _Ap or _Abi: An ABI tag from the simd_abi namespace
73  * _Ip: often used for integer types with sizeof(_Ip) == sizeof(_Tp),
74  * _IV, _IW as for _TV, _TW
75  * _Np: number of elements (not bytes)
76  * _Bytes: number of bytes
77  *
78  * Variable names:
79  * __k: mask object (vector- or bitmask)
80  */
81 _GLIBCXX_SIMD_BEGIN_NAMESPACE
82 
83 #if !_GLIBCXX_SIMD_X86INTRIN
84 using __m128 [[__gnu__::__vector_size__(16)]] = float;
85 using __m128d [[__gnu__::__vector_size__(16)]] = double;
86 using __m128i [[__gnu__::__vector_size__(16)]] = long long;
87 using __m256 [[__gnu__::__vector_size__(32)]] = float;
88 using __m256d [[__gnu__::__vector_size__(32)]] = double;
89 using __m256i [[__gnu__::__vector_size__(32)]] = long long;
90 using __m512 [[__gnu__::__vector_size__(64)]] = float;
91 using __m512d [[__gnu__::__vector_size__(64)]] = double;
92 using __m512i [[__gnu__::__vector_size__(64)]] = long long;
93 #endif
94 
95 #if _GLIBCXX_SIMD_HAVE_SVE
96 constexpr inline int __sve_vectorized_size_bytes = __ARM_FEATURE_SVE_BITS / 8;
97 #else
98 constexpr inline int __sve_vectorized_size_bytes = 0;
99 #endif
100 
101 namespace simd_abi {
102 // simd_abi forward declarations {{{
103 // implementation details:
104 struct _Scalar;
105 
106 template <int _Np>
107  struct _Fixed;
108 
109 // There are two major ABIs that appear on different architectures.
110 // Both have non-boolean values packed into an N Byte register
111 // -> #elements = N / sizeof(T)
112 // Masks differ:
113 // 1. Use value vector registers for masks (all 0 or all 1)
114 // 2. Use bitmasks (mask registers) with one bit per value in the corresponding
115 // value vector
116 //
117 // Both can be partially used, masking off the rest when doing horizontal
118 // operations or operations that can trap (e.g. FP_INVALID or integer division
119 // by 0). This is encoded as the number of used bytes.
120 template <int _UsedBytes>
121  struct _VecBuiltin;
122 
123 template <int _UsedBytes>
124  struct _VecBltnBtmsk;
125 
126 template <int _UsedBytes, int _TotalBytes = __sve_vectorized_size_bytes>
127  struct _SveAbi;
128 
129 template <typename _Tp, int _Np>
130  using _VecN = _VecBuiltin<sizeof(_Tp) * _Np>;
131 
132 template <int _UsedBytes = 16>
133  using _Sse = _VecBuiltin<_UsedBytes>;
134 
135 template <int _UsedBytes = 32>
136  using _Avx = _VecBuiltin<_UsedBytes>;
137 
138 template <int _UsedBytes = 64>
139  using _Avx512 = _VecBltnBtmsk<_UsedBytes>;
140 
141 template <int _UsedBytes = 16>
142  using _Neon = _VecBuiltin<_UsedBytes>;
143 
144 template <int _UsedBytes = __sve_vectorized_size_bytes>
145  using _Sve = _SveAbi<_UsedBytes, __sve_vectorized_size_bytes>;
146 
147 // implementation-defined:
148 using __sse = _Sse<>;
149 using __avx = _Avx<>;
150 using __avx512 = _Avx512<>;
151 using __neon = _Neon<>;
152 using __neon128 = _Neon<16>;
153 using __neon64 = _Neon<8>;
154 using __sve = _Sve<>;
155 
156 // standard:
157 template <typename _Tp, size_t _Np, typename...>
158  struct deduce;
159 
160 template <int _Np>
161  using fixed_size = _Fixed<_Np>;
162 
163 using scalar = _Scalar;
164 
165 // }}}
166 } // namespace simd_abi
167 // forward declarations is_simd(_mask), simd(_mask), simd_size {{{
168 template <typename _Tp>
169  struct is_simd;
170 
171 template <typename _Tp>
172  struct is_simd_mask;
173 
174 template <typename _Tp, typename _Abi>
175  class simd;
176 
177 template <typename _Tp, typename _Abi>
178  class simd_mask;
179 
180 template <typename _Tp, typename _Abi>
181  struct simd_size;
182 
183 // }}}
184 // load/store flags {{{
185 struct element_aligned_tag
186 {
187  template <typename _Tp, typename _Up = typename _Tp::value_type>
188  static constexpr size_t _S_alignment = alignof(_Up);
189 
190  template <typename _Tp, typename _Up>
191  _GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
192  _S_apply(_Up* __ptr)
193  { return __ptr; }
194 };
195 
196 struct vector_aligned_tag
197 {
198  template <typename _Tp, typename _Up = typename _Tp::value_type>
199  static constexpr size_t _S_alignment
200  = std::__bit_ceil(sizeof(_Up) * _Tp::size());
201 
202  template <typename _Tp, typename _Up>
203  _GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
204  _S_apply(_Up* __ptr)
205  { return static_cast<_Up*>(__builtin_assume_aligned(__ptr, _S_alignment<_Tp, _Up>)); }
206 };
207 
208 template <size_t _Np> struct overaligned_tag
209 {
210  template <typename _Tp, typename _Up = typename _Tp::value_type>
211  static constexpr size_t _S_alignment = _Np;
212 
213  template <typename _Tp, typename _Up>
214  _GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
215  _S_apply(_Up* __ptr)
216  { return static_cast<_Up*>(__builtin_assume_aligned(__ptr, _Np)); }
217 };
218 
219 inline constexpr element_aligned_tag element_aligned = {};
220 
221 inline constexpr vector_aligned_tag vector_aligned = {};
222 
223 template <size_t _Np>
224  inline constexpr overaligned_tag<_Np> overaligned = {};
225 
226 // }}}
227 template <size_t _Xp>
228  using _SizeConstant = integral_constant<size_t, _Xp>;
229 // constexpr feature detection{{{
230 constexpr inline bool __have_mmx = _GLIBCXX_SIMD_HAVE_MMX;
231 constexpr inline bool __have_sse = _GLIBCXX_SIMD_HAVE_SSE;
232 constexpr inline bool __have_sse2 = _GLIBCXX_SIMD_HAVE_SSE2;
233 constexpr inline bool __have_sse3 = _GLIBCXX_SIMD_HAVE_SSE3;
234 constexpr inline bool __have_ssse3 = _GLIBCXX_SIMD_HAVE_SSSE3;
235 constexpr inline bool __have_sse4_1 = _GLIBCXX_SIMD_HAVE_SSE4_1;
236 constexpr inline bool __have_sse4_2 = _GLIBCXX_SIMD_HAVE_SSE4_2;
237 constexpr inline bool __have_xop = _GLIBCXX_SIMD_HAVE_XOP;
238 constexpr inline bool __have_avx = _GLIBCXX_SIMD_HAVE_AVX;
239 constexpr inline bool __have_avx2 = _GLIBCXX_SIMD_HAVE_AVX2;
240 constexpr inline bool __have_bmi = _GLIBCXX_SIMD_HAVE_BMI1;
241 constexpr inline bool __have_bmi2 = _GLIBCXX_SIMD_HAVE_BMI2;
242 constexpr inline bool __have_lzcnt = _GLIBCXX_SIMD_HAVE_LZCNT;
243 constexpr inline bool __have_sse4a = _GLIBCXX_SIMD_HAVE_SSE4A;
244 constexpr inline bool __have_fma = _GLIBCXX_SIMD_HAVE_FMA;
245 constexpr inline bool __have_fma4 = _GLIBCXX_SIMD_HAVE_FMA4;
246 constexpr inline bool __have_f16c = _GLIBCXX_SIMD_HAVE_F16C;
247 constexpr inline bool __have_popcnt = _GLIBCXX_SIMD_HAVE_POPCNT;
248 constexpr inline bool __have_avx512f = _GLIBCXX_SIMD_HAVE_AVX512F;
249 constexpr inline bool __have_avx512dq = _GLIBCXX_SIMD_HAVE_AVX512DQ;
250 constexpr inline bool __have_avx512vl = _GLIBCXX_SIMD_HAVE_AVX512VL;
251 constexpr inline bool __have_avx512bw = _GLIBCXX_SIMD_HAVE_AVX512BW;
252 constexpr inline bool __have_avx512dq_vl = __have_avx512dq && __have_avx512vl;
253 constexpr inline bool __have_avx512bw_vl = __have_avx512bw && __have_avx512vl;
254 constexpr inline bool __have_avx512bitalg = _GLIBCXX_SIMD_HAVE_AVX512BITALG;
255 constexpr inline bool __have_avx512vbmi2 = _GLIBCXX_SIMD_HAVE_AVX512VBMI2;
256 constexpr inline bool __have_avx512vbmi = _GLIBCXX_SIMD_HAVE_AVX512VBMI;
257 constexpr inline bool __have_avx512ifma = _GLIBCXX_SIMD_HAVE_AVX512IFMA;
258 constexpr inline bool __have_avx512cd = _GLIBCXX_SIMD_HAVE_AVX512CD;
259 constexpr inline bool __have_avx512vnni = _GLIBCXX_SIMD_HAVE_AVX512VNNI;
260 constexpr inline bool __have_avx512vpopcntdq = _GLIBCXX_SIMD_HAVE_AVX512VPOPCNTDQ;
261 constexpr inline bool __have_avx512vp2intersect = _GLIBCXX_SIMD_HAVE_AVX512VP2INTERSECT;
262 
263 constexpr inline bool __have_neon = _GLIBCXX_SIMD_HAVE_NEON;
264 constexpr inline bool __have_neon_a32 = _GLIBCXX_SIMD_HAVE_NEON_A32;
265 constexpr inline bool __have_neon_a64 = _GLIBCXX_SIMD_HAVE_NEON_A64;
266 constexpr inline bool __support_neon_float =
267 #if defined __GCC_IEC_559
268  __GCC_IEC_559 == 0;
269 #elif defined __FAST_MATH__
270  true;
271 #else
272  false;
273 #endif
274 
275 constexpr inline bool __have_sve = _GLIBCXX_SIMD_HAVE_SVE;
276 constexpr inline bool __have_sve2 = _GLIBCXX_SIMD_HAVE_SVE2;
277 
278 #ifdef _ARCH_PWR10
279 constexpr inline bool __have_power10vec = true;
280 #else
281 constexpr inline bool __have_power10vec = false;
282 #endif
283 #ifdef __POWER9_VECTOR__
284 constexpr inline bool __have_power9vec = true;
285 #else
286 constexpr inline bool __have_power9vec = false;
287 #endif
288 #if defined __POWER8_VECTOR__
289 constexpr inline bool __have_power8vec = true;
290 #else
291 constexpr inline bool __have_power8vec = __have_power9vec;
292 #endif
293 #if defined __VSX__
294 constexpr inline bool __have_power_vsx = true;
295 #else
296 constexpr inline bool __have_power_vsx = __have_power8vec;
297 #endif
298 #if defined __ALTIVEC__
299 constexpr inline bool __have_power_vmx = true;
300 #else
301 constexpr inline bool __have_power_vmx = __have_power_vsx;
302 #endif
303 
304 // }}}
305 
306 namespace __detail
307 {
308 #ifdef math_errhandling
309  // Determines _S_handle_fpexcept from math_errhandling if it is defined and expands to a constant
310  // expression. math_errhandling may expand to an extern symbol, in which case a constexpr value
311  // must be guessed.
312  template <int = math_errhandling>
313  constexpr bool
314  __handle_fpexcept_impl(int)
315  { return math_errhandling & MATH_ERREXCEPT; }
316 #endif
317 
318  // Fallback if math_errhandling doesn't work: with fast-math assume floating-point exceptions are
319  // ignored, otherwise implement correct exception behavior.
320  constexpr bool
321  __handle_fpexcept_impl(float)
322  {
323 #if defined __FAST_MATH__
324  return false;
325 #else
326  return true;
327 #endif
328  }
329 
330  /// True if math functions must raise floating-point exceptions as specified by C17.
331  static constexpr bool _S_handle_fpexcept = __handle_fpexcept_impl(0);
332 
333  constexpr std::uint_least64_t
334  __floating_point_flags()
335  {
336  std::uint_least64_t __flags = 0;
337  if constexpr (_S_handle_fpexcept)
338  __flags |= 1;
339 #ifdef __FAST_MATH__
340  __flags |= 1 << 1;
341 #elif __FINITE_MATH_ONLY__
342  __flags |= 2 << 1;
343 #elif __GCC_IEC_559 < 2
344  __flags |= 3 << 1;
345 #endif
346  __flags |= (__FLT_EVAL_METHOD__ + 1) << 3;
347  return __flags;
348  }
349 
350  constexpr std::uint_least64_t
351  __machine_flags()
352  {
353  if constexpr (__have_mmx || __have_sse)
354  return __have_mmx
355  | (__have_sse << 1)
356  | (__have_sse2 << 2)
357  | (__have_sse3 << 3)
358  | (__have_ssse3 << 4)
359  | (__have_sse4_1 << 5)
360  | (__have_sse4_2 << 6)
361  | (__have_xop << 7)
362  | (__have_avx << 8)
363  | (__have_avx2 << 9)
364  | (__have_bmi << 10)
365  | (__have_bmi2 << 11)
366  | (__have_lzcnt << 12)
367  | (__have_sse4a << 13)
368  | (__have_fma << 14)
369  | (__have_fma4 << 15)
370  | (__have_f16c << 16)
371  | (__have_popcnt << 17)
372  | (__have_avx512f << 18)
373  | (__have_avx512dq << 19)
374  | (__have_avx512vl << 20)
375  | (__have_avx512bw << 21)
376  | (__have_avx512bitalg << 22)
377  | (__have_avx512vbmi2 << 23)
378  | (__have_avx512vbmi << 24)
379  | (__have_avx512ifma << 25)
380  | (__have_avx512cd << 26)
381  | (__have_avx512vnni << 27)
382  | (__have_avx512vpopcntdq << 28)
383  | (__have_avx512vp2intersect << 29);
384  else if constexpr (__have_neon || __have_sve)
385  return __have_neon
386  | (__have_neon_a32 << 1)
387  | (__have_neon_a64 << 2)
388  | (__have_neon_a64 << 2)
389  | (__support_neon_float << 3)
390  | (__have_sve << 4)
391  | (__have_sve2 << 5);
392  else if constexpr (__have_power_vmx)
393  return __have_power_vmx
394  | (__have_power_vsx << 1)
395  | (__have_power8vec << 2)
396  | (__have_power9vec << 3)
397  | (__have_power10vec << 4);
398  else
399  return 0;
400  }
401 
402  namespace
403  {
404  struct _OdrEnforcer {};
405  }
406 
407  template <std::uint_least64_t...>
408  struct _MachineFlagsTemplate {};
409 
410  /**@internal
411  * Use this type as default template argument to all function templates that
412  * are not declared always_inline. It ensures, that a function
413  * specialization, which the compiler decides not to inline, has a unique symbol
414  * (_OdrEnforcer) or a symbol matching the machine/architecture flags
415  * (_MachineFlagsTemplate). This helps to avoid ODR violations in cases where
416  * users link TUs compiled with different flags. This is especially important
417  * for using simd in libraries.
418  */
419  using __odr_helper
420  = conditional_t<__machine_flags() == 0, _OdrEnforcer,
421  _MachineFlagsTemplate<__machine_flags(), __floating_point_flags()>>;
422 
423  struct _Minimum
424  {
425  template <typename _Tp>
426  _GLIBCXX_SIMD_INTRINSIC constexpr
427  _Tp
428  operator()(_Tp __a, _Tp __b) const
429  {
430  using std::min;
431  return min(__a, __b);
432  }
433  };
434 
435  struct _Maximum
436  {
437  template <typename _Tp>
438  _GLIBCXX_SIMD_INTRINSIC constexpr
439  _Tp
440  operator()(_Tp __a, _Tp __b) const
441  {
442  using std::max;
443  return max(__a, __b);
444  }
445  };
446 } // namespace __detail
447 
448 // unrolled/pack execution helpers
449 // __execute_n_times{{{
450 template <typename _Fp, size_t... _I>
451  [[__gnu__::__flatten__]] _GLIBCXX_SIMD_INTRINSIC constexpr
452  void
453  __execute_on_index_sequence(_Fp&& __f, index_sequence<_I...>)
454  { ((void)__f(_SizeConstant<_I>()), ...); }
455 
456 template <typename _Fp>
457  _GLIBCXX_SIMD_INTRINSIC constexpr void
458  __execute_on_index_sequence(_Fp&&, index_sequence<>)
459  { }
460 
461 template <size_t _Np, typename _Fp>
462  _GLIBCXX_SIMD_INTRINSIC constexpr void
463  __execute_n_times(_Fp&& __f)
464  {
465  __execute_on_index_sequence(static_cast<_Fp&&>(__f),
466  make_index_sequence<_Np>{});
467  }
468 
469 // }}}
470 // __generate_from_n_evaluations{{{
471 template <typename _R, typename _Fp, size_t... _I>
472  [[__gnu__::__flatten__]] _GLIBCXX_SIMD_INTRINSIC constexpr
473  _R
474  __execute_on_index_sequence_with_return(_Fp&& __f, index_sequence<_I...>)
475  { return _R{__f(_SizeConstant<_I>())...}; }
476 
477 template <size_t _Np, typename _R, typename _Fp>
478  _GLIBCXX_SIMD_INTRINSIC constexpr _R
479  __generate_from_n_evaluations(_Fp&& __f)
480  {
481  return __execute_on_index_sequence_with_return<_R>(
482  static_cast<_Fp&&>(__f), make_index_sequence<_Np>{});
483  }
484 
485 // }}}
486 // __call_with_n_evaluations{{{
487 template <size_t... _I, typename _F0, typename _FArgs>
488  [[__gnu__::__flatten__]] _GLIBCXX_SIMD_INTRINSIC constexpr
489  auto
490  __call_with_n_evaluations(index_sequence<_I...>, _F0&& __f0, _FArgs&& __fargs)
491  { return __f0(__fargs(_SizeConstant<_I>())...); }
492 
493 template <size_t _Np, typename _F0, typename _FArgs>
494  _GLIBCXX_SIMD_INTRINSIC constexpr auto
495  __call_with_n_evaluations(_F0&& __f0, _FArgs&& __fargs)
496  {
497  return __call_with_n_evaluations(make_index_sequence<_Np>{},
498  static_cast<_F0&&>(__f0),
499  static_cast<_FArgs&&>(__fargs));
500  }
501 
502 // }}}
503 // __call_with_subscripts{{{
504 template <size_t _First = 0, size_t... _It, typename _Tp, typename _Fp>
505  [[__gnu__::__flatten__]] _GLIBCXX_SIMD_INTRINSIC constexpr
506  auto
507  __call_with_subscripts(_Tp&& __x, index_sequence<_It...>, _Fp&& __fun)
508  { return __fun(__x[_First + _It]...); }
509 
510 template <size_t _Np, size_t _First = 0, typename _Tp, typename _Fp>
511  _GLIBCXX_SIMD_INTRINSIC constexpr auto
512  __call_with_subscripts(_Tp&& __x, _Fp&& __fun)
513  {
514  return __call_with_subscripts<_First>(static_cast<_Tp&&>(__x),
515  make_index_sequence<_Np>(),
516  static_cast<_Fp&&>(__fun));
517  }
518 
519 // }}}
520 
521 // vvv ---- type traits ---- vvv
522 // integer type aliases{{{
523 using _UChar = unsigned char;
524 using _SChar = signed char;
525 using _UShort = unsigned short;
526 using _UInt = unsigned int;
527 using _ULong = unsigned long;
528 using _ULLong = unsigned long long;
529 using _LLong = long long;
530 
531 //}}}
532 // __first_of_pack{{{
533 template <typename _T0, typename...>
534  struct __first_of_pack
535  { using type = _T0; };
536 
537 template <typename... _Ts>
538  using __first_of_pack_t = typename __first_of_pack<_Ts...>::type;
539 
540 //}}}
541 // __value_type_or_identity_t {{{
542 template <typename _Tp>
543  typename _Tp::value_type
544  __value_type_or_identity_impl(int);
545 
546 template <typename _Tp>
547  _Tp
548  __value_type_or_identity_impl(float);
549 
550 template <typename _Tp>
551  using __value_type_or_identity_t
552  = decltype(__value_type_or_identity_impl<_Tp>(int()));
553 
554 // }}}
555 // __is_vectorizable {{{
556 template <typename _Tp>
557  struct __is_vectorizable : public is_arithmetic<_Tp> {};
558 
559 template <>
560  struct __is_vectorizable<bool> : public false_type {};
561 
562 template <typename _Tp>
563  inline constexpr bool __is_vectorizable_v = __is_vectorizable<_Tp>::value;
564 
565 // Deduces to a vectorizable type
566 template <typename _Tp, typename = enable_if_t<__is_vectorizable_v<_Tp>>>
567  using _Vectorizable = _Tp;
568 
569 // }}}
570 // _LoadStorePtr / __is_possible_loadstore_conversion {{{
571 template <typename _Ptr, typename _ValueType>
572  struct __is_possible_loadstore_conversion
573  : conjunction<__is_vectorizable<_Ptr>, __is_vectorizable<_ValueType>> {};
574 
575 template <>
576  struct __is_possible_loadstore_conversion<bool, bool> : true_type {};
577 
578 // Deduces to a type allowed for load/store with the given value type.
579 template <typename _Ptr, typename _ValueType,
580  typename = enable_if_t<
581  __is_possible_loadstore_conversion<_Ptr, _ValueType>::value>>
582  using _LoadStorePtr = _Ptr;
583 
584 // }}}
585 // __is_bitmask{{{
586 template <typename _Tp, typename = void_t<>>
587  struct __is_bitmask : false_type {};
588 
589 template <typename _Tp>
590  inline constexpr bool __is_bitmask_v = __is_bitmask<_Tp>::value;
591 
592 // the __mmaskXX case:
593 template <typename _Tp>
594  struct __is_bitmask<_Tp,
595  void_t<decltype(declval<unsigned&>() = declval<_Tp>() & 1u)>>
596  : true_type {};
597 
598 // }}}
599 // __int_for_sizeof{{{
600 #pragma GCC diagnostic push
601 #pragma GCC diagnostic ignored "-Wpedantic"
602 template <size_t _Bytes>
603  constexpr auto
604  __int_for_sizeof()
605  {
606  static_assert(_Bytes > 0);
607  if constexpr (_Bytes == sizeof(int))
608  return int();
609  else if constexpr (_Bytes == sizeof(_SChar))
610  return _SChar();
611  else if constexpr (_Bytes == sizeof(short))
612  return short();
613  else if constexpr (_Bytes == sizeof(long))
614  return long();
615  else if constexpr (_Bytes == sizeof(_LLong))
616  return _LLong();
617  #ifdef __SIZEOF_INT128__
618  else if constexpr (_Bytes == sizeof(__int128))
619  return __int128();
620  #endif // __SIZEOF_INT128__
621  else if constexpr (_Bytes % sizeof(int) == 0)
622  {
623  constexpr size_t _Np = _Bytes / sizeof(int);
624  struct _Ip
625  {
626  int _M_data[_Np];
627 
628  _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
629  operator&(_Ip __rhs) const
630  {
631  return __generate_from_n_evaluations<_Np, _Ip>(
632  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
633  return __rhs._M_data[__i] & _M_data[__i];
634  });
635  }
636 
637  _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
638  operator|(_Ip __rhs) const
639  {
640  return __generate_from_n_evaluations<_Np, _Ip>(
641  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
642  return __rhs._M_data[__i] | _M_data[__i];
643  });
644  }
645 
646  _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
647  operator^(_Ip __rhs) const
648  {
649  return __generate_from_n_evaluations<_Np, _Ip>(
650  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
651  return __rhs._M_data[__i] ^ _M_data[__i];
652  });
653  }
654 
655  _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
656  operator~() const
657  {
658  return __generate_from_n_evaluations<_Np, _Ip>(
659  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { return ~_M_data[__i]; });
660  }
661  };
662  return _Ip{};
663  }
664  else
665  static_assert(_Bytes == 0, "this should be unreachable");
666  }
667 #pragma GCC diagnostic pop
668 
669 template <typename _Tp>
670  using __int_for_sizeof_t = decltype(__int_for_sizeof<sizeof(_Tp)>());
671 
672 template <size_t _Np>
673  using __int_with_sizeof_t = decltype(__int_for_sizeof<_Np>());
674 
675 // }}}
676 // __is_fixed_size_abi{{{
677 template <typename _Tp>
678  struct __is_fixed_size_abi : false_type {};
679 
680 template <int _Np>
681  struct __is_fixed_size_abi<simd_abi::fixed_size<_Np>> : true_type {};
682 
683 template <typename _Tp>
684  inline constexpr bool __is_fixed_size_abi_v = __is_fixed_size_abi<_Tp>::value;
685 
686 // }}}
687 // __is_scalar_abi {{{
688 template <typename _Abi>
689  constexpr bool
690  __is_scalar_abi()
691  { return is_same_v<simd_abi::scalar, _Abi>; }
692 
693 // }}}
694 // __abi_bytes_v {{{
695 template <template <int> class _Abi, int _Bytes>
696  constexpr int
697  __abi_bytes_impl(_Abi<_Bytes>*)
698  { return _Bytes; }
699 
700 template <typename _Tp>
701  constexpr int
702  __abi_bytes_impl(_Tp*)
703  { return -1; }
704 
705 template <typename _Abi>
706  inline constexpr int __abi_bytes_v
707  = __abi_bytes_impl(static_cast<_Abi*>(nullptr));
708 
709 // }}}
710 // __is_builtin_bitmask_abi {{{
711 template <typename _Abi>
712  constexpr bool
713  __is_builtin_bitmask_abi()
714  { return is_same_v<simd_abi::_VecBltnBtmsk<__abi_bytes_v<_Abi>>, _Abi>; }
715 
716 // }}}
717 // __is_sse_abi {{{
718 template <typename _Abi>
719  constexpr bool
720  __is_sse_abi()
721  {
722  constexpr auto _Bytes = __abi_bytes_v<_Abi>;
723  return _Bytes <= 16 && is_same_v<simd_abi::_VecBuiltin<_Bytes>, _Abi>;
724  }
725 
726 // }}}
727 // __is_avx_abi {{{
728 template <typename _Abi>
729  constexpr bool
730  __is_avx_abi()
731  {
732  constexpr auto _Bytes = __abi_bytes_v<_Abi>;
733  return _Bytes > 16 && _Bytes <= 32
734  && is_same_v<simd_abi::_VecBuiltin<_Bytes>, _Abi>;
735  }
736 
737 // }}}
738 // __is_avx512_abi {{{
739 template <typename _Abi>
740  constexpr bool
741  __is_avx512_abi()
742  {
743  constexpr auto _Bytes = __abi_bytes_v<_Abi>;
744  return _Bytes <= 64 && is_same_v<simd_abi::_Avx512<_Bytes>, _Abi>;
745  }
746 
747 // }}}
748 // __is_neon_abi {{{
749 template <typename _Abi>
750  constexpr bool
751  __is_neon_abi()
752  {
753  constexpr auto _Bytes = __abi_bytes_v<_Abi>;
754  return _Bytes <= 16 && is_same_v<simd_abi::_VecBuiltin<_Bytes>, _Abi>;
755  }
756 
757 // }}}
758 // __is_sve_abi {{{
759 template <typename _Abi>
760  constexpr bool
761  __is_sve_abi()
762  {
763  constexpr auto _Bytes = __abi_bytes_v<_Abi>;
764  return _Bytes <= __sve_vectorized_size_bytes && is_same_v<simd_abi::_Sve<_Bytes>, _Abi>;
765  }
766 
767 // }}}
768 // __make_dependent_t {{{
769 template <typename, typename _Up>
770  struct __make_dependent
771  { using type = _Up; };
772 
773 template <typename _Tp, typename _Up>
774  using __make_dependent_t = typename __make_dependent<_Tp, _Up>::type;
775 
776 // }}}
777 // ^^^ ---- type traits ---- ^^^
778 
779 // __invoke_ub{{{
780 template <typename... _Args>
781  [[noreturn]] _GLIBCXX_SIMD_ALWAYS_INLINE void
782  __invoke_ub([[maybe_unused]] const char* __msg, [[maybe_unused]] const _Args&... __args)
783  {
784 #ifdef _GLIBCXX_DEBUG_UB
785  __builtin_fprintf(stderr, __msg, __args...);
786  __builtin_trap();
787 #else
788  __builtin_unreachable();
789 #endif
790  }
791 
792 // }}}
793 // __assert_unreachable{{{
794 template <typename _Tp>
795  struct __assert_unreachable
796  { static_assert(!is_same_v<_Tp, _Tp>, "this should be unreachable"); };
797 
798 // }}}
799 // __size_or_zero_v {{{
800 template <typename _Tp, typename _Ap, size_t _Np = simd_size<_Tp, _Ap>::value>
801  constexpr size_t
802  __size_or_zero_dispatch(int)
803  { return _Np; }
804 
805 template <typename _Tp, typename _Ap>
806  constexpr size_t
807  __size_or_zero_dispatch(float)
808  { return 0; }
809 
810 template <typename _Tp, typename _Ap>
811  inline constexpr size_t __size_or_zero_v
812  = __size_or_zero_dispatch<_Tp, _Ap>(0);
813 
814 // }}}
815 // __div_roundup {{{
816 inline constexpr size_t
817 __div_roundup(size_t __a, size_t __b)
818 { return (__a + __b - 1) / __b; }
819 
820 // }}}
821 // _ExactBool{{{
822 class _ExactBool
823 {
824  const bool _M_data;
825 
826 public:
827  _GLIBCXX_SIMD_INTRINSIC constexpr
828  _ExactBool(bool __b) : _M_data(__b) {}
829 
830  _ExactBool(int) = delete;
831 
832  _GLIBCXX_SIMD_INTRINSIC constexpr
833  operator bool() const
834  { return _M_data; }
835 };
836 
837 // }}}
838 // __may_alias{{{
839 /**@internal
840  * Helper __may_alias<_Tp> that turns _Tp into the type to be used for an
841  * aliasing pointer. This adds the __may_alias attribute to _Tp (with compilers
842  * that support it).
843  */
844 template <typename _Tp>
845  using __may_alias [[__gnu__::__may_alias__]] = _Tp;
846 
847 // }}}
848 // _UnsupportedBase {{{
849 // simd and simd_mask base for unsupported <_Tp, _Abi>
850 struct _UnsupportedBase
851 {
852  _UnsupportedBase() = delete;
853  _UnsupportedBase(const _UnsupportedBase&) = delete;
854  _UnsupportedBase& operator=(const _UnsupportedBase&) = delete;
855  ~_UnsupportedBase() = delete;
856 };
857 
858 // }}}
859 // _InvalidTraits {{{
860 /**
861  * @internal
862  * Defines the implementation of __a given <_Tp, _Abi>.
863  *
864  * Implementations must ensure that only valid <_Tp, _Abi> instantiations are
865  * possible. Static assertions in the type definition do not suffice. It is
866  * important that SFINAE works.
867  */
868 struct _InvalidTraits
869 {
870  using _IsValid = false_type;
871  using _SimdBase = _UnsupportedBase;
872  using _MaskBase = _UnsupportedBase;
873 
874  static constexpr size_t _S_full_size = 0;
875  static constexpr bool _S_is_partial = false;
876 
877  static constexpr size_t _S_simd_align = 1;
878  struct _SimdImpl;
879  struct _SimdMember {};
880  struct _SimdCastType;
881 
882  static constexpr size_t _S_mask_align = 1;
883  struct _MaskImpl;
884  struct _MaskMember {};
885  struct _MaskCastType;
886 };
887 
888 // }}}
889 // _SimdTraits {{{
890 template <typename _Tp, typename _Abi, typename = void_t<>>
891  struct _SimdTraits : _InvalidTraits {};
892 
893 // }}}
894 // __private_init, __bitset_init{{{
895 /**
896  * @internal
897  * Tag used for private init constructor of simd and simd_mask
898  */
899 inline constexpr struct _PrivateInit {} __private_init = {};
900 
901 inline constexpr struct _BitsetInit {} __bitset_init = {};
902 
903 // }}}
904 // __is_narrowing_conversion<_From, _To>{{{
905 template <typename _From, typename _To, bool = is_arithmetic_v<_From>,
906  bool = is_arithmetic_v<_To>>
907  struct __is_narrowing_conversion;
908 
909 // ignore "signed/unsigned mismatch" in the following trait.
910 // The implicit conversions will do the right thing here.
911 template <typename _From, typename _To>
912  struct __is_narrowing_conversion<_From, _To, true, true>
913  : public __bool_constant<(
914  __digits_v<_From> > __digits_v<_To>
915  || __finite_max_v<_From> > __finite_max_v<_To>
916  || __finite_min_v<_From> < __finite_min_v<_To>
917  || (is_signed_v<_From> && is_unsigned_v<_To>))> {};
918 
919 template <typename _Tp>
920  struct __is_narrowing_conversion<_Tp, bool, true, true>
921  : public true_type {};
922 
923 template <>
924  struct __is_narrowing_conversion<bool, bool, true, true>
925  : public false_type {};
926 
927 template <typename _Tp>
928  struct __is_narrowing_conversion<_Tp, _Tp, true, true>
929  : public false_type {};
930 
931 template <typename _From, typename _To>
932  struct __is_narrowing_conversion<_From, _To, false, true>
933  : public negation<is_convertible<_From, _To>> {};
934 
935 // }}}
936 // __converts_to_higher_integer_rank{{{
937 template <typename _From, typename _To, bool = (sizeof(_From) < sizeof(_To))>
938  struct __converts_to_higher_integer_rank : public true_type {};
939 
940 // this may fail for char -> short if sizeof(char) == sizeof(short)
941 template <typename _From, typename _To>
942  struct __converts_to_higher_integer_rank<_From, _To, false>
943  : public is_same<decltype(declval<_From>() + declval<_To>()), _To> {};
944 
945 // }}}
946 // __data(simd/simd_mask) {{{
947 template <typename _Tp, typename _Ap>
948  _GLIBCXX_SIMD_INTRINSIC constexpr const auto&
949  __data(const simd<_Tp, _Ap>& __x);
950 
951 template <typename _Tp, typename _Ap>
952  _GLIBCXX_SIMD_INTRINSIC constexpr auto&
953  __data(simd<_Tp, _Ap>& __x);
954 
955 template <typename _Tp, typename _Ap>
956  _GLIBCXX_SIMD_INTRINSIC constexpr const auto&
957  __data(const simd_mask<_Tp, _Ap>& __x);
958 
959 template <typename _Tp, typename _Ap>
960  _GLIBCXX_SIMD_INTRINSIC constexpr auto&
961  __data(simd_mask<_Tp, _Ap>& __x);
962 
963 // }}}
964 // _SimdConverter {{{
965 template <typename _FromT, typename _FromA, typename _ToT, typename _ToA,
966  typename = void>
967  struct _SimdConverter;
968 
969 template <typename _Tp, typename _Ap>
970  struct _SimdConverter<_Tp, _Ap, _Tp, _Ap, void>
971  {
972  template <typename _Up>
973  _GLIBCXX_SIMD_INTRINSIC const _Up&
974  operator()(const _Up& __x)
975  { return __x; }
976  };
977 
978 // }}}
979 // __to_value_type_or_member_type {{{
980 template <typename _V>
981  _GLIBCXX_SIMD_INTRINSIC constexpr auto
982  __to_value_type_or_member_type(const _V& __x) -> decltype(__data(__x))
983  { return __data(__x); }
984 
985 template <typename _V>
986  _GLIBCXX_SIMD_INTRINSIC constexpr const typename _V::value_type&
987  __to_value_type_or_member_type(const typename _V::value_type& __x)
988  { return __x; }
989 
990 // }}}
991 // __bool_storage_member_type{{{
992 template <size_t _Size>
993  struct __bool_storage_member_type;
994 
995 template <size_t _Size>
996  using __bool_storage_member_type_t =
997  typename __bool_storage_member_type<_Size>::type;
998 
999 // }}}
1000 // _SimdTuple {{{
1001 // why not tuple?
1002 // 1. tuple gives no guarantee about the storage order, but I require
1003 // storage
1004 // equivalent to array<_Tp, _Np>
1005 // 2. direct access to the element type (first template argument)
1006 // 3. enforces equal element type, only different _Abi types are allowed
1007 template <typename _Tp, typename... _Abis>
1008  struct _SimdTuple;
1009 
1010 //}}}
1011 // __fixed_size_storage_t {{{
1012 template <typename _Tp, int _Np>
1013  struct __fixed_size_storage;
1014 
1015 template <typename _Tp, int _Np>
1016  using __fixed_size_storage_t = typename __fixed_size_storage<_Tp, _Np>::type;
1017 
1018 // }}}
1019 // _SimdWrapper fwd decl{{{
1020 template <typename _Tp, size_t _Size, typename = void_t<>>
1021  struct _SimdWrapper;
1022 
1023 template <typename _Tp>
1024  using _SimdWrapper8 = _SimdWrapper<_Tp, 8 / sizeof(_Tp)>;
1025 template <typename _Tp>
1026  using _SimdWrapper16 = _SimdWrapper<_Tp, 16 / sizeof(_Tp)>;
1027 template <typename _Tp>
1028  using _SimdWrapper32 = _SimdWrapper<_Tp, 32 / sizeof(_Tp)>;
1029 template <typename _Tp>
1030  using _SimdWrapper64 = _SimdWrapper<_Tp, 64 / sizeof(_Tp)>;
1031 
1032 template <typename _Tp, size_t _Width>
1033  struct _SveSimdWrapper;
1034 
1035 // }}}
1036 // __is_simd_wrapper {{{
1037 template <typename _Tp>
1038  struct __is_simd_wrapper : false_type {};
1039 
1040 template <typename _Tp, size_t _Np>
1041  struct __is_simd_wrapper<_SimdWrapper<_Tp, _Np>> : true_type {};
1042 
1043 template <typename _Tp>
1044  inline constexpr bool __is_simd_wrapper_v = __is_simd_wrapper<_Tp>::value;
1045 
1046 // }}}
1047 // _BitOps {{{
1048 struct _BitOps
1049 {
1050  // _S_bit_iteration {{{
1051  template <typename _Tp, typename _Fp>
1052  static void
1053  _S_bit_iteration(_Tp __mask, _Fp&& __f)
1054  {
1055  static_assert(sizeof(_ULLong) >= sizeof(_Tp));
1056  conditional_t<sizeof(_Tp) <= sizeof(_UInt), _UInt, _ULLong> __k;
1057  if constexpr (is_convertible_v<_Tp, decltype(__k)>)
1058  __k = __mask;
1059  else
1060  __k = __mask.to_ullong();
1061  while(__k)
1062  {
1063  __f(std::__countr_zero(__k));
1064  __k &= (__k - 1);
1065  }
1066  }
1067 
1068  //}}}
1069 };
1070 
1071 //}}}
1072 // __increment, __decrement {{{
1073 template <typename _Tp = void>
1074  struct __increment
1075  { constexpr _Tp operator()(_Tp __a) const { return ++__a; } };
1076 
1077 template <>
1078  struct __increment<void>
1079  {
1080  template <typename _Tp>
1081  constexpr _Tp
1082  operator()(_Tp __a) const
1083  { return ++__a; }
1084  };
1085 
1086 template <typename _Tp = void>
1087  struct __decrement
1088  { constexpr _Tp operator()(_Tp __a) const { return --__a; } };
1089 
1090 template <>
1091  struct __decrement<void>
1092  {
1093  template <typename _Tp>
1094  constexpr _Tp
1095  operator()(_Tp __a) const
1096  { return --__a; }
1097  };
1098 
1099 // }}}
1100 // _ValuePreserving(OrInt) {{{
1101 template <typename _From, typename _To,
1102  typename = enable_if_t<negation<
1103  __is_narrowing_conversion<__remove_cvref_t<_From>, _To>>::value>>
1104  using _ValuePreserving = _From;
1105 
1106 template <typename _From, typename _To,
1107  typename _DecayedFrom = __remove_cvref_t<_From>,
1108  typename = enable_if_t<conjunction<
1109  is_convertible<_From, _To>,
1110  disjunction<
1111  is_same<_DecayedFrom, _To>, is_same<_DecayedFrom, int>,
1112  conjunction<is_same<_DecayedFrom, _UInt>, is_unsigned<_To>>,
1113  negation<__is_narrowing_conversion<_DecayedFrom, _To>>>>::value>>
1114  using _ValuePreservingOrInt = _From;
1115 
1116 // }}}
1117 // __intrinsic_type {{{
1118 template <typename _Tp, size_t _Bytes, typename = void_t<>>
1119  struct __intrinsic_type;
1120 
1121 template <typename _Tp, size_t _Size>
1122  using __intrinsic_type_t =
1123  typename __intrinsic_type<_Tp, _Size * sizeof(_Tp)>::type;
1124 
1125 template <typename _Tp>
1126  using __intrinsic_type2_t = typename __intrinsic_type<_Tp, 2>::type;
1127 template <typename _Tp>
1128  using __intrinsic_type4_t = typename __intrinsic_type<_Tp, 4>::type;
1129 template <typename _Tp>
1130  using __intrinsic_type8_t = typename __intrinsic_type<_Tp, 8>::type;
1131 template <typename _Tp>
1132  using __intrinsic_type16_t = typename __intrinsic_type<_Tp, 16>::type;
1133 template <typename _Tp>
1134  using __intrinsic_type32_t = typename __intrinsic_type<_Tp, 32>::type;
1135 template <typename _Tp>
1136  using __intrinsic_type64_t = typename __intrinsic_type<_Tp, 64>::type;
1137 
1138 // }}}
1139 // _BitMask {{{
1140 template <size_t _Np, bool _Sanitized = false>
1141  struct _BitMask;
1142 
1143 template <size_t _Np, bool _Sanitized>
1144  struct __is_bitmask<_BitMask<_Np, _Sanitized>, void> : true_type {};
1145 
1146 template <size_t _Np>
1147  using _SanitizedBitMask = _BitMask<_Np, true>;
1148 
1149 template <size_t _Np, bool _Sanitized>
1150  struct _BitMask
1151  {
1152  static_assert(_Np > 0);
1153 
1154  static constexpr size_t _NBytes = __div_roundup(_Np, __CHAR_BIT__);
1155 
1156  using _Tp = conditional_t<_Np == 1, bool,
1157  make_unsigned_t<__int_with_sizeof_t<std::min(
1158  sizeof(_ULLong), std::__bit_ceil(_NBytes))>>>;
1159 
1160  static constexpr int _S_array_size = __div_roundup(_NBytes, sizeof(_Tp));
1161 
1162  _Tp _M_bits[_S_array_size];
1163 
1164  static constexpr int _S_unused_bits
1165  = _Np == 1 ? 0 : _S_array_size * sizeof(_Tp) * __CHAR_BIT__ - _Np;
1166 
1167  static constexpr _Tp _S_bitmask = +_Tp(~_Tp()) >> _S_unused_bits;
1168 
1169  constexpr _BitMask() noexcept = default;
1170 
1171  constexpr _BitMask(unsigned long long __x) noexcept
1172  : _M_bits{static_cast<_Tp>(__x)} {}
1173 
1174  _BitMask(bitset<_Np> __x) noexcept : _BitMask(__x.to_ullong()) {}
1175 
1176  constexpr _BitMask(const _BitMask&) noexcept = default;
1177 
1178  template <bool _RhsSanitized, typename = enable_if_t<_RhsSanitized == false
1179  && _Sanitized == true>>
1180  constexpr _BitMask(const _BitMask<_Np, _RhsSanitized>& __rhs) noexcept
1181  : _BitMask(__rhs._M_sanitized()) {}
1182 
1183  constexpr operator _SimdWrapper<bool, _Np>() const noexcept
1184  {
1185  static_assert(_S_array_size == 1);
1186  return _M_bits[0];
1187  }
1188 
1189  // precondition: is sanitized
1190  constexpr _Tp
1191  _M_to_bits() const noexcept
1192  {
1193  static_assert(_S_array_size == 1);
1194  return _M_bits[0];
1195  }
1196 
1197  // precondition: is sanitized
1198  constexpr unsigned long long
1199  to_ullong() const noexcept
1200  {
1201  static_assert(_S_array_size == 1);
1202  return _M_bits[0];
1203  }
1204 
1205  // precondition: is sanitized
1206  constexpr unsigned long
1207  to_ulong() const noexcept
1208  {
1209  static_assert(_S_array_size == 1);
1210  return _M_bits[0];
1211  }
1212 
1213  constexpr bitset<_Np>
1214  _M_to_bitset() const noexcept
1215  {
1216  static_assert(_S_array_size == 1);
1217  return _M_bits[0];
1218  }
1219 
1220  constexpr decltype(auto)
1221  _M_sanitized() const noexcept
1222  {
1223  if constexpr (_Sanitized)
1224  return *this;
1225  else if constexpr (_Np == 1)
1226  return _SanitizedBitMask<_Np>(_M_bits[0]);
1227  else
1228  {
1229  _SanitizedBitMask<_Np> __r = {};
1230  for (int __i = 0; __i < _S_array_size; ++__i)
1231  __r._M_bits[__i] = _M_bits[__i];
1232  if constexpr (_S_unused_bits > 0)
1233  __r._M_bits[_S_array_size - 1] &= _S_bitmask;
1234  return __r;
1235  }
1236  }
1237 
1238  template <size_t _Mp, bool _LSanitized>
1239  constexpr _BitMask<_Np + _Mp, _Sanitized>
1240  _M_prepend(_BitMask<_Mp, _LSanitized> __lsb) const noexcept
1241  {
1242  constexpr size_t _RN = _Np + _Mp;
1243  using _Rp = _BitMask<_RN, _Sanitized>;
1244  if constexpr (_Rp::_S_array_size == 1)
1245  {
1246  _Rp __r{{_M_bits[0]}};
1247  __r._M_bits[0] <<= _Mp;
1248  __r._M_bits[0] |= __lsb._M_sanitized()._M_bits[0];
1249  return __r;
1250  }
1251  else
1252  __assert_unreachable<_Rp>();
1253  }
1254 
1255  // Return a new _BitMask with size _NewSize while dropping _DropLsb least
1256  // significant bits. If the operation implicitly produces a sanitized bitmask,
1257  // the result type will have _Sanitized set.
1258  template <size_t _DropLsb, size_t _NewSize = _Np - _DropLsb>
1259  constexpr auto
1260  _M_extract() const noexcept
1261  {
1262  static_assert(_Np > _DropLsb);
1263  static_assert(_DropLsb + _NewSize <= sizeof(_ULLong) * __CHAR_BIT__,
1264  "not implemented for bitmasks larger than one ullong");
1265  if constexpr (_NewSize == 1)
1266  // must sanitize because the return _Tp is bool
1267  return _SanitizedBitMask<1>(_M_bits[0] & (_Tp(1) << _DropLsb));
1268  else
1269  return _BitMask<_NewSize,
1270  ((_NewSize + _DropLsb == sizeof(_Tp) * __CHAR_BIT__
1271  && _NewSize + _DropLsb <= _Np)
1272  || ((_Sanitized || _Np == sizeof(_Tp) * __CHAR_BIT__)
1273  && _NewSize + _DropLsb >= _Np))>(_M_bits[0]
1274  >> _DropLsb);
1275  }
1276 
1277  // True if all bits are set. Implicitly sanitizes if _Sanitized == false.
1278  constexpr bool
1279  all() const noexcept
1280  {
1281  if constexpr (_Np == 1)
1282  return _M_bits[0];
1283  else if constexpr (!_Sanitized)
1284  return _M_sanitized().all();
1285  else
1286  {
1287  constexpr _Tp __allbits = ~_Tp();
1288  for (int __i = 0; __i < _S_array_size - 1; ++__i)
1289  if (_M_bits[__i] != __allbits)
1290  return false;
1291  return _M_bits[_S_array_size - 1] == _S_bitmask;
1292  }
1293  }
1294 
1295  // True if at least one bit is set. Implicitly sanitizes if _Sanitized ==
1296  // false.
1297  constexpr bool
1298  any() const noexcept
1299  {
1300  if constexpr (_Np == 1)
1301  return _M_bits[0];
1302  else if constexpr (!_Sanitized)
1303  return _M_sanitized().any();
1304  else
1305  {
1306  for (int __i = 0; __i < _S_array_size - 1; ++__i)
1307  if (_M_bits[__i] != 0)
1308  return true;
1309  return _M_bits[_S_array_size - 1] != 0;
1310  }
1311  }
1312 
1313  // True if no bit is set. Implicitly sanitizes if _Sanitized == false.
1314  constexpr bool
1315  none() const noexcept
1316  {
1317  if constexpr (_Np == 1)
1318  return !_M_bits[0];
1319  else if constexpr (!_Sanitized)
1320  return _M_sanitized().none();
1321  else
1322  {
1323  for (int __i = 0; __i < _S_array_size - 1; ++__i)
1324  if (_M_bits[__i] != 0)
1325  return false;
1326  return _M_bits[_S_array_size - 1] == 0;
1327  }
1328  }
1329 
1330  // Returns the number of set bits. Implicitly sanitizes if _Sanitized ==
1331  // false.
1332  constexpr int
1333  count() const noexcept
1334  {
1335  if constexpr (_Np == 1)
1336  return _M_bits[0];
1337  else if constexpr (!_Sanitized)
1338  return _M_sanitized().none();
1339  else
1340  {
1341  int __result = __builtin_popcountll(_M_bits[0]);
1342  for (int __i = 1; __i < _S_array_size; ++__i)
1343  __result += __builtin_popcountll(_M_bits[__i]);
1344  return __result;
1345  }
1346  }
1347 
1348  // Returns the bit at offset __i as bool.
1349  constexpr bool
1350  operator[](size_t __i) const noexcept
1351  {
1352  if constexpr (_Np == 1)
1353  return _M_bits[0];
1354  else if constexpr (_S_array_size == 1)
1355  return (_M_bits[0] >> __i) & 1;
1356  else
1357  {
1358  const size_t __j = __i / (sizeof(_Tp) * __CHAR_BIT__);
1359  const size_t __shift = __i % (sizeof(_Tp) * __CHAR_BIT__);
1360  return (_M_bits[__j] >> __shift) & 1;
1361  }
1362  }
1363 
1364  template <size_t __i>
1365  constexpr bool
1366  operator[](_SizeConstant<__i>) const noexcept
1367  {
1368  static_assert(__i < _Np);
1369  constexpr size_t __j = __i / (sizeof(_Tp) * __CHAR_BIT__);
1370  constexpr size_t __shift = __i % (sizeof(_Tp) * __CHAR_BIT__);
1371  return static_cast<bool>(_M_bits[__j] & (_Tp(1) << __shift));
1372  }
1373 
1374  // Set the bit at offset __i to __x.
1375  constexpr void
1376  set(size_t __i, bool __x) noexcept
1377  {
1378  if constexpr (_Np == 1)
1379  _M_bits[0] = __x;
1380  else if constexpr (_S_array_size == 1)
1381  {
1382  _M_bits[0] &= ~_Tp(_Tp(1) << __i);
1383  _M_bits[0] |= _Tp(_Tp(__x) << __i);
1384  }
1385  else
1386  {
1387  const size_t __j = __i / (sizeof(_Tp) * __CHAR_BIT__);
1388  const size_t __shift = __i % (sizeof(_Tp) * __CHAR_BIT__);
1389  _M_bits[__j] &= ~_Tp(_Tp(1) << __shift);
1390  _M_bits[__j] |= _Tp(_Tp(__x) << __shift);
1391  }
1392  }
1393 
1394  template <size_t __i>
1395  constexpr void
1396  set(_SizeConstant<__i>, bool __x) noexcept
1397  {
1398  static_assert(__i < _Np);
1399  if constexpr (_Np == 1)
1400  _M_bits[0] = __x;
1401  else
1402  {
1403  constexpr size_t __j = __i / (sizeof(_Tp) * __CHAR_BIT__);
1404  constexpr size_t __shift = __i % (sizeof(_Tp) * __CHAR_BIT__);
1405  constexpr _Tp __mask = ~_Tp(_Tp(1) << __shift);
1406  _M_bits[__j] &= __mask;
1407  _M_bits[__j] |= _Tp(_Tp(__x) << __shift);
1408  }
1409  }
1410 
1411  // Inverts all bits. Sanitized input leads to sanitized output.
1412  constexpr _BitMask
1413  operator~() const noexcept
1414  {
1415  if constexpr (_Np == 1)
1416  return !_M_bits[0];
1417  else
1418  {
1419  _BitMask __result{};
1420  for (int __i = 0; __i < _S_array_size - 1; ++__i)
1421  __result._M_bits[__i] = ~_M_bits[__i];
1422  if constexpr (_Sanitized)
1423  __result._M_bits[_S_array_size - 1]
1424  = _M_bits[_S_array_size - 1] ^ _S_bitmask;
1425  else
1426  __result._M_bits[_S_array_size - 1] = ~_M_bits[_S_array_size - 1];
1427  return __result;
1428  }
1429  }
1430 
1431  constexpr _BitMask&
1432  operator^=(const _BitMask& __b) & noexcept
1433  {
1434  __execute_n_times<_S_array_size>(
1435  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { _M_bits[__i] ^= __b._M_bits[__i]; });
1436  return *this;
1437  }
1438 
1439  constexpr _BitMask&
1440  operator|=(const _BitMask& __b) & noexcept
1441  {
1442  __execute_n_times<_S_array_size>(
1443  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { _M_bits[__i] |= __b._M_bits[__i]; });
1444  return *this;
1445  }
1446 
1447  constexpr _BitMask&
1448  operator&=(const _BitMask& __b) & noexcept
1449  {
1450  __execute_n_times<_S_array_size>(
1451  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { _M_bits[__i] &= __b._M_bits[__i]; });
1452  return *this;
1453  }
1454 
1455  friend constexpr _BitMask
1456  operator^(const _BitMask& __a, const _BitMask& __b) noexcept
1457  {
1458  _BitMask __r = __a;
1459  __r ^= __b;
1460  return __r;
1461  }
1462 
1463  friend constexpr _BitMask
1464  operator|(const _BitMask& __a, const _BitMask& __b) noexcept
1465  {
1466  _BitMask __r = __a;
1467  __r |= __b;
1468  return __r;
1469  }
1470 
1471  friend constexpr _BitMask
1472  operator&(const _BitMask& __a, const _BitMask& __b) noexcept
1473  {
1474  _BitMask __r = __a;
1475  __r &= __b;
1476  return __r;
1477  }
1478 
1479  _GLIBCXX_SIMD_INTRINSIC
1480  constexpr bool
1481  _M_is_constprop() const
1482  {
1483  if constexpr (_S_array_size == 0)
1484  return __builtin_constant_p(_M_bits[0]);
1485  else
1486  {
1487  for (int __i = 0; __i < _S_array_size; ++__i)
1488  if (!__builtin_constant_p(_M_bits[__i]))
1489  return false;
1490  return true;
1491  }
1492  }
1493  };
1494 
1495 // }}}
1496 
1497 // vvv ---- builtin vector types [[gnu::vector_size(N)]] and operations ---- vvv
1498 // __min_vector_size {{{
1499 template <typename _Tp = void>
1500  static inline constexpr int __min_vector_size = 2 * sizeof(_Tp);
1501 
1502 #if _GLIBCXX_SIMD_HAVE_NEON
1503 template <>
1504  inline constexpr int __min_vector_size<void> = 8;
1505 #else
1506 template <>
1507  inline constexpr int __min_vector_size<void> = 16;
1508 #endif
1509 
1510 // }}}
1511 // __vector_type {{{
1512 template <typename _Tp, size_t _Np, typename = void>
1513  struct __vector_type_n {};
1514 
1515 // substition failure for 0-element case
1516 template <typename _Tp>
1517  struct __vector_type_n<_Tp, 0, void> {};
1518 
1519 // special case 1-element to be _Tp itself
1520 template <typename _Tp>
1521  struct __vector_type_n<_Tp, 1, enable_if_t<__is_vectorizable_v<_Tp>>>
1522  { using type = _Tp; };
1523 
1524 // else, use GNU-style builtin vector types
1525 template <typename _Tp, size_t _Np>
1526  struct __vector_type_n<_Tp, _Np, enable_if_t<__is_vectorizable_v<_Tp> && _Np >= 2>>
1527  {
1528  static constexpr size_t _S_Np2 = std::__bit_ceil(_Np * sizeof(_Tp));
1529 
1530  static constexpr size_t _S_Bytes =
1531 #ifdef __i386__
1532  // Using [[gnu::vector_size(8)]] would wreak havoc on the FPU because
1533  // those objects are passed via MMX registers and nothing ever calls EMMS.
1534  _S_Np2 == 8 ? 16 :
1535 #endif
1536  _S_Np2 < __min_vector_size<_Tp> ? __min_vector_size<_Tp>
1537  : _S_Np2;
1538 
1539  using type [[__gnu__::__vector_size__(_S_Bytes)]] = _Tp;
1540  };
1541 
1542 template <typename _Tp, size_t _Bytes, size_t = _Bytes % sizeof(_Tp)>
1543  struct __vector_type;
1544 
1545 template <typename _Tp, size_t _Bytes>
1546  struct __vector_type<_Tp, _Bytes, 0>
1547  : __vector_type_n<_Tp, _Bytes / sizeof(_Tp)> {};
1548 
1549 template <typename _Tp, size_t _Size>
1550  using __vector_type_t = typename __vector_type_n<_Tp, _Size>::type;
1551 
1552 template <typename _Tp>
1553  using __vector_type2_t = typename __vector_type<_Tp, 2>::type;
1554 template <typename _Tp>
1555  using __vector_type4_t = typename __vector_type<_Tp, 4>::type;
1556 template <typename _Tp>
1557  using __vector_type8_t = typename __vector_type<_Tp, 8>::type;
1558 template <typename _Tp>
1559  using __vector_type16_t = typename __vector_type<_Tp, 16>::type;
1560 template <typename _Tp>
1561  using __vector_type32_t = typename __vector_type<_Tp, 32>::type;
1562 template <typename _Tp>
1563  using __vector_type64_t = typename __vector_type<_Tp, 64>::type;
1564 
1565 // }}}
1566 // __is_vector_type {{{
1567 template <typename _Tp, typename = void_t<>>
1568  struct __is_vector_type : false_type {};
1569 
1570 template <typename _Tp>
1571  struct __is_vector_type<
1572  _Tp, void_t<typename __vector_type<
1573  remove_reference_t<decltype(declval<_Tp>()[0])>, sizeof(_Tp)>::type>>
1574  : is_same<_Tp, typename __vector_type<
1575  remove_reference_t<decltype(declval<_Tp>()[0])>,
1576  sizeof(_Tp)>::type> {};
1577 
1578 template <typename _Tp>
1579  inline constexpr bool __is_vector_type_v = __is_vector_type<_Tp>::value;
1580 
1581 // }}}
1582 // __is_intrinsic_type {{{
1583 #if _GLIBCXX_SIMD_HAVE_SSE_ABI
1584 template <typename _Tp>
1585  using __is_intrinsic_type = __is_vector_type<_Tp>;
1586 #else // not SSE (x86)
1587 template <typename _Tp, typename = void_t<>>
1588  struct __is_intrinsic_type : false_type {};
1589 
1590 template <typename _Tp>
1591  struct __is_intrinsic_type<
1592  _Tp, void_t<typename __intrinsic_type<
1593  remove_reference_t<decltype(declval<_Tp>()[0])>, sizeof(_Tp)>::type>>
1594  : is_same<_Tp, typename __intrinsic_type<
1595  remove_reference_t<decltype(declval<_Tp>()[0])>,
1596  sizeof(_Tp)>::type> {};
1597 #endif
1598 
1599 template <typename _Tp>
1600  inline constexpr bool __is_intrinsic_type_v = __is_intrinsic_type<_Tp>::value;
1601 
1602 // }}}
1603 // _VectorTraits{{{
1604 template <typename _Tp, typename = void_t<>>
1605  struct _VectorTraitsImpl;
1606 
1607 template <typename _Tp>
1608  struct _VectorTraitsImpl<_Tp, enable_if_t<__is_vector_type_v<_Tp>
1609  || __is_intrinsic_type_v<_Tp>>>
1610  {
1611  using type = _Tp;
1612  using value_type = remove_reference_t<decltype(declval<_Tp>()[0])>;
1613  static constexpr int _S_full_size = sizeof(_Tp) / sizeof(value_type);
1614  using _Wrapper = _SimdWrapper<value_type, _S_full_size>;
1615  template <typename _Up, int _W = _S_full_size>
1616  static constexpr bool _S_is
1617  = is_same_v<value_type, _Up> && _W == _S_full_size;
1618  };
1619 
1620 template <typename _Tp, size_t _Np>
1621  struct _VectorTraitsImpl<_SimdWrapper<_Tp, _Np>,
1622  void_t<__vector_type_t<_Tp, _Np>>>
1623  {
1624  using type = __vector_type_t<_Tp, _Np>;
1625  using value_type = _Tp;
1626  static constexpr int _S_full_size = sizeof(type) / sizeof(value_type);
1627  using _Wrapper = _SimdWrapper<_Tp, _Np>;
1628  static constexpr bool _S_is_partial = (_Np == _S_full_size);
1629  static constexpr int _S_partial_width = _Np;
1630  template <typename _Up, int _W = _S_full_size>
1631  static constexpr bool _S_is
1632  = is_same_v<value_type, _Up>&& _W == _S_full_size;
1633  };
1634 
1635 template <typename _Tp, typename = typename _VectorTraitsImpl<_Tp>::type>
1636  using _VectorTraits = _VectorTraitsImpl<_Tp>;
1637 
1638 // }}}
1639 // __as_vector{{{
1640 template <typename _V>
1641  _GLIBCXX_SIMD_INTRINSIC constexpr auto
1642  __as_vector(_V __x)
1643  {
1644  if constexpr (__is_vector_type_v<_V>)
1645  return __x;
1646  else if constexpr (is_simd<_V>::value || is_simd_mask<_V>::value)
1647  {
1648  if constexpr (__is_fixed_size_abi_v<typename _V::abi_type>)
1649  {
1650  static_assert(is_simd<_V>::value);
1651  static_assert(_V::abi_type::template __traits<
1652  typename _V::value_type>::_SimdMember::_S_tuple_size == 1);
1653  return __as_vector(__data(__x).first);
1654  }
1655  else if constexpr (_V::size() > 1)
1656  return __data(__x)._M_data;
1657  else
1658  {
1659  static_assert(is_simd<_V>::value);
1660  using _Tp = typename _V::value_type;
1661 #ifdef __i386__
1662  constexpr auto __bytes = sizeof(_Tp) == 8 ? 16 : sizeof(_Tp);
1663  using _RV [[__gnu__::__vector_size__(__bytes)]] = _Tp;
1664 #else
1665  using _RV [[__gnu__::__vector_size__(sizeof(_Tp))]] = _Tp;
1666 #endif
1667  return _RV{__data(__x)};
1668  }
1669  }
1670  else if constexpr (__is_vectorizable_v<_V>)
1671  return __vector_type_t<_V, 2>{__x};
1672  else
1673  return __x._M_data;
1674  }
1675 
1676 // }}}
1677 // __as_wrapper{{{
1678 template <size_t _Np = 0, typename _V>
1679  _GLIBCXX_SIMD_INTRINSIC constexpr auto
1680  __as_wrapper(_V __x)
1681  {
1682  if constexpr (__is_vector_type_v<_V>)
1683  return _SimdWrapper<typename _VectorTraits<_V>::value_type,
1684  (_Np > 0 ? _Np : _VectorTraits<_V>::_S_full_size)>(__x);
1685  else if constexpr (is_simd<_V>::value || is_simd_mask<_V>::value)
1686  {
1687  static_assert(_V::size() == _Np);
1688  return __data(__x);
1689  }
1690  else
1691  {
1692  static_assert(_V::_S_size == _Np);
1693  return __x;
1694  }
1695  }
1696 
1697 // }}}
1698 // __intrin_bitcast{{{
1699 template <typename _To, typename _From>
1700  _GLIBCXX_SIMD_INTRINSIC constexpr _To
1701  __intrin_bitcast(_From __v)
1702  {
1703  static_assert((__is_vector_type_v<_From> || __is_intrinsic_type_v<_From>)
1704  && (__is_vector_type_v<_To> || __is_intrinsic_type_v<_To>));
1705  if constexpr (sizeof(_To) == sizeof(_From))
1706  return reinterpret_cast<_To>(__v);
1707  else if constexpr (sizeof(_From) > sizeof(_To))
1708  if constexpr (sizeof(_To) >= 16)
1709  return reinterpret_cast<const __may_alias<_To>&>(__v);
1710  else
1711  {
1712  _To __r;
1713  __builtin_memcpy(&__r, &__v, sizeof(_To));
1714  return __r;
1715  }
1716 #if _GLIBCXX_SIMD_X86INTRIN && !defined _GLIBCXX_CLANG
1717  else if constexpr (__have_avx && sizeof(_From) == 16 && sizeof(_To) == 32)
1718  return reinterpret_cast<_To>(__builtin_ia32_ps256_ps(
1719  reinterpret_cast<__vector_type_t<float, 4>>(__v)));
1720  else if constexpr (__have_avx512f && sizeof(_From) == 16
1721  && sizeof(_To) == 64)
1722  return reinterpret_cast<_To>(__builtin_ia32_ps512_ps(
1723  reinterpret_cast<__vector_type_t<float, 4>>(__v)));
1724  else if constexpr (__have_avx512f && sizeof(_From) == 32
1725  && sizeof(_To) == 64)
1726  return reinterpret_cast<_To>(__builtin_ia32_ps512_256ps(
1727  reinterpret_cast<__vector_type_t<float, 8>>(__v)));
1728 #endif // _GLIBCXX_SIMD_X86INTRIN
1729  else if constexpr (sizeof(__v) <= 8)
1730  return reinterpret_cast<_To>(
1731  __vector_type_t<__int_for_sizeof_t<_From>, sizeof(_To) / sizeof(_From)>{
1732  reinterpret_cast<__int_for_sizeof_t<_From>>(__v)});
1733  else
1734  {
1735  static_assert(sizeof(_To) > sizeof(_From));
1736  _To __r = {};
1737  __builtin_memcpy(&__r, &__v, sizeof(_From));
1738  return __r;
1739  }
1740  }
1741 
1742 // }}}
1743 // __vector_bitcast{{{
1744 template <typename _To, size_t _NN = 0, typename _From,
1745  typename _FromVT = _VectorTraits<_From>,
1746  size_t _Np = _NN == 0 ? sizeof(_From) / sizeof(_To) : _NN>
1747  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_To, _Np>
1748  __vector_bitcast(_From __x)
1749  {
1750  using _R = __vector_type_t<_To, _Np>;
1751  return __intrin_bitcast<_R>(__x);
1752  }
1753 
1754 template <typename _To, size_t _NN = 0, typename _Tp, size_t _Nx,
1755  size_t _Np
1756  = _NN == 0 ? sizeof(_SimdWrapper<_Tp, _Nx>) / sizeof(_To) : _NN>
1757  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_To, _Np>
1758  __vector_bitcast(const _SimdWrapper<_Tp, _Nx>& __x)
1759  {
1760  static_assert(_Np > 1);
1761  return __intrin_bitcast<__vector_type_t<_To, _Np>>(__x._M_data);
1762  }
1763 
1764 // }}}
1765 // __convert_x86 declarations {{{
1766 #ifdef _GLIBCXX_SIMD_WORKAROUND_PR85048
1767 template <typename _To, typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1768  _To __convert_x86(_Tp);
1769 
1770 template <typename _To, typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1771  _To __convert_x86(_Tp, _Tp);
1772 
1773 template <typename _To, typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1774  _To __convert_x86(_Tp, _Tp, _Tp, _Tp);
1775 
1776 template <typename _To, typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1777  _To __convert_x86(_Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp);
1778 
1779 template <typename _To, typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1780  _To __convert_x86(_Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp, _Tp,
1781  _Tp, _Tp, _Tp, _Tp);
1782 #endif // _GLIBCXX_SIMD_WORKAROUND_PR85048
1783 
1784 //}}}
1785 // __bit_cast {{{
1786 template <typename _To, typename _From>
1787  _GLIBCXX_SIMD_INTRINSIC constexpr _To
1788  __bit_cast(const _From __x)
1789  {
1790 #if __has_builtin(__builtin_bit_cast)
1791  return __builtin_bit_cast(_To, __x);
1792 #else
1793  static_assert(sizeof(_To) == sizeof(_From));
1794  constexpr bool __to_is_vectorizable
1795  = is_arithmetic_v<_To> || is_enum_v<_To>;
1796  constexpr bool __from_is_vectorizable
1797  = is_arithmetic_v<_From> || is_enum_v<_From>;
1798  if constexpr (__is_vector_type_v<_To> && __is_vector_type_v<_From>)
1799  return reinterpret_cast<_To>(__x);
1800  else if constexpr (__is_vector_type_v<_To> && __from_is_vectorizable)
1801  {
1802  using _FV [[__gnu__::__vector_size__(sizeof(_From))]] = _From;
1803  return reinterpret_cast<_To>(_FV{__x});
1804  }
1805  else if constexpr (__to_is_vectorizable && __from_is_vectorizable)
1806  {
1807  using _TV [[__gnu__::__vector_size__(sizeof(_To))]] = _To;
1808  using _FV [[__gnu__::__vector_size__(sizeof(_From))]] = _From;
1809  return reinterpret_cast<_TV>(_FV{__x})[0];
1810  }
1811  else if constexpr (__to_is_vectorizable && __is_vector_type_v<_From>)
1812  {
1813  using _TV [[__gnu__::__vector_size__(sizeof(_To))]] = _To;
1814  return reinterpret_cast<_TV>(__x)[0];
1815  }
1816  else
1817  {
1818  _To __r;
1819  __builtin_memcpy(reinterpret_cast<char*>(&__r),
1820  reinterpret_cast<const char*>(&__x), sizeof(_To));
1821  return __r;
1822  }
1823 #endif
1824  }
1825 
1826 // }}}
1827 // __to_intrin {{{
1828 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>,
1829  typename _R = __intrinsic_type_t<typename _TVT::value_type, _TVT::_S_full_size>>
1830  _GLIBCXX_SIMD_INTRINSIC constexpr _R
1831  __to_intrin(_Tp __x)
1832  {
1833  static_assert(sizeof(__x) <= sizeof(_R),
1834  "__to_intrin may never drop values off the end");
1835  if constexpr (sizeof(__x) == sizeof(_R))
1836  return reinterpret_cast<_R>(__as_vector(__x));
1837  else
1838  {
1839  using _Up = __int_for_sizeof_t<_Tp>;
1840  return reinterpret_cast<_R>(
1841  __vector_type_t<_Up, sizeof(_R) / sizeof(_Up)>{__bit_cast<_Up>(__x)});
1842  }
1843  }
1844 
1845 // }}}
1846 // __make_vector{{{
1847 template <typename _Tp, typename... _Args>
1848  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_Tp, sizeof...(_Args)>
1849  __make_vector(const _Args&... __args)
1850  { return __vector_type_t<_Tp, sizeof...(_Args)>{static_cast<_Tp>(__args)...}; }
1851 
1852 // }}}
1853 // __vector_broadcast{{{
1854 template <size_t _Np, typename _Tp, size_t... _I>
1855  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_Tp, _Np>
1856  __vector_broadcast_impl(_Tp __x, index_sequence<_I...>)
1857  { return __vector_type_t<_Tp, _Np>{((void)_I, __x)...}; }
1858 
1859 template <size_t _Np, typename _Tp>
1860  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_Tp, _Np>
1861  __vector_broadcast(_Tp __x)
1862  { return __vector_broadcast_impl<_Np, _Tp>(__x, make_index_sequence<_Np>()); }
1863 
1864 // }}}
1865 // __generate_vector{{{
1866  template <typename _Tp, size_t _Np, typename _Gp, size_t... _I>
1867  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_Tp, _Np>
1868  __generate_vector_impl(_Gp&& __gen, index_sequence<_I...>)
1869  { return __vector_type_t<_Tp, _Np>{ static_cast<_Tp>(__gen(_SizeConstant<_I>()))...}; }
1870 
1871 template <typename _V, typename _VVT = _VectorTraits<_V>, typename _Gp>
1872  _GLIBCXX_SIMD_INTRINSIC constexpr _V
1873  __generate_vector(_Gp&& __gen)
1874  {
1875  if constexpr (__is_vector_type_v<_V>)
1876  return __generate_vector_impl<typename _VVT::value_type,
1877  _VVT::_S_full_size>(
1878  static_cast<_Gp&&>(__gen), make_index_sequence<_VVT::_S_full_size>());
1879  else
1880  return __generate_vector_impl<typename _VVT::value_type,
1881  _VVT::_S_partial_width>(
1882  static_cast<_Gp&&>(__gen),
1883  make_index_sequence<_VVT::_S_partial_width>());
1884  }
1885 
1886 template <typename _Tp, size_t _Np, typename _Gp>
1887  _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_Tp, _Np>
1888  __generate_vector(_Gp&& __gen)
1889  {
1890  return __generate_vector_impl<_Tp, _Np>(static_cast<_Gp&&>(__gen),
1891  make_index_sequence<_Np>());
1892  }
1893 
1894 // }}}
1895 // __xor{{{
1896 template <typename _TW>
1897  _GLIBCXX_SIMD_INTRINSIC constexpr _TW
1898  __xor(_TW __a, _TW __b) noexcept
1899  {
1900  if constexpr (__is_vector_type_v<_TW> || __is_simd_wrapper_v<_TW>)
1901  {
1902  using _Tp = typename conditional_t<__is_simd_wrapper_v<_TW>, _TW,
1903  _VectorTraitsImpl<_TW>>::value_type;
1904  if constexpr (is_floating_point_v<_Tp>)
1905  {
1906  using _Ip = make_unsigned_t<__int_for_sizeof_t<_Tp>>;
1907  return __vector_bitcast<_Tp>(__vector_bitcast<_Ip>(__a)
1908  ^ __vector_bitcast<_Ip>(__b));
1909  }
1910  else if constexpr (__is_vector_type_v<_TW>)
1911  return __a ^ __b;
1912  else
1913  return __a._M_data ^ __b._M_data;
1914  }
1915  else
1916  return __a ^ __b;
1917  }
1918 
1919 // }}}
1920 // __or{{{
1921 template <typename _TW>
1922  _GLIBCXX_SIMD_INTRINSIC constexpr _TW
1923  __or(_TW __a, _TW __b) noexcept
1924  {
1925  if constexpr (__is_vector_type_v<_TW> || __is_simd_wrapper_v<_TW>)
1926  {
1927  using _Tp = typename conditional_t<__is_simd_wrapper_v<_TW>, _TW,
1928  _VectorTraitsImpl<_TW>>::value_type;
1929  if constexpr (is_floating_point_v<_Tp>)
1930  {
1931  using _Ip = make_unsigned_t<__int_for_sizeof_t<_Tp>>;
1932  return __vector_bitcast<_Tp>(__vector_bitcast<_Ip>(__a)
1933  | __vector_bitcast<_Ip>(__b));
1934  }
1935  else if constexpr (__is_vector_type_v<_TW>)
1936  return __a | __b;
1937  else
1938  return __a._M_data | __b._M_data;
1939  }
1940  else
1941  return __a | __b;
1942  }
1943 
1944 // }}}
1945 // __and{{{
1946 template <typename _TW>
1947  _GLIBCXX_SIMD_INTRINSIC constexpr _TW
1948  __and(_TW __a, _TW __b) noexcept
1949  {
1950  if constexpr (__is_vector_type_v<_TW> || __is_simd_wrapper_v<_TW>)
1951  {
1952  using _Tp = typename conditional_t<__is_simd_wrapper_v<_TW>, _TW,
1953  _VectorTraitsImpl<_TW>>::value_type;
1954  if constexpr (is_floating_point_v<_Tp>)
1955  {
1956  using _Ip = make_unsigned_t<__int_for_sizeof_t<_Tp>>;
1957  return __vector_bitcast<_Tp>(__vector_bitcast<_Ip>(__a)
1958  & __vector_bitcast<_Ip>(__b));
1959  }
1960  else if constexpr (__is_vector_type_v<_TW>)
1961  return __a & __b;
1962  else
1963  return __a._M_data & __b._M_data;
1964  }
1965  else
1966  return __a & __b;
1967  }
1968 
1969 // }}}
1970 // __andnot{{{
1971 #if _GLIBCXX_SIMD_X86INTRIN && !defined _GLIBCXX_CLANG
1972 static constexpr struct
1973 {
1974  _GLIBCXX_SIMD_INTRINSIC __v4sf
1975  operator()(__v4sf __a, __v4sf __b) const noexcept
1976  { return __builtin_ia32_andnps(__a, __b); }
1977 
1978  _GLIBCXX_SIMD_INTRINSIC __v2df
1979  operator()(__v2df __a, __v2df __b) const noexcept
1980  { return __builtin_ia32_andnpd(__a, __b); }
1981 
1982  _GLIBCXX_SIMD_INTRINSIC __v2di
1983  operator()(__v2di __a, __v2di __b) const noexcept
1984  { return __builtin_ia32_pandn128(__a, __b); }
1985 
1986  _GLIBCXX_SIMD_INTRINSIC __v8sf
1987  operator()(__v8sf __a, __v8sf __b) const noexcept
1988  { return __builtin_ia32_andnps256(__a, __b); }
1989 
1990  _GLIBCXX_SIMD_INTRINSIC __v4df
1991  operator()(__v4df __a, __v4df __b) const noexcept
1992  { return __builtin_ia32_andnpd256(__a, __b); }
1993 
1994  _GLIBCXX_SIMD_INTRINSIC __v4di
1995  operator()(__v4di __a, __v4di __b) const noexcept
1996  {
1997  if constexpr (__have_avx2)
1998  return __builtin_ia32_andnotsi256(__a, __b);
1999  else
2000  return reinterpret_cast<__v4di>(
2001  __builtin_ia32_andnpd256(reinterpret_cast<__v4df>(__a),
2002  reinterpret_cast<__v4df>(__b)));
2003  }
2004 
2005  _GLIBCXX_SIMD_INTRINSIC __v16sf
2006  operator()(__v16sf __a, __v16sf __b) const noexcept
2007  {
2008  if constexpr (__have_avx512dq)
2009  return _mm512_andnot_ps(__a, __b);
2010  else
2011  return reinterpret_cast<__v16sf>(
2012  _mm512_andnot_si512(reinterpret_cast<__v8di>(__a),
2013  reinterpret_cast<__v8di>(__b)));
2014  }
2015 
2016  _GLIBCXX_SIMD_INTRINSIC __v8df
2017  operator()(__v8df __a, __v8df __b) const noexcept
2018  {
2019  if constexpr (__have_avx512dq)
2020  return _mm512_andnot_pd(__a, __b);
2021  else
2022  return reinterpret_cast<__v8df>(
2023  _mm512_andnot_si512(reinterpret_cast<__v8di>(__a),
2024  reinterpret_cast<__v8di>(__b)));
2025  }
2026 
2027  _GLIBCXX_SIMD_INTRINSIC __v8di
2028  operator()(__v8di __a, __v8di __b) const noexcept
2029  { return _mm512_andnot_si512(__a, __b); }
2030 } _S_x86_andnot;
2031 #endif // _GLIBCXX_SIMD_X86INTRIN && !_GLIBCXX_CLANG
2032 
2033 template <typename _TW>
2034  _GLIBCXX_SIMD_INTRINSIC constexpr _TW
2035  __andnot(_TW __a, _TW __b) noexcept
2036  {
2037  if constexpr (__is_vector_type_v<_TW> || __is_simd_wrapper_v<_TW>)
2038  {
2039  using _TVT = conditional_t<__is_simd_wrapper_v<_TW>, _TW,
2040  _VectorTraitsImpl<_TW>>;
2041  using _Tp = typename _TVT::value_type;
2042 #if _GLIBCXX_SIMD_X86INTRIN && !defined _GLIBCXX_CLANG
2043  if constexpr (sizeof(_TW) >= 16)
2044  {
2045  const auto __ai = __to_intrin(__a);
2046  const auto __bi = __to_intrin(__b);
2047  if (!__builtin_is_constant_evaluated()
2048  && !(__builtin_constant_p(__ai) && __builtin_constant_p(__bi)))
2049  {
2050  const auto __r = _S_x86_andnot(__ai, __bi);
2051  if constexpr (is_convertible_v<decltype(__r), _TW>)
2052  return __r;
2053  else
2054  return reinterpret_cast<typename _TVT::type>(__r);
2055  }
2056  }
2057 #endif // _GLIBCXX_SIMD_X86INTRIN
2058  using _Ip = make_unsigned_t<__int_for_sizeof_t<_Tp>>;
2059  return __vector_bitcast<_Tp>(~__vector_bitcast<_Ip>(__a)
2060  & __vector_bitcast<_Ip>(__b));
2061  }
2062  else
2063  return ~__a & __b;
2064  }
2065 
2066 // }}}
2067 // __not{{{
2068 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
2069  _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
2070  __not(_Tp __a) noexcept
2071  {
2072  if constexpr (is_floating_point_v<typename _TVT::value_type>)
2073  return reinterpret_cast<typename _TVT::type>(
2074  ~__vector_bitcast<unsigned>(__a));
2075  else
2076  return ~__a;
2077  }
2078 
2079 // }}}
2080 // __vec_shuffle{{{
2081 template <typename _T0, typename _T1, typename _Fun, size_t... _Is>
2082  _GLIBCXX_SIMD_INTRINSIC constexpr
2083  __vector_type_t<remove_reference_t<decltype(declval<_T0>()[0])>, sizeof...(_Is)>
2084  __vec_shuffle(_T0 __x, _T1 __y, index_sequence<_Is...> __seq, _Fun __idx_perm)
2085  {
2086  constexpr int _N0 = sizeof(__x) / sizeof(__x[0]);
2087  constexpr int _N1 = sizeof(__y) / sizeof(__y[0]);
2088  using _Tp = remove_reference_t<decltype(declval<_T0>()[0])>;
2089  using _RV [[maybe_unused]] = __vector_type_t<_Tp, sizeof...(_Is)>;
2090 #if __has_builtin(__builtin_shufflevector)
2091 #ifdef _GLIBCXX_CLANG
2092  // Clang requires _T0 == _T1
2093  if constexpr (sizeof(__x) > sizeof(__y) and _N1 == 1)
2094  return __vec_shuffle(__x, _T0{__y[0]}, __seq, __idx_perm);
2095  else if constexpr (sizeof(__x) > sizeof(__y))
2096  return __vec_shuffle(__x, __intrin_bitcast<_T0>(__y), __seq, __idx_perm);
2097  else if constexpr (sizeof(__x) < sizeof(__y) and _N0 == 1)
2098  return __vec_shuffle(_T1{__x[0]}, __y, __seq, [=](int __i) {
2099  __i = __idx_perm(__i);
2100  return __i < _N0 ? __i : __i - _N0 + _N1;
2101  });
2102  else if constexpr (sizeof(__x) < sizeof(__y))
2103  return __vec_shuffle(__intrin_bitcast<_T1>(__x), __y, __seq, [=](int __i) {
2104  __i = __idx_perm(__i);
2105  return __i < _N0 ? __i : __i - _N0 + _N1;
2106  });
2107  else
2108 #endif
2109  {
2110  const auto __r = __builtin_shufflevector(__x, __y, [=] {
2111  constexpr int __j = __idx_perm(_Is);
2112  static_assert(__j < _N0 + _N1);
2113  return __j;
2114  }()...);
2115 #ifdef __i386__
2116  if constexpr (sizeof(__r) == sizeof(_RV))
2117  return __r;
2118  else
2119  return _RV {__r[_Is]...};
2120 #else
2121  return __r;
2122 #endif
2123  }
2124 #else
2125  return _RV {
2126  [=]() -> _Tp {
2127  constexpr int __j = __idx_perm(_Is);
2128  static_assert(__j < _N0 + _N1);
2129  if constexpr (__j < 0)
2130  return 0;
2131  else if constexpr (__j < _N0)
2132  return __x[__j];
2133  else
2134  return __y[__j - _N0];
2135  }()...
2136  };
2137 #endif
2138  }
2139 
2140 template <typename _T0, typename _Fun, typename _Seq>
2141  _GLIBCXX_SIMD_INTRINSIC constexpr auto
2142  __vec_shuffle(_T0 __x, _Seq __seq, _Fun __idx_perm)
2143  { return __vec_shuffle(__x, _T0(), __seq, __idx_perm); }
2144 
2145 // }}}
2146 // __concat{{{
2147 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>,
2148  typename _R = __vector_type_t<typename _TVT::value_type, _TVT::_S_full_size * 2>>
2149  constexpr _R
2150  __concat(_Tp a_, _Tp b_)
2151  {
2152 #ifdef _GLIBCXX_SIMD_WORKAROUND_XXX_1
2153  using _W
2154  = conditional_t<is_floating_point_v<typename _TVT::value_type>, double,
2155  conditional_t<(sizeof(_Tp) >= 2 * sizeof(long long)),
2156  long long, typename _TVT::value_type>>;
2157  constexpr int input_width = sizeof(_Tp) / sizeof(_W);
2158  const auto __a = __vector_bitcast<_W>(a_);
2159  const auto __b = __vector_bitcast<_W>(b_);
2160  using _Up = __vector_type_t<_W, sizeof(_R) / sizeof(_W)>;
2161 #else
2162  constexpr int input_width = _TVT::_S_full_size;
2163  const _Tp& __a = a_;
2164  const _Tp& __b = b_;
2165  using _Up = _R;
2166 #endif
2167  if constexpr (input_width == 2)
2168  return reinterpret_cast<_R>(_Up{__a[0], __a[1], __b[0], __b[1]});
2169  else if constexpr (input_width == 4)
2170  return reinterpret_cast<_R>(
2171  _Up{__a[0], __a[1], __a[2], __a[3], __b[0], __b[1], __b[2], __b[3]});
2172  else if constexpr (input_width == 8)
2173  return reinterpret_cast<_R>(
2174  _Up{__a[0], __a[1], __a[2], __a[3], __a[4], __a[5], __a[6], __a[7],
2175  __b[0], __b[1], __b[2], __b[3], __b[4], __b[5], __b[6], __b[7]});
2176  else if constexpr (input_width == 16)
2177  return reinterpret_cast<_R>(
2178  _Up{__a[0], __a[1], __a[2], __a[3], __a[4], __a[5], __a[6],
2179  __a[7], __a[8], __a[9], __a[10], __a[11], __a[12], __a[13],
2180  __a[14], __a[15], __b[0], __b[1], __b[2], __b[3], __b[4],
2181  __b[5], __b[6], __b[7], __b[8], __b[9], __b[10], __b[11],
2182  __b[12], __b[13], __b[14], __b[15]});
2183  else if constexpr (input_width == 32)
2184  return reinterpret_cast<_R>(
2185  _Up{__a[0], __a[1], __a[2], __a[3], __a[4], __a[5], __a[6],
2186  __a[7], __a[8], __a[9], __a[10], __a[11], __a[12], __a[13],
2187  __a[14], __a[15], __a[16], __a[17], __a[18], __a[19], __a[20],
2188  __a[21], __a[22], __a[23], __a[24], __a[25], __a[26], __a[27],
2189  __a[28], __a[29], __a[30], __a[31], __b[0], __b[1], __b[2],
2190  __b[3], __b[4], __b[5], __b[6], __b[7], __b[8], __b[9],
2191  __b[10], __b[11], __b[12], __b[13], __b[14], __b[15], __b[16],
2192  __b[17], __b[18], __b[19], __b[20], __b[21], __b[22], __b[23],
2193  __b[24], __b[25], __b[26], __b[27], __b[28], __b[29], __b[30],
2194  __b[31]});
2195  }
2196 
2197 // }}}
2198 // __zero_extend {{{
2199 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
2200  struct _ZeroExtendProxy
2201  {
2202  using value_type = typename _TVT::value_type;
2203  static constexpr size_t _Np = _TVT::_S_full_size;
2204  const _Tp __x;
2205 
2206  template <typename _To, typename _ToVT = _VectorTraits<_To>,
2207  typename
2208  = enable_if_t<is_same_v<typename _ToVT::value_type, value_type>>>
2209  _GLIBCXX_SIMD_INTRINSIC operator _To() const
2210  {
2211  constexpr size_t _ToN = _ToVT::_S_full_size;
2212  if constexpr (_ToN == _Np)
2213  return __x;
2214  else if constexpr (_ToN == 2 * _Np)
2215  {
2216 #ifdef _GLIBCXX_SIMD_WORKAROUND_XXX_3
2217  if constexpr (__have_avx && _TVT::template _S_is<float, 4>)
2218  return __vector_bitcast<value_type>(
2219  _mm256_insertf128_ps(__m256(), __x, 0));
2220  else if constexpr (__have_avx && _TVT::template _S_is<double, 2>)
2221  return __vector_bitcast<value_type>(
2222  _mm256_insertf128_pd(__m256d(), __x, 0));
2223  else if constexpr (__have_avx2 && _Np * sizeof(value_type) == 16)
2224  return __vector_bitcast<value_type>(
2225  _mm256_insertf128_si256(__m256i(), __to_intrin(__x), 0));
2226  else if constexpr (__have_avx512f && _TVT::template _S_is<float, 8>)
2227  {
2228  if constexpr (__have_avx512dq)
2229  return __vector_bitcast<value_type>(
2230  _mm512_insertf32x8(__m512(), __x, 0));
2231  else
2232  return reinterpret_cast<__m512>(
2233  _mm512_insertf64x4(__m512d(),
2234  reinterpret_cast<__m256d>(__x), 0));
2235  }
2236  else if constexpr (__have_avx512f
2237  && _TVT::template _S_is<double, 4>)
2238  return __vector_bitcast<value_type>(
2239  _mm512_insertf64x4(__m512d(), __x, 0));
2240  else if constexpr (__have_avx512f && _Np * sizeof(value_type) == 32)
2241  return __vector_bitcast<value_type>(
2242  _mm512_inserti64x4(__m512i(), __to_intrin(__x), 0));
2243 #endif
2244  return __concat(__x, _Tp());
2245  }
2246  else if constexpr (_ToN == 4 * _Np)
2247  {
2248 #ifdef _GLIBCXX_SIMD_WORKAROUND_XXX_3
2249  if constexpr (__have_avx512dq && _TVT::template _S_is<double, 2>)
2250  {
2251  return __vector_bitcast<value_type>(
2252  _mm512_insertf64x2(__m512d(), __x, 0));
2253  }
2254  else if constexpr (__have_avx512f
2255  && is_floating_point_v<value_type>)
2256  {
2257  return __vector_bitcast<value_type>(
2258  _mm512_insertf32x4(__m512(), reinterpret_cast<__m128>(__x),
2259  0));
2260  }
2261  else if constexpr (__have_avx512f && _Np * sizeof(value_type) == 16)
2262  {
2263  return __vector_bitcast<value_type>(
2264  _mm512_inserti32x4(__m512i(), __to_intrin(__x), 0));
2265  }
2266 #endif
2267  return __concat(__concat(__x, _Tp()),
2268  __vector_type_t<value_type, _Np * 2>());
2269  }
2270  else if constexpr (_ToN == 8 * _Np)
2271  return __concat(operator __vector_type_t<value_type, _Np * 4>(),
2272  __vector_type_t<value_type, _Np * 4>());
2273  else if constexpr (_ToN == 16 * _Np)
2274  return __concat(operator __vector_type_t<value_type, _Np * 8>(),
2275  __vector_type_t<value_type, _Np * 8>());
2276  else
2277  __assert_unreachable<_Tp>();
2278  }
2279  };
2280 
2281 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
2282  _GLIBCXX_SIMD_INTRINSIC _ZeroExtendProxy<_Tp, _TVT>
2283  __zero_extend(_Tp __x)
2284  { return {__x}; }
2285 
2286 // }}}
2287 // __extract<_Np, By>{{{
2288 template <int _Offset,
2289  int _SplitBy,
2290  typename _Tp,
2291  typename _TVT = _VectorTraits<_Tp>,
2292  typename _R = __vector_type_t<typename _TVT::value_type, _TVT::_S_full_size / _SplitBy>>
2293  _GLIBCXX_SIMD_INTRINSIC constexpr _R
2294  __extract(_Tp __in)
2295  {
2296  using value_type = typename _TVT::value_type;
2297 #if _GLIBCXX_SIMD_X86INTRIN // {{{
2298  if constexpr (sizeof(_Tp) == 64 && _SplitBy == 4 && _Offset > 0)
2299  {
2300  if constexpr (__have_avx512dq && is_same_v<double, value_type>)
2301  return _mm512_extractf64x2_pd(__to_intrin(__in), _Offset);
2302  else if constexpr (is_floating_point_v<value_type>)
2303  return __vector_bitcast<value_type>(
2304  _mm512_extractf32x4_ps(__intrin_bitcast<__m512>(__in), _Offset));
2305  else
2306  return reinterpret_cast<_R>(
2307  _mm512_extracti32x4_epi32(__intrin_bitcast<__m512i>(__in),
2308  _Offset));
2309  }
2310  else
2311 #endif // _GLIBCXX_SIMD_X86INTRIN }}}
2312  {
2313 #ifdef _GLIBCXX_SIMD_WORKAROUND_XXX_1
2314  using _W = conditional_t<
2315  is_floating_point_v<value_type>, double,
2316  conditional_t<(sizeof(_R) >= 16), long long, value_type>>;
2317  static_assert(sizeof(_R) % sizeof(_W) == 0);
2318  constexpr int __return_width = sizeof(_R) / sizeof(_W);
2319  using _Up = __vector_type_t<_W, __return_width>;
2320  const auto __x = __vector_bitcast<_W>(__in);
2321 #else
2322  constexpr int __return_width = _TVT::_S_full_size / _SplitBy;
2323  using _Up = _R;
2324  const __vector_type_t<value_type, _TVT::_S_full_size>& __x
2325  = __in; // only needed for _Tp = _SimdWrapper<value_type, _Np>
2326 #endif
2327  constexpr int _O = _Offset * __return_width;
2328  return __call_with_subscripts<__return_width, _O>(
2329  __x, [](auto... __entries) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
2330  return reinterpret_cast<_R>(_Up{__entries...});
2331  });
2332  }
2333  }
2334 
2335 // }}}
2336 // __lo/__hi64[z]{{{
2337 template <typename _Tp,
2338  typename _R = __vector_type8_t<typename _VectorTraits<_Tp>::value_type>>
2339  _GLIBCXX_SIMD_INTRINSIC constexpr _R
2340  __lo64(_Tp __x)
2341  {
2342  _R __r{};
2343  __builtin_memcpy(&__r, &__x, 8);
2344  return __r;
2345  }
2346 
2347 template <typename _Tp,
2348  typename _R = __vector_type8_t<typename _VectorTraits<_Tp>::value_type>>
2349  _GLIBCXX_SIMD_INTRINSIC constexpr _R
2350  __hi64(_Tp __x)
2351  {
2352  static_assert(sizeof(_Tp) == 16, "use __hi64z if you meant it");
2353  _R __r{};
2354  __builtin_memcpy(&__r, reinterpret_cast<const char*>(&__x) + 8, 8);
2355  return __r;
2356  }
2357 
2358 template <typename _Tp,
2359  typename _R = __vector_type8_t<typename _VectorTraits<_Tp>::value_type>>
2360  _GLIBCXX_SIMD_INTRINSIC constexpr _R
2361  __hi64z([[maybe_unused]] _Tp __x)
2362  {
2363  _R __r{};
2364  if constexpr (sizeof(_Tp) == 16)
2365  __builtin_memcpy(&__r, reinterpret_cast<const char*>(&__x) + 8, 8);
2366  return __r;
2367  }
2368 
2369 // }}}
2370 // __lo/__hi128{{{
2371 template <typename _Tp>
2372  _GLIBCXX_SIMD_INTRINSIC constexpr auto
2373  __lo128(_Tp __x)
2374  { return __extract<0, sizeof(_Tp) / 16>(__x); }
2375 
2376 template <typename _Tp>
2377  _GLIBCXX_SIMD_INTRINSIC constexpr auto
2378  __hi128(_Tp __x)
2379  {
2380  static_assert(sizeof(__x) == 32);
2381  return __extract<1, 2>(__x);
2382  }
2383 
2384 // }}}
2385 // __lo/__hi256{{{
2386 template <typename _Tp>
2387  _GLIBCXX_SIMD_INTRINSIC constexpr auto
2388  __lo256(_Tp __x)
2389  {
2390  static_assert(sizeof(__x) == 64);
2391  return __extract<0, 2>(__x);
2392  }
2393 
2394 template <typename _Tp>
2395  _GLIBCXX_SIMD_INTRINSIC constexpr auto
2396  __hi256(_Tp __x)
2397  {
2398  static_assert(sizeof(__x) == 64);
2399  return __extract<1, 2>(__x);
2400  }
2401 
2402 // }}}
2403 // __auto_bitcast{{{
2404 template <typename _Tp>
2405  struct _AutoCast
2406  {
2407  static_assert(__is_vector_type_v<_Tp>);
2408 
2409  const _Tp __x;
2410 
2411  template <typename _Up, typename _UVT = _VectorTraits<_Up>>
2412  _GLIBCXX_SIMD_INTRINSIC constexpr operator _Up() const
2413  { return __intrin_bitcast<typename _UVT::type>(__x); }
2414  };
2415 
2416 template <typename _Tp>
2417  _GLIBCXX_SIMD_INTRINSIC constexpr _AutoCast<_Tp>
2418  __auto_bitcast(const _Tp& __x)
2419  { return {__x}; }
2420 
2421 template <typename _Tp, size_t _Np>
2422  _GLIBCXX_SIMD_INTRINSIC constexpr
2423  _AutoCast<typename _SimdWrapper<_Tp, _Np>::_BuiltinType>
2424  __auto_bitcast(const _SimdWrapper<_Tp, _Np>& __x)
2425  { return {__x._M_data}; }
2426 
2427 // }}}
2428 // ^^^ ---- builtin vector types [[gnu::vector_size(N)]] and operations ---- ^^^
2429 
2430 #if _GLIBCXX_SIMD_HAVE_SSE_ABI
2431 // __bool_storage_member_type{{{
2432 #if _GLIBCXX_SIMD_HAVE_AVX512F && _GLIBCXX_SIMD_X86INTRIN
2433 template <size_t _Size>
2434  struct __bool_storage_member_type
2435  {
2436  static_assert((_Size & (_Size - 1)) != 0,
2437  "This trait may only be used for non-power-of-2 sizes. "
2438  "Power-of-2 sizes must be specialized.");
2439  using type =
2440  typename __bool_storage_member_type<std::__bit_ceil(_Size)>::type;
2441  };
2442 
2443 template <>
2444  struct __bool_storage_member_type<1> { using type = bool; };
2445 
2446 template <>
2447  struct __bool_storage_member_type<2> { using type = __mmask8; };
2448 
2449 template <>
2450  struct __bool_storage_member_type<4> { using type = __mmask8; };
2451 
2452 template <>
2453  struct __bool_storage_member_type<8> { using type = __mmask8; };
2454 
2455 template <>
2456  struct __bool_storage_member_type<16> { using type = __mmask16; };
2457 
2458 template <>
2459  struct __bool_storage_member_type<32> { using type = __mmask32; };
2460 
2461 template <>
2462  struct __bool_storage_member_type<64> { using type = __mmask64; };
2463 #endif // _GLIBCXX_SIMD_HAVE_AVX512F
2464 
2465 // }}}
2466 // __intrinsic_type (x86){{{
2467 // the following excludes bool via __is_vectorizable
2468 #if _GLIBCXX_SIMD_HAVE_SSE
2469 template <typename _Tp, size_t _Bytes>
2470  struct __intrinsic_type<_Tp, _Bytes, enable_if_t<__is_vectorizable_v<_Tp> && _Bytes <= 64>>
2471  {
2472  // allow _Tp == long double with -mlong-double-64
2473  static_assert(!(is_same_v<_Tp, long double>
2474  && sizeof(long double) > sizeof(double)),
2475  "no __intrinsic_type support for long double on x86");
2476 
2477  static constexpr size_t _S_VBytes = _Bytes <= 16 ? 16 : _Bytes <= 32 ? 32 : 64;
2478 
2479  using type [[__gnu__::__vector_size__(_S_VBytes)]]
2480  = conditional_t<is_integral_v<_Tp>, long long int, _Tp>;
2481  };
2482 #endif // _GLIBCXX_SIMD_HAVE_SSE
2483 
2484 // }}}
2485 #endif // _GLIBCXX_SIMD_HAVE_SSE_ABI
2486 // __intrinsic_type (ARM){{{
2487 #if _GLIBCXX_SIMD_HAVE_NEON
2488 template <>
2489  struct __intrinsic_type<float, 8, void>
2490  { using type = float32x2_t; };
2491 
2492 template <>
2493  struct __intrinsic_type<float, 16, void>
2494  { using type = float32x4_t; };
2495 
2496 template <>
2497  struct __intrinsic_type<double, 8, void>
2498  {
2499 #if _GLIBCXX_SIMD_HAVE_NEON_A64
2500  using type = float64x1_t;
2501 #endif
2502  };
2503 
2504 template <>
2505  struct __intrinsic_type<double, 16, void>
2506  {
2507 #if _GLIBCXX_SIMD_HAVE_NEON_A64
2508  using type = float64x2_t;
2509 #endif
2510  };
2511 
2512 #define _GLIBCXX_SIMD_ARM_INTRIN(_Bits, _Np) \
2513 template <> \
2514  struct __intrinsic_type<__int_with_sizeof_t<_Bits / 8>, \
2515  _Np * _Bits / 8, void> \
2516  { using type = int##_Bits##x##_Np##_t; }; \
2517 template <> \
2518  struct __intrinsic_type<make_unsigned_t<__int_with_sizeof_t<_Bits / 8>>, \
2519  _Np * _Bits / 8, void> \
2520  { using type = uint##_Bits##x##_Np##_t; }
2521 _GLIBCXX_SIMD_ARM_INTRIN(8, 8);
2522 _GLIBCXX_SIMD_ARM_INTRIN(8, 16);
2523 _GLIBCXX_SIMD_ARM_INTRIN(16, 4);
2524 _GLIBCXX_SIMD_ARM_INTRIN(16, 8);
2525 _GLIBCXX_SIMD_ARM_INTRIN(32, 2);
2526 _GLIBCXX_SIMD_ARM_INTRIN(32, 4);
2527 _GLIBCXX_SIMD_ARM_INTRIN(64, 1);
2528 _GLIBCXX_SIMD_ARM_INTRIN(64, 2);
2529 #undef _GLIBCXX_SIMD_ARM_INTRIN
2530 
2531 template <typename _Tp, size_t _Bytes>
2532  struct __intrinsic_type<_Tp, _Bytes, enable_if_t<__is_vectorizable_v<_Tp> && _Bytes <= 16>>
2533  {
2534  static constexpr int _SVecBytes = _Bytes <= 8 ? 8 : 16;
2535 
2536  using _Ip = __int_for_sizeof_t<_Tp>;
2537 
2538  using _Up = conditional_t<
2539  is_floating_point_v<_Tp>, _Tp,
2540  conditional_t<is_unsigned_v<_Tp>, make_unsigned_t<_Ip>, _Ip>>;
2541 
2542  static_assert(!is_same_v<_Tp, _Up> || _SVecBytes != _Bytes,
2543  "should use explicit specialization above");
2544 
2545  using type = typename __intrinsic_type<_Up, _SVecBytes>::type;
2546  };
2547 #endif // _GLIBCXX_SIMD_HAVE_NEON
2548 
2549 // }}}
2550 // __intrinsic_type (PPC){{{
2551 #ifdef __ALTIVEC__
2552 template <typename _Tp>
2553  struct __intrinsic_type_impl;
2554 
2555 #define _GLIBCXX_SIMD_PPC_INTRIN(_Tp) \
2556  template <> \
2557  struct __intrinsic_type_impl<_Tp> { using type = __vector _Tp; }
2558 _GLIBCXX_SIMD_PPC_INTRIN(float);
2559 #ifdef __VSX__
2560 _GLIBCXX_SIMD_PPC_INTRIN(double);
2561 #endif
2562 _GLIBCXX_SIMD_PPC_INTRIN(signed char);
2563 _GLIBCXX_SIMD_PPC_INTRIN(unsigned char);
2564 _GLIBCXX_SIMD_PPC_INTRIN(signed short);
2565 _GLIBCXX_SIMD_PPC_INTRIN(unsigned short);
2566 _GLIBCXX_SIMD_PPC_INTRIN(signed int);
2567 _GLIBCXX_SIMD_PPC_INTRIN(unsigned int);
2568 #if defined __VSX__ || __SIZEOF_LONG__ == 4
2569 _GLIBCXX_SIMD_PPC_INTRIN(signed long);
2570 _GLIBCXX_SIMD_PPC_INTRIN(unsigned long);
2571 #endif
2572 #ifdef __VSX__
2573 _GLIBCXX_SIMD_PPC_INTRIN(signed long long);
2574 _GLIBCXX_SIMD_PPC_INTRIN(unsigned long long);
2575 #endif
2576 #undef _GLIBCXX_SIMD_PPC_INTRIN
2577 
2578 template <typename _Tp, size_t _Bytes>
2579  struct __intrinsic_type<_Tp, _Bytes, enable_if_t<__is_vectorizable_v<_Tp> && _Bytes <= 16>>
2580  {
2581  static constexpr bool _S_is_ldouble = is_same_v<_Tp, long double>;
2582 
2583  // allow _Tp == long double with -mlong-double-64
2584  static_assert(!(_S_is_ldouble && sizeof(long double) > sizeof(double)),
2585  "no __intrinsic_type support for 128-bit floating point on PowerPC");
2586 
2587 #ifndef __VSX__
2588  static_assert(!(is_same_v<_Tp, double>
2589  || (_S_is_ldouble && sizeof(long double) == sizeof(double))),
2590  "no __intrinsic_type support for 64-bit floating point on PowerPC w/o VSX");
2591 #endif
2592 
2593  static constexpr auto __element_type()
2594  {
2595  if constexpr (is_floating_point_v<_Tp>)
2596  {
2597  if constexpr (_S_is_ldouble)
2598  return double {};
2599  else
2600  return _Tp {};
2601  }
2602  else if constexpr (is_signed_v<_Tp>)
2603  {
2604  if constexpr (sizeof(_Tp) == sizeof(_SChar))
2605  return _SChar {};
2606  else if constexpr (sizeof(_Tp) == sizeof(short))
2607  return short {};
2608  else if constexpr (sizeof(_Tp) == sizeof(int))
2609  return int {};
2610  else if constexpr (sizeof(_Tp) == sizeof(_LLong))
2611  return _LLong {};
2612  }
2613  else
2614  {
2615  if constexpr (sizeof(_Tp) == sizeof(_UChar))
2616  return _UChar {};
2617  else if constexpr (sizeof(_Tp) == sizeof(_UShort))
2618  return _UShort {};
2619  else if constexpr (sizeof(_Tp) == sizeof(_UInt))
2620  return _UInt {};
2621  else if constexpr (sizeof(_Tp) == sizeof(_ULLong))
2622  return _ULLong {};
2623  }
2624  }
2625 
2626  using type = typename __intrinsic_type_impl<decltype(__element_type())>::type;
2627  };
2628 #endif // __ALTIVEC__
2629 
2630 // }}}
2631 // _SimdWrapper<bool>{{{1
2632 template <size_t _Width>
2633  struct _SimdWrapper<bool, _Width,
2634  void_t<typename __bool_storage_member_type<_Width>::type>>
2635  {
2636  using _BuiltinType = typename __bool_storage_member_type<_Width>::type;
2637  using value_type = bool;
2638 
2639  static constexpr size_t _S_full_size = sizeof(_BuiltinType) * __CHAR_BIT__;
2640 
2641  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdWrapper<bool, _S_full_size>
2642  __as_full_vector() const
2643  { return _M_data; }
2644 
2645  _GLIBCXX_SIMD_INTRINSIC constexpr
2646  _SimdWrapper() = default;
2647 
2648  _GLIBCXX_SIMD_INTRINSIC constexpr
2649  _SimdWrapper(_BuiltinType __k) : _M_data(__k) {};
2650 
2651  _GLIBCXX_SIMD_INTRINSIC
2652  operator const _BuiltinType&() const
2653  { return _M_data; }
2654 
2655  _GLIBCXX_SIMD_INTRINSIC
2656  operator _BuiltinType&()
2657  { return _M_data; }
2658 
2659  _GLIBCXX_SIMD_INTRINSIC _BuiltinType
2660  __intrin() const
2661  { return _M_data; }
2662 
2663  _GLIBCXX_SIMD_INTRINSIC constexpr value_type
2664  operator[](size_t __i) const
2665  { return _M_data & (_BuiltinType(1) << __i); }
2666 
2667  template <size_t __i>
2668  _GLIBCXX_SIMD_INTRINSIC constexpr value_type
2669  operator[](_SizeConstant<__i>) const
2670  { return _M_data & (_BuiltinType(1) << __i); }
2671 
2672  _GLIBCXX_SIMD_INTRINSIC constexpr void
2673  _M_set(size_t __i, value_type __x)
2674  {
2675  if (__x)
2676  _M_data |= (_BuiltinType(1) << __i);
2677  else
2678  _M_data &= ~(_BuiltinType(1) << __i);
2679  }
2680 
2681  _GLIBCXX_SIMD_INTRINSIC constexpr bool
2682  _M_is_constprop() const
2683  { return __builtin_constant_p(_M_data); }
2684 
2685  _GLIBCXX_SIMD_INTRINSIC constexpr bool
2686  _M_is_constprop_none_of() const
2687  {
2688  if (__builtin_constant_p(_M_data))
2689  {
2690  constexpr int __nbits = sizeof(_BuiltinType) * __CHAR_BIT__;
2691  constexpr _BuiltinType __active_mask
2692  = ~_BuiltinType() >> (__nbits - _Width);
2693  return (_M_data & __active_mask) == 0;
2694  }
2695  return false;
2696  }
2697 
2698  _GLIBCXX_SIMD_INTRINSIC constexpr bool
2699  _M_is_constprop_all_of() const
2700  {
2701  if (__builtin_constant_p(_M_data))
2702  {
2703  constexpr int __nbits = sizeof(_BuiltinType) * __CHAR_BIT__;
2704  constexpr _BuiltinType __active_mask
2705  = ~_BuiltinType() >> (__nbits - _Width);
2706  return (_M_data & __active_mask) == __active_mask;
2707  }
2708  return false;
2709  }
2710 
2711  _BuiltinType _M_data;
2712  };
2713 
2714 // _SimdWrapperBase{{{1
2715 template <bool _MustZeroInitPadding, typename _BuiltinType>
2716  struct _SimdWrapperBase;
2717 
2718 template <typename _BuiltinType>
2719  struct _SimdWrapperBase<false, _BuiltinType> // no padding or no SNaNs
2720  {
2721  _GLIBCXX_SIMD_INTRINSIC constexpr
2722  _SimdWrapperBase() = default;
2723 
2724  _GLIBCXX_SIMD_INTRINSIC constexpr
2725  _SimdWrapperBase(_BuiltinType __init) : _M_data(__init) {}
2726 
2727  _BuiltinType _M_data;
2728  };
2729 
2730 template <typename _BuiltinType>
2731  struct _SimdWrapperBase<true, _BuiltinType> // with padding that needs to
2732  // never become SNaN
2733  {
2734  _GLIBCXX_SIMD_INTRINSIC constexpr
2735  _SimdWrapperBase() : _M_data() {}
2736 
2737  _GLIBCXX_SIMD_INTRINSIC constexpr
2738  _SimdWrapperBase(_BuiltinType __init) : _M_data(__init) {}
2739 
2740  _BuiltinType _M_data;
2741  };
2742 
2743 // }}}
2744 // _SimdWrapper{{{
2745 struct _DisabledSimdWrapper;
2746 
2747 template <typename _Tp, size_t _Width>
2748  struct _SimdWrapper<
2749  _Tp, _Width,
2750  void_t<__vector_type_t<_Tp, _Width>, __intrinsic_type_t<_Tp, _Width>>>
2751  : _SimdWrapperBase<__has_iec559_behavior<__signaling_NaN, _Tp>::value
2752  && sizeof(_Tp) * _Width
2753  == sizeof(__vector_type_t<_Tp, _Width>),
2754  __vector_type_t<_Tp, _Width>>
2755  {
2756  static constexpr bool _S_need_default_init
2757  = __has_iec559_behavior<__signaling_NaN, _Tp>::value
2758  and sizeof(_Tp) * _Width == sizeof(__vector_type_t<_Tp, _Width>);
2759 
2760  using _BuiltinType = __vector_type_t<_Tp, _Width>;
2761 
2762  using _Base = _SimdWrapperBase<_S_need_default_init, _BuiltinType>;
2763 
2764  static_assert(__is_vectorizable_v<_Tp>);
2765  static_assert(_Width >= 2); // 1 doesn't make sense, use _Tp directly then
2766 
2767  using value_type = _Tp;
2768 
2769  static inline constexpr size_t _S_full_size
2770  = sizeof(_BuiltinType) / sizeof(value_type);
2771  static inline constexpr int _S_size = _Width;
2772  static inline constexpr bool _S_is_partial = _S_full_size != _S_size;
2773 
2774  using _Base::_M_data;
2775 
2776  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdWrapper<_Tp, _S_full_size>
2777  __as_full_vector() const
2778  { return _M_data; }
2779 
2780  _GLIBCXX_SIMD_INTRINSIC constexpr
2781  _SimdWrapper(initializer_list<_Tp> __init)
2782  : _Base(__generate_from_n_evaluations<_Width, _BuiltinType>(
2783  [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
2784  return __init.begin()[__i.value];
2785  })) {}
2786 
2787  _GLIBCXX_SIMD_INTRINSIC constexpr
2788  _SimdWrapper() = default;
2789 
2790  _GLIBCXX_SIMD_INTRINSIC constexpr
2791  _SimdWrapper(const _SimdWrapper&) = default;
2792 
2793  _GLIBCXX_SIMD_INTRINSIC constexpr
2794  _SimdWrapper(_SimdWrapper&&) = default;
2795 
2796  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdWrapper&
2797  operator=(const _SimdWrapper&) = default;
2798 
2799  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdWrapper&
2800  operator=(_SimdWrapper&&) = default;
2801 
2802  // Convert from exactly matching __vector_type_t
2803  using _SimdWrapperBase<_S_need_default_init, _BuiltinType>::_SimdWrapperBase;
2804 
2805  // Convert from __intrinsic_type_t if __intrinsic_type_t and __vector_type_t differ, otherwise
2806  // this ctor should not exist. Making the argument type unusable is our next best solution.
2807  _GLIBCXX_SIMD_INTRINSIC constexpr
2808  _SimdWrapper(conditional_t<is_same_v<_BuiltinType, __intrinsic_type_t<_Tp, _Width>>,
2809  _DisabledSimdWrapper, __intrinsic_type_t<_Tp, _Width>> __x)
2810  : _Base(__vector_bitcast<_Tp, _Width>(__x)) {}
2811 
2812  // Convert from different __vector_type_t, but only if bit reinterpretation is a correct
2813  // conversion of the value_type
2814  template <typename _V, typename _TVT = _VectorTraits<_V>,
2815  typename = enable_if_t<sizeof(typename _TVT::value_type) == sizeof(_Tp)
2816  and sizeof(_V) == sizeof(_BuiltinType)
2817  and is_integral_v<_Tp>
2818  and is_integral_v<typename _TVT::value_type>>>
2819  _GLIBCXX_SIMD_INTRINSIC constexpr
2820  _SimdWrapper(_V __x)
2821  : _Base(reinterpret_cast<_BuiltinType>(__x)) {}
2822 
2823  template <typename... _As,
2824  typename = enable_if_t<((is_same_v<simd_abi::scalar, _As> && ...)
2825  && sizeof...(_As) <= _Width)>>
2826  _GLIBCXX_SIMD_INTRINSIC constexpr
2827  operator _SimdTuple<_Tp, _As...>() const
2828  {
2829  return __generate_from_n_evaluations<sizeof...(_As), _SimdTuple<_Tp, _As...>>(
2830  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA
2831  { return _M_data[int(__i)]; });
2832  }
2833 
2834  _GLIBCXX_SIMD_INTRINSIC constexpr
2835  operator const _BuiltinType&() const
2836  { return _M_data; }
2837 
2838  _GLIBCXX_SIMD_INTRINSIC constexpr
2839  operator _BuiltinType&()
2840  { return _M_data; }
2841 
2842  _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
2843  operator[](size_t __i) const
2844  { return _M_data[__i]; }
2845 
2846  template <size_t __i>
2847  _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
2848  operator[](_SizeConstant<__i>) const
2849  { return _M_data[__i]; }
2850 
2851  _GLIBCXX_SIMD_INTRINSIC constexpr void
2852  _M_set(size_t __i, _Tp __x)
2853  {
2854  if (__builtin_is_constant_evaluated())
2855  _M_data = __generate_from_n_evaluations<_Width, _BuiltinType>([&](auto __j) {
2856  return __j == __i ? __x : _M_data[__j()];
2857  });
2858  else
2859  _M_data[__i] = __x;
2860  }
2861 
2862  _GLIBCXX_SIMD_INTRINSIC
2863  constexpr bool
2864  _M_is_constprop() const
2865  { return __builtin_constant_p(_M_data); }
2866 
2867  _GLIBCXX_SIMD_INTRINSIC constexpr bool
2868  _M_is_constprop_none_of() const
2869  {
2870  if (__builtin_constant_p(_M_data))
2871  {
2872  bool __r = true;
2873  if constexpr (is_floating_point_v<_Tp>)
2874  {
2875  using _Ip = __int_for_sizeof_t<_Tp>;
2876  const auto __intdata = __vector_bitcast<_Ip>(_M_data);
2877  __execute_n_times<_Width>(
2878  [&](auto __i) { __r &= __intdata[__i.value] == _Ip(); });
2879  }
2880  else
2881  __execute_n_times<_Width>(
2882  [&](auto __i) { __r &= _M_data[__i.value] == _Tp(); });
2883  if (__builtin_constant_p(__r))
2884  return __r;
2885  }
2886  return false;
2887  }
2888 
2889  _GLIBCXX_SIMD_INTRINSIC constexpr bool
2890  _M_is_constprop_all_of() const
2891  {
2892  if (__builtin_constant_p(_M_data))
2893  {
2894  bool __r = true;
2895  if constexpr (is_floating_point_v<_Tp>)
2896  {
2897  using _Ip = __int_for_sizeof_t<_Tp>;
2898  const auto __intdata = __vector_bitcast<_Ip>(_M_data);
2899  __execute_n_times<_Width>(
2900  [&](auto __i) { __r &= __intdata[__i.value] == ~_Ip(); });
2901  }
2902  else
2903  __execute_n_times<_Width>(
2904  [&](auto __i) { __r &= _M_data[__i.value] == ~_Tp(); });
2905  if (__builtin_constant_p(__r))
2906  return __r;
2907  }
2908  return false;
2909  }
2910  };
2911 
2912 // }}}
2913 
2914 // __vectorized_sizeof {{{
2915 template <typename _Tp>
2916  constexpr size_t
2917  __vectorized_sizeof()
2918  {
2919  if constexpr (!__is_vectorizable_v<_Tp>)
2920  return 0;
2921 
2922  if constexpr (sizeof(_Tp) <= 8)
2923  {
2924  // X86:
2925  if constexpr (__have_avx512bw)
2926  return 64;
2927  if constexpr (__have_avx512f && sizeof(_Tp) >= 4)
2928  return 64;
2929  if constexpr (__have_avx2)
2930  return 32;
2931  if constexpr (__have_avx && is_floating_point_v<_Tp>)
2932  return 32;
2933  if constexpr (__have_sse2)
2934  return 16;
2935  if constexpr (__have_sse && is_same_v<_Tp, float>)
2936  return 16;
2937  /* The following is too much trouble because of mixed MMX and x87 code.
2938  * While nothing here explicitly calls MMX instructions of registers,
2939  * they are still emitted but no EMMS cleanup is done.
2940  if constexpr (__have_mmx && sizeof(_Tp) <= 4 && is_integral_v<_Tp>)
2941  return 8;
2942  */
2943 
2944  // PowerPC:
2945  if constexpr (__have_power8vec
2946  || (__have_power_vmx && (sizeof(_Tp) < 8))
2947  || (__have_power_vsx && is_floating_point_v<_Tp>) )
2948  return 16;
2949 
2950  // ARM:
2951  if constexpr (__have_neon_a64)
2952  return 16;
2953  if constexpr (__have_neon_a32 and (not is_floating_point_v<_Tp>
2954  or is_same_v<_Tp, float>))
2955  return 16;
2956  if constexpr (__have_neon
2957  && sizeof(_Tp) < 8
2958  // Only allow fp if the user allows non-ICE559 fp (e.g.
2959  // via -ffast-math). ARMv7 NEON fp is not conforming to
2960  // IEC559.
2961  && (__support_neon_float || !is_floating_point_v<_Tp>))
2962  return 16;
2963  }
2964 
2965  return sizeof(_Tp);
2966  }
2967 
2968 // }}}
2969 namespace simd_abi {
2970 // most of simd_abi is defined in simd_detail.h
2971 template <typename _Tp>
2972  inline constexpr int max_fixed_size
2973  = ((__have_avx512bw && sizeof(_Tp) == 1)
2974  || (__have_sve && __sve_vectorized_size_bytes/sizeof(_Tp) >= 64)) ? 64 : 32;
2975 
2976 // compatible {{{
2977 #if defined __x86_64__ || defined __aarch64__
2978 template <typename _Tp>
2979  using compatible = conditional_t<(sizeof(_Tp) <= 8), _VecBuiltin<16>, scalar>;
2980 #elif defined __ARM_NEON
2981 // FIXME: not sure, probably needs to be scalar (or dependent on the hard-float
2982 // ABI?)
2983 template <typename _Tp>
2984  using compatible
2985  = conditional_t<(sizeof(_Tp) < 8
2986  && (__support_neon_float || !is_floating_point_v<_Tp>)),
2987  _VecBuiltin<16>, scalar>;
2988 #else
2989 template <typename>
2990  using compatible = scalar;
2991 #endif
2992 
2993 // }}}
2994 // native {{{
2995 template <typename _Tp>
2996  constexpr auto
2997  __determine_native_abi()
2998  {
2999  constexpr size_t __bytes = __vectorized_sizeof<_Tp>();
3000  if constexpr (__bytes == sizeof(_Tp))
3001  return static_cast<scalar*>(nullptr);
3002  else if constexpr (__have_sve)
3003  return static_cast<_SveAbi<__sve_vectorized_size_bytes>*>(nullptr);
3004  else if constexpr (__have_avx512vl || (__have_avx512f && __bytes == 64))
3005  return static_cast<_VecBltnBtmsk<__bytes>*>(nullptr);
3006  else
3007  return static_cast<_VecBuiltin<__bytes>*>(nullptr);
3008  }
3009 
3010 template <typename _Tp, typename = enable_if_t<__is_vectorizable_v<_Tp>>>
3011  using native = remove_pointer_t<decltype(__determine_native_abi<_Tp>())>;
3012 
3013 // }}}
3014 // __default_abi {{{
3015 #if defined _GLIBCXX_SIMD_DEFAULT_ABI
3016 template <typename _Tp>
3017  using __default_abi = _GLIBCXX_SIMD_DEFAULT_ABI<_Tp>;
3018 #else
3019 template <typename _Tp>
3020  using __default_abi = compatible<_Tp>;
3021 #endif
3022 
3023 // }}}
3024 } // namespace simd_abi
3025 
3026 // traits {{{1
3027 template <typename _Tp>
3028  struct is_simd_flag_type
3029  : false_type
3030  {};
3031 
3032 template <>
3033  struct is_simd_flag_type<element_aligned_tag>
3034  : true_type
3035  {};
3036 
3037 template <>
3038  struct is_simd_flag_type<vector_aligned_tag>
3039  : true_type
3040  {};
3041 
3042 template <size_t _Np>
3043  struct is_simd_flag_type<overaligned_tag<_Np>>
3044  : __bool_constant<(_Np > 0) and __has_single_bit(_Np)>
3045  {};
3046 
3047 template <typename _Tp>
3048  inline constexpr bool is_simd_flag_type_v = is_simd_flag_type<_Tp>::value;
3049 
3050 template <typename _Tp, typename = enable_if_t<is_simd_flag_type_v<_Tp>>>
3051  using _IsSimdFlagType = _Tp;
3052 
3053 // is_abi_tag {{{2
3054 template <typename _Tp, typename = void_t<>>
3055  struct is_abi_tag : false_type {};
3056 
3057 template <typename _Tp>
3058  struct is_abi_tag<_Tp, void_t<typename _Tp::_IsValidAbiTag>>
3059  : public _Tp::_IsValidAbiTag {};
3060 
3061 template <typename _Tp>
3062  inline constexpr bool is_abi_tag_v = is_abi_tag<_Tp>::value;
3063 
3064 // is_simd(_mask) {{{2
3065 template <typename _Tp>
3066  struct is_simd : public false_type {};
3067 
3068 template <typename _Tp>
3069  inline constexpr bool is_simd_v = is_simd<_Tp>::value;
3070 
3071 template <typename _Tp>
3072  struct is_simd_mask : public false_type {};
3073 
3074 template <typename _Tp>
3075 inline constexpr bool is_simd_mask_v = is_simd_mask<_Tp>::value;
3076 
3077 // simd_size {{{2
3078 template <typename _Tp, typename _Abi, typename = void>
3079  struct __simd_size_impl {};
3080 
3081 template <typename _Tp, typename _Abi>
3082  struct __simd_size_impl<
3083  _Tp, _Abi,
3084  enable_if_t<conjunction_v<__is_vectorizable<_Tp>, is_abi_tag<_Abi>>>>
3085  : _SizeConstant<_Abi::template _S_size<_Tp>> {};
3086 
3087 template <typename _Tp, typename _Abi = simd_abi::__default_abi<_Tp>>
3088  struct simd_size : __simd_size_impl<_Tp, _Abi> {};
3089 
3090 template <typename _Tp, typename _Abi = simd_abi::__default_abi<_Tp>>
3091  inline constexpr size_t simd_size_v = simd_size<_Tp, _Abi>::value;
3092 
3093 // simd_abi::deduce {{{2
3094 template <typename _Tp, size_t _Np, typename = void>
3095  struct __deduce_impl;
3096 
3097 template <typename _Tp, size_t _Np, typename = void>
3098  struct __no_sve_deduce_impl;
3099 
3100 namespace simd_abi {
3101 /**
3102  * @tparam _Tp The requested `value_type` for the elements.
3103  * @tparam _Np The requested number of elements.
3104  * @tparam _Abis This parameter is ignored, since this implementation cannot
3105  * make any use of it. Either __a good native ABI is matched and used as `type`
3106  * alias, or the `fixed_size<_Np>` ABI is used, which internally is built from
3107  * the best matching native ABIs.
3108  */
3109 template <typename _Tp, size_t _Np, typename...>
3110  struct deduce : __deduce_impl<_Tp, _Np> {};
3111 
3112 template <typename _Tp, size_t _Np, typename... _Abis>
3113  using deduce_t = typename deduce<_Tp, _Np, _Abis...>::type;
3114 
3115 template <typename _Tp, size_t _Np, typename...>
3116  struct __no_sve_deduce : __no_sve_deduce_impl<_Tp, _Np> {};
3117 
3118 template <typename _Tp, size_t _Np, typename... _Abis>
3119  using __no_sve_deduce_t = typename __no_sve_deduce<_Tp, _Np, _Abis...>::type;
3120 } // namespace simd_abi
3121 
3122 // }}}2
3123 // rebind_simd {{{2
3124 template <typename _Tp, typename _V, typename = void>
3125  struct rebind_simd;
3126 
3127 template <typename _Tp, typename _Up, typename _Abi>
3128  struct rebind_simd<_Tp, simd<_Up, _Abi>,
3129  void_t<std::conditional_t<!__is_sve_abi<_Abi>(),
3130  simd_abi::__no_sve_deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>,
3131  simd_abi::deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>>>>
3132  {
3133  using type = simd<_Tp, std::conditional_t<
3134  !__is_sve_abi<_Abi>(),
3135  simd_abi::__no_sve_deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>,
3136  simd_abi::deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>>>;
3137  };
3138 
3139 template <typename _Tp, typename _Up, typename _Abi>
3140  struct rebind_simd<_Tp, simd_mask<_Up, _Abi>,
3141  void_t<std::conditional_t<!__is_sve_abi<_Abi>(),
3142  simd_abi::__no_sve_deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>,
3143  simd_abi::deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>>>>
3144  {
3145  using type = simd_mask<_Tp, std::conditional_t<
3146  !__is_sve_abi<_Abi>(),
3147  simd_abi::__no_sve_deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>,
3148  simd_abi::deduce_t<_Tp, simd_size_v<_Up, _Abi>, _Abi>>>;
3149  };
3150 
3151 template <typename _Tp, typename _V>
3152  using rebind_simd_t = typename rebind_simd<_Tp, _V>::type;
3153 
3154 // resize_simd {{{2
3155 template <int _Np, typename _V, typename = void>
3156  struct resize_simd;
3157 
3158 template <int _Np, typename _Tp, typename _Abi>
3159  struct resize_simd<_Np, simd<_Tp, _Abi>, void_t<simd_abi::deduce_t<_Tp, _Np, _Abi>>>
3160  { using type = simd<_Tp, simd_abi::deduce_t<_Tp, _Np, _Abi>>; };
3161 
3162 template <int _Np, typename _Tp, typename _Abi>
3163  struct resize_simd<_Np, simd_mask<_Tp, _Abi>, void_t<simd_abi::deduce_t<_Tp, _Np, _Abi>>>
3164  { using type = simd_mask<_Tp, simd_abi::deduce_t<_Tp, _Np, _Abi>>; };
3165 
3166 template <int _Np, typename _V>
3167  using resize_simd_t = typename resize_simd<_Np, _V>::type;
3168 
3169 // }}}2
3170 // memory_alignment {{{2
3171 template <typename _Tp, typename _Up = typename _Tp::value_type>
3172  struct memory_alignment
3173  : public _SizeConstant<vector_aligned_tag::_S_alignment<_Tp, _Up>> {};
3174 
3175 template <typename _Tp, typename _Up = typename _Tp::value_type>
3176  inline constexpr size_t memory_alignment_v = memory_alignment<_Tp, _Up>::value;
3177 
3178 // class template simd [simd] {{{1
3179 template <typename _Tp, typename _Abi = simd_abi::__default_abi<_Tp>>
3180  class simd;
3181 
3182 template <typename _Tp, typename _Abi>
3183  struct is_simd<simd<_Tp, _Abi>> : public true_type {};
3184 
3185 template <typename _Tp>
3186  using native_simd = simd<_Tp, simd_abi::native<_Tp>>;
3187 
3188 template <typename _Tp, int _Np>
3189  using fixed_size_simd = simd<_Tp, simd_abi::fixed_size<_Np>>;
3190 
3191 template <typename _Tp, size_t _Np>
3192  using __deduced_simd = simd<_Tp, simd_abi::deduce_t<_Tp, _Np>>;
3193 
3194 // class template simd_mask [simd_mask] {{{1
3195 template <typename _Tp, typename _Abi = simd_abi::__default_abi<_Tp>>
3196  class simd_mask;
3197 
3198 template <typename _Tp, typename _Abi>
3199  struct is_simd_mask<simd_mask<_Tp, _Abi>> : public true_type {};
3200 
3201 template <typename _Tp>
3202  using native_simd_mask = simd_mask<_Tp, simd_abi::native<_Tp>>;
3203 
3204 template <typename _Tp, int _Np>
3205  using fixed_size_simd_mask = simd_mask<_Tp, simd_abi::fixed_size<_Np>>;
3206 
3207 template <typename _Tp, size_t _Np>
3208  using __deduced_simd_mask = simd_mask<_Tp, simd_abi::deduce_t<_Tp, _Np>>;
3209 
3210 // casts [simd.casts] {{{1
3211 // static_simd_cast {{{2
3212 template <typename _Tp, typename _Up, typename _Ap, bool = is_simd_v<_Tp>, typename = void>
3213  struct __static_simd_cast_return_type;
3214 
3215 template <typename _Tp, typename _A0, typename _Up, typename _Ap>
3216  struct __static_simd_cast_return_type<simd_mask<_Tp, _A0>, _Up, _Ap, false, void>
3217  : __static_simd_cast_return_type<simd<_Tp, _A0>, _Up, _Ap> {};
3218 
3219 template <typename _Tp, typename _Up, typename _Ap>
3220  struct __static_simd_cast_return_type<
3221  _Tp, _Up, _Ap, true, enable_if_t<_Tp::size() == simd_size_v<_Up, _Ap>>>
3222  { using type = _Tp; };
3223 
3224 template <typename _Tp, typename _Ap>
3225  struct __static_simd_cast_return_type<_Tp, _Tp, _Ap, false,
3226 #ifdef _GLIBCXX_SIMD_FIX_P2TS_ISSUE66
3227  enable_if_t<__is_vectorizable_v<_Tp>>
3228 #else
3229  void
3230 #endif
3231  >
3232  { using type = simd<_Tp, _Ap>; };
3233 
3234 template <typename _Tp, typename = void>
3235  struct __safe_make_signed { using type = _Tp;};
3236 
3237 template <typename _Tp>
3238  struct __safe_make_signed<_Tp, enable_if_t<is_integral_v<_Tp>>>
3239  {
3240  // the extra make_unsigned_t is because of PR85951
3241  using type = make_signed_t<make_unsigned_t<_Tp>>;
3242  };
3243 
3244 template <typename _Tp>
3245  using safe_make_signed_t = typename __safe_make_signed<_Tp>::type;
3246 
3247 template <typename _Tp, typename _Up, typename _Ap>
3248  struct __static_simd_cast_return_type<_Tp, _Up, _Ap, false,
3249 #ifdef _GLIBCXX_SIMD_FIX_P2TS_ISSUE66
3250  enable_if_t<__is_vectorizable_v<_Tp>>
3251 #else
3252  void
3253 #endif
3254  >
3255  {
3256  using type = conditional_t<
3257  (is_integral_v<_Up> && is_integral_v<_Tp> &&
3258 #ifndef _GLIBCXX_SIMD_FIX_P2TS_ISSUE65
3259  is_signed_v<_Up> != is_signed_v<_Tp> &&
3260 #endif
3261  is_same_v<safe_make_signed_t<_Up>, safe_make_signed_t<_Tp>>),
3262  simd<_Tp, _Ap>, fixed_size_simd<_Tp, simd_size_v<_Up, _Ap>>>;
3263  };
3264 
3265 template <typename _Tp, typename _Up, typename _Ap,
3266  typename _R
3267  = typename __static_simd_cast_return_type<_Tp, _Up, _Ap>::type>
3268  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _R
3269  static_simd_cast(const simd<_Up, _Ap>& __x)
3270  {
3271  if constexpr (is_same<_R, simd<_Up, _Ap>>::value)
3272  return __x;
3273  else
3274  {
3275  _SimdConverter<_Up, _Ap, typename _R::value_type, typename _R::abi_type>
3276  __c;
3277  return _R(__private_init, __c(__data(__x)));
3278  }
3279  }
3280 
3281 namespace __proposed {
3282 template <typename _Tp, typename _Up, typename _Ap,
3283  typename _R
3284  = typename __static_simd_cast_return_type<_Tp, _Up, _Ap>::type>
3285  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR typename _R::mask_type
3286  static_simd_cast(const simd_mask<_Up, _Ap>& __x)
3287  {
3288  using _RM = typename _R::mask_type;
3289  return {__private_init, _RM::abi_type::_MaskImpl::template _S_convert<
3290  typename _RM::simd_type::value_type>(__x)};
3291  }
3292 
3293 template <typename _To, typename _Up, typename _Abi>
3294  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3295  _To
3296  simd_bit_cast(const simd<_Up, _Abi>& __x)
3297  {
3298  using _Tp = typename _To::value_type;
3299  using _ToMember = typename _SimdTraits<_Tp, typename _To::abi_type>::_SimdMember;
3300  using _From = simd<_Up, _Abi>;
3301  using _FromMember = typename _SimdTraits<_Up, _Abi>::_SimdMember;
3302  // with concepts, the following should be constraints
3303  static_assert(sizeof(_To) == sizeof(_From));
3304  static_assert(is_trivially_copyable_v<_Tp> && is_trivially_copyable_v<_Up>);
3305  static_assert(is_trivially_copyable_v<_ToMember> && is_trivially_copyable_v<_FromMember>);
3306 #if __has_builtin(__builtin_bit_cast)
3307  return {__private_init, __builtin_bit_cast(_ToMember, __data(__x))};
3308 #else
3309  return {__private_init, __bit_cast<_ToMember>(__data(__x))};
3310 #endif
3311  }
3312 
3313 template <typename _To, typename _Up, typename _Abi>
3314  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3315  _To
3316  simd_bit_cast(const simd_mask<_Up, _Abi>& __x)
3317  {
3318  using _From = simd_mask<_Up, _Abi>;
3319  static_assert(sizeof(_To) == sizeof(_From));
3320  static_assert(is_trivially_copyable_v<_From>);
3321  // _To can be simd<T, A>, specifically simd<T, fixed_size<N>> in which case _To is not trivially
3322  // copyable.
3323  if constexpr (is_simd_v<_To>)
3324  {
3325  using _Tp = typename _To::value_type;
3326  using _ToMember = typename _SimdTraits<_Tp, typename _To::abi_type>::_SimdMember;
3327  static_assert(is_trivially_copyable_v<_ToMember>);
3328 #if __has_builtin(__builtin_bit_cast)
3329  return {__private_init, __builtin_bit_cast(_ToMember, __x)};
3330 #else
3331  return {__private_init, __bit_cast<_ToMember>(__x)};
3332 #endif
3333  }
3334  else
3335  {
3336  static_assert(is_trivially_copyable_v<_To>);
3337 #if __has_builtin(__builtin_bit_cast)
3338  return __builtin_bit_cast(_To, __x);
3339 #else
3340  return __bit_cast<_To>(__x);
3341 #endif
3342  }
3343  }
3344 } // namespace __proposed
3345 
3346 // simd_cast {{{2
3347 template <typename _Tp, typename _Up, typename _Ap,
3348  typename _To = __value_type_or_identity_t<_Tp>>
3349  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR auto
3350  simd_cast(const simd<_ValuePreserving<_Up, _To>, _Ap>& __x)
3351  -> decltype(static_simd_cast<_Tp>(__x))
3352  { return static_simd_cast<_Tp>(__x); }
3353 
3354 namespace __proposed {
3355 template <typename _Tp, typename _Up, typename _Ap,
3356  typename _To = __value_type_or_identity_t<_Tp>>
3357  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR auto
3358  simd_cast(const simd_mask<_ValuePreserving<_Up, _To>, _Ap>& __x)
3359  -> decltype(static_simd_cast<_Tp>(__x))
3360  { return static_simd_cast<_Tp>(__x); }
3361 } // namespace __proposed
3362 
3363 // }}}2
3364 // resizing_simd_cast {{{
3365 namespace __proposed {
3366 /* Proposed spec:
3367 
3368 template <class T, class U, class Abi>
3369 T resizing_simd_cast(const simd<U, Abi>& x)
3370 
3371 p1 Constraints:
3372  - is_simd_v<T> is true and
3373  - T::value_type is the same type as U
3374 
3375 p2 Returns:
3376  A simd object with the i^th element initialized to x[i] for all i in the
3377  range of [0, min(T::size(), simd_size_v<U, Abi>)). If T::size() is larger
3378  than simd_size_v<U, Abi>, the remaining elements are value-initialized.
3379 
3380 template <class T, class U, class Abi>
3381 T resizing_simd_cast(const simd_mask<U, Abi>& x)
3382 
3383 p1 Constraints: is_simd_mask_v<T> is true
3384 
3385 p2 Returns:
3386  A simd_mask object with the i^th element initialized to x[i] for all i in
3387 the range of [0, min(T::size(), simd_size_v<U, Abi>)). If T::size() is larger
3388  than simd_size_v<U, Abi>, the remaining elements are initialized to false.
3389 
3390  */
3391 
3392 template <typename _Tp, typename _Up, typename _Ap>
3393  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR enable_if_t<
3394  conjunction_v<is_simd<_Tp>, is_same<typename _Tp::value_type, _Up>>, _Tp>
3395  resizing_simd_cast(const simd<_Up, _Ap>& __x)
3396  {
3397  if constexpr (is_same_v<typename _Tp::abi_type, _Ap>)
3398  return __x;
3399  else if (__builtin_is_constant_evaluated())
3400  return _Tp([&](auto __i) constexpr {
3401  return __i < simd_size_v<_Up, _Ap> ? __x[__i] : _Up();
3402  });
3403  else if constexpr (simd_size_v<_Up, _Ap> == 1)
3404  {
3405  _Tp __r{};
3406  __r[0] = __x[0];
3407  return __r;
3408  }
3409  else if constexpr (_Tp::size() == 1)
3410  return __x[0];
3411  else if constexpr (sizeof(_Tp) == sizeof(__x)
3412  && !__is_fixed_size_abi_v<_Ap> && !__is_sve_abi<_Ap>())
3413  return {__private_init,
3414  __vector_bitcast<typename _Tp::value_type, _Tp::size()>(
3415  _Ap::_S_masked(__data(__x))._M_data)};
3416  else
3417  {
3418  _Tp __r{};
3419  __builtin_memcpy(&__data(__r), &__data(__x),
3420  sizeof(_Up)
3421  * std::min(_Tp::size(), simd_size_v<_Up, _Ap>));
3422  return __r;
3423  }
3424  }
3425 
3426 template <typename _Tp, typename _Up, typename _Ap>
3427  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3428  enable_if_t<is_simd_mask_v<_Tp>, _Tp>
3429  resizing_simd_cast(const simd_mask<_Up, _Ap>& __x)
3430  {
3431  return {__private_init, _Tp::abi_type::_MaskImpl::template _S_convert<
3432  typename _Tp::simd_type::value_type>(__x)};
3433  }
3434 } // namespace __proposed
3435 
3436 // }}}
3437 // to_fixed_size {{{2
3438 template <typename _Tp, int _Np>
3439  _GLIBCXX_SIMD_INTRINSIC fixed_size_simd<_Tp, _Np>
3440  to_fixed_size(const fixed_size_simd<_Tp, _Np>& __x)
3441  { return __x; }
3442 
3443 template <typename _Tp, int _Np>
3444  _GLIBCXX_SIMD_INTRINSIC fixed_size_simd_mask<_Tp, _Np>
3445  to_fixed_size(const fixed_size_simd_mask<_Tp, _Np>& __x)
3446  { return __x; }
3447 
3448 template <typename _Tp, typename _Ap>
3449  _GLIBCXX_SIMD_INTRINSIC fixed_size_simd<_Tp, simd_size_v<_Tp, _Ap>>
3450  to_fixed_size(const simd<_Tp, _Ap>& __x)
3451  {
3452  using _Rp = fixed_size_simd<_Tp, simd_size_v<_Tp, _Ap>>;
3453  return _Rp([&__x](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { return __x[__i]; });
3454  }
3455 
3456 template <typename _Tp, typename _Ap>
3457  _GLIBCXX_SIMD_INTRINSIC fixed_size_simd_mask<_Tp, simd_size_v<_Tp, _Ap>>
3458  to_fixed_size(const simd_mask<_Tp, _Ap>& __x)
3459  {
3460  return {__private_init,
3461  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { return __x[__i]; }};
3462  }
3463 
3464 // to_native {{{2
3465 template <typename _Tp, int _Np>
3466  _GLIBCXX_SIMD_INTRINSIC
3467  enable_if_t<(_Np == native_simd<_Tp>::size()), native_simd<_Tp>>
3468  to_native(const fixed_size_simd<_Tp, _Np>& __x)
3469  {
3470  alignas(memory_alignment_v<native_simd<_Tp>>) _Tp __mem[_Np];
3471  __x.copy_to(__mem, vector_aligned);
3472  return {__mem, vector_aligned};
3473  }
3474 
3475 template <typename _Tp, int _Np>
3476  _GLIBCXX_SIMD_INTRINSIC
3477  enable_if_t<(_Np == native_simd_mask<_Tp>::size()), native_simd_mask<_Tp>>
3478  to_native(const fixed_size_simd_mask<_Tp, _Np>& __x)
3479  {
3480  return native_simd_mask<_Tp>(
3481  __private_init,
3482  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { return __x[__i]; });
3483  }
3484 
3485 // to_compatible {{{2
3486 template <typename _Tp, int _Np>
3487  _GLIBCXX_SIMD_INTRINSIC enable_if_t<(_Np == simd<_Tp>::size()), simd<_Tp>>
3488  to_compatible(const simd<_Tp, simd_abi::fixed_size<_Np>>& __x)
3489  {
3490  alignas(memory_alignment_v<simd<_Tp>>) _Tp __mem[_Np];
3491  __x.copy_to(__mem, vector_aligned);
3492  return {__mem, vector_aligned};
3493  }
3494 
3495 template <typename _Tp, int _Np>
3496  _GLIBCXX_SIMD_INTRINSIC
3497  enable_if_t<(_Np == simd_mask<_Tp>::size()), simd_mask<_Tp>>
3498  to_compatible(const simd_mask<_Tp, simd_abi::fixed_size<_Np>>& __x)
3499  {
3500  return simd_mask<_Tp>(
3501  __private_init,
3502  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { return __x[__i]; });
3503  }
3504 
3505 // masked assignment [simd_mask.where] {{{1
3506 
3507 // where_expression {{{1
3508 // const_where_expression<M, T> {{{2
3509 template <typename _M, typename _Tp>
3510  class const_where_expression
3511  {
3512  using _V = _Tp;
3513  static_assert(is_same_v<_V, __remove_cvref_t<_Tp>>);
3514 
3515  struct _Wrapper { using value_type = _V; };
3516 
3517  protected:
3518  using _Impl = typename _V::_Impl;
3519 
3520  using value_type =
3521  typename conditional_t<is_arithmetic_v<_V>, _Wrapper, _V>::value_type;
3522 
3523  _GLIBCXX_SIMD_INTRINSIC friend const _M&
3524  __get_mask(const const_where_expression& __x)
3525  { return __x._M_k; }
3526 
3527  _GLIBCXX_SIMD_INTRINSIC friend const _Tp&
3528  __get_lvalue(const const_where_expression& __x)
3529  { return __x._M_value; }
3530 
3531  const _M& _M_k;
3532  _Tp& _M_value;
3533 
3534  public:
3535  const_where_expression(const const_where_expression&) = delete;
3536 
3537  const_where_expression& operator=(const const_where_expression&) = delete;
3538 
3539  _GLIBCXX_SIMD_INTRINSIC constexpr
3540  const_where_expression(const _M& __kk, const _Tp& dd)
3541  : _M_k(__kk), _M_value(const_cast<_Tp&>(dd)) {}
3542 
3543  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
3544  operator-() const&&
3545  {
3546  return {__private_init,
3547  _Impl::template _S_masked_unary<negate>(__data(_M_k),
3548  __data(_M_value))};
3549  }
3550 
3551  template <typename _Up, typename _Flags>
3552  [[nodiscard]] _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
3553  copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
3554  {
3555  return {__private_init,
3556  _Impl::_S_masked_load(__data(_M_value), __data(_M_k),
3557  _Flags::template _S_apply<_V>(__mem))};
3558  }
3559 
3560  template <typename _Up, typename _Flags>
3561  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3562  copy_to(_LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
3563  {
3564  _Impl::_S_masked_store(__data(_M_value),
3565  _Flags::template _S_apply<_V>(__mem),
3566  __data(_M_k));
3567  }
3568  };
3569 
3570 // const_where_expression<bool, T> {{{2
3571 template <typename _Tp>
3572  class const_where_expression<bool, _Tp>
3573  {
3574  using _M = bool;
3575  using _V = _Tp;
3576 
3577  static_assert(is_same_v<_V, __remove_cvref_t<_Tp>>);
3578 
3579  struct _Wrapper { using value_type = _V; };
3580 
3581  protected:
3582  using value_type
3583  = typename conditional_t<is_arithmetic_v<_V>, _Wrapper, _V>::value_type;
3584 
3585  _GLIBCXX_SIMD_INTRINSIC friend const _M&
3586  __get_mask(const const_where_expression& __x)
3587  { return __x._M_k; }
3588 
3589  _GLIBCXX_SIMD_INTRINSIC friend const _Tp&
3590  __get_lvalue(const const_where_expression& __x)
3591  { return __x._M_value; }
3592 
3593  const bool _M_k;
3594  _Tp& _M_value;
3595 
3596  public:
3597  const_where_expression(const const_where_expression&) = delete;
3598  const_where_expression& operator=(const const_where_expression&) = delete;
3599 
3600  _GLIBCXX_SIMD_INTRINSIC constexpr
3601  const_where_expression(const bool __kk, const _Tp& dd)
3602  : _M_k(__kk), _M_value(const_cast<_Tp&>(dd)) {}
3603 
3604  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
3605  operator-() const&&
3606  { return _M_k ? -_M_value : _M_value; }
3607 
3608  template <typename _Up, typename _Flags>
3609  [[nodiscard]] _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
3610  copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
3611  { return _M_k ? static_cast<_V>(__mem[0]) : _M_value; }
3612 
3613  template <typename _Up, typename _Flags>
3614  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3615  copy_to(_LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
3616  {
3617  if (_M_k)
3618  __mem[0] = _M_value;
3619  }
3620  };
3621 
3622 // where_expression<M, T> {{{2
3623 template <typename _M, typename _Tp>
3624  class where_expression : public const_where_expression<_M, _Tp>
3625  {
3626  using _Impl = typename const_where_expression<_M, _Tp>::_Impl;
3627 
3628  static_assert(!is_const<_Tp>::value,
3629  "where_expression may only be instantiated with __a non-const "
3630  "_Tp parameter");
3631 
3632  using typename const_where_expression<_M, _Tp>::value_type;
3633  using const_where_expression<_M, _Tp>::_M_k;
3634  using const_where_expression<_M, _Tp>::_M_value;
3635 
3636  static_assert(
3637  is_same<typename _M::abi_type, typename _Tp::abi_type>::value, "");
3638  static_assert(_M::size() == _Tp::size(), "");
3639 
3640  _GLIBCXX_SIMD_INTRINSIC friend constexpr _Tp&
3641  __get_lvalue(where_expression& __x)
3642  { return __x._M_value; }
3643 
3644  public:
3645  where_expression(const where_expression&) = delete;
3646  where_expression& operator=(const where_expression&) = delete;
3647 
3648  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3649  where_expression(const _M& __kk, _Tp& dd)
3650  : const_where_expression<_M, _Tp>(__kk, dd) {}
3651 
3652  template <typename _Up>
3653  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3654  operator=(_Up&& __x) &&
3655  {
3656  _Impl::_S_masked_assign(__data(_M_k), __data(_M_value),
3657  __to_value_type_or_member_type<_Tp>(
3658  static_cast<_Up&&>(__x)));
3659  }
3660 
3661 #define _GLIBCXX_SIMD_OP_(__op, __name) \
3662  template <typename _Up> \
3663  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void \
3664  operator __op##=(_Up&& __x)&& \
3665  { \
3666  _Impl::template _S_masked_cassign( \
3667  __data(_M_k), __data(_M_value), \
3668  __to_value_type_or_member_type<_Tp>(static_cast<_Up&&>(__x)), \
3669  [](auto __impl, auto __lhs, auto __rhs) \
3670  constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA \
3671  { return __impl.__name(__lhs, __rhs); }); \
3672  } \
3673  static_assert(true)
3674  _GLIBCXX_SIMD_OP_(+, _S_plus);
3675  _GLIBCXX_SIMD_OP_(-, _S_minus);
3676  _GLIBCXX_SIMD_OP_(*, _S_multiplies);
3677  _GLIBCXX_SIMD_OP_(/, _S_divides);
3678  _GLIBCXX_SIMD_OP_(%, _S_modulus);
3679  _GLIBCXX_SIMD_OP_(&, _S_bit_and);
3680  _GLIBCXX_SIMD_OP_(|, _S_bit_or);
3681  _GLIBCXX_SIMD_OP_(^, _S_bit_xor);
3682  _GLIBCXX_SIMD_OP_(<<, _S_shift_left);
3683  _GLIBCXX_SIMD_OP_(>>, _S_shift_right);
3684 #undef _GLIBCXX_SIMD_OP_
3685 
3686  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3687  operator++() &&
3688  {
3689  __data(_M_value)
3690  = _Impl::template _S_masked_unary<__increment>(__data(_M_k), __data(_M_value));
3691  }
3692 
3693  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3694  operator++(int) &&
3695  {
3696  __data(_M_value)
3697  = _Impl::template _S_masked_unary<__increment>(__data(_M_k), __data(_M_value));
3698  }
3699 
3700  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3701  operator--() &&
3702  {
3703  __data(_M_value)
3704  = _Impl::template _S_masked_unary<__decrement>(__data(_M_k), __data(_M_value));
3705  }
3706 
3707  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3708  operator--(int) &&
3709  {
3710  __data(_M_value)
3711  = _Impl::template _S_masked_unary<__decrement>(__data(_M_k), __data(_M_value));
3712  }
3713 
3714  // intentionally hides const_where_expression::copy_from
3715  template <typename _Up, typename _Flags>
3716  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3717  copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) &&
3718  {
3719  __data(_M_value) = _Impl::_S_masked_load(__data(_M_value), __data(_M_k),
3720  _Flags::template _S_apply<_Tp>(__mem));
3721  }
3722  };
3723 
3724 // where_expression<bool, T> {{{2
3725 template <typename _Tp>
3726  class where_expression<bool, _Tp>
3727  : public const_where_expression<bool, _Tp>
3728  {
3729  using _M = bool;
3730  using typename const_where_expression<_M, _Tp>::value_type;
3731  using const_where_expression<_M, _Tp>::_M_k;
3732  using const_where_expression<_M, _Tp>::_M_value;
3733 
3734  public:
3735  where_expression(const where_expression&) = delete;
3736  where_expression& operator=(const where_expression&) = delete;
3737 
3738  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3739  where_expression(const _M& __kk, _Tp& dd)
3740  : const_where_expression<_M, _Tp>(__kk, dd) {}
3741 
3742 #define _GLIBCXX_SIMD_OP_(__op) \
3743  template <typename _Up> \
3744  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void \
3745  operator __op(_Up&& __x)&& \
3746  { if (_M_k) _M_value __op static_cast<_Up&&>(__x); }
3747 
3748  _GLIBCXX_SIMD_OP_(=)
3749  _GLIBCXX_SIMD_OP_(+=)
3750  _GLIBCXX_SIMD_OP_(-=)
3751  _GLIBCXX_SIMD_OP_(*=)
3752  _GLIBCXX_SIMD_OP_(/=)
3753  _GLIBCXX_SIMD_OP_(%=)
3754  _GLIBCXX_SIMD_OP_(&=)
3755  _GLIBCXX_SIMD_OP_(|=)
3756  _GLIBCXX_SIMD_OP_(^=)
3757  _GLIBCXX_SIMD_OP_(<<=)
3758  _GLIBCXX_SIMD_OP_(>>=)
3759  #undef _GLIBCXX_SIMD_OP_
3760 
3761  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3762  operator++() &&
3763  { if (_M_k) ++_M_value; }
3764 
3765  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3766  operator++(int) &&
3767  { if (_M_k) ++_M_value; }
3768 
3769  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3770  operator--() &&
3771  { if (_M_k) --_M_value; }
3772 
3773  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3774  operator--(int) &&
3775  { if (_M_k) --_M_value; }
3776 
3777  // intentionally hides const_where_expression::copy_from
3778  template <typename _Up, typename _Flags>
3779  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
3780  copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) &&
3781  { if (_M_k) _M_value = __mem[0]; }
3782  };
3783 
3784 // where {{{1
3785 template <typename _Tp, typename _Ap>
3786  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3787  where_expression<simd_mask<_Tp, _Ap>, simd<_Tp, _Ap>>
3788  where(const typename simd<_Tp, _Ap>::mask_type& __k, simd<_Tp, _Ap>& __value)
3789  { return {__k, __value}; }
3790 
3791 template <typename _Tp, typename _Ap>
3792  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3793  const_where_expression<simd_mask<_Tp, _Ap>, simd<_Tp, _Ap>>
3794  where(const typename simd<_Tp, _Ap>::mask_type& __k, const simd<_Tp, _Ap>& __value)
3795  { return {__k, __value}; }
3796 
3797 template <typename _Tp, typename _Ap>
3798  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3799  where_expression<simd_mask<_Tp, _Ap>, simd_mask<_Tp, _Ap>>
3800  where(const remove_const_t<simd_mask<_Tp, _Ap>>& __k, simd_mask<_Tp, _Ap>& __value)
3801  { return {__k, __value}; }
3802 
3803 template <typename _Tp, typename _Ap>
3804  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3805  const_where_expression<simd_mask<_Tp, _Ap>, simd_mask<_Tp, _Ap>>
3806  where(const remove_const_t<simd_mask<_Tp, _Ap>>& __k, const simd_mask<_Tp, _Ap>& __value)
3807  { return {__k, __value}; }
3808 
3809 template <typename _Tp>
3810  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR where_expression<bool, _Tp>
3811  where(_ExactBool __k, _Tp& __value)
3812  { return {__k, __value}; }
3813 
3814 template <typename _Tp>
3815  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR const_where_expression<bool, _Tp>
3816  where(_ExactBool __k, const _Tp& __value)
3817  { return {__k, __value}; }
3818 
3819 template <typename _Tp, typename _Ap>
3820  _GLIBCXX_SIMD_CONSTEXPR void
3821  where(bool __k, simd<_Tp, _Ap>& __value) = delete;
3822 
3823 template <typename _Tp, typename _Ap>
3824  _GLIBCXX_SIMD_CONSTEXPR void
3825  where(bool __k, const simd<_Tp, _Ap>& __value) = delete;
3826 
3827 // proposed mask iterations {{{1
3828 namespace __proposed {
3829 template <size_t _Np>
3830  class where_range
3831  {
3832  const bitset<_Np> __bits;
3833 
3834  public:
3835  where_range(bitset<_Np> __b) : __bits(__b) {}
3836 
3837  class iterator
3838  {
3839  size_t __mask;
3840  size_t __bit;
3841 
3842  _GLIBCXX_SIMD_INTRINSIC void
3843  __next_bit()
3844  { __bit = __builtin_ctzl(__mask); }
3845 
3846  _GLIBCXX_SIMD_INTRINSIC void
3847  __reset_lsb()
3848  {
3849  // 01100100 - 1 = 01100011
3850  __mask &= (__mask - 1);
3851  // __asm__("btr %1,%0" : "+r"(__mask) : "r"(__bit));
3852  }
3853 
3854  public:
3855  iterator(decltype(__mask) __m) : __mask(__m) { __next_bit(); }
3856  iterator(const iterator&) = default;
3857  iterator(iterator&&) = default;
3858 
3859  _GLIBCXX_SIMD_ALWAYS_INLINE size_t
3860  operator->() const
3861  { return __bit; }
3862 
3863  _GLIBCXX_SIMD_ALWAYS_INLINE size_t
3864  operator*() const
3865  { return __bit; }
3866 
3867  _GLIBCXX_SIMD_ALWAYS_INLINE iterator&
3868  operator++()
3869  {
3870  __reset_lsb();
3871  __next_bit();
3872  return *this;
3873  }
3874 
3875  _GLIBCXX_SIMD_ALWAYS_INLINE iterator
3876  operator++(int)
3877  {
3878  iterator __tmp = *this;
3879  __reset_lsb();
3880  __next_bit();
3881  return __tmp;
3882  }
3883 
3884  _GLIBCXX_SIMD_ALWAYS_INLINE bool
3885  operator==(const iterator& __rhs) const
3886  { return __mask == __rhs.__mask; }
3887 
3888  _GLIBCXX_SIMD_ALWAYS_INLINE bool
3889  operator!=(const iterator& __rhs) const
3890  { return __mask != __rhs.__mask; }
3891  };
3892 
3893  iterator
3894  begin() const
3895  { return __bits.to_ullong(); }
3896 
3897  iterator
3898  end() const
3899  { return 0; }
3900  };
3901 
3902 template <typename _Tp, typename _Ap>
3903  where_range<simd_size_v<_Tp, _Ap>>
3904  where(const simd_mask<_Tp, _Ap>& __k)
3905  { return __k.__to_bitset(); }
3906 
3907 } // namespace __proposed
3908 
3909 // }}}1
3910 // reductions [simd.reductions] {{{1
3911 template <typename _Tp, typename _Abi, typename _BinaryOperation = plus<>>
3912  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _Tp
3913  reduce(const simd<_Tp, _Abi>& __v, _BinaryOperation __binary_op = _BinaryOperation())
3914  { return _Abi::_SimdImpl::_S_reduce(__v, __binary_op); }
3915 
3916 template <typename _M, typename _V, typename _BinaryOperation = plus<>>
3917  _GLIBCXX_SIMD_INTRINSIC typename _V::value_type
3918  reduce(const const_where_expression<_M, _V>& __x,
3919  typename _V::value_type __identity_element, _BinaryOperation __binary_op)
3920  {
3921  if (__builtin_expect(none_of(__get_mask(__x)), false))
3922  return __identity_element;
3923 
3924  _V __tmp = __identity_element;
3925  _V::_Impl::_S_masked_assign(__data(__get_mask(__x)), __data(__tmp),
3926  __data(__get_lvalue(__x)));
3927  return reduce(__tmp, __binary_op);
3928  }
3929 
3930 template <typename _M, typename _V>
3931  _GLIBCXX_SIMD_INTRINSIC typename _V::value_type
3932  reduce(const const_where_expression<_M, _V>& __x, plus<> __binary_op = {})
3933  { return reduce(__x, 0, __binary_op); }
3934 
3935 template <typename _M, typename _V>
3936  _GLIBCXX_SIMD_INTRINSIC typename _V::value_type
3937  reduce(const const_where_expression<_M, _V>& __x, multiplies<> __binary_op)
3938  { return reduce(__x, 1, __binary_op); }
3939 
3940 template <typename _M, typename _V>
3941  _GLIBCXX_SIMD_INTRINSIC typename _V::value_type
3942  reduce(const const_where_expression<_M, _V>& __x, bit_and<> __binary_op)
3943  { return reduce(__x, ~typename _V::value_type(), __binary_op); }
3944 
3945 template <typename _M, typename _V>
3946  _GLIBCXX_SIMD_INTRINSIC typename _V::value_type
3947  reduce(const const_where_expression<_M, _V>& __x, bit_or<> __binary_op)
3948  { return reduce(__x, 0, __binary_op); }
3949 
3950 template <typename _M, typename _V>
3951  _GLIBCXX_SIMD_INTRINSIC typename _V::value_type
3952  reduce(const const_where_expression<_M, _V>& __x, bit_xor<> __binary_op)
3953  { return reduce(__x, 0, __binary_op); }
3954 
3955 template <typename _Tp, typename _Abi>
3956  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _Tp
3957  hmin(const simd<_Tp, _Abi>& __v) noexcept
3958  { return _Abi::_SimdImpl::_S_reduce(__v, __detail::_Minimum()); }
3959 
3960 template <typename _Tp, typename _Abi>
3961  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _Tp
3962  hmax(const simd<_Tp, _Abi>& __v) noexcept
3963  { return _Abi::_SimdImpl::_S_reduce(__v, __detail::_Maximum()); }
3964 
3965 template <typename _M, typename _V>
3966  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3967  typename _V::value_type
3968  hmin(const const_where_expression<_M, _V>& __x) noexcept
3969  {
3970  using _Tp = typename _V::value_type;
3971  constexpr _Tp __id_elem =
3972 #ifdef __FINITE_MATH_ONLY__
3973  __finite_max_v<_Tp>;
3974 #else
3975  __value_or<__infinity, _Tp>(__finite_max_v<_Tp>);
3976 #endif
3977  _V __tmp = __id_elem;
3978  _V::_Impl::_S_masked_assign(__data(__get_mask(__x)), __data(__tmp),
3979  __data(__get_lvalue(__x)));
3980  return _V::abi_type::_SimdImpl::_S_reduce(__tmp, __detail::_Minimum());
3981  }
3982 
3983 template <typename _M, typename _V>
3984  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
3985  typename _V::value_type
3986  hmax(const const_where_expression<_M, _V>& __x) noexcept
3987  {
3988  using _Tp = typename _V::value_type;
3989  constexpr _Tp __id_elem =
3990 #ifdef __FINITE_MATH_ONLY__
3991  __finite_min_v<_Tp>;
3992 #else
3993  [] {
3994  if constexpr (__value_exists_v<__infinity, _Tp>)
3995  return -__infinity_v<_Tp>;
3996  else
3997  return __finite_min_v<_Tp>;
3998  }();
3999 #endif
4000  _V __tmp = __id_elem;
4001  _V::_Impl::_S_masked_assign(__data(__get_mask(__x)), __data(__tmp),
4002  __data(__get_lvalue(__x)));
4003  return _V::abi_type::_SimdImpl::_S_reduce(__tmp, __detail::_Maximum());
4004  }
4005 
4006 // }}}1
4007 // algorithms [simd.alg] {{{
4008 template <typename _Tp, typename _Ap>
4009  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR simd<_Tp, _Ap>
4010  min(const simd<_Tp, _Ap>& __a, const simd<_Tp, _Ap>& __b)
4011  { return {__private_init, _Ap::_SimdImpl::_S_min(__data(__a), __data(__b))}; }
4012 
4013 template <typename _Tp, typename _Ap>
4014  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR simd<_Tp, _Ap>
4015  max(const simd<_Tp, _Ap>& __a, const simd<_Tp, _Ap>& __b)
4016  { return {__private_init, _Ap::_SimdImpl::_S_max(__data(__a), __data(__b))}; }
4017 
4018 template <typename _Tp, typename _Ap>
4019  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
4020  pair<simd<_Tp, _Ap>, simd<_Tp, _Ap>>
4021  minmax(const simd<_Tp, _Ap>& __a, const simd<_Tp, _Ap>& __b)
4022  {
4023  const auto pair_of_members
4024  = _Ap::_SimdImpl::_S_minmax(__data(__a), __data(__b));
4025  return {simd<_Tp, _Ap>(__private_init, pair_of_members.first),
4026  simd<_Tp, _Ap>(__private_init, pair_of_members.second)};
4027  }
4028 
4029 template <typename _Tp, typename _Ap>
4030  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR simd<_Tp, _Ap>
4031  clamp(const simd<_Tp, _Ap>& __v, const simd<_Tp, _Ap>& __lo, const simd<_Tp, _Ap>& __hi)
4032  {
4033  using _Impl = typename _Ap::_SimdImpl;
4034  return {__private_init,
4035  _Impl::_S_min(__data(__hi),
4036  _Impl::_S_max(__data(__lo), __data(__v)))};
4037  }
4038 
4039 // }}}
4040 
4041 template <size_t... _Sizes, typename _Tp, typename _Ap,
4042  typename = enable_if_t<((_Sizes + ...) == simd<_Tp, _Ap>::size())>>
4043  inline tuple<simd<_Tp, simd_abi::deduce_t<_Tp, _Sizes>>...>
4044  split(const simd<_Tp, _Ap>&);
4045 
4046 // __extract_part {{{
4047 template <int _Index, int _Total, int _Combine = 1, typename _Tp, size_t _Np>
4048  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST constexpr
4049  conditional_t<_Np == _Total and _Combine == 1, _Tp, _SimdWrapper<_Tp, _Np / _Total * _Combine>>
4050  __extract_part(const _SimdWrapper<_Tp, _Np> __x);
4051 
4052 template <int _Index, int _Parts, int _Combine = 1, typename _Tp, typename _A0, typename... _As>
4053  _GLIBCXX_SIMD_INTRINSIC constexpr auto
4054  __extract_part(const _SimdTuple<_Tp, _A0, _As...>& __x);
4055 
4056 // }}}
4057 // _SizeList {{{
4058 template <size_t _V0, size_t... _Values>
4059  struct _SizeList
4060  {
4061  template <size_t _I>
4062  static constexpr size_t
4063  _S_at(_SizeConstant<_I> = {})
4064  {
4065  if constexpr (_I == 0)
4066  return _V0;
4067  else
4068  return _SizeList<_Values...>::template _S_at<_I - 1>();
4069  }
4070 
4071  template <size_t _I>
4072  static constexpr auto
4073  _S_before(_SizeConstant<_I> = {})
4074  {
4075  if constexpr (_I == 0)
4076  return _SizeConstant<0>();
4077  else
4078  return _SizeConstant<
4079  _V0 + _SizeList<_Values...>::template _S_before<_I - 1>()>();
4080  }
4081 
4082  template <size_t _Np>
4083  static constexpr auto
4084  _S_pop_front(_SizeConstant<_Np> = {})
4085  {
4086  if constexpr (_Np == 0)
4087  return _SizeList();
4088  else
4089  return _SizeList<_Values...>::template _S_pop_front<_Np - 1>();
4090  }
4091  };
4092 
4093 // }}}
4094 // __extract_center {{{
4095 template <typename _Tp, size_t _Np>
4096  _GLIBCXX_SIMD_INTRINSIC _SimdWrapper<_Tp, _Np / 2>
4097  __extract_center(_SimdWrapper<_Tp, _Np> __x)
4098  {
4099  static_assert(_Np >= 4);
4100  static_assert(_Np % 4 == 0); // x0 - x1 - x2 - x3 -> return {x1, x2}
4101 #if _GLIBCXX_SIMD_X86INTRIN // {{{
4102  if constexpr (__have_avx512f && sizeof(_Tp) * _Np == 64)
4103  {
4104  const auto __intrin = __to_intrin(__x);
4105  if constexpr (is_integral_v<_Tp>)
4106  return __vector_bitcast<_Tp>(_mm512_castsi512_si256(
4107  _mm512_shuffle_i32x4(__intrin, __intrin,
4108  1 + 2 * 0x4 + 2 * 0x10 + 3 * 0x40)));
4109  else if constexpr (sizeof(_Tp) == 4)
4110  return __vector_bitcast<_Tp>(_mm512_castps512_ps256(
4111  _mm512_shuffle_f32x4(__intrin, __intrin,
4112  1 + 2 * 0x4 + 2 * 0x10 + 3 * 0x40)));
4113  else if constexpr (sizeof(_Tp) == 8)
4114  return __vector_bitcast<_Tp>(_mm512_castpd512_pd256(
4115  _mm512_shuffle_f64x2(__intrin, __intrin,
4116  1 + 2 * 0x4 + 2 * 0x10 + 3 * 0x40)));
4117  else
4118  __assert_unreachable<_Tp>();
4119  }
4120  else if constexpr (sizeof(_Tp) * _Np == 32 && is_floating_point_v<_Tp>)
4121  return __vector_bitcast<_Tp>(
4122  _mm_shuffle_pd(__lo128(__vector_bitcast<double>(__x)),
4123  __hi128(__vector_bitcast<double>(__x)), 1));
4124  else if constexpr (sizeof(__x) == 32 && sizeof(_Tp) * _Np <= 32)
4125  return __vector_bitcast<_Tp>(
4126  _mm_alignr_epi8(__hi128(__vector_bitcast<_LLong>(__x)),
4127  __lo128(__vector_bitcast<_LLong>(__x)),
4128  sizeof(_Tp) * _Np / 4));
4129  else
4130 #endif // _GLIBCXX_SIMD_X86INTRIN }}}
4131  {
4132  __vector_type_t<_Tp, _Np / 2> __r;
4133  __builtin_memcpy(&__r,
4134  reinterpret_cast<const char*>(&__x)
4135  + sizeof(_Tp) * _Np / 4,
4136  sizeof(_Tp) * _Np / 2);
4137  return __r;
4138  }
4139  }
4140 
4141 template <typename _Tp, typename _A0, typename... _As>
4142  _GLIBCXX_SIMD_INTRINSIC
4143  _SimdWrapper<_Tp, _SimdTuple<_Tp, _A0, _As...>::_S_size() / 2>
4144  __extract_center(const _SimdTuple<_Tp, _A0, _As...>& __x)
4145  {
4146  if constexpr (sizeof...(_As) == 0)
4147  return __extract_center(__x.first);
4148  else
4149  return __extract_part<1, 4, 2>(__x);
4150  }
4151 
4152 // }}}
4153 // __split_wrapper {{{
4154 template <size_t... _Sizes, typename _Tp, typename... _As>
4155  auto
4156  __split_wrapper(_SizeList<_Sizes...>, const _SimdTuple<_Tp, _As...>& __x)
4157  {
4158  return split<_Sizes...>(
4159  fixed_size_simd<_Tp, _SimdTuple<_Tp, _As...>::_S_size()>(__private_init,
4160  __x));
4161  }
4162 
4163 // }}}
4164 
4165 // split<simd>(simd) {{{
4166 template <typename _V, typename _Ap,
4167  size_t _Parts = simd_size_v<typename _V::value_type, _Ap> / _V::size()>
4168  enable_if_t<simd_size_v<typename _V::value_type, _Ap> == _Parts * _V::size()
4169  && is_simd_v<_V>, array<_V, _Parts>>
4170  split(const simd<typename _V::value_type, _Ap>& __x)
4171  {
4172  using _Tp = typename _V::value_type;
4173 
4174  auto __gen_fallback = [&]() constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4175  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4176  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4177  return _V([&](auto __j) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA
4178  { return __x[__i * _V::size() + __j]; });
4179  });
4180  };
4181 
4182  if constexpr (_Parts == 1)
4183  {
4184  return {simd_cast<_V>(__x)};
4185  }
4186  else if (__x._M_is_constprop())
4187  {
4188  return __gen_fallback();
4189  }
4190 #if _GLIBCXX_SIMD_HAVE_SVE
4191  else if constexpr(__is_sve_abi<_Ap>)
4192  {
4193  return __gen_fallback();
4194  }
4195 #endif
4196  else if constexpr (
4197  __is_fixed_size_abi_v<_Ap>
4198  && (is_same_v<typename _V::abi_type, simd_abi::scalar>
4199  || (__is_fixed_size_abi_v<typename _V::abi_type>
4200  && sizeof(_V) == sizeof(_Tp) * _V::size() // _V doesn't have padding
4201  )))
4202  {
4203  // fixed_size -> fixed_size (w/o padding) or scalar
4204 #ifdef _GLIBCXX_SIMD_USE_ALIASING_LOADS
4205  const __may_alias<_Tp>* const __element_ptr
4206  = reinterpret_cast<const __may_alias<_Tp>*>(&__data(__x));
4207  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4208  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA
4209  { return _V(__element_ptr + __i * _V::size(), vector_aligned); });
4210 #else
4211  const auto& __xx = __data(__x);
4212  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4213  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4214  [[maybe_unused]] constexpr size_t __offset
4215  = decltype(__i)::value * _V::size();
4216  return _V([&](auto __j) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4217  constexpr _SizeConstant<__j + __offset> __k;
4218  return __xx[__k];
4219  });
4220  });
4221 #endif
4222  }
4223  else if constexpr (is_same_v<typename _V::abi_type, simd_abi::scalar>)
4224  {
4225  // normally memcpy should work here as well
4226  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4227  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA { return __x[__i]; });
4228  }
4229  else
4230  {
4231  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4232  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4233  if constexpr (__is_fixed_size_abi_v<typename _V::abi_type>)
4234  return _V([&](auto __j) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4235  return __x[__i * _V::size() + __j];
4236  });
4237  else
4238  return _V(__private_init,
4239  __extract_part<decltype(__i)::value, _Parts>(__data(__x)));
4240  });
4241  }
4242  }
4243 
4244 // }}}
4245 // split<simd_mask>(simd_mask) {{{
4246 template <typename _V, typename _Ap,
4247  size_t _Parts = simd_size_v<typename _V::simd_type::value_type, _Ap> / _V::size()>
4248  enable_if_t<is_simd_mask_v<_V> && simd_size_v<typename
4249  _V::simd_type::value_type, _Ap> == _Parts * _V::size(), array<_V, _Parts>>
4250  split(const simd_mask<typename _V::simd_type::value_type, _Ap>& __x)
4251  {
4252  if constexpr (is_same_v<_Ap, typename _V::abi_type>)
4253  return {__x};
4254  else if constexpr (_Parts == 1)
4255  return {__proposed::static_simd_cast<_V>(__x)};
4256  else if constexpr (_Parts == 2 && __is_sse_abi<typename _V::abi_type>()
4257  && __is_avx_abi<_Ap>())
4258  return {_V(__private_init, __lo128(__data(__x))),
4259  _V(__private_init, __hi128(__data(__x)))};
4260  else if constexpr (_V::size() <= __CHAR_BIT__ * sizeof(_ULLong))
4261  {
4262  const bitset __bits = __x.__to_bitset();
4263  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4264  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4265  constexpr size_t __offset = __i * _V::size();
4266  return _V(__bitset_init, (__bits >> __offset).to_ullong());
4267  });
4268  }
4269  else
4270  {
4271  return __generate_from_n_evaluations<_Parts, array<_V, _Parts>>(
4272  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4273  constexpr size_t __offset = __i * _V::size();
4274  return _V(__private_init,
4275  [&](auto __j) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4276  return __x[__j + __offset];
4277  });
4278  });
4279  }
4280  }
4281 
4282 // }}}
4283 // split<_Sizes...>(simd) {{{
4284 template <size_t... _Sizes, typename _Tp, typename _Ap, typename>
4285  _GLIBCXX_SIMD_ALWAYS_INLINE
4286  tuple<simd<_Tp, simd_abi::deduce_t<_Tp, _Sizes>>...>
4287  split(const simd<_Tp, _Ap>& __x)
4288  {
4289  using _SL = _SizeList<_Sizes...>;
4290  using _Tuple = tuple<__deduced_simd<_Tp, _Sizes>...>;
4291  constexpr size_t _Np = simd_size_v<_Tp, _Ap>;
4292  constexpr size_t _N0 = _SL::template _S_at<0>();
4293  using _V = __deduced_simd<_Tp, _N0>;
4294 
4295  auto __gen_fallback = [&]() constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA
4296  {
4297  return __generate_from_n_evaluations<sizeof...(_Sizes), _Tuple>(
4298  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4299  using _Vi = __deduced_simd<_Tp, _SL::_S_at(__i)>;
4300  constexpr size_t __offset = _SL::_S_before(__i);
4301  return _Vi([&](auto __j) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4302  return __x[__offset + __j];
4303  });
4304  });
4305  };
4306 
4307  if (__x._M_is_constprop())
4308  __gen_fallback();
4309 #if _GLIBCXX_SIMD_HAVE_SVE
4310  else if constexpr (__have_sve)
4311  __gen_fallback();
4312 #endif
4313  else if constexpr (_Np == _N0)
4314  {
4315  static_assert(sizeof...(_Sizes) == 1);
4316  return {simd_cast<_V>(__x)};
4317  }
4318  else if constexpr // split from fixed_size, such that __x::first.size == _N0
4319  (__is_fixed_size_abi_v<
4320  _Ap> && __fixed_size_storage_t<_Tp, _Np>::_S_first_size == _N0)
4321  {
4322  static_assert(
4323  !__is_fixed_size_abi_v<typename _V::abi_type>,
4324  "How can <_Tp, _Np> be __a single _SimdTuple entry but __a "
4325  "fixed_size_simd "
4326  "when deduced?");
4327  // extract first and recurse (__split_wrapper is needed to deduce a new
4328  // _Sizes pack)
4329  return tuple_cat(make_tuple(_V(__private_init, __data(__x).first)),
4330  __split_wrapper(_SL::template _S_pop_front<1>(),
4331  __data(__x).second));
4332  }
4333  else if constexpr ((!__is_fixed_size_abi_v<simd_abi::deduce_t<_Tp, _Sizes>> && ...))
4334  {
4335  constexpr array<size_t, sizeof...(_Sizes)> __size = {_Sizes...};
4336  return __generate_from_n_evaluations<sizeof...(_Sizes), _Tuple>(
4337  [&](auto __i) constexpr {
4338  constexpr size_t __offset = [&]() {
4339  size_t __r = 0;
4340  for (unsigned __j = 0; __j < __i; ++__j)
4341  __r += __size[__j];
4342  return __r;
4343  }();
4344  return __deduced_simd<_Tp, __size[__i]>(
4345  __private_init,
4346  __extract_part<__offset, _Np, __size[__i]>(__data(__x)));
4347  });
4348  }
4349 #ifdef _GLIBCXX_SIMD_USE_ALIASING_LOADS
4350  const __may_alias<_Tp>* const __element_ptr
4351  = reinterpret_cast<const __may_alias<_Tp>*>(&__x);
4352  return __generate_from_n_evaluations<sizeof...(_Sizes), _Tuple>(
4353  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4354  using _Vi = __deduced_simd<_Tp, _SL::_S_at(__i)>;
4355  constexpr size_t __offset = _SL::_S_before(__i);
4356  constexpr size_t __base_align = alignof(simd<_Tp, _Ap>);
4357  constexpr size_t __a
4358  = __base_align - ((__offset * sizeof(_Tp)) % __base_align);
4359  constexpr size_t __b = ((__a - 1) & __a) ^ __a;
4360  constexpr size_t __alignment = __b == 0 ? __a : __b;
4361  return _Vi(__element_ptr + __offset, overaligned<__alignment>);
4362  });
4363 #else
4364  return __generate_from_n_evaluations<sizeof...(_Sizes), _Tuple>(
4365  [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4366  using _Vi = __deduced_simd<_Tp, _SL::_S_at(__i)>;
4367  const auto& __xx = __data(__x);
4368  using _Offset = decltype(_SL::_S_before(__i));
4369  return _Vi([&](auto __j) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4370  constexpr _SizeConstant<_Offset::value + __j> __k;
4371  return __xx[__k];
4372  });
4373  });
4374 #endif
4375  }
4376 
4377 // }}}
4378 
4379 // __subscript_in_pack {{{
4380 template <size_t _I, typename _Tp, typename _Ap, typename... _As>
4381  _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
4382  __subscript_in_pack(const simd<_Tp, _Ap>& __x, const simd<_Tp, _As>&... __xs)
4383  {
4384  if constexpr (_I < simd_size_v<_Tp, _Ap>)
4385  return __x[_I];
4386  else
4387  return __subscript_in_pack<_I - simd_size_v<_Tp, _Ap>>(__xs...);
4388  }
4389 
4390 // }}}
4391 // __store_pack_of_simd {{{
4392 template <typename _Tp, typename _A0, typename... _As>
4393  _GLIBCXX_SIMD_INTRINSIC void
4394  __store_pack_of_simd(char* __mem, const simd<_Tp, _A0>& __x0, const simd<_Tp, _As>&... __xs)
4395  {
4396  constexpr size_t __n_bytes = sizeof(_Tp) * simd_size_v<_Tp, _A0>;
4397  __builtin_memcpy(__mem, &__data(__x0), __n_bytes);
4398  if constexpr (sizeof...(__xs) > 0)
4399  __store_pack_of_simd(__mem + __n_bytes, __xs...);
4400  }
4401 
4402 // }}}
4403 // concat(simd...) {{{
4404 template <typename _Tp, typename... _As, typename = __detail::__odr_helper>
4405  inline _GLIBCXX_SIMD_CONSTEXPR
4406  simd<_Tp, simd_abi::deduce_t<_Tp, (simd_size_v<_Tp, _As> + ...)>>
4407  concat(const simd<_Tp, _As>&... __xs)
4408  {
4409  constexpr int _Np = (simd_size_v<_Tp, _As> + ...);
4410  using _Abi = simd_abi::deduce_t<_Tp, _Np>;
4411  using _Rp = simd<_Tp, _Abi>;
4412  using _RW = typename _SimdTraits<_Tp, _Abi>::_SimdMember;
4413  if constexpr (sizeof...(__xs) == 1)
4414  return simd_cast<_Rp>(__xs...);
4415  else if ((... && __xs._M_is_constprop()))
4416  return _Rp([&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA
4417  { return __subscript_in_pack<__i>(__xs...); });
4418  else if constexpr (__is_simd_wrapper_v<_RW> and sizeof...(__xs) == 2)
4419  {
4420  return {__private_init,
4421  __vec_shuffle(__as_vector(__xs)..., std::make_index_sequence<_RW::_S_full_size>(),
4422  [](int __i) {
4423  constexpr int __sizes[2] = {int(simd_size_v<_Tp, _As>)...};
4424  constexpr int __vsizes[2]
4425  = {int(sizeof(__as_vector(__xs)) / sizeof(_Tp))...};
4426  constexpr int __padding0 = __vsizes[0] - __sizes[0];
4427  return __i >= _Np ? -1 : __i < __sizes[0] ? __i : __i + __padding0;
4428  })};
4429  }
4430  else if constexpr (__is_simd_wrapper_v<_RW> and sizeof...(__xs) == 3)
4431  return [](const auto& __x0, const auto& __x1, const auto& __x2)
4432  _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4433  return concat(concat(__x0, __x1), __x2);
4434  }(__xs...);
4435  else if constexpr (__is_simd_wrapper_v<_RW> and sizeof...(__xs) > 3)
4436  return [](const auto& __x0, const auto& __x1, const auto&... __rest)
4437  _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4438  return concat(concat(__x0, __x1), concat(__rest...));
4439  }(__xs...);
4440  else
4441  {
4442  _Rp __r{};
4443  __store_pack_of_simd(reinterpret_cast<char*>(&__data(__r)), __xs...);
4444  return __r;
4445  }
4446  }
4447 
4448 // }}}
4449 // concat(array<simd>) {{{
4450 template <typename _Tp, typename _Abi, size_t _Np>
4451  _GLIBCXX_SIMD_ALWAYS_INLINE
4452  _GLIBCXX_SIMD_CONSTEXPR __deduced_simd<_Tp, simd_size_v<_Tp, _Abi> * _Np>
4453  concat(const array<simd<_Tp, _Abi>, _Np>& __x)
4454  {
4455  return __call_with_subscripts<_Np>(
4456  __x, [](const auto&... __xs) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4457  return concat(__xs...);
4458  });
4459  }
4460 
4461 // }}}
4462 
4463 /// @cond undocumented
4464 // _SmartReference {{{
4465 template <typename _Up, typename _Accessor = _Up,
4466  typename _ValueType = typename _Up::value_type>
4467  class _SmartReference
4468  {
4469  friend _Accessor;
4470  int _M_index;
4471  _Up& _M_obj;
4472 
4473  _GLIBCXX_SIMD_INTRINSIC constexpr _ValueType
4474  _M_read() const noexcept
4475  {
4476  if constexpr (is_arithmetic_v<_Up>)
4477  return _M_obj;
4478  else
4479  return _M_obj[_M_index];
4480  }
4481 
4482  template <typename _Tp>
4483  _GLIBCXX_SIMD_INTRINSIC constexpr void
4484  _M_write(_Tp&& __x) const
4485  { _Accessor::_S_set(_M_obj, _M_index, static_cast<_Tp&&>(__x)); }
4486 
4487  public:
4488  _GLIBCXX_SIMD_INTRINSIC constexpr
4489  _SmartReference(_Up& __o, int __i) noexcept
4490  : _M_index(__i), _M_obj(__o) {}
4491 
4492  using value_type = _ValueType;
4493 
4494  _GLIBCXX_SIMD_INTRINSIC
4495  _SmartReference(const _SmartReference&) = delete;
4496 
4497  _GLIBCXX_SIMD_INTRINSIC constexpr
4498  operator value_type() const noexcept
4499  { return _M_read(); }
4500 
4501  template <typename _Tp, typename = _ValuePreservingOrInt<__remove_cvref_t<_Tp>, value_type>>
4502  _GLIBCXX_SIMD_INTRINSIC constexpr _SmartReference
4503  operator=(_Tp&& __x) &&
4504  {
4505  _M_write(static_cast<_Tp&&>(__x));
4506  return {_M_obj, _M_index};
4507  }
4508 
4509 #define _GLIBCXX_SIMD_OP_(__op) \
4510  template <typename _Tp, \
4511  typename _TT = decltype(declval<value_type>() __op declval<_Tp>()), \
4512  typename = _ValuePreservingOrInt<__remove_cvref_t<_Tp>, _TT>, \
4513  typename = _ValuePreservingOrInt<_TT, value_type>> \
4514  _GLIBCXX_SIMD_INTRINSIC constexpr _SmartReference \
4515  operator __op##=(_Tp&& __x) && \
4516  { \
4517  const value_type& __lhs = _M_read(); \
4518  _M_write(__lhs __op __x); \
4519  return {_M_obj, _M_index}; \
4520  }
4521  _GLIBCXX_SIMD_ALL_ARITHMETICS(_GLIBCXX_SIMD_OP_);
4522  _GLIBCXX_SIMD_ALL_SHIFTS(_GLIBCXX_SIMD_OP_);
4523  _GLIBCXX_SIMD_ALL_BINARY(_GLIBCXX_SIMD_OP_);
4524 #undef _GLIBCXX_SIMD_OP_
4525 
4526  template <typename _Tp = void,
4527  typename = decltype(++declval<conditional_t<true, value_type, _Tp>&>())>
4528  _GLIBCXX_SIMD_INTRINSIC constexpr _SmartReference
4529  operator++() &&
4530  {
4531  value_type __x = _M_read();
4532  _M_write(++__x);
4533  return {_M_obj, _M_index};
4534  }
4535 
4536  template <typename _Tp = void,
4537  typename = decltype(declval<conditional_t<true, value_type, _Tp>&>()++)>
4538  _GLIBCXX_SIMD_INTRINSIC constexpr value_type
4539  operator++(int) &&
4540  {
4541  const value_type __r = _M_read();
4542  value_type __x = __r;
4543  _M_write(++__x);
4544  return __r;
4545  }
4546 
4547  template <typename _Tp = void,
4548  typename = decltype(--declval<conditional_t<true, value_type, _Tp>&>())>
4549  _GLIBCXX_SIMD_INTRINSIC constexpr _SmartReference
4550  operator--() &&
4551  {
4552  value_type __x = _M_read();
4553  _M_write(--__x);
4554  return {_M_obj, _M_index};
4555  }
4556 
4557  template <typename _Tp = void,
4558  typename = decltype(declval<conditional_t<true, value_type, _Tp>&>()--)>
4559  _GLIBCXX_SIMD_INTRINSIC constexpr value_type
4560  operator--(int) &&
4561  {
4562  const value_type __r = _M_read();
4563  value_type __x = __r;
4564  _M_write(--__x);
4565  return __r;
4566  }
4567 
4568  _GLIBCXX_SIMD_INTRINSIC friend void
4569  swap(_SmartReference&& __a, _SmartReference&& __b) noexcept(
4570  conjunction<
4571  is_nothrow_constructible<value_type, _SmartReference&&>,
4572  is_nothrow_assignable<_SmartReference&&, value_type&&>>::value)
4573  {
4574  value_type __tmp = static_cast<_SmartReference&&>(__a);
4575  static_cast<_SmartReference&&>(__a) = static_cast<value_type>(__b);
4576  static_cast<_SmartReference&&>(__b) = std::move(__tmp);
4577  }
4578 
4579  _GLIBCXX_SIMD_INTRINSIC friend void
4580  swap(value_type& __a, _SmartReference&& __b) noexcept(
4581  conjunction<
4582  is_nothrow_constructible<value_type, value_type&&>,
4583  is_nothrow_assignable<value_type&, value_type&&>,
4584  is_nothrow_assignable<_SmartReference&&, value_type&&>>::value)
4585  {
4586  value_type __tmp(std::move(__a));
4587  __a = static_cast<value_type>(__b);
4588  static_cast<_SmartReference&&>(__b) = std::move(__tmp);
4589  }
4590 
4591  _GLIBCXX_SIMD_INTRINSIC friend void
4592  swap(_SmartReference&& __a, value_type& __b) noexcept(
4593  conjunction<
4594  is_nothrow_constructible<value_type, _SmartReference&&>,
4595  is_nothrow_assignable<value_type&, value_type&&>,
4596  is_nothrow_assignable<_SmartReference&&, value_type&&>>::value)
4597  {
4598  value_type __tmp(__a);
4599  static_cast<_SmartReference&&>(__a) = std::move(__b);
4600  __b = std::move(__tmp);
4601  }
4602  };
4603 
4604 // }}}
4605 // __scalar_abi_wrapper {{{
4606 template <int _Bytes>
4607  struct __scalar_abi_wrapper
4608  {
4609  template <typename _Tp> static constexpr size_t _S_full_size = 1;
4610  template <typename _Tp> static constexpr size_t _S_size = 1;
4611  template <typename _Tp> static constexpr size_t _S_is_partial = false;
4612 
4613  template <typename _Tp, typename _Abi = simd_abi::scalar>
4614  static constexpr bool _S_is_valid_v
4615  = _Abi::template _IsValid<_Tp>::value && sizeof(_Tp) == _Bytes;
4616  };
4617 
4618 // }}}
4619 // __decay_abi metafunction {{{
4620 template <typename _Tp>
4621  struct __decay_abi { using type = _Tp; };
4622 
4623 template <int _Bytes>
4624  struct __decay_abi<__scalar_abi_wrapper<_Bytes>>
4625  { using type = simd_abi::scalar; };
4626 
4627 // }}}
4628 // __find_next_valid_abi metafunction {{{1
4629 // Given an ABI tag A<N>, find an N2 < N such that A<N2>::_S_is_valid_v<_Tp> ==
4630 // true, N2 is a power-of-2, and A<N2>::_S_is_partial<_Tp> is false. Break
4631 // recursion at 2 elements in the resulting ABI tag. In this case
4632 // type::_S_is_valid_v<_Tp> may be false.
4633 template <template <int> class _Abi, int _Bytes, typename _Tp>
4634  struct __find_next_valid_abi
4635  {
4636  static constexpr auto
4637  _S_choose()
4638  {
4639  constexpr int _NextBytes = std::__bit_ceil((unsigned)_Bytes) / 2;
4640  using _NextAbi = _Abi<_NextBytes>;
4641  if constexpr (_NextBytes < sizeof(_Tp) * 2) // break recursion
4642  return _Abi<_Bytes>();
4643  else if constexpr (_NextAbi::template _S_is_partial<_Tp> == false
4644  && _NextAbi::template _S_is_valid_v<_Tp>)
4645  return _NextAbi();
4646  else
4647  return __find_next_valid_abi<_Abi, _NextBytes, _Tp>::_S_choose();
4648  }
4649 
4650  using type = decltype(_S_choose());
4651  };
4652 
4653 template <int _Bytes, typename _Tp>
4654  struct __find_next_valid_abi<__scalar_abi_wrapper, _Bytes, _Tp>
4655  { using type = simd_abi::scalar; };
4656 
4657 // _AbiList {{{1
4658 template <template <int> class...>
4659  struct _AbiList
4660  {
4661  template <typename, int> static constexpr bool _S_has_valid_abi = false;
4662  template <typename, int> using _FirstValidAbi = void;
4663  template <typename, int> using _BestAbi = void;
4664  };
4665 
4666 template <template <int> class _A0, template <int> class... _Rest>
4667  struct _AbiList<_A0, _Rest...>
4668  {
4669  template <typename _Tp, int _Np>
4670  static constexpr bool _S_has_valid_abi
4671  = _A0<sizeof(_Tp) * _Np>::template _S_is_valid_v<
4672  _Tp> || _AbiList<_Rest...>::template _S_has_valid_abi<_Tp, _Np>;
4673 
4674  template <typename _Tp, int _Np>
4675  using _FirstValidAbi = conditional_t<
4676  _A0<sizeof(_Tp) * _Np>::template _S_is_valid_v<_Tp>,
4677  typename __decay_abi<_A0<sizeof(_Tp) * _Np>>::type,
4678  typename _AbiList<_Rest...>::template _FirstValidAbi<_Tp, _Np>>;
4679 
4680  template <typename _Tp, int _Np>
4681  static constexpr auto
4682  _S_determine_best_abi()
4683  {
4684  static_assert(_Np >= 1);
4685  constexpr int _Bytes = sizeof(_Tp) * _Np;
4686  if constexpr (_Np == 1)
4687  return __make_dependent_t<_Tp, simd_abi::scalar>{};
4688  else
4689  {
4690  constexpr int __fullsize = _A0<_Bytes>::template _S_full_size<_Tp>;
4691  // _A0<_Bytes> is good if:
4692  // 1. The ABI tag is valid for _Tp
4693  // 2. The storage overhead is no more than padding to fill the next
4694  // power-of-2 number of bytes
4695  if constexpr (_A0<_Bytes>::template _S_is_valid_v<_Tp>
4696  && ((__is_sve_abi<_A0<_Bytes>>() && __have_sve
4697  && (_Np <= __sve_vectorized_size_bytes/sizeof(_Tp)))
4698  || (__fullsize / 2 < _Np))
4699  )
4700  return typename __decay_abi<_A0<_Bytes>>::type{};
4701  else
4702  {
4703  using _Bp =
4704  typename __find_next_valid_abi<_A0, _Bytes, _Tp>::type;
4705  if constexpr (_Bp::template _S_is_valid_v<
4706  _Tp> && _Bp::template _S_size<_Tp> <= _Np)
4707  return _Bp{};
4708  else
4709  return
4710  typename _AbiList<_Rest...>::template _BestAbi<_Tp, _Np>{};
4711  }
4712  }
4713  }
4714 
4715  template <typename _Tp, int _Np>
4716  using _BestAbi = decltype(_S_determine_best_abi<_Tp, _Np>());
4717  };
4718 
4719 // }}}1
4720 
4721 // the following lists all native ABIs, which makes them accessible to
4722 // simd_abi::deduce and select_best_vector_type_t (for fixed_size). Order
4723 // matters: Whatever comes first has higher priority.
4724 using _AllNativeAbis = _AbiList<
4725 #if _GLIBCXX_SIMD_HAVE_SVE
4726  simd_abi::_SveAbi,
4727 #endif
4728  simd_abi::_VecBltnBtmsk, simd_abi::_VecBuiltin, __scalar_abi_wrapper>;
4729 
4730 using _NoSveAllNativeAbis = _AbiList<simd_abi::_VecBltnBtmsk, simd_abi::_VecBuiltin,
4731  __scalar_abi_wrapper>;
4732 
4733 // valid _SimdTraits specialization {{{1
4734 template <typename _Tp, typename _Abi>
4735  struct _SimdTraits<_Tp, _Abi, void_t<typename _Abi::template _IsValid<_Tp>>>
4736  : _Abi::template __traits<_Tp> {};
4737 
4738 // __deduce_impl specializations {{{1
4739 // try all native ABIs (including scalar) first
4740 template <typename _Tp, size_t _Np>
4741  struct __deduce_impl<
4742  _Tp, _Np, enable_if_t<_AllNativeAbis::template _S_has_valid_abi<_Tp, _Np>>>
4743  { using type = _AllNativeAbis::_FirstValidAbi<_Tp, _Np>; };
4744 
4745 template <typename _Tp, size_t _Np>
4746  struct __no_sve_deduce_impl<
4747  _Tp, _Np, enable_if_t<_NoSveAllNativeAbis::template _S_has_valid_abi<_Tp, _Np>>>
4748  { using type = _NoSveAllNativeAbis::_FirstValidAbi<_Tp, _Np>; };
4749 
4750 // fall back to fixed_size only if scalar and native ABIs don't match
4751 template <typename _Tp, size_t _Np, typename = void>
4752  struct __deduce_fixed_size_fallback {};
4753 
4754 template <typename _Tp, size_t _Np>
4755  struct __deduce_fixed_size_fallback<_Tp, _Np,
4756  enable_if_t<simd_abi::fixed_size<_Np>::template _S_is_valid_v<_Tp>>>
4757  { using type = simd_abi::fixed_size<_Np>; };
4758 
4759 template <typename _Tp, size_t _Np, typename>
4760  struct __deduce_impl : public __deduce_fixed_size_fallback<_Tp, _Np> {};
4761 
4762 template <typename _Tp, size_t _Np, typename>
4763  struct __no_sve_deduce_impl
4764  : public __deduce_fixed_size_fallback<_Tp, _Np>
4765  {};
4766 
4767 
4768 //}}}1
4769 /// @endcond
4770 
4771 // simd_mask {{{
4772 template <typename _Tp, typename _Abi>
4773  class simd_mask : public _SimdTraits<_Tp, _Abi>::_MaskBase
4774  {
4775  // types, tags, and friends {{{
4776  using _Traits = _SimdTraits<_Tp, _Abi>;
4777  using _MemberType = typename _Traits::_MaskMember;
4778 
4779  // We map all masks with equal element sizeof to a single integer type, the
4780  // one given by __int_for_sizeof_t<_Tp>. This is the approach
4781  // [[gnu::vector_size(N)]] types take as well and it reduces the number of
4782  // template specializations in the implementation classes.
4783  using _Ip = __int_for_sizeof_t<_Tp>;
4784  static constexpr _Ip* _S_type_tag = nullptr;
4785 
4786  friend typename _Traits::_MaskBase;
4787  friend class simd<_Tp, _Abi>; // to construct masks on return
4788  friend typename _Traits::_SimdImpl; // to construct masks on return and
4789  // inspect data on masked operations
4790  public:
4791  using _Impl = typename _Traits::_MaskImpl;
4792  friend _Impl;
4793 
4794  // }}}
4795  // member types {{{
4796  using value_type = bool;
4797  using reference = _SmartReference<_MemberType, _Impl, value_type>;
4798  using simd_type = simd<_Tp, _Abi>;
4799  using abi_type = _Abi;
4800 
4801  // }}}
4802  static constexpr size_t size() // {{{
4803  { return __size_or_zero_v<_Tp, _Abi>; }
4804 
4805  // }}}
4806  // constructors & assignment {{{
4807  simd_mask() = default;
4808  simd_mask(const simd_mask&) = default;
4809  simd_mask(simd_mask&&) = default;
4810  simd_mask& operator=(const simd_mask&) = default;
4811  simd_mask& operator=(simd_mask&&) = default;
4812 
4813  // }}}
4814  // access to internal representation (optional feature) {{{
4815  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR explicit
4816  simd_mask(typename _Traits::_MaskCastType __init)
4817  : _M_data{__init} {}
4818  // conversions to internal type is done in _MaskBase
4819 
4820  // }}}
4821  // bitset interface (extension to be proposed) {{{
4822  // TS_FEEDBACK:
4823  // Conversion of simd_mask to and from bitset makes it much easier to
4824  // interface with other facilities. I suggest adding `static
4825  // simd_mask::from_bitset` and `simd_mask::to_bitset`.
4826  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR static simd_mask
4827  __from_bitset(bitset<size()> bs)
4828  { return {__bitset_init, bs}; }
4829 
4830  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bitset<size()>
4831  __to_bitset() const
4832  { return _Impl::_S_to_bits(_M_data)._M_to_bitset(); }
4833 
4834  // }}}
4835  // explicit broadcast constructor {{{
4836  _GLIBCXX_SIMD_ALWAYS_INLINE explicit _GLIBCXX_SIMD_CONSTEXPR
4837  simd_mask(value_type __x)
4838  : _M_data(_Impl::template _S_broadcast<_Ip>(__x)) {}
4839 
4840  // }}}
4841  // implicit type conversion constructor {{{
4842  #ifdef _GLIBCXX_SIMD_ENABLE_IMPLICIT_MASK_CAST
4843  // proposed improvement
4844  template <typename _Up, typename _A2,
4845  typename = enable_if_t<simd_size_v<_Up, _A2> == size()>>
4846  _GLIBCXX_SIMD_ALWAYS_INLINE explicit(sizeof(_MemberType)
4847  != sizeof(typename _SimdTraits<_Up, _A2>::_MaskMember))
4848  simd_mask(const simd_mask<_Up, _A2>& __x)
4849  : simd_mask(__proposed::static_simd_cast<simd_mask>(__x)) {}
4850  #else
4851  // conforming to ISO/IEC 19570:2018
4852  template <typename _Up, typename = enable_if_t<conjunction<
4853  is_same<abi_type, simd_abi::fixed_size<size()>>,
4854  is_same<_Up, _Up>>::value>>
4855  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
4856  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
4857  : _M_data(_Impl::_S_from_bitmask(__data(__x), _S_type_tag)) {}
4858  #endif
4859 
4860  // }}}
4861  // load constructor {{{
4862  template <typename _Flags>
4863  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
4864  simd_mask(const value_type* __mem, _IsSimdFlagType<_Flags>)
4865  : _M_data(_Impl::template _S_load<_Ip>(_Flags::template _S_apply<simd_mask>(__mem))) {}
4866 
4867  template <typename _Flags>
4868  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
4869  simd_mask(const value_type* __mem, simd_mask __k, _IsSimdFlagType<_Flags>)
4870  : _M_data{}
4871  {
4872  _M_data = _Impl::_S_masked_load(_M_data, __k._M_data,
4873  _Flags::template _S_apply<simd_mask>(__mem));
4874  }
4875 
4876  // }}}
4877  // loads [simd_mask.load] {{{
4878  template <typename _Flags>
4879  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
4880  copy_from(const value_type* __mem, _IsSimdFlagType<_Flags>)
4881  { _M_data = _Impl::template _S_load<_Ip>(_Flags::template _S_apply<simd_mask>(__mem)); }
4882 
4883  // }}}
4884  // stores [simd_mask.store] {{{
4885  template <typename _Flags>
4886  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
4887  copy_to(value_type* __mem, _IsSimdFlagType<_Flags>) const
4888  { _Impl::_S_store(_M_data, _Flags::template _S_apply<simd_mask>(__mem)); }
4889 
4890  // }}}
4891  // scalar access {{{
4892  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR reference
4893  operator[](size_t __i)
4894  {
4895  if (__i >= size())
4896  __invoke_ub("Subscript %d is out of range [0, %d]", __i, size() - 1);
4897  return {_M_data, int(__i)};
4898  }
4899 
4900  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR value_type
4901  operator[](size_t __i) const
4902  {
4903  if (__i >= size())
4904  __invoke_ub("Subscript %d is out of range [0, %d]", __i, size() - 1);
4905  if constexpr (__is_scalar_abi<_Abi>())
4906  return _M_data;
4907  else
4908  return static_cast<bool>(_M_data[__i]);
4909  }
4910 
4911  // }}}
4912  // negation {{{
4913  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd_mask
4914  operator!() const
4915  { return {__private_init, _Impl::_S_bit_not(_M_data)}; }
4916 
4917  // }}}
4918  // simd_mask binary operators [simd_mask.binary] {{{
4919  #ifdef _GLIBCXX_SIMD_ENABLE_IMPLICIT_MASK_CAST
4920  // simd_mask<int> && simd_mask<uint> needs disambiguation
4921  template <typename _Up, typename _A2,
4922  typename = enable_if_t<is_convertible_v<simd_mask<_Up, _A2>, simd_mask>>>
4923  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4924  operator&&(const simd_mask& __x, const simd_mask<_Up, _A2>& __y)
4925  {
4926  return {__private_init,
4927  _Impl::_S_logical_and(__x._M_data, simd_mask(__y)._M_data)};
4928  }
4929 
4930  template <typename _Up, typename _A2,
4931  typename = enable_if_t<is_convertible_v<simd_mask<_Up, _A2>, simd_mask>>>
4932  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4933  operator||(const simd_mask& __x, const simd_mask<_Up, _A2>& __y)
4934  {
4935  return {__private_init,
4936  _Impl::_S_logical_or(__x._M_data, simd_mask(__y)._M_data)};
4937  }
4938  #endif // _GLIBCXX_SIMD_ENABLE_IMPLICIT_MASK_CAST
4939 
4940  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4941  operator&&(const simd_mask& __x, const simd_mask& __y)
4942  { return {__private_init, _Impl::_S_logical_and(__x._M_data, __y._M_data)}; }
4943 
4944  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4945  operator||(const simd_mask& __x, const simd_mask& __y)
4946  { return {__private_init, _Impl::_S_logical_or(__x._M_data, __y._M_data)}; }
4947 
4948  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4949  operator&(const simd_mask& __x, const simd_mask& __y)
4950  { return {__private_init, _Impl::_S_bit_and(__x._M_data, __y._M_data)}; }
4951 
4952  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4953  operator|(const simd_mask& __x, const simd_mask& __y)
4954  { return {__private_init, _Impl::_S_bit_or(__x._M_data, __y._M_data)}; }
4955 
4956  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4957  operator^(const simd_mask& __x, const simd_mask& __y)
4958  { return {__private_init, _Impl::_S_bit_xor(__x._M_data, __y._M_data)}; }
4959 
4960  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask&
4961  operator&=(simd_mask& __x, const simd_mask& __y)
4962  {
4963  __x._M_data = _Impl::_S_bit_and(__x._M_data, __y._M_data);
4964  return __x;
4965  }
4966 
4967  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask&
4968  operator|=(simd_mask& __x, const simd_mask& __y)
4969  {
4970  __x._M_data = _Impl::_S_bit_or(__x._M_data, __y._M_data);
4971  return __x;
4972  }
4973 
4974  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask&
4975  operator^=(simd_mask& __x, const simd_mask& __y)
4976  {
4977  __x._M_data = _Impl::_S_bit_xor(__x._M_data, __y._M_data);
4978  return __x;
4979  }
4980 
4981  // }}}
4982  // simd_mask compares [simd_mask.comparison] {{{
4983  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4984  operator==(const simd_mask& __x, const simd_mask& __y)
4985  { return !operator!=(__x, __y); }
4986 
4987  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
4988  operator!=(const simd_mask& __x, const simd_mask& __y)
4989  { return {__private_init, _Impl::_S_bit_xor(__x._M_data, __y._M_data)}; }
4990 
4991  // }}}
4992  // private_init ctor {{{
4993  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
4994  simd_mask(_PrivateInit, typename _Traits::_MaskMember __init)
4995  : _M_data(__init) {}
4996 
4997  // }}}
4998  // private_init generator ctor {{{
4999  template <typename _Fp, typename = decltype(bool(declval<_Fp>()(size_t())))>
5000  _GLIBCXX_SIMD_INTRINSIC constexpr
5001  simd_mask(_PrivateInit, _Fp&& __gen)
5002  : _M_data()
5003  {
5004  __execute_n_times<size()>([&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
5005  _Impl::_S_set(_M_data, __i, __gen(__i));
5006  });
5007  }
5008 
5009  // }}}
5010  // bitset_init ctor {{{
5011  _GLIBCXX_SIMD_INTRINSIC constexpr
5012  simd_mask(_BitsetInit, bitset<size()> __init)
5013  : _M_data(_Impl::_S_from_bitmask(_SanitizedBitMask<size()>(__init), _S_type_tag))
5014  {}
5015 
5016  // }}}
5017  // __cvt {{{
5018  // TS_FEEDBACK:
5019  // The conversion operator this implements should be a ctor on simd_mask.
5020  // Once you call .__cvt() on a simd_mask it converts conveniently.
5021  // A useful variation: add `explicit(sizeof(_Tp) != sizeof(_Up))`
5022  struct _CvtProxy
5023  {
5024  template <typename _Up, typename _A2,
5025  typename = enable_if_t<simd_size_v<_Up, _A2> == simd_size_v<_Tp, _Abi>>>
5026  _GLIBCXX_SIMD_ALWAYS_INLINE
5027  operator simd_mask<_Up, _A2>() &&
5028  {
5029  using namespace std::experimental::__proposed;
5030  return static_simd_cast<simd_mask<_Up, _A2>>(_M_data);
5031  }
5032 
5033  const simd_mask<_Tp, _Abi>& _M_data;
5034  };
5035 
5036  _GLIBCXX_SIMD_INTRINSIC _CvtProxy
5037  __cvt() const
5038  { return {*this}; }
5039 
5040  // }}}
5041  // operator?: overloads (suggested extension) {{{
5042  #ifdef __GXX_CONDITIONAL_IS_OVERLOADABLE__
5043  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
5044  operator?:(const simd_mask& __k, const simd_mask& __where_true,
5045  const simd_mask& __where_false)
5046  {
5047  auto __ret = __where_false;
5048  _Impl::_S_masked_assign(__k._M_data, __ret._M_data, __where_true._M_data);
5049  return __ret;
5050  }
5051 
5052  template <typename _U1, typename _U2,
5053  typename _Rp = simd<common_type_t<_U1, _U2>, _Abi>,
5054  typename = enable_if_t<conjunction_v<
5055  is_convertible<_U1, _Rp>, is_convertible<_U2, _Rp>,
5056  is_convertible<simd_mask, typename _Rp::mask_type>>>>
5057  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend _Rp
5058  operator?:(const simd_mask& __k, const _U1& __where_true,
5059  const _U2& __where_false)
5060  {
5061  _Rp __ret = __where_false;
5062  _Rp::_Impl::_S_masked_assign(
5063  __data(static_cast<typename _Rp::mask_type>(__k)), __data(__ret),
5064  __data(static_cast<_Rp>(__where_true)));
5065  return __ret;
5066  }
5067 
5068  #ifdef _GLIBCXX_SIMD_ENABLE_IMPLICIT_MASK_CAST
5069  template <typename _Kp, typename _Ak, typename _Up, typename _Au,
5070  typename = enable_if_t<
5071  conjunction_v<is_convertible<simd_mask<_Kp, _Ak>, simd_mask>,
5072  is_convertible<simd_mask<_Up, _Au>, simd_mask>>>>
5073  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
5074  operator?:(const simd_mask<_Kp, _Ak>& __k, const simd_mask& __where_true,
5075  const simd_mask<_Up, _Au>& __where_false)
5076  {
5077  simd_mask __ret = __where_false;
5078  _Impl::_S_masked_assign(simd_mask(__k)._M_data, __ret._M_data,
5079  __where_true._M_data);
5080  return __ret;
5081  }
5082  #endif // _GLIBCXX_SIMD_ENABLE_IMPLICIT_MASK_CAST
5083  #endif // __GXX_CONDITIONAL_IS_OVERLOADABLE__
5084 
5085  // }}}
5086  // _M_is_constprop {{{
5087  _GLIBCXX_SIMD_INTRINSIC constexpr bool
5088  _M_is_constprop() const
5089  {
5090  if constexpr (__is_scalar_abi<_Abi>())
5091  return __builtin_constant_p(_M_data);
5092  else
5093  return _M_data._M_is_constprop();
5094  }
5095 
5096  // }}}
5097 
5098  private:
5099  friend const auto& __data<_Tp, abi_type>(const simd_mask&);
5100  friend auto& __data<_Tp, abi_type>(simd_mask&);
5101  alignas(_Traits::_S_mask_align) _MemberType _M_data;
5102  };
5103 
5104 // }}}
5105 
5106 /// @cond undocumented
5107 // __data(simd_mask) {{{
5108 template <typename _Tp, typename _Ap>
5109  _GLIBCXX_SIMD_INTRINSIC constexpr const auto&
5110  __data(const simd_mask<_Tp, _Ap>& __x)
5111  { return __x._M_data; }
5112 
5113 template <typename _Tp, typename _Ap>
5114  _GLIBCXX_SIMD_INTRINSIC constexpr auto&
5115  __data(simd_mask<_Tp, _Ap>& __x)
5116  { return __x._M_data; }
5117 
5118 // }}}
5119 /// @endcond
5120 
5121 // simd_mask reductions [simd_mask.reductions] {{{
5122 template <typename _Tp, typename _Abi>
5123  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5124  all_of(const simd_mask<_Tp, _Abi>& __k) noexcept
5125  {
5126  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5127  {
5128  for (size_t __i = 0; __i < simd_size_v<_Tp, _Abi>; ++__i)
5129  if (!__k[__i])
5130  return false;
5131  return true;
5132  }
5133  else
5134  return _Abi::_MaskImpl::_S_all_of(__k);
5135  }
5136 
5137 template <typename _Tp, typename _Abi>
5138  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5139  any_of(const simd_mask<_Tp, _Abi>& __k) noexcept
5140  {
5141  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5142  {
5143  for (size_t __i = 0; __i < simd_size_v<_Tp, _Abi>; ++__i)
5144  if (__k[__i])
5145  return true;
5146  return false;
5147  }
5148  else
5149  return _Abi::_MaskImpl::_S_any_of(__k);
5150  }
5151 
5152 template <typename _Tp, typename _Abi>
5153  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5154  none_of(const simd_mask<_Tp, _Abi>& __k) noexcept
5155  {
5156  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5157  {
5158  for (size_t __i = 0; __i < simd_size_v<_Tp, _Abi>; ++__i)
5159  if (__k[__i])
5160  return false;
5161  return true;
5162  }
5163  else
5164  return _Abi::_MaskImpl::_S_none_of(__k);
5165  }
5166 
5167 template <typename _Tp, typename _Abi>
5168  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5169  some_of(const simd_mask<_Tp, _Abi>& __k) noexcept
5170  {
5171  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5172  {
5173  for (size_t __i = 1; __i < simd_size_v<_Tp, _Abi>; ++__i)
5174  if (__k[__i] != __k[__i - 1])
5175  return true;
5176  return false;
5177  }
5178  else
5179  return _Abi::_MaskImpl::_S_some_of(__k);
5180  }
5181 
5182 template <typename _Tp, typename _Abi>
5183  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR int
5184  popcount(const simd_mask<_Tp, _Abi>& __k) noexcept
5185  {
5186  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5187  {
5188  const int __r = __call_with_subscripts<simd_size_v<_Tp, _Abi>>(
5189  __k, [](auto... __elements) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
5190  return ((__elements != 0) + ...);
5191  });
5192  if (__builtin_is_constant_evaluated() || __builtin_constant_p(__r))
5193  return __r;
5194  }
5195  return _Abi::_MaskImpl::_S_popcount(__k);
5196  }
5197 
5198 template <typename _Tp, typename _Abi>
5199  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR int
5200  find_first_set(const simd_mask<_Tp, _Abi>& __k)
5201  {
5202  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5203  {
5204  constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5205  const size_t _Idx = __call_with_n_evaluations<_Np>(
5206  [](auto... __indexes) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
5207  return std::min({__indexes...});
5208  }, [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
5209  return __k[__i] ? +__i : _Np;
5210  });
5211  if (_Idx >= _Np)
5212  __invoke_ub("find_first_set(empty mask) is UB");
5213  if (__builtin_constant_p(_Idx))
5214  return _Idx;
5215  }
5216  return _Abi::_MaskImpl::_S_find_first_set(__k);
5217  }
5218 
5219 template <typename _Tp, typename _Abi>
5220  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR int
5221  find_last_set(const simd_mask<_Tp, _Abi>& __k)
5222  {
5223  if (__builtin_is_constant_evaluated() || __k._M_is_constprop())
5224  {
5225  constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5226  const int _Idx = __call_with_n_evaluations<_Np>(
5227  [](auto... __indexes) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
5228  return std::max({__indexes...});
5229  }, [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
5230  return __k[__i] ? int(__i) : -1;
5231  });
5232  if (_Idx < 0)
5233  __invoke_ub("find_first_set(empty mask) is UB");
5234  if (__builtin_constant_p(_Idx))
5235  return _Idx;
5236  }
5237  return _Abi::_MaskImpl::_S_find_last_set(__k);
5238  }
5239 
5240 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5241 all_of(_ExactBool __x) noexcept
5242 { return __x; }
5243 
5244 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5245 any_of(_ExactBool __x) noexcept
5246 { return __x; }
5247 
5248 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5249 none_of(_ExactBool __x) noexcept
5250 { return !__x; }
5251 
5252 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bool
5253 some_of(_ExactBool) noexcept
5254 { return false; }
5255 
5256 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR int
5257 popcount(_ExactBool __x) noexcept
5258 { return __x; }
5259 
5260 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR int
5261 find_first_set(_ExactBool)
5262 { return 0; }
5263 
5264 _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR int
5265 find_last_set(_ExactBool)
5266 { return 0; }
5267 
5268 // }}}
5269 
5270 /// @cond undocumented
5271 // _SimdIntOperators{{{1
5272 template <typename _V, typename _Tp, typename _Abi, bool>
5273  class _SimdIntOperators {};
5274 
5275 template <typename _V, typename _Tp, typename _Abi>
5276  class _SimdIntOperators<_V, _Tp, _Abi, true>
5277  {
5278  using _Impl = typename _SimdTraits<_Tp, _Abi>::_SimdImpl;
5279 
5280  _GLIBCXX_SIMD_INTRINSIC constexpr const _V&
5281  __derived() const
5282  { return *static_cast<const _V*>(this); }
5283 
5284  template <typename _Up>
5285  _GLIBCXX_SIMD_INTRINSIC static _GLIBCXX_SIMD_CONSTEXPR _V
5286  _S_make_derived(_Up&& __d)
5287  { return {__private_init, static_cast<_Up&&>(__d)}; }
5288 
5289  public:
5290  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5291  _V&
5292  operator%=(_V& __lhs, const _V& __x)
5293  { return __lhs = __lhs % __x; }
5294 
5295  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5296  _V&
5297  operator&=(_V& __lhs, const _V& __x)
5298  { return __lhs = __lhs & __x; }
5299 
5300  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5301  _V&
5302  operator|=(_V& __lhs, const _V& __x)
5303  { return __lhs = __lhs | __x; }
5304 
5305  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5306  _V&
5307  operator^=(_V& __lhs, const _V& __x)
5308  { return __lhs = __lhs ^ __x; }
5309 
5310  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5311  _V&
5312  operator<<=(_V& __lhs, const _V& __x)
5313  { return __lhs = __lhs << __x; }
5314 
5315  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5316  _V&
5317  operator>>=(_V& __lhs, const _V& __x)
5318  { return __lhs = __lhs >> __x; }
5319 
5320  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5321  _V&
5322  operator<<=(_V& __lhs, int __x)
5323  { return __lhs = __lhs << __x; }
5324 
5325  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5326  _V&
5327  operator>>=(_V& __lhs, int __x)
5328  { return __lhs = __lhs >> __x; }
5329 
5330  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5331  _V
5332  operator%(const _V& __x, const _V& __y)
5333  {
5334  return _SimdIntOperators::_S_make_derived(
5335  _Impl::_S_modulus(__data(__x), __data(__y)));
5336  }
5337 
5338  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5339  _V
5340  operator&(const _V& __x, const _V& __y)
5341  {
5342  return _SimdIntOperators::_S_make_derived(
5343  _Impl::_S_bit_and(__data(__x), __data(__y)));
5344  }
5345 
5346  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5347  _V
5348  operator|(const _V& __x, const _V& __y)
5349  {
5350  return _SimdIntOperators::_S_make_derived(
5351  _Impl::_S_bit_or(__data(__x), __data(__y)));
5352  }
5353 
5354  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5355  _V
5356  operator^(const _V& __x, const _V& __y)
5357  {
5358  return _SimdIntOperators::_S_make_derived(
5359  _Impl::_S_bit_xor(__data(__x), __data(__y)));
5360  }
5361 
5362  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5363  _V
5364  operator<<(const _V& __x, const _V& __y)
5365  {
5366  return _SimdIntOperators::_S_make_derived(
5367  _Impl::_S_bit_shift_left(__data(__x), __data(__y)));
5368  }
5369 
5370  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5371  _V
5372  operator>>(const _V& __x, const _V& __y)
5373  {
5374  return _SimdIntOperators::_S_make_derived(
5375  _Impl::_S_bit_shift_right(__data(__x), __data(__y)));
5376  }
5377 
5378  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5379  _V
5380  operator<<(const _V& __x, int __y)
5381  {
5382  if (__y < 0)
5383  __invoke_ub("The behavior is undefined if the right operand of a "
5384  "shift operation is negative. [expr.shift]\nA shift by "
5385  "%d was requested",
5386  __y);
5387  if (size_t(__y) >= sizeof(declval<_Tp>() << __y) * __CHAR_BIT__)
5388  __invoke_ub(
5389  "The behavior is undefined if the right operand of a "
5390  "shift operation is greater than or equal to the width of the "
5391  "promoted left operand. [expr.shift]\nA shift by %d was requested",
5392  __y);
5393  return _SimdIntOperators::_S_make_derived(
5394  _Impl::_S_bit_shift_left(__data(__x), __y));
5395  }
5396 
5397  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend
5398  _V
5399  operator>>(const _V& __x, int __y)
5400  {
5401  if (__y < 0)
5402  __invoke_ub(
5403  "The behavior is undefined if the right operand of a shift "
5404  "operation is negative. [expr.shift]\nA shift by %d was requested",
5405  __y);
5406  if (size_t(__y) >= sizeof(declval<_Tp>() << __y) * __CHAR_BIT__)
5407  __invoke_ub(
5408  "The behavior is undefined if the right operand of a shift "
5409  "operation is greater than or equal to the width of the promoted "
5410  "left operand. [expr.shift]\nA shift by %d was requested",
5411  __y);
5412  return _SimdIntOperators::_S_make_derived(
5413  _Impl::_S_bit_shift_right(__data(__x), __y));
5414  }
5415 
5416  // unary operators (for integral _Tp)
5417  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
5418  _V
5419  operator~() const
5420  { return {__private_init, _Impl::_S_complement(__derived()._M_data)}; }
5421  };
5422 
5423 //}}}1
5424 /// @endcond
5425 
5426 // simd {{{
5427 template <typename _Tp, typename _Abi>
5428  class simd : public _SimdIntOperators<
5429  simd<_Tp, _Abi>, _Tp, _Abi,
5430  conjunction<is_integral<_Tp>,
5431  typename _SimdTraits<_Tp, _Abi>::_IsValid>::value>,
5432  public _SimdTraits<_Tp, _Abi>::_SimdBase
5433  {
5434  using _Traits = _SimdTraits<_Tp, _Abi>;
5435  using _MemberType = typename _Traits::_SimdMember;
5436  using _CastType = typename _Traits::_SimdCastType;
5437  static constexpr _Tp* _S_type_tag = nullptr;
5438  friend typename _Traits::_SimdBase;
5439 
5440  public:
5441  using _Impl = typename _Traits::_SimdImpl;
5442  friend _Impl;
5443  friend _SimdIntOperators<simd, _Tp, _Abi, true>;
5444 
5445  using value_type = _Tp;
5446  using reference = _SmartReference<_MemberType, _Impl, value_type>;
5447  using mask_type = simd_mask<_Tp, _Abi>;
5448  using abi_type = _Abi;
5449 
5450  static constexpr size_t size()
5451  { return __size_or_zero_v<_Tp, _Abi>; }
5452 
5453  _GLIBCXX_SIMD_CONSTEXPR simd() = default;
5454  _GLIBCXX_SIMD_CONSTEXPR simd(const simd&) = default;
5455  _GLIBCXX_SIMD_CONSTEXPR simd(simd&&) noexcept = default;
5456  _GLIBCXX_SIMD_CONSTEXPR simd& operator=(const simd&) = default;
5457  _GLIBCXX_SIMD_CONSTEXPR simd& operator=(simd&&) noexcept = default;
5458 
5459  // implicit broadcast constructor
5460  template <typename _Up,
5461  typename = enable_if_t<!is_same_v<__remove_cvref_t<_Up>, bool>>>
5462  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
5463  simd(_ValuePreservingOrInt<_Up, value_type>&& __x)
5464  : _M_data(
5465  _Impl::_S_broadcast(static_cast<value_type>(static_cast<_Up&&>(__x))))
5466  {}
5467 
5468  // implicit type conversion constructor (convert from fixed_size to
5469  // fixed_size)
5470  template <typename _Up>
5471  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
5472  simd(const simd<_Up, simd_abi::fixed_size<size()>>& __x,
5473  enable_if_t<
5474  conjunction<
5475  is_same<simd_abi::fixed_size<size()>, abi_type>,
5476  negation<__is_narrowing_conversion<_Up, value_type>>,
5477  __converts_to_higher_integer_rank<_Up, value_type>>::value,
5478  void*> = nullptr)
5479  : simd{static_cast<array<_Up, size()>>(__x).data(), vector_aligned} {}
5480 
5481  // explicit type conversion constructor
5482 #ifdef _GLIBCXX_SIMD_ENABLE_STATIC_CAST
5483  template <typename _Up, typename _A2,
5484  typename = decltype(static_simd_cast<simd>(
5485  declval<const simd<_Up, _A2>&>()))>
5486  _GLIBCXX_SIMD_ALWAYS_INLINE explicit _GLIBCXX_SIMD_CONSTEXPR
5487  simd(const simd<_Up, _A2>& __x)
5488  : simd(static_simd_cast<simd>(__x)) {}
5489 #endif // _GLIBCXX_SIMD_ENABLE_STATIC_CAST
5490 
5491  // generator constructor
5492  template <typename _Fp>
5493  _GLIBCXX_SIMD_ALWAYS_INLINE explicit _GLIBCXX_SIMD_CONSTEXPR
5494  simd(_Fp&& __gen, _ValuePreservingOrInt<decltype(declval<_Fp>()(
5495  declval<_SizeConstant<0>&>())),
5496  value_type>* = nullptr)
5497  : _M_data(_Impl::_S_generator(static_cast<_Fp&&>(__gen), _S_type_tag)) {}
5498 
5499  // load constructor
5500  template <typename _Up, typename _Flags>
5501  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
5502  simd(const _Up* __mem, _IsSimdFlagType<_Flags>)
5503  : _M_data(
5504  _Impl::_S_load(_Flags::template _S_apply<simd>(__mem), _S_type_tag))
5505  {}
5506 
5507  // loads [simd.load]
5508  template <typename _Up, typename _Flags>
5509  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
5510  copy_from(const _Vectorizable<_Up>* __mem, _IsSimdFlagType<_Flags>)
5511  {
5512  _M_data = static_cast<decltype(_M_data)>(
5513  _Impl::_S_load(_Flags::template _S_apply<simd>(__mem), _S_type_tag));
5514  }
5515 
5516  // stores [simd.store]
5517  template <typename _Up, typename _Flags>
5518  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
5519  copy_to(_Vectorizable<_Up>* __mem, _IsSimdFlagType<_Flags>) const
5520  {
5521  _Impl::_S_store(_M_data, _Flags::template _S_apply<simd>(__mem),
5522  _S_type_tag);
5523  }
5524 
5525  // scalar access
5526  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR reference
5527  operator[](size_t __i)
5528  { return {_M_data, int(__i)}; }
5529 
5530  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR value_type
5531  operator[]([[maybe_unused]] size_t __i) const
5532  {
5533  if constexpr (__is_scalar_abi<_Abi>())
5534  {
5535  _GLIBCXX_DEBUG_ASSERT(__i == 0);
5536  return _M_data;
5537  }
5538  else
5539  return _M_data[__i];
5540  }
5541 
5542  // increment and decrement:
5543  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd&
5544  operator++()
5545  {
5546  _Impl::_S_increment(_M_data);
5547  return *this;
5548  }
5549 
5550  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd
5551  operator++(int)
5552  {
5553  simd __r = *this;
5554  _Impl::_S_increment(_M_data);
5555  return __r;
5556  }
5557 
5558  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd&
5559  operator--()
5560  {
5561  _Impl::_S_decrement(_M_data);
5562  return *this;
5563  }
5564 
5565  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd
5566  operator--(int)
5567  {
5568  simd __r = *this;
5569  _Impl::_S_decrement(_M_data);
5570  return __r;
5571  }
5572 
5573  // unary operators (for any _Tp)
5574  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR mask_type
5575  operator!() const
5576  { return {__private_init, _Impl::_S_negate(_M_data)}; }
5577 
5578  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd
5579  operator+() const
5580  { return *this; }
5581 
5582  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd
5583  operator-() const
5584  { return {__private_init, _Impl::_S_unary_minus(_M_data)}; }
5585 
5586  // access to internal representation (suggested extension)
5587  _GLIBCXX_SIMD_ALWAYS_INLINE explicit _GLIBCXX_SIMD_CONSTEXPR
5588  simd(_CastType __init) : _M_data(__init) {}
5589 
5590  // compound assignment [simd.cassign]
5591  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd&
5592  operator+=(simd& __lhs, const simd& __x)
5593  { return __lhs = __lhs + __x; }
5594 
5595  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd&
5596  operator-=(simd& __lhs, const simd& __x)
5597  { return __lhs = __lhs - __x; }
5598 
5599  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd&
5600  operator*=(simd& __lhs, const simd& __x)
5601  { return __lhs = __lhs * __x; }
5602 
5603  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd&
5604  operator/=(simd& __lhs, const simd& __x)
5605  { return __lhs = __lhs / __x; }
5606 
5607  // binary operators [simd.binary]
5608  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd
5609  operator+(const simd& __x, const simd& __y)
5610  { return {__private_init, _Impl::_S_plus(__x._M_data, __y._M_data)}; }
5611 
5612  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd
5613  operator-(const simd& __x, const simd& __y)
5614  { return {__private_init, _Impl::_S_minus(__x._M_data, __y._M_data)}; }
5615 
5616  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd
5617  operator*(const simd& __x, const simd& __y)
5618  { return {__private_init, _Impl::_S_multiplies(__x._M_data, __y._M_data)}; }
5619 
5620  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd
5621  operator/(const simd& __x, const simd& __y)
5622  { return {__private_init, _Impl::_S_divides(__x._M_data, __y._M_data)}; }
5623 
5624  // compares [simd.comparison]
5625  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend mask_type
5626  operator==(const simd& __x, const simd& __y)
5627  { return simd::_S_make_mask(_Impl::_S_equal_to(__x._M_data, __y._M_data)); }
5628 
5629  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend mask_type
5630  operator!=(const simd& __x, const simd& __y)
5631  {
5632  return simd::_S_make_mask(
5633  _Impl::_S_not_equal_to(__x._M_data, __y._M_data));
5634  }
5635 
5636  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend mask_type
5637  operator<(const simd& __x, const simd& __y)
5638  { return simd::_S_make_mask(_Impl::_S_less(__x._M_data, __y._M_data)); }
5639 
5640  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend mask_type
5641  operator<=(const simd& __x, const simd& __y)
5642  {
5643  return simd::_S_make_mask(_Impl::_S_less_equal(__x._M_data, __y._M_data));
5644  }
5645 
5646  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend mask_type
5647  operator>(const simd& __x, const simd& __y)
5648  { return simd::_S_make_mask(_Impl::_S_less(__y._M_data, __x._M_data)); }
5649 
5650  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend mask_type
5651  operator>=(const simd& __x, const simd& __y)
5652  {
5653  return simd::_S_make_mask(_Impl::_S_less_equal(__y._M_data, __x._M_data));
5654  }
5655 
5656  // operator?: overloads (suggested extension) {{{
5657 #ifdef __GXX_CONDITIONAL_IS_OVERLOADABLE__
5658  _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd
5659  operator?:(const mask_type& __k, const simd& __where_true,
5660  const simd& __where_false)
5661  {
5662  auto __ret = __where_false;
5663  _Impl::_S_masked_assign(__data(__k), __data(__ret), __data(__where_true));
5664  return __ret;
5665  }
5666 
5667 #endif // __GXX_CONDITIONAL_IS_OVERLOADABLE__
5668  // }}}
5669 
5670  // "private" because of the first arguments's namespace
5671  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
5672  simd(_PrivateInit, const _MemberType& __init)
5673  : _M_data(__init) {}
5674 
5675  // "private" because of the first arguments's namespace
5676  _GLIBCXX_SIMD_INTRINSIC
5677  simd(_BitsetInit, bitset<size()> __init) : _M_data()
5678  { where(mask_type(__bitset_init, __init), *this) = ~*this; }
5679 
5680  _GLIBCXX_SIMD_INTRINSIC constexpr bool
5681  _M_is_constprop() const
5682  {
5683  if constexpr (__is_scalar_abi<_Abi>())
5684  return __builtin_constant_p(_M_data);
5685  else
5686  return _M_data._M_is_constprop();
5687  }
5688 
5689  private:
5690  _GLIBCXX_SIMD_INTRINSIC static constexpr mask_type
5691  _S_make_mask(typename mask_type::_MemberType __k)
5692  { return {__private_init, __k}; }
5693 
5694  friend const auto& __data<value_type, abi_type>(const simd&);
5695  friend auto& __data<value_type, abi_type>(simd&);
5696  alignas(_Traits::_S_simd_align) _MemberType _M_data;
5697  };
5698 
5699 // }}}
5700 /// @cond undocumented
5701 // __data {{{
5702 template <typename _Tp, typename _Ap>
5703  _GLIBCXX_SIMD_INTRINSIC constexpr const auto&
5704  __data(const simd<_Tp, _Ap>& __x)
5705  { return __x._M_data; }
5706 
5707 template <typename _Tp, typename _Ap>
5708  _GLIBCXX_SIMD_INTRINSIC constexpr auto&
5709  __data(simd<_Tp, _Ap>& __x)
5710  { return __x._M_data; }
5711 
5712 // }}}
5713 namespace __float_bitwise_operators { //{{{
5714 template <typename _Tp, typename _Ap>
5715  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR simd<_Tp, _Ap>
5716  operator^(const simd<_Tp, _Ap>& __a, const simd<_Tp, _Ap>& __b)
5717  { return {__private_init, _Ap::_SimdImpl::_S_bit_xor(__data(__a), __data(__b))}; }
5718 
5719 template <typename _Tp, typename _Ap>
5720  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR simd<_Tp, _Ap>
5721  operator|(const simd<_Tp, _Ap>& __a, const simd<_Tp, _Ap>& __b)
5722  { return {__private_init, _Ap::_SimdImpl::_S_bit_or(__data(__a), __data(__b))}; }
5723 
5724 template <typename _Tp, typename _Ap>
5725  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR simd<_Tp, _Ap>
5726  operator&(const simd<_Tp, _Ap>& __a, const simd<_Tp, _Ap>& __b)
5727  { return {__private_init, _Ap::_SimdImpl::_S_bit_and(__data(__a), __data(__b))}; }
5728 
5729 template <typename _Tp, typename _Ap>
5730  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
5731  enable_if_t<is_floating_point_v<_Tp>, simd<_Tp, _Ap>>
5732  operator~(const simd<_Tp, _Ap>& __a)
5733  { return {__private_init, _Ap::_SimdImpl::_S_complement(__data(__a))}; }
5734 } // namespace __float_bitwise_operators }}}
5735 /// @endcond
5736 
5737 /// @}
5738 _GLIBCXX_SIMD_END_NAMESPACE
5739 
5740 #endif // __cplusplus >= 201703L
5741 #endif // _GLIBCXX_EXPERIMENTAL_SIMD_H
5742 
5743 // vim: foldmethod=marker foldmarker={{{,}}}
constexpr duration< __common_rep_t< _Rep1, __disable_if_is_duration< _Rep2 > >, _Period > operator%(const duration< _Rep1, _Period > &__d, const _Rep2 &__s)
Definition: chrono.h:783
constexpr bool operator<=(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition: chrono.h:859
constexpr bool operator>=(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition: chrono.h:873
constexpr bool operator<(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition: chrono.h:826
constexpr bool operator>(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition: chrono.h:866
constexpr complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition: complex:434
constexpr complex< _Tp > operator/(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x divided by y.
Definition: complex:464
constexpr complex< _Tp > operator-(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x minus y.
Definition: complex:404
constexpr complex< _Tp > operator+(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x plus y.
Definition: complex:374
typename remove_reference< _Tp >::type remove_reference_t
Alias template for remove_reference.
Definition: type_traits:1892
typename make_unsigned< _Tp >::type make_unsigned_t
Alias template for make_unsigned.
Definition: type_traits:2252
__bool_constant< true > true_type
The type used as a compile-time boolean with true value.
Definition: type_traits:119
typename conditional< _Cond, _Iftrue, _Iffalse >::type conditional_t
Alias template for conditional.
Definition: type_traits:2950
typename remove_pointer< _Tp >::type remove_pointer_t
Alias template for remove_pointer.
Definition: type_traits:2358
__bool_constant< false > false_type
The type used as a compile-time boolean with false value.
Definition: type_traits:122
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2946
constexpr auto tuple_cat(_Tpls &&... __tpls) -> typename __tuple_cat_result< _Tpls... >::__type
Create a tuple containing all elements from multiple tuple-like objects.
Definition: tuple:2859
auto declval() noexcept -> decltype(__declval< _Tp >(0))
Definition: type_traits:2720
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
constexpr tuple< typename __decay_and_strip< _Elements >::__type... > make_tuple(_Elements &&... __args)
Create a tuple containing copies of the arguments.
Definition: tuple:2723
constexpr const _Tp & max(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:256
constexpr const _Tp & min(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:232
constexpr _Tp reduce(_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOperation __binary_op)
Calculate reduction of values in a range.
Definition: numeric:294
void void_t
A metafunction that always yields void, used for detecting valid types.
ISO C++ entities toplevel namespace is std.
std::basic_istream< _CharT, _Traits > & operator>>(std::basic_istream< _CharT, _Traits > &__is, bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1658
constexpr bitset< _Nb > operator&(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1618
std::basic_ostream< _CharT, _Traits > & operator<<(std::basic_ostream< _CharT, _Traits > &__os, const bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1754
make_integer_sequence< size_t, _Num > make_index_sequence
Alias template make_index_sequence.
Definition: utility.h:529
constexpr bitset< _Nb > operator|(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1628
constexpr bitset< _Nb > operator^(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1638