libstdc++
simd_x86_conversions.h
1 // x86 specific conversion optimizations -*- 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_CONVERSIONS_H
26 #define _GLIBCXX_EXPERIMENTAL_SIMD_X86_CONVERSIONS_H
27 
28 #if __cplusplus >= 201703L
29 
30 // work around PR85827
31 // 1-arg __convert_x86 {{{1
32 template <typename _To, typename _V, typename _Traits>
33  _GLIBCXX_SIMD_INTRINSIC _To
34  __convert_x86(_V __v)
35  {
36  static_assert(__is_vector_type_v<_V>);
37  using _Tp = typename _Traits::value_type;
38  constexpr size_t _Np = _Traits::_S_full_size;
39  [[maybe_unused]] const auto __intrin = __to_intrin(__v);
40  using _Up = typename _VectorTraits<_To>::value_type;
41  constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
42 
43  // [xyz]_to_[xyz] {{{2
44  [[maybe_unused]] constexpr bool __x_to_x
45  = sizeof(__v) <= 16 && sizeof(_To) <= 16;
46  [[maybe_unused]] constexpr bool __x_to_y
47  = sizeof(__v) <= 16 && sizeof(_To) == 32;
48  [[maybe_unused]] constexpr bool __x_to_z
49  = sizeof(__v) <= 16 && sizeof(_To) == 64;
50  [[maybe_unused]] constexpr bool __y_to_x
51  = sizeof(__v) == 32 && sizeof(_To) <= 16;
52  [[maybe_unused]] constexpr bool __y_to_y
53  = sizeof(__v) == 32 && sizeof(_To) == 32;
54  [[maybe_unused]] constexpr bool __y_to_z
55  = sizeof(__v) == 32 && sizeof(_To) == 64;
56  [[maybe_unused]] constexpr bool __z_to_x
57  = sizeof(__v) == 64 && sizeof(_To) <= 16;
58  [[maybe_unused]] constexpr bool __z_to_y
59  = sizeof(__v) == 64 && sizeof(_To) == 32;
60  [[maybe_unused]] constexpr bool __z_to_z
61  = sizeof(__v) == 64 && sizeof(_To) == 64;
62 
63  // iX_to_iX {{{2
64  [[maybe_unused]] constexpr bool __i_to_i
65  = is_integral_v<_Up> && is_integral_v<_Tp>;
66  [[maybe_unused]] constexpr bool __i8_to_i16
67  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 2;
68  [[maybe_unused]] constexpr bool __i8_to_i32
69  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 4;
70  [[maybe_unused]] constexpr bool __i8_to_i64
71  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 8;
72  [[maybe_unused]] constexpr bool __i16_to_i8
73  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 1;
74  [[maybe_unused]] constexpr bool __i16_to_i32
75  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 4;
76  [[maybe_unused]] constexpr bool __i16_to_i64
77  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 8;
78  [[maybe_unused]] constexpr bool __i32_to_i8
79  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 1;
80  [[maybe_unused]] constexpr bool __i32_to_i16
81  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 2;
82  [[maybe_unused]] constexpr bool __i32_to_i64
83  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 8;
84  [[maybe_unused]] constexpr bool __i64_to_i8
85  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
86  [[maybe_unused]] constexpr bool __i64_to_i16
87  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 2;
88  [[maybe_unused]] constexpr bool __i64_to_i32
89  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 4;
90 
91  // [fsu]X_to_[fsu]X {{{2
92  // ibw = integral && byte or word, i.e. char and short with any signedness
93  [[maybe_unused]] constexpr bool __s64_to_f32
94  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
95  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
96  [[maybe_unused]] constexpr bool __s32_to_f32
97  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
98  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
99  [[maybe_unused]] constexpr bool __s16_to_f32
100  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
101  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
102  [[maybe_unused]] constexpr bool __s8_to_f32
103  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
104  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
105  [[maybe_unused]] constexpr bool __u64_to_f32
106  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
107  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
108  [[maybe_unused]] constexpr bool __u32_to_f32
109  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
110  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
111  [[maybe_unused]] constexpr bool __u16_to_f32
112  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
113  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
114  [[maybe_unused]] constexpr bool __u8_to_f32
115  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
116  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
117  [[maybe_unused]] constexpr bool __s64_to_f64
118  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
119  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
120  [[maybe_unused]] constexpr bool __s32_to_f64
121  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
122  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
123  [[maybe_unused]] constexpr bool __u64_to_f64
124  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
125  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
126  [[maybe_unused]] constexpr bool __u32_to_f64
127  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
128  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
129  [[maybe_unused]] constexpr bool __f32_to_s64
130  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
131  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
132  [[maybe_unused]] constexpr bool __f32_to_s32
133  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
134  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
135  [[maybe_unused]] constexpr bool __f32_to_u64
136  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
137  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
138  [[maybe_unused]] constexpr bool __f32_to_u32
139  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
140  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
141  [[maybe_unused]] constexpr bool __f64_to_s64
142  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
143  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
144  [[maybe_unused]] constexpr bool __f64_to_s32
145  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
146  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
147  [[maybe_unused]] constexpr bool __f64_to_u64
148  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
149  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
150  [[maybe_unused]] constexpr bool __f64_to_u32
151  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
152  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
153  [[maybe_unused]] constexpr bool __ibw_to_f32
154  = is_integral_v<_Tp> && sizeof(_Tp) <= 2
155  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
156  [[maybe_unused]] constexpr bool __ibw_to_f64
157  = is_integral_v<_Tp> && sizeof(_Tp) <= 2
158  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
159  [[maybe_unused]] constexpr bool __f32_to_ibw
160  = is_integral_v<_Up> && sizeof(_Up) <= 2
161  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
162  [[maybe_unused]] constexpr bool __f64_to_ibw
163  = is_integral_v<_Up> && sizeof(_Up) <= 2
164  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
165  [[maybe_unused]] constexpr bool __f32_to_f64
166  = is_floating_point_v<_Tp> && sizeof(_Tp) == 4
167  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
168  [[maybe_unused]] constexpr bool __f64_to_f32
169  = is_floating_point_v<_Tp> && sizeof(_Tp) == 8
170  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
171 
172  if constexpr (__i_to_i && __y_to_x && !__have_avx2) //{{{2
173  return __convert_x86<_To>(__lo128(__v), __hi128(__v));
174  else if constexpr (__i_to_i && __x_to_y && !__have_avx2) //{{{2
175  return __concat(__convert_x86<__vector_type_t<_Up, _M / 2>>(__v),
176  __convert_x86<__vector_type_t<_Up, _M / 2>>(
177  __extract_part<1, _Np / _M * 2>(__v)));
178  else if constexpr (__i_to_i) //{{{2
179  {
180  static_assert(__x_to_x || __have_avx2,
181  "integral conversions with ymm registers require AVX2");
182  static_assert(__have_avx512bw
183  || ((sizeof(_Tp) >= 4 || sizeof(__v) < 64)
184  && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
185  "8/16-bit integers in zmm registers require AVX512BW");
186  static_assert((sizeof(__v) < 64 && sizeof(_To) < 64) || __have_avx512f,
187  "integral conversions with ymm registers require AVX2");
188  }
189  if constexpr (is_floating_point_v<_Tp> == is_floating_point_v<_Up> && //{{{2
190  sizeof(_Tp) == sizeof(_Up))
191  {
192  // conversion uses simple bit reinterpretation (or no conversion at all)
193  if constexpr (_Np >= _M)
194  return __intrin_bitcast<_To>(__v);
195  else
196  return __zero_extend(__vector_bitcast<_Up>(__v));
197  }
198  else if constexpr (_Np < _M && sizeof(_To) > 16) //{{{2
199  // zero extend (eg. xmm -> ymm)
200  return __zero_extend(
201  __convert_x86<__vector_type_t<
202  _Up, (16 / sizeof(_Up) > _Np) ? 16 / sizeof(_Up) : _Np>>(__v));
203  else if constexpr (_Np > _M && sizeof(__v) > 16) //{{{2
204  // partial input (eg. ymm -> xmm)
205  return __convert_x86<_To>(__extract_part<0, _Np / _M>(__v));
206  else if constexpr (__i64_to_i32) //{{{2
207  {
208  if constexpr (__x_to_x && __have_avx512vl)
209  return __intrin_bitcast<_To>(_mm_cvtepi64_epi32(__intrin));
210  else if constexpr (__x_to_x)
211  return __auto_bitcast(
212  _mm_shuffle_ps(__vector_bitcast<float>(__v), __m128(), 8));
213  else if constexpr (__y_to_x && __have_avx512vl)
214  return __intrin_bitcast<_To>(_mm256_cvtepi64_epi32(__intrin));
215  else if constexpr (__y_to_x && __have_avx512f)
216  return __intrin_bitcast<_To>(
217  __lo128(_mm512_cvtepi64_epi32(__auto_bitcast(__v))));
218  else if constexpr (__y_to_x)
219  return __intrin_bitcast<_To>(
220  __lo128(_mm256_permute4x64_epi64(_mm256_shuffle_epi32(__intrin, 8),
221  0 + 4 * 2)));
222  else if constexpr (__z_to_y)
223  return __intrin_bitcast<_To>(_mm512_cvtepi64_epi32(__intrin));
224  }
225  else if constexpr (__i64_to_i16) //{{{2
226  {
227  if constexpr (__x_to_x && __have_avx512vl)
228  return __intrin_bitcast<_To>(_mm_cvtepi64_epi16(__intrin));
229  else if constexpr (__x_to_x && __have_avx512f)
230  return __intrin_bitcast<_To>(
231  __lo128(_mm512_cvtepi64_epi16(__auto_bitcast(__v))));
232  else if constexpr (__x_to_x && __have_ssse3)
233  {
234  return __intrin_bitcast<_To>(
235  _mm_shuffle_epi8(__intrin,
236  _mm_setr_epi8(0, 1, 8, 9, -0x80, -0x80, -0x80,
237  -0x80, -0x80, -0x80, -0x80, -0x80,
238  -0x80, -0x80, -0x80, -0x80)));
239  // fallback without SSSE3
240  }
241  else if constexpr (__y_to_x && __have_avx512vl)
242  return __intrin_bitcast<_To>(_mm256_cvtepi64_epi16(__intrin));
243  else if constexpr (__y_to_x && __have_avx512f)
244  return __intrin_bitcast<_To>(
245  __lo128(_mm512_cvtepi64_epi16(__auto_bitcast(__v))));
246  else if constexpr (__y_to_x)
247  {
248  const auto __a = _mm256_shuffle_epi8(
249  __intrin,
250  _mm256_setr_epi8(0, 1, 8, 9, -0x80, -0x80, -0x80, -0x80, -0x80,
251  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
252  -0x80, -0x80, -0x80, -0x80, 0, 1, 8, 9, -0x80,
253  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
254  -0x80));
255  return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
256  }
257  else if constexpr (__z_to_x)
258  return __intrin_bitcast<_To>(_mm512_cvtepi64_epi16(__intrin));
259  }
260  else if constexpr (__i64_to_i8) //{{{2
261  {
262  if constexpr (__x_to_x && __have_avx512vl)
263  return __intrin_bitcast<_To>(_mm_cvtepi64_epi8(__intrin));
264  else if constexpr (__x_to_x && __have_avx512f)
265  return __intrin_bitcast<_To>(
266  __lo128(_mm512_cvtepi64_epi8(__zero_extend(__intrin))));
267  else if constexpr (__y_to_x && __have_avx512vl)
268  return __intrin_bitcast<_To>(_mm256_cvtepi64_epi8(__intrin));
269  else if constexpr (__y_to_x && __have_avx512f)
270  return __intrin_bitcast<_To>(
271  _mm512_cvtepi64_epi8(__zero_extend(__intrin)));
272  else if constexpr (__z_to_x)
273  return __intrin_bitcast<_To>(_mm512_cvtepi64_epi8(__intrin));
274  }
275  else if constexpr (__i32_to_i64) //{{{2
276  {
277  if constexpr (__have_sse4_1 && __x_to_x)
278  return __intrin_bitcast<_To>(is_signed_v<_Tp>
279  ? _mm_cvtepi32_epi64(__intrin)
280  : _mm_cvtepu32_epi64(__intrin));
281  else if constexpr (__x_to_x)
282  {
283  return __intrin_bitcast<_To>(
284  _mm_unpacklo_epi32(__intrin, is_signed_v<_Tp>
285  ? _mm_srai_epi32(__intrin, 31)
286  : __m128i()));
287  }
288  else if constexpr (__x_to_y)
289  return __intrin_bitcast<_To>(is_signed_v<_Tp>
290  ? _mm256_cvtepi32_epi64(__intrin)
291  : _mm256_cvtepu32_epi64(__intrin));
292  else if constexpr (__y_to_z)
293  return __intrin_bitcast<_To>(is_signed_v<_Tp>
294  ? _mm512_cvtepi32_epi64(__intrin)
295  : _mm512_cvtepu32_epi64(__intrin));
296  }
297  else if constexpr (__i32_to_i16) //{{{2
298  {
299  if constexpr (__x_to_x && __have_avx512vl)
300  return __intrin_bitcast<_To>(_mm_cvtepi32_epi16(__intrin));
301  else if constexpr (__x_to_x && __have_avx512f)
302  return __intrin_bitcast<_To>(
303  __lo128(_mm512_cvtepi32_epi16(__auto_bitcast(__v))));
304  else if constexpr (__x_to_x && __have_ssse3)
305  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
306  __intrin, _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80,
307  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80)));
308  else if constexpr (__x_to_x)
309  {
310  auto __a = _mm_unpacklo_epi16(__intrin, __m128i()); // 0o.o 1o.o
311  auto __b = _mm_unpackhi_epi16(__intrin, __m128i()); // 2o.o 3o.o
312  auto __c = _mm_unpacklo_epi16(__a, __b); // 02oo ..oo
313  auto __d = _mm_unpackhi_epi16(__a, __b); // 13oo ..oo
314  return __intrin_bitcast<_To>(
315  _mm_unpacklo_epi16(__c, __d)); // 0123 oooo
316  }
317  else if constexpr (__y_to_x && __have_avx512vl)
318  return __intrin_bitcast<_To>(_mm256_cvtepi32_epi16(__intrin));
319  else if constexpr (__y_to_x && __have_avx512f)
320  return __intrin_bitcast<_To>(
321  __lo128(_mm512_cvtepi32_epi16(__auto_bitcast(__v))));
322  else if constexpr (__y_to_x)
323  {
324  auto __a = _mm256_shuffle_epi8(
325  __intrin,
326  _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80, -0x80,
327  -0x80, -0x80, -0x80, -0x80, -0x80, 0, 1, 4, 5, 8,
328  9, 12, 13, -0x80, -0x80, -0x80, -0x80, -0x80,
329  -0x80, -0x80, -0x80));
330  return __intrin_bitcast<_To>(__lo128(
331  _mm256_permute4x64_epi64(__a,
332  0xf8))); // __a[0] __a[2] | __a[3] __a[3]
333  }
334  else if constexpr (__z_to_y)
335  return __intrin_bitcast<_To>(_mm512_cvtepi32_epi16(__intrin));
336  }
337  else if constexpr (__i32_to_i8) //{{{2
338  {
339  if constexpr (__x_to_x && __have_avx512vl)
340  return __intrin_bitcast<_To>(_mm_cvtepi32_epi8(__intrin));
341  else if constexpr (__x_to_x && __have_avx512f)
342  return __intrin_bitcast<_To>(
343  __lo128(_mm512_cvtepi32_epi8(__zero_extend(__intrin))));
344  else if constexpr (__x_to_x && __have_ssse3)
345  {
346  return __intrin_bitcast<_To>(
347  _mm_shuffle_epi8(__intrin,
348  _mm_setr_epi8(0, 4, 8, 12, -0x80, -0x80, -0x80,
349  -0x80, -0x80, -0x80, -0x80, -0x80,
350  -0x80, -0x80, -0x80, -0x80)));
351  }
352  else if constexpr (__x_to_x)
353  {
354  const auto __a
355  = _mm_unpacklo_epi8(__intrin, __intrin); // 0... .... 1... ....
356  const auto __b
357  = _mm_unpackhi_epi8(__intrin, __intrin); // 2... .... 3... ....
358  const auto __c = _mm_unpacklo_epi8(__a, __b); // 02.. .... .... ....
359  const auto __d = _mm_unpackhi_epi8(__a, __b); // 13.. .... .... ....
360  const auto __e = _mm_unpacklo_epi8(__c, __d); // 0123 .... .... ....
361  return __intrin_bitcast<_To>(__e & _mm_cvtsi32_si128(-1));
362  }
363  else if constexpr (__y_to_x && __have_avx512vl)
364  return __intrin_bitcast<_To>(_mm256_cvtepi32_epi8(__intrin));
365  else if constexpr (__y_to_x && __have_avx512f)
366  return __intrin_bitcast<_To>(
367  _mm512_cvtepi32_epi8(__zero_extend(__intrin)));
368  else if constexpr (__z_to_x)
369  return __intrin_bitcast<_To>(_mm512_cvtepi32_epi8(__intrin));
370  }
371  else if constexpr (__i16_to_i64) //{{{2
372  {
373  if constexpr (__x_to_x && __have_sse4_1)
374  return __intrin_bitcast<_To>(is_signed_v<_Tp>
375  ? _mm_cvtepi16_epi64(__intrin)
376  : _mm_cvtepu16_epi64(__intrin));
377  else if constexpr (__x_to_x && is_signed_v<_Tp>)
378  {
379  auto __x = _mm_srai_epi16(__intrin, 15);
380  auto __y = _mm_unpacklo_epi16(__intrin, __x);
381  __x = _mm_unpacklo_epi16(__x, __x);
382  return __intrin_bitcast<_To>(_mm_unpacklo_epi32(__y, __x));
383  }
384  else if constexpr (__x_to_x)
385  return __intrin_bitcast<_To>(
386  _mm_unpacklo_epi32(_mm_unpacklo_epi16(__intrin, __m128i()),
387  __m128i()));
388  else if constexpr (__x_to_y)
389  return __intrin_bitcast<_To>(is_signed_v<_Tp>
390  ? _mm256_cvtepi16_epi64(__intrin)
391  : _mm256_cvtepu16_epi64(__intrin));
392  else if constexpr (__x_to_z)
393  return __intrin_bitcast<_To>(is_signed_v<_Tp>
394  ? _mm512_cvtepi16_epi64(__intrin)
395  : _mm512_cvtepu16_epi64(__intrin));
396  }
397  else if constexpr (__i16_to_i32) //{{{2
398  {
399  if constexpr (__x_to_x && __have_sse4_1)
400  return __intrin_bitcast<_To>(is_signed_v<_Tp>
401  ? _mm_cvtepi16_epi32(__intrin)
402  : _mm_cvtepu16_epi32(__intrin));
403  else if constexpr (__x_to_x && is_signed_v<_Tp>)
404  return __intrin_bitcast<_To>(
405  _mm_srai_epi32(_mm_unpacklo_epi16(__intrin, __intrin), 16));
406  else if constexpr (__x_to_x && is_unsigned_v<_Tp>)
407  return __intrin_bitcast<_To>(_mm_unpacklo_epi16(__intrin, __m128i()));
408  else if constexpr (__x_to_y)
409  return __intrin_bitcast<_To>(is_signed_v<_Tp>
410  ? _mm256_cvtepi16_epi32(__intrin)
411  : _mm256_cvtepu16_epi32(__intrin));
412  else if constexpr (__y_to_z)
413  return __intrin_bitcast<_To>(is_signed_v<_Tp>
414  ? _mm512_cvtepi16_epi32(__intrin)
415  : _mm512_cvtepu16_epi32(__intrin));
416  }
417  else if constexpr (__i16_to_i8) //{{{2
418  {
419  if constexpr (__x_to_x && __have_avx512bw_vl)
420  return __intrin_bitcast<_To>(_mm_cvtepi16_epi8(__intrin));
421  else if constexpr (__x_to_x && __have_avx512bw)
422  return __intrin_bitcast<_To>(
423  __lo128(_mm512_cvtepi16_epi8(__zero_extend(__intrin))));
424  else if constexpr (__x_to_x && __have_ssse3)
425  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
426  __intrin, _mm_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -0x80, -0x80,
427  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80)));
428  else if constexpr (__x_to_x)
429  {
430  auto __a
431  = _mm_unpacklo_epi8(__intrin, __intrin); // 00.. 11.. 22.. 33..
432  auto __b
433  = _mm_unpackhi_epi8(__intrin, __intrin); // 44.. 55.. 66.. 77..
434  auto __c = _mm_unpacklo_epi8(__a, __b); // 0404 .... 1515 ....
435  auto __d = _mm_unpackhi_epi8(__a, __b); // 2626 .... 3737 ....
436  auto __e = _mm_unpacklo_epi8(__c, __d); // 0246 0246 .... ....
437  auto __f = _mm_unpackhi_epi8(__c, __d); // 1357 1357 .... ....
438  return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__e, __f));
439  }
440  else if constexpr (__y_to_x && __have_avx512bw_vl)
441  return __intrin_bitcast<_To>(_mm256_cvtepi16_epi8(__intrin));
442  else if constexpr (__y_to_x && __have_avx512bw)
443  return __intrin_bitcast<_To>(
444  __lo256(_mm512_cvtepi16_epi8(__zero_extend(__intrin))));
445  else if constexpr (__y_to_x)
446  {
447  auto __a = _mm256_shuffle_epi8(
448  __intrin,
449  _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -0x80, -0x80, -0x80,
450  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
451  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, 0, 2,
452  4, 6, 8, 10, 12, 14));
453  return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
454  }
455  else if constexpr (__z_to_y && __have_avx512bw)
456  return __intrin_bitcast<_To>(_mm512_cvtepi16_epi8(__intrin));
457  else if constexpr (__z_to_y)
458  __assert_unreachable<_Tp>();
459  }
460  else if constexpr (__i8_to_i64) //{{{2
461  {
462  if constexpr (__x_to_x && __have_sse4_1)
463  return __intrin_bitcast<_To>(is_signed_v<_Tp>
464  ? _mm_cvtepi8_epi64(__intrin)
465  : _mm_cvtepu8_epi64(__intrin));
466  else if constexpr (__x_to_x && is_signed_v<_Tp>)
467  {
468  if constexpr (__have_ssse3)
469  {
470  auto __dup = _mm_unpacklo_epi8(__intrin, __intrin);
471  auto __epi16 = _mm_srai_epi16(__dup, 8);
472  _mm_shuffle_epi8(__epi16,
473  _mm_setr_epi8(0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3,
474  3, 3, 3, 3, 3));
475  }
476  else
477  {
478  auto __x = _mm_unpacklo_epi8(__intrin, __intrin);
479  __x = _mm_unpacklo_epi16(__x, __x);
480  return __intrin_bitcast<_To>(
481  _mm_unpacklo_epi32(_mm_srai_epi32(__x, 24),
482  _mm_srai_epi32(__x, 31)));
483  }
484  }
485  else if constexpr (__x_to_x)
486  {
487  return __intrin_bitcast<_To>(_mm_unpacklo_epi32(
488  _mm_unpacklo_epi16(_mm_unpacklo_epi8(__intrin, __m128i()),
489  __m128i()),
490  __m128i()));
491  }
492  else if constexpr (__x_to_y)
493  return __intrin_bitcast<_To>(is_signed_v<_Tp>
494  ? _mm256_cvtepi8_epi64(__intrin)
495  : _mm256_cvtepu8_epi64(__intrin));
496  else if constexpr (__x_to_z)
497  return __intrin_bitcast<_To>(is_signed_v<_Tp>
498  ? _mm512_cvtepi8_epi64(__intrin)
499  : _mm512_cvtepu8_epi64(__intrin));
500  }
501  else if constexpr (__i8_to_i32) //{{{2
502  {
503  if constexpr (__x_to_x && __have_sse4_1)
504  return __intrin_bitcast<_To>(is_signed_v<_Tp>
505  ? _mm_cvtepi8_epi32(__intrin)
506  : _mm_cvtepu8_epi32(__intrin));
507  else if constexpr (__x_to_x && is_signed_v<_Tp>)
508  {
509  const auto __x = _mm_unpacklo_epi8(__intrin, __intrin);
510  return __intrin_bitcast<_To>(
511  _mm_srai_epi32(_mm_unpacklo_epi16(__x, __x), 24));
512  }
513  else if constexpr (__x_to_x && is_unsigned_v<_Tp>)
514  return __intrin_bitcast<_To>(
515  _mm_unpacklo_epi16(_mm_unpacklo_epi8(__intrin, __m128i()),
516  __m128i()));
517  else if constexpr (__x_to_y)
518  return __intrin_bitcast<_To>(is_signed_v<_Tp>
519  ? _mm256_cvtepi8_epi32(__intrin)
520  : _mm256_cvtepu8_epi32(__intrin));
521  else if constexpr (__x_to_z)
522  return __intrin_bitcast<_To>(is_signed_v<_Tp>
523  ? _mm512_cvtepi8_epi32(__intrin)
524  : _mm512_cvtepu8_epi32(__intrin));
525  }
526  else if constexpr (__i8_to_i16) //{{{2
527  {
528  if constexpr (__x_to_x && __have_sse4_1)
529  return __intrin_bitcast<_To>(is_signed_v<_Tp>
530  ? _mm_cvtepi8_epi16(__intrin)
531  : _mm_cvtepu8_epi16(__intrin));
532  else if constexpr (__x_to_x && is_signed_v<_Tp>)
533  return __intrin_bitcast<_To>(
534  _mm_srai_epi16(_mm_unpacklo_epi8(__intrin, __intrin), 8));
535  else if constexpr (__x_to_x && is_unsigned_v<_Tp>)
536  return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__intrin, __m128i()));
537  else if constexpr (__x_to_y)
538  return __intrin_bitcast<_To>(is_signed_v<_Tp>
539  ? _mm256_cvtepi8_epi16(__intrin)
540  : _mm256_cvtepu8_epi16(__intrin));
541  else if constexpr (__y_to_z && __have_avx512bw)
542  return __intrin_bitcast<_To>(is_signed_v<_Tp>
543  ? _mm512_cvtepi8_epi16(__intrin)
544  : _mm512_cvtepu8_epi16(__intrin));
545  else if constexpr (__y_to_z)
546  __assert_unreachable<_Tp>();
547  }
548  else if constexpr (__f32_to_s64) //{{{2
549  {
550  if constexpr (__have_avx512dq_vl && __x_to_x)
551  return __intrin_bitcast<_To>(_mm_cvttps_epi64(__intrin));
552  else if constexpr (__have_avx512dq_vl && __x_to_y)
553  return __intrin_bitcast<_To>(_mm256_cvttps_epi64(__intrin));
554  else if constexpr (__have_avx512dq && __y_to_z)
555  return __intrin_bitcast<_To>(_mm512_cvttps_epi64(__intrin));
556  // else use scalar fallback
557  }
558  else if constexpr (__f32_to_u64) //{{{2
559  {
560  if constexpr (__have_avx512dq_vl && __x_to_x)
561  return __intrin_bitcast<_To>(_mm_cvttps_epu64(__intrin));
562  else if constexpr (__have_avx512dq_vl && __x_to_y)
563  return __intrin_bitcast<_To>(_mm256_cvttps_epu64(__intrin));
564  else if constexpr (__have_avx512dq && __y_to_z)
565  return __intrin_bitcast<_To>(_mm512_cvttps_epu64(__intrin));
566  // else use scalar fallback
567  }
568  else if constexpr (__f32_to_s32) //{{{2
569  {
570  if constexpr (__x_to_x || __y_to_y || __z_to_z)
571  {
572  // go to fallback, it does the right thing
573  }
574  else
575  __assert_unreachable<_Tp>();
576  }
577  else if constexpr (__f32_to_u32) //{{{2
578  {
579  if constexpr (__have_avx512vl && __x_to_x)
580  return __auto_bitcast(_mm_cvttps_epu32(__intrin));
581  else if constexpr (__have_avx512f && __x_to_x)
582  return __auto_bitcast(
583  __lo128(_mm512_cvttps_epu32(__auto_bitcast(__v))));
584  else if constexpr (__have_avx512vl && __y_to_y)
585  return __vector_bitcast<_Up>(_mm256_cvttps_epu32(__intrin));
586  else if constexpr (__have_avx512f && __y_to_y)
587  return __vector_bitcast<_Up>(
588  __lo256(_mm512_cvttps_epu32(__auto_bitcast(__v))));
589  else if constexpr (__x_to_x || __y_to_y || __z_to_z)
590  {
591  // go to fallback, it does the right thing. We can't use the
592  // _mm_floor_ps - 0x8000'0000 trick for f32->u32 because it would
593  // discard small input values (only 24 mantissa bits)
594  }
595  else
596  __assert_unreachable<_Tp>();
597  }
598  else if constexpr (__f32_to_ibw) //{{{2
599  return __convert_x86<_To>(__convert_x86<__vector_type_t<int, _Np>>(__v));
600  else if constexpr (__f64_to_s64) //{{{2
601  {
602  if constexpr (__have_avx512dq_vl && __x_to_x)
603  return __intrin_bitcast<_To>(_mm_cvttpd_epi64(__intrin));
604  else if constexpr (__have_avx512dq_vl && __y_to_y)
605  return __intrin_bitcast<_To>(_mm256_cvttpd_epi64(__intrin));
606  else if constexpr (__have_avx512dq && __z_to_z)
607  return __intrin_bitcast<_To>(_mm512_cvttpd_epi64(__intrin));
608  // else use scalar fallback
609  }
610  else if constexpr (__f64_to_u64) //{{{2
611  {
612  if constexpr (__have_avx512dq_vl && __x_to_x)
613  return __intrin_bitcast<_To>(_mm_cvttpd_epu64(__intrin));
614  else if constexpr (__have_avx512dq_vl && __y_to_y)
615  return __intrin_bitcast<_To>(_mm256_cvttpd_epu64(__intrin));
616  else if constexpr (__have_avx512dq && __z_to_z)
617  return __intrin_bitcast<_To>(_mm512_cvttpd_epu64(__intrin));
618  // else use scalar fallback
619  }
620  else if constexpr (__f64_to_s32) //{{{2
621  {
622  if constexpr (__x_to_x)
623  return __intrin_bitcast<_To>(_mm_cvttpd_epi32(__intrin));
624  else if constexpr (__y_to_x)
625  return __intrin_bitcast<_To>(_mm256_cvttpd_epi32(__intrin));
626  else if constexpr (__z_to_y)
627  return __intrin_bitcast<_To>(_mm512_cvttpd_epi32(__intrin));
628  }
629  else if constexpr (__f64_to_u32) //{{{2
630  {
631  if constexpr (__have_avx512vl && __x_to_x)
632  return __intrin_bitcast<_To>(_mm_cvttpd_epu32(__intrin));
633  else if constexpr (__have_sse4_1 && __x_to_x)
634  return __vector_bitcast<_Up, _M>(
635  _mm_cvttpd_epi32(_mm_floor_pd(__intrin) - 0x8000'0000u))
636  ^ 0x8000'0000u;
637  else if constexpr (__x_to_x)
638  {
639  // use scalar fallback: it's only 2 values to convert, can't get
640  // much better than scalar decomposition
641  }
642  else if constexpr (__have_avx512vl && __y_to_x)
643  return __intrin_bitcast<_To>(_mm256_cvttpd_epu32(__intrin));
644  else if constexpr (__y_to_x)
645  {
646  return __intrin_bitcast<_To>(
647  __vector_bitcast<_Up>(
648  _mm256_cvttpd_epi32(_mm256_floor_pd(__intrin) - 0x8000'0000u))
649  ^ 0x8000'0000u);
650  }
651  else if constexpr (__z_to_y)
652  return __intrin_bitcast<_To>(_mm512_cvttpd_epu32(__intrin));
653  }
654  else if constexpr (__f64_to_ibw) //{{{2
655  {
656  return __convert_x86<_To>(
657  __convert_x86<__vector_type_t<int, (_Np < 4 ? 4 : _Np)>>(__v));
658  }
659  else if constexpr (__s64_to_f32) //{{{2
660  {
661  if constexpr (__x_to_x && __have_avx512dq_vl)
662  return __intrin_bitcast<_To>(_mm_cvtepi64_ps(__intrin));
663  else if constexpr (__y_to_x && __have_avx512dq_vl)
664  return __intrin_bitcast<_To>(_mm256_cvtepi64_ps(__intrin));
665  else if constexpr (__z_to_y && __have_avx512dq)
666  return __intrin_bitcast<_To>(_mm512_cvtepi64_ps(__intrin));
667  else if constexpr (__z_to_y)
668  return __intrin_bitcast<_To>(
669  _mm512_cvtpd_ps(__convert_x86<__vector_type_t<double, 8>>(__v)));
670  }
671  else if constexpr (__u64_to_f32) //{{{2
672  {
673  if constexpr (__x_to_x && __have_avx512dq_vl)
674  return __intrin_bitcast<_To>(_mm_cvtepu64_ps(__intrin));
675  else if constexpr (__y_to_x && __have_avx512dq_vl)
676  return __intrin_bitcast<_To>(_mm256_cvtepu64_ps(__intrin));
677  else if constexpr (__z_to_y && __have_avx512dq)
678  return __intrin_bitcast<_To>(_mm512_cvtepu64_ps(__intrin));
679  else if constexpr (__z_to_y)
680  {
681  return __intrin_bitcast<_To>(
682  __lo256(_mm512_cvtepu32_ps(__auto_bitcast(
683  _mm512_cvtepi64_epi32(_mm512_srai_epi64(__intrin, 32)))))
684  * 0x100000000LL
685  + __lo256(_mm512_cvtepu32_ps(
686  __auto_bitcast(_mm512_cvtepi64_epi32(__intrin)))));
687  }
688  }
689  else if constexpr (__s32_to_f32) //{{{2
690  {
691  // use fallback (builtin conversion)
692  }
693  else if constexpr (__u32_to_f32) //{{{2
694  {
695  if constexpr (__x_to_x && __have_avx512vl)
696  {
697  // use fallback
698  }
699  else if constexpr (__x_to_x && __have_avx512f)
700  return __intrin_bitcast<_To>(
701  __lo128(_mm512_cvtepu32_ps(__auto_bitcast(__v))));
702  else if constexpr (__x_to_x && (__have_fma || __have_fma4))
703  // work around PR85819
704  return __auto_bitcast(0x10000
705  * _mm_cvtepi32_ps(__to_intrin(__v >> 16))
706  + _mm_cvtepi32_ps(__to_intrin(__v & 0xffff)));
707  else if constexpr (__y_to_y && __have_avx512vl)
708  {
709  // use fallback
710  }
711  else if constexpr (__y_to_y && __have_avx512f)
712  return __intrin_bitcast<_To>(
713  __lo256(_mm512_cvtepu32_ps(__auto_bitcast(__v))));
714  else if constexpr (__y_to_y)
715  // work around PR85819
716  return 0x10000 * _mm256_cvtepi32_ps(__to_intrin(__v >> 16))
717  + _mm256_cvtepi32_ps(__to_intrin(__v & 0xffff));
718  // else use fallback (builtin conversion)
719  }
720  else if constexpr (__ibw_to_f32) //{{{2
721  {
722  if constexpr (_M <= 4 || __have_avx2)
723  return __convert_x86<_To>(
724  __convert_x86<__vector_type_t<int, _M>>(__v));
725  else
726  {
727  static_assert(__x_to_y);
728  __m128i __a, __b;
729  if constexpr (__have_sse4_1)
730  {
731  __a = sizeof(_Tp) == 2
732  ? (is_signed_v<_Tp> ? _mm_cvtepi16_epi32(__intrin)
733  : _mm_cvtepu16_epi32(__intrin))
734  : (is_signed_v<_Tp> ? _mm_cvtepi8_epi32(__intrin)
735  : _mm_cvtepu8_epi32(__intrin));
736  const auto __w
737  = _mm_shuffle_epi32(__intrin, sizeof(_Tp) == 2 ? 0xee : 0xe9);
738  __b = sizeof(_Tp) == 2
739  ? (is_signed_v<_Tp> ? _mm_cvtepi16_epi32(__w)
740  : _mm_cvtepu16_epi32(__w))
741  : (is_signed_v<_Tp> ? _mm_cvtepi8_epi32(__w)
742  : _mm_cvtepu8_epi32(__w));
743  }
744  else
745  {
746  __m128i __tmp;
747  if constexpr (sizeof(_Tp) == 1)
748  {
749  __tmp = is_signed_v<_Tp>
750  ? _mm_srai_epi16(_mm_unpacklo_epi8(__intrin,
751  __intrin),
752  8)
753  : _mm_unpacklo_epi8(__intrin, __m128i());
754  }
755  else
756  {
757  static_assert(sizeof(_Tp) == 2);
758  __tmp = __intrin;
759  }
760  __a = is_signed_v<_Tp>
761  ? _mm_srai_epi32(_mm_unpacklo_epi16(__tmp, __tmp), 16)
762  : _mm_unpacklo_epi16(__tmp, __m128i());
763  __b = is_signed_v<_Tp>
764  ? _mm_srai_epi32(_mm_unpackhi_epi16(__tmp, __tmp), 16)
765  : _mm_unpackhi_epi16(__tmp, __m128i());
766  }
767  return __convert_x86<_To>(__vector_bitcast<int>(__a),
768  __vector_bitcast<int>(__b));
769  }
770  }
771  else if constexpr (__s64_to_f64) //{{{2
772  {
773  if constexpr (__x_to_x && __have_avx512dq_vl)
774  return __intrin_bitcast<_To>(_mm_cvtepi64_pd(__intrin));
775  else if constexpr (__y_to_y && __have_avx512dq_vl)
776  return __intrin_bitcast<_To>(_mm256_cvtepi64_pd(__intrin));
777  else if constexpr (__z_to_z && __have_avx512dq)
778  return __intrin_bitcast<_To>(_mm512_cvtepi64_pd(__intrin));
779  else if constexpr (__z_to_z)
780  {
781  return __intrin_bitcast<_To>(
782  _mm512_cvtepi32_pd(_mm512_cvtepi64_epi32(__to_intrin(__v >> 32)))
783  * 0x100000000LL
784  + _mm512_cvtepu32_pd(_mm512_cvtepi64_epi32(__intrin)));
785  }
786  }
787  else if constexpr (__u64_to_f64) //{{{2
788  {
789  if constexpr (__x_to_x && __have_avx512dq_vl)
790  return __intrin_bitcast<_To>(_mm_cvtepu64_pd(__intrin));
791  else if constexpr (__y_to_y && __have_avx512dq_vl)
792  return __intrin_bitcast<_To>(_mm256_cvtepu64_pd(__intrin));
793  else if constexpr (__z_to_z && __have_avx512dq)
794  return __intrin_bitcast<_To>(_mm512_cvtepu64_pd(__intrin));
795  else if constexpr (__z_to_z)
796  {
797  return __intrin_bitcast<_To>(
798  _mm512_cvtepu32_pd(_mm512_cvtepi64_epi32(__to_intrin(__v >> 32)))
799  * 0x100000000LL
800  + _mm512_cvtepu32_pd(_mm512_cvtepi64_epi32(__intrin)));
801  }
802  }
803  else if constexpr (__s32_to_f64) //{{{2
804  {
805  if constexpr (__x_to_x)
806  return __intrin_bitcast<_To>(_mm_cvtepi32_pd(__intrin));
807  else if constexpr (__x_to_y)
808  return __intrin_bitcast<_To>(_mm256_cvtepi32_pd(__intrin));
809  else if constexpr (__y_to_z)
810  return __intrin_bitcast<_To>(_mm512_cvtepi32_pd(__intrin));
811  }
812  else if constexpr (__u32_to_f64) //{{{2
813  {
814  if constexpr (__x_to_x && __have_avx512vl)
815  return __intrin_bitcast<_To>(_mm_cvtepu32_pd(__intrin));
816  else if constexpr (__x_to_x && __have_avx512f)
817  return __intrin_bitcast<_To>(
818  __lo128(_mm512_cvtepu32_pd(__auto_bitcast(__v))));
819  else if constexpr (__x_to_x)
820  return __intrin_bitcast<_To>(
821  _mm_cvtepi32_pd(__to_intrin(__v ^ 0x8000'0000u)) + 0x8000'0000u);
822  else if constexpr (__x_to_y && __have_avx512vl)
823  return __intrin_bitcast<_To>(_mm256_cvtepu32_pd(__intrin));
824  else if constexpr (__x_to_y && __have_avx512f)
825  return __intrin_bitcast<_To>(
826  __lo256(_mm512_cvtepu32_pd(__auto_bitcast(__v))));
827  else if constexpr (__x_to_y)
828  return __intrin_bitcast<_To>(
829  _mm256_cvtepi32_pd(__to_intrin(__v ^ 0x8000'0000u)) + 0x8000'0000u);
830  else if constexpr (__y_to_z)
831  return __intrin_bitcast<_To>(_mm512_cvtepu32_pd(__intrin));
832  }
833  else if constexpr (__ibw_to_f64) //{{{2
834  {
835  return __convert_x86<_To>(
836  __convert_x86<__vector_type_t<int, std::max(size_t(4), _M)>>(__v));
837  }
838  else if constexpr (__f32_to_f64) //{{{2
839  {
840  if constexpr (__x_to_x)
841  return __intrin_bitcast<_To>(_mm_cvtps_pd(__intrin));
842  else if constexpr (__x_to_y)
843  return __intrin_bitcast<_To>(_mm256_cvtps_pd(__intrin));
844  else if constexpr (__y_to_z)
845  return __intrin_bitcast<_To>(_mm512_cvtps_pd(__intrin));
846  }
847  else if constexpr (__f64_to_f32) //{{{2
848  {
849  if constexpr (__x_to_x)
850  return __intrin_bitcast<_To>(_mm_cvtpd_ps(__intrin));
851  else if constexpr (__y_to_x)
852  return __intrin_bitcast<_To>(_mm256_cvtpd_ps(__intrin));
853  else if constexpr (__z_to_y)
854  return __intrin_bitcast<_To>(_mm512_cvtpd_ps(__intrin));
855  }
856  else //{{{2
857  __assert_unreachable<_Tp>();
858 
859  // fallback:{{{2
860  return __vector_convert<_To>(__v, make_index_sequence<std::min(_M, _Np)>());
861  //}}}
862  }
863 
864 // }}}
865 // 2-arg __convert_x86 {{{1
866 template <typename _To, typename _V, typename _Traits>
867  _GLIBCXX_SIMD_INTRINSIC _To
868  __convert_x86(_V __v0, _V __v1)
869  {
870  static_assert(__is_vector_type_v<_V>);
871  using _Tp = typename _Traits::value_type;
872  constexpr size_t _Np = _Traits::_S_full_size;
873  [[maybe_unused]] const auto __i0 = __to_intrin(__v0);
874  [[maybe_unused]] const auto __i1 = __to_intrin(__v1);
875  using _Up = typename _VectorTraits<_To>::value_type;
876  constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
877 
878  static_assert(2 * _Np <= _M,
879  "__v1 would be discarded; use the one-argument "
880  "__convert_x86 overload instead");
881 
882  // [xyz]_to_[xyz] {{{2
883  [[maybe_unused]] constexpr bool __x_to_x
884  = sizeof(__v0) <= 16 && sizeof(_To) <= 16;
885  [[maybe_unused]] constexpr bool __x_to_y
886  = sizeof(__v0) <= 16 && sizeof(_To) == 32;
887  [[maybe_unused]] constexpr bool __x_to_z
888  = sizeof(__v0) <= 16 && sizeof(_To) == 64;
889  [[maybe_unused]] constexpr bool __y_to_x
890  = sizeof(__v0) == 32 && sizeof(_To) <= 16;
891  [[maybe_unused]] constexpr bool __y_to_y
892  = sizeof(__v0) == 32 && sizeof(_To) == 32;
893  [[maybe_unused]] constexpr bool __y_to_z
894  = sizeof(__v0) == 32 && sizeof(_To) == 64;
895  [[maybe_unused]] constexpr bool __z_to_x
896  = sizeof(__v0) == 64 && sizeof(_To) <= 16;
897  [[maybe_unused]] constexpr bool __z_to_y
898  = sizeof(__v0) == 64 && sizeof(_To) == 32;
899  [[maybe_unused]] constexpr bool __z_to_z
900  = sizeof(__v0) == 64 && sizeof(_To) == 64;
901 
902  // iX_to_iX {{{2
903  [[maybe_unused]] constexpr bool __i_to_i
904  = is_integral_v<_Up> && is_integral_v<_Tp>;
905  [[maybe_unused]] constexpr bool __i8_to_i16
906  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 2;
907  [[maybe_unused]] constexpr bool __i8_to_i32
908  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 4;
909  [[maybe_unused]] constexpr bool __i8_to_i64
910  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 8;
911  [[maybe_unused]] constexpr bool __i16_to_i8
912  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 1;
913  [[maybe_unused]] constexpr bool __i16_to_i32
914  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 4;
915  [[maybe_unused]] constexpr bool __i16_to_i64
916  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 8;
917  [[maybe_unused]] constexpr bool __i32_to_i8
918  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 1;
919  [[maybe_unused]] constexpr bool __i32_to_i16
920  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 2;
921  [[maybe_unused]] constexpr bool __i32_to_i64
922  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 8;
923  [[maybe_unused]] constexpr bool __i64_to_i8
924  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
925  [[maybe_unused]] constexpr bool __i64_to_i16
926  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 2;
927  [[maybe_unused]] constexpr bool __i64_to_i32
928  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 4;
929 
930  // [fsu]X_to_[fsu]X {{{2
931  // ibw = integral && byte or word, i.e. char and short with any signedness
932  [[maybe_unused]] constexpr bool __i64_to_f32
933  = is_integral_v<_Tp> && sizeof(_Tp) == 8
934  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
935  [[maybe_unused]] constexpr bool __s32_to_f32
936  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
937  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
938  [[maybe_unused]] constexpr bool __s16_to_f32
939  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
940  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
941  [[maybe_unused]] constexpr bool __s8_to_f32
942  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
943  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
944  [[maybe_unused]] constexpr bool __u32_to_f32
945  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
946  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
947  [[maybe_unused]] constexpr bool __u16_to_f32
948  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
949  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
950  [[maybe_unused]] constexpr bool __u8_to_f32
951  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
952  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
953  [[maybe_unused]] constexpr bool __s64_to_f64
954  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
955  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
956  [[maybe_unused]] constexpr bool __s32_to_f64
957  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
958  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
959  [[maybe_unused]] constexpr bool __s16_to_f64
960  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
961  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
962  [[maybe_unused]] constexpr bool __s8_to_f64
963  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
964  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
965  [[maybe_unused]] constexpr bool __u64_to_f64
966  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
967  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
968  [[maybe_unused]] constexpr bool __u32_to_f64
969  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
970  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
971  [[maybe_unused]] constexpr bool __u16_to_f64
972  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
973  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
974  [[maybe_unused]] constexpr bool __u8_to_f64
975  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
976  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
977  [[maybe_unused]] constexpr bool __f32_to_s64
978  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
979  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
980  [[maybe_unused]] constexpr bool __f32_to_s32
981  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
982  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
983  [[maybe_unused]] constexpr bool __f32_to_u64
984  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
985  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
986  [[maybe_unused]] constexpr bool __f32_to_u32
987  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
988  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
989  [[maybe_unused]] constexpr bool __f64_to_s64
990  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
991  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
992  [[maybe_unused]] constexpr bool __f64_to_s32
993  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
994  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
995  [[maybe_unused]] constexpr bool __f64_to_u64
996  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
997  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
998  [[maybe_unused]] constexpr bool __f64_to_u32
999  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
1000  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1001  [[maybe_unused]] constexpr bool __f32_to_ibw
1002  = is_integral_v<_Up> && sizeof(_Up) <= 2
1003  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
1004  [[maybe_unused]] constexpr bool __f64_to_ibw
1005  = is_integral_v<_Up> && sizeof(_Up) <= 2
1006  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1007  [[maybe_unused]] constexpr bool __f32_to_f64
1008  = is_floating_point_v<_Tp> && sizeof(_Tp) == 4
1009  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1010  [[maybe_unused]] constexpr bool __f64_to_f32
1011  = is_floating_point_v<_Tp> && sizeof(_Tp) == 8
1012  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1013 
1014  if constexpr (__i_to_i && __y_to_x && !__have_avx2) //{{{2
1015  // <double, 4>, <double, 4> => <short, 8>
1016  return __convert_x86<_To>(__lo128(__v0), __hi128(__v0), __lo128(__v1),
1017  __hi128(__v1));
1018  else if constexpr (__i_to_i) // assert ISA {{{2
1019  {
1020  static_assert(__x_to_x || __have_avx2,
1021  "integral conversions with ymm registers require AVX2");
1022  static_assert(__have_avx512bw
1023  || ((sizeof(_Tp) >= 4 || sizeof(__v0) < 64)
1024  && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
1025  "8/16-bit integers in zmm registers require AVX512BW");
1026  static_assert((sizeof(__v0) < 64 && sizeof(_To) < 64) || __have_avx512f,
1027  "integral conversions with ymm registers require AVX2");
1028  }
1029  // concat => use 1-arg __convert_x86 {{{2
1030  if constexpr (sizeof(__v0) < 16 || (sizeof(__v0) == 16 && __have_avx2)
1031  || (sizeof(__v0) == 16 && __have_avx
1032  && is_floating_point_v<_Tp>)
1033  || (sizeof(__v0) == 32 && __have_avx512f
1034  && (sizeof(_Tp) >= 4 || __have_avx512bw)))
1035  {
1036  // The ISA can handle wider input registers, so concat and use one-arg
1037  // implementation. This reduces code duplication considerably.
1038  return __convert_x86<_To>(__concat(__v0, __v1));
1039  }
1040  else //{{{2
1041  {
1042  // conversion using bit reinterpretation (or no conversion at all)
1043  // should all go through the concat branch above:
1044  static_assert(
1045  !(is_floating_point_v<
1046  _Tp> == is_floating_point_v<_Up> && sizeof(_Tp) == sizeof(_Up)));
1047  // handle all zero extension{{{2
1048  if constexpr (2 * _Np < _M && sizeof(_To) > 16)
1049  {
1050  constexpr size_t Min = 16 / sizeof(_Up);
1051  return __zero_extend(
1052  __convert_x86<
1053  __vector_type_t<_Up, (Min > 2 * _Np) ? Min : 2 * _Np>>(__v0,
1054  __v1));
1055  }
1056  else if constexpr (__i64_to_i32) //{{{2
1057  {
1058  if constexpr (__x_to_x)
1059  return __auto_bitcast(_mm_shuffle_ps(__auto_bitcast(__v0),
1060  __auto_bitcast(__v1), 0x88));
1061  else if constexpr (__y_to_y)
1062  {
1063  // AVX512F is not available (would concat otherwise)
1064  return __auto_bitcast(
1065  __xzyw(_mm256_shuffle_ps(__auto_bitcast(__v0),
1066  __auto_bitcast(__v1), 0x88)));
1067  // alternative:
1068  // const auto v0_abxxcdxx = _mm256_shuffle_epi32(__v0, 8);
1069  // const auto v1_efxxghxx = _mm256_shuffle_epi32(__v1, 8);
1070  // const auto v_abefcdgh = _mm256_unpacklo_epi64(v0_abxxcdxx,
1071  // v1_efxxghxx); return _mm256_permute4x64_epi64(v_abefcdgh,
1072  // 0x01 * 0 + 0x04 * 2 + 0x10 * 1 + 0x40 * 3); // abcdefgh
1073  }
1074  else if constexpr (__z_to_z)
1075  return __intrin_bitcast<_To>(
1076  __concat(_mm512_cvtepi64_epi32(__i0),
1077  _mm512_cvtepi64_epi32(__i1)));
1078  }
1079  else if constexpr (__i64_to_i16) //{{{2
1080  {
1081  if constexpr (__x_to_x)
1082  {
1083  // AVX2 is not available (would concat otherwise)
1084  if constexpr (__have_sse4_1)
1085  {
1086  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
1087  _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 4), 0x44),
1088  _mm_setr_epi8(0, 1, 8, 9, 4, 5, 12, 13, -0x80, -0x80,
1089  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80)));
1090  }
1091  else
1092  {
1093  return __vector_type_t<_Up, _M>{_Up(__v0[0]), _Up(__v0[1]),
1094  _Up(__v1[0]), _Up(__v1[1])};
1095  }
1096  }
1097  else if constexpr (__y_to_x)
1098  {
1099  auto __a
1100  = _mm256_unpacklo_epi16(__i0, __i1); // 04.. .... 26.. ....
1101  auto __b
1102  = _mm256_unpackhi_epi16(__i0, __i1); // 15.. .... 37.. ....
1103  auto __c
1104  = _mm256_unpacklo_epi16(__a, __b); // 0145 .... 2367 ....
1105  return __intrin_bitcast<_To>(
1106  _mm_unpacklo_epi32(__lo128(__c), __hi128(__c))); // 0123 4567
1107  }
1108  else if constexpr (__z_to_y)
1109  return __intrin_bitcast<_To>(
1110  __concat(_mm512_cvtepi64_epi16(__i0),
1111  _mm512_cvtepi64_epi16(__i1)));
1112  }
1113  else if constexpr (__i64_to_i8) //{{{2
1114  {
1115  if constexpr (__x_to_x && __have_sse4_1)
1116  {
1117  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
1118  _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 4), 0x44),
1119  _mm_setr_epi8(0, 8, 4, 12, -0x80, -0x80, -0x80, -0x80, -0x80,
1120  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
1121  -0x80)));
1122  }
1123  else if constexpr (__x_to_x && __have_ssse3)
1124  {
1125  return __intrin_bitcast<_To>(_mm_unpacklo_epi16(
1126  _mm_shuffle_epi8(
1127  __i0, _mm_setr_epi8(0, 8, -0x80, -0x80, -0x80, -0x80, -0x80,
1128  -0x80, -0x80, -0x80, -0x80, -0x80,
1129  -0x80, -0x80, -0x80, -0x80)),
1130  _mm_shuffle_epi8(
1131  __i1, _mm_setr_epi8(0, 8, -0x80, -0x80, -0x80, -0x80, -0x80,
1132  -0x80, -0x80, -0x80, -0x80, -0x80,
1133  -0x80, -0x80, -0x80, -0x80))));
1134  }
1135  else if constexpr (__x_to_x)
1136  {
1137  return __vector_type_t<_Up, _M>{_Up(__v0[0]), _Up(__v0[1]),
1138  _Up(__v1[0]), _Up(__v1[1])};
1139  }
1140  else if constexpr (__y_to_x)
1141  {
1142  const auto __a = _mm256_shuffle_epi8(
1143  _mm256_blend_epi32(__i0, _mm256_slli_epi64(__i1, 32), 0xAA),
1144  _mm256_setr_epi8(0, 8, -0x80, -0x80, 4, 12, -0x80, -0x80,
1145  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
1146  -0x80, -0x80, -0x80, -0x80, 0, 8, -0x80,
1147  -0x80, 4, 12, -0x80, -0x80, -0x80, -0x80,
1148  -0x80, -0x80, -0x80, -0x80));
1149  return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
1150  } // __z_to_x uses concat fallback
1151  }
1152  else if constexpr (__i32_to_i16) //{{{2
1153  {
1154  if constexpr (__x_to_x)
1155  {
1156  // AVX2 is not available (would concat otherwise)
1157  if constexpr (__have_sse4_1)
1158  {
1159  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
1160  _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 2), 0xaa),
1161  _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10,
1162  11, 14, 15)));
1163  }
1164  else if constexpr (__have_ssse3)
1165  {
1166  return __intrin_bitcast<_To>(
1167  _mm_hadd_epi16(__to_intrin(__v0 << 16),
1168  __to_intrin(__v1 << 16)));
1169  /*
1170  return _mm_unpacklo_epi64(
1171  _mm_shuffle_epi8(__i0, _mm_setr_epi8(0, 1, 4, 5, 8, 9,
1172  12, 13, 8, 9, 12, 13, 12, 13, 14, 15)),
1173  _mm_shuffle_epi8(__i1, _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12,
1174  13, 8, 9, 12, 13, 12, 13, 14, 15)));
1175  */
1176  }
1177  else
1178  {
1179  auto __a = _mm_unpacklo_epi16(__i0, __i1); // 04.. 15..
1180  auto __b = _mm_unpackhi_epi16(__i0, __i1); // 26.. 37..
1181  auto __c = _mm_unpacklo_epi16(__a, __b); // 0246 ....
1182  auto __d = _mm_unpackhi_epi16(__a, __b); // 1357 ....
1183  return __intrin_bitcast<_To>(
1184  _mm_unpacklo_epi16(__c, __d)); // 0123 4567
1185  }
1186  }
1187  else if constexpr (__y_to_y)
1188  {
1189  const auto __shuf
1190  = _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80,
1191  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
1192  0, 1, 4, 5, 8, 9, 12, 13, -0x80, -0x80,
1193  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80);
1194  auto __a = _mm256_shuffle_epi8(__i0, __shuf);
1195  auto __b = _mm256_shuffle_epi8(__i1, __shuf);
1196  return __intrin_bitcast<_To>(
1197  __xzyw(_mm256_unpacklo_epi64(__a, __b)));
1198  } // __z_to_z uses concat fallback
1199  }
1200  else if constexpr (__i32_to_i8) //{{{2
1201  {
1202  if constexpr (__x_to_x && __have_ssse3)
1203  {
1204  const auto shufmask
1205  = _mm_setr_epi8(0, 4, 8, 12, -0x80, -0x80, -0x80, -0x80,
1206  -0x80, -0x80, -0x80, -0x80, -0x80, -0x80,
1207  -0x80, -0x80);
1208  return __intrin_bitcast<_To>(
1209  _mm_unpacklo_epi32(_mm_shuffle_epi8(__i0, shufmask),
1210  _mm_shuffle_epi8(__i1, shufmask)));
1211  }
1212  else if constexpr (__x_to_x)
1213  {
1214  auto __a = _mm_unpacklo_epi8(__i0, __i1); // 04.. .... 15.. ....
1215  auto __b = _mm_unpackhi_epi8(__i0, __i1); // 26.. .... 37.. ....
1216  auto __c = _mm_unpacklo_epi8(__a, __b); // 0246 .... .... ....
1217  auto __d = _mm_unpackhi_epi8(__a, __b); // 1357 .... .... ....
1218  auto __e = _mm_unpacklo_epi8(__c, __d); // 0123 4567 .... ....
1219  return __intrin_bitcast<_To>(__e & __m128i{-1, 0});
1220  }
1221  else if constexpr (__y_to_x)
1222  {
1223  const auto __a = _mm256_shuffle_epi8(
1224  _mm256_blend_epi16(__i0, _mm256_slli_epi32(__i1, 16), 0xAA),
1225  _mm256_setr_epi8(0, 4, 8, 12, -0x80, -0x80, -0x80, -0x80, 2,
1226  6, 10, 14, -0x80, -0x80, -0x80, -0x80, -0x80,
1227  -0x80, -0x80, -0x80, 0, 4, 8, 12, -0x80,
1228  -0x80, -0x80, -0x80, 2, 6, 10, 14));
1229  return __intrin_bitcast<_To>(__lo128(__a) | __hi128(__a));
1230  } // __z_to_y uses concat fallback
1231  }
1232  else if constexpr (__i16_to_i8) //{{{2
1233  {
1234  if constexpr (__x_to_x && __have_ssse3)
1235  {
1236  const auto __shuf = reinterpret_cast<__m128i>(
1237  __vector_type_t<_UChar, 16>{0, 2, 4, 6, 8, 10, 12, 14, 0x80,
1238  0x80, 0x80, 0x80, 0x80, 0x80,
1239  0x80, 0x80});
1240  return __intrin_bitcast<_To>(
1241  _mm_unpacklo_epi64(_mm_shuffle_epi8(__i0, __shuf),
1242  _mm_shuffle_epi8(__i1, __shuf)));
1243  }
1244  else if constexpr (__x_to_x)
1245  {
1246  auto __a = _mm_unpacklo_epi8(__i0, __i1); // 08.. 19.. 2A.. 3B..
1247  auto __b = _mm_unpackhi_epi8(__i0, __i1); // 4C.. 5D.. 6E.. 7F..
1248  auto __c = _mm_unpacklo_epi8(__a, __b); // 048C .... 159D ....
1249  auto __d = _mm_unpackhi_epi8(__a, __b); // 26AE .... 37BF ....
1250  auto __e = _mm_unpacklo_epi8(__c, __d); // 0246 8ACE .... ....
1251  auto __f = _mm_unpackhi_epi8(__c, __d); // 1357 9BDF .... ....
1252  return __intrin_bitcast<_To>(_mm_unpacklo_epi8(__e, __f));
1253  }
1254  else if constexpr (__y_to_y)
1255  {
1256  return __intrin_bitcast<_To>(__xzyw(_mm256_shuffle_epi8(
1257  (__to_intrin(__v0) & _mm256_set1_epi32(0x00ff00ff))
1258  | _mm256_slli_epi16(__i1, 8),
1259  _mm256_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11,
1260  13, 15, 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5,
1261  7, 9, 11, 13, 15))));
1262  } // __z_to_z uses concat fallback
1263  }
1264  else if constexpr (__i64_to_f32) //{{{2
1265  {
1266  if constexpr (__x_to_x)
1267  return __make_wrapper<float>(__v0[0], __v0[1], __v1[0], __v1[1]);
1268  else if constexpr (__y_to_y)
1269  {
1270  static_assert(__y_to_y && __have_avx2);
1271  const auto __a = _mm256_unpacklo_epi32(__i0, __i1); // aeAE cgCG
1272  const auto __b = _mm256_unpackhi_epi32(__i0, __i1); // bfBF dhDH
1273  const auto __lo32
1274  = _mm256_unpacklo_epi32(__a, __b); // abef cdgh
1275  const auto __hi32 = __vector_bitcast<
1276  conditional_t<is_signed_v<_Tp>, int, _UInt>>(
1277  _mm256_unpackhi_epi32(__a, __b)); // ABEF CDGH
1278  const auto __hi
1279  = 0x100000000LL
1280  * __convert_x86<__vector_type_t<float, 8>>(__hi32);
1281  const auto __mid
1282  = 0x10000 * _mm256_cvtepi32_ps(_mm256_srli_epi32(__lo32, 16));
1283  const auto __lo
1284  = _mm256_cvtepi32_ps(_mm256_set1_epi32(0x0000ffffu) & __lo32);
1285  return __xzyw((__hi + __mid) + __lo);
1286  }
1287  else if constexpr (__z_to_z && __have_avx512dq)
1288  {
1289  return is_signed_v<_Tp> ? __concat(_mm512_cvtepi64_ps(__i0),
1290  _mm512_cvtepi64_ps(__i1))
1291  : __concat(_mm512_cvtepu64_ps(__i0),
1292  _mm512_cvtepu64_ps(__i1));
1293  }
1294  else if constexpr (__z_to_z && is_signed_v<_Tp>)
1295  {
1296  const __m512 __hi32 = _mm512_cvtepi32_ps(
1297  __concat(_mm512_cvtepi64_epi32(__to_intrin(__v0 >> 32)),
1298  _mm512_cvtepi64_epi32(__to_intrin(__v1 >> 32))));
1299  const __m512i __lo32 = __concat(_mm512_cvtepi64_epi32(__i0),
1300  _mm512_cvtepi64_epi32(__i1));
1301  // split low 32-bits, because if __hi32 is a small negative
1302  // number, the 24-bit mantissa may lose important information if
1303  // any of the high 8 bits of __lo32 is set, leading to
1304  // catastrophic cancelation in the FMA
1305  const __m512 __hi16
1306  = _mm512_cvtepu32_ps(_mm512_set1_epi32(0xffff0000u) & __lo32);
1307  const __m512 __lo16
1308  = _mm512_cvtepi32_ps(_mm512_set1_epi32(0x0000ffffu) & __lo32);
1309  return (__hi32 * 0x100000000LL + __hi16) + __lo16;
1310  }
1311  else if constexpr (__z_to_z && is_unsigned_v<_Tp>)
1312  {
1313  return __intrin_bitcast<_To>(
1314  _mm512_cvtepu32_ps(__concat(
1315  _mm512_cvtepi64_epi32(_mm512_srai_epi64(__i0, 32)),
1316  _mm512_cvtepi64_epi32(_mm512_srai_epi64(__i1, 32))))
1317  * 0x100000000LL
1318  + _mm512_cvtepu32_ps(__concat(_mm512_cvtepi64_epi32(__i0),
1319  _mm512_cvtepi64_epi32(__i1))));
1320  }
1321  }
1322  else if constexpr (__f64_to_s32) //{{{2
1323  {
1324  // use concat fallback
1325  }
1326  else if constexpr (__f64_to_u32) //{{{2
1327  {
1328  if constexpr (__x_to_x && __have_sse4_1)
1329  {
1330  return __vector_bitcast<_Up, _M>(_mm_unpacklo_epi64(
1331  _mm_cvttpd_epi32(_mm_floor_pd(__i0) - 0x8000'0000u),
1332  _mm_cvttpd_epi32(_mm_floor_pd(__i1) - 0x8000'0000u)))
1333  ^ 0x8000'0000u;
1334  // without SSE4.1 just use the scalar fallback, it's only four
1335  // values
1336  }
1337  else if constexpr (__y_to_y)
1338  {
1339  return __vector_bitcast<_Up>(
1340  __concat(_mm256_cvttpd_epi32(_mm256_floor_pd(__i0)
1341  - 0x8000'0000u),
1342  _mm256_cvttpd_epi32(_mm256_floor_pd(__i1)
1343  - 0x8000'0000u)))
1344  ^ 0x8000'0000u;
1345  } // __z_to_z uses fallback
1346  }
1347  else if constexpr (__f64_to_ibw) //{{{2
1348  {
1349  // one-arg __f64_to_ibw goes via _SimdWrapper<int, ?>. The fallback
1350  // would go via two independet conversions to _SimdWrapper<_To> and
1351  // subsequent interleaving. This is better, because f64->__i32
1352  // allows to combine __v0 and __v1 into one register: if constexpr
1353  // (__z_to_x || __y_to_x) {
1354  return __convert_x86<_To>(
1355  __convert_x86<__vector_type_t<int, _Np * 2>>(__v0, __v1));
1356  //}
1357  }
1358  else if constexpr (__f32_to_ibw) //{{{2
1359  {
1360  return __convert_x86<_To>(
1361  __convert_x86<__vector_type_t<int, _Np>>(__v0),
1362  __convert_x86<__vector_type_t<int, _Np>>(__v1));
1363  } //}}}
1364 
1365  // fallback: {{{2
1366  if constexpr (sizeof(_To) >= 32)
1367  // if _To is ymm or zmm, then _SimdWrapper<_Up, _M / 2> is xmm or ymm
1368  return __concat(__convert_x86<__vector_type_t<_Up, _M / 2>>(__v0),
1369  __convert_x86<__vector_type_t<_Up, _M / 2>>(__v1));
1370  else if constexpr (sizeof(_To) == 16)
1371  {
1372  const auto __lo = __to_intrin(__convert_x86<_To>(__v0));
1373  const auto __hi = __to_intrin(__convert_x86<_To>(__v1));
1374  if constexpr (sizeof(_Up) * _Np == 8)
1375  {
1376  if constexpr (is_floating_point_v<_Up>)
1377  return __auto_bitcast(
1378  _mm_unpacklo_pd(__vector_bitcast<double>(__lo),
1379  __vector_bitcast<double>(__hi)));
1380  else
1381  return __intrin_bitcast<_To>(_mm_unpacklo_epi64(__lo, __hi));
1382  }
1383  else if constexpr (sizeof(_Up) * _Np == 4)
1384  {
1385  if constexpr (is_floating_point_v<_Up>)
1386  return __auto_bitcast(
1387  _mm_unpacklo_ps(__vector_bitcast<float>(__lo),
1388  __vector_bitcast<float>(__hi)));
1389  else
1390  return __intrin_bitcast<_To>(_mm_unpacklo_epi32(__lo, __hi));
1391  }
1392  else if constexpr (sizeof(_Up) * _Np == 2)
1393  return __intrin_bitcast<_To>(_mm_unpacklo_epi16(__lo, __hi));
1394  else
1395  __assert_unreachable<_Tp>();
1396  }
1397  else
1398  return __vector_convert<_To>(__v0, __v1, make_index_sequence<_Np>());
1399  //}}}
1400  }
1401  }
1402 
1403 //}}}1
1404 // 4-arg __convert_x86 {{{1
1405 template <typename _To, typename _V, typename _Traits>
1406  _GLIBCXX_SIMD_INTRINSIC _To
1407  __convert_x86(_V __v0, _V __v1, _V __v2, _V __v3)
1408  {
1409  static_assert(__is_vector_type_v<_V>);
1410  using _Tp = typename _Traits::value_type;
1411  constexpr size_t _Np = _Traits::_S_full_size;
1412  [[maybe_unused]] const auto __i0 = __to_intrin(__v0);
1413  [[maybe_unused]] const auto __i1 = __to_intrin(__v1);
1414  [[maybe_unused]] const auto __i2 = __to_intrin(__v2);
1415  [[maybe_unused]] const auto __i3 = __to_intrin(__v3);
1416  using _Up = typename _VectorTraits<_To>::value_type;
1417  constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
1418 
1419  static_assert(4 * _Np <= _M,
1420  "__v2/__v3 would be discarded; use the two/one-argument "
1421  "__convert_x86 overload instead");
1422 
1423  // [xyz]_to_[xyz] {{{2
1424  [[maybe_unused]] constexpr bool __x_to_x
1425  = sizeof(__v0) <= 16 && sizeof(_To) <= 16;
1426  [[maybe_unused]] constexpr bool __x_to_y
1427  = sizeof(__v0) <= 16 && sizeof(_To) == 32;
1428  [[maybe_unused]] constexpr bool __x_to_z
1429  = sizeof(__v0) <= 16 && sizeof(_To) == 64;
1430  [[maybe_unused]] constexpr bool __y_to_x
1431  = sizeof(__v0) == 32 && sizeof(_To) <= 16;
1432  [[maybe_unused]] constexpr bool __y_to_y
1433  = sizeof(__v0) == 32 && sizeof(_To) == 32;
1434  [[maybe_unused]] constexpr bool __y_to_z
1435  = sizeof(__v0) == 32 && sizeof(_To) == 64;
1436  [[maybe_unused]] constexpr bool __z_to_x
1437  = sizeof(__v0) == 64 && sizeof(_To) <= 16;
1438  [[maybe_unused]] constexpr bool __z_to_y
1439  = sizeof(__v0) == 64 && sizeof(_To) == 32;
1440  [[maybe_unused]] constexpr bool __z_to_z
1441  = sizeof(__v0) == 64 && sizeof(_To) == 64;
1442 
1443  // iX_to_iX {{{2
1444  [[maybe_unused]] constexpr bool __i_to_i
1445  = is_integral_v<_Up> && is_integral_v<_Tp>;
1446  [[maybe_unused]] constexpr bool __i8_to_i16
1447  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 2;
1448  [[maybe_unused]] constexpr bool __i8_to_i32
1449  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 4;
1450  [[maybe_unused]] constexpr bool __i8_to_i64
1451  = __i_to_i && sizeof(_Tp) == 1 && sizeof(_Up) == 8;
1452  [[maybe_unused]] constexpr bool __i16_to_i8
1453  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 1;
1454  [[maybe_unused]] constexpr bool __i16_to_i32
1455  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 4;
1456  [[maybe_unused]] constexpr bool __i16_to_i64
1457  = __i_to_i && sizeof(_Tp) == 2 && sizeof(_Up) == 8;
1458  [[maybe_unused]] constexpr bool __i32_to_i8
1459  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 1;
1460  [[maybe_unused]] constexpr bool __i32_to_i16
1461  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 2;
1462  [[maybe_unused]] constexpr bool __i32_to_i64
1463  = __i_to_i && sizeof(_Tp) == 4 && sizeof(_Up) == 8;
1464  [[maybe_unused]] constexpr bool __i64_to_i8
1465  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
1466  [[maybe_unused]] constexpr bool __i64_to_i16
1467  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 2;
1468  [[maybe_unused]] constexpr bool __i64_to_i32
1469  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 4;
1470 
1471  // [fsu]X_to_[fsu]X {{{2
1472  // ibw = integral && byte or word, i.e. char and short with any signedness
1473  [[maybe_unused]] constexpr bool __i64_to_f32
1474  = is_integral_v<_Tp> && sizeof(_Tp) == 8
1475  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1476  [[maybe_unused]] constexpr bool __s32_to_f32
1477  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
1478  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1479  [[maybe_unused]] constexpr bool __s16_to_f32
1480  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
1481  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1482  [[maybe_unused]] constexpr bool __s8_to_f32
1483  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
1484  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1485  [[maybe_unused]] constexpr bool __u32_to_f32
1486  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
1487  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1488  [[maybe_unused]] constexpr bool __u16_to_f32
1489  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
1490  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1491  [[maybe_unused]] constexpr bool __u8_to_f32
1492  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
1493  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1494  [[maybe_unused]] constexpr bool __s64_to_f64
1495  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 8
1496  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1497  [[maybe_unused]] constexpr bool __s32_to_f64
1498  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 4
1499  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1500  [[maybe_unused]] constexpr bool __s16_to_f64
1501  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 2
1502  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1503  [[maybe_unused]] constexpr bool __s8_to_f64
1504  = is_integral_v<_Tp> && is_signed_v<_Tp> && sizeof(_Tp) == 1
1505  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1506  [[maybe_unused]] constexpr bool __u64_to_f64
1507  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 8
1508  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1509  [[maybe_unused]] constexpr bool __u32_to_f64
1510  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 4
1511  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1512  [[maybe_unused]] constexpr bool __u16_to_f64
1513  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 2
1514  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1515  [[maybe_unused]] constexpr bool __u8_to_f64
1516  = is_integral_v<_Tp> && is_unsigned_v<_Tp> && sizeof(_Tp) == 1
1517  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1518  [[maybe_unused]] constexpr bool __f32_to_s64
1519  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
1520  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
1521  [[maybe_unused]] constexpr bool __f32_to_s32
1522  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
1523  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
1524  [[maybe_unused]] constexpr bool __f32_to_u64
1525  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
1526  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
1527  [[maybe_unused]] constexpr bool __f32_to_u32
1528  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
1529  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
1530  [[maybe_unused]] constexpr bool __f64_to_s64
1531  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 8
1532  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1533  [[maybe_unused]] constexpr bool __f64_to_s32
1534  = is_integral_v<_Up> && is_signed_v<_Up> && sizeof(_Up) == 4
1535  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1536  [[maybe_unused]] constexpr bool __f64_to_u64
1537  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 8
1538  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1539  [[maybe_unused]] constexpr bool __f64_to_u32
1540  = is_integral_v<_Up> && is_unsigned_v<_Up> && sizeof(_Up) == 4
1541  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1542  [[maybe_unused]] constexpr bool __f32_to_ibw
1543  = is_integral_v<_Up> && sizeof(_Up) <= 2
1544  && is_floating_point_v<_Tp> && sizeof(_Tp) == 4;
1545  [[maybe_unused]] constexpr bool __f64_to_ibw
1546  = is_integral_v<_Up> && sizeof(_Up) <= 2
1547  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1548  [[maybe_unused]] constexpr bool __f32_to_f64
1549  = is_floating_point_v<_Tp> && sizeof(_Tp) == 4
1550  && is_floating_point_v<_Up> && sizeof(_Up) == 8;
1551  [[maybe_unused]] constexpr bool __f64_to_f32
1552  = is_floating_point_v<_Tp> && sizeof(_Tp) == 8
1553  && is_floating_point_v<_Up> && sizeof(_Up) == 4;
1554 
1555  if constexpr (__i_to_i && __y_to_x && !__have_avx2) //{{{2
1556  {
1557  // <double, 4>, <double, 4>, <double, 4>, <double, 4> => <char, 16>
1558  return __convert_x86<_To>(__lo128(__v0), __hi128(__v0), __lo128(__v1),
1559  __hi128(__v1), __lo128(__v2), __hi128(__v2),
1560  __lo128(__v3), __hi128(__v3));
1561  }
1562  else if constexpr (__i_to_i) // assert ISA {{{2
1563  {
1564  static_assert(__x_to_x || __have_avx2,
1565  "integral conversions with ymm registers require AVX2");
1566  static_assert(__have_avx512bw
1567  || ((sizeof(_Tp) >= 4 || sizeof(__v0) < 64)
1568  && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
1569  "8/16-bit integers in zmm registers require AVX512BW");
1570  static_assert((sizeof(__v0) < 64 && sizeof(_To) < 64) || __have_avx512f,
1571  "integral conversions with ymm registers require AVX2");
1572  }
1573  // concat => use 2-arg __convert_x86 {{{2
1574  if constexpr (sizeof(__v0) < 16 || (sizeof(__v0) == 16 && __have_avx2)
1575  || (sizeof(__v0) == 16 && __have_avx
1576  && is_floating_point_v<_Tp>)
1577  || (sizeof(__v0) == 32 && __have_avx512f))
1578  {
1579  // The ISA can handle wider input registers, so concat and use two-arg
1580  // implementation. This reduces code duplication considerably.
1581  return __convert_x86<_To>(__concat(__v0, __v1), __concat(__v2, __v3));
1582  }
1583  else //{{{2
1584  {
1585  // conversion using bit reinterpretation (or no conversion at all)
1586  // should all go through the concat branch above:
1587  static_assert(
1588  !(is_floating_point_v<
1589  _Tp> == is_floating_point_v<_Up> && sizeof(_Tp) == sizeof(_Up)));
1590  // handle all zero extension{{{2
1591  if constexpr (4 * _Np < _M && sizeof(_To) > 16)
1592  {
1593  constexpr size_t Min = 16 / sizeof(_Up);
1594  return __zero_extend(
1595  __convert_x86<
1596  __vector_type_t<_Up, (Min > 4 * _Np) ? Min : 4 * _Np>>(
1597  __v0, __v1, __v2, __v3));
1598  }
1599  else if constexpr (__i64_to_i16) //{{{2
1600  {
1601  if constexpr (__x_to_x && __have_sse4_1)
1602  {
1603  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
1604  _mm_blend_epi16(
1605  _mm_blend_epi16(__i0, _mm_slli_si128(__i1, 2), 0x22),
1606  _mm_blend_epi16(_mm_slli_si128(__i2, 4),
1607  _mm_slli_si128(__i3, 6), 0x88),
1608  0xcc),
1609  _mm_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7,
1610  14, 15)));
1611  }
1612  else if constexpr (__y_to_y && __have_avx2)
1613  {
1614  return __intrin_bitcast<_To>(_mm256_shuffle_epi8(
1615  __xzyw(_mm256_blend_epi16(
1616  __auto_bitcast(
1617  _mm256_shuffle_ps(__vector_bitcast<float>(__v0),
1618  __vector_bitcast<float>(__v2),
1619  0x88)), // 0.1. 8.9. 2.3. A.B.
1620  __to_intrin(__vector_bitcast<int>(_mm256_shuffle_ps(
1621  __vector_bitcast<float>(__v1),
1622  __vector_bitcast<float>(__v3), 0x88))
1623  << 16), // .4.5 .C.D .6.7 .E.F
1624  0xaa) // 0415 8C9D 2637 AEBF
1625  ), // 0415 2637 8C9D AEBF
1626  _mm256_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11,
1627  14, 15, 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7,
1628  10, 11, 14, 15)));
1629  /*
1630  auto __a = _mm256_unpacklo_epi16(__v0, __v1); // 04.. .... 26..
1631  .... auto __b = _mm256_unpackhi_epi16(__v0, __v1); // 15..
1632  .... 37.. .... auto __c = _mm256_unpacklo_epi16(__v2, __v3); //
1633  8C.. .... AE.. .... auto __d = _mm256_unpackhi_epi16(__v2,
1634  __v3);
1635  // 9D.. .... BF.. .... auto __e = _mm256_unpacklo_epi16(__a,
1636  __b);
1637  // 0145 .... 2367 .... auto __f = _mm256_unpacklo_epi16(__c,
1638  __d);
1639  // 89CD .... ABEF .... auto __g = _mm256_unpacklo_epi64(__e,
1640  __f);
1641  // 0145 89CD 2367 ABEF return __concat(
1642  _mm_unpacklo_epi32(__lo128(__g), __hi128(__g)),
1643  _mm_unpackhi_epi32(__lo128(__g), __hi128(__g))); // 0123
1644  4567 89AB CDEF
1645  */
1646  } // else use fallback
1647  }
1648  else if constexpr (__i64_to_i8) //{{{2
1649  {
1650  if constexpr (__x_to_x)
1651  {
1652  // TODO: use fallback for now
1653  }
1654  else if constexpr (__y_to_x)
1655  {
1656  auto __a
1657  = _mm256_srli_epi32(_mm256_slli_epi32(__i0, 24), 24)
1658  | _mm256_srli_epi32(_mm256_slli_epi32(__i1, 24), 16)
1659  | _mm256_srli_epi32(_mm256_slli_epi32(__i2, 24), 8)
1660  | _mm256_slli_epi32(
1661  __i3, 24); // 048C .... 159D .... 26AE .... 37BF ....
1662  /*return _mm_shuffle_epi8(
1663  _mm_blend_epi32(__lo128(__a) << 32, __hi128(__a), 0x5),
1664  _mm_setr_epi8(4, 12, 0, 8, 5, 13, 1, 9, 6, 14, 2, 10, 7, 15,
1665  3, 11));*/
1666  auto __b = _mm256_unpackhi_epi64(
1667  __a, __a); // 159D .... 159D .... 37BF .... 37BF ....
1668  auto __c = _mm256_unpacklo_epi8(
1669  __a, __b); // 0145 89CD .... .... 2367 ABEF .... ....
1670  return __intrin_bitcast<_To>(
1671  _mm_unpacklo_epi16(__lo128(__c),
1672  __hi128(__c))); // 0123 4567 89AB CDEF
1673  }
1674  }
1675  else if constexpr (__i32_to_i8) //{{{2
1676  {
1677  if constexpr (__x_to_x)
1678  {
1679  if constexpr (__have_ssse3)
1680  {
1681  const auto __x0 = __vector_bitcast<_UInt>(__v0) & 0xff;
1682  const auto __x1 = (__vector_bitcast<_UInt>(__v1) & 0xff)
1683  << 8;
1684  const auto __x2 = (__vector_bitcast<_UInt>(__v2) & 0xff)
1685  << 16;
1686  const auto __x3 = __vector_bitcast<_UInt>(__v3) << 24;
1687  return __intrin_bitcast<_To>(
1688  _mm_shuffle_epi8(__to_intrin(__x0 | __x1 | __x2 | __x3),
1689  _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13,
1690  2, 6, 10, 14, 3, 7, 11,
1691  15)));
1692  }
1693  else
1694  {
1695  auto __a
1696  = _mm_unpacklo_epi8(__i0, __i2); // 08.. .... 19.. ....
1697  auto __b
1698  = _mm_unpackhi_epi8(__i0, __i2); // 2A.. .... 3B.. ....
1699  auto __c
1700  = _mm_unpacklo_epi8(__i1, __i3); // 4C.. .... 5D.. ....
1701  auto __d
1702  = _mm_unpackhi_epi8(__i1, __i3); // 6E.. .... 7F.. ....
1703  auto __e
1704  = _mm_unpacklo_epi8(__a, __c); // 048C .... .... ....
1705  auto __f
1706  = _mm_unpackhi_epi8(__a, __c); // 159D .... .... ....
1707  auto __g
1708  = _mm_unpacklo_epi8(__b, __d); // 26AE .... .... ....
1709  auto __h
1710  = _mm_unpackhi_epi8(__b, __d); // 37BF .... .... ....
1711  return __intrin_bitcast<_To>(_mm_unpacklo_epi8(
1712  _mm_unpacklo_epi8(__e, __g), // 0246 8ACE .... ....
1713  _mm_unpacklo_epi8(__f, __h) // 1357 9BDF .... ....
1714  )); // 0123 4567 89AB CDEF
1715  }
1716  }
1717  else if constexpr (__y_to_y)
1718  {
1719  const auto __a = _mm256_shuffle_epi8(
1720  __to_intrin((__vector_bitcast<_UShort>(_mm256_blend_epi16(
1721  __i0, _mm256_slli_epi32(__i1, 16), 0xAA))
1722  & 0xff)
1723  | (__vector_bitcast<_UShort>(_mm256_blend_epi16(
1724  __i2, _mm256_slli_epi32(__i3, 16), 0xAA))
1725  << 8)),
1726  _mm256_setr_epi8(0, 4, 8, 12, 2, 6, 10, 14, 1, 5, 9, 13, 3, 7,
1727  11, 15, 0, 4, 8, 12, 2, 6, 10, 14, 1, 5, 9,
1728  13, 3, 7, 11, 15));
1729  return __intrin_bitcast<_To>(_mm256_permutevar8x32_epi32(
1730  __a, _mm256_setr_epi32(0, 4, 1, 5, 2, 6, 3, 7)));
1731  }
1732  }
1733  else if constexpr (__i64_to_f32) //{{{2
1734  {
1735  // this branch is only relevant with AVX and w/o AVX2 (i.e. no ymm
1736  // integers)
1737  if constexpr (__x_to_y)
1738  {
1739  return __make_wrapper<float>(__v0[0], __v0[1], __v1[0], __v1[1],
1740  __v2[0], __v2[1], __v3[0],
1741  __v3[1]);
1742 
1743  const auto __a = _mm_unpacklo_epi32(__i0, __i1); // acAC
1744  const auto __b = _mm_unpackhi_epi32(__i0, __i1); // bdBD
1745  const auto __c = _mm_unpacklo_epi32(__i2, __i3); // egEG
1746  const auto __d = _mm_unpackhi_epi32(__i2, __i3); // fhFH
1747  const auto __lo32a = _mm_unpacklo_epi32(__a, __b); // abcd
1748  const auto __lo32b = _mm_unpacklo_epi32(__c, __d); // efgh
1749  const auto __hi32 = __vector_bitcast<
1750  conditional_t<is_signed_v<_Tp>, int, _UInt>>(
1751  __concat(_mm_unpackhi_epi32(__a, __b),
1752  _mm_unpackhi_epi32(__c, __d))); // ABCD EFGH
1753  const auto __hi
1754  = 0x100000000LL
1755  * __convert_x86<__vector_type_t<float, 8>>(__hi32);
1756  const auto __mid
1757  = 0x10000
1758  * _mm256_cvtepi32_ps(__concat(_mm_srli_epi32(__lo32a, 16),
1759  _mm_srli_epi32(__lo32b, 16)));
1760  const auto __lo = _mm256_cvtepi32_ps(
1761  __concat(_mm_set1_epi32(0x0000ffffu) & __lo32a,
1762  _mm_set1_epi32(0x0000ffffu) & __lo32b));
1763  return (__hi + __mid) + __lo;
1764  }
1765  }
1766  else if constexpr (__f64_to_ibw) //{{{2
1767  {
1768  return __convert_x86<_To>(
1769  __convert_x86<__vector_type_t<int, _Np * 2>>(__v0, __v1),
1770  __convert_x86<__vector_type_t<int, _Np * 2>>(__v2, __v3));
1771  }
1772  else if constexpr (__f32_to_ibw) //{{{2
1773  {
1774  return __convert_x86<_To>(
1775  __convert_x86<__vector_type_t<int, _Np>>(__v0),
1776  __convert_x86<__vector_type_t<int, _Np>>(__v1),
1777  __convert_x86<__vector_type_t<int, _Np>>(__v2),
1778  __convert_x86<__vector_type_t<int, _Np>>(__v3));
1779  } //}}}
1780 
1781  // fallback: {{{2
1782  if constexpr (sizeof(_To) >= 32)
1783  // if _To is ymm or zmm, then _SimdWrapper<_Up, _M / 2> is xmm or ymm
1784  return __concat(__convert_x86<__vector_type_t<_Up, _M / 2>>(__v0,
1785  __v1),
1786  __convert_x86<__vector_type_t<_Up, _M / 2>>(__v2,
1787  __v3));
1788  else if constexpr (sizeof(_To) == 16)
1789  {
1790  const auto __lo = __to_intrin(__convert_x86<_To>(__v0, __v1));
1791  const auto __hi = __to_intrin(__convert_x86<_To>(__v2, __v3));
1792  if constexpr (sizeof(_Up) * _Np * 2 == 8)
1793  {
1794  if constexpr (is_floating_point_v<_Up>)
1795  return __auto_bitcast(_mm_unpacklo_pd(__lo, __hi));
1796  else
1797  return __intrin_bitcast<_To>(_mm_unpacklo_epi64(__lo, __hi));
1798  }
1799  else if constexpr (sizeof(_Up) * _Np * 2 == 4)
1800  {
1801  if constexpr (is_floating_point_v<_Up>)
1802  return __auto_bitcast(_mm_unpacklo_ps(__lo, __hi));
1803  else
1804  return __intrin_bitcast<_To>(_mm_unpacklo_epi32(__lo, __hi));
1805  }
1806  else
1807  __assert_unreachable<_Tp>();
1808  }
1809  else
1810  return __vector_convert<_To>(__v0, __v1, __v2, __v3,
1811  make_index_sequence<_Np>());
1812  //}}}2
1813  }
1814  }
1815 
1816 //}}}
1817 // 8-arg __convert_x86 {{{1
1818 template <typename _To, typename _V, typename _Traits>
1819  _GLIBCXX_SIMD_INTRINSIC _To
1820  __convert_x86(_V __v0, _V __v1, _V __v2, _V __v3, _V __v4, _V __v5, _V __v6,
1821  _V __v7)
1822  {
1823  static_assert(__is_vector_type_v<_V>);
1824  using _Tp = typename _Traits::value_type;
1825  constexpr size_t _Np = _Traits::_S_full_size;
1826  [[maybe_unused]] const auto __i0 = __to_intrin(__v0);
1827  [[maybe_unused]] const auto __i1 = __to_intrin(__v1);
1828  [[maybe_unused]] const auto __i2 = __to_intrin(__v2);
1829  [[maybe_unused]] const auto __i3 = __to_intrin(__v3);
1830  [[maybe_unused]] const auto __i4 = __to_intrin(__v4);
1831  [[maybe_unused]] const auto __i5 = __to_intrin(__v5);
1832  [[maybe_unused]] const auto __i6 = __to_intrin(__v6);
1833  [[maybe_unused]] const auto __i7 = __to_intrin(__v7);
1834  using _Up = typename _VectorTraits<_To>::value_type;
1835  constexpr size_t _M = _VectorTraits<_To>::_S_full_size;
1836 
1837  static_assert(8 * _Np <= _M,
1838  "__v4-__v7 would be discarded; use the four/two/one-argument "
1839  "__convert_x86 overload instead");
1840 
1841  // [xyz]_to_[xyz] {{{2
1842  [[maybe_unused]] constexpr bool __x_to_x
1843  = sizeof(__v0) <= 16 && sizeof(_To) <= 16;
1844  [[maybe_unused]] constexpr bool __x_to_y
1845  = sizeof(__v0) <= 16 && sizeof(_To) == 32;
1846  [[maybe_unused]] constexpr bool __x_to_z
1847  = sizeof(__v0) <= 16 && sizeof(_To) == 64;
1848  [[maybe_unused]] constexpr bool __y_to_x
1849  = sizeof(__v0) == 32 && sizeof(_To) <= 16;
1850  [[maybe_unused]] constexpr bool __y_to_y
1851  = sizeof(__v0) == 32 && sizeof(_To) == 32;
1852  [[maybe_unused]] constexpr bool __y_to_z
1853  = sizeof(__v0) == 32 && sizeof(_To) == 64;
1854  [[maybe_unused]] constexpr bool __z_to_x
1855  = sizeof(__v0) == 64 && sizeof(_To) <= 16;
1856  [[maybe_unused]] constexpr bool __z_to_y
1857  = sizeof(__v0) == 64 && sizeof(_To) == 32;
1858  [[maybe_unused]] constexpr bool __z_to_z
1859  = sizeof(__v0) == 64 && sizeof(_To) == 64;
1860 
1861  // [if]X_to_i8 {{{2
1862  [[maybe_unused]] constexpr bool __i_to_i
1863  = is_integral_v<_Up> && is_integral_v<_Tp>;
1864  [[maybe_unused]] constexpr bool __i64_to_i8
1865  = __i_to_i && sizeof(_Tp) == 8 && sizeof(_Up) == 1;
1866  [[maybe_unused]] constexpr bool __f64_to_i8
1867  = is_integral_v<_Up> && sizeof(_Up) == 1
1868  && is_floating_point_v<_Tp> && sizeof(_Tp) == 8;
1869 
1870  if constexpr (__i_to_i) // assert ISA {{{2
1871  {
1872  static_assert(__x_to_x || __have_avx2,
1873  "integral conversions with ymm registers require AVX2");
1874  static_assert(__have_avx512bw
1875  || ((sizeof(_Tp) >= 4 || sizeof(__v0) < 64)
1876  && (sizeof(_Up) >= 4 || sizeof(_To) < 64)),
1877  "8/16-bit integers in zmm registers require AVX512BW");
1878  static_assert((sizeof(__v0) < 64 && sizeof(_To) < 64) || __have_avx512f,
1879  "integral conversions with ymm registers require AVX2");
1880  }
1881  // concat => use 4-arg __convert_x86 {{{2
1882  if constexpr (sizeof(__v0) < 16 || (sizeof(__v0) == 16 && __have_avx2)
1883  || (sizeof(__v0) == 16 && __have_avx
1884  && is_floating_point_v<_Tp>)
1885  || (sizeof(__v0) == 32 && __have_avx512f))
1886  {
1887  // The ISA can handle wider input registers, so concat and use two-arg
1888  // implementation. This reduces code duplication considerably.
1889  return __convert_x86<_To>(__concat(__v0, __v1), __concat(__v2, __v3),
1890  __concat(__v4, __v5), __concat(__v6, __v7));
1891  }
1892  else //{{{2
1893  {
1894  // conversion using bit reinterpretation (or no conversion at all)
1895  // should all go through the concat branch above:
1896  static_assert(
1897  !(is_floating_point_v<
1898  _Tp> == is_floating_point_v<_Up> && sizeof(_Tp) == sizeof(_Up)));
1899  static_assert(!(8 * _Np < _M && sizeof(_To) > 16),
1900  "zero extension should be impossible");
1901  if constexpr (__i64_to_i8) //{{{2
1902  {
1903  if constexpr (__x_to_x && __have_ssse3)
1904  {
1905  // unsure whether this is better than the variant below
1906  return __intrin_bitcast<_To>(_mm_shuffle_epi8(
1907  __to_intrin(
1908  (((__v0 & 0xff) | ((__v1 & 0xff) << 8))
1909  | (((__v2 & 0xff) << 16) | ((__v3 & 0xff) << 24)))
1910  | ((((__v4 & 0xff) << 32) | ((__v5 & 0xff) << 40))
1911  | (((__v6 & 0xff) << 48) | (__v7 << 56)))),
1912  _mm_setr_epi8(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14,
1913  7, 15)));
1914  }
1915  else if constexpr (__x_to_x)
1916  {
1917  const auto __a = _mm_unpacklo_epi8(__i0, __i1); // ac
1918  const auto __b = _mm_unpackhi_epi8(__i0, __i1); // bd
1919  const auto __c = _mm_unpacklo_epi8(__i2, __i3); // eg
1920  const auto __d = _mm_unpackhi_epi8(__i2, __i3); // fh
1921  const auto __e = _mm_unpacklo_epi8(__i4, __i5); // ik
1922  const auto __f = _mm_unpackhi_epi8(__i4, __i5); // jl
1923  const auto __g = _mm_unpacklo_epi8(__i6, __i7); // mo
1924  const auto __h = _mm_unpackhi_epi8(__i6, __i7); // np
1925  return __intrin_bitcast<_To>(_mm_unpacklo_epi64(
1926  _mm_unpacklo_epi32(_mm_unpacklo_epi8(__a, __b), // abcd
1927  _mm_unpacklo_epi8(__c, __d)), // efgh
1928  _mm_unpacklo_epi32(_mm_unpacklo_epi8(__e, __f), // ijkl
1929  _mm_unpacklo_epi8(__g, __h)) // mnop
1930  ));
1931  }
1932  else if constexpr (__y_to_y)
1933  {
1934  auto __a = // 048C GKOS 159D HLPT 26AE IMQU 37BF JNRV
1935  __to_intrin(
1936  (((__v0 & 0xff) | ((__v1 & 0xff) << 8))
1937  | (((__v2 & 0xff) << 16) | ((__v3 & 0xff) << 24)))
1938  | ((((__v4 & 0xff) << 32) | ((__v5 & 0xff) << 40))
1939  | (((__v6 & 0xff) << 48) | ((__v7 << 56)))));
1940  /*
1941  auto __b = _mm256_unpackhi_epi64(__a, __a); // 159D HLPT 159D
1942  HLPT 37BF JNRV 37BF JNRV auto __c = _mm256_unpacklo_epi8(__a,
1943  __b); // 0145 89CD GHKL OPST 2367 ABEF IJMN QRUV auto __d =
1944  __xzyw(__c); // 0145 89CD 2367 ABEF GHKL OPST IJMN QRUV return
1945  _mm256_shuffle_epi8(
1946  __d, _mm256_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12,
1947  13, 6, 7, 14, 15, 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7,
1948  14, 15));
1949  */
1950  auto __b = _mm256_shuffle_epi8( // 0145 89CD GHKL OPST 2367 ABEF
1951  // IJMN QRUV
1952  __a, _mm256_setr_epi8(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13,
1953  6, 14, 7, 15, 0, 8, 1, 9, 2, 10, 3, 11,
1954  4, 12, 5, 13, 6, 14, 7, 15));
1955  auto __c
1956  = __xzyw(__b); // 0145 89CD 2367 ABEF GHKL OPST IJMN QRUV
1957  return __intrin_bitcast<_To>(_mm256_shuffle_epi8(
1958  __c, _mm256_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13,
1959  6, 7, 14, 15, 0, 1, 8, 9, 2, 3, 10, 11,
1960  4, 5, 12, 13, 6, 7, 14, 15)));
1961  }
1962  else if constexpr (__z_to_z)
1963  {
1964  return __concat(
1965  __convert_x86<__vector_type_t<_Up, _M / 2>>(__v0, __v1, __v2,
1966  __v3),
1967  __convert_x86<__vector_type_t<_Up, _M / 2>>(__v4, __v5, __v6,
1968  __v7));
1969  }
1970  }
1971  else if constexpr (__f64_to_i8) //{{{2
1972  {
1973  return __convert_x86<_To>(
1974  __convert_x86<__vector_type_t<int, _Np * 2>>(__v0, __v1),
1975  __convert_x86<__vector_type_t<int, _Np * 2>>(__v2, __v3),
1976  __convert_x86<__vector_type_t<int, _Np * 2>>(__v4, __v5),
1977  __convert_x86<__vector_type_t<int, _Np * 2>>(__v6, __v7));
1978  }
1979  else // unreachable {{{2
1980  __assert_unreachable<_Tp>();
1981  //}}}
1982 
1983  // fallback: {{{2
1984  if constexpr (sizeof(_To) >= 32)
1985  // if _To is ymm or zmm, then _SimdWrapper<_Up, _M / 2> is xmm or ymm
1986  return __concat(
1987  __convert_x86<__vector_type_t<_Up, _M / 2>>(__v0, __v1, __v2, __v3),
1988  __convert_x86<__vector_type_t<_Up, _M / 2>>(__v4, __v5, __v6,
1989  __v7));
1990  else if constexpr (sizeof(_To) == 16)
1991  {
1992  const auto __lo
1993  = __to_intrin(__convert_x86<_To>(__v0, __v1, __v2, __v3));
1994  const auto __hi
1995  = __to_intrin(__convert_x86<_To>(__v4, __v5, __v6, __v7));
1996  static_assert(sizeof(_Up) == 1 && _Np == 2);
1997  return __intrin_bitcast<_To>(_mm_unpacklo_epi64(__lo, __hi));
1998  }
1999  else
2000  {
2001  __assert_unreachable<_Tp>();
2002  // return __vector_convert<_To>(__v0, __v1, __v2, __v3, __v4, __v5,
2003  // __v6, __v7,
2004  // make_index_sequence<_Np>());
2005  } //}}}2
2006  }
2007  }
2008 
2009 //}}}
2010 // 16-arg __convert_x86 {{{1
2011 template <typename _To, typename _V, typename _Traits>
2012  _GLIBCXX_SIMD_INTRINSIC _To
2013  __convert_x86(_V __v0, _V __v1, _V __v2, _V __v3, _V __v4, _V __v5, _V __v6,
2014  _V __v7, _V __v8, _V __v9, _V __v10, _V __v11, _V __v12,
2015  _V __v13, _V __v14, _V __v15)
2016  {
2017  // concat => use 8-arg __convert_x86
2018  return __convert_x86<_To>(__concat(__v0, __v1), __concat(__v2, __v3),
2019  __concat(__v4, __v5), __concat(__v6, __v7),
2020  __concat(__v8, __v9), __concat(__v10, __v11),
2021  __concat(__v12, __v13), __concat(__v14, __v15));
2022  }
2023 
2024 //}}}
2025 
2026 #endif // __cplusplus >= 201703L
2027 #endif // _GLIBCXX_EXPERIMENTAL_SIMD_X86_CONVERSIONS_H
2028 
2029 // vim: foldmethod=marker
constexpr const _Tp & max(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:254
constexpr const _Tp & min(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:230
make_integer_sequence< size_t, _Num > make_index_sequence
Alias template make_index_sequence.
Definition: utility.h:185