vppinfra: AVX512 in clib_count_equal_*
[vpp.git] / src / vppinfra / vector_avx512.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef included_vector_avx512_h
17 #define included_vector_avx512_h
18
19 #include <vppinfra/clib.h>
20 #include <x86intrin.h>
21
22 /* *INDENT-OFF* */
23 #define foreach_avx512_vec512i \
24   _(i,8,64,epi8) _(i,16,32,epi16) _(i,32,16,epi32)  _(i,64,8,epi64)
25 #define foreach_avx512_vec512u \
26   _(u,8,64,epi8) _(u,16,32,epi16) _(u,32,16,epi32)  _(u,64,8,epi64)
27 #define foreach_avx512_vec512f \
28   _(f,32,8,ps) _(f,64,4,pd)
29
30 /* splat, load_unaligned, store_unaligned, is_all_zero, is_equal,
31    is_all_equal, is_zero_mask */
32 #define _(t, s, c, i) \
33 static_always_inline t##s##x##c                                         \
34 t##s##x##c##_splat (t##s x)                                             \
35 { return (t##s##x##c) _mm512_set1_##i (x); }                            \
36 \
37 static_always_inline t##s##x##c                                         \
38 t##s##x##c##_load_aligned (void *p)                                     \
39 { return (t##s##x##c) _mm512_load_si512 (p); }                          \
40 \
41 static_always_inline void                                               \
42 t##s##x##c##_store_aligned (t##s##x##c v, void *p)                      \
43 { _mm512_store_si512 ((__m512i *) p, (__m512i) v); }                    \
44 \
45 static_always_inline t##s##x##c                                         \
46 t##s##x##c##_load_unaligned (void *p)                                   \
47 { return (t##s##x##c) _mm512_loadu_si512 (p); }                         \
48 \
49 static_always_inline void                                               \
50 t##s##x##c##_store_unaligned (t##s##x##c v, void *p)                    \
51 { _mm512_storeu_si512 ((__m512i *) p, (__m512i) v); }                   \
52 \
53 static_always_inline int                                                \
54 t##s##x##c##_is_all_zero (t##s##x##c v)                                 \
55 { return (_mm512_test_epi64_mask ((__m512i) v, (__m512i) v) == 0); }    \
56 \
57 static_always_inline int                                                \
58 t##s##x##c##_is_equal (t##s##x##c a, t##s##x##c b)                      \
59 { return t##s##x##c##_is_all_zero (a ^ b); }                            \
60 \
61 static_always_inline int                                                \
62 t##s##x##c##_is_all_equal (t##s##x##c v, t##s x)                        \
63 { return t##s##x##c##_is_equal (v, t##s##x##c##_splat (x)); }           \
64 \
65 static_always_inline u##c                                               \
66 t##s##x##c##_is_zero_mask (t##s##x##c v)                                \
67 { return _mm512_test_##i##_mask ((__m512i) v, (__m512i) v); }           \
68 \
69 static_always_inline t##s##x##c                                         \
70 t##s##x##c##_interleave_lo (t##s##x##c a, t##s##x##c b)                 \
71 { return (t##s##x##c) _mm512_unpacklo_##i ((__m512i) a, (__m512i) b); } \
72 \
73 static_always_inline t##s##x##c                                         \
74 t##s##x##c##_interleave_hi (t##s##x##c a, t##s##x##c b)                 \
75 { return (t##s##x##c) _mm512_unpackhi_##i ((__m512i) a, (__m512i) b); } \
76
77
78 foreach_avx512_vec512i foreach_avx512_vec512u
79 #undef _
80 /* *INDENT-ON* */
81
82 static_always_inline u32
83 u16x32_msb_mask (u16x32 v)
84 {
85   return (u32) _mm512_movepi16_mask ((__m512i) v);
86 }
87
88 /* 512-bit packs */
89 #define _(f, t, fn)                                                           \
90   always_inline t t##_pack (f lo, f hi)                                       \
91   {                                                                           \
92     return (t) fn ((__m512i) lo, (__m512i) hi);                               \
93   }
94
95 _ (i16x32, i8x64, _mm512_packs_epi16)
96 _ (i16x32, u8x64, _mm512_packus_epi16)
97 _ (i32x16, i16x32, _mm512_packs_epi32)
98 _ (i32x16, u16x32, _mm512_packus_epi32)
99 #undef _
100
101 static_always_inline u32x16
102 u32x16_byte_swap (u32x16 v)
103 {
104   u8x64 swap = {
105     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
106     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
107     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
108     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
109   };
110   return (u32x16) _mm512_shuffle_epi8 ((__m512i) v, (__m512i) swap);
111 }
112
113 static_always_inline u16x32
114 u16x32_byte_swap (u16x32 v)
115 {
116   u8x64 swap = {
117     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
118     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
119     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
120     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14
121   };
122   return (u16x32) _mm512_shuffle_epi8 ((__m512i) v, (__m512i) swap);
123 }
124
125 #define _(f, t)                                                               \
126   static_always_inline t f##_extract_lo (f v)                                 \
127   {                                                                           \
128     return (t) _mm512_extracti64x4_epi64 ((__m512i) v, 0);                    \
129   }                                                                           \
130   static_always_inline t f##_extract_hi (f v)                                 \
131   {                                                                           \
132     return (t) _mm512_extracti64x4_epi64 ((__m512i) v, 1);                    \
133   }
134
135 _ (u64x8, u64x4)
136 _ (u32x16, u32x8)
137 _ (u16x32, u16x16)
138 _ (u8x64, u8x32)
139 #undef _
140
141 static_always_inline u32
142 u32x16_min_scalar (u32x16 v)
143 {
144   return u32x8_min_scalar (u32x8_min (u32x16_extract_lo (v),
145                                       u32x16_extract_hi (v)));
146 }
147
148 static_always_inline u32x16
149 u32x16_insert_lo (u32x16 r, u32x8 v)
150 {
151   return (u32x16) _mm512_inserti64x4 ((__m512i) r, (__m256i) v, 0);
152 }
153
154 static_always_inline u32x16
155 u32x16_insert_hi (u32x16 r, u32x8 v)
156 {
157   return (u32x16) _mm512_inserti64x4 ((__m512i) r, (__m256i) v, 1);
158 }
159
160 static_always_inline u64x8
161 u64x8_permute (u64x8 a, u64x8 b, u64x8 mask)
162 {
163   return (u64x8) _mm512_permutex2var_epi64 ((__m512i) a, (__m512i) mask,
164                                             (__m512i) b);
165 }
166
167
168 #define u32x16_ternary_logic(a, b, c, d) \
169   (u32x16) _mm512_ternarylogic_epi32 ((__m512i) a, (__m512i) b, (__m512i) c, d)
170
171 #define u8x64_insert_u8x16(a, b, n) \
172   (u8x64) _mm512_inserti64x2 ((__m512i) (a), (__m128i) (b), n)
173
174 #define u8x64_extract_u8x16(a, n) \
175   (u8x16) _mm512_extracti64x2_epi64 ((__m512i) (a), n)
176
177 #define u8x64_word_shift_left(a,n)  (u8x64) _mm512_bslli_epi128((__m512i) a, n)
178 #define u8x64_word_shift_right(a,n) (u8x64) _mm512_bsrli_epi128((__m512i) a, n)
179
180 static_always_inline u8x64
181 u8x64_xor3 (u8x64 a, u8x64 b, u8x64 c)
182 {
183   return (u8x64) _mm512_ternarylogic_epi32 ((__m512i) a, (__m512i) b,
184                                             (__m512i) c, 0x96);
185 }
186
187 static_always_inline u8x64
188 u8x64_reflect_u8x16 (u8x64 x)
189 {
190   static const u8x64 mask = {
191     15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
192     15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
193     15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
194     15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
195   };
196   return (u8x64) _mm512_shuffle_epi8 ((__m512i) x, (__m512i) mask);
197 }
198
199 static_always_inline u8x64
200 u8x64_shuffle (u8x64 v, u8x64 m)
201 {
202   return (u8x64) _mm512_shuffle_epi8 ((__m512i) v, (__m512i) m);
203 }
204
205 #define u8x64_align_right(a, b, imm) \
206   (u8x64) _mm512_alignr_epi8 ((__m512i) a, (__m512i) b, imm)
207
208 #define u64x8_align_right(a, b, imm)                                          \
209   (u64x8) _mm512_alignr_epi64 ((__m512i) a, (__m512i) b, imm)
210
211 static_always_inline u32
212 u32x16_sum_elts (u32x16 sum16)
213 {
214   u32x8 sum8;
215   sum16 += (u32x16) u8x64_align_right (sum16, sum16, 8);
216   sum16 += (u32x16) u8x64_align_right (sum16, sum16, 4);
217   sum8 = u32x16_extract_hi (sum16) + u32x16_extract_lo (sum16);
218   return sum8[0] + sum8[4];
219 }
220
221 #define _(t, m, p, i, e)                                                      \
222   static_always_inline t t##_mask_load (t a, void *p, m mask)                 \
223   {                                                                           \
224     return (t) p##_mask_loadu_##e ((i) a, mask, p);                           \
225   }                                                                           \
226   static_always_inline t t##_mask_load_zero (void *p, m mask)                 \
227   {                                                                           \
228     return (t) p##_maskz_loadu_##e (mask, p);                                 \
229   }                                                                           \
230   static_always_inline void t##_mask_store (t a, void *p, m mask)             \
231   {                                                                           \
232     p##_mask_storeu_##e (p, mask, (i) a);                                     \
233   }
234
235 _ (u8x64, u64, _mm512, __m512i, epi8)
236 _ (u8x32, u32, _mm256, __m256i, epi8)
237 _ (u8x16, u16, _mm, __m128i, epi8)
238 _ (u16x32, u32, _mm512, __m512i, epi16)
239 _ (u16x16, u16, _mm256, __m256i, epi16)
240 _ (u16x8, u8, _mm, __m128i, epi16)
241 _ (u32x16, u16, _mm512, __m512i, epi32)
242 _ (u32x8, u8, _mm256, __m256i, epi32)
243 _ (u32x4, u8, _mm, __m128i, epi32)
244 _ (u64x8, u8, _mm512, __m512i, epi64)
245 _ (u64x4, u8, _mm256, __m256i, epi64)
246 _ (u64x2, u8, _mm, __m128i, epi64)
247 #undef _
248
249 #ifdef CLIB_HAVE_VEC512
250 #define CLIB_HAVE_VEC512_MASK_LOAD_STORE
251 #endif
252 #ifdef CLIB_HAVE_VEC256
253 #define CLIB_HAVE_VEC256_MASK_LOAD_STORE
254 #endif
255 #ifdef CLIB_HAVE_VEC128
256 #define CLIB_HAVE_VEC128_MASK_LOAD_STORE
257 #endif
258
259 static_always_inline u8x64
260 u8x64_splat_u8x16 (u8x16 a)
261 {
262   return (u8x64) _mm512_broadcast_i64x2 ((__m128i) a);
263 }
264
265 static_always_inline u32x16
266 u32x16_splat_u32x4 (u32x4 a)
267 {
268   return (u32x16) _mm512_broadcast_i64x2 ((__m128i) a);
269 }
270
271 static_always_inline u32x16
272 u32x16_mask_blend (u32x16 a, u32x16 b, u16 mask)
273 {
274   return (u32x16) _mm512_mask_blend_epi32 (mask, (__m512i) a, (__m512i) b);
275 }
276
277 static_always_inline u8x64
278 u8x64_mask_blend (u8x64 a, u8x64 b, u64 mask)
279 {
280   return (u8x64) _mm512_mask_blend_epi8 (mask, (__m512i) a, (__m512i) b);
281 }
282
283 #define _(t, m, e, p, it)                                                     \
284   static_always_inline m t##_is_equal_mask (t a, t b)                         \
285   {                                                                           \
286     return p##_cmpeq_##e##_mask ((it) a, (it) b);                             \
287   }
288 _ (u8x16, u16, epu8, _mm, __m128i)
289 _ (u16x8, u8, epu16, _mm, __m128i)
290 _ (u32x4, u8, epu32, _mm, __m128i)
291 _ (u64x2, u8, epu64, _mm, __m128i)
292
293 _ (u8x32, u32, epu8, _mm256, __m256i)
294 _ (u16x16, u16, epu16, _mm256, __m256i)
295 _ (u32x8, u8, epu32, _mm256, __m256i)
296 _ (u64x4, u8, epu64, _mm256, __m256i)
297
298 _ (u8x64, u64, epu8, _mm512, __m512i)
299 _ (u16x32, u32, epu16, _mm512, __m512i)
300 _ (u32x16, u16, epu32, _mm512, __m512i)
301 _ (u64x8, u8, epu64, _mm512, __m512i)
302 #undef _
303
304 #define _(t, m, e, p, it)                                                     \
305   static_always_inline m t##_is_not_equal_mask (t a, t b)                     \
306   {                                                                           \
307     return p##_cmpneq_##e##_mask ((it) a, (it) b);                            \
308   }
309 _ (u8x16, u16, epu8, _mm, __m128i)
310 _ (u16x8, u8, epu16, _mm, __m128i)
311 _ (u32x4, u8, epu32, _mm, __m128i)
312 _ (u64x2, u8, epu64, _mm, __m128i)
313
314 _ (u8x32, u32, epu8, _mm256, __m256i)
315 _ (u16x16, u16, epu16, _mm256, __m256i)
316 _ (u32x8, u8, epu32, _mm256, __m256i)
317 _ (u64x4, u8, epu64, _mm256, __m256i)
318
319 _ (u8x64, u64, epu8, _mm512, __m512i)
320 _ (u16x32, u32, epu16, _mm512, __m512i)
321 _ (u32x16, u16, epu32, _mm512, __m512i)
322 _ (u64x8, u8, epu64, _mm512, __m512i)
323 #undef _
324
325 #define _(f, t, fn, it)                                                       \
326   static_always_inline t t##_from_##f (f x) { return (t) fn ((it) x); }
327 _ (u16x16, u32x16, _mm512_cvtepi16_epi32, __m256i)
328 _ (u32x16, u16x16, _mm512_cvtusepi32_epi16, __m512i)
329 _ (u32x8, u16x8, _mm256_cvtusepi32_epi16, __m256i)
330 _ (u32x8, u64x8, _mm512_cvtepu32_epi64, __m256i)
331 #undef _
332
333 #define _(vt, mt, p, it, epi)                                                 \
334   static_always_inline vt vt##_compress (vt a, mt mask)                       \
335   {                                                                           \
336     return (vt) p##_maskz_compress_##epi (mask, (it) a);                      \
337   }                                                                           \
338   static_always_inline vt vt##_expand (vt a, mt mask)                         \
339   {                                                                           \
340     return (vt) p##_maskz_expand_##epi (mask, (it) a);                        \
341   }                                                                           \
342   static_always_inline void vt##_compress_store (vt v, mt mask, void *p)      \
343   {                                                                           \
344     p##_mask_compressstoreu_##epi (p, mask, (it) v);                          \
345   }
346
347 _ (u64x8, u8, _mm512, __m512i, epi64)
348 _ (u32x16, u16, _mm512, __m512i, epi32)
349 _ (u64x4, u8, _mm256, __m256i, epi64)
350 _ (u32x8, u8, _mm256, __m256i, epi32)
351 _ (u64x2, u8, _mm, __m128i, epi64)
352 _ (u32x4, u8, _mm, __m128i, epi32)
353 #ifdef __AVX512VBMI2__
354 _ (u16x32, u32, _mm512, __m512i, epi16)
355 _ (u8x64, u64, _mm512, __m512i, epi8)
356 _ (u16x16, u16, _mm256, __m256i, epi16)
357 _ (u8x32, u32, _mm256, __m256i, epi8)
358 _ (u16x8, u8, _mm, __m128i, epi16)
359 _ (u8x16, u16, _mm, __m128i, epi8)
360 #endif
361 #undef _
362
363 #ifdef CLIB_HAVE_VEC256
364 #define CLIB_HAVE_VEC256_COMPRESS
365 #ifdef __AVX512VBMI2__
366 #define CLIB_HAVE_VEC256_COMPRESS_U8_U16
367 #endif
368
369 #endif
370 #ifdef CLIB_HAVE_VEC512
371 #define CLIB_HAVE_VEC512_COMPRESS
372 #ifdef __AVX512VBMI2__
373 #define CLIB_HAVE_VEC512_COMPRESS_U8_U16
374 #endif
375
376 #endif
377
378 #ifndef __AVX512VBMI2__
379 static_always_inline u16x16
380 u16x16_compress (u16x16 v, u16 mask)
381 {
382   return u16x16_from_u32x16 (u32x16_compress (u32x16_from_u16x16 (v), mask));
383 }
384
385 static_always_inline u16x8
386 u16x8_compress (u16x8 v, u8 mask)
387 {
388   return u16x8_from_u32x8 (u32x8_compress (u32x8_from_u16x8 (v), mask));
389 }
390 #endif
391
392 static_always_inline void
393 u32x16_transpose (u32x16 m[16])
394 {
395   __m512i r[16], a, b, c, d, x, y;
396
397   /* *INDENT-OFF* */
398   __m512i pm1 = (__m512i) (u64x8) { 0, 1, 8, 9, 4, 5, 12, 13};
399   __m512i pm2 = (__m512i) (u64x8) { 2, 3, 10, 11, 6, 7, 14, 15};
400   __m512i pm3 = (__m512i) (u64x8) { 0, 1, 2, 3, 8, 9, 10, 11};
401   __m512i pm4 = (__m512i) (u64x8) { 4, 5, 6, 7, 12, 13, 14, 15};
402   /* *INDENT-ON* */
403
404   r[0] = _mm512_unpacklo_epi32 ((__m512i) m[0], (__m512i) m[1]);
405   r[1] = _mm512_unpacklo_epi32 ((__m512i) m[2], (__m512i) m[3]);
406   r[2] = _mm512_unpacklo_epi32 ((__m512i) m[4], (__m512i) m[5]);
407   r[3] = _mm512_unpacklo_epi32 ((__m512i) m[6], (__m512i) m[7]);
408   r[4] = _mm512_unpacklo_epi32 ((__m512i) m[8], (__m512i) m[9]);
409   r[5] = _mm512_unpacklo_epi32 ((__m512i) m[10], (__m512i) m[11]);
410   r[6] = _mm512_unpacklo_epi32 ((__m512i) m[12], (__m512i) m[13]);
411   r[7] = _mm512_unpacklo_epi32 ((__m512i) m[14], (__m512i) m[15]);
412
413   r[8] = _mm512_unpackhi_epi32 ((__m512i) m[0], (__m512i) m[1]);
414   r[9] = _mm512_unpackhi_epi32 ((__m512i) m[2], (__m512i) m[3]);
415   r[10] = _mm512_unpackhi_epi32 ((__m512i) m[4], (__m512i) m[5]);
416   r[11] = _mm512_unpackhi_epi32 ((__m512i) m[6], (__m512i) m[7]);
417   r[12] = _mm512_unpackhi_epi32 ((__m512i) m[8], (__m512i) m[9]);
418   r[13] = _mm512_unpackhi_epi32 ((__m512i) m[10], (__m512i) m[11]);
419   r[14] = _mm512_unpackhi_epi32 ((__m512i) m[12], (__m512i) m[13]);
420   r[15] = _mm512_unpackhi_epi32 ((__m512i) m[14], (__m512i) m[15]);
421
422   a = _mm512_unpacklo_epi64 (r[0], r[1]);
423   b = _mm512_unpacklo_epi64 (r[2], r[3]);
424   c = _mm512_unpacklo_epi64 (r[4], r[5]);
425   d = _mm512_unpacklo_epi64 (r[6], r[7]);
426   x = _mm512_permutex2var_epi64 (a, pm1, b);
427   y = _mm512_permutex2var_epi64 (c, pm1, d);
428   m[0] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
429   m[8] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
430   x = _mm512_permutex2var_epi64 (a, pm2, b);
431   y = _mm512_permutex2var_epi64 (c, pm2, d);
432   m[4] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
433   m[12] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
434
435   a = _mm512_unpacklo_epi64 (r[8], r[9]);
436   b = _mm512_unpacklo_epi64 (r[10], r[11]);
437   c = _mm512_unpacklo_epi64 (r[12], r[13]);
438   d = _mm512_unpacklo_epi64 (r[14], r[15]);
439   x = _mm512_permutex2var_epi64 (a, pm1, b);
440   y = _mm512_permutex2var_epi64 (c, pm1, d);
441   m[2] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
442   m[10] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
443   x = _mm512_permutex2var_epi64 (a, pm2, b);
444   y = _mm512_permutex2var_epi64 (c, pm2, d);
445   m[6] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
446   m[14] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
447
448   a = _mm512_unpackhi_epi64 (r[0], r[1]);
449   b = _mm512_unpackhi_epi64 (r[2], r[3]);
450   c = _mm512_unpackhi_epi64 (r[4], r[5]);
451   d = _mm512_unpackhi_epi64 (r[6], r[7]);
452   x = _mm512_permutex2var_epi64 (a, pm1, b);
453   y = _mm512_permutex2var_epi64 (c, pm1, d);
454   m[1] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
455   m[9] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
456   x = _mm512_permutex2var_epi64 (a, pm2, b);
457   y = _mm512_permutex2var_epi64 (c, pm2, d);
458   m[5] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
459   m[13] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
460
461   a = _mm512_unpackhi_epi64 (r[8], r[9]);
462   b = _mm512_unpackhi_epi64 (r[10], r[11]);
463   c = _mm512_unpackhi_epi64 (r[12], r[13]);
464   d = _mm512_unpackhi_epi64 (r[14], r[15]);
465   x = _mm512_permutex2var_epi64 (a, pm1, b);
466   y = _mm512_permutex2var_epi64 (c, pm1, d);
467   m[3] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
468   m[11] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
469   x = _mm512_permutex2var_epi64 (a, pm2, b);
470   y = _mm512_permutex2var_epi64 (c, pm2, d);
471   m[7] = (u32x16) _mm512_permutex2var_epi64 (x, pm3, y);
472   m[15] = (u32x16) _mm512_permutex2var_epi64 (x, pm4, y);
473 }
474
475
476
477 static_always_inline void
478 u64x8_transpose (u64x8 m[8])
479 {
480   __m512i r[8], x, y;
481
482   /* *INDENT-OFF* */
483   __m512i pm1 = (__m512i) (u64x8) { 0, 1, 8, 9, 4, 5, 12, 13};
484   __m512i pm2 = (__m512i) (u64x8) { 2, 3, 10, 11, 6, 7, 14, 15};
485   __m512i pm3 = (__m512i) (u64x8) { 0, 1, 2, 3, 8, 9, 10, 11};
486   __m512i pm4 = (__m512i) (u64x8) { 4, 5, 6, 7, 12, 13, 14, 15};
487   /* *INDENT-ON* */
488
489   r[0] = _mm512_unpacklo_epi64 ((__m512i) m[0], (__m512i) m[1]);
490   r[1] = _mm512_unpacklo_epi64 ((__m512i) m[2], (__m512i) m[3]);
491   r[2] = _mm512_unpacklo_epi64 ((__m512i) m[4], (__m512i) m[5]);
492   r[3] = _mm512_unpacklo_epi64 ((__m512i) m[6], (__m512i) m[7]);
493   r[4] = _mm512_unpackhi_epi64 ((__m512i) m[0], (__m512i) m[1]);
494   r[5] = _mm512_unpackhi_epi64 ((__m512i) m[2], (__m512i) m[3]);
495   r[6] = _mm512_unpackhi_epi64 ((__m512i) m[4], (__m512i) m[5]);
496   r[7] = _mm512_unpackhi_epi64 ((__m512i) m[6], (__m512i) m[7]);
497
498   x = _mm512_permutex2var_epi64 (r[0], pm1, r[1]);
499   y = _mm512_permutex2var_epi64 (r[2], pm1, r[3]);
500   m[0] = (u64x8) _mm512_permutex2var_epi64 (x, pm3, y);
501   m[4] = (u64x8) _mm512_permutex2var_epi64 (x, pm4, y);
502   x = _mm512_permutex2var_epi64 (r[0], pm2, r[1]);
503   y = _mm512_permutex2var_epi64 (r[2], pm2, r[3]);
504   m[2] = (u64x8) _mm512_permutex2var_epi64 (x, pm3, y);
505   m[6] = (u64x8) _mm512_permutex2var_epi64 (x, pm4, y);
506
507   x = _mm512_permutex2var_epi64 (r[4], pm1, r[5]);
508   y = _mm512_permutex2var_epi64 (r[6], pm1, r[7]);
509   m[1] = (u64x8) _mm512_permutex2var_epi64 (x, pm3, y);
510   m[5] = (u64x8) _mm512_permutex2var_epi64 (x, pm4, y);
511   x = _mm512_permutex2var_epi64 (r[4], pm2, r[5]);
512   y = _mm512_permutex2var_epi64 (r[6], pm2, r[7]);
513   m[3] = (u64x8) _mm512_permutex2var_epi64 (x, pm3, y);
514   m[7] = (u64x8) _mm512_permutex2var_epi64 (x, pm4, y);
515 }
516
517 #endif /* included_vector_avx512_h */
518 /*
519  * fd.io coding-style-patch-verification: ON
520  *
521  * Local Variables:
522  * eval: (c-set-style "gnu")
523  * End:
524  */