libstdc++
simd_x86.h
1// Simd x86 specific implementations -*- C++ -*-
2
3// Copyright (C) 2020-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25#ifndef _GLIBCXX_EXPERIMENTAL_SIMD_X86_H_
26#define _GLIBCXX_EXPERIMENTAL_SIMD_X86_H_
27
28#if __cplusplus >= 201703L
29
30#if !_GLIBCXX_SIMD_X86INTRIN
31#error \
32 "simd_x86.h may only be included when MMX or SSE on x86(_64) are available"
33#endif
34
35_GLIBCXX_SIMD_BEGIN_NAMESPACE
36
37// __to_masktype {{{
38// Given <T, N> return <__int_for_sizeof_t<T>, N>. For _SimdWrapper and
39// __vector_type_t.
40template <typename _Tp, size_t _Np>
41 _GLIBCXX_SIMD_INTRINSIC constexpr _SimdWrapper<__int_for_sizeof_t<_Tp>, _Np>
42 __to_masktype(_SimdWrapper<_Tp, _Np> __x)
43 { return reinterpret_cast<__vector_type_t<__int_for_sizeof_t<_Tp>, _Np>>(__x._M_data); }
44
45template <typename _TV,
46 typename _TVT
47 = enable_if_t<__is_vector_type_v<_TV>, _VectorTraits<_TV>>,
48 typename _Up = __int_for_sizeof_t<typename _TVT::value_type>>
49 _GLIBCXX_SIMD_INTRINSIC constexpr __vector_type_t<_Up, _TVT::_S_full_size>
50 __to_masktype(_TV __x)
51 { return reinterpret_cast<__vector_type_t<_Up, _TVT::_S_full_size>>(__x); }
52
53// }}}
54// __interleave128_lo {{{
55template <typename _Ap, typename _Bp, typename _Tp = common_type_t<_Ap, _Bp>,
56 typename _Trait = _VectorTraits<_Tp>>
57 _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
58 __interleave128_lo(const _Ap& __av, const _Bp& __bv)
59 {
60 const _Tp __a(__av);
61 const _Tp __b(__bv);
62 if constexpr (sizeof(_Tp) == 16 && _Trait::_S_full_size == 2)
63 return _Tp{__a[0], __b[0]};
64 else if constexpr (sizeof(_Tp) == 16 && _Trait::_S_full_size == 4)
65 return _Tp{__a[0], __b[0], __a[1], __b[1]};
66 else if constexpr (sizeof(_Tp) == 16 && _Trait::_S_full_size == 8)
67 return _Tp{__a[0], __b[0], __a[1], __b[1],
68 __a[2], __b[2], __a[3], __b[3]};
69 else if constexpr (sizeof(_Tp) == 16 && _Trait::_S_full_size == 16)
70 return _Tp{__a[0], __b[0], __a[1], __b[1], __a[2], __b[2],
71 __a[3], __b[3], __a[4], __b[4], __a[5], __b[5],
72 __a[6], __b[6], __a[7], __b[7]};
73 else if constexpr (sizeof(_Tp) == 32 && _Trait::_S_full_size == 4)
74 return _Tp{__a[0], __b[0], __a[2], __b[2]};
75 else if constexpr (sizeof(_Tp) == 32 && _Trait::_S_full_size == 8)
76 return _Tp{__a[0], __b[0], __a[1], __b[1],
77 __a[4], __b[4], __a[5], __b[5]};
78 else if constexpr (sizeof(_Tp) == 32 && _Trait::_S_full_size == 16)
79 return _Tp{__a[0], __b[0], __a[1], __b[1], __a[2], __b[2],
80 __a[3], __b[3], __a[8], __b[8], __a[9], __b[9],
81 __a[10], __b[10], __a[11], __b[11]};
82 else if constexpr (sizeof(_Tp) == 32 && _Trait::_S_full_size == 32)
83 return _Tp{__a[0], __b[0], __a[1], __b[1], __a[2], __b[2], __a[3],
84 __b[3], __a[4], __b[4], __a[5], __b[5], __a[6], __b[6],
85 __a[7], __b[7], __a[16], __b[16], __a[17], __b[17], __a[18],
86 __b[18], __a[19], __b[19], __a[20], __b[20], __a[21], __b[21],
87 __a[22], __b[22], __a[23], __b[23]};
88 else if constexpr (sizeof(_Tp) == 64 && _Trait::_S_full_size == 8)
89 return _Tp{__a[0], __b[0], __a[2], __b[2],
90 __a[4], __b[4], __a[6], __b[6]};
91 else if constexpr (sizeof(_Tp) == 64 && _Trait::_S_full_size == 16)
92 return _Tp{__a[0], __b[0], __a[1], __b[1], __a[4], __b[4],
93 __a[5], __b[5], __a[8], __b[8], __a[9], __b[9],
94 __a[12], __b[12], __a[13], __b[13]};
95 else if constexpr (sizeof(_Tp) == 64 && _Trait::_S_full_size == 32)
96 return _Tp{__a[0], __b[0], __a[1], __b[1], __a[2], __b[2], __a[3],
97 __b[3], __a[8], __b[8], __a[9], __b[9], __a[10], __b[10],
98 __a[11], __b[11], __a[16], __b[16], __a[17], __b[17], __a[18],
99 __b[18], __a[19], __b[19], __a[24], __b[24], __a[25], __b[25],
100 __a[26], __b[26], __a[27], __b[27]};
101 else if constexpr (sizeof(_Tp) == 64 && _Trait::_S_full_size == 64)
102 return _Tp{__a[0], __b[0], __a[1], __b[1], __a[2], __b[2], __a[3],
103 __b[3], __a[4], __b[4], __a[5], __b[5], __a[6], __b[6],
104 __a[7], __b[7], __a[16], __b[16], __a[17], __b[17], __a[18],
105 __b[18], __a[19], __b[19], __a[20], __b[20], __a[21], __b[21],
106 __a[22], __b[22], __a[23], __b[23], __a[32], __b[32], __a[33],
107 __b[33], __a[34], __b[34], __a[35], __b[35], __a[36], __b[36],
108 __a[37], __b[37], __a[38], __b[38], __a[39], __b[39], __a[48],
109 __b[48], __a[49], __b[49], __a[50], __b[50], __a[51], __b[51],
110 __a[52], __b[52], __a[53], __b[53], __a[54], __b[54], __a[55],
111 __b[55]};
112 else
113 __assert_unreachable<_Tp>();
114 }
115
116// }}}
117// __is_zero{{{
118template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
119 _GLIBCXX_SIMD_INTRINSIC constexpr bool
120 __is_zero(_Tp __a)
121 {
122 if (!__builtin_is_constant_evaluated())
123 {
124 if constexpr (__have_avx)
125 {
126 if constexpr (_TVT::template _S_is<float, 8>)
127 return _mm256_testz_ps(__a, __a);
128 else if constexpr (_TVT::template _S_is<double, 4>)
129 return _mm256_testz_pd(__a, __a);
130 else if constexpr (sizeof(_Tp) == 32)
131 return _mm256_testz_si256(__to_intrin(__a), __to_intrin(__a));
132 else if constexpr (_TVT::template _S_is<float>)
133 return _mm_testz_ps(__to_intrin(__a), __to_intrin(__a));
134 else if constexpr (_TVT::template _S_is<double, 2>)
135 return _mm_testz_pd(__a, __a);
136 else
137 return _mm_testz_si128(__to_intrin(__a), __to_intrin(__a));
138 }
139 else if constexpr (__have_sse4_1)
140 return _mm_testz_si128(__intrin_bitcast<__m128i>(__a),
141 __intrin_bitcast<__m128i>(__a));
142 }
143 else if constexpr (sizeof(_Tp) <= 8)
144 return reinterpret_cast<__int_for_sizeof_t<_Tp>>(__a) == 0;
145 else
146 {
147 const auto __b = __vector_bitcast<_LLong>(__a);
148 if constexpr (sizeof(__b) == 16)
149 return (__b[0] | __b[1]) == 0;
150 else if constexpr (sizeof(__b) == 32)
151 return __is_zero(__lo128(__b) | __hi128(__b));
152 else if constexpr (sizeof(__b) == 64)
153 return __is_zero(__lo256(__b) | __hi256(__b));
154 else
155 __assert_unreachable<_Tp>();
156 }
157 }
158
159// }}}
160// __movemask{{{
161template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
162 _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST int
163 __movemask(_Tp __a)
164 {
165 if constexpr (sizeof(_Tp) == 32)
166 {
167 if constexpr (_TVT::template _S_is<float>)
168 return _mm256_movemask_ps(__to_intrin(__a));
169 else if constexpr (_TVT::template _S_is<double>)
170 return _mm256_movemask_pd(__to_intrin(__a));
171 else
172 return _mm256_movemask_epi8(__to_intrin(__a));
173 }
174 else if constexpr (_TVT::template _S_is<float>)
175 return _mm_movemask_ps(__to_intrin(__a));
176 else if constexpr (_TVT::template _S_is<double>)
177 return _mm_movemask_pd(__to_intrin(__a));
178 else
179 return _mm_movemask_epi8(__to_intrin(__a));
180 }
181
182// }}}
183// __testz{{{
184template <typename _TI, typename _TVT = _VectorTraits<_TI>>
185 _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST constexpr int
186 __testz(_TI __a, _TI __b)
187 {
188 static_assert(is_same_v<_TI, __intrinsic_type_t<typename _TVT::value_type,
189 _TVT::_S_full_size>>);
190 if (!__builtin_is_constant_evaluated())
191 {
192 if constexpr (sizeof(_TI) == 32)
193 {
194 if constexpr (_TVT::template _S_is<float>)
195 return _mm256_testz_ps(__to_intrin(__a), __to_intrin(__b));
196 else if constexpr (_TVT::template _S_is<double>)
197 return _mm256_testz_pd(__to_intrin(__a), __to_intrin(__b));
198 else
199 return _mm256_testz_si256(__to_intrin(__a), __to_intrin(__b));
200 }
201 else if constexpr (_TVT::template _S_is<float> && __have_avx)
202 return _mm_testz_ps(__to_intrin(__a), __to_intrin(__b));
203 else if constexpr (_TVT::template _S_is<double> && __have_avx)
204 return _mm_testz_pd(__to_intrin(__a), __to_intrin(__b));
205 else if constexpr (__have_sse4_1)
206 return _mm_testz_si128(__intrin_bitcast<__m128i>(__to_intrin(__a)),
207 __intrin_bitcast<__m128i>(__to_intrin(__b)));
208 else
209 return __movemask(0 == __and(__a, __b)) != 0;
210 }
211 else
212 return __is_zero(__and(__a, __b));
213 }
214
215// }}}
216// __testc{{{
217// requires SSE4.1 or above
218template <typename _TI, typename _TVT = _VectorTraits<_TI>>
219 _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST constexpr int
220 __testc(_TI __a, _TI __b)
221 {
222 static_assert(is_same_v<_TI, __intrinsic_type_t<typename _TVT::value_type,
223 _TVT::_S_full_size>>);
224 if (__builtin_is_constant_evaluated())
225 return __is_zero(__andnot(__a, __b));
226
227 if constexpr (sizeof(_TI) == 32)
228 {
229 if constexpr (_TVT::template _S_is<float>)
230 return _mm256_testc_ps(__a, __b);
231 else if constexpr (_TVT::template _S_is<double>)
232 return _mm256_testc_pd(__a, __b);
233 else
234 return _mm256_testc_si256(__to_intrin(__a), __to_intrin(__b));
235 }
236 else if constexpr (_TVT::template _S_is<float> && __have_avx)
237 return _mm_testc_ps(__to_intrin(__a), __to_intrin(__b));
238 else if constexpr (_TVT::template _S_is<double> && __have_avx)
239 return _mm_testc_pd(__to_intrin(__a), __to_intrin(__b));
240 else
241 {
242 static_assert(is_same_v<_TI, _TI> && __have_sse4_1);
243 return _mm_testc_si128(__intrin_bitcast<__m128i>(__to_intrin(__a)),
244 __intrin_bitcast<__m128i>(__to_intrin(__b)));
245 }
246 }
247
248// }}}
249// __testnzc{{{
250template <typename _TI, typename _TVT = _VectorTraits<_TI>>
251 _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST constexpr int
252 __testnzc(_TI __a, _TI __b)
253 {
254 static_assert(is_same_v<_TI, __intrinsic_type_t<typename _TVT::value_type,
255 _TVT::_S_full_size>>);
256 if (!__builtin_is_constant_evaluated())
257 {
258 if constexpr (sizeof(_TI) == 32)
259 {
260 if constexpr (_TVT::template _S_is<float>)
261 return _mm256_testnzc_ps(__a, __b);
262 else if constexpr (_TVT::template _S_is<double>)
263 return _mm256_testnzc_pd(__a, __b);
264 else
265 return _mm256_testnzc_si256(__to_intrin(__a), __to_intrin(__b));
266 }
267 else if constexpr (_TVT::template _S_is<float> && __have_avx)
268 return _mm_testnzc_ps(__to_intrin(__a), __to_intrin(__b));
269 else if constexpr (_TVT::template _S_is<double> && __have_avx)
270 return _mm_testnzc_pd(__to_intrin(__a), __to_intrin(__b));
271 else if constexpr (__have_sse4_1)
272 return _mm_testnzc_si128(__intrin_bitcast<__m128i>(__to_intrin(__a)),
273 __intrin_bitcast<__m128i>(__to_intrin(__b)));
274 else
275 return __movemask(0 == __and(__a, __b)) == 0
276 && __movemask(0 == __andnot(__a, __b)) == 0;
277 }
278 else
279 return !(__is_zero(__and(__a, __b)) || __is_zero(__andnot(__a, __b)));
280 }
281
282// }}}
283// __xzyw{{{
284// shuffles the complete vector, swapping the inner two quarters. Often useful
285// for AVX for fixing up a shuffle result.
286template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
287 _GLIBCXX_SIMD_INTRINSIC _Tp
288 __xzyw(_Tp __a)
289 {
290 if constexpr (sizeof(_Tp) == 16)
291 {
292 const auto __x = __vector_bitcast<conditional_t<
293 is_floating_point_v<typename _TVT::value_type>, float, int>>(__a);
294 return reinterpret_cast<_Tp>(
295 decltype(__x){__x[0], __x[2], __x[1], __x[3]});
296 }
297 else if constexpr (sizeof(_Tp) == 32)
298 {
299 const auto __x = __vector_bitcast<conditional_t<
300 is_floating_point_v<typename _TVT::value_type>, double, _LLong>>(__a);
301 return reinterpret_cast<_Tp>(
302 decltype(__x){__x[0], __x[2], __x[1], __x[3]});
303 }
304 else if constexpr (sizeof(_Tp) == 64)
305 {
306 const auto __x = __vector_bitcast<conditional_t<
307 is_floating_point_v<typename _TVT::value_type>, double, _LLong>>(__a);
308 return reinterpret_cast<_Tp>(decltype(__x){__x[0], __x[1], __x[4],
309 __x[5], __x[2], __x[3],
310 __x[6], __x[7]});
311 }
312 else
313 __assert_unreachable<_Tp>();
314 }
315
316// }}}
317// __maskload_epi32{{{
318template <typename _Tp>
319 _GLIBCXX_SIMD_INTRINSIC auto
320 __maskload_epi32(const int* __ptr, _Tp __k)
321 {
322 if constexpr (sizeof(__k) == 16)
323 return _mm_maskload_epi32(__ptr, __k);
324 else
325 return _mm256_maskload_epi32(__ptr, __k);
326 }
327
328// }}}
329// __maskload_epi64{{{
330template <typename _Tp>
331 _GLIBCXX_SIMD_INTRINSIC auto
332 __maskload_epi64(const _LLong* __ptr, _Tp __k)
333 {
334 if constexpr (sizeof(__k) == 16)
335 return _mm_maskload_epi64(__ptr, __k);
336 else
337 return _mm256_maskload_epi64(__ptr, __k);
338 }
339
340// }}}
341// __maskload_ps{{{
342template <typename _Tp>
343 _GLIBCXX_SIMD_INTRINSIC auto
344 __maskload_ps(const float* __ptr, _Tp __k)
345 {
346 if constexpr (sizeof(__k) == 16)
347 return _mm_maskload_ps(__ptr, __k);
348 else
349 return _mm256_maskload_ps(__ptr, __k);
350 }
351
352// }}}
353// __maskload_pd{{{
354template <typename _Tp>
355 _GLIBCXX_SIMD_INTRINSIC auto
356 __maskload_pd(const double* __ptr, _Tp __k)
357 {
358 if constexpr (sizeof(__k) == 16)
359 return _mm_maskload_pd(__ptr, __k);
360 else
361 return _mm256_maskload_pd(__ptr, __k);
362 }
363
364// }}}
365
366#ifdef __clang__
367template <size_t _Np, typename _Tp, typename _Kp>
368 _GLIBCXX_SIMD_INTRINSIC constexpr auto
369 __movm(_Kp __k) noexcept
370 {
371 static_assert(is_unsigned_v<_Kp>);
372 if constexpr (sizeof(_Tp) == 1 && __have_avx512bw)
373 {
374 if constexpr (_Np <= 16 && __have_avx512vl)
375 return __builtin_ia32_cvtmask2b128(__k);
376 else if constexpr (_Np <= 32 && __have_avx512vl)
377 return __builtin_ia32_cvtmask2b256(__k);
378 else
379 return __builtin_ia32_cvtmask2b512(__k);
380 }
381 else if constexpr (sizeof(_Tp) == 2 && __have_avx512bw)
382 {
383 if constexpr (_Np <= 8 && __have_avx512vl)
384 return __builtin_ia32_cvtmask2w128(__k);
385 else if constexpr (_Np <= 16 && __have_avx512vl)
386 return __builtin_ia32_cvtmask2w256(__k);
387 else
388 return __builtin_ia32_cvtmask2w512(__k);
389 }
390 else if constexpr (sizeof(_Tp) == 4 && __have_avx512dq)
391 {
392 if constexpr (_Np <= 4 && __have_avx512vl)
393 return __builtin_ia32_cvtmask2d128(__k);
394 else if constexpr (_Np <= 8 && __have_avx512vl)
395 return __builtin_ia32_cvtmask2d256(__k);
396 else
397 return __builtin_ia32_cvtmask2d512(__k);
398 }
399 else if constexpr (sizeof(_Tp) == 8 && __have_avx512dq)
400 {
401 if constexpr (_Np <= 2 && __have_avx512vl)
402 return __builtin_ia32_cvtmask2q128(__k);
403 else if constexpr (_Np <= 4 && __have_avx512vl)
404 return __builtin_ia32_cvtmask2q256(__k);
405 else
406 return __builtin_ia32_cvtmask2q512(__k);
407 }
408 else
409 __assert_unreachable<_Tp>();
410 }
411#endif // __clang__
412
413#ifdef _GLIBCXX_SIMD_WORKAROUND_PR85048
414#include "simd_x86_conversions.h"
415#endif
416
417// ISA & type detection {{{
418template <typename _Tp, size_t _Np>
419 constexpr bool
420 __is_sse_ps()
421 {
422 return __have_sse
423 && is_same_v<_Tp,
424 float> && sizeof(__intrinsic_type_t<_Tp, _Np>) == 16;
425 }
426
427template <typename _Tp, size_t _Np>
428 constexpr bool
429 __is_sse_pd()
430 {
431 return __have_sse2
432 && is_same_v<_Tp,
433 double> && sizeof(__intrinsic_type_t<_Tp, _Np>) == 16;
434 }
435
436template <typename _Tp, size_t _Np>
437 constexpr bool
438 __is_avx_ps()
439 {
440 return __have_avx
441 && is_same_v<_Tp,
442 float> && sizeof(__intrinsic_type_t<_Tp, _Np>) == 32;
443 }
444
445template <typename _Tp, size_t _Np>
446 constexpr bool
447 __is_avx_pd()
448 {
449 return __have_avx
450 && is_same_v<_Tp,
451 double> && sizeof(__intrinsic_type_t<_Tp, _Np>) == 32;
452 }
453
454template <typename _Tp, size_t _Np>
455 constexpr bool
456 __is_avx512_ps()
457 {
458 return __have_avx512f
459 && is_same_v<_Tp,
460 float> && sizeof(__intrinsic_type_t<_Tp, _Np>) == 64;
461 }
462
463template <typename _Tp, size_t _Np>
464 constexpr bool
465 __is_avx512_pd()
466 {
467 return __have_avx512f
468 && is_same_v<_Tp,
469 double> && sizeof(__intrinsic_type_t<_Tp, _Np>) == 64;
470 }
471
472// }}}
473struct _MaskImplX86Mixin;
474
475// _CommonImplX86 {{{
476struct _CommonImplX86 : _CommonImplBuiltin
477{
478#ifdef _GLIBCXX_SIMD_WORKAROUND_PR85048
479 // _S_converts_via_decomposition {{{
480 template <typename _From, typename _To, size_t _ToSize>
481 static constexpr bool
482 _S_converts_via_decomposition()
483 {
484 if constexpr (is_integral_v<
485 _From> && is_integral_v<_To> && sizeof(_From) == 8
486 && _ToSize == 16)
487 return (sizeof(_To) == 2 && !__have_ssse3)
488 || (sizeof(_To) == 1 && !__have_avx512f);
489 else if constexpr (is_floating_point_v<_From> && is_integral_v<_To>)
490 return ((sizeof(_From) == 4 || sizeof(_From) == 8) && sizeof(_To) == 8
491 && !__have_avx512dq)
492 || (sizeof(_From) == 8 && sizeof(_To) == 4 && !__have_sse4_1
493 && _ToSize == 16);
494 else if constexpr (
495 is_integral_v<_From> && is_floating_point_v<_To> && sizeof(_From) == 8
496 && !__have_avx512dq)
497 return (sizeof(_To) == 4 && _ToSize == 16)
498 || (sizeof(_To) == 8 && _ToSize < 64);
499 else
500 return false;
501 }
502
503 template <typename _From, typename _To, size_t _ToSize>
504 static inline constexpr bool __converts_via_decomposition_v
505 = _S_converts_via_decomposition<_From, _To, _ToSize>();
506
507 // }}}
508#endif
509 // _S_store {{{
510 using _CommonImplBuiltin::_S_store;
511
512 template <typename _Tp, size_t _Np>
513 _GLIBCXX_SIMD_INTRINSIC static constexpr void
514 _S_store(_SimdWrapper<_Tp, _Np> __x, void* __addr)
515 {
516 constexpr size_t _Bytes = _Np * sizeof(_Tp);
517
518 if (__builtin_is_constant_evaluated())
519 _CommonImplBuiltin::_S_store(__x, __addr);
520 else if constexpr ((_Bytes & (_Bytes - 1)) != 0 && __have_avx512bw_vl)
521 {
522 const auto __v = __to_intrin(__x);
523
524 if constexpr (_Bytes & 1)
525 {
526 if constexpr (_Bytes < 16)
527 _mm_mask_storeu_epi8(__addr, 0xffffu >> (16 - _Bytes),
528 __intrin_bitcast<__m128i>(__v));
529 else if constexpr (_Bytes < 32)
530 _mm256_mask_storeu_epi8(__addr, 0xffffffffu >> (32 - _Bytes),
531 __intrin_bitcast<__m256i>(__v));
532 else
533 _mm512_mask_storeu_epi8(__addr,
534 0xffffffffffffffffull >> (64 - _Bytes),
535 __intrin_bitcast<__m512i>(__v));
536 }
537 else if constexpr (_Bytes & 2)
538 {
539 if constexpr (_Bytes < 16)
540 _mm_mask_storeu_epi16(__addr, 0xffu >> (8 - _Bytes / 2),
541 __intrin_bitcast<__m128i>(__v));
542 else if constexpr (_Bytes < 32)
543 _mm256_mask_storeu_epi16(__addr, 0xffffu >> (16 - _Bytes / 2),
544 __intrin_bitcast<__m256i>(__v));
545 else
546 _mm512_mask_storeu_epi16(__addr,
547 0xffffffffull >> (32 - _Bytes / 2),
548 __intrin_bitcast<__m512i>(__v));
549 }
550 else if constexpr (_Bytes & 4)
551 {
552 if constexpr (_Bytes < 16)
553 _mm_mask_storeu_epi32(__addr, 0xfu >> (4 - _Bytes / 4),
554 __intrin_bitcast<__m128i>(__v));
555 else if constexpr (_Bytes < 32)
556 _mm256_mask_storeu_epi32(__addr, 0xffu >> (8 - _Bytes / 4),
557 __intrin_bitcast<__m256i>(__v));
558 else
559 _mm512_mask_storeu_epi32(__addr, 0xffffull >> (16 - _Bytes / 4),
560 __intrin_bitcast<__m512i>(__v));
561 }
562 else
563 {
564 static_assert(
565 _Bytes > 16,
566 "_Bytes < 16 && (_Bytes & 7) == 0 && (_Bytes & (_Bytes "
567 "- 1)) != 0 is impossible");
568 if constexpr (_Bytes < 32)
569 _mm256_mask_storeu_epi64(__addr, 0xfu >> (4 - _Bytes / 8),
570 __intrin_bitcast<__m256i>(__v));
571 else
572 _mm512_mask_storeu_epi64(__addr, 0xffull >> (8 - _Bytes / 8),
573 __intrin_bitcast<__m512i>(__v));
574 }
575 }
576 else
577 _CommonImplBuiltin::_S_store(__x, __addr);
578 }
579
580 // }}}
581 // _S_store_bool_array(_BitMask) {{{
582 template <size_t _Np, bool _Sanitized>
583 _GLIBCXX_SIMD_INTRINSIC static constexpr void
584 _S_store_bool_array(const _BitMask<_Np, _Sanitized> __x, bool* __mem)
585 {
586 if (__builtin_is_constant_evaluated())
587 _CommonImplBuiltin::_S_store_bool_array(__x, __mem);
588 else if constexpr (__have_avx512bw_vl) // don't care for BW w/o VL
589 _S_store<_Np>(1 & __vector_bitcast<_UChar, _Np>(
590 [=]() constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
591 if constexpr (_Np <= 16)
592 return _mm_movm_epi8(__x._M_to_bits());
593 else if constexpr (_Np <= 32)
594 return _mm256_movm_epi8(__x._M_to_bits());
595 else if constexpr (_Np <= 64)
596 return _mm512_movm_epi8(__x._M_to_bits());
597 else
598 __assert_unreachable<_SizeConstant<_Np>>();
599 }()),
600 __mem);
601 else if constexpr (__have_bmi2)
602 {
603 if constexpr (_Np <= 4)
604 _S_store<_Np>(_pdep_u32(__x._M_to_bits(), 0x01010101U), __mem);
605 else
606 __execute_n_times<__div_roundup(_Np, sizeof(size_t))>(
607 [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
608 constexpr size_t __offset = __i * sizeof(size_t);
609 constexpr int __todo = std::min(sizeof(size_t), _Np - __offset);
610 if constexpr (__todo == 1)
611 __mem[__offset] = __x[__offset];
612 else
613 {
614 const auto __bools =
615#ifdef __x86_64__
616 _pdep_u64(__x.template _M_extract<__offset>().to_ullong(),
617 0x0101010101010101ULL);
618#else // __x86_64__
619 _pdep_u32(
620 __x.template _M_extract<__offset>()._M_to_bits(),
621 0x01010101U);
622#endif // __x86_64__
623 _S_store<__todo>(__bools, __mem + __offset);
624 }
625 });
626 }
627 else if constexpr (__have_sse2 && _Np > 7)
628 __execute_n_times<__div_roundup(_Np, 16)>([&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
629 constexpr int __offset = __i * 16;
630 constexpr int __todo = std::min(16, int(_Np) - __offset);
631 const int __bits = __x.template _M_extract<__offset>()._M_to_bits();
632 __vector_type16_t<_UChar> __bools;
633 if constexpr (__have_avx512f)
634 {
635 auto __as32bits
636 = _mm512_maskz_mov_epi32(__bits, __to_intrin(
637 __vector_broadcast<16>(1)));
638 auto __as16bits
639 = __xzyw(_mm256_packs_epi32(__lo256(__as32bits),
640 __todo > 8 ? __hi256(__as32bits)
641 : __m256i()));
642 __bools = __vector_bitcast<_UChar>(
643 _mm_packs_epi16(__lo128(__as16bits), __hi128(__as16bits)));
644 }
645 else
646 {
647 using _V = __vector_type_t<_UChar, 16>;
648 auto __tmp = _mm_cvtsi32_si128(__bits);
649 __tmp = _mm_unpacklo_epi8(__tmp, __tmp);
650 __tmp = _mm_unpacklo_epi16(__tmp, __tmp);
651 __tmp = _mm_unpacklo_epi32(__tmp, __tmp);
652 _V __tmp2 = reinterpret_cast<_V>(__tmp);
653 __tmp2 &= _V{1, 2, 4, 8, 16, 32, 64, 128,
654 1, 2, 4, 8, 16, 32, 64, 128}; // mask bit index
655 __bools = (__tmp2 == 0) + 1; // 0xff -> 0x00 | 0x00 -> 0x01
656 }
657 _S_store<__todo>(__bools, __mem + __offset);
658 });
659 else
660 _CommonImplBuiltin::_S_store_bool_array(__x, __mem);
661 }
662
663 // }}}
664 // _S_blend_avx512 {{{
665 // Returns: __k ? __b : __a
666 // TODO: reverse __a and __b to match COND_EXPR
667 // Requires: _TV to be a __vector_type_t matching valuetype for the bitmask
668 // __k
669 template <typename _Kp, typename _TV>
670 _GLIBCXX_SIMD_INTRINSIC static _TV
671 _S_blend_avx512(const _Kp __k, const _TV __a, const _TV __b) noexcept
672 {
673 static_assert(__is_vector_type_v<_TV>);
674 using _Tp = typename _VectorTraits<_TV>::value_type;
675 static_assert(sizeof(_TV) >= 16);
676 static_assert(sizeof(_Tp) <= 8);
677#ifdef __clang__
678 return __movm<_VectorTraits<_TV>::_S_full_size, _Tp>(__k) ? __b : __a;
679#else
680 using _IntT
681 = conditional_t<(sizeof(_Tp) > 2),
682 conditional_t<sizeof(_Tp) == 4, int, long long>,
683 conditional_t<sizeof(_Tp) == 1, char, short>>;
684 [[maybe_unused]] const auto __aa = __vector_bitcast<_IntT>(__a);
685 [[maybe_unused]] const auto __bb = __vector_bitcast<_IntT>(__b);
686 if constexpr (sizeof(_TV) == 64)
687 {
688 if constexpr (sizeof(_Tp) == 1)
689 return reinterpret_cast<_TV>(
690 __builtin_ia32_blendmb_512_mask(__aa, __bb, __k));
691 else if constexpr (sizeof(_Tp) == 2)
692 return reinterpret_cast<_TV>(
693 __builtin_ia32_blendmw_512_mask(__aa, __bb, __k));
694 else if constexpr (sizeof(_Tp) == 4 && is_floating_point_v<_Tp>)
695 return __builtin_ia32_blendmps_512_mask(__a, __b, __k);
696 else if constexpr (sizeof(_Tp) == 4)
697 return reinterpret_cast<_TV>(
698 __builtin_ia32_blendmd_512_mask(__aa, __bb, __k));
699 else if constexpr (sizeof(_Tp) == 8 && is_floating_point_v<_Tp>)
700 return __builtin_ia32_blendmpd_512_mask(__a, __b, __k);
701 else if constexpr (sizeof(_Tp) == 8)
702 return reinterpret_cast<_TV>(
703 __builtin_ia32_blendmq_512_mask(__aa, __bb, __k));
704 }
705 else if constexpr (sizeof(_TV) == 32)
706 {
707 if constexpr (sizeof(_Tp) == 1)
708 return reinterpret_cast<_TV>(
709 __builtin_ia32_blendmb_256_mask(__aa, __bb, __k));
710 else if constexpr (sizeof(_Tp) == 2)
711 return reinterpret_cast<_TV>(
712 __builtin_ia32_blendmw_256_mask(__aa, __bb, __k));
713 else if constexpr (sizeof(_Tp) == 4 && is_floating_point_v<_Tp>)
714 return __builtin_ia32_blendmps_256_mask(__a, __b, __k);
715 else if constexpr (sizeof(_Tp) == 4)
716 return reinterpret_cast<_TV>(
717 __builtin_ia32_blendmd_256_mask(__aa, __bb, __k));
718 else if constexpr (sizeof(_Tp) == 8 && is_floating_point_v<_Tp>)
719 return __builtin_ia32_blendmpd_256_mask(__a, __b, __k);
720 else if constexpr (sizeof(_Tp) == 8)
721 return reinterpret_cast<_TV>(
722 __builtin_ia32_blendmq_256_mask(__aa, __bb, __k));
723 }
724 else if constexpr (sizeof(_TV) == 16)
725 {
726 if constexpr (sizeof(_Tp) == 1)
727 return reinterpret_cast<_TV>(
728 __builtin_ia32_blendmb_128_mask(__aa, __bb, __k));
729 else if constexpr (sizeof(_Tp) == 2)
730 return reinterpret_cast<_TV>(
731 __builtin_ia32_blendmw_128_mask(__aa, __bb, __k));
732 else if constexpr (sizeof(_Tp) == 4 && is_floating_point_v<_Tp>)
733 return __builtin_ia32_blendmps_128_mask(__a, __b, __k);
734 else if constexpr (sizeof(_Tp) == 4)
735 return reinterpret_cast<_TV>(
736 __builtin_ia32_blendmd_128_mask(__aa, __bb, __k));
737 else if constexpr (sizeof(_Tp) == 8 && is_floating_point_v<_Tp>)
738 return __builtin_ia32_blendmpd_128_mask(__a, __b, __k);
739 else if constexpr (sizeof(_Tp) == 8)
740 return reinterpret_cast<_TV>(
741 __builtin_ia32_blendmq_128_mask(__aa, __bb, __k));
742 }
743#endif
744 }
745
746 // }}}
747 // _S_blend_intrin {{{
748 // Returns: __k ? __b : __a
749 // TODO: reverse __a and __b to match COND_EXPR
750 // Requires: _Tp to be an intrinsic type (integers blend per byte) and 16/32
751 // Bytes wide
752 template <typename _Tp>
753 _GLIBCXX_SIMD_INTRINSIC static _Tp
754 _S_blend_intrin(_Tp __k, _Tp __a, _Tp __b) noexcept
755 {
756 static_assert(is_same_v<decltype(__to_intrin(__a)), _Tp>);
757 constexpr struct
758 {
759 _GLIBCXX_SIMD_INTRINSIC __m128 operator()(__m128 __a, __m128 __b,
760 __m128 __k) const noexcept
761 {
762 return __builtin_ia32_blendvps(__a, __b, __k);
763 }
764 _GLIBCXX_SIMD_INTRINSIC __m128d operator()(__m128d __a, __m128d __b,
765 __m128d __k) const noexcept
766 {
767 return __builtin_ia32_blendvpd(__a, __b, __k);
768 }
769 _GLIBCXX_SIMD_INTRINSIC __m128i operator()(__m128i __a, __m128i __b,
770 __m128i __k) const noexcept
771 {
772 return reinterpret_cast<__m128i>(
773 __builtin_ia32_pblendvb128(reinterpret_cast<__v16qi>(__a),
774 reinterpret_cast<__v16qi>(__b),
775 reinterpret_cast<__v16qi>(__k)));
776 }
777 _GLIBCXX_SIMD_INTRINSIC __m256 operator()(__m256 __a, __m256 __b,
778 __m256 __k) const noexcept
779 {
780 return __builtin_ia32_blendvps256(__a, __b, __k);
781 }
782 _GLIBCXX_SIMD_INTRINSIC __m256d operator()(__m256d __a, __m256d __b,
783 __m256d __k) const noexcept
784 {
785 return __builtin_ia32_blendvpd256(__a, __b, __k);
786 }
787 _GLIBCXX_SIMD_INTRINSIC __m256i operator()(__m256i __a, __m256i __b,
788 __m256i __k) const noexcept
789 {
790 if constexpr (__have_avx2)
791 return reinterpret_cast<__m256i>(
792 __builtin_ia32_pblendvb256(reinterpret_cast<__v32qi>(__a),
793 reinterpret_cast<__v32qi>(__b),
794 reinterpret_cast<__v32qi>(__k)));
795 else
796 return reinterpret_cast<__m256i>(
797 __builtin_ia32_blendvps256(reinterpret_cast<__v8sf>(__a),
798 reinterpret_cast<__v8sf>(__b),
799 reinterpret_cast<__v8sf>(__k)));
800 }
801 } __eval;
802 return __eval(__a, __b, __k);
803 }
804
805 // }}}
806 // _S_blend {{{
807 // Returns: __k ? __at1 : __at0
808 // TODO: reverse __at0 and __at1 to match COND_EXPR
809 template <typename _Tp, size_t _Np>
810 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
811 _S_blend(_SimdWrapper<bool, _Np> __k, _SimdWrapper<_Tp, _Np> __at0,
812 _SimdWrapper<_Tp, _Np> __at1)
813 {
814 static_assert(is_same_v<_Tp, _Tp> && __have_avx512f);
815 if (__k._M_is_constprop() && __at0._M_is_constprop()
816 && __at1._M_is_constprop())
817 return __generate_from_n_evaluations<_Np, __vector_type_t<_Tp, _Np>>(
818 [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
819 return __k[__i] ? __at1[__i] : __at0[__i];
820 });
821 else if constexpr (sizeof(__at0) == 64
822 || (__have_avx512vl && sizeof(__at0) >= 16))
823 return _S_blend_avx512(__k._M_data, __at0._M_data, __at1._M_data);
824 else
825 {
826 static_assert((__have_avx512vl && sizeof(__at0) < 16)
827 || !__have_avx512vl);
828 constexpr size_t __size = (__have_avx512vl ? 16 : 64) / sizeof(_Tp);
829 return __vector_bitcast<_Tp, _Np>(
830 _S_blend_avx512(__k._M_data, __vector_bitcast<_Tp, __size>(__at0),
831 __vector_bitcast<_Tp, __size>(__at1)));
832 }
833 }
834
835 template <typename _Tp, size_t _Np>
836 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
837 _S_blend(_SimdWrapper<__int_for_sizeof_t<_Tp>, _Np> __k,
838 _SimdWrapper<_Tp, _Np> __at0, _SimdWrapper<_Tp, _Np> __at1)
839 {
840 const auto __kk = __wrapper_bitcast<_Tp>(__k);
841 if (__builtin_is_constant_evaluated()
842 || (__kk._M_is_constprop() && __at0._M_is_constprop()
843 && __at1._M_is_constprop()))
844 {
845 auto __r = __or(__andnot(__kk, __at0), __and(__kk, __at1));
846 if (__r._M_is_constprop())
847 return __r;
848 }
849 if constexpr (((__have_avx512f && sizeof(__at0) == 64) || __have_avx512vl)
850 && (sizeof(_Tp) >= 4 || __have_avx512bw))
851 // convert to bitmask and call overload above
852 return _S_blend(
853 _SimdWrapper<bool, _Np>(
854 __make_dependent_t<_Tp, _MaskImplX86Mixin>::_S_to_bits(__k)
855 ._M_to_bits()),
856 __at0, __at1);
857 else
858 {
859 // Since GCC does not assume __k to be a mask, using the builtin
860 // conditional operator introduces an extra compare against 0 before
861 // blending. So we rather call the intrinsic here.
862 if constexpr (__have_sse4_1)
863 return _S_blend_intrin(__to_intrin(__kk), __to_intrin(__at0),
864 __to_intrin(__at1));
865 else
866 return __or(__andnot(__kk, __at0), __and(__kk, __at1));
867 }
868 }
869
870 // }}}
871};
872
873// }}}
874// _SimdImplX86 {{{
875template <typename _Abi, typename>
876 struct _SimdImplX86 : _SimdImplBuiltin<_Abi>
877 {
878 using _Base = _SimdImplBuiltin<_Abi>;
879
880 template <typename _Tp>
881 using _MaskMember = typename _Base::template _MaskMember<_Tp>;
882
883 template <typename _Tp>
884 static constexpr size_t _S_full_size = _Abi::template _S_full_size<_Tp>;
885
886 template <typename _Tp>
887 static constexpr size_t _S_size = _Abi::template _S_size<_Tp>;
888
889 template <typename _Tp>
890 static constexpr size_t _S_max_store_size
891 = (sizeof(_Tp) >= 4 && __have_avx512f) || __have_avx512bw ? 64
892 : (is_floating_point_v<_Tp>&& __have_avx) || __have_avx2 ? 32
893 : 16;
894
895 using _MaskImpl = typename _Abi::_MaskImpl;
896
897 // _S_masked_load {{{
898 template <typename _Tp, size_t _Np, typename _Up>
899 static inline _SimdWrapper<_Tp, _Np>
900 _S_masked_load(_SimdWrapper<_Tp, _Np> __merge, _MaskMember<_Tp> __k,
901 const _Up* __mem) noexcept
902 {
903 static_assert(_Np == _S_size<_Tp>);
904 if constexpr (is_same_v<_Tp, _Up> || // no conversion
905 (sizeof(_Tp) == sizeof(_Up)
906 && is_integral_v<
907 _Tp> == is_integral_v<_Up>) // conversion via bit
908 // reinterpretation
909 )
910 {
911 [[maybe_unused]] const auto __intrin = __to_intrin(__merge);
912 if constexpr ((__is_avx512_abi<_Abi>() || __have_avx512bw_vl)
913 && sizeof(_Tp) == 1)
914 {
915 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
916 if constexpr (sizeof(__intrin) == 16)
917 __merge = __vector_bitcast<_Tp, _Np>(
918 _mm_mask_loadu_epi8(__intrin, __kk, __mem));
919 else if constexpr (sizeof(__merge) == 32)
920 __merge = __vector_bitcast<_Tp, _Np>(
921 _mm256_mask_loadu_epi8(__intrin, __kk, __mem));
922 else if constexpr (sizeof(__merge) == 64)
923 __merge = __vector_bitcast<_Tp, _Np>(
924 _mm512_mask_loadu_epi8(__intrin, __kk, __mem));
925 else
926 __assert_unreachable<_Tp>();
927 }
928 else if constexpr ((__is_avx512_abi<_Abi>() || __have_avx512bw_vl)
929 && sizeof(_Tp) == 2)
930 {
931 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
932 if constexpr (sizeof(__intrin) == 16)
933 __merge = __vector_bitcast<_Tp, _Np>(
934 _mm_mask_loadu_epi16(__intrin, __kk, __mem));
935 else if constexpr (sizeof(__intrin) == 32)
936 __merge = __vector_bitcast<_Tp, _Np>(
937 _mm256_mask_loadu_epi16(__intrin, __kk, __mem));
938 else if constexpr (sizeof(__intrin) == 64)
939 __merge = __vector_bitcast<_Tp, _Np>(
940 _mm512_mask_loadu_epi16(__intrin, __kk, __mem));
941 else
942 __assert_unreachable<_Tp>();
943 }
944 else if constexpr ((__is_avx512_abi<_Abi>() || __have_avx512vl)
945 && sizeof(_Tp) == 4 && is_integral_v<_Up>)
946 {
947 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
948 if constexpr (sizeof(__intrin) == 16)
949 __merge = __vector_bitcast<_Tp, _Np>(
950 _mm_mask_loadu_epi32(__intrin, __kk, __mem));
951 else if constexpr (sizeof(__intrin) == 32)
952 __merge = __vector_bitcast<_Tp, _Np>(
953 _mm256_mask_loadu_epi32(__intrin, __kk, __mem));
954 else if constexpr (sizeof(__intrin) == 64)
955 __merge = __vector_bitcast<_Tp, _Np>(
956 _mm512_mask_loadu_epi32(__intrin, __kk, __mem));
957 else
958 __assert_unreachable<_Tp>();
959 }
960 else if constexpr ((__is_avx512_abi<_Abi>() || __have_avx512vl)
961 && sizeof(_Tp) == 4 && is_floating_point_v<_Up>)
962 {
963 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
964 if constexpr (sizeof(__intrin) == 16)
965 __merge = __vector_bitcast<_Tp, _Np>(
966 _mm_mask_loadu_ps(__intrin, __kk, __mem));
967 else if constexpr (sizeof(__intrin) == 32)
968 __merge = __vector_bitcast<_Tp, _Np>(
969 _mm256_mask_loadu_ps(__intrin, __kk, __mem));
970 else if constexpr (sizeof(__intrin) == 64)
971 __merge = __vector_bitcast<_Tp, _Np>(
972 _mm512_mask_loadu_ps(__intrin, __kk, __mem));
973 else
974 __assert_unreachable<_Tp>();
975 }
976 else if constexpr (__have_avx2 && sizeof(_Tp) == 4
977 && is_integral_v<_Up>)
978 {
979 static_assert(sizeof(__intrin) == 16 || sizeof(__intrin) == 32);
980 __merge
981 = __or(__andnot(__vector_bitcast<_Tp>(__k), __merge._M_data),
982 __vector_bitcast<_Tp, _Np>(
983 __maskload_epi32(reinterpret_cast<const int*>(__mem),
984 __to_intrin(__k))));
985 }
986 else if constexpr (__have_avx && sizeof(_Tp) == 4)
987 {
988 static_assert(sizeof(__intrin) == 16 || sizeof(__intrin) == 32);
989 __merge
990 = __or(__andnot(__vector_bitcast<_Tp>(__k), __merge._M_data),
991 __vector_bitcast<_Tp, _Np>(
992 __maskload_ps(reinterpret_cast<const float*>(__mem),
993 __to_intrin(__k))));
994 }
995 else if constexpr ((__is_avx512_abi<_Abi>() || __have_avx512vl)
996 && sizeof(_Tp) == 8 && is_integral_v<_Up>)
997 {
998 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
999 if constexpr (sizeof(__intrin) == 16)
1000 __merge = __vector_bitcast<_Tp, _Np>(
1001 _mm_mask_loadu_epi64(__intrin, __kk, __mem));
1002 else if constexpr (sizeof(__intrin) == 32)
1003 __merge = __vector_bitcast<_Tp, _Np>(
1004 _mm256_mask_loadu_epi64(__intrin, __kk, __mem));
1005 else if constexpr (sizeof(__intrin) == 64)
1006 __merge = __vector_bitcast<_Tp, _Np>(
1007 _mm512_mask_loadu_epi64(__intrin, __kk, __mem));
1008 else
1009 __assert_unreachable<_Tp>();
1010 }
1011 else if constexpr ((__is_avx512_abi<_Abi>() || __have_avx512vl)
1012 && sizeof(_Tp) == 8 && is_floating_point_v<_Up>)
1013 {
1014 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
1015 if constexpr (sizeof(__intrin) == 16)
1016 __merge = __vector_bitcast<_Tp, _Np>(
1017 _mm_mask_loadu_pd(__intrin, __kk, __mem));
1018 else if constexpr (sizeof(__intrin) == 32)
1019 __merge = __vector_bitcast<_Tp, _Np>(
1020 _mm256_mask_loadu_pd(__intrin, __kk, __mem));
1021 else if constexpr (sizeof(__intrin) == 64)
1022 __merge = __vector_bitcast<_Tp, _Np>(
1023 _mm512_mask_loadu_pd(__intrin, __kk, __mem));
1024 else
1025 __assert_unreachable<_Tp>();
1026 }
1027 else if constexpr (__have_avx2 && sizeof(_Tp) == 8
1028 && is_integral_v<_Up>)
1029 {
1030 static_assert(sizeof(__intrin) == 16 || sizeof(__intrin) == 32);
1031 __merge
1032 = __or(__andnot(__vector_bitcast<_Tp>(__k), __merge._M_data),
1033 __vector_bitcast<_Tp, _Np>(__maskload_epi64(
1034 reinterpret_cast<const _LLong*>(__mem),
1035 __to_intrin(__k))));
1036 }
1037 else if constexpr (__have_avx && sizeof(_Tp) == 8)
1038 {
1039 static_assert(sizeof(__intrin) == 16 || sizeof(__intrin) == 32);
1040 __merge
1041 = __or(__andnot(__vector_bitcast<_Tp>(__k), __merge._M_data),
1042 __vector_bitcast<_Tp, _Np>(
1043 __maskload_pd(reinterpret_cast<const double*>(__mem),
1044 __to_intrin(__k))));
1045 }
1046 else
1047 _BitOps::_S_bit_iteration(_MaskImpl::_S_to_bits(__k),
1048 [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
1049 __merge._M_set(__i, static_cast<_Tp>(__mem[__i]));
1050 });
1051 }
1052 /* Very uncertain, that the following improves anything. Needs
1053 benchmarking
1054 * before it's activated.
1055 else if constexpr (sizeof(_Up) <= 8 && // no long double
1056 !__converts_via_decomposition_v<
1057 _Up, _Tp,
1058 sizeof(__merge)> // conversion via decomposition
1059 // is better handled via the
1060 // bit_iteration fallback below
1061 )
1062 {
1063 // TODO: copy pattern from _S_masked_store, which doesn't resort to
1064 // fixed_size
1065 using _Ap = simd_abi::deduce_t<_Up, _Np>;
1066 using _ATraits = _SimdTraits<_Up, _Ap>;
1067 using _AImpl = typename _ATraits::_SimdImpl;
1068 typename _ATraits::_SimdMember __uncvted{};
1069 typename _ATraits::_MaskMember __kk = _Ap::_MaskImpl::template
1070 _S_convert<_Up>(__k);
1071 __uncvted = _AImpl::_S_masked_load(__uncvted, __kk, __mem);
1072 _SimdConverter<_Up, _Ap, _Tp, _Abi> __converter;
1073 _Base::_S_masked_assign(__k, __merge, __converter(__uncvted));
1074 }
1075 */
1076 else
1077 __merge = _Base::_S_masked_load(__merge, __k, __mem);
1078 return __merge;
1079 }
1080
1081 // }}}
1082 // _S_masked_store_nocvt {{{
1083 template <typename _Tp, size_t _Np>
1084 _GLIBCXX_SIMD_INTRINSIC static void
1085 _S_masked_store_nocvt(_SimdWrapper<_Tp, _Np> __v, _Tp* __mem, _SimdWrapper<bool, _Np> __k)
1086 {
1087 [[maybe_unused]] const auto __vi = __to_intrin(__v);
1088 if constexpr (sizeof(__vi) == 64)
1089 {
1090 static_assert(sizeof(__v) == 64 && __have_avx512f);
1091 if constexpr (__have_avx512bw && sizeof(_Tp) == 1)
1092 _mm512_mask_storeu_epi8(__mem, __k, __vi);
1093 else if constexpr (__have_avx512bw && sizeof(_Tp) == 2)
1094 _mm512_mask_storeu_epi16(__mem, __k, __vi);
1095 else if constexpr (__have_avx512f && sizeof(_Tp) == 4)
1096 {
1097 if constexpr (is_integral_v<_Tp>)
1098 _mm512_mask_storeu_epi32(__mem, __k, __vi);
1099 else
1100 _mm512_mask_storeu_ps(__mem, __k, __vi);
1101 }
1102 else if constexpr (__have_avx512f && sizeof(_Tp) == 8)
1103 {
1104 if constexpr (is_integral_v<_Tp>)
1105 _mm512_mask_storeu_epi64(__mem, __k, __vi);
1106 else
1107 _mm512_mask_storeu_pd(__mem, __k, __vi);
1108 }
1109#if 0 // with KNL either sizeof(_Tp) >= 4 or sizeof(_vi) <= 32
1110 // with Skylake-AVX512, __have_avx512bw is true
1111 else if constexpr (__have_sse2)
1112 {
1113 using _M = __vector_type_t<_Tp, _Np>;
1114 using _MVT = _VectorTraits<_M>;
1115 _mm_maskmoveu_si128(__auto_bitcast(__extract<0, 4>(__v._M_data)),
1116 __auto_bitcast(_MaskImpl::template _S_convert<_Tp, _Np>(__k._M_data)),
1117 reinterpret_cast<char*>(__mem));
1118 _mm_maskmoveu_si128(__auto_bitcast(__extract<1, 4>(__v._M_data)),
1119 __auto_bitcast(_MaskImpl::template _S_convert<_Tp, _Np>(
1120 __k._M_data >> 1 * _MVT::_S_full_size)),
1121 reinterpret_cast<char*>(__mem) + 1 * 16);
1122 _mm_maskmoveu_si128(__auto_bitcast(__extract<2, 4>(__v._M_data)),
1123 __auto_bitcast(_MaskImpl::template _S_convert<_Tp, _Np>(
1124 __k._M_data >> 2 * _MVT::_S_full_size)),
1125 reinterpret_cast<char*>(__mem) + 2 * 16);
1126 if constexpr (_Np > 48 / sizeof(_Tp))
1127 _mm_maskmoveu_si128(
1128 __auto_bitcast(__extract<3, 4>(__v._M_data)),
1129 __auto_bitcast(_MaskImpl::template _S_convert<_Tp, _Np>(
1130 __k._M_data >> 3 * _MVT::_S_full_size)),
1131 reinterpret_cast<char*>(__mem) + 3 * 16);
1132 }
1133#endif
1134 else
1135 __assert_unreachable<_Tp>();
1136 }
1137 else if constexpr (sizeof(__vi) == 32)
1138 {
1139 if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 1)
1140 _mm256_mask_storeu_epi8(__mem, __k, __vi);
1141 else if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 2)
1142 _mm256_mask_storeu_epi16(__mem, __k, __vi);
1143 else if constexpr (__have_avx512vl && sizeof(_Tp) == 4)
1144 {
1145 if constexpr (is_integral_v<_Tp>)
1146 _mm256_mask_storeu_epi32(__mem, __k, __vi);
1147 else
1148 _mm256_mask_storeu_ps(__mem, __k, __vi);
1149 }
1150 else if constexpr (__have_avx512vl && sizeof(_Tp) == 8)
1151 {
1152 if constexpr (is_integral_v<_Tp>)
1153 _mm256_mask_storeu_epi64(__mem, __k, __vi);
1154 else
1155 _mm256_mask_storeu_pd(__mem, __k, __vi);
1156 }
1157 else if constexpr (__have_avx512f
1158 && (sizeof(_Tp) >= 4 || __have_avx512bw))
1159 {
1160 // use a 512-bit maskstore, using zero-extension of the bitmask
1161 _S_masked_store_nocvt(
1162 _SimdWrapper64<_Tp>(
1163 __intrin_bitcast<__vector_type64_t<_Tp>>(__v._M_data)),
1164 __mem, _SimdWrapper<bool, 64 / sizeof(_Tp)>(__k._M_data));
1165 }
1166 else
1167 _S_masked_store_nocvt(__v, __mem,
1168 _MaskImpl::template _S_to_maskvector<
1169 __int_for_sizeof_t<_Tp>, _Np>(__k));
1170 }
1171 else if constexpr (sizeof(__vi) == 16)
1172 {
1173 if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 1)
1174 _mm_mask_storeu_epi8(__mem, __k, __vi);
1175 else if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 2)
1176 _mm_mask_storeu_epi16(__mem, __k, __vi);
1177 else if constexpr (__have_avx512vl && sizeof(_Tp) == 4)
1178 {
1179 if constexpr (is_integral_v<_Tp>)
1180 _mm_mask_storeu_epi32(__mem, __k, __vi);
1181 else
1182 _mm_mask_storeu_ps(__mem, __k, __vi);
1183 }
1184 else if constexpr (__have_avx512vl && sizeof(_Tp) == 8)
1185 {
1186 if constexpr (is_integral_v<_Tp>)
1187 _mm_mask_storeu_epi64(__mem, __k, __vi);
1188 else
1189 _mm_mask_storeu_pd(__mem, __k, __vi);
1190 }
1191 else if constexpr (__have_avx512f
1192 && (sizeof(_Tp) >= 4 || __have_avx512bw))
1193 {
1194 // use a 512-bit maskstore, using zero-extension of the bitmask
1195 _S_masked_store_nocvt(
1196 _SimdWrapper64<_Tp>(
1197 __intrin_bitcast<__intrinsic_type64_t<_Tp>>(__v._M_data)),
1198 __mem, _SimdWrapper<bool, 64 / sizeof(_Tp)>(__k._M_data));
1199 }
1200 else
1201 _S_masked_store_nocvt(__v, __mem,
1202 _MaskImpl::template _S_to_maskvector<
1203 __int_for_sizeof_t<_Tp>, _Np>(__k));
1204 }
1205 else
1206 __assert_unreachable<_Tp>();
1207 }
1208
1209 template <typename _Tp, size_t _Np>
1210 _GLIBCXX_SIMD_INTRINSIC static void
1211 _S_masked_store_nocvt(_SimdWrapper<_Tp, _Np> __v, _Tp* __mem,
1212 _SimdWrapper<__int_for_sizeof_t<_Tp>, _Np> __k)
1213 {
1214 if constexpr (sizeof(__v) <= 16)
1215 {
1216 [[maybe_unused]] const auto __vi
1217 = __intrin_bitcast<__m128i>(__as_vector(__v));
1218 [[maybe_unused]] const auto __ki
1219 = __intrin_bitcast<__m128i>(__as_vector(__k));
1220 if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 1)
1221 _mm_mask_storeu_epi8(__mem, _mm_movepi8_mask(__ki), __vi);
1222 else if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 2)
1223 _mm_mask_storeu_epi16(__mem, _mm_movepi16_mask(__ki), __vi);
1224 else if constexpr (__have_avx2 && sizeof(_Tp) == 4
1225 && is_integral_v<_Tp>)
1226 _mm_maskstore_epi32(reinterpret_cast<int*>(__mem), __ki, __vi);
1227 else if constexpr (__have_avx && sizeof(_Tp) == 4)
1228 _mm_maskstore_ps(reinterpret_cast<float*>(__mem), __ki,
1229 __vector_bitcast<float>(__vi));
1230 else if constexpr (__have_avx2 && sizeof(_Tp) == 8
1231 && is_integral_v<_Tp>)
1232 _mm_maskstore_epi64(reinterpret_cast<_LLong*>(__mem), __ki, __vi);
1233 else if constexpr (__have_avx && sizeof(_Tp) == 8)
1234 _mm_maskstore_pd(reinterpret_cast<double*>(__mem), __ki,
1235 __vector_bitcast<double>(__vi));
1236 else if constexpr (__have_sse2)
1237 _mm_maskmoveu_si128(__vi, __ki, reinterpret_cast<char*>(__mem));
1238 }
1239 else if constexpr (sizeof(__v) == 32)
1240 {
1241 [[maybe_unused]] const auto __vi
1242 = __intrin_bitcast<__m256i>(__as_vector(__v));
1243 [[maybe_unused]] const auto __ki
1244 = __intrin_bitcast<__m256i>(__as_vector(__k));
1245 if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 1)
1246 _mm256_mask_storeu_epi8(__mem, _mm256_movepi8_mask(__ki), __vi);
1247 else if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 2)
1248 _mm256_mask_storeu_epi16(__mem, _mm256_movepi16_mask(__ki), __vi);
1249 else if constexpr (__have_avx2 && sizeof(_Tp) == 4
1250 && is_integral_v<_Tp>)
1251 _mm256_maskstore_epi32(reinterpret_cast<int*>(__mem), __ki, __vi);
1252 else if constexpr (sizeof(_Tp) == 4)
1253 _mm256_maskstore_ps(reinterpret_cast<float*>(__mem), __ki,
1254 __vector_bitcast<float>(__v));
1255 else if constexpr (__have_avx2 && sizeof(_Tp) == 8
1256 && is_integral_v<_Tp>)
1257 _mm256_maskstore_epi64(reinterpret_cast<_LLong*>(__mem), __ki,
1258 __vi);
1259 else if constexpr (__have_avx && sizeof(_Tp) == 8)
1260 _mm256_maskstore_pd(reinterpret_cast<double*>(__mem), __ki,
1261 __vector_bitcast<double>(__v));
1262 else if constexpr (__have_sse2)
1263 {
1264 _mm_maskmoveu_si128(__lo128(__vi), __lo128(__ki),
1265 reinterpret_cast<char*>(__mem));
1266 _mm_maskmoveu_si128(__hi128(__vi), __hi128(__ki),
1267 reinterpret_cast<char*>(__mem) + 16);
1268 }
1269 }
1270 else
1271 __assert_unreachable<_Tp>();
1272 }
1273
1274 // }}}
1275 // _S_masked_store {{{
1276 template <typename _Tp, size_t _Np, typename _Up>
1277 _GLIBCXX_SIMD_INTRINSIC static void
1278 _S_masked_store(const _SimdWrapper<_Tp, _Np> __v, _Up* __mem,
1279 const _MaskMember<_Tp> __k) noexcept
1280 {
1281 if constexpr (is_integral_v<
1282 _Tp> && is_integral_v<_Up> && sizeof(_Tp) > sizeof(_Up)
1283 && __have_avx512f && (sizeof(_Tp) >= 4 || __have_avx512bw)
1284 && (sizeof(__v) == 64 || __have_avx512vl))
1285 { // truncating store
1286 const auto __vi = __to_intrin(__v);
1287 const auto __kk = _MaskImpl::_S_to_bits(__k)._M_to_bits();
1288 if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 4
1289 && sizeof(__vi) == 64)
1290 _mm512_mask_cvtepi64_storeu_epi32(__mem, __kk, __vi);
1291 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 4
1292 && sizeof(__vi) == 32)
1293 _mm256_mask_cvtepi64_storeu_epi32(__mem, __kk, __vi);
1294 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 4
1295 && sizeof(__vi) == 16)
1296 _mm_mask_cvtepi64_storeu_epi32(__mem, __kk, __vi);
1297 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 2
1298 && sizeof(__vi) == 64)
1299 _mm512_mask_cvtepi64_storeu_epi16(__mem, __kk, __vi);
1300 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 2
1301 && sizeof(__vi) == 32)
1302 _mm256_mask_cvtepi64_storeu_epi16(__mem, __kk, __vi);
1303 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 2
1304 && sizeof(__vi) == 16)
1305 _mm_mask_cvtepi64_storeu_epi16(__mem, __kk, __vi);
1306 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 1
1307 && sizeof(__vi) == 64)
1308 _mm512_mask_cvtepi64_storeu_epi8(__mem, __kk, __vi);
1309 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 1
1310 && sizeof(__vi) == 32)
1311 _mm256_mask_cvtepi64_storeu_epi8(__mem, __kk, __vi);
1312 else if constexpr (sizeof(_Tp) == 8 && sizeof(_Up) == 1
1313 && sizeof(__vi) == 16)
1314 _mm_mask_cvtepi64_storeu_epi8(__mem, __kk, __vi);
1315 else if constexpr (sizeof(_Tp) == 4 && sizeof(_Up) == 2
1316 && sizeof(__vi) == 64)
1317 _mm512_mask_cvtepi32_storeu_epi16(__mem, __kk, __vi);
1318 else if constexpr (sizeof(_Tp) == 4 && sizeof(_Up) == 2
1319 && sizeof(__vi) == 32)
1320 _mm256_mask_cvtepi32_storeu_epi16(__mem, __kk, __vi);
1321 else if constexpr (sizeof(_Tp) == 4 && sizeof(_Up) == 2
1322 && sizeof(__vi) == 16)
1323 _mm_mask_cvtepi32_storeu_epi16(__mem, __kk, __vi);
1324 else if constexpr (sizeof(_Tp) == 4 && sizeof(_Up) == 1
1325 && sizeof(__vi) == 64)
1326 _mm512_mask_cvtepi32_storeu_epi8(__mem, __kk, __vi);
1327 else if constexpr (sizeof(_Tp) == 4 && sizeof(_Up) == 1
1328 && sizeof(__vi) == 32)
1329 _mm256_mask_cvtepi32_storeu_epi8(__mem, __kk, __vi);
1330 else if constexpr (sizeof(_Tp) == 4 && sizeof(_Up) == 1
1331 && sizeof(__vi) == 16)
1332 _mm_mask_cvtepi32_storeu_epi8(__mem, __kk, __vi);
1333 else if constexpr (sizeof(_Tp) == 2 && sizeof(_Up) == 1
1334 && sizeof(__vi) == 64)
1335 _mm512_mask_cvtepi16_storeu_epi8(__mem, __kk, __vi);
1336 else if constexpr (sizeof(_Tp) == 2 && sizeof(_Up) == 1
1337 && sizeof(__vi) == 32)
1338 _mm256_mask_cvtepi16_storeu_epi8(__mem, __kk, __vi);
1339 else if constexpr (sizeof(_Tp) == 2 && sizeof(_Up) == 1
1340 && sizeof(__vi) == 16)
1341 _mm_mask_cvtepi16_storeu_epi8(__mem, __kk, __vi);
1342 else
1343 __assert_unreachable<_Tp>();
1344 }
1345 else
1346 _Base::_S_masked_store(__v, __mem, __k);
1347 }
1348
1349 // }}}
1350 // _S_multiplies {{{
1351 template <typename _V, typename _VVT = _VectorTraits<_V>>
1352 _GLIBCXX_SIMD_INTRINSIC static constexpr _V
1353 _S_multiplies(_V __x, _V __y)
1354 {
1355 using _Tp = typename _VVT::value_type;
1356 if (__builtin_is_constant_evaluated() || __x._M_is_constprop()
1357 || __y._M_is_constprop())
1358 return __as_vector(__x) * __as_vector(__y);
1359 else if constexpr (sizeof(_Tp) == 1)
1360 {
1361 if constexpr (sizeof(_V) == 2)
1362 {
1363 const auto __xs = reinterpret_cast<short>(__x._M_data);
1364 const auto __ys = reinterpret_cast<short>(__y._M_data);
1365 return reinterpret_cast<__vector_type_t<_Tp, 2>>(short(
1366 ((__xs * __ys) & 0xff) | ((__xs >> 8) * (__ys & 0xff00))));
1367 }
1368 else if constexpr (sizeof(_V) == 4 && _VVT::_S_partial_width == 3)
1369 {
1370 const auto __xi = reinterpret_cast<int>(__x._M_data);
1371 const auto __yi = reinterpret_cast<int>(__y._M_data);
1372 return reinterpret_cast<__vector_type_t<_Tp, 3>>(
1373 ((__xi * __yi) & 0xff)
1374 | (((__xi >> 8) * (__yi & 0xff00)) & 0xff00)
1375 | ((__xi >> 16) * (__yi & 0xff0000)));
1376 }
1377 else if constexpr (sizeof(_V) == 4)
1378 {
1379 const auto __xi = reinterpret_cast<int>(__x._M_data);
1380 const auto __yi = reinterpret_cast<int>(__y._M_data);
1381 return reinterpret_cast<__vector_type_t<_Tp, 4>>(
1382 ((__xi * __yi) & 0xff)
1383 | (((__xi >> 8) * (__yi & 0xff00)) & 0xff00)
1384 | (((__xi >> 16) * (__yi & 0xff0000)) & 0xff0000)
1385 | ((__xi >> 24) * (__yi & 0xff000000u)));
1386 }
1387 else if constexpr (sizeof(_V) == 8 && __have_avx2
1388 && is_signed_v<_Tp>)
1389 return __convert<typename _VVT::type>(
1390 __vector_bitcast<short>(_mm_cvtepi8_epi16(__to_intrin(__x)))
1391 * __vector_bitcast<short>(_mm_cvtepi8_epi16(__to_intrin(__y))));
1392 else if constexpr (sizeof(_V) == 8 && __have_avx2
1393 && is_unsigned_v<_Tp>)
1394 return __convert<typename _VVT::type>(
1395 __vector_bitcast<short>(_mm_cvtepu8_epi16(__to_intrin(__x)))
1396 * __vector_bitcast<short>(_mm_cvtepu8_epi16(__to_intrin(__y))));
1397 else
1398 {
1399 // codegen of `x*y` is suboptimal (as of GCC 9.0.1)
1400 constexpr size_t __full_size = _VVT::_S_full_size;
1401 constexpr int _Np = sizeof(_V) >= 16 ? __full_size / 2 : 8;
1402 using _ShortW = _SimdWrapper<short, _Np>;
1403 const _ShortW __even = __vector_bitcast<short, _Np>(__x)
1404 * __vector_bitcast<short, _Np>(__y);
1405 _ShortW __high_byte = _ShortW()._M_data - 256;
1406 //[&]() { asm("" : "+x"(__high_byte._M_data)); }();
1407 const _ShortW __odd
1408 = (__vector_bitcast<short, _Np>(__x) >> 8)
1409 * (__vector_bitcast<short, _Np>(__y) & __high_byte._M_data);
1410 if constexpr (__have_avx512bw && sizeof(_V) > 2)
1411 return _CommonImplX86::_S_blend_avx512(
1412 0xaaaa'aaaa'aaaa'aaaaLL, __vector_bitcast<_Tp>(__even),
1413 __vector_bitcast<_Tp>(__odd));
1414 else if constexpr (__have_sse4_1 && sizeof(_V) > 2)
1415 return _CommonImplX86::_S_blend_intrin(__to_intrin(
1416 __high_byte),
1417 __to_intrin(__even),
1418 __to_intrin(__odd));
1419 else
1420 return __to_intrin(
1421 __or(__andnot(__high_byte, __even), __odd));
1422 }
1423 }
1424 else
1425 return _Base::_S_multiplies(__x, __y);
1426 }
1427
1428 // }}}
1429 // _S_divides {{{
1430#ifdef _GLIBCXX_SIMD_WORKAROUND_PR90993
1431 template <typename _Tp, size_t _Np>
1432 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
1433 _S_divides(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
1434 {
1435 if (!__builtin_is_constant_evaluated()
1436 && !__builtin_constant_p(__y._M_data))
1437 if constexpr (is_integral_v<_Tp> && sizeof(_Tp) <= 4)
1438 { // use divps - codegen of `x/y` is suboptimal (as of GCC 9.0.1)
1439 // Note that using floating-point division is likely to raise the
1440 // *Inexact* exception flag and thus appears like an invalid
1441 // "as-if" transformation. However, C++ doesn't specify how the
1442 // fpenv can be observed and points to C. C says that function
1443 // calls are assumed to potentially raise fp exceptions, unless
1444 // documented otherwise. Consequently, operator/, which is a
1445 // function call, may raise fp exceptions.
1446 /*const struct _CsrGuard
1447 {
1448 const unsigned _M_data = _mm_getcsr();
1449 _CsrGuard()
1450 {
1451 _mm_setcsr(0x9f80); // turn off FP exceptions and
1452 flush-to-zero
1453 }
1454 ~_CsrGuard() { _mm_setcsr(_M_data); }
1455 } __csr;*/
1456 using _Float = conditional_t<sizeof(_Tp) == 4, double, float>;
1457 constexpr size_t __n_intermediate
1458 = std::min(_Np, (__have_avx512f ? 64
1459 : __have_avx ? 32
1460 : 16)
1461 / sizeof(_Float));
1462 using _FloatV = __vector_type_t<_Float, __n_intermediate>;
1463 constexpr size_t __n_floatv
1464 = __div_roundup(_Np, __n_intermediate);
1465 using _R = __vector_type_t<_Tp, _Np>;
1466 const auto __xf = __convert_all<_FloatV, __n_floatv>(__x);
1467 const auto __yf = __convert_all<_FloatV, __n_floatv>(
1468 _Abi::__make_padding_nonzero(__as_vector(__y)));
1469 return __call_with_n_evaluations<__n_floatv>(
1470 [](auto... __quotients) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
1471 return __vector_convert<_R>(__quotients...);
1472 },
1473 [&__xf, &__yf](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA
1474 -> _SimdWrapper<_Float, __n_intermediate>
1475 {
1476#if __RECIPROCAL_MATH__
1477 // If -freciprocal-math is active, using the `/` operator is
1478 // incorrect because it may be translated to an imprecise
1479 // multiplication with reciprocal. We need to use inline
1480 // assembly to force a real division.
1481 _FloatV __r;
1482 if constexpr (__have_avx) // -mno-sse2avx is irrelevant
1483 // because once -mavx is given, GCC
1484 // emits VEX encoded vdivp[sd]
1485 {
1486 if constexpr (sizeof(_Tp) == 4)
1487 asm("vdivpd\t{%2, %1, %0|%0, %1, %2}"
1488 : "=x"(__r)
1489 : "x"(__xf[__i]), "x"(__yf[__i]));
1490 else
1491 asm("vdivps\t{%2, %1, %0|%0, %1, %2}"
1492 : "=x"(__r)
1493 : "x"(__xf[__i]), "x"(__yf[__i]));
1494 }
1495 else
1496 {
1497 __r = __xf[__i];
1498 if constexpr (sizeof(_Tp) == 4)
1499 asm("divpd\t{%1, %0|%0, %1}"
1500 : "=x"(__r)
1501 : "x"(__yf[__i]));
1502 else
1503 asm("divps\t{%1, %0|%0, %1}"
1504 : "=x"(__r)
1505 : "x"(__yf[__i]));
1506 }
1507 return __r;
1508#else
1509 return __xf[__i] / __yf[__i];
1510#endif
1511 });
1512 }
1513 /* 64-bit int division is potentially optimizable via double division if
1514 * the value in __x is small enough and the conversion between
1515 * int<->double is efficient enough:
1516 else if constexpr (is_integral_v<_Tp> && is_unsigned_v<_Tp> &&
1517 sizeof(_Tp) == 8)
1518 {
1519 if constexpr (__have_sse4_1 && sizeof(__x) == 16)
1520 {
1521 if (_mm_test_all_zeros(__x, __m128i{0xffe0'0000'0000'0000ull,
1522 0xffe0'0000'0000'0000ull}))
1523 {
1524 __x._M_data | 0x __vector_convert<__m128d>(__x._M_data)
1525 }
1526 }
1527 }
1528 */
1529 return _Base::_S_divides(__x, __y);
1530 }
1531#else
1532 using _Base::_S_divides;
1533#endif // _GLIBCXX_SIMD_WORKAROUND_PR90993
1534
1535 // }}}
1536 // _S_modulus {{{
1537 template <typename _Tp, size_t _Np>
1538 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
1539 _S_modulus(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
1540 {
1541 if (__builtin_is_constant_evaluated()
1542 || __builtin_constant_p(__y._M_data) || sizeof(_Tp) >= 8)
1543 return _Base::_S_modulus(__x, __y);
1544 else
1545 return _Base::_S_minus(__x, _S_multiplies(__y, _S_divides(__x, __y)));
1546 }
1547
1548 // }}}
1549 // _S_bit_shift_left {{{
1550 // Notes on UB. C++2a [expr.shift] says:
1551 // -1- [...] The operands shall be of integral or unscoped enumeration type
1552 // and integral promotions are performed. The type of the result is that
1553 // of the promoted left operand. The behavior is undefined if the right
1554 // operand is negative, or greater than or equal to the width of the
1555 // promoted left operand.
1556 // -2- The value of E1 << E2 is the unique value congruent to E1×2^E2 modulo
1557 // 2^N, where N is the width of the type of the result.
1558 //
1559 // C++17 [expr.shift] says:
1560 // -2- The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated
1561 // bits are zero-filled. If E1 has an unsigned type, the value of the
1562 // result is E1 × 2^E2 , reduced modulo one more than the maximum value
1563 // representable in the result type. Otherwise, if E1 has a signed type
1564 // and non-negative value, and E1 × 2^E2 is representable in the
1565 // corresponding unsigned type of the result type, then that value,
1566 // converted to the result type, is the resulting value; otherwise, the
1567 // behavior is undefined.
1568 //
1569 // Consequences:
1570 // With C++2a signed and unsigned types have the same UB
1571 // characteristics:
1572 // - left shift is not UB for 0 <= RHS < max(32, #bits(T))
1573 //
1574 // With C++17 there's little room for optimizations because the standard
1575 // requires all shifts to happen on promoted integrals (i.e. int). Thus,
1576 // short and char shifts must assume shifts affect bits of neighboring
1577 // values.
1578 #ifndef _GLIBCXX_SIMD_NO_SHIFT_OPT
1579 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1580 constexpr inline _GLIBCXX_CONST static typename _TVT::type
1581 _S_bit_shift_left(_Tp __xx, int __y)
1582 {
1583 using _V = typename _TVT::type;
1584 using _Up = typename _TVT::value_type;
1585 _V __x = __xx;
1586 [[maybe_unused]] const auto __ix = __to_intrin(__x);
1587 if (__builtin_is_constant_evaluated())
1588 return __x << __y;
1589#if __cplusplus > 201703
1590 // after C++17, signed shifts have no UB, and behave just like unsigned
1591 // shifts
1592 else if constexpr (sizeof(_Up) == 1 && is_signed_v<_Up>)
1593 return __vector_bitcast<_Up>(
1594 _S_bit_shift_left(__vector_bitcast<make_unsigned_t<_Up>>(__x),
1595 __y));
1596#endif
1597 else if constexpr (sizeof(_Up) == 1)
1598 {
1599 // (cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83894)
1600 if (__builtin_constant_p(__y))
1601 {
1602 if (__y == 0)
1603 return __x;
1604 else if (__y == 1)
1605 return __x + __x;
1606 else if (__y == 2)
1607 {
1608 __x = __x + __x;
1609 return __x + __x;
1610 }
1611 else if (__y > 2 && __y < 8)
1612 {
1613 if constexpr (sizeof(__x) > sizeof(unsigned))
1614 {
1615 const _UChar __mask = 0xff << __y; // precomputed vector
1616 return __vector_bitcast<_Up>(
1617 __vector_bitcast<_UChar>(
1618 __vector_bitcast<unsigned>(__x) << __y)
1619 & __mask);
1620 }
1621 else
1622 {
1623 const unsigned __mask
1624 = (0xff & (0xff << __y)) * 0x01010101u;
1625 return reinterpret_cast<_V>(
1626 static_cast<__int_for_sizeof_t<_V>>(
1627 unsigned(
1628 reinterpret_cast<__int_for_sizeof_t<_V>>(__x)
1629 << __y)
1630 & __mask));
1631 }
1632 }
1633 else if (__y >= 8 && __y < 32)
1634 return _V();
1635 else
1636 __builtin_unreachable();
1637 }
1638 // general strategy in the following: use an sllv instead of sll
1639 // instruction, because it's 2 to 4 times faster:
1640 else if constexpr (__have_avx512bw_vl && sizeof(__x) == 16)
1641 return __vector_bitcast<_Up>(_mm256_cvtepi16_epi8(
1642 _mm256_sllv_epi16(_mm256_cvtepi8_epi16(__ix),
1643 _mm256_set1_epi16(__y))));
1644 else if constexpr (__have_avx512bw && sizeof(__x) == 32)
1645 return __vector_bitcast<_Up>(_mm512_cvtepi16_epi8(
1646 _mm512_sllv_epi16(_mm512_cvtepi8_epi16(__ix),
1647 _mm512_set1_epi16(__y))));
1648 else if constexpr (__have_avx512bw && sizeof(__x) == 64)
1649 {
1650 const auto __shift = _mm512_set1_epi16(__y);
1651 return __vector_bitcast<_Up>(
1652 __concat(_mm512_cvtepi16_epi8(_mm512_sllv_epi16(
1653 _mm512_cvtepi8_epi16(__lo256(__ix)), __shift)),
1654 _mm512_cvtepi16_epi8(_mm512_sllv_epi16(
1655 _mm512_cvtepi8_epi16(__hi256(__ix)), __shift))));
1656 }
1657 else if constexpr (__have_avx2 && sizeof(__x) == 32)
1658 {
1659#if 1
1660 const auto __shift = _mm_cvtsi32_si128(__y);
1661 auto __k
1662 = _mm256_sll_epi16(_mm256_slli_epi16(~__m256i(), 8), __shift);
1663 __k |= _mm256_srli_epi16(__k, 8);
1664 return __vector_bitcast<_Up>(_mm256_sll_epi32(__ix, __shift)
1665 & __k);
1666#else
1667 const _Up __k = 0xff << __y;
1668 return __vector_bitcast<_Up>(__vector_bitcast<int>(__x) << __y)
1669 & __k;
1670#endif
1671 }
1672 else
1673 {
1674 const auto __shift = _mm_cvtsi32_si128(__y);
1675 auto __k
1676 = _mm_sll_epi16(_mm_slli_epi16(~__m128i(), 8), __shift);
1677 __k |= _mm_srli_epi16(__k, 8);
1678 return __intrin_bitcast<_V>(_mm_sll_epi16(__ix, __shift) & __k);
1679 }
1680 }
1681 return __x << __y;
1682 }
1683
1684 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1685 constexpr inline _GLIBCXX_CONST static typename _TVT::type
1686 _S_bit_shift_left(_Tp __xx, typename _TVT::type __y)
1687 {
1688 using _V = typename _TVT::type;
1689 using _Up = typename _TVT::value_type;
1690 _V __x = __xx;
1691 [[maybe_unused]] const auto __ix = __to_intrin(__x);
1692 [[maybe_unused]] const auto __iy = __to_intrin(__y);
1693 if (__builtin_is_constant_evaluated())
1694 return __x << __y;
1695#if __cplusplus > 201703
1696 // after C++17, signed shifts have no UB, and behave just like unsigned
1697 // shifts
1698 else if constexpr (is_signed_v<_Up>)
1699 return __vector_bitcast<_Up>(
1700 _S_bit_shift_left(__vector_bitcast<make_unsigned_t<_Up>>(__x),
1701 __vector_bitcast<make_unsigned_t<_Up>>(__y)));
1702#endif
1703 else if constexpr (sizeof(_Up) == 1)
1704 {
1705 if constexpr (sizeof __ix == 64 && __have_avx512bw)
1706 return __vector_bitcast<_Up>(__concat(
1707 _mm512_cvtepi16_epi8(
1708 _mm512_sllv_epi16(_mm512_cvtepu8_epi16(__lo256(__ix)),
1709 _mm512_cvtepu8_epi16(__lo256(__iy)))),
1710 _mm512_cvtepi16_epi8(
1711 _mm512_sllv_epi16(_mm512_cvtepu8_epi16(__hi256(__ix)),
1712 _mm512_cvtepu8_epi16(__hi256(__iy))))));
1713 else if constexpr (sizeof __ix == 32 && __have_avx512bw)
1714 return __vector_bitcast<_Up>(_mm512_cvtepi16_epi8(
1715 _mm512_sllv_epi16(_mm512_cvtepu8_epi16(__ix),
1716 _mm512_cvtepu8_epi16(__iy))));
1717 else if constexpr (sizeof __x <= 8 && __have_avx512bw_vl)
1718 return __intrin_bitcast<_V>(
1719 _mm_cvtepi16_epi8(_mm_sllv_epi16(_mm_cvtepu8_epi16(__ix),
1720 _mm_cvtepu8_epi16(__iy))));
1721 else if constexpr (sizeof __ix == 16 && __have_avx512bw_vl)
1722 return __intrin_bitcast<_V>(_mm256_cvtepi16_epi8(
1723 _mm256_sllv_epi16(_mm256_cvtepu8_epi16(__ix),
1724 _mm256_cvtepu8_epi16(__iy))));
1725 else if constexpr (sizeof __ix == 16 && __have_avx512bw)
1726 return __intrin_bitcast<_V>(
1727 __lo128(_mm512_cvtepi16_epi8(_mm512_sllv_epi16(
1728 _mm512_cvtepu8_epi16(_mm256_castsi128_si256(__ix)),
1729 _mm512_cvtepu8_epi16(_mm256_castsi128_si256(__iy))))));
1730 else if constexpr (__have_sse4_1 && sizeof(__x) == 16)
1731 {
1732 auto __mask
1733 = __vector_bitcast<_Up>(__vector_bitcast<short>(__y) << 5);
1734 auto __x4
1735 = __vector_bitcast<_Up>(__vector_bitcast<short>(__x) << 4);
1736 __x4 &= char(0xf0);
1737 __x = reinterpret_cast<_V>(_CommonImplX86::_S_blend_intrin(
1738 __to_intrin(__mask), __to_intrin(__x), __to_intrin(__x4)));
1739 __mask += __mask;
1740 auto __x2
1741 = __vector_bitcast<_Up>(__vector_bitcast<short>(__x) << 2);
1742 __x2 &= char(0xfc);
1743 __x = reinterpret_cast<_V>(_CommonImplX86::_S_blend_intrin(
1744 __to_intrin(__mask), __to_intrin(__x), __to_intrin(__x2)));
1745 __mask += __mask;
1746 auto __x1 = __x + __x;
1747 __x = reinterpret_cast<_V>(_CommonImplX86::_S_blend_intrin(
1748 __to_intrin(__mask), __to_intrin(__x), __to_intrin(__x1)));
1749 return __x
1750 & ((__y & char(0xf8)) == 0); // y > 7 nulls the result
1751 }
1752 else if constexpr (sizeof(__x) == 16)
1753 {
1754 auto __mask
1755 = __vector_bitcast<_UChar>(__vector_bitcast<short>(__y) << 5);
1756 auto __x4
1757 = __vector_bitcast<_Up>(__vector_bitcast<short>(__x) << 4);
1758 __x4 &= char(0xf0);
1759 __x = __vector_bitcast<_SChar>(__mask) < 0 ? __x4 : __x;
1760 __mask += __mask;
1761 auto __x2
1762 = __vector_bitcast<_Up>(__vector_bitcast<short>(__x) << 2);
1763 __x2 &= char(0xfc);
1764 __x = __vector_bitcast<_SChar>(__mask) < 0 ? __x2 : __x;
1765 __mask += __mask;
1766 auto __x1 = __x + __x;
1767 __x = __vector_bitcast<_SChar>(__mask) < 0 ? __x1 : __x;
1768 return __x
1769 & ((__y & char(0xf8)) == 0); // y > 7 nulls the result
1770 }
1771 else
1772 return __x << __y;
1773 }
1774 else if constexpr (sizeof(_Up) == 2)
1775 {
1776 if constexpr (sizeof __ix == 64 && __have_avx512bw)
1777 return __vector_bitcast<_Up>(_mm512_sllv_epi16(__ix, __iy));
1778 else if constexpr (sizeof __ix == 32 && __have_avx512bw_vl)
1779 return __vector_bitcast<_Up>(_mm256_sllv_epi16(__ix, __iy));
1780 else if constexpr (sizeof __ix == 32 && __have_avx512bw)
1781 return __vector_bitcast<_Up>(
1782 __lo256(_mm512_sllv_epi16(_mm512_castsi256_si512(__ix),
1783 _mm512_castsi256_si512(__iy))));
1784 else if constexpr (sizeof __ix == 32 && __have_avx2)
1785 {
1786 const auto __ux = __vector_bitcast<unsigned>(__x);
1787 const auto __uy = __vector_bitcast<unsigned>(__y);
1788 return __vector_bitcast<_Up>(_mm256_blend_epi16(
1789 __auto_bitcast(__ux << (__uy & 0x0000ffffu)),
1790 __auto_bitcast((__ux & 0xffff0000u) << (__uy >> 16)), 0xaa));
1791 }
1792 else if constexpr (sizeof __ix == 16 && __have_avx512bw_vl)
1793 return __intrin_bitcast<_V>(_mm_sllv_epi16(__ix, __iy));
1794 else if constexpr (sizeof __ix == 16 && __have_avx512bw)
1795 return __intrin_bitcast<_V>(
1796 __lo128(_mm512_sllv_epi16(_mm512_castsi128_si512(__ix),
1797 _mm512_castsi128_si512(__iy))));
1798 else if constexpr (sizeof __ix == 16 && __have_avx2)
1799 {
1800 const auto __ux = __vector_bitcast<unsigned>(__ix);
1801 const auto __uy = __vector_bitcast<unsigned>(__iy);
1802 return __intrin_bitcast<_V>(_mm_blend_epi16(
1803 __auto_bitcast(__ux << (__uy & 0x0000ffffu)),
1804 __auto_bitcast((__ux & 0xffff0000u) << (__uy >> 16)), 0xaa));
1805 }
1806 else if constexpr (sizeof __ix == 16)
1807 {
1808 using _Float4 = __vector_type_t<float, 4>;
1809 using _Int4 = __vector_type_t<int, 4>;
1810 using _UInt4 = __vector_type_t<unsigned, 4>;
1811 const _UInt4 __yu
1812 = reinterpret_cast<_UInt4>(__to_intrin(__y + (0x3f8 >> 3)));
1813 return __x
1814 * __intrin_bitcast<_V>(
1815 __vector_convert<_Int4>(_SimdWrapper<float, 4>(
1816 reinterpret_cast<_Float4>(__yu << 23)))
1817 | (__vector_convert<_Int4>(_SimdWrapper<float, 4>(
1818 reinterpret_cast<_Float4>((__yu >> 16) << 23)))
1819 << 16));
1820 }
1821 else
1822 __assert_unreachable<_Tp>();
1823 }
1824 else if constexpr (sizeof(_Up) == 4 && sizeof __ix == 16
1825 && !__have_avx2)
1826 // latency is suboptimal, but throughput is at full speedup
1827 return __intrin_bitcast<_V>(
1828 __vector_bitcast<unsigned>(__ix)
1829 * __vector_convert<__vector_type16_t<int>>(
1830 _SimdWrapper<float, 4>(__vector_bitcast<float>(
1831 (__vector_bitcast<unsigned, 4>(__y) << 23) + 0x3f80'0000))));
1832 else if constexpr (sizeof(_Up) == 8 && sizeof __ix == 16
1833 && !__have_avx2)
1834 {
1835 const auto __lo = _mm_sll_epi64(__ix, __iy);
1836 const auto __hi
1837 = _mm_sll_epi64(__ix, _mm_unpackhi_epi64(__iy, __iy));
1838 if constexpr (__have_sse4_1)
1839 return __vector_bitcast<_Up>(_mm_blend_epi16(__lo, __hi, 0xf0));
1840 else
1841 return __vector_bitcast<_Up>(
1842 _mm_move_sd(__vector_bitcast<double>(__hi),
1843 __vector_bitcast<double>(__lo)));
1844 }
1845 else
1846 return __x << __y;
1847 }
1848#endif // _GLIBCXX_SIMD_NO_SHIFT_OPT
1849
1850 // }}}
1851 // _S_bit_shift_right {{{
1852#ifndef _GLIBCXX_SIMD_NO_SHIFT_OPT
1853 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1854 constexpr inline _GLIBCXX_CONST static typename _TVT::type
1855 _S_bit_shift_right(_Tp __xx, int __y)
1856 {
1857 using _V = typename _TVT::type;
1858 using _Up = typename _TVT::value_type;
1859 _V __x = __xx;
1860 [[maybe_unused]] const auto __ix = __to_intrin(__x);
1861 if (__builtin_is_constant_evaluated())
1862 return __x >> __y;
1863 else if (__builtin_constant_p(__y)
1864 && is_unsigned_v<
1865 _Up> && __y >= int(sizeof(_Up) * __CHAR_BIT__))
1866 return _V();
1867 else if constexpr (sizeof(_Up) == 1 && is_unsigned_v<_Up>) //{{{
1868 return __intrin_bitcast<_V>(__vector_bitcast<_UShort>(__ix) >> __y)
1869 & _Up(0xff >> __y);
1870 //}}}
1871 else if constexpr (sizeof(_Up) == 1 && is_signed_v<_Up>) //{{{
1872 return __intrin_bitcast<_V>(
1873 (__vector_bitcast<_UShort>(__vector_bitcast<short>(__ix)
1874 >> (__y + 8))
1875 << 8)
1876 | (__vector_bitcast<_UShort>(
1877 __vector_bitcast<short>(__vector_bitcast<_UShort>(__ix) << 8)
1878 >> __y)
1879 >> 8));
1880 //}}}
1881 // GCC optimizes sizeof == 2, 4, and unsigned 8 as expected
1882 else if constexpr (sizeof(_Up) == 8 && is_signed_v<_Up>) //{{{
1883 {
1884 if (__y > 32)
1885 return (__intrin_bitcast<_V>(__vector_bitcast<int>(__ix) >> 32)
1886 & _Up(0xffff'ffff'0000'0000ull))
1887 | __vector_bitcast<_Up>(
1888 __vector_bitcast<int>(__vector_bitcast<_ULLong>(__ix)
1889 >> 32)
1890 >> (__y - 32));
1891 else
1892 return __intrin_bitcast<_V>(__vector_bitcast<_ULLong>(__ix)
1893 >> __y)
1894 | __vector_bitcast<_Up>(
1895 __vector_bitcast<int>(__ix & -0x8000'0000'0000'0000ll)
1896 >> __y);
1897 }
1898 //}}}
1899 else
1900 return __x >> __y;
1901 }
1902
1903 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
1904 constexpr inline _GLIBCXX_CONST static typename _TVT::type
1905 _S_bit_shift_right(_Tp __xx, typename _TVT::type __y)
1906 {
1907 using _V = typename _TVT::type;
1908 using _Up = typename _TVT::value_type;
1909 _V __x = __xx;
1910 [[maybe_unused]] const auto __ix = __to_intrin(__x);
1911 [[maybe_unused]] const auto __iy = __to_intrin(__y);
1912 if (__builtin_is_constant_evaluated()
1913 || (__builtin_constant_p(__x) && __builtin_constant_p(__y)))
1914 return __x >> __y;
1915 else if constexpr (sizeof(_Up) == 1) //{{{
1916 {
1917 if constexpr (sizeof(__x) <= 8 && __have_avx512bw_vl)
1918 return __intrin_bitcast<_V>(_mm_cvtepi16_epi8(
1919 is_signed_v<_Up> ? _mm_srav_epi16(_mm_cvtepi8_epi16(__ix),
1920 _mm_cvtepi8_epi16(__iy))
1921 : _mm_srlv_epi16(_mm_cvtepu8_epi16(__ix),
1922 _mm_cvtepu8_epi16(__iy))));
1923 if constexpr (sizeof(__x) == 16 && __have_avx512bw_vl)
1924 return __intrin_bitcast<_V>(_mm256_cvtepi16_epi8(
1925 is_signed_v<_Up>
1926 ? _mm256_srav_epi16(_mm256_cvtepi8_epi16(__ix),
1927 _mm256_cvtepi8_epi16(__iy))
1928 : _mm256_srlv_epi16(_mm256_cvtepu8_epi16(__ix),
1929 _mm256_cvtepu8_epi16(__iy))));
1930 else if constexpr (sizeof(__x) == 32 && __have_avx512bw)
1931 return __vector_bitcast<_Up>(_mm512_cvtepi16_epi8(
1932 is_signed_v<_Up>
1933 ? _mm512_srav_epi16(_mm512_cvtepi8_epi16(__ix),
1934 _mm512_cvtepi8_epi16(__iy))
1935 : _mm512_srlv_epi16(_mm512_cvtepu8_epi16(__ix),
1936 _mm512_cvtepu8_epi16(__iy))));
1937 else if constexpr (sizeof(__x) == 64 && is_signed_v<_Up>)
1938 return __vector_bitcast<_Up>(_mm512_mask_mov_epi8(
1939 _mm512_srav_epi16(__ix, _mm512_srli_epi16(__iy, 8)),
1940 0x5555'5555'5555'5555ull,
1941 _mm512_srav_epi16(
1942 _mm512_slli_epi16(__ix, 8),
1943 _mm512_maskz_add_epi8(0x5555'5555'5555'5555ull, __iy,
1944 _mm512_set1_epi16(8)))));
1945 else if constexpr (sizeof(__x) == 64 && is_unsigned_v<_Up>)
1946 return __vector_bitcast<_Up>(_mm512_mask_mov_epi8(
1947 _mm512_srlv_epi16(__ix, _mm512_srli_epi16(__iy, 8)),
1948 0x5555'5555'5555'5555ull,
1949 _mm512_srlv_epi16(
1950 _mm512_maskz_mov_epi8(0x5555'5555'5555'5555ull, __ix),
1951 _mm512_maskz_mov_epi8(0x5555'5555'5555'5555ull, __iy))));
1952 /* This has better throughput but higher latency than the impl below
1953 else if constexpr (__have_avx2 && sizeof(__x) == 16 &&
1954 is_unsigned_v<_Up>)
1955 {
1956 const auto __shorts = __to_intrin(_S_bit_shift_right(
1957 __vector_bitcast<_UShort>(_mm256_cvtepu8_epi16(__ix)),
1958 __vector_bitcast<_UShort>(_mm256_cvtepu8_epi16(__iy))));
1959 return __vector_bitcast<_Up>(
1960 _mm_packus_epi16(__lo128(__shorts), __hi128(__shorts)));
1961 }
1962 */
1963 else if constexpr (__have_avx2 && sizeof(__x) > 8)
1964 // the following uses vpsr[al]vd, which requires AVX2
1965 if constexpr (is_signed_v<_Up>)
1966 {
1967 const auto r3 = __vector_bitcast<_UInt>(
1968 (__vector_bitcast<int>(__x)
1969 >> (__vector_bitcast<_UInt>(__y) >> 24)))
1970 & 0xff000000u;
1971 const auto r2
1972 = __vector_bitcast<_UInt>(
1973 ((__vector_bitcast<int>(__x) << 8)
1974 >> ((__vector_bitcast<_UInt>(__y) << 8) >> 24)))
1975 & 0xff000000u;
1976 const auto r1
1977 = __vector_bitcast<_UInt>(
1978 ((__vector_bitcast<int>(__x) << 16)
1979 >> ((__vector_bitcast<_UInt>(__y) << 16) >> 24)))
1980 & 0xff000000u;
1981 const auto r0 = __vector_bitcast<_UInt>(
1982 (__vector_bitcast<int>(__x) << 24)
1983 >> ((__vector_bitcast<_UInt>(__y) << 24) >> 24));
1984 return __vector_bitcast<_Up>(r3 | (r2 >> 8) | (r1 >> 16)
1985 | (r0 >> 24));
1986 }
1987 else
1988 {
1989 const auto r3 = (__vector_bitcast<_UInt>(__x)
1990 >> (__vector_bitcast<_UInt>(__y) >> 24))
1991 & 0xff000000u;
1992 const auto r2
1993 = ((__vector_bitcast<_UInt>(__x) << 8)
1994 >> ((__vector_bitcast<_UInt>(__y) << 8) >> 24))
1995 & 0xff000000u;
1996 const auto r1
1997 = ((__vector_bitcast<_UInt>(__x) << 16)
1998 >> ((__vector_bitcast<_UInt>(__y) << 16) >> 24))
1999 & 0xff000000u;
2000 const auto r0
2001 = (__vector_bitcast<_UInt>(__x) << 24)
2002 >> ((__vector_bitcast<_UInt>(__y) << 24) >> 24);
2003 return __vector_bitcast<_Up>(r3 | (r2 >> 8) | (r1 >> 16)
2004 | (r0 >> 24));
2005 }
2006 else if constexpr (__have_sse4_1
2007 && is_unsigned_v<_Up> && sizeof(__x) > 2)
2008 {
2009 auto __x128 = __vector_bitcast<_Up>(__ix);
2010 auto __mask
2011 = __vector_bitcast<_Up>(__vector_bitcast<_UShort>(__iy) << 5);
2012 auto __x4 = __vector_bitcast<_Up>(
2013 (__vector_bitcast<_UShort>(__x128) >> 4) & _UShort(0xff0f));
2014 __x128 = __vector_bitcast<_Up>(_CommonImplX86::_S_blend_intrin(
2015 __to_intrin(__mask), __to_intrin(__x128), __to_intrin(__x4)));
2016 __mask += __mask;
2017 auto __x2 = __vector_bitcast<_Up>(
2018 (__vector_bitcast<_UShort>(__x128) >> 2) & _UShort(0xff3f));
2019 __x128 = __vector_bitcast<_Up>(_CommonImplX86::_S_blend_intrin(
2020 __to_intrin(__mask), __to_intrin(__x128), __to_intrin(__x2)));
2021 __mask += __mask;
2022 auto __x1 = __vector_bitcast<_Up>(
2023 (__vector_bitcast<_UShort>(__x128) >> 1) & _UShort(0xff7f));
2024 __x128 = __vector_bitcast<_Up>(_CommonImplX86::_S_blend_intrin(
2025 __to_intrin(__mask), __to_intrin(__x128), __to_intrin(__x1)));
2026 return __intrin_bitcast<_V>(
2027 __x128
2028 & ((__vector_bitcast<_Up>(__iy) & char(0xf8))
2029 == 0)); // y > 7 nulls the result
2030 }
2031 else if constexpr (__have_sse4_1
2032 && is_signed_v<_Up> && sizeof(__x) > 2)
2033 {
2034 auto __mask = __vector_bitcast<_UChar>(
2035 __vector_bitcast<_UShort>(__iy) << 5);
2036 auto __maskl = [&]() _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
2037 return __to_intrin(__vector_bitcast<_UShort>(__mask) << 8);
2038 };
2039 auto __xh = __vector_bitcast<short>(__ix);
2040 auto __xl = __vector_bitcast<short>(__ix) << 8;
2041 auto __xh4 = __xh >> 4;
2042 auto __xl4 = __xl >> 4;
2043 __xh = __vector_bitcast<short>(_CommonImplX86::_S_blend_intrin(
2044 __to_intrin(__mask), __to_intrin(__xh), __to_intrin(__xh4)));
2045 __xl = __vector_bitcast<short>(
2046 _CommonImplX86::_S_blend_intrin(__maskl(), __to_intrin(__xl),
2047 __to_intrin(__xl4)));
2048 __mask += __mask;
2049 auto __xh2 = __xh >> 2;
2050 auto __xl2 = __xl >> 2;
2051 __xh = __vector_bitcast<short>(_CommonImplX86::_S_blend_intrin(
2052 __to_intrin(__mask), __to_intrin(__xh), __to_intrin(__xh2)));
2053 __xl = __vector_bitcast<short>(
2054 _CommonImplX86::_S_blend_intrin(__maskl(), __to_intrin(__xl),
2055 __to_intrin(__xl2)));
2056 __mask += __mask;
2057 auto __xh1 = __xh >> 1;
2058 auto __xl1 = __xl >> 1;
2059 __xh = __vector_bitcast<short>(_CommonImplX86::_S_blend_intrin(
2060 __to_intrin(__mask), __to_intrin(__xh), __to_intrin(__xh1)));
2061 __xl = __vector_bitcast<short>(
2062 _CommonImplX86::_S_blend_intrin(__maskl(), __to_intrin(__xl),
2063 __to_intrin(__xl1)));
2064 return __intrin_bitcast<_V>(
2065 (__vector_bitcast<_Up>((__xh & short(0xff00)))
2066 | __vector_bitcast<_Up>(__vector_bitcast<_UShort>(__xl)
2067 >> 8))
2068 & ((__vector_bitcast<_Up>(__iy) & char(0xf8))
2069 == 0)); // y > 7 nulls the result
2070 }
2071 else if constexpr (is_unsigned_v<_Up> && sizeof(__x) > 2) // SSE2
2072 {
2073 auto __mask
2074 = __vector_bitcast<_Up>(__vector_bitcast<_UShort>(__y) << 5);
2075 auto __x4 = __vector_bitcast<_Up>(
2076 (__vector_bitcast<_UShort>(__x) >> 4) & _UShort(0xff0f));
2077 __x = __mask > 0x7f ? __x4 : __x;
2078 __mask += __mask;
2079 auto __x2 = __vector_bitcast<_Up>(
2080 (__vector_bitcast<_UShort>(__x) >> 2) & _UShort(0xff3f));
2081 __x = __mask > 0x7f ? __x2 : __x;
2082 __mask += __mask;
2083 auto __x1 = __vector_bitcast<_Up>(
2084 (__vector_bitcast<_UShort>(__x) >> 1) & _UShort(0xff7f));
2085 __x = __mask > 0x7f ? __x1 : __x;
2086 return __x
2087 & ((__y & char(0xf8)) == 0); // y > 7 nulls the result
2088 }
2089 else if constexpr (sizeof(__x) > 2) // signed SSE2
2090 {
2091 static_assert(is_signed_v<_Up>);
2092 auto __maskh = __vector_bitcast<_UShort>(__y) << 5;
2093 auto __maskl = __vector_bitcast<_UShort>(__y) << (5 + 8);
2094 auto __xh = __vector_bitcast<short>(__x);
2095 auto __xl = __vector_bitcast<short>(__x) << 8;
2096 auto __xh4 = __xh >> 4;
2097 auto __xl4 = __xl >> 4;
2098 __xh = __maskh > 0x7fff ? __xh4 : __xh;
2099 __xl = __maskl > 0x7fff ? __xl4 : __xl;
2100 __maskh += __maskh;
2101 __maskl += __maskl;
2102 auto __xh2 = __xh >> 2;
2103 auto __xl2 = __xl >> 2;
2104 __xh = __maskh > 0x7fff ? __xh2 : __xh;
2105 __xl = __maskl > 0x7fff ? __xl2 : __xl;
2106 __maskh += __maskh;
2107 __maskl += __maskl;
2108 auto __xh1 = __xh >> 1;
2109 auto __xl1 = __xl >> 1;
2110 __xh = __maskh > 0x7fff ? __xh1 : __xh;
2111 __xl = __maskl > 0x7fff ? __xl1 : __xl;
2112 __x = __vector_bitcast<_Up>((__xh & short(0xff00)))
2113 | __vector_bitcast<_Up>(__vector_bitcast<_UShort>(__xl)
2114 >> 8);
2115 return __x
2116 & ((__y & char(0xf8)) == 0); // y > 7 nulls the result
2117 }
2118 else
2119 return __x >> __y;
2120 } //}}}
2121 else if constexpr (sizeof(_Up) == 2 && sizeof(__x) >= 4) //{{{
2122 {
2123 [[maybe_unused]] auto __blend_0xaa
2124 = [](auto __a, auto __b) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
2125 if constexpr (sizeof(__a) == 16)
2126 return _mm_blend_epi16(__to_intrin(__a), __to_intrin(__b),
2127 0xaa);
2128 else if constexpr (sizeof(__a) == 32)
2129 return _mm256_blend_epi16(__to_intrin(__a), __to_intrin(__b),
2130 0xaa);
2131 else if constexpr (sizeof(__a) == 64)
2132 return _mm512_mask_blend_epi16(0xaaaa'aaaaU, __to_intrin(__a),
2133 __to_intrin(__b));
2134 else
2135 __assert_unreachable<decltype(__a)>();
2136 };
2137 if constexpr (__have_avx512bw_vl && sizeof(_Tp) <= 16)
2138 return __intrin_bitcast<_V>(is_signed_v<_Up>
2139 ? _mm_srav_epi16(__ix, __iy)
2140 : _mm_srlv_epi16(__ix, __iy));
2141 else if constexpr (__have_avx512bw_vl && sizeof(_Tp) == 32)
2142 return __vector_bitcast<_Up>(is_signed_v<_Up>
2143 ? _mm256_srav_epi16(__ix, __iy)
2144 : _mm256_srlv_epi16(__ix, __iy));
2145 else if constexpr (__have_avx512bw && sizeof(_Tp) == 64)
2146 return __vector_bitcast<_Up>(is_signed_v<_Up>
2147 ? _mm512_srav_epi16(__ix, __iy)
2148 : _mm512_srlv_epi16(__ix, __iy));
2149 else if constexpr (__have_avx2 && is_signed_v<_Up>)
2150 return __intrin_bitcast<_V>(
2151 __blend_0xaa(((__vector_bitcast<int>(__ix) << 16)
2152 >> (__vector_bitcast<int>(__iy) & 0xffffu))
2153 >> 16,
2154 __vector_bitcast<int>(__ix)
2155 >> (__vector_bitcast<int>(__iy) >> 16)));
2156 else if constexpr (__have_avx2 && is_unsigned_v<_Up>)
2157 return __intrin_bitcast<_V>(
2158 __blend_0xaa((__vector_bitcast<_UInt>(__ix) & 0xffffu)
2159 >> (__vector_bitcast<_UInt>(__iy) & 0xffffu),
2160 __vector_bitcast<_UInt>(__ix)
2161 >> (__vector_bitcast<_UInt>(__iy) >> 16)));
2162 else if constexpr (__have_sse4_1)
2163 {
2164 auto __mask = __vector_bitcast<_UShort>(__iy);
2165 auto __x128 = __vector_bitcast<_Up>(__ix);
2166 //__mask *= 0x0808;
2167 __mask = (__mask << 3) | (__mask << 11);
2168 // do __x128 = 0 where __y[4] is set
2169 __x128 = __vector_bitcast<_Up>(
2170 _mm_blendv_epi8(__to_intrin(__x128), __m128i(),
2171 __to_intrin(__mask)));
2172 // do __x128 =>> 8 where __y[3] is set
2173 __x128 = __vector_bitcast<_Up>(
2174 _mm_blendv_epi8(__to_intrin(__x128), __to_intrin(__x128 >> 8),
2175 __to_intrin(__mask += __mask)));
2176 // do __x128 =>> 4 where __y[2] is set
2177 __x128 = __vector_bitcast<_Up>(
2178 _mm_blendv_epi8(__to_intrin(__x128), __to_intrin(__x128 >> 4),
2179 __to_intrin(__mask += __mask)));
2180 // do __x128 =>> 2 where __y[1] is set
2181 __x128 = __vector_bitcast<_Up>(
2182 _mm_blendv_epi8(__to_intrin(__x128), __to_intrin(__x128 >> 2),
2183 __to_intrin(__mask += __mask)));
2184 // do __x128 =>> 1 where __y[0] is set
2185 return __intrin_bitcast<_V>(
2186 _mm_blendv_epi8(__to_intrin(__x128), __to_intrin(__x128 >> 1),
2187 __to_intrin(__mask + __mask)));
2188 }
2189 else
2190 {
2191 auto __k = __vector_bitcast<_UShort>(__iy) << 11;
2192 auto __x128 = __vector_bitcast<_Up>(__ix);
2193 auto __mask
2194 = [](__vector_type16_t<_UShort> __kk) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
2195 return __vector_bitcast<short>(__kk) < 0;
2196 };
2197 // do __x128 = 0 where __y[4] is set
2198 __x128 = __mask(__k) ? decltype(__x128)() : __x128;
2199 // do __x128 =>> 8 where __y[3] is set
2200 __x128 = __mask(__k += __k) ? __x128 >> 8 : __x128;
2201 // do __x128 =>> 4 where __y[2] is set
2202 __x128 = __mask(__k += __k) ? __x128 >> 4 : __x128;
2203 // do __x128 =>> 2 where __y[1] is set
2204 __x128 = __mask(__k += __k) ? __x128 >> 2 : __x128;
2205 // do __x128 =>> 1 where __y[0] is set
2206 return __intrin_bitcast<_V>(__mask(__k + __k) ? __x128 >> 1
2207 : __x128);
2208 }
2209 } //}}}
2210 else if constexpr (sizeof(_Up) == 4 && !__have_avx2) //{{{
2211 {
2212 if constexpr (is_unsigned_v<_Up>)
2213 {
2214 // x >> y == x * 2^-y == (x * 2^(31-y)) >> 31
2215 const __m128 __factor_f = reinterpret_cast<__m128>(
2216 0x4f00'0000u - (__vector_bitcast<unsigned, 4>(__y) << 23));
2217 const __m128i __factor
2218 = __builtin_constant_p(__factor_f)
2219 ? __to_intrin(
2220 __make_vector<unsigned>(__factor_f[0], __factor_f[1],
2221 __factor_f[2], __factor_f[3]))
2222 : _mm_cvttps_epi32(__factor_f);
2223 const auto __r02
2224 = _mm_srli_epi64(_mm_mul_epu32(__ix, __factor), 31);
2225 const auto __r13 = _mm_mul_epu32(_mm_srli_si128(__ix, 4),
2226 _mm_srli_si128(__factor, 4));
2227 if constexpr (__have_sse4_1)
2228 return __intrin_bitcast<_V>(
2229 _mm_blend_epi16(_mm_slli_epi64(__r13, 1), __r02, 0x33));
2230 else
2231 return __intrin_bitcast<_V>(
2232 __r02 | _mm_slli_si128(_mm_srli_epi64(__r13, 31), 4));
2233 }
2234 else
2235 {
2236 auto __shift = [](auto __a, auto __b) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
2237 if constexpr (is_signed_v<_Up>)
2238 return _mm_sra_epi32(__a, __b);
2239 else
2240 return _mm_srl_epi32(__a, __b);
2241 };
2242 const auto __r0
2243 = __shift(__ix, _mm_unpacklo_epi32(__iy, __m128i()));
2244 const auto __r1 = __shift(__ix, _mm_srli_epi64(__iy, 32));
2245 const auto __r2
2246 = __shift(__ix, _mm_unpackhi_epi32(__iy, __m128i()));
2247 const auto __r3 = __shift(__ix, _mm_srli_si128(__iy, 12));
2248 if constexpr (__have_sse4_1)
2249 return __intrin_bitcast<_V>(
2250 _mm_blend_epi16(_mm_blend_epi16(__r1, __r0, 0x3),
2251 _mm_blend_epi16(__r3, __r2, 0x30), 0xf0));
2252 else
2253 return __intrin_bitcast<_V>(_mm_unpacklo_epi64(
2254 _mm_unpacklo_epi32(__r0, _mm_srli_si128(__r1, 4)),
2255 _mm_unpackhi_epi32(__r2, _mm_srli_si128(__r3, 4))));
2256 }
2257 } //}}}
2258 else
2259 return __x >> __y;
2260 }
2261#endif // _GLIBCXX_SIMD_NO_SHIFT_OPT
2262
2263 // }}}
2264 // compares {{{
2265 // _S_equal_to {{{
2266 template <typename _Tp, size_t _Np>
2267 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
2268 _S_equal_to(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
2269 {
2270 if constexpr (__is_avx512_abi<_Abi>()) // {{{
2271 {
2272 if (__builtin_is_constant_evaluated()
2273 || (__x._M_is_constprop() && __y._M_is_constprop()))
2274 return _MaskImpl::_S_to_bits(
2275 __as_wrapper<_Np>(__x._M_data == __y._M_data));
2276
2277 constexpr auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
2278 [[maybe_unused]] const auto __xi = __to_intrin(__x);
2279 [[maybe_unused]] const auto __yi = __to_intrin(__y);
2280 if constexpr (is_floating_point_v<_Tp>)
2281 {
2282 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
2283 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_EQ_OQ);
2284 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
2285 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_EQ_OQ);
2286 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
2287 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_EQ_OQ);
2288 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
2289 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_EQ_OQ);
2290 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
2291 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_EQ_OQ);
2292 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
2293 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_EQ_OQ);
2294 else
2295 __assert_unreachable<_Tp>();
2296 }
2297 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
2298 return _mm512_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
2299 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
2300 return _mm512_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
2301 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 2)
2302 return _mm512_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
2303 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 1)
2304 return _mm512_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
2305 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
2306 return _mm256_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
2307 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
2308 return _mm256_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
2309 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 2)
2310 return _mm256_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
2311 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 1)
2312 return _mm256_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
2313 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
2314 return _mm_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
2315 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
2316 return _mm_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
2317 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 2)
2318 return _mm_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
2319 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 1)
2320 return _mm_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
2321 else
2322 __assert_unreachable<_Tp>();
2323 } // }}}
2324 else if (__builtin_is_constant_evaluated())
2325 return _Base::_S_equal_to(__x, __y);
2326 else if constexpr (sizeof(__x) == 8)
2327 {
2328 const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
2329 == __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
2330 _MaskMember<_Tp> __r64{};
2331 __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
2332 return __r64;
2333 }
2334 else
2335 return _Base::_S_equal_to(__x, __y);
2336 }
2337
2338 // }}}
2339 // _S_not_equal_to {{{
2340 template <typename _Tp, size_t _Np>
2341 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
2342 _S_not_equal_to(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
2343 {
2344 if constexpr (__is_avx512_abi<_Abi>()) // {{{
2345 {
2346 if (__builtin_is_constant_evaluated()
2347 || (__x._M_is_constprop() && __y._M_is_constprop()))
2348 return _MaskImpl::_S_to_bits(
2349 __as_wrapper<_Np>(__x._M_data != __y._M_data));
2350
2351 constexpr auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
2352 [[maybe_unused]] const auto __xi = __to_intrin(__x);
2353 [[maybe_unused]] const auto __yi = __to_intrin(__y);
2354 if constexpr (is_floating_point_v<_Tp>)
2355 {
2356 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
2357 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_NEQ_UQ);
2358 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
2359 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_NEQ_UQ);
2360 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
2361 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_NEQ_UQ);
2362 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
2363 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_NEQ_UQ);
2364 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
2365 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_NEQ_UQ);
2366 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
2367 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_NEQ_UQ);
2368 else
2369 __assert_unreachable<_Tp>();
2370 }
2371 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
2372 return ~_mm512_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
2373 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
2374 return ~_mm512_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
2375 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 2)
2376 return ~_mm512_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
2377 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 1)
2378 return ~_mm512_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
2379 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
2380 return ~_mm256_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
2381 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
2382 return ~_mm256_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
2383 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 2)
2384 return ~_mm256_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
2385 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 1)
2386 return ~_mm256_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
2387 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
2388 return ~_mm_mask_cmpeq_epi64_mask(__k1, __xi, __yi);
2389 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
2390 return ~_mm_mask_cmpeq_epi32_mask(__k1, __xi, __yi);
2391 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 2)
2392 return ~_mm_mask_cmpeq_epi16_mask(__k1, __xi, __yi);
2393 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 1)
2394 return ~_mm_mask_cmpeq_epi8_mask(__k1, __xi, __yi);
2395 else
2396 __assert_unreachable<_Tp>();
2397 } // }}}
2398 else if (__builtin_is_constant_evaluated())
2399 return _Base::_S_not_equal_to(__x, __y);
2400 else if constexpr (sizeof(__x) == 8)
2401 {
2402 const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
2403 != __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
2404 _MaskMember<_Tp> __r64{};
2405 __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
2406 return __r64;
2407 }
2408 else
2409 return _Base::_S_not_equal_to(__x, __y);
2410 }
2411
2412 // }}}
2413 // _S_less {{{
2414 template <typename _Tp, size_t _Np>
2415 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
2416 _S_less(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
2417 {
2418 if constexpr (__is_avx512_abi<_Abi>()) // {{{
2419 {
2420 if (__builtin_is_constant_evaluated()
2421 || (__x._M_is_constprop() && __y._M_is_constprop()))
2422 return _MaskImpl::_S_to_bits(
2423 __as_wrapper<_Np>(__x._M_data < __y._M_data));
2424
2425 constexpr auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
2426 [[maybe_unused]] const auto __xi = __to_intrin(__x);
2427 [[maybe_unused]] const auto __yi = __to_intrin(__y);
2428 if constexpr (sizeof(__xi) == 64)
2429 {
2430 if constexpr (is_same_v<_Tp, float>)
2431 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LT_OS);
2432 else if constexpr (is_same_v<_Tp, double>)
2433 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LT_OS);
2434 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 1)
2435 return _mm512_mask_cmplt_epi8_mask(__k1, __xi, __yi);
2436 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 2)
2437 return _mm512_mask_cmplt_epi16_mask(__k1, __xi, __yi);
2438 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 4)
2439 return _mm512_mask_cmplt_epi32_mask(__k1, __xi, __yi);
2440 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 8)
2441 return _mm512_mask_cmplt_epi64_mask(__k1, __xi, __yi);
2442 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 1)
2443 return _mm512_mask_cmplt_epu8_mask(__k1, __xi, __yi);
2444 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 2)
2445 return _mm512_mask_cmplt_epu16_mask(__k1, __xi, __yi);
2446 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 4)
2447 return _mm512_mask_cmplt_epu32_mask(__k1, __xi, __yi);
2448 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 8)
2449 return _mm512_mask_cmplt_epu64_mask(__k1, __xi, __yi);
2450 else
2451 __assert_unreachable<_Tp>();
2452 }
2453 else if constexpr (sizeof(__xi) == 32)
2454 {
2455 if constexpr (is_same_v<_Tp, float>)
2456 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LT_OS);
2457 else if constexpr (is_same_v<_Tp, double>)
2458 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LT_OS);
2459 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 1)
2460 return _mm256_mask_cmplt_epi8_mask(__k1, __xi, __yi);
2461 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 2)
2462 return _mm256_mask_cmplt_epi16_mask(__k1, __xi, __yi);
2463 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 4)
2464 return _mm256_mask_cmplt_epi32_mask(__k1, __xi, __yi);
2465 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 8)
2466 return _mm256_mask_cmplt_epi64_mask(__k1, __xi, __yi);
2467 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 1)
2468 return _mm256_mask_cmplt_epu8_mask(__k1, __xi, __yi);
2469 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 2)
2470 return _mm256_mask_cmplt_epu16_mask(__k1, __xi, __yi);
2471 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 4)
2472 return _mm256_mask_cmplt_epu32_mask(__k1, __xi, __yi);
2473 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 8)
2474 return _mm256_mask_cmplt_epu64_mask(__k1, __xi, __yi);
2475 else
2476 __assert_unreachable<_Tp>();
2477 }
2478 else if constexpr (sizeof(__xi) == 16)
2479 {
2480 if constexpr (is_same_v<_Tp, float>)
2481 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LT_OS);
2482 else if constexpr (is_same_v<_Tp, double>)
2483 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LT_OS);
2484 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 1)
2485 return _mm_mask_cmplt_epi8_mask(__k1, __xi, __yi);
2486 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 2)
2487 return _mm_mask_cmplt_epi16_mask(__k1, __xi, __yi);
2488 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 4)
2489 return _mm_mask_cmplt_epi32_mask(__k1, __xi, __yi);
2490 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 8)
2491 return _mm_mask_cmplt_epi64_mask(__k1, __xi, __yi);
2492 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 1)
2493 return _mm_mask_cmplt_epu8_mask(__k1, __xi, __yi);
2494 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 2)
2495 return _mm_mask_cmplt_epu16_mask(__k1, __xi, __yi);
2496 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 4)
2497 return _mm_mask_cmplt_epu32_mask(__k1, __xi, __yi);
2498 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 8)
2499 return _mm_mask_cmplt_epu64_mask(__k1, __xi, __yi);
2500 else
2501 __assert_unreachable<_Tp>();
2502 }
2503 else
2504 __assert_unreachable<_Tp>();
2505 } // }}}
2506 else if (__builtin_is_constant_evaluated())
2507 return _Base::_S_less(__x, __y);
2508 else if constexpr (sizeof(__x) == 8)
2509 {
2510 const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
2511 < __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
2512 _MaskMember<_Tp> __r64{};
2513 __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
2514 return __r64;
2515 }
2516 else
2517 return _Base::_S_less(__x, __y);
2518 }
2519
2520 // }}}
2521 // _S_less_equal {{{
2522 template <typename _Tp, size_t _Np>
2523 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
2524 _S_less_equal(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
2525 {
2526 if constexpr (__is_avx512_abi<_Abi>()) // {{{
2527 {
2528 if (__builtin_is_constant_evaluated()
2529 || (__x._M_is_constprop() && __y._M_is_constprop()))
2530 return _MaskImpl::_S_to_bits(
2531 __as_wrapper<_Np>(__x._M_data <= __y._M_data));
2532
2533 constexpr auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
2534 [[maybe_unused]] const auto __xi = __to_intrin(__x);
2535 [[maybe_unused]] const auto __yi = __to_intrin(__y);
2536 if constexpr (sizeof(__xi) == 64)
2537 {
2538 if constexpr (is_same_v<_Tp, float>)
2539 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LE_OS);
2540 else if constexpr (is_same_v<_Tp, double>)
2541 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LE_OS);
2542 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 1)
2543 return _mm512_mask_cmple_epi8_mask(__k1, __xi, __yi);
2544 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 2)
2545 return _mm512_mask_cmple_epi16_mask(__k1, __xi, __yi);
2546 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 4)
2547 return _mm512_mask_cmple_epi32_mask(__k1, __xi, __yi);
2548 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 8)
2549 return _mm512_mask_cmple_epi64_mask(__k1, __xi, __yi);
2550 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 1)
2551 return _mm512_mask_cmple_epu8_mask(__k1, __xi, __yi);
2552 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 2)
2553 return _mm512_mask_cmple_epu16_mask(__k1, __xi, __yi);
2554 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 4)
2555 return _mm512_mask_cmple_epu32_mask(__k1, __xi, __yi);
2556 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 8)
2557 return _mm512_mask_cmple_epu64_mask(__k1, __xi, __yi);
2558 else
2559 __assert_unreachable<_Tp>();
2560 }
2561 else if constexpr (sizeof(__xi) == 32)
2562 {
2563 if constexpr (is_same_v<_Tp, float>)
2564 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LE_OS);
2565 else if constexpr (is_same_v<_Tp, double>)
2566 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LE_OS);
2567 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 1)
2568 return _mm256_mask_cmple_epi8_mask(__k1, __xi, __yi);
2569 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 2)
2570 return _mm256_mask_cmple_epi16_mask(__k1, __xi, __yi);
2571 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 4)
2572 return _mm256_mask_cmple_epi32_mask(__k1, __xi, __yi);
2573 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 8)
2574 return _mm256_mask_cmple_epi64_mask(__k1, __xi, __yi);
2575 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 1)
2576 return _mm256_mask_cmple_epu8_mask(__k1, __xi, __yi);
2577 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 2)
2578 return _mm256_mask_cmple_epu16_mask(__k1, __xi, __yi);
2579 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 4)
2580 return _mm256_mask_cmple_epu32_mask(__k1, __xi, __yi);
2581 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 8)
2582 return _mm256_mask_cmple_epu64_mask(__k1, __xi, __yi);
2583 else
2584 __assert_unreachable<_Tp>();
2585 }
2586 else if constexpr (sizeof(__xi) == 16)
2587 {
2588 if constexpr (is_same_v<_Tp, float>)
2589 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LE_OS);
2590 else if constexpr (is_same_v<_Tp, double>)
2591 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LE_OS);
2592 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 1)
2593 return _mm_mask_cmple_epi8_mask(__k1, __xi, __yi);
2594 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 2)
2595 return _mm_mask_cmple_epi16_mask(__k1, __xi, __yi);
2596 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 4)
2597 return _mm_mask_cmple_epi32_mask(__k1, __xi, __yi);
2598 else if constexpr (is_signed_v<_Tp> && sizeof(_Tp) == 8)
2599 return _mm_mask_cmple_epi64_mask(__k1, __xi, __yi);
2600 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 1)
2601 return _mm_mask_cmple_epu8_mask(__k1, __xi, __yi);
2602 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 2)
2603 return _mm_mask_cmple_epu16_mask(__k1, __xi, __yi);
2604 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 4)
2605 return _mm_mask_cmple_epu32_mask(__k1, __xi, __yi);
2606 else if constexpr (is_unsigned_v<_Tp> && sizeof(_Tp) == 8)
2607 return _mm_mask_cmple_epu64_mask(__k1, __xi, __yi);
2608 else
2609 __assert_unreachable<_Tp>();
2610 }
2611 else
2612 __assert_unreachable<_Tp>();
2613 } // }}}
2614 else if (__builtin_is_constant_evaluated())
2615 return _Base::_S_less_equal(__x, __y);
2616 else if constexpr (sizeof(__x) == 8)
2617 {
2618 const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
2619 <= __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
2620 _MaskMember<_Tp> __r64{};
2621 __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
2622 return __r64;
2623 }
2624 else
2625 return _Base::_S_less_equal(__x, __y);
2626 }
2627
2628 // }}} }}}
2629 // negation {{{
2630 template <typename _Tp, size_t _Np>
2631 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
2632 _S_negate(_SimdWrapper<_Tp, _Np> __x) noexcept
2633 {
2634 if constexpr (__is_avx512_abi<_Abi>())
2635 return _S_equal_to(__x, _SimdWrapper<_Tp, _Np>());
2636 else
2637 return _Base::_S_negate(__x);
2638 }
2639
2640 // }}}
2641 // math {{{
2642 using _Base::_S_abs;
2643
2644 // _S_sqrt {{{
2645 template <typename _Tp, size_t _Np>
2646 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
2647 _S_sqrt(_SimdWrapper<_Tp, _Np> __x)
2648 {
2649 if constexpr (__is_sse_ps<_Tp, _Np>())
2650 return __auto_bitcast(_mm_sqrt_ps(__to_intrin(__x)));
2651 else if constexpr (__is_sse_pd<_Tp, _Np>())
2652 return _mm_sqrt_pd(__x);
2653 else if constexpr (__is_avx_ps<_Tp, _Np>())
2654 return _mm256_sqrt_ps(__x);
2655 else if constexpr (__is_avx_pd<_Tp, _Np>())
2656 return _mm256_sqrt_pd(__x);
2657 else if constexpr (__is_avx512_ps<_Tp, _Np>())
2658 return _mm512_sqrt_ps(__x);
2659 else if constexpr (__is_avx512_pd<_Tp, _Np>())
2660 return _mm512_sqrt_pd(__x);
2661 else
2662 __assert_unreachable<_Tp>();
2663 }
2664
2665 // }}}
2666 // _S_ldexp {{{
2667 template <typename _Tp, size_t _Np>
2668 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
2669 _S_ldexp(_SimdWrapper<_Tp, _Np> __x,
2670 __fixed_size_storage_t<int, _Np> __exp)
2671 {
2672 if constexpr (sizeof(__x) == 64 || __have_avx512vl)
2673 {
2674 const auto __xi = __to_intrin(__x);
2675 constexpr _SimdConverter<int, simd_abi::fixed_size<_Np>, _Tp, _Abi>
2676 __cvt;
2677 const auto __expi = __to_intrin(__cvt(__exp));
2678 using _Up = __bool_storage_member_type_t<_Np>;
2679 constexpr _Up __k1 = _Np < sizeof(_Up) * __CHAR_BIT__ ? _Up((1ULL << _Np) - 1) : ~_Up();
2680 if constexpr (sizeof(__xi) == 16)
2681 {
2682 if constexpr (sizeof(_Tp) == 8)
2683 return _mm_maskz_scalef_pd(__k1, __xi, __expi);
2684 else
2685 return _mm_maskz_scalef_ps(__k1, __xi, __expi);
2686 }
2687 else if constexpr (sizeof(__xi) == 32)
2688 {
2689 if constexpr (sizeof(_Tp) == 8)
2690 return _mm256_maskz_scalef_pd(__k1, __xi, __expi);
2691 else
2692 return _mm256_maskz_scalef_ps(__k1, __xi, __expi);
2693 }
2694 else
2695 {
2696 static_assert(sizeof(__xi) == 64);
2697 if constexpr (sizeof(_Tp) == 8)
2698 return _mm512_maskz_scalef_pd(__k1, __xi, __expi);
2699 else
2700 return _mm512_maskz_scalef_ps(__k1, __xi, __expi);
2701 }
2702 }
2703 else
2704 return _Base::_S_ldexp(__x, __exp);
2705 }
2706
2707 // }}}
2708 // _S_trunc {{{
2709 template <typename _Tp, size_t _Np>
2710 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
2711 _S_trunc(_SimdWrapper<_Tp, _Np> __x)
2712 {
2713 if constexpr (__is_avx512_ps<_Tp, _Np>())
2714 return _mm512_roundscale_ps(__x, 0x0b);
2715 else if constexpr (__is_avx512_pd<_Tp, _Np>())
2716 return _mm512_roundscale_pd(__x, 0x0b);
2717 else if constexpr (__is_avx_ps<_Tp, _Np>())
2718 return _mm256_round_ps(__x, 0xb);
2719 else if constexpr (__is_avx_pd<_Tp, _Np>())
2720 return _mm256_round_pd(__x, 0xb);
2721 else if constexpr (__have_sse4_1 && __is_sse_ps<_Tp, _Np>())
2722 return __auto_bitcast(_mm_round_ps(__to_intrin(__x), 0xb));
2723 else if constexpr (__have_sse4_1 && __is_sse_pd<_Tp, _Np>())
2724 return _mm_round_pd(__x, 0xb);
2725 else if constexpr (__is_sse_ps<_Tp, _Np>())
2726 {
2727 auto __truncated
2728 = _mm_cvtepi32_ps(_mm_cvttps_epi32(__to_intrin(__x)));
2729 const auto __no_fractional_values
2730 = __vector_bitcast<int>(__vector_bitcast<_UInt>(__to_intrin(__x))
2731 & 0x7f800000u)
2732 < 0x4b000000; // the exponent is so large that no mantissa bits
2733 // signify fractional values (0x3f8 + 23*8 =
2734 // 0x4b0)
2735 return __no_fractional_values ? __truncated : __to_intrin(__x);
2736 }
2737 else
2738 return _Base::_S_trunc(__x);
2739 }
2740
2741 // }}}
2742 // _S_round {{{
2743 template <typename _Tp, size_t _Np>
2744 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
2745 _S_round(_SimdWrapper<_Tp, _Np> __x)
2746 {
2747 // Note that _MM_FROUND_TO_NEAREST_INT rounds ties to even, not away
2748 // from zero as required by std::round. Therefore this function is more
2749 // complicated.
2750 using _V = __vector_type_t<_Tp, _Np>;
2751 _V __truncated;
2752 if constexpr (__is_avx512_ps<_Tp, _Np>())
2753 __truncated = _mm512_roundscale_ps(__x._M_data, 0x0b);
2754 else if constexpr (__is_avx512_pd<_Tp, _Np>())
2755 __truncated = _mm512_roundscale_pd(__x._M_data, 0x0b);
2756 else if constexpr (__is_avx_ps<_Tp, _Np>())
2757 __truncated = _mm256_round_ps(__x._M_data,
2758 _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
2759 else if constexpr (__is_avx_pd<_Tp, _Np>())
2760 __truncated = _mm256_round_pd(__x._M_data,
2761 _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
2762 else if constexpr (__have_sse4_1 && __is_sse_ps<_Tp, _Np>())
2763 __truncated = __auto_bitcast(
2764 _mm_round_ps(__to_intrin(__x),
2765 _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
2766 else if constexpr (__have_sse4_1 && __is_sse_pd<_Tp, _Np>())
2767 __truncated
2768 = _mm_round_pd(__x._M_data, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
2769 else if constexpr (__is_sse_ps<_Tp, _Np>())
2770 __truncated = __auto_bitcast(
2771 _mm_cvtepi32_ps(_mm_cvttps_epi32(__to_intrin(__x))));
2772 else
2773 return _Base::_S_round(__x);
2774
2775 // x < 0 => truncated <= 0 && truncated >= x => x - truncated <= 0
2776 // x > 0 => truncated >= 0 && truncated <= x => x - truncated >= 0
2777
2778 const _V __rounded
2779 = __truncated
2780 + (__and(_S_absmask<_V>, __x._M_data - __truncated) >= _Tp(.5)
2781 ? __or(__and(_S_signmask<_V>, __x._M_data), _V() + 1)
2782 : _V());
2783 if constexpr (__have_sse4_1)
2784 return __rounded;
2785 else // adjust for missing range in cvttps_epi32
2786 return __and(_S_absmask<_V>, __x._M_data) < 0x1p23f ? __rounded
2787 : __x._M_data;
2788 }
2789
2790 // }}}
2791 // _S_nearbyint {{{
2792 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
2793 _GLIBCXX_SIMD_INTRINSIC static _Tp
2794 _S_nearbyint(_Tp __x) noexcept
2795 {
2796 if constexpr (_TVT::template _S_is<float, 16>)
2797 return _mm512_roundscale_ps(__x, 0x0c);
2798 else if constexpr (_TVT::template _S_is<double, 8>)
2799 return _mm512_roundscale_pd(__x, 0x0c);
2800 else if constexpr (_TVT::template _S_is<float, 8>)
2801 return _mm256_round_ps(__x,
2802 _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC);
2803 else if constexpr (_TVT::template _S_is<double, 4>)
2804 return _mm256_round_pd(__x,
2805 _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC);
2806 else if constexpr (__have_sse4_1 && _TVT::template _S_is<float, 4>)
2807 return _mm_round_ps(__x,
2808 _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC);
2809 else if constexpr (__have_sse4_1 && _TVT::template _S_is<double, 2>)
2810 return _mm_round_pd(__x,
2811 _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC);
2812 else
2813 return _Base::_S_nearbyint(__x);
2814 }
2815
2816 // }}}
2817 // _S_rint {{{
2818 template <typename _Tp, typename _TVT = _VectorTraits<_Tp>>
2819 _GLIBCXX_SIMD_INTRINSIC static _Tp
2820 _S_rint(_Tp __x) noexcept
2821 {
2822 if constexpr (_TVT::template _S_is<float, 16>)
2823 return _mm512_roundscale_ps(__x, 0x04);
2824 else if constexpr (_TVT::template _S_is<double, 8>)
2825 return _mm512_roundscale_pd(__x, 0x04);
2826 else if constexpr (_TVT::template _S_is<float, 8>)
2827 return _mm256_round_ps(__x, _MM_FROUND_CUR_DIRECTION);
2828 else if constexpr (_TVT::template _S_is<double, 4>)
2829 return _mm256_round_pd(__x, _MM_FROUND_CUR_DIRECTION);
2830 else if constexpr (__have_sse4_1 && _TVT::template _S_is<float, 4>)
2831 return _mm_round_ps(__x, _MM_FROUND_CUR_DIRECTION);
2832 else if constexpr (__have_sse4_1 && _TVT::template _S_is<double, 2>)
2833 return _mm_round_pd(__x, _MM_FROUND_CUR_DIRECTION);
2834 else
2835 return _Base::_S_rint(__x);
2836 }
2837
2838 // }}}
2839 // _S_floor {{{
2840 template <typename _Tp, size_t _Np>
2841 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
2842 _S_floor(_SimdWrapper<_Tp, _Np> __x)
2843 {
2844 if constexpr (__is_avx512_ps<_Tp, _Np>())
2845 return _mm512_roundscale_ps(__x, 0x09);
2846 else if constexpr (__is_avx512_pd<_Tp, _Np>())
2847 return _mm512_roundscale_pd(__x, 0x09);
2848 else if constexpr (__is_avx_ps<_Tp, _Np>())
2849 return _mm256_round_ps(__x, 0x9);
2850 else if constexpr (__is_avx_pd<_Tp, _Np>())
2851 return _mm256_round_pd(__x, 0x9);
2852 else if constexpr (__have_sse4_1 && __is_sse_ps<_Tp, _Np>())
2853 return __auto_bitcast(_mm_round_ps(__to_intrin(__x), 0x9));
2854 else if constexpr (__have_sse4_1 && __is_sse_pd<_Tp, _Np>())
2855 return _mm_round_pd(__x, 0x9);
2856 else
2857 return _Base::_S_floor(__x);
2858 }
2859
2860 // }}}
2861 // _S_ceil {{{
2862 template <typename _Tp, size_t _Np>
2863 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
2864 _S_ceil(_SimdWrapper<_Tp, _Np> __x)
2865 {
2866 if constexpr (__is_avx512_ps<_Tp, _Np>())
2867 return _mm512_roundscale_ps(__x, 0x0a);
2868 else if constexpr (__is_avx512_pd<_Tp, _Np>())
2869 return _mm512_roundscale_pd(__x, 0x0a);
2870 else if constexpr (__is_avx_ps<_Tp, _Np>())
2871 return _mm256_round_ps(__x, 0xa);
2872 else if constexpr (__is_avx_pd<_Tp, _Np>())
2873 return _mm256_round_pd(__x, 0xa);
2874 else if constexpr (__have_sse4_1 && __is_sse_ps<_Tp, _Np>())
2875 return __auto_bitcast(_mm_round_ps(__to_intrin(__x), 0xa));
2876 else if constexpr (__have_sse4_1 && __is_sse_pd<_Tp, _Np>())
2877 return _mm_round_pd(__x, 0xa);
2878 else
2879 return _Base::_S_ceil(__x);
2880 }
2881
2882 // }}}
2883 // _S_signbit {{{
2884 template <typename _Tp, size_t _Np>
2885 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
2886 _S_signbit(_SimdWrapper<_Tp, _Np> __x)
2887 {
2888 if constexpr (__is_avx512_abi<_Abi>() && __have_avx512dq)
2889 {
2890 if constexpr (sizeof(__x) == 64 && sizeof(_Tp) == 4)
2891 return _mm512_movepi32_mask(
2892 __intrin_bitcast<__m512i>(__x._M_data));
2893 else if constexpr (sizeof(__x) == 64 && sizeof(_Tp) == 8)
2894 return _mm512_movepi64_mask(
2895 __intrin_bitcast<__m512i>(__x._M_data));
2896 else if constexpr (sizeof(__x) == 32 && sizeof(_Tp) == 4)
2897 return _mm256_movepi32_mask(
2898 __intrin_bitcast<__m256i>(__x._M_data));
2899 else if constexpr (sizeof(__x) == 32 && sizeof(_Tp) == 8)
2900 return _mm256_movepi64_mask(
2901 __intrin_bitcast<__m256i>(__x._M_data));
2902 else if constexpr (sizeof(__x) <= 16 && sizeof(_Tp) == 4)
2903 return _mm_movepi32_mask(__intrin_bitcast<__m128i>(__x._M_data));
2904 else if constexpr (sizeof(__x) <= 16 && sizeof(_Tp) == 8)
2905 return _mm_movepi64_mask(__intrin_bitcast<__m128i>(__x._M_data));
2906 }
2907 else if constexpr (__is_avx512_abi<_Abi>())
2908 {
2909 const auto __xi = __to_intrin(__x);
2910 [[maybe_unused]] constexpr auto __k1
2911 = _Abi::template _S_implicit_mask_intrin<_Tp>();
2912 if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
2913 return _mm_movemask_ps(__xi);
2914 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
2915 return _mm_movemask_pd(__xi);
2916 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
2917 return _mm256_movemask_ps(__xi);
2918 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
2919 return _mm256_movemask_pd(__xi);
2920 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
2921 return _mm512_mask_cmplt_epi32_mask(
2922 __k1, __intrin_bitcast<__m512i>(__xi), __m512i());
2923 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
2924 return _mm512_mask_cmplt_epi64_mask(
2925 __k1, __intrin_bitcast<__m512i>(__xi), __m512i());
2926 else
2927 __assert_unreachable<_Tp>();
2928 }
2929 else
2930 return _Base::_S_signbit(__x);
2931 /*{
2932 using _I = __int_for_sizeof_t<_Tp>;
2933 if constexpr (sizeof(__x) == 64)
2934 return _S_less(__vector_bitcast<_I>(__x), _I());
2935 else
2936 {
2937 const auto __xx = __vector_bitcast<_I>(__x._M_data);
2938 [[maybe_unused]] constexpr _I __signmask = __finite_min_v<_I>;
2939 if constexpr ((sizeof(_Tp) == 4 &&
2940 (__have_avx2 || sizeof(__x) == 16)) ||
2941 __have_avx512vl)
2942 {
2943 return __vector_bitcast<_Tp>(__xx >> __digits_v<_I>);
2944 }
2945 else if constexpr ((__have_avx2 ||
2946 (__have_ssse3 && sizeof(__x) == 16)))
2947 {
2948 return __vector_bitcast<_Tp>((__xx & __signmask) ==
2949 __signmask);
2950 }
2951 else
2952 { // SSE2/3 or AVX (w/o AVX2)
2953 constexpr auto __one = __vector_broadcast<_Np, _Tp>(1);
2954 return __vector_bitcast<_Tp>(
2955 __vector_bitcast<_Tp>(
2956 (__xx & __signmask) |
2957 __vector_bitcast<_I>(__one)) // -1 or 1
2958 != __one);
2959 }
2960 }
2961 }*/
2962 }
2963
2964 // }}}
2965 // _S_isnonzerovalue_mask {{{
2966 // (isnormal | is subnormal == !isinf & !isnan & !is zero)
2967 template <typename _Tp>
2968 _GLIBCXX_SIMD_INTRINSIC static auto
2969 _S_isnonzerovalue_mask(_Tp __x)
2970 {
2971 using _Traits = _VectorTraits<_Tp>;
2972 if constexpr (__have_avx512dq_vl)
2973 {
2974 if constexpr (_Traits::template _S_is<
2975 float, 2> || _Traits::template _S_is<float, 4>)
2976 return _knot_mask8(_mm_fpclass_ps_mask(__to_intrin(__x), 0x9f));
2977 else if constexpr (_Traits::template _S_is<float, 8>)
2978 return _knot_mask8(_mm256_fpclass_ps_mask(__x, 0x9f));
2979 else if constexpr (_Traits::template _S_is<float, 16>)
2980 return _knot_mask16(_mm512_fpclass_ps_mask(__x, 0x9f));
2981 else if constexpr (_Traits::template _S_is<double, 2>)
2982 return _knot_mask8(_mm_fpclass_pd_mask(__x, 0x9f));
2983 else if constexpr (_Traits::template _S_is<double, 4>)
2984 return _knot_mask8(_mm256_fpclass_pd_mask(__x, 0x9f));
2985 else if constexpr (_Traits::template _S_is<double, 8>)
2986 return _knot_mask8(_mm512_fpclass_pd_mask(__x, 0x9f));
2987 else
2988 __assert_unreachable<_Tp>();
2989 }
2990 else
2991 {
2992 using _Up = typename _Traits::value_type;
2993 constexpr size_t _Np = _Traits::_S_full_size;
2994 const auto __a = __x * __infinity_v<_Up>; // NaN if __x == 0
2995 const auto __b = __x * _Up(); // NaN if __x == inf
2996 if constexpr (__have_avx512vl && __is_sse_ps<_Up, _Np>())
2997 return _mm_cmp_ps_mask(__to_intrin(__a), __to_intrin(__b),
2998 _CMP_ORD_Q);
2999 else if constexpr (__have_avx512f && __is_sse_ps<_Up, _Np>())
3000 return __mmask8(0xf
3001 & _mm512_cmp_ps_mask(__auto_bitcast(__a),
3002 __auto_bitcast(__b),
3003 _CMP_ORD_Q));
3004 else if constexpr (__have_avx512vl && __is_sse_pd<_Up, _Np>())
3005 return _mm_cmp_pd_mask(__a, __b, _CMP_ORD_Q);
3006 else if constexpr (__have_avx512f && __is_sse_pd<_Up, _Np>())
3007 return __mmask8(0x3
3008 & _mm512_cmp_pd_mask(__auto_bitcast(__a),
3009 __auto_bitcast(__b),
3010 _CMP_ORD_Q));
3011 else if constexpr (__have_avx512vl && __is_avx_ps<_Up, _Np>())
3012 return _mm256_cmp_ps_mask(__a, __b, _CMP_ORD_Q);
3013 else if constexpr (__have_avx512f && __is_avx_ps<_Up, _Np>())
3014 return __mmask8(_mm512_cmp_ps_mask(__auto_bitcast(__a),
3015 __auto_bitcast(__b),
3016 _CMP_ORD_Q));
3017 else if constexpr (__have_avx512vl && __is_avx_pd<_Up, _Np>())
3018 return _mm256_cmp_pd_mask(__a, __b, _CMP_ORD_Q);
3019 else if constexpr (__have_avx512f && __is_avx_pd<_Up, _Np>())
3020 return __mmask8(0xf
3021 & _mm512_cmp_pd_mask(__auto_bitcast(__a),
3022 __auto_bitcast(__b),
3023 _CMP_ORD_Q));
3024 else if constexpr (__is_avx512_ps<_Up, _Np>())
3025 return _mm512_cmp_ps_mask(__a, __b, _CMP_ORD_Q);
3026 else if constexpr (__is_avx512_pd<_Up, _Np>())
3027 return _mm512_cmp_pd_mask(__a, __b, _CMP_ORD_Q);
3028 else
3029 __assert_unreachable<_Tp>();
3030 }
3031 }
3032
3033 // }}}
3034 // _S_isfinite {{{
3035 template <typename _Tp, size_t _Np>
3036 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
3037 _S_isfinite(_SimdWrapper<_Tp, _Np> __x)
3038 {
3039 static_assert(is_floating_point_v<_Tp>);
3040#if !__FINITE_MATH_ONLY__
3041 if constexpr (__is_avx512_abi<_Abi>() && __have_avx512dq)
3042 {
3043 const auto __xi = __to_intrin(__x);
3044 constexpr auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3045 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3046 return __k1 ^ _mm512_mask_fpclass_ps_mask(__k1, __xi, 0x99);
3047 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3048 return __k1 ^ _mm512_mask_fpclass_pd_mask(__k1, __xi, 0x99);
3049 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3050 return __k1 ^ _mm256_mask_fpclass_ps_mask(__k1, __xi, 0x99);
3051 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3052 return __k1 ^ _mm256_mask_fpclass_pd_mask(__k1, __xi, 0x99);
3053 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3054 return __k1 ^ _mm_mask_fpclass_ps_mask(__k1, __xi, 0x99);
3055 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3056 return __k1 ^ _mm_mask_fpclass_pd_mask(__k1, __xi, 0x99);
3057 }
3058 else if constexpr (__is_avx512_abi<_Abi>())
3059 {
3060 // if all exponent bits are set, __x is either inf or NaN
3061 using _I = __int_for_sizeof_t<_Tp>;
3062 const auto __inf = __vector_bitcast<_I>(
3063 __vector_broadcast<_Np>(__infinity_v<_Tp>));
3064 return _S_less<_I, _Np>(__vector_bitcast<_I>(__x) & __inf, __inf);
3065 }
3066 else
3067#endif
3068 return _Base::_S_isfinite(__x);
3069 }
3070
3071 // }}}
3072 // _S_isinf {{{
3073 template <typename _Tp, size_t _Np>
3074 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
3075 _S_isinf(_SimdWrapper<_Tp, _Np> __x)
3076 {
3077#if !__FINITE_MATH_ONLY__
3078 if constexpr (__is_avx512_abi<_Abi>() && __have_avx512dq)
3079 {
3080 const auto __xi = __to_intrin(__x);
3081 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3082 return _mm512_fpclass_ps_mask(__xi, 0x18);
3083 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3084 return _mm512_fpclass_pd_mask(__xi, 0x18);
3085 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3086 return _mm256_fpclass_ps_mask(__xi, 0x18);
3087 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3088 return _mm256_fpclass_pd_mask(__xi, 0x18);
3089 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3090 return _mm_fpclass_ps_mask(__xi, 0x18);
3091 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3092 return _mm_fpclass_pd_mask(__xi, 0x18);
3093 else
3094 __assert_unreachable<_Tp>();
3095 }
3096 else if constexpr (__have_avx512dq_vl)
3097 {
3098 if constexpr (__is_sse_pd<_Tp, _Np>())
3099 return _mm_movm_epi64(_mm_fpclass_pd_mask(__x, 0x18));
3100 else if constexpr (__is_avx_pd<_Tp, _Np>())
3101 return _mm256_movm_epi64(_mm256_fpclass_pd_mask(__x, 0x18));
3102 else if constexpr (__is_sse_ps<_Tp, _Np>())
3103 return _mm_movm_epi32(
3104 _mm_fpclass_ps_mask(__to_intrin(__x), 0x18));
3105 else if constexpr (__is_avx_ps<_Tp, _Np>())
3106 return _mm256_movm_epi32(_mm256_fpclass_ps_mask(__x, 0x18));
3107 else
3108 __assert_unreachable<_Tp>();
3109 }
3110 else
3111#endif
3112 return _Base::_S_isinf(__x);
3113 }
3114
3115 // }}}
3116 // _S_isnormal {{{
3117 template <typename _Tp, size_t _Np>
3118 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
3119 _S_isnormal(_SimdWrapper<_Tp, _Np> __x)
3120 {
3121#if __FINITE_MATH_ONLY__
3122 [[maybe_unused]] constexpr int __mode = 0x26;
3123#else
3124 [[maybe_unused]] constexpr int __mode = 0xbf;
3125#endif
3126 if constexpr (__is_avx512_abi<_Abi>() && __have_avx512dq)
3127 {
3128 const auto __xi = __to_intrin(__x);
3129 const auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3130 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3131 return __k1 ^ _mm512_mask_fpclass_ps_mask(__k1, __xi, __mode);
3132 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3133 return __k1 ^ _mm512_mask_fpclass_pd_mask(__k1, __xi, __mode);
3134 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3135 return __k1 ^ _mm256_mask_fpclass_ps_mask(__k1, __xi, __mode);
3136 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3137 return __k1 ^ _mm256_mask_fpclass_pd_mask(__k1, __xi, __mode);
3138 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3139 return __k1 ^ _mm_mask_fpclass_ps_mask(__k1, __xi, __mode);
3140 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3141 return __k1 ^ _mm_mask_fpclass_pd_mask(__k1, __xi, __mode);
3142 else
3143 __assert_unreachable<_Tp>();
3144 }
3145 else if constexpr (__have_avx512dq)
3146 {
3147 if constexpr (__have_avx512vl && __is_sse_ps<_Tp, _Np>())
3148 return _mm_movm_epi32(
3149 _knot_mask8(_mm_fpclass_ps_mask(__to_intrin(__x), __mode)));
3150 else if constexpr (__have_avx512vl && __is_avx_ps<_Tp, _Np>())
3151 return _mm256_movm_epi32(
3152 _knot_mask8(_mm256_fpclass_ps_mask(__x, __mode)));
3153 else if constexpr (__is_avx512_ps<_Tp, _Np>())
3154 return _knot_mask16(_mm512_fpclass_ps_mask(__x, __mode));
3155 else if constexpr (__have_avx512vl && __is_sse_pd<_Tp, _Np>())
3156 return _mm_movm_epi64(
3157 _knot_mask8(_mm_fpclass_pd_mask(__x, __mode)));
3158 else if constexpr (__have_avx512vl && __is_avx_pd<_Tp, _Np>())
3159 return _mm256_movm_epi64(
3160 _knot_mask8(_mm256_fpclass_pd_mask(__x, __mode)));
3161 else if constexpr (__is_avx512_pd<_Tp, _Np>())
3162 return _knot_mask8(_mm512_fpclass_pd_mask(__x, __mode));
3163 else
3164 __assert_unreachable<_Tp>();
3165 }
3166 else if constexpr (__is_avx512_abi<_Abi>())
3167 {
3168 using _I = __int_for_sizeof_t<_Tp>;
3169 const auto absn = __vector_bitcast<_I>(_S_abs(__x));
3170 const auto minn = __vector_bitcast<_I>(
3171 __vector_broadcast<_Np>(__norm_min_v<_Tp>));
3172#if __FINITE_MATH_ONLY__
3173 return _S_less_equal<_I, _Np>(minn, absn);
3174#else
3175 const auto infn
3176 = __vector_bitcast<_I>(__vector_broadcast<_Np>(__infinity_v<_Tp>));
3177 return __and(_S_less_equal<_I, _Np>(minn, absn),
3178 _S_less<_I, _Np>(absn, infn));
3179#endif
3180 }
3181 else
3182 return _Base::_S_isnormal(__x);
3183 }
3184
3185 // }}}
3186 // _S_isnan {{{
3187 template <typename _Tp, size_t _Np>
3188 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
3189 _S_isnan(_SimdWrapper<_Tp, _Np> __x)
3190 { return _S_isunordered(__x, __x); }
3191
3192 // }}}
3193 // _S_isunordered {{{
3194 template <typename _Tp, size_t _Np>
3195 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
3196 _S_isunordered([[maybe_unused]] _SimdWrapper<_Tp, _Np> __x,
3197 [[maybe_unused]] _SimdWrapper<_Tp, _Np> __y)
3198 {
3199#if __FINITE_MATH_ONLY__
3200 return {}; // false
3201#else
3202 const auto __xi = __to_intrin(__x);
3203 const auto __yi = __to_intrin(__y);
3204 if constexpr (__is_avx512_abi<_Abi>())
3205 {
3206 constexpr auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3207 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3208 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_UNORD_Q);
3209 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3210 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_UNORD_Q);
3211 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3212 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_UNORD_Q);
3213 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3214 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_UNORD_Q);
3215 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3216 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_UNORD_Q);
3217 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3218 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_UNORD_Q);
3219 }
3220 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3221 return __to_masktype(_mm256_cmp_ps(__xi, __yi, _CMP_UNORD_Q));
3222 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3223 return __to_masktype(_mm256_cmp_pd(__xi, __yi, _CMP_UNORD_Q));
3224 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3225 return __auto_bitcast(_mm_cmpunord_ps(__xi, __yi));
3226 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3227 return __to_masktype(_mm_cmpunord_pd(__xi, __yi));
3228 else
3229 __assert_unreachable<_Tp>();
3230#endif
3231 }
3232
3233 // }}}
3234 // _S_isgreater {{{
3235 template <typename _Tp, size_t _Np>
3236 static constexpr _MaskMember<_Tp>
3237 _S_isgreater(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
3238 {
3239 const auto __xi = __to_intrin(__x);
3240 const auto __yi = __to_intrin(__y);
3241 if constexpr (__is_avx512_abi<_Abi>())
3242 {
3243 const auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3244 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3245 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_GT_OQ);
3246 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3247 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_GT_OQ);
3248 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3249 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_GT_OQ);
3250 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3251 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_GT_OQ);
3252 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3253 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_GT_OQ);
3254 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3255 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_GT_OQ);
3256 else
3257 __assert_unreachable<_Tp>();
3258 }
3259 else if constexpr (__have_avx)
3260 {
3261 if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3262 return __to_masktype(_mm256_cmp_ps(__xi, __yi, _CMP_GT_OQ));
3263 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3264 return __to_masktype(_mm256_cmp_pd(__xi, __yi, _CMP_GT_OQ));
3265 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3266 return __auto_bitcast(_mm_cmp_ps(__xi, __yi, _CMP_GT_OQ));
3267 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3268 return __to_masktype(_mm_cmp_pd(__xi, __yi, _CMP_GT_OQ));
3269 else
3270 __assert_unreachable<_Tp>();
3271 }
3272 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3273 && sizeof(_Tp) == 4)
3274 {
3275 const auto __xn = __vector_bitcast<int>(__xi);
3276 const auto __yn = __vector_bitcast<int>(__yi);
3277 const auto __xp = __xn < 0 ? -(__xn & 0x7fff'ffff) : __xn;
3278 const auto __yp = __yn < 0 ? -(__yn & 0x7fff'ffff) : __yn;
3279 return __auto_bitcast(
3280 __and(__to_masktype(_mm_cmpord_ps(__xi, __yi)), __xp > __yp));
3281 }
3282 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3283 && sizeof(_Tp) == 8)
3284 return __vector_type_t<__int_with_sizeof_t<8>, 2>{
3285 -_mm_ucomigt_sd(__xi, __yi),
3286 -_mm_ucomigt_sd(_mm_unpackhi_pd(__xi, __xi),
3287 _mm_unpackhi_pd(__yi, __yi))};
3288 else
3289 return _Base::_S_isgreater(__x, __y);
3290 }
3291
3292 // }}}
3293 // _S_isgreaterequal {{{
3294 template <typename _Tp, size_t _Np>
3295 static constexpr _MaskMember<_Tp>
3296 _S_isgreaterequal(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
3297 {
3298 const auto __xi = __to_intrin(__x);
3299 const auto __yi = __to_intrin(__y);
3300 if constexpr (__is_avx512_abi<_Abi>())
3301 {
3302 const auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3303 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3304 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_GE_OQ);
3305 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3306 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_GE_OQ);
3307 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3308 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_GE_OQ);
3309 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3310 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_GE_OQ);
3311 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3312 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_GE_OQ);
3313 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3314 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_GE_OQ);
3315 else
3316 __assert_unreachable<_Tp>();
3317 }
3318 else if constexpr (__have_avx)
3319 {
3320 if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3321 return __to_masktype(_mm256_cmp_ps(__xi, __yi, _CMP_GE_OQ));
3322 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3323 return __to_masktype(_mm256_cmp_pd(__xi, __yi, _CMP_GE_OQ));
3324 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3325 return __auto_bitcast(_mm_cmp_ps(__xi, __yi, _CMP_GE_OQ));
3326 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3327 return __to_masktype(_mm_cmp_pd(__xi, __yi, _CMP_GE_OQ));
3328 else
3329 __assert_unreachable<_Tp>();
3330 }
3331 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3332 && sizeof(_Tp) == 4)
3333 {
3334 const auto __xn = __vector_bitcast<int>(__xi);
3335 const auto __yn = __vector_bitcast<int>(__yi);
3336 const auto __xp = __xn < 0 ? -(__xn & 0x7fff'ffff) : __xn;
3337 const auto __yp = __yn < 0 ? -(__yn & 0x7fff'ffff) : __yn;
3338 return __auto_bitcast(
3339 __and(__to_masktype(_mm_cmpord_ps(__xi, __yi)), __xp >= __yp));
3340 }
3341 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3342 && sizeof(_Tp) == 8)
3343 return __vector_type_t<__int_with_sizeof_t<8>, 2>{
3344 -_mm_ucomige_sd(__xi, __yi),
3345 -_mm_ucomige_sd(_mm_unpackhi_pd(__xi, __xi),
3346 _mm_unpackhi_pd(__yi, __yi))};
3347 else
3348 return _Base::_S_isgreaterequal(__x, __y);
3349 }
3350
3351 // }}}
3352 // _S_isless {{{
3353 template <typename _Tp, size_t _Np>
3354 static constexpr _MaskMember<_Tp>
3355 _S_isless(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
3356 {
3357 const auto __xi = __to_intrin(__x);
3358 const auto __yi = __to_intrin(__y);
3359 if constexpr (__is_avx512_abi<_Abi>())
3360 {
3361 const auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3362 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3363 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LT_OQ);
3364 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3365 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LT_OQ);
3366 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3367 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LT_OQ);
3368 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3369 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LT_OQ);
3370 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3371 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LT_OQ);
3372 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3373 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LT_OQ);
3374 else
3375 __assert_unreachable<_Tp>();
3376 }
3377 else if constexpr (__have_avx)
3378 {
3379 if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3380 return __to_masktype(_mm256_cmp_ps(__xi, __yi, _CMP_LT_OQ));
3381 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3382 return __to_masktype(_mm256_cmp_pd(__xi, __yi, _CMP_LT_OQ));
3383 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3384 return __auto_bitcast(_mm_cmp_ps(__xi, __yi, _CMP_LT_OQ));
3385 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3386 return __to_masktype(_mm_cmp_pd(__xi, __yi, _CMP_LT_OQ));
3387 else
3388 __assert_unreachable<_Tp>();
3389 }
3390 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3391 && sizeof(_Tp) == 4)
3392 {
3393 const auto __xn = __vector_bitcast<int>(__xi);
3394 const auto __yn = __vector_bitcast<int>(__yi);
3395 const auto __xp = __xn < 0 ? -(__xn & 0x7fff'ffff) : __xn;
3396 const auto __yp = __yn < 0 ? -(__yn & 0x7fff'ffff) : __yn;
3397 return __auto_bitcast(
3398 __and(__to_masktype(_mm_cmpord_ps(__xi, __yi)), __xp < __yp));
3399 }
3400 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3401 && sizeof(_Tp) == 8)
3402 return __vector_type_t<__int_with_sizeof_t<8>, 2>{
3403 -_mm_ucomigt_sd(__yi, __xi),
3404 -_mm_ucomigt_sd(_mm_unpackhi_pd(__yi, __yi),
3405 _mm_unpackhi_pd(__xi, __xi))};
3406 else
3407 return _Base::_S_isless(__x, __y);
3408 }
3409
3410 // }}}
3411 // _S_islessequal {{{
3412 template <typename _Tp, size_t _Np>
3413 static constexpr _MaskMember<_Tp>
3414 _S_islessequal(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
3415 {
3416 const auto __xi = __to_intrin(__x);
3417 const auto __yi = __to_intrin(__y);
3418 if constexpr (__is_avx512_abi<_Abi>())
3419 {
3420 const auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3421 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3422 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LE_OQ);
3423 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3424 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LE_OQ);
3425 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3426 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LE_OQ);
3427 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3428 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LE_OQ);
3429 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3430 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_LE_OQ);
3431 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3432 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_LE_OQ);
3433 else
3434 __assert_unreachable<_Tp>();
3435 }
3436 else if constexpr (__have_avx)
3437 {
3438 if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3439 return __to_masktype(_mm256_cmp_ps(__xi, __yi, _CMP_LE_OQ));
3440 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3441 return __to_masktype(_mm256_cmp_pd(__xi, __yi, _CMP_LE_OQ));
3442 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3443 return __auto_bitcast(_mm_cmp_ps(__xi, __yi, _CMP_LE_OQ));
3444 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3445 return __to_masktype(_mm_cmp_pd(__xi, __yi, _CMP_LE_OQ));
3446 else
3447 __assert_unreachable<_Tp>();
3448 }
3449 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3450 && sizeof(_Tp) == 4)
3451 {
3452 const auto __xn = __vector_bitcast<int>(__xi);
3453 const auto __yn = __vector_bitcast<int>(__yi);
3454 const auto __xp = __xn < 0 ? -(__xn & 0x7fff'ffff) : __xn;
3455 const auto __yp = __yn < 0 ? -(__yn & 0x7fff'ffff) : __yn;
3456 return __auto_bitcast(
3457 __and(__to_masktype(_mm_cmpord_ps(__xi, __yi)), __xp <= __yp));
3458 }
3459 else if constexpr (__have_sse2 && sizeof(__xi) == 16
3460 && sizeof(_Tp) == 8)
3461 return __vector_type_t<__int_with_sizeof_t<8>, 2>{
3462 -_mm_ucomige_sd(__yi, __xi),
3463 -_mm_ucomige_sd(_mm_unpackhi_pd(__yi, __yi),
3464 _mm_unpackhi_pd(__xi, __xi))};
3465 else
3466 return _Base::_S_islessequal(__x, __y);
3467 }
3468
3469 // }}}
3470 // _S_islessgreater {{{
3471 template <typename _Tp, size_t _Np>
3472 static constexpr _MaskMember<_Tp>
3473 _S_islessgreater(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
3474 {
3475 const auto __xi = __to_intrin(__x);
3476 const auto __yi = __to_intrin(__y);
3477 if constexpr (__is_avx512_abi<_Abi>())
3478 {
3479 const auto __k1 = _Abi::template _S_implicit_mask_intrin<_Tp>();
3480 if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 4)
3481 return _mm512_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_NEQ_OQ);
3482 else if constexpr (sizeof(__xi) == 64 && sizeof(_Tp) == 8)
3483 return _mm512_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_NEQ_OQ);
3484 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3485 return _mm256_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_NEQ_OQ);
3486 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3487 return _mm256_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_NEQ_OQ);
3488 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3489 return _mm_mask_cmp_ps_mask(__k1, __xi, __yi, _CMP_NEQ_OQ);
3490 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3491 return _mm_mask_cmp_pd_mask(__k1, __xi, __yi, _CMP_NEQ_OQ);
3492 else
3493 __assert_unreachable<_Tp>();
3494 }
3495 else if constexpr (__have_avx)
3496 {
3497 if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 4)
3498 return __to_masktype(_mm256_cmp_ps(__xi, __yi, _CMP_NEQ_OQ));
3499 else if constexpr (sizeof(__xi) == 32 && sizeof(_Tp) == 8)
3500 return __to_masktype(_mm256_cmp_pd(__xi, __yi, _CMP_NEQ_OQ));
3501 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3502 return __auto_bitcast(_mm_cmp_ps(__xi, __yi, _CMP_NEQ_OQ));
3503 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3504 return __to_masktype(_mm_cmp_pd(__xi, __yi, _CMP_NEQ_OQ));
3505 else
3506 __assert_unreachable<_Tp>();
3507 }
3508 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 4)
3509 return __auto_bitcast(
3510 __and(_mm_cmpord_ps(__xi, __yi), _mm_cmpneq_ps(__xi, __yi)));
3511 else if constexpr (sizeof(__xi) == 16 && sizeof(_Tp) == 8)
3512 return __to_masktype(
3513 __and(_mm_cmpord_pd(__xi, __yi), _mm_cmpneq_pd(__xi, __yi)));
3514 else
3515 __assert_unreachable<_Tp>();
3516 }
3517
3518 //}}} }}}
3519 template <template <typename> class _Op, typename _Tp, typename _K, size_t _Np>
3520 _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
3521 _S_masked_unary(const _SimdWrapper<_K, _Np> __k, const _SimdWrapper<_Tp, _Np> __v)
3522 {
3523 if (__k._M_is_constprop_none_of())
3524 return __v;
3525 else if (__k._M_is_constprop_all_of())
3526 {
3527 auto __vv = _Base::_M_make_simd(__v);
3528 _Op<decltype(__vv)> __op;
3529 return __data(__op(__vv));
3530 }
3531 else if constexpr (__is_bitmask_v<decltype(__k)>
3532 && (is_same_v<_Op<void>, __increment<void>>
3533 || is_same_v<_Op<void>, __decrement<void>>))
3534 {
3535 // optimize masked unary increment and decrement as masked sub +/-1
3536 constexpr int __pm_one
3537 = is_same_v<_Op<void>, __increment<void>> ? -1 : 1;
3538#ifdef __clang__
3539 return __movm<_Np, _Tp>(__k._M_data) ? __v._M_data - __pm_one : __v._M_data;
3540#else // __clang__
3541 if constexpr (is_integral_v<_Tp>)
3542 {
3543 constexpr bool __lp64 = sizeof(long) == sizeof(long long);
3544 using _Ip = std::make_signed_t<_Tp>;
3545 using _Up = std::conditional_t<
3546 std::is_same_v<_Ip, long>,
3549 std::is_same_v<_Ip, signed char>, char, _Ip>>;
3550 const auto __value = __vector_bitcast<_Up>(__v._M_data);
3551#define _GLIBCXX_SIMD_MASK_SUB(_Sizeof, _Width, _Instr) \
3552 if constexpr (sizeof(_Tp) == _Sizeof && sizeof(__v) == _Width) \
3553 return __vector_bitcast<_Tp>(__builtin_ia32_##_Instr##_mask(__value, \
3554 __vector_broadcast<_Np>(_Up(__pm_one)), __value, __k._M_data))
3555 _GLIBCXX_SIMD_MASK_SUB(1, 64, psubb512);
3556 _GLIBCXX_SIMD_MASK_SUB(1, 32, psubb256);
3557 _GLIBCXX_SIMD_MASK_SUB(1, 16, psubb128);
3558 _GLIBCXX_SIMD_MASK_SUB(2, 64, psubw512);
3559 _GLIBCXX_SIMD_MASK_SUB(2, 32, psubw256);
3560 _GLIBCXX_SIMD_MASK_SUB(2, 16, psubw128);
3561 _GLIBCXX_SIMD_MASK_SUB(4, 64, psubd512);
3562 _GLIBCXX_SIMD_MASK_SUB(4, 32, psubd256);
3563 _GLIBCXX_SIMD_MASK_SUB(4, 16, psubd128);
3564 _GLIBCXX_SIMD_MASK_SUB(8, 64, psubq512);
3565 _GLIBCXX_SIMD_MASK_SUB(8, 32, psubq256);
3566 _GLIBCXX_SIMD_MASK_SUB(8, 16, psubq128);
3567#undef _GLIBCXX_SIMD_MASK_SUB
3568 }
3569 else
3570 {
3571#define _GLIBCXX_SIMD_MASK_SUB(_Sizeof, _Width, _Instr) \
3572 if constexpr (sizeof(_Tp) == _Sizeof && sizeof(__v) == _Width) \
3573 return __builtin_ia32_##_Instr##_mask( \
3574 __v._M_data, __vector_broadcast<_Np>(_Tp(__pm_one)), __v._M_data, \
3575 __k._M_data, _MM_FROUND_CUR_DIRECTION)
3576 _GLIBCXX_SIMD_MASK_SUB(4, 64, subps512);
3577 _GLIBCXX_SIMD_MASK_SUB(4, 32, subps256);
3578 _GLIBCXX_SIMD_MASK_SUB(4, 16, subps128);
3579 _GLIBCXX_SIMD_MASK_SUB(8, 64, subpd512);
3580 _GLIBCXX_SIMD_MASK_SUB(8, 32, subpd256);
3581 _GLIBCXX_SIMD_MASK_SUB(8, 16, subpd128);
3582#undef _GLIBCXX_SIMD_MASK_SUB
3583 }
3584#endif // __clang__
3585 }
3586 else
3587 return _Base::template _S_masked_unary<_Op>(__k, __v);
3588 }
3589 };
3590
3591// }}}
3592// _MaskImplX86Mixin {{{
3593struct _MaskImplX86Mixin
3594{
3595 template <typename _Tp>
3596 using _TypeTag = _Tp*;
3597
3598 using _Base = _MaskImplBuiltinMixin;
3599
3600 // _S_to_maskvector(bool) {{{
3601 template <typename _Up, size_t _ToN = 1, typename _Tp>
3602 _GLIBCXX_SIMD_INTRINSIC static constexpr
3603 enable_if_t<is_same_v<_Tp, bool>, _SimdWrapper<_Up, _ToN>>
3604 _S_to_maskvector(_Tp __x)
3605 {
3606 static_assert(is_same_v<_Up, __int_for_sizeof_t<_Up>>);
3607 return __x ? __vector_type_t<_Up, _ToN>{~_Up()}
3608 : __vector_type_t<_Up, _ToN>();
3609 }
3610
3611 // }}}
3612 // _S_to_maskvector(_SanitizedBitMask) {{{
3613 template <typename _Up, size_t _UpN = 0, size_t _Np, size_t _ToN = _UpN == 0 ? _Np : _UpN>
3614 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Up, _ToN>
3615 _S_to_maskvector(_SanitizedBitMask<_Np> __x)
3616 {
3617 static_assert(is_same_v<_Up, __int_for_sizeof_t<_Up>>);
3618 using _UV = __vector_type_t<_Up, _ToN>;
3619 using _UI = __intrinsic_type_t<_Up, _ToN>;
3620 [[maybe_unused]] const auto __k = __x._M_to_bits();
3621 if constexpr (_Np == 1)
3622 return _S_to_maskvector<_Up, _ToN>(__k);
3623 else if (__x._M_is_constprop() || __builtin_is_constant_evaluated())
3624 return __generate_from_n_evaluations<std::min(_ToN, _Np), _UV>(
3625 [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA -> _Up { return -__x[__i.value]; });
3626 else if constexpr (sizeof(_Up) == 1)
3627 {
3628 if constexpr (sizeof(_UI) == 16)
3629 {
3630 if constexpr (__have_avx512bw_vl)
3631 return __intrin_bitcast<_UV>(_mm_movm_epi8(__k));
3632 else if constexpr (__have_avx512bw)
3633 return __intrin_bitcast<_UV>(__lo128(_mm512_movm_epi8(__k)));
3634 else if constexpr (__have_avx512f)
3635 {
3636 auto __as32bits = _mm512_maskz_mov_epi32(__k, ~__m512i());
3637 auto __as16bits
3638 = __xzyw(_mm256_packs_epi32(__lo256(__as32bits),
3639 __hi256(__as32bits)));
3640 return __intrin_bitcast<_UV>(
3641 _mm_packs_epi16(__lo128(__as16bits), __hi128(__as16bits)));
3642 }
3643 else if constexpr (__have_ssse3)
3644 {
3645 const auto __bitmask = __to_intrin(
3646 __make_vector<_UChar>(1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4,
3647 8, 16, 32, 64, 128));
3648 return __intrin_bitcast<_UV>(
3649 __vector_bitcast<_Up>(
3650 _mm_shuffle_epi8(__to_intrin(
3651 __vector_type_t<_ULLong, 2>{__k}),
3652 _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1,
3653 1, 1, 1, 1, 1, 1, 1))
3654 & __bitmask)
3655 != 0);
3656 }
3657 // else fall through
3658 }
3659 else if constexpr (sizeof(_UI) == 32)
3660 {
3661 if constexpr (__have_avx512bw_vl)
3662 return __vector_bitcast<_Up>(_mm256_movm_epi8(__k));
3663 else if constexpr (__have_avx512bw)
3664 return __vector_bitcast<_Up>(__lo256(_mm512_movm_epi8(__k)));
3665 else if constexpr (__have_avx512f)
3666 {
3667 auto __as16bits = // 0 16 1 17 ... 15 31
3668 _mm512_srli_epi32(_mm512_maskz_mov_epi32(__k, ~__m512i()),
3669 16)
3670 | _mm512_slli_epi32(_mm512_maskz_mov_epi32(__k >> 16,
3671 ~__m512i()),
3672 16);
3673 auto __0_16_1_17 = __xzyw(_mm256_packs_epi16(
3674 __lo256(__as16bits),
3675 __hi256(__as16bits)) // 0 16 1 17 2 18 3 19 8 24 9 25 ...
3676 );
3677 // deinterleave:
3678 return __vector_bitcast<_Up>(__xzyw(_mm256_shuffle_epi8(
3679 __0_16_1_17, // 0 16 1 17 2 ...
3680 _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9,
3681 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 14, 1,
3682 3, 5, 7, 9, 11, 13,
3683 15)))); // 0-7 16-23 8-15 24-31 -> xzyw
3684 // 0-3 8-11 16-19 24-27
3685 // 4-7 12-15 20-23 28-31
3686 }
3687 else if constexpr (__have_avx2)
3688 {
3689 const auto __bitmask
3690 = _mm256_broadcastsi128_si256(__to_intrin(
3691 __make_vector<_UChar>(1, 2, 4, 8, 16, 32, 64, 128, 1, 2,
3692 4, 8, 16, 32, 64, 128)));
3693 return __vector_bitcast<_Up>(
3694 __vector_bitcast<_Up>(
3695 _mm256_shuffle_epi8(
3696 _mm256_broadcastsi128_si256(
3697 __to_intrin(__vector_type_t<_ULLong, 2>{__k})),
3698 _mm256_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
3699 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
3700 3, 3, 3, 3, 3, 3))
3701 & __bitmask)
3702 != 0);
3703 }
3704 // else fall through
3705 }
3706 else if constexpr (sizeof(_UI) == 64)
3707 return reinterpret_cast<_UV>(_mm512_movm_epi8(__k));
3708 if constexpr (std::min(_ToN, _Np) <= 4)
3709 {
3710 if constexpr (_Np > 7) // avoid overflow
3711 __x &= _SanitizedBitMask<_Np>(0x0f);
3712 const _UInt __char_mask
3713 = ((_UInt(__x.to_ulong()) * 0x00204081U) & 0x01010101ULL)
3714 * 0xff;
3715 _UV __r = {};
3716 __builtin_memcpy(&__r, &__char_mask,
3717 std::min(sizeof(__r), sizeof(__char_mask)));
3718 return __r;
3719 }
3720 else if constexpr (std::min(_ToN, _Np) <= 7)
3721 {
3722 if constexpr (_Np > 7) // avoid overflow
3723 __x &= _SanitizedBitMask<_Np>(0x7f);
3724 const _ULLong __char_mask
3725 = ((__x.to_ulong() * 0x40810204081ULL) & 0x0101010101010101ULL)
3726 * 0xff;
3727 _UV __r = {};
3728 __builtin_memcpy(&__r, &__char_mask,
3729 std::min(sizeof(__r), sizeof(__char_mask)));
3730 return __r;
3731 }
3732 }
3733 else if constexpr (sizeof(_Up) == 2)
3734 {
3735 if constexpr (sizeof(_UI) == 16)
3736 {
3737 if constexpr (__have_avx512bw_vl)
3738 return __intrin_bitcast<_UV>(_mm_movm_epi16(__k));
3739 else if constexpr (__have_avx512bw)
3740 return __intrin_bitcast<_UV>(__lo128(_mm512_movm_epi16(__k)));
3741 else if constexpr (__have_avx512f)
3742 {
3743 __m256i __as32bits = {};
3744 if constexpr (__have_avx512vl)
3745 __as32bits = _mm256_maskz_mov_epi32(__k, ~__m256i());
3746 else
3747 __as32bits
3748 = __lo256(_mm512_maskz_mov_epi32(__k, ~__m512i()));
3749 return __intrin_bitcast<_UV>(
3750 _mm_packs_epi32(__lo128(__as32bits), __hi128(__as32bits)));
3751 }
3752 // else fall through
3753 }
3754 else if constexpr (sizeof(_UI) == 32)
3755 {
3756 if constexpr (__have_avx512bw_vl)
3757 return __vector_bitcast<_Up>(_mm256_movm_epi16(__k));
3758 else if constexpr (__have_avx512bw)
3759 return __vector_bitcast<_Up>(__lo256(_mm512_movm_epi16(__k)));
3760 else if constexpr (__have_avx512f)
3761 {
3762 auto __as32bits = _mm512_maskz_mov_epi32(__k, ~__m512i());
3763 return __vector_bitcast<_Up>(
3764 __xzyw(_mm256_packs_epi32(__lo256(__as32bits),
3765 __hi256(__as32bits))));
3766 }
3767 // else fall through
3768 }
3769 else if constexpr (sizeof(_UI) == 64)
3770 return __vector_bitcast<_Up>(_mm512_movm_epi16(__k));
3771 }
3772 else if constexpr (sizeof(_Up) == 4)
3773 {
3774 if constexpr (sizeof(_UI) == 16)
3775 {
3776 if constexpr (__have_avx512dq_vl)
3777 return __intrin_bitcast<_UV>(_mm_movm_epi32(__k));
3778 else if constexpr (__have_avx512dq)
3779 return __intrin_bitcast<_UV>(__lo128(_mm512_movm_epi32(__k)));
3780 else if constexpr (__have_avx512vl)
3781 return __intrin_bitcast<_UV>(
3782 _mm_maskz_mov_epi32(__k, ~__m128i()));
3783 else if constexpr (__have_avx512f)
3784 return __intrin_bitcast<_UV>(
3785 __lo128(_mm512_maskz_mov_epi32(__k, ~__m512i())));
3786 // else fall through
3787 }
3788 else if constexpr (sizeof(_UI) == 32)
3789 {
3790 if constexpr (__have_avx512dq_vl)
3791 return __vector_bitcast<_Up>(_mm256_movm_epi32(__k));
3792 else if constexpr (__have_avx512dq)
3793 return __vector_bitcast<_Up>(__lo256(_mm512_movm_epi32(__k)));
3794 else if constexpr (__have_avx512vl)
3795 return __vector_bitcast<_Up>(
3796 _mm256_maskz_mov_epi32(__k, ~__m256i()));
3797 else if constexpr (__have_avx512f)
3798 return __vector_bitcast<_Up>(
3799 __lo256(_mm512_maskz_mov_epi32(__k, ~__m512i())));
3800 // else fall through
3801 }
3802 else if constexpr (sizeof(_UI) == 64)
3803 return __vector_bitcast<_Up>(
3804 __have_avx512dq ? _mm512_movm_epi32(__k)
3805 : _mm512_maskz_mov_epi32(__k, ~__m512i()));
3806 }
3807 else if constexpr (sizeof(_Up) == 8)
3808 {
3809 if constexpr (sizeof(_UI) == 16)
3810 {
3811 if constexpr (__have_avx512dq_vl)
3812 return __vector_bitcast<_Up>(_mm_movm_epi64(__k));
3813 else if constexpr (__have_avx512dq)
3814 return __vector_bitcast<_Up>(__lo128(_mm512_movm_epi64(__k)));
3815 else if constexpr (__have_avx512vl)
3816 return __vector_bitcast<_Up>(
3817 _mm_maskz_mov_epi64(__k, ~__m128i()));
3818 else if constexpr (__have_avx512f)
3819 return __vector_bitcast<_Up>(
3820 __lo128(_mm512_maskz_mov_epi64(__k, ~__m512i())));
3821 // else fall through
3822 }
3823 else if constexpr (sizeof(_UI) == 32)
3824 {
3825 if constexpr (__have_avx512dq_vl)
3826 return __vector_bitcast<_Up>(_mm256_movm_epi64(__k));
3827 else if constexpr (__have_avx512dq)
3828 return __vector_bitcast<_Up>(__lo256(_mm512_movm_epi64(__k)));
3829 else if constexpr (__have_avx512vl)
3830 return __vector_bitcast<_Up>(
3831 _mm256_maskz_mov_epi64(__k, ~__m256i()));
3832 else if constexpr (__have_avx512f)
3833 return __vector_bitcast<_Up>(
3834 __lo256(_mm512_maskz_mov_epi64(__k, ~__m512i())));
3835 // else fall through
3836 }
3837 else if constexpr (sizeof(_UI) == 64)
3838 return __vector_bitcast<_Up>(
3839 __have_avx512dq ? _mm512_movm_epi64(__k)
3840 : _mm512_maskz_mov_epi64(__k, ~__m512i()));
3841 }
3842
3843 using _UpUInt = make_unsigned_t<_Up>;
3844 using _V = __vector_type_t<_UpUInt, _ToN>;
3845 constexpr size_t __bits_per_element = sizeof(_Up) * __CHAR_BIT__;
3846 if constexpr (_ToN == 2)
3847 {
3848 return __vector_bitcast<_Up>(_V{_UpUInt(-__x[0]), _UpUInt(-__x[1])});
3849 }
3850 else if constexpr (!__have_avx2 && __have_avx && sizeof(_V) == 32)
3851 {
3852 if constexpr (sizeof(_Up) == 4)
3853 return __vector_bitcast<_Up>(_mm256_cmp_ps(
3854 _mm256_and_ps(_mm256_castsi256_ps(_mm256_set1_epi32(__k)),
3855 _mm256_castsi256_ps(_mm256_setr_epi32(
3856 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80))),
3857 _mm256_setzero_ps(), _CMP_NEQ_UQ));
3858 else if constexpr (sizeof(_Up) == 8)
3859 return __vector_bitcast<_Up>(_mm256_cmp_pd(
3860 _mm256_and_pd(_mm256_castsi256_pd(_mm256_set1_epi64x(__k)),
3861 _mm256_castsi256_pd(
3862 _mm256_setr_epi64x(0x01, 0x02, 0x04, 0x08))),
3863 _mm256_setzero_pd(), _CMP_NEQ_UQ));
3864 else
3865 __assert_unreachable<_Up>();
3866 }
3867 else if constexpr (__bits_per_element >= _ToN)
3868 {
3869 constexpr auto __bitmask
3870 = __generate_vector<_V>([](auto __i)
3871 constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA -> _UpUInt
3872 { return __i < _ToN ? 1ull << __i : 0; });
3873 const auto __bits
3874 = __vector_broadcast<_ToN, _UpUInt>(__k) & __bitmask;
3875 if constexpr (__bits_per_element > _ToN)
3876 return __vector_bitcast<_Up>(__bits) > 0;
3877 else
3878 return __vector_bitcast<_Up>(__bits != 0);
3879 }
3880 else
3881 {
3882 const _V __tmp
3883 = __generate_vector<_V>([&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
3884 return static_cast<_UpUInt>(
3885 __k >> (__bits_per_element * (__i / __bits_per_element)));
3886 })
3887 & __generate_vector<_V>([](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
3888 return static_cast<_UpUInt>(1ull
3889 << (__i % __bits_per_element));
3890 }); // mask bit index
3891 return __intrin_bitcast<_UV>(__tmp != _V());
3892 }
3893 }
3894
3895 // }}}
3896 // _S_to_maskvector(_SimdWrapper) {{{
3897 template <typename _Up, size_t _UpN = 0, typename _Tp, size_t _Np,
3898 size_t _ToN = _UpN == 0 ? _Np : _UpN>
3899 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Up, _ToN>
3900 _S_to_maskvector(_SimdWrapper<_Tp, _Np> __x)
3901 {
3902 static_assert(is_same_v<_Up, __int_for_sizeof_t<_Up>>);
3903 using _TW = _SimdWrapper<_Tp, _Np>;
3904 using _UW = _SimdWrapper<_Up, _ToN>;
3905 using _UI = __intrinsic_type_t<_Up, _ToN>;
3906 if constexpr (is_same_v<_Tp, bool>) // bits -> vector
3907 return _S_to_maskvector<_Up, _ToN>(
3908 _BitMask<_Np>(__x._M_data)._M_sanitized());
3909 // vector -> vector bitcast
3910 else if constexpr (sizeof(_Up) == sizeof(_Tp)
3911 && sizeof(_TW) == sizeof(_UW))
3912 return __wrapper_bitcast<_Up, _ToN>(
3913 _ToN <= _Np
3914 ? __x
3915 : simd_abi::_VecBuiltin<sizeof(_Tp) * _Np>::_S_masked(__x));
3916 else // vector -> vector {{{
3917 {
3918 if (__x._M_is_constprop() || __builtin_is_constant_evaluated())
3919 {
3920 const auto __y = __vector_bitcast<__int_for_sizeof_t<_Tp>>(__x);
3921 return __generate_from_n_evaluations<std::min(_ToN, _Np),
3922 __vector_type_t<_Up, _ToN>>(
3923 [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA -> _Up { return __y[__i.value]; });
3924 }
3925 using _To = __vector_type_t<_Up, _ToN>;
3926 [[maybe_unused]] constexpr size_t _FromN = _Np;
3927 constexpr int _FromBytes = sizeof(_Tp);
3928 constexpr int _ToBytes = sizeof(_Up);
3929 const auto __k = __x._M_data;
3930
3931 if constexpr (_FromBytes == _ToBytes)
3932 return __intrin_bitcast<_To>(__k);
3933 else if constexpr (sizeof(_UI) == 16 && sizeof(__k) == 16)
3934 { // SSE -> SSE {{{
3935 if constexpr (_FromBytes == 4 && _ToBytes == 8)
3936 return __intrin_bitcast<_To>(__interleave128_lo(__k, __k));
3937 else if constexpr (_FromBytes == 2 && _ToBytes == 8)
3938 {
3939 const auto __y
3940 = __vector_bitcast<int>(__interleave128_lo(__k, __k));
3941 return __intrin_bitcast<_To>(__interleave128_lo(__y, __y));
3942 }
3943 else if constexpr (_FromBytes == 1 && _ToBytes == 8)
3944 {
3945 auto __y
3946 = __vector_bitcast<short>(__interleave128_lo(__k, __k));
3947 auto __z
3948 = __vector_bitcast<int>(__interleave128_lo(__y, __y));
3949 return __intrin_bitcast<_To>(__interleave128_lo(__z, __z));
3950 }
3951 else if constexpr (_FromBytes == 8 && _ToBytes == 4
3952 && __have_sse2)
3953 return __intrin_bitcast<_To>(
3954 _mm_packs_epi32(__vector_bitcast<_LLong>(__k), __m128i()));
3955 else if constexpr (_FromBytes == 8 && _ToBytes == 4)
3956 return __vector_shuffle<1, 3, 6, 7>(__vector_bitcast<_Up>(__k),
3957 _UI());
3958 else if constexpr (_FromBytes == 2 && _ToBytes == 4)
3959 return __intrin_bitcast<_To>(__interleave128_lo(__k, __k));
3960 else if constexpr (_FromBytes == 1 && _ToBytes == 4)
3961 {
3962 const auto __y
3963 = __vector_bitcast<short>(__interleave128_lo(__k, __k));
3964 return __intrin_bitcast<_To>(__interleave128_lo(__y, __y));
3965 }
3966 else if constexpr (_FromBytes == 8 && _ToBytes == 2)
3967 {
3968 if constexpr (__have_sse2 && !__have_ssse3)
3969 return __intrin_bitcast<_To>(_mm_packs_epi32(
3970 _mm_packs_epi32(__vector_bitcast<_LLong>(__k), __m128i()),
3971 __m128i()));
3972 else
3973 return __intrin_bitcast<_To>(
3974 __vector_permute<3, 7, -1, -1, -1, -1, -1, -1>(
3975 __vector_bitcast<_Up>(__k)));
3976 }
3977 else if constexpr (_FromBytes == 4 && _ToBytes == 2)
3978 return __intrin_bitcast<_To>(
3979 _mm_packs_epi32(__vector_bitcast<_LLong>(__k), __m128i()));
3980 else if constexpr (_FromBytes == 1 && _ToBytes == 2)
3981 return __intrin_bitcast<_To>(__interleave128_lo(__k, __k));
3982 else if constexpr (_FromBytes == 8 && _ToBytes == 1
3983 && __have_ssse3)
3984 return __intrin_bitcast<_To>(
3985 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
3986 _mm_setr_epi8(7, 15, -1, -1, -1, -1, -1, -1,
3987 -1, -1, -1, -1, -1, -1, -1,
3988 -1)));
3989 else if constexpr (_FromBytes == 8 && _ToBytes == 1)
3990 {
3991 auto __y
3992 = _mm_packs_epi32(__vector_bitcast<_LLong>(__k), __m128i());
3993 __y = _mm_packs_epi32(__y, __m128i());
3994 return __intrin_bitcast<_To>(_mm_packs_epi16(__y, __m128i()));
3995 }
3996 else if constexpr (_FromBytes == 4 && _ToBytes == 1
3997 && __have_ssse3)
3998 return __intrin_bitcast<_To>(
3999 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4000 _mm_setr_epi8(3, 7, 11, 15, -1, -1, -1, -1,
4001 -1, -1, -1, -1, -1, -1, -1,
4002 -1)));
4003 else if constexpr (_FromBytes == 4 && _ToBytes == 1)
4004 {
4005 const auto __y
4006 = _mm_packs_epi32(__vector_bitcast<_LLong>(__k), __m128i());
4007 return __intrin_bitcast<_To>(_mm_packs_epi16(__y, __m128i()));
4008 }
4009 else if constexpr (_FromBytes == 2 && _ToBytes == 1)
4010 return __intrin_bitcast<_To>(
4011 _mm_packs_epi16(__vector_bitcast<_LLong>(__k), __m128i()));
4012 else
4013 __assert_unreachable<_Tp>();
4014 } // }}}
4015 else if constexpr (sizeof(_UI) == 32 && sizeof(__k) == 32)
4016 { // AVX -> AVX {{{
4017 if constexpr (_FromBytes == _ToBytes)
4018 __assert_unreachable<_Tp>();
4019 else if constexpr (_FromBytes == _ToBytes * 2)
4020 {
4021 const auto __y = __vector_bitcast<_LLong>(__k);
4022 return __intrin_bitcast<_To>(_mm256_castsi128_si256(
4023 _mm_packs_epi16(__lo128(__y), __hi128(__y))));
4024 }
4025 else if constexpr (_FromBytes == _ToBytes * 4)
4026 {
4027 const auto __y = __vector_bitcast<_LLong>(__k);
4028 return __intrin_bitcast<_To>(_mm256_castsi128_si256(
4029 _mm_packs_epi16(_mm_packs_epi16(__lo128(__y), __hi128(__y)),
4030 __m128i())));
4031 }
4032 else if constexpr (_FromBytes == _ToBytes * 8)
4033 {
4034 const auto __y = __vector_bitcast<_LLong>(__k);
4035 return __intrin_bitcast<_To>(
4036 _mm256_castsi128_si256(_mm_shuffle_epi8(
4037 _mm_packs_epi16(__lo128(__y), __hi128(__y)),
4038 _mm_setr_epi8(3, 7, 11, 15, -1, -1, -1, -1, -1, -1, -1,
4039 -1, -1, -1, -1, -1))));
4040 }
4041 else if constexpr (_FromBytes * 2 == _ToBytes)
4042 {
4043 auto __y = __xzyw(__to_intrin(__k));
4044 if constexpr (is_floating_point_v<
4045 _Tp> || (!__have_avx2 && _FromBytes == 4))
4046 {
4047 const auto __yy = __vector_bitcast<float>(__y);
4048 return __intrin_bitcast<_To>(
4049 _mm256_unpacklo_ps(__yy, __yy));
4050 }
4051 else
4052 return __intrin_bitcast<_To>(
4053 _mm256_unpacklo_epi8(__y, __y));
4054 }
4055 else if constexpr (_FromBytes * 4 == _ToBytes)
4056 {
4057 auto __y
4058 = _mm_unpacklo_epi8(__lo128(__vector_bitcast<_LLong>(__k)),
4059 __lo128(__vector_bitcast<_LLong>(
4060 __k))); // drops 3/4 of input
4061 return __intrin_bitcast<_To>(
4062 __concat(_mm_unpacklo_epi16(__y, __y),
4063 _mm_unpackhi_epi16(__y, __y)));
4064 }
4065 else if constexpr (_FromBytes == 1 && _ToBytes == 8)
4066 {
4067 auto __y
4068 = _mm_unpacklo_epi8(__lo128(__vector_bitcast<_LLong>(__k)),
4069 __lo128(__vector_bitcast<_LLong>(
4070 __k))); // drops 3/4 of input
4071 __y
4072 = _mm_unpacklo_epi16(__y,
4073 __y); // drops another 1/2 => 7/8 total
4074 return __intrin_bitcast<_To>(
4075 __concat(_mm_unpacklo_epi32(__y, __y),
4076 _mm_unpackhi_epi32(__y, __y)));
4077 }
4078 else
4079 __assert_unreachable<_Tp>();
4080 } // }}}
4081 else if constexpr (sizeof(_UI) == 32 && sizeof(__k) == 16)
4082 { // SSE -> AVX {{{
4083 if constexpr (_FromBytes == _ToBytes)
4084 return __intrin_bitcast<_To>(
4085 __intrinsic_type_t<_Tp, 32 / sizeof(_Tp)>(
4086 __zero_extend(__to_intrin(__k))));
4087 else if constexpr (_FromBytes * 2 == _ToBytes)
4088 { // keep all
4089 return __intrin_bitcast<_To>(
4090 __concat(_mm_unpacklo_epi8(__vector_bitcast<_LLong>(__k),
4091 __vector_bitcast<_LLong>(__k)),
4092 _mm_unpackhi_epi8(__vector_bitcast<_LLong>(__k),
4093 __vector_bitcast<_LLong>(__k))));
4094 }
4095 else if constexpr (_FromBytes * 4 == _ToBytes)
4096 {
4097 if constexpr (__have_avx2)
4098 {
4099 return __intrin_bitcast<_To>(_mm256_shuffle_epi8(
4100 __concat(__vector_bitcast<_LLong>(__k),
4101 __vector_bitcast<_LLong>(__k)),
4102 _mm256_setr_epi8(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3,
4103 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,
4104 6, 6, 7, 7, 7, 7)));
4105 }
4106 else
4107 {
4108 return __intrin_bitcast<_To>(__concat(
4109 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4110 _mm_setr_epi8(0, 0, 0, 0, 1, 1, 1, 1,
4111 2, 2, 2, 2, 3, 3, 3, 3)),
4112 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4113 _mm_setr_epi8(4, 4, 4, 4, 5, 5, 5, 5,
4114 6, 6, 6, 6, 7, 7, 7,
4115 7))));
4116 }
4117 }
4118 else if constexpr (_FromBytes * 8 == _ToBytes)
4119 {
4120 if constexpr (__have_avx2)
4121 {
4122 return __intrin_bitcast<_To>(_mm256_shuffle_epi8(
4123 __concat(__vector_bitcast<_LLong>(__k),
4124 __vector_bitcast<_LLong>(__k)),
4125 _mm256_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
4126 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
4127 3, 3, 3, 3, 3, 3)));
4128 }
4129 else
4130 {
4131 return __intrin_bitcast<_To>(__concat(
4132 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4133 _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0,
4134 1, 1, 1, 1, 1, 1, 1, 1)),
4135 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4136 _mm_setr_epi8(2, 2, 2, 2, 2, 2, 2, 2,
4137 3, 3, 3, 3, 3, 3, 3,
4138 3))));
4139 }
4140 }
4141 else if constexpr (_FromBytes == _ToBytes * 2)
4142 return __intrin_bitcast<_To>(__m256i(__zero_extend(
4143 _mm_packs_epi16(__vector_bitcast<_LLong>(__k), __m128i()))));
4144 else if constexpr (_FromBytes == 8 && _ToBytes == 2)
4145 {
4146 return __intrin_bitcast<_To>(__m256i(__zero_extend(
4147 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4148 _mm_setr_epi8(6, 7, 14, 15, -1, -1, -1, -1,
4149 -1, -1, -1, -1, -1, -1, -1,
4150 -1)))));
4151 }
4152 else if constexpr (_FromBytes == 4 && _ToBytes == 1)
4153 {
4154 return __intrin_bitcast<_To>(__m256i(__zero_extend(
4155 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4156 _mm_setr_epi8(3, 7, 11, 15, -1, -1, -1, -1,
4157 -1, -1, -1, -1, -1, -1, -1,
4158 -1)))));
4159 }
4160 else if constexpr (_FromBytes == 8 && _ToBytes == 1)
4161 {
4162 return __intrin_bitcast<_To>(__m256i(__zero_extend(
4163 _mm_shuffle_epi8(__vector_bitcast<_LLong>(__k),
4164 _mm_setr_epi8(7, 15, -1, -1, -1, -1, -1,
4165 -1, -1, -1, -1, -1, -1, -1,
4166 -1, -1)))));
4167 }
4168 else
4169 static_assert(!is_same_v<_Tp, _Tp>, "should be unreachable");
4170 } // }}}
4171 else if constexpr (sizeof(_UI) == 16 && sizeof(__k) == 32)
4172 { // AVX -> SSE {{{
4173 if constexpr (_FromBytes == _ToBytes)
4174 { // keep low 1/2
4175 return __intrin_bitcast<_To>(__lo128(__k));
4176 }
4177 else if constexpr (_FromBytes == _ToBytes * 2)
4178 { // keep all
4179 auto __y = __vector_bitcast<_LLong>(__k);
4180 return __intrin_bitcast<_To>(
4181 _mm_packs_epi16(__lo128(__y), __hi128(__y)));
4182 }
4183 else if constexpr (_FromBytes == _ToBytes * 4)
4184 { // add 1/2 undef
4185 auto __y = __vector_bitcast<_LLong>(__k);
4186 return __intrin_bitcast<_To>(
4187 _mm_packs_epi16(_mm_packs_epi16(__lo128(__y), __hi128(__y)),
4188 __m128i()));
4189 }
4190 else if constexpr (_FromBytes == 8 && _ToBytes == 1)
4191 { // add 3/4 undef
4192 auto __y = __vector_bitcast<_LLong>(__k);
4193 return __intrin_bitcast<_To>(_mm_shuffle_epi8(
4194 _mm_packs_epi16(__lo128(__y), __hi128(__y)),
4195 _mm_setr_epi8(3, 7, 11, 15, -1, -1, -1, -1, -1, -1, -1, -1,
4196 -1, -1, -1, -1)));
4197 }
4198 else if constexpr (_FromBytes * 2 == _ToBytes)
4199 { // keep low 1/4
4200 auto __y = __lo128(__vector_bitcast<_LLong>(__k));
4201 return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__y, __y));
4202 }
4203 else if constexpr (_FromBytes * 4 == _ToBytes)
4204 { // keep low 1/8
4205 auto __y = __lo128(__vector_bitcast<_LLong>(__k));
4206 __y = _mm_unpacklo_epi8(__y, __y);
4207 return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__y, __y));
4208 }
4209 else if constexpr (_FromBytes * 8 == _ToBytes)
4210 { // keep low 1/16
4211 auto __y = __lo128(__vector_bitcast<_LLong>(__k));
4212 __y = _mm_unpacklo_epi8(__y, __y);
4213 __y = _mm_unpacklo_epi8(__y, __y);
4214 return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__y, __y));
4215 }
4216 else
4217 static_assert(!is_same_v<_Tp, _Tp>, "should be unreachable");
4218 } // }}}
4219 else
4220 return _Base::template _S_to_maskvector<_Up, _ToN>(__x);
4221 /*
4222 if constexpr (_FromBytes > _ToBytes) {
4223 const _To __y = __vector_bitcast<_Up>(__k);
4224 return [&] <size_t... _Is> (index_sequence<_Is...>) {
4225 constexpr int _Stride = _FromBytes / _ToBytes;
4226 return _To{__y[(_Is + 1) * _Stride - 1]...};
4227 }(make_index_sequence<std::min(_ToN, _FromN)>());
4228 } else {
4229 // {0, 0, 1, 1} (_Dups = 2, _Is<4>)
4230 // {0, 0, 0, 0, 1, 1, 1, 1} (_Dups = 4, _Is<8>)
4231 // {0, 0, 1, 1, 2, 2, 3, 3} (_Dups = 2, _Is<8>)
4232 // ...
4233 return [&] <size_t... _Is> (index_sequence<_Is...>) {
4234 constexpr int __dup = _ToBytes / _FromBytes;
4235 return __intrin_bitcast<_To>(_From{__k[_Is / __dup]...});
4236 }(make_index_sequence<_FromN>());
4237 }
4238 */
4239 } // }}}
4240 }
4241
4242 // }}}
4243 // _S_to_bits {{{
4244 template <typename _Tp, size_t _Np>
4245 _GLIBCXX_SIMD_INTRINSIC static constexpr _SanitizedBitMask<_Np>
4246 _S_to_bits(_SimdWrapper<_Tp, _Np> __x)
4247 {
4248 if constexpr (is_same_v<_Tp, bool>)
4249 return _BitMask<_Np>(__x._M_data)._M_sanitized();
4250 else
4251 {
4252 static_assert(is_same_v<_Tp, __int_for_sizeof_t<_Tp>>);
4253 if (__builtin_is_constant_evaluated()
4254 || __builtin_constant_p(__x._M_data))
4255 {
4256 const auto __bools = -__x._M_data;
4257 const _ULLong __k = __call_with_n_evaluations<_Np>(
4258 [](auto... __bits) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4259 return (__bits | ...);
4260 }, [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4261 return _ULLong(__bools[+__i]) << __i;
4262 });
4263 if (__builtin_is_constant_evaluated()
4264 || __builtin_constant_p(__k))
4265 return __k;
4266 }
4267 const auto __xi = __to_intrin(__x);
4268 if constexpr (sizeof(_Tp) == 1)
4269 if constexpr (sizeof(__xi) == 16)
4270 if constexpr (__have_avx512bw_vl)
4271 return _BitMask<_Np>(_mm_movepi8_mask(__xi));
4272 else // implies SSE2
4273 return _BitMask<_Np>(_mm_movemask_epi8(__xi));
4274 else if constexpr (sizeof(__xi) == 32)
4275 if constexpr (__have_avx512bw_vl)
4276 return _BitMask<_Np>(_mm256_movepi8_mask(__xi));
4277 else // implies AVX2
4278 return _BitMask<_Np>(_mm256_movemask_epi8(__xi));
4279 else // implies AVX512BW
4280 return _BitMask<_Np>(_mm512_movepi8_mask(__xi));
4281
4282 else if constexpr (sizeof(_Tp) == 2)
4283 if constexpr (sizeof(__xi) == 16)
4284 if constexpr (__have_avx512bw_vl)
4285 return _BitMask<_Np>(_mm_movepi16_mask(__xi));
4286 else if constexpr (__have_avx512bw)
4287 return _BitMask<_Np>(_mm512_movepi16_mask(__zero_extend(__xi)));
4288 else // implies SSE2
4289 return _BitMask<_Np>(
4290 _mm_movemask_epi8(_mm_packs_epi16(__xi, __m128i())));
4291 else if constexpr (sizeof(__xi) == 32)
4292 if constexpr (__have_avx512bw_vl)
4293 return _BitMask<_Np>(_mm256_movepi16_mask(__xi));
4294 else if constexpr (__have_avx512bw)
4295 return _BitMask<_Np>(_mm512_movepi16_mask(__zero_extend(__xi)));
4296 else // implies SSE2
4297 return _BitMask<_Np>(_mm_movemask_epi8(
4298 _mm_packs_epi16(__lo128(__xi), __hi128(__xi))));
4299 else // implies AVX512BW
4300 return _BitMask<_Np>(_mm512_movepi16_mask(__xi));
4301
4302 else if constexpr (sizeof(_Tp) == 4)
4303 if constexpr (sizeof(__xi) == 16)
4304 if constexpr (__have_avx512dq_vl)
4305 return _BitMask<_Np>(_mm_movepi32_mask(__xi));
4306 else if constexpr (__have_avx512vl)
4307 return _BitMask<_Np>(_mm_cmplt_epi32_mask(__xi, __m128i()));
4308 else if constexpr (__have_avx512dq)
4309 return _BitMask<_Np>(_mm512_movepi32_mask(__zero_extend(__xi)));
4310 else if constexpr (__have_avx512f)
4311 return _BitMask<_Np>(
4312 _mm512_cmplt_epi32_mask(__zero_extend(__xi), __m512i()));
4313 else // implies SSE
4314 return _BitMask<_Np>(
4315 _mm_movemask_ps(reinterpret_cast<__m128>(__xi)));
4316 else if constexpr (sizeof(__xi) == 32)
4317 if constexpr (__have_avx512dq_vl)
4318 return _BitMask<_Np>(_mm256_movepi32_mask(__xi));
4319 else if constexpr (__have_avx512dq)
4320 return _BitMask<_Np>(_mm512_movepi32_mask(__zero_extend(__xi)));
4321 else if constexpr (__have_avx512vl)
4322 return _BitMask<_Np>(_mm256_cmplt_epi32_mask(__xi, __m256i()));
4323 else if constexpr (__have_avx512f)
4324 return _BitMask<_Np>(
4325 _mm512_cmplt_epi32_mask(__zero_extend(__xi), __m512i()));
4326 else // implies AVX
4327 return _BitMask<_Np>(
4328 _mm256_movemask_ps(reinterpret_cast<__m256>(__xi)));
4329 else // implies AVX512??
4330 if constexpr (__have_avx512dq)
4331 return _BitMask<_Np>(_mm512_movepi32_mask(__xi));
4332 else // implies AVX512F
4333 return _BitMask<_Np>(_mm512_cmplt_epi32_mask(__xi, __m512i()));
4334
4335 else if constexpr (sizeof(_Tp) == 8)
4336 if constexpr (sizeof(__xi) == 16)
4337 if constexpr (__have_avx512dq_vl)
4338 return _BitMask<_Np>(_mm_movepi64_mask(__xi));
4339 else if constexpr (__have_avx512dq)
4340 return _BitMask<_Np>(_mm512_movepi64_mask(__zero_extend(__xi)));
4341 else if constexpr (__have_avx512vl)
4342 return _BitMask<_Np>(_mm_cmplt_epi64_mask(__xi, __m128i()));
4343 else if constexpr (__have_avx512f)
4344 return _BitMask<_Np>(
4345 _mm512_cmplt_epi64_mask(__zero_extend(__xi), __m512i()));
4346 else // implies SSE2
4347 return _BitMask<_Np>(
4348 _mm_movemask_pd(reinterpret_cast<__m128d>(__xi)));
4349 else if constexpr (sizeof(__xi) == 32)
4350 if constexpr (__have_avx512dq_vl)
4351 return _BitMask<_Np>(_mm256_movepi64_mask(__xi));
4352 else if constexpr (__have_avx512dq)
4353 return _BitMask<_Np>(_mm512_movepi64_mask(__zero_extend(__xi)));
4354 else if constexpr (__have_avx512vl)
4355 return _BitMask<_Np>(_mm256_cmplt_epi64_mask(__xi, __m256i()));
4356 else if constexpr (__have_avx512f)
4357 return _BitMask<_Np>(
4358 _mm512_cmplt_epi64_mask(__zero_extend(__xi), __m512i()));
4359 else // implies AVX
4360 return _BitMask<_Np>(
4361 _mm256_movemask_pd(reinterpret_cast<__m256d>(__xi)));
4362 else // implies AVX512??
4363 if constexpr (__have_avx512dq)
4364 return _BitMask<_Np>(_mm512_movepi64_mask(__xi));
4365 else // implies AVX512F
4366 return _BitMask<_Np>(_mm512_cmplt_epi64_mask(__xi, __m512i()));
4367
4368 else
4369 __assert_unreachable<_Tp>();
4370 }
4371 }
4372 // }}}
4373};
4374
4375// }}}
4376// _MaskImplX86 {{{
4377template <typename _Abi, typename>
4378 struct _MaskImplX86 : _MaskImplX86Mixin, _MaskImplBuiltin<_Abi>
4379 {
4380 using _MaskImplX86Mixin::_S_to_bits;
4381 using _MaskImplX86Mixin::_S_to_maskvector;
4382 using _MaskImplBuiltin<_Abi>::_S_convert;
4383
4384 // member types {{{
4385 template <typename _Tp>
4386 using _SimdMember = typename _Abi::template __traits<_Tp>::_SimdMember;
4387
4388 template <typename _Tp>
4389 using _MaskMember = typename _Abi::template _MaskMember<_Tp>;
4390
4391 template <typename _Tp>
4392 static constexpr size_t _S_size = simd_size_v<_Tp, _Abi>;
4393
4394 using _Base = _MaskImplBuiltin<_Abi>;
4395
4396 // }}}
4397 // _S_broadcast {{{
4398 template <typename _Tp>
4399 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
4400 _S_broadcast(bool __x)
4401 {
4402 if constexpr (__is_avx512_abi<_Abi>())
4403 return __x ? _Abi::_S_masked(_MaskMember<_Tp>(-1))
4404 : _MaskMember<_Tp>();
4405 else
4406 return _Base::template _S_broadcast<_Tp>(__x);
4407 }
4408
4409 // }}}
4410 // _S_load {{{
4411 template <typename _Tp>
4412 _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember<_Tp>
4413 _S_load(const bool* __mem)
4414 {
4415 static_assert(is_same_v<_Tp, __int_for_sizeof_t<_Tp>>);
4416 if (__builtin_is_constant_evaluated())
4417 {
4418 if constexpr (__is_avx512_abi<_Abi>())
4419 {
4420 _MaskMember<_Tp> __r{};
4421 for (size_t __i = 0; __i < _S_size<_Tp>; ++__i)
4422 __r._M_data |= _ULLong(__mem[__i]) << __i;
4423 return __r;
4424 }
4425 else
4426 return _Base::template _S_load<_Tp>(__mem);
4427 }
4428 else if constexpr (__have_avx512bw)
4429 {
4430 const auto __to_vec_or_bits
4431 = [](auto __bits) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA -> decltype(auto) {
4432 if constexpr (__is_avx512_abi<_Abi>())
4433 return __bits;
4434 else
4435 return _S_to_maskvector<_Tp>(
4436 _BitMask<_S_size<_Tp>>(__bits)._M_sanitized());
4437 };
4438
4439 if constexpr (_S_size<_Tp> <= 16 && __have_avx512vl)
4440 {
4441 __m128i __a = {};
4442 __builtin_memcpy(&__a, __mem, _S_size<_Tp>);
4443 return __to_vec_or_bits(_mm_test_epi8_mask(__a, __a));
4444 }
4445 else if constexpr (_S_size<_Tp> <= 32 && __have_avx512vl)
4446 {
4447 __m256i __a = {};
4448 __builtin_memcpy(&__a, __mem, _S_size<_Tp>);
4449 return __to_vec_or_bits(_mm256_test_epi8_mask(__a, __a));
4450 }
4451 else if constexpr (_S_size<_Tp> <= 64)
4452 {
4453 __m512i __a = {};
4454 __builtin_memcpy(&__a, __mem, _S_size<_Tp>);
4455 return __to_vec_or_bits(_mm512_test_epi8_mask(__a, __a));
4456 }
4457 }
4458 else if constexpr (__is_avx512_abi<_Abi>())
4459 {
4460 if constexpr (_S_size<_Tp> <= 8)
4461 {
4462 __m128i __a = {};
4463 __builtin_memcpy(&__a, __mem, _S_size<_Tp>);
4464 const auto __b = _mm512_cvtepi8_epi64(__a);
4465 return _mm512_test_epi64_mask(__b, __b);
4466 }
4467 else if constexpr (_S_size<_Tp> <= 16)
4468 {
4469 __m128i __a = {};
4470 __builtin_memcpy(&__a, __mem, _S_size<_Tp>);
4471 const auto __b = _mm512_cvtepi8_epi32(__a);
4472 return _mm512_test_epi32_mask(__b, __b);
4473 }
4474 else if constexpr (_S_size<_Tp> <= 32)
4475 {
4476 __m128i __a = {};
4477 __builtin_memcpy(&__a, __mem, 16);
4478 const auto __b = _mm512_cvtepi8_epi32(__a);
4479 __builtin_memcpy(&__a, __mem + 16, _S_size<_Tp> - 16);
4480 const auto __c = _mm512_cvtepi8_epi32(__a);
4481 return _mm512_test_epi32_mask(__b, __b)
4482 | (_mm512_test_epi32_mask(__c, __c) << 16);
4483 }
4484 else if constexpr (_S_size<_Tp> <= 64)
4485 {
4486 __m128i __a = {};
4487 __builtin_memcpy(&__a, __mem, 16);
4488 const auto __b = _mm512_cvtepi8_epi32(__a);
4489 __builtin_memcpy(&__a, __mem + 16, 16);
4490 const auto __c = _mm512_cvtepi8_epi32(__a);
4491 if constexpr (_S_size<_Tp> <= 48)
4492 {
4493 __builtin_memcpy(&__a, __mem + 32, _S_size<_Tp> - 32);
4494 const auto __d = _mm512_cvtepi8_epi32(__a);
4495 return _mm512_test_epi32_mask(__b, __b)
4496 | (_mm512_test_epi32_mask(__c, __c) << 16)
4497 | (_ULLong(_mm512_test_epi32_mask(__d, __d)) << 32);
4498 }
4499 else
4500 {
4501 __builtin_memcpy(&__a, __mem + 16, 16);
4502 const auto __d = _mm512_cvtepi8_epi32(__a);
4503 __builtin_memcpy(&__a, __mem + 32, _S_size<_Tp> - 48);
4504 const auto __e = _mm512_cvtepi8_epi32(__a);
4505 return _mm512_test_epi32_mask(__b, __b)
4506 | (_mm512_test_epi32_mask(__c, __c) << 16)
4507 | (_ULLong(_mm512_test_epi32_mask(__d, __d)) << 32)
4508 | (_ULLong(_mm512_test_epi32_mask(__e, __e)) << 48);
4509 }
4510 }
4511 else
4512 __assert_unreachable<_Tp>();
4513 }
4514 else if constexpr (sizeof(_Tp) == 8 && _S_size<_Tp> == 2)
4515 return __vector_bitcast<_Tp>(
4516 __vector_type16_t<int>{-int(__mem[0]), -int(__mem[0]),
4517 -int(__mem[1]), -int(__mem[1])});
4518 else if constexpr (sizeof(_Tp) == 8 && _S_size<_Tp> <= 4 && __have_avx)
4519 {
4520 int __bool4 = 0;
4521 __builtin_memcpy(&__bool4, __mem, _S_size<_Tp>);
4522 const auto __k = __to_intrin(
4523 (__vector_broadcast<4>(__bool4)
4524 & __make_vector<int>(0x1, 0x100, 0x10000,
4525 _S_size<_Tp> == 4 ? 0x1000000 : 0))
4526 != 0);
4527 return __vector_bitcast<_Tp>(
4528 __concat(_mm_unpacklo_epi32(__k, __k),
4529 _mm_unpackhi_epi32(__k, __k)));
4530 }
4531 else if constexpr (sizeof(_Tp) == 4 && _S_size<_Tp> <= 4)
4532 {
4533 int __bools = 0;
4534 __builtin_memcpy(&__bools, __mem, _S_size<_Tp>);
4535 if constexpr (__have_sse2)
4536 {
4537 __m128i __k = _mm_cvtsi32_si128(__bools);
4538 __k = _mm_cmpgt_epi16(_mm_unpacklo_epi8(__k, __k), __m128i());
4539 return __vector_bitcast<_Tp, _S_size<_Tp>>(
4540 _mm_unpacklo_epi16(__k, __k));
4541 }
4542 else
4543 {
4544 __m128 __k = _mm_cvtpi8_ps(_mm_cvtsi32_si64(__bools));
4545 _mm_empty();
4546 return __vector_bitcast<_Tp, _S_size<_Tp>>(
4547 _mm_cmpgt_ps(__k, __m128()));
4548 }
4549 }
4550 else if constexpr (sizeof(_Tp) == 4 && _S_size<_Tp> <= 8)
4551 {
4552 __m128i __k = {};
4553 __builtin_memcpy(&__k, __mem, _S_size<_Tp>);
4554 __k = _mm_cmpgt_epi16(_mm_unpacklo_epi8(__k, __k), __m128i());
4555 return __vector_bitcast<_Tp>(
4556 __concat(_mm_unpacklo_epi16(__k, __k),
4557 _mm_unpackhi_epi16(__k, __k)));
4558 }
4559 else if constexpr (sizeof(_Tp) == 2 && _S_size<_Tp> <= 16)
4560 {
4561 __m128i __k = {};
4562 __builtin_memcpy(&__k, __mem, _S_size<_Tp>);
4563 __k = _mm_cmpgt_epi8(__k, __m128i());
4564 if constexpr (_S_size<_Tp> <= 8)
4565 return __vector_bitcast<_Tp, _S_size<_Tp>>(
4566 _mm_unpacklo_epi8(__k, __k));
4567 else
4568 return __concat(_mm_unpacklo_epi8(__k, __k),
4569 _mm_unpackhi_epi8(__k, __k));
4570 }
4571 else
4572 return _Base::template _S_load<_Tp>(__mem);
4573 }
4574
4575 // }}}
4576 // _S_from_bitmask{{{
4577 template <size_t _Np, typename _Tp>
4578 _GLIBCXX_SIMD_INTRINSIC static _MaskMember<_Tp>
4579 _S_from_bitmask(_SanitizedBitMask<_Np> __bits, _TypeTag<_Tp>)
4580 {
4581 static_assert(is_same_v<_Tp, __int_for_sizeof_t<_Tp>>);
4582 if constexpr (__is_avx512_abi<_Abi>())
4583 return __bits._M_to_bits();
4584 else
4585 return _S_to_maskvector<_Tp, _S_size<_Tp>>(__bits);
4586 }
4587
4588 // }}}
4589 // _S_masked_load {{{2
4590 template <typename _Tp, size_t _Np>
4591 static inline _SimdWrapper<_Tp, _Np>
4592 _S_masked_load(_SimdWrapper<_Tp, _Np> __merge,
4593 _SimdWrapper<_Tp, _Np> __mask, const bool* __mem) noexcept
4594 {
4595 if constexpr (__is_avx512_abi<_Abi>())
4596 {
4597 if constexpr (__have_avx512bw_vl)
4598 {
4599 if constexpr (_Np <= 16)
4600 {
4601 const auto __a
4602 = _mm_mask_loadu_epi8(__m128i(), __mask, __mem);
4603 return (__merge & ~__mask) | _mm_test_epi8_mask(__a, __a);
4604 }
4605 else if constexpr (_Np <= 32)
4606 {
4607 const auto __a
4608 = _mm256_mask_loadu_epi8(__m256i(), __mask, __mem);
4609 return (__merge & ~__mask)
4610 | _mm256_test_epi8_mask(__a, __a);
4611 }
4612 else if constexpr (_Np <= 64)
4613 {
4614 const auto __a
4615 = _mm512_mask_loadu_epi8(__m512i(), __mask, __mem);
4616 return (__merge & ~__mask)
4617 | _mm512_test_epi8_mask(__a, __a);
4618 }
4619 else
4620 __assert_unreachable<_Tp>();
4621 }
4622 else
4623 {
4624 _BitOps::_S_bit_iteration(__mask, [&](auto __i) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4625 __merge._M_set(__i, __mem[__i]);
4626 });
4627 return __merge;
4628 }
4629 }
4630 else if constexpr (__have_avx512bw_vl && _Np == 32 && sizeof(_Tp) == 1)
4631 {
4632 const auto __k = _S_to_bits(__mask)._M_to_bits();
4633 __merge = _mm256_mask_sub_epi8(__to_intrin(__merge), __k, __m256i(),
4634 _mm256_mask_loadu_epi8(__m256i(),
4635 __k, __mem));
4636 }
4637 else if constexpr (__have_avx512bw_vl && _Np == 16 && sizeof(_Tp) == 1)
4638 {
4639 const auto __k = _S_to_bits(__mask)._M_to_bits();
4640 __merge
4641 = _mm_mask_sub_epi8(__vector_bitcast<_LLong>(__merge), __k,
4642 __m128i(),
4643 _mm_mask_loadu_epi8(__m128i(), __k, __mem));
4644 }
4645 else if constexpr (__have_avx512bw_vl && _Np == 16 && sizeof(_Tp) == 2)
4646 {
4647 const auto __k = _S_to_bits(__mask)._M_to_bits();
4648 __merge = _mm256_mask_sub_epi16(
4649 __vector_bitcast<_LLong>(__merge), __k, __m256i(),
4650 _mm256_cvtepi8_epi16(_mm_mask_loadu_epi8(__m128i(), __k, __mem)));
4651 }
4652 else if constexpr (__have_avx512bw_vl && _Np == 8 && sizeof(_Tp) == 2)
4653 {
4654 const auto __k = _S_to_bits(__mask)._M_to_bits();
4655 __merge = _mm_mask_sub_epi16(
4656 __vector_bitcast<_LLong>(__merge), __k, __m128i(),
4657 _mm_cvtepi8_epi16(_mm_mask_loadu_epi8(__m128i(), __k, __mem)));
4658 }
4659 else if constexpr (__have_avx512bw_vl && _Np == 8 && sizeof(_Tp) == 4)
4660 {
4661 const auto __k = _S_to_bits(__mask)._M_to_bits();
4662 __merge = __vector_bitcast<_Tp>(_mm256_mask_sub_epi32(
4663 __vector_bitcast<_LLong>(__merge), __k, __m256i(),
4664 _mm256_cvtepi8_epi32(
4665 _mm_mask_loadu_epi8(__m128i(), __k, __mem))));
4666 }
4667 else if constexpr (__have_avx512bw_vl && _Np == 4 && sizeof(_Tp) == 4)
4668 {
4669 const auto __k = _S_to_bits(__mask)._M_to_bits();
4670 __merge = __vector_bitcast<_Tp>(_mm_mask_sub_epi32(
4671 __vector_bitcast<_LLong>(__merge), __k, __m128i(),
4672 _mm_cvtepi8_epi32(_mm_mask_loadu_epi8(__m128i(), __k, __mem))));
4673 }
4674 else if constexpr (__have_avx512bw_vl && _Np == 4 && sizeof(_Tp) == 8)
4675 {
4676 const auto __k = _S_to_bits(__mask)._M_to_bits();
4677 __merge = __vector_bitcast<_Tp>(_mm256_mask_sub_epi64(
4678 __vector_bitcast<_LLong>(__merge), __k, __m256i(),
4679 _mm256_cvtepi8_epi64(
4680 _mm_mask_loadu_epi8(__m128i(), __k, __mem))));
4681 }
4682 else if constexpr (__have_avx512bw_vl && _Np == 2 && sizeof(_Tp) == 8)
4683 {
4684 const auto __k = _S_to_bits(__mask)._M_to_bits();
4685 __merge = __vector_bitcast<_Tp>(_mm_mask_sub_epi64(
4686 __vector_bitcast<_LLong>(__merge), __k, __m128i(),
4687 _mm_cvtepi8_epi64(_mm_mask_loadu_epi8(__m128i(), __k, __mem))));
4688 }
4689 else
4690 return _Base::_S_masked_load(__merge, __mask, __mem);
4691 return __merge;
4692 }
4693
4694 // _S_store {{{2
4695 template <typename _Tp, size_t _Np>
4696 _GLIBCXX_SIMD_INTRINSIC static constexpr void
4697 _S_store(_SimdWrapper<_Tp, _Np> __v, bool* __mem) noexcept
4698 {
4699 if (__builtin_is_constant_evaluated())
4700 _Base::_S_store(__v, __mem);
4701 else if constexpr (__is_avx512_abi<_Abi>())
4702 {
4703 if constexpr (__have_avx512bw_vl)
4704 _CommonImplX86::_S_store<_Np>(
4705 __vector_bitcast<char>([](auto __data) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
4706 if constexpr (_Np <= 16)
4707 return _mm_maskz_set1_epi8(__data, 1);
4708 else if constexpr (_Np <= 32)
4709 return _mm256_maskz_set1_epi8(__data, 1);
4710 else
4711 return _mm512_maskz_set1_epi8(__data, 1);
4712 }(__v._M_data)),
4713 __mem);
4714 else if constexpr (_Np <= 8)
4715 _CommonImplX86::_S_store<_Np>(
4716 __vector_bitcast<char>(
4717#if defined __x86_64__
4718 __make_wrapper<_ULLong>(
4719 _pdep_u64(__v._M_data, 0x0101010101010101ULL), 0ull)
4720#else
4721 __make_wrapper<_UInt>(_pdep_u32(__v._M_data, 0x01010101U),
4722 _pdep_u32(__v._M_data >> 4,
4723 0x01010101U))
4724#endif
4725 ),
4726 __mem);
4727 else if constexpr (_Np <= 16)
4728 _mm512_mask_cvtepi32_storeu_epi8(
4729 __mem, 0xffffu >> (16 - _Np),
4730 _mm512_maskz_set1_epi32(__v._M_data, 1));
4731 else
4732 __assert_unreachable<_Tp>();
4733 }
4734 else if constexpr (__is_sse_abi<_Abi>()) //{{{
4735 {
4736 if constexpr (_Np == 2 && sizeof(_Tp) == 8)
4737 {
4738 const auto __k = __vector_bitcast<int>(__v);
4739 __mem[0] = -__k[1];
4740 __mem[1] = -__k[3];
4741 }
4742 else if constexpr (_Np <= 4 && sizeof(_Tp) == 4)
4743 {
4744 if constexpr (__have_sse2)
4745 {
4746 const unsigned __bool4
4747 = __vector_bitcast<_UInt>(_mm_packs_epi16(
4748 _mm_packs_epi32(__intrin_bitcast<__m128i>(
4749 __to_intrin(__v)),
4750 __m128i()),
4751 __m128i()))[0]
4752 & 0x01010101u;
4753 __builtin_memcpy(__mem, &__bool4, _Np);
4754 }
4755 else if constexpr (__have_mmx)
4756 {
4757 const __m64 __k = _mm_cvtps_pi8(
4758 __and(__to_intrin(__v), _mm_set1_ps(1.f)));
4759 __builtin_memcpy(__mem, &__k, _Np);
4760 _mm_empty();
4761 }
4762 else
4763 return _Base::_S_store(__v, __mem);
4764 }
4765 else if constexpr (_Np <= 8 && sizeof(_Tp) == 2)
4766 {
4767 _CommonImplX86::_S_store<_Np>(
4768 __vector_bitcast<char>(_mm_packs_epi16(
4769 __to_intrin(__vector_bitcast<_UShort>(__v) >> 15),
4770 __m128i())),
4771 __mem);
4772 }
4773 else if constexpr (_Np <= 16 && sizeof(_Tp) == 1)
4774 _CommonImplX86::_S_store<_Np>(__v._M_data & 1, __mem);
4775 else
4776 __assert_unreachable<_Tp>();
4777 } // }}}
4778 else if constexpr (__is_avx_abi<_Abi>()) // {{{
4779 {
4780 if constexpr (_Np <= 4 && sizeof(_Tp) == 8)
4781 {
4782 auto __k = __intrin_bitcast<__m256i>(__to_intrin(__v));
4783 int __bool4{};
4784 if constexpr (__have_avx2)
4785 __bool4 = _mm256_movemask_epi8(__k);
4786 else
4787 __bool4 = (_mm_movemask_epi8(__lo128(__k))
4788 | (_mm_movemask_epi8(__hi128(__k)) << 16));
4789 __bool4 &= 0x01010101;
4790 __builtin_memcpy(__mem, &__bool4, _Np);
4791 }
4792 else if constexpr (_Np <= 8 && sizeof(_Tp) == 4)
4793 {
4794 const auto __k = __intrin_bitcast<__m256i>(__to_intrin(__v));
4795 const auto __k2
4796 = _mm_srli_epi16(_mm_packs_epi16(__lo128(__k), __hi128(__k)),
4797 15);
4798 const auto __k3
4799 = __vector_bitcast<char>(_mm_packs_epi16(__k2, __m128i()));
4800 _CommonImplX86::_S_store<_Np>(__k3, __mem);
4801 }
4802 else if constexpr (_Np <= 16 && sizeof(_Tp) == 2)
4803 {
4804 if constexpr (__have_avx2)
4805 {
4806 const auto __x = _mm256_srli_epi16(__to_intrin(__v), 15);
4807 const auto __bools = __vector_bitcast<char>(
4808 _mm_packs_epi16(__lo128(__x), __hi128(__x)));
4809 _CommonImplX86::_S_store<_Np>(__bools, __mem);
4810 }
4811 else
4812 {
4813 const auto __bools
4814 = 1
4815 & __vector_bitcast<_UChar>(
4816 _mm_packs_epi16(__lo128(__to_intrin(__v)),
4817 __hi128(__to_intrin(__v))));
4818 _CommonImplX86::_S_store<_Np>(__bools, __mem);
4819 }
4820 }
4821 else if constexpr (_Np <= 32 && sizeof(_Tp) == 1)
4822 _CommonImplX86::_S_store<_Np>(1 & __v._M_data, __mem);
4823 else
4824 __assert_unreachable<_Tp>();
4825 } // }}}
4826 else
4827 __assert_unreachable<_Tp>();
4828 }
4829
4830 // _S_masked_store {{{2
4831 template <typename _Tp, size_t _Np>
4832 static inline void
4833 _S_masked_store(const _SimdWrapper<_Tp, _Np> __v, bool* __mem,
4834 const _SimdWrapper<_Tp, _Np> __k) noexcept
4835 {
4836 if constexpr (__is_avx512_abi<_Abi>())
4837 {
4838 static_assert(is_same_v<_Tp, bool>);
4839 if constexpr (_Np <= 16 && __have_avx512bw_vl)
4840 _mm_mask_storeu_epi8(__mem, __k, _mm_maskz_set1_epi8(__v, 1));
4841 else if constexpr (_Np <= 16)
4842 _mm512_mask_cvtepi32_storeu_epi8(__mem, __k,
4843 _mm512_maskz_set1_epi32(__v, 1));
4844 else if constexpr (_Np <= 32 && __have_avx512bw_vl)
4845 _mm256_mask_storeu_epi8(__mem, __k,
4846 _mm256_maskz_set1_epi8(__v, 1));
4847 else if constexpr (_Np <= 32 && __have_avx512bw)
4848 _mm256_mask_storeu_epi8(__mem, __k,
4849 __lo256(_mm512_maskz_set1_epi8(__v, 1)));
4850 else if constexpr (_Np <= 64 && __have_avx512bw)
4851 _mm512_mask_storeu_epi8(__mem, __k,
4852 _mm512_maskz_set1_epi8(__v, 1));
4853 else
4854 __assert_unreachable<_Tp>();
4855 }
4856 else
4857 _Base::_S_masked_store(__v, __mem, __k);
4858 }
4859
4860 // logical and bitwise operators {{{2
4861 template <typename _Tp, size_t _Np>
4862 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
4863 _S_logical_and(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
4864 {
4865 if constexpr (is_same_v<_Tp, bool>)
4866 {
4867 if (__builtin_is_constant_evaluated())
4868 return __x._M_data & __y._M_data;
4869 else if constexpr (__have_avx512dq && _Np <= 8)
4870 return _kand_mask8(__x._M_data, __y._M_data);
4871 else if constexpr (_Np <= 16)
4872 return _kand_mask16(__x._M_data, __y._M_data);
4873 else if constexpr (__have_avx512bw && _Np <= 32)
4874 return _kand_mask32(__x._M_data, __y._M_data);
4875 else if constexpr (__have_avx512bw && _Np <= 64)
4876 return _kand_mask64(__x._M_data, __y._M_data);
4877 else
4878 __assert_unreachable<_Tp>();
4879 }
4880 else
4881 return _Base::_S_logical_and(__x, __y);
4882 }
4883
4884 template <typename _Tp, size_t _Np>
4885 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
4886 _S_logical_or(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
4887 {
4888 if constexpr (is_same_v<_Tp, bool>)
4889 {
4890 if (__builtin_is_constant_evaluated())
4891 return __x._M_data | __y._M_data;
4892 else if constexpr (__have_avx512dq && _Np <= 8)
4893 return _kor_mask8(__x._M_data, __y._M_data);
4894 else if constexpr (_Np <= 16)
4895 return _kor_mask16(__x._M_data, __y._M_data);
4896 else if constexpr (__have_avx512bw && _Np <= 32)
4897 return _kor_mask32(__x._M_data, __y._M_data);
4898 else if constexpr (__have_avx512bw && _Np <= 64)
4899 return _kor_mask64(__x._M_data, __y._M_data);
4900 else
4901 __assert_unreachable<_Tp>();
4902 }
4903 else
4904 return _Base::_S_logical_or(__x, __y);
4905 }
4906
4907 template <typename _Tp, size_t _Np>
4908 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
4909 _S_bit_not(const _SimdWrapper<_Tp, _Np>& __x)
4910 {
4911 if constexpr (is_same_v<_Tp, bool>)
4912 {
4913 if (__builtin_is_constant_evaluated())
4914 return __x._M_data ^ _Abi::template __implicit_mask_n<_Np>();
4915 else if constexpr (__have_avx512dq && _Np <= 8)
4916 return _kandn_mask8(__x._M_data,
4917 _Abi::template __implicit_mask_n<_Np>());
4918 else if constexpr (_Np <= 16)
4919 return _kandn_mask16(__x._M_data,
4920 _Abi::template __implicit_mask_n<_Np>());
4921 else if constexpr (__have_avx512bw && _Np <= 32)
4922 return _kandn_mask32(__x._M_data,
4923 _Abi::template __implicit_mask_n<_Np>());
4924 else if constexpr (__have_avx512bw && _Np <= 64)
4925 return _kandn_mask64(__x._M_data,
4926 _Abi::template __implicit_mask_n<_Np>());
4927 else
4928 __assert_unreachable<_Tp>();
4929 }
4930 else
4931 return _Base::_S_bit_not(__x);
4932 }
4933
4934 template <typename _Tp, size_t _Np>
4935 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
4936 _S_bit_and(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
4937 {
4938 if constexpr (is_same_v<_Tp, bool>)
4939 {
4940 if (__builtin_is_constant_evaluated())
4941 return __x._M_data & __y._M_data;
4942 else if constexpr (__have_avx512dq && _Np <= 8)
4943 return _kand_mask8(__x._M_data, __y._M_data);
4944 else if constexpr (_Np <= 16)
4945 return _kand_mask16(__x._M_data, __y._M_data);
4946 else if constexpr (__have_avx512bw && _Np <= 32)
4947 return _kand_mask32(__x._M_data, __y._M_data);
4948 else if constexpr (__have_avx512bw && _Np <= 64)
4949 return _kand_mask64(__x._M_data, __y._M_data);
4950 else
4951 __assert_unreachable<_Tp>();
4952 }
4953 else
4954 return _Base::_S_bit_and(__x, __y);
4955 }
4956
4957 template <typename _Tp, size_t _Np>
4958 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
4959 _S_bit_or(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
4960 {
4961 if constexpr (is_same_v<_Tp, bool>)
4962 {
4963 if (__builtin_is_constant_evaluated())
4964 return __x._M_data | __y._M_data;
4965 else if constexpr (__have_avx512dq && _Np <= 8)
4966 return _kor_mask8(__x._M_data, __y._M_data);
4967 else if constexpr (_Np <= 16)
4968 return _kor_mask16(__x._M_data, __y._M_data);
4969 else if constexpr (__have_avx512bw && _Np <= 32)
4970 return _kor_mask32(__x._M_data, __y._M_data);
4971 else if constexpr (__have_avx512bw && _Np <= 64)
4972 return _kor_mask64(__x._M_data, __y._M_data);
4973 else
4974 __assert_unreachable<_Tp>();
4975 }
4976 else
4977 return _Base::_S_bit_or(__x, __y);
4978 }
4979
4980 template <typename _Tp, size_t _Np>
4981 _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
4982 _S_bit_xor(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
4983 {
4984 if constexpr (is_same_v<_Tp, bool>)
4985 {
4986 if (__builtin_is_constant_evaluated())
4987 return __x._M_data ^ __y._M_data;
4988 else if constexpr (__have_avx512dq && _Np <= 8)
4989 return _kxor_mask8(__x._M_data, __y._M_data);
4990 else if constexpr (_Np <= 16)
4991 return _kxor_mask16(__x._M_data, __y._M_data);
4992 else if constexpr (__have_avx512bw && _Np <= 32)
4993 return _kxor_mask32(__x._M_data, __y._M_data);
4994 else if constexpr (__have_avx512bw && _Np <= 64)
4995 return _kxor_mask64(__x._M_data, __y._M_data);
4996 else
4997 __assert_unreachable<_Tp>();
4998 }
4999 else
5000 return _Base::_S_bit_xor(__x, __y);
5001 }
5002
5003 //}}}2
5004 // _S_masked_assign{{{
5005 template <size_t _Np>
5006 _GLIBCXX_SIMD_INTRINSIC static void
5007 _S_masked_assign(_SimdWrapper<bool, _Np> __k,
5008 _SimdWrapper<bool, _Np>& __lhs, _SimdWrapper<bool, _Np> __rhs)
5009 {
5010 __lhs._M_data
5011 = (~__k._M_data & __lhs._M_data) | (__k._M_data & __rhs._M_data);
5012 }
5013
5014 template <size_t _Np>
5015 _GLIBCXX_SIMD_INTRINSIC static void
5016 _S_masked_assign(_SimdWrapper<bool, _Np> __k,
5017 _SimdWrapper<bool, _Np>& __lhs, bool __rhs)
5018 {
5019 if (__rhs)
5020 __lhs._M_data = __k._M_data | __lhs._M_data;
5021 else
5022 __lhs._M_data = ~__k._M_data & __lhs._M_data;
5023 }
5024
5025 using _MaskImplBuiltin<_Abi>::_S_masked_assign;
5026
5027 //}}}
5028 // _S_all_of {{{
5029 template <typename _Tp>
5030 _GLIBCXX_SIMD_INTRINSIC static bool
5031 _S_all_of(simd_mask<_Tp, _Abi> __k)
5032 {
5033 if constexpr (__is_sse_abi<_Abi>() || __is_avx_abi<_Abi>())
5034 {
5035 constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5036 using _TI = __intrinsic_type_t<_Tp, _Np>;
5037 const _TI __a = reinterpret_cast<_TI>(__to_intrin(__data(__k)));
5038 if constexpr (__have_sse4_1)
5039 {
5040 _GLIBCXX_SIMD_USE_CONSTEXPR _TI __b
5041 = _Abi::template _S_implicit_mask_intrin<_Tp>();
5042 return 0 != __testc(__a, __b);
5043 }
5044 else if constexpr (is_same_v<_Tp, float>)
5045 return (_mm_movemask_ps(__a) & ((1 << _Np) - 1))
5046 == (1 << _Np) - 1;
5047 else if constexpr (is_same_v<_Tp, double>)
5048 return (_mm_movemask_pd(__a) & ((1 << _Np) - 1))
5049 == (1 << _Np) - 1;
5050 else
5051 return (_mm_movemask_epi8(__a) & ((1 << (_Np * sizeof(_Tp))) - 1))
5052 == (1 << (_Np * sizeof(_Tp))) - 1;
5053 }
5054 else if constexpr (__is_avx512_abi<_Abi>())
5055 {
5056 constexpr auto _Mask = _Abi::template _S_implicit_mask<_Tp>();
5057 const auto __kk = __k._M_data._M_data;
5058 if constexpr (sizeof(__kk) == 1)
5059 {
5060 if constexpr (__have_avx512dq)
5061 return _kortestc_mask8_u8(__kk, _Mask == 0xff
5062 ? __kk
5063 : __mmask8(~_Mask));
5064 else
5065 return _kortestc_mask16_u8(__kk, __mmask16(~_Mask));
5066 }
5067 else if constexpr (sizeof(__kk) == 2)
5068 return _kortestc_mask16_u8(__kk, _Mask == 0xffff
5069 ? __kk
5070 : __mmask16(~_Mask));
5071 else if constexpr (sizeof(__kk) == 4 && __have_avx512bw)
5072 return _kortestc_mask32_u8(__kk, _Mask == 0xffffffffU
5073 ? __kk
5074 : __mmask32(~_Mask));
5075 else if constexpr (sizeof(__kk) == 8 && __have_avx512bw)
5076 return _kortestc_mask64_u8(__kk, _Mask == 0xffffffffffffffffULL
5077 ? __kk
5078 : __mmask64(~_Mask));
5079 else
5080 __assert_unreachable<_Tp>();
5081 }
5082 }
5083
5084 // }}}
5085 // _S_any_of {{{
5086 template <typename _Tp>
5087 _GLIBCXX_SIMD_INTRINSIC static bool
5088 _S_any_of(simd_mask<_Tp, _Abi> __k)
5089 {
5090 if constexpr (__is_sse_abi<_Abi>() || __is_avx_abi<_Abi>())
5091 {
5092 constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5093 using _TI = __intrinsic_type_t<_Tp, _Np>;
5094 const _TI __a = reinterpret_cast<_TI>(__to_intrin(__data(__k)));
5095 if constexpr (__have_sse4_1)
5096 {
5097 if constexpr (_Abi::template _S_is_partial<
5098 _Tp> || sizeof(__k) < 16)
5099 {
5100 _GLIBCXX_SIMD_USE_CONSTEXPR _TI __b
5101 = _Abi::template _S_implicit_mask_intrin<_Tp>();
5102 return 0 == __testz(__a, __b);
5103 }
5104 else
5105 return 0 == __testz(__a, __a);
5106 }
5107 else if constexpr (is_same_v<_Tp, float>)
5108 return (_mm_movemask_ps(__a) & ((1 << _Np) - 1)) != 0;
5109 else if constexpr (is_same_v<_Tp, double>)
5110 return (_mm_movemask_pd(__a) & ((1 << _Np) - 1)) != 0;
5111 else
5112 return (_mm_movemask_epi8(__a) & ((1 << (_Np * sizeof(_Tp))) - 1))
5113 != 0;
5114 }
5115 else if constexpr (__is_avx512_abi<_Abi>())
5116 return (__k._M_data._M_data & _Abi::template _S_implicit_mask<_Tp>())
5117 != 0;
5118 }
5119
5120 // }}}
5121 // _S_none_of {{{
5122 template <typename _Tp>
5123 _GLIBCXX_SIMD_INTRINSIC static bool
5124 _S_none_of(simd_mask<_Tp, _Abi> __k)
5125 {
5126 if constexpr (__is_sse_abi<_Abi>() || __is_avx_abi<_Abi>())
5127 {
5128 constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5129 using _TI = __intrinsic_type_t<_Tp, _Np>;
5130 const _TI __a = reinterpret_cast<_TI>(__to_intrin(__data(__k)));
5131 if constexpr (__have_sse4_1)
5132 {
5133 if constexpr (_Abi::template _S_is_partial<
5134 _Tp> || sizeof(__k) < 16)
5135 {
5136 _GLIBCXX_SIMD_USE_CONSTEXPR _TI __b
5137 = _Abi::template _S_implicit_mask_intrin<_Tp>();
5138 return 0 != __testz(__a, __b);
5139 }
5140 else
5141 return 0 != __testz(__a, __a);
5142 }
5143 else if constexpr (is_same_v<_Tp, float>)
5144 return (__movemask(__a) & ((1 << _Np) - 1)) == 0;
5145 else if constexpr (is_same_v<_Tp, double>)
5146 return (__movemask(__a) & ((1 << _Np) - 1)) == 0;
5147 else
5148 return (__movemask(__a) & int((1ull << (_Np * sizeof(_Tp))) - 1))
5149 == 0;
5150 }
5151 else if constexpr (__is_avx512_abi<_Abi>())
5152 return (__k._M_data._M_data & _Abi::template _S_implicit_mask<_Tp>())
5153 == 0;
5154 }
5155
5156 // }}}
5157 // _S_some_of {{{
5158 template <typename _Tp>
5159 _GLIBCXX_SIMD_INTRINSIC static bool
5160 _S_some_of(simd_mask<_Tp, _Abi> __k)
5161 {
5162 if constexpr (__is_sse_abi<_Abi>() || __is_avx_abi<_Abi>())
5163 {
5164 constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5165 using _TI = __intrinsic_type_t<_Tp, _Np>;
5166 const _TI __a = reinterpret_cast<_TI>(__to_intrin(__data(__k)));
5167 if constexpr (__have_sse4_1)
5168 {
5169 _GLIBCXX_SIMD_USE_CONSTEXPR _TI __b
5170 = _Abi::template _S_implicit_mask_intrin<_Tp>();
5171 return 0 != __testnzc(__a, __b);
5172 }
5173 else if constexpr (is_same_v<_Tp, float>)
5174 {
5175 constexpr int __allbits = (1 << _Np) - 1;
5176 const auto __tmp = _mm_movemask_ps(__a) & __allbits;
5177 return __tmp > 0 && __tmp < __allbits;
5178 }
5179 else if constexpr (is_same_v<_Tp, double>)
5180 {
5181 constexpr int __allbits = (1 << _Np) - 1;
5182 const auto __tmp = _mm_movemask_pd(__a) & __allbits;
5183 return __tmp > 0 && __tmp < __allbits;
5184 }
5185 else
5186 {
5187 constexpr int __allbits = (1 << (_Np * sizeof(_Tp))) - 1;
5188 const auto __tmp = _mm_movemask_epi8(__a) & __allbits;
5189 return __tmp > 0 && __tmp < __allbits;
5190 }
5191 }
5192 else if constexpr (__is_avx512_abi<_Abi>())
5193 return _S_any_of(__k) && !_S_all_of(__k);
5194 else
5195 __assert_unreachable<_Tp>();
5196 }
5197
5198 // }}}
5199 // _S_popcount {{{
5200 template <typename _Tp>
5201 _GLIBCXX_SIMD_INTRINSIC static int
5202 _S_popcount(simd_mask<_Tp, _Abi> __k)
5203 {
5204 constexpr size_t _Np = simd_size_v<_Tp, _Abi>;
5205 const auto __kk = _Abi::_S_masked(__k._M_data)._M_data;
5206 if constexpr (__is_avx512_abi<_Abi>())
5207 {
5208 if constexpr (_Np > 32)
5209 return __builtin_popcountll(__kk);
5210 else
5211 return __builtin_popcount(__kk);
5212 }
5213 else
5214 {
5215 if constexpr (__have_popcnt)
5216 {
5217 int __bits
5218 = __movemask(__to_intrin(__vector_bitcast<_Tp>(__kk)));
5219 const int __count = __builtin_popcount(__bits);
5220 return is_integral_v<_Tp> ? __count / sizeof(_Tp) : __count;
5221 }
5222 else if constexpr (_Np == 2 && sizeof(_Tp) == 8)
5223 {
5224 const int mask = _mm_movemask_pd(__auto_bitcast(__kk));
5225 return mask - (mask >> 1);
5226 }
5227 else if constexpr (_Np <= 4 && sizeof(_Tp) == 8)
5228 {
5229 auto __x = -(__lo128(__kk) + __hi128(__kk));
5230 return __x[0] + __x[1];
5231 }
5232 else if constexpr (_Np <= 4 && sizeof(_Tp) == 4)
5233 {
5234 if constexpr (__have_sse2)
5235 {
5236 __m128i __x = __intrin_bitcast<__m128i>(__to_intrin(__kk));
5237 __x = _mm_add_epi32(
5238 __x, _mm_shuffle_epi32(__x, _MM_SHUFFLE(0, 1, 2, 3)));
5239 __x = _mm_add_epi32(
5240 __x, _mm_shufflelo_epi16(__x, _MM_SHUFFLE(1, 0, 3, 2)));
5241 return -_mm_cvtsi128_si32(__x);
5242 }
5243 else
5244 return __builtin_popcount(
5245 _mm_movemask_ps(__auto_bitcast(__kk)));
5246 }
5247 else if constexpr (_Np <= 8 && sizeof(_Tp) == 2)
5248 {
5249 auto __x = __to_intrin(__kk);
5250 __x = _mm_add_epi16(__x,
5251 _mm_shuffle_epi32(__x,
5252 _MM_SHUFFLE(0, 1, 2, 3)));
5253 __x = _mm_add_epi16(
5254 __x, _mm_shufflelo_epi16(__x, _MM_SHUFFLE(0, 1, 2, 3)));
5255 __x = _mm_add_epi16(
5256 __x, _mm_shufflelo_epi16(__x, _MM_SHUFFLE(2, 3, 0, 1)));
5257 return -short(_mm_extract_epi16(__x, 0));
5258 }
5259 else if constexpr (_Np <= 16 && sizeof(_Tp) == 1)
5260 {
5261 auto __x = __to_intrin(__kk);
5262 __x = _mm_add_epi8(__x,
5263 _mm_shuffle_epi32(__x,
5264 _MM_SHUFFLE(0, 1, 2, 3)));
5265 __x = _mm_add_epi8(__x,
5266 _mm_shufflelo_epi16(__x, _MM_SHUFFLE(0, 1, 2,
5267 3)));
5268 __x = _mm_add_epi8(__x,
5269 _mm_shufflelo_epi16(__x, _MM_SHUFFLE(2, 3, 0,
5270 1)));
5271 auto __y = -__vector_bitcast<_UChar>(__x);
5272 if constexpr (__have_sse4_1)
5273 return __y[0] + __y[1];
5274 else
5275 {
5276 unsigned __z = _mm_extract_epi16(__to_intrin(__y), 0);
5277 return (__z & 0xff) + (__z >> 8);
5278 }
5279 }
5280 else if constexpr (sizeof(__kk) == 32)
5281 {
5282 // The following works only as long as the implementations above
5283 // use a summation
5284 using _I = __int_for_sizeof_t<_Tp>;
5285 const auto __as_int = __vector_bitcast<_I>(__kk);
5286 _MaskImplX86<simd_abi::__sse>::_S_popcount(
5287 simd_mask<_I, simd_abi::__sse>(__private_init,
5288 __lo128(__as_int)
5289 + __hi128(__as_int)));
5290 }
5291 else
5292 __assert_unreachable<_Tp>();
5293 }
5294 }
5295
5296 // }}}
5297 // _S_find_first_set {{{
5298 template <typename _Tp>
5299 _GLIBCXX_SIMD_INTRINSIC static int
5300 _S_find_first_set(simd_mask<_Tp, _Abi> __k)
5301 {
5302 if constexpr (__is_avx512_abi<_Abi>())
5303 return std::__countr_zero(__k._M_data._M_data);
5304 else
5305 return _Base::_S_find_first_set(__k);
5306 }
5307
5308 // }}}
5309 // _S_find_last_set {{{
5310 template <typename _Tp>
5311 _GLIBCXX_SIMD_INTRINSIC static int
5312 _S_find_last_set(simd_mask<_Tp, _Abi> __k)
5313 {
5314 if constexpr (__is_avx512_abi<_Abi>())
5315 return std::__bit_width(__k._M_data._M_data) - 1;
5316 else
5317 return _Base::_S_find_last_set(__k);
5318 }
5319
5320 // }}}
5321 };
5322
5323// }}}
5324
5325_GLIBCXX_SIMD_END_NAMESPACE
5326#endif // __cplusplus >= 201703L
5327#endif // _GLIBCXX_EXPERIMENTAL_SIMD_X86_H_
5328
5329// vim: foldmethod=marker sw=2 noet ts=8 sts=2 tw=80
typename conditional< _Cond, _Iftrue, _Iffalse >::type conditional_t
Alias template for conditional.
Definition: type_traits:2612
typename make_signed< _Tp >::type make_signed_t
Alias template for make_signed.
Definition: type_traits:1999
constexpr const _Tp & min(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:230