vppinfra: AVX512 mask load/stores and compress store
[vpp.git] / src / vppinfra / vector_avx2.h
1 /*
2  * Copyright (c) 2018 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_avx2_h
17 #define included_vector_avx2_h
18
19 #include <vppinfra/clib.h>
20 #include <x86intrin.h>
21
22 /* *INDENT-OFF* */
23 #define foreach_avx2_vec256i \
24   _(i,8,32,epi8) _(i,16,16,epi16) _(i,32,8,epi32)  _(i,64,4,epi64)
25 #define foreach_avx2_vec256u \
26   _(u,8,32,epi8) _(u,16,16,epi16) _(u,32,8,epi32)  _(u,64,4,epi64)
27 #define foreach_avx2_vec256f \
28   _(f,32,8,ps) _(f,64,4,pd)
29
30 #define _mm256_set1_epi64 _mm256_set1_epi64x
31
32 /* splat, load_unaligned, store_unaligned, is_all_zero, is_equal,
33    is_all_equal */
34 #define _(t, s, c, i) \
35 static_always_inline t##s##x##c                                         \
36 t##s##x##c##_splat (t##s x)                                             \
37 { return (t##s##x##c) _mm256_set1_##i (x); }                            \
38 \
39 static_always_inline t##s##x##c                                         \
40 t##s##x##c##_load_unaligned (void *p)                                   \
41 { return (t##s##x##c) _mm256_loadu_si256 (p); }                         \
42 \
43 static_always_inline void                                               \
44 t##s##x##c##_store_unaligned (t##s##x##c v, void *p)                    \
45 { _mm256_storeu_si256 ((__m256i *) p, (__m256i) v); }                   \
46 \
47 static_always_inline int                                                \
48 t##s##x##c##_is_all_zero (t##s##x##c x)                                 \
49 { return _mm256_testz_si256 ((__m256i) x, (__m256i) x); }               \
50 \
51 static_always_inline int                                                \
52 t##s##x##c##_is_equal (t##s##x##c a, t##s##x##c b)                      \
53 { return t##s##x##c##_is_all_zero (a ^ b); }                            \
54 \
55 static_always_inline int                                                \
56 t##s##x##c##_is_all_equal (t##s##x##c v, t##s x)                        \
57 { return t##s##x##c##_is_equal (v, t##s##x##c##_splat (x)); }           \
58 \
59 static_always_inline t##s##x##c                                         \
60 t##s##x##c##_interleave_lo (t##s##x##c a, t##s##x##c b)                 \
61 { return (t##s##x##c) _mm256_unpacklo_##i ((__m256i) a, (__m256i) b); } \
62 \
63 static_always_inline t##s##x##c                                         \
64 t##s##x##c##_interleave_hi (t##s##x##c a, t##s##x##c b)                 \
65 { return (t##s##x##c) _mm256_unpackhi_##i ((__m256i) a, (__m256i) b); } \
66
67
68 foreach_avx2_vec256i foreach_avx2_vec256u
69 #undef _
70 /* *INDENT-ON* */
71
72 always_inline u32x8
73 u32x8_permute (u32x8 v, u32x8 idx)
74 {
75   return (u32x8) _mm256_permutevar8x32_epi32 ((__m256i) v, (__m256i) idx);
76 }
77
78 /* _extract_lo, _extract_hi */
79 /* *INDENT-OFF* */
80 #define _(t1,t2) \
81 always_inline t1                                                        \
82 t2##_extract_lo (t2 v)                                                  \
83 { return (t1) _mm256_extracti128_si256 ((__m256i) v, 0); }              \
84 \
85 always_inline t1                                                        \
86 t2##_extract_hi (t2 v)                                                  \
87 { return (t1) _mm256_extracti128_si256 ((__m256i) v, 1); }              \
88 \
89 always_inline t2                                                        \
90 t2##_insert_lo (t2 v1, t1 v2)                                           \
91 { return (t2) _mm256_inserti128_si256 ((__m256i) v1, (__m128i) v2, 0); }\
92 \
93 always_inline t2                                                        \
94 t2##_insert_hi (t2 v1, t1 v2)                                           \
95 { return (t2) _mm256_inserti128_si256 ((__m256i) v1, (__m128i) v2, 1); }\
96
97 _(u8x16, u8x32)
98 _(u16x8, u16x16)
99 _(u32x4, u32x8)
100 _(u64x2, u64x4)
101 #undef _
102 /* *INDENT-ON* */
103
104
105
106
107 static_always_inline u32
108 u8x32_msb_mask (u8x32 v)
109 {
110   return _mm256_movemask_epi8 ((__m256i) v);
111 }
112
113 /* _from_ */
114 /* *INDENT-OFF* */
115 #define _(f,t,i) \
116 static_always_inline t                                                  \
117 t##_from_##f (f x)                                                      \
118 { return (t) _mm256_cvt##i ((__m128i) x); }
119
120 _(u16x8, u32x8, epu16_epi32)
121 _(u16x8, u64x4, epu16_epi64)
122 _(u32x4, u64x4, epu32_epi64)
123 _ (u8x16, u16x16, epu8_epi16)
124 _(u8x16, u32x8, epu8_epi32)
125 _(u8x16, u64x4, epu8_epi64)
126 _(i16x8, i32x8, epi16_epi32)
127 _(i16x8, i64x4, epi16_epi64)
128 _(i32x4, i64x4, epi32_epi64)
129 _ (i8x16, i16x16, epi8_epi16)
130 _(i8x16, i32x8, epi8_epi32)
131 _(i8x16, i64x4, epi8_epi64)
132 #undef _
133 /* *INDENT-ON* */
134
135 static_always_inline u64x4
136 u64x4_byte_swap (u64x4 v)
137 {
138   u8x32 swap = {
139     7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
140     7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
141   };
142   return (u64x4) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) swap);
143 }
144
145 static_always_inline u32x8
146 u32x8_byte_swap (u32x8 v)
147 {
148   u8x32 swap = {
149     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
150     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
151   };
152   return (u32x8) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) swap);
153 }
154
155 static_always_inline u16x16
156 u16x16_byte_swap (u16x16 v)
157 {
158   u8x32 swap = {
159     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
160     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14
161   };
162   return (u16x16) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) swap);
163 }
164
165 static_always_inline u8x32
166 u8x32_shuffle (u8x32 v, u8x32 m)
167 {
168   return (u8x32) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) m);
169 }
170
171 #define u8x32_align_right(a, b, imm) \
172   (u8x32) _mm256_alignr_epi8 ((__m256i) a, (__m256i) b, imm)
173
174 static_always_inline u32
175 u32x8_sum_elts (u32x8 sum8)
176 {
177   sum8 += (u32x8) u8x32_align_right (sum8, sum8, 8);
178   sum8 += (u32x8) u8x32_align_right (sum8, sum8, 4);
179   return sum8[0] + sum8[4];
180 }
181
182 static_always_inline u32x8
183 u32x8_hadd (u32x8 v1, u32x8 v2)
184 {
185   return (u32x8) _mm256_hadd_epi32 ((__m256i) v1, (__m256i) v2);
186 }
187
188 static_always_inline u16x16
189 u16x16_mask_last (u16x16 v, u8 n_last)
190 {
191   const u16x16 masks[17] = {
192     {0},
193     {-1},
194     {-1, -1},
195     {-1, -1, -1},
196     {-1, -1, -1, -1},
197     {-1, -1, -1, -1, -1},
198     {-1, -1, -1, -1, -1, -1},
199     {-1, -1, -1, -1, -1, -1, -1},
200     {-1, -1, -1, -1, -1, -1, -1, -1},
201     {-1, -1, -1, -1, -1, -1, -1, -1, -1},
202     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
203     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
204     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
205     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
206     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
207     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
208     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
209   };
210
211   ASSERT (n_last < 17);
212
213   return v & masks[16 - n_last];
214 }
215
216 static_always_inline f32x8
217 f32x8_from_u32x8 (u32x8 v)
218 {
219   return (f32x8) _mm256_cvtepi32_ps ((__m256i) v);
220 }
221
222 static_always_inline u32x8
223 u32x8_from_f32x8 (f32x8 v)
224 {
225   return (u32x8) _mm256_cvttps_epi32 ((__m256) v);
226 }
227
228 #define u32x8_blend(a,b,m) \
229   (u32x8) _mm256_blend_epi32 ((__m256i) a, (__m256i) b, m)
230
231 #define u16x16_blend(v1, v2, mask) \
232   (u16x16) _mm256_blend_epi16 ((__m256i) (v1), (__m256i) (v2), mask)
233
234 static_always_inline u64x4
235 u64x4_gather (void *p0, void *p1, void *p2, void *p3)
236 {
237   u64x4 r = {
238     *(u64 *) p0, *(u64 *) p1, *(u64 *) p2, *(u64 *) p3
239   };
240   return r;
241 }
242
243 static_always_inline u32x8
244 u32x8_gather (void *p0, void *p1, void *p2, void *p3, void *p4, void *p5,
245               void *p6, void *p7)
246 {
247   u32x8 r = {
248     *(u32 *) p0, *(u32 *) p1, *(u32 *) p2, *(u32 *) p3,
249     *(u32 *) p4, *(u32 *) p5, *(u32 *) p6, *(u32 *) p7,
250   };
251   return r;
252 }
253
254
255 static_always_inline void
256 u64x4_scatter (u64x4 r, void *p0, void *p1, void *p2, void *p3)
257 {
258   *(u64 *) p0 = r[0];
259   *(u64 *) p1 = r[1];
260   *(u64 *) p2 = r[2];
261   *(u64 *) p3 = r[3];
262 }
263
264 static_always_inline void
265 u32x8_scatter (u32x8 r, void *p0, void *p1, void *p2, void *p3, void *p4,
266                void *p5, void *p6, void *p7)
267 {
268   *(u32 *) p0 = r[0];
269   *(u32 *) p1 = r[1];
270   *(u32 *) p2 = r[2];
271   *(u32 *) p3 = r[3];
272   *(u32 *) p4 = r[4];
273   *(u32 *) p5 = r[5];
274   *(u32 *) p6 = r[6];
275   *(u32 *) p7 = r[7];
276 }
277
278 static_always_inline void
279 u64x4_scatter_one (u64x4 r, int index, void *p)
280 {
281   *(u64 *) p = r[index];
282 }
283
284 static_always_inline void
285 u32x8_scatter_one (u32x8 r, int index, void *p)
286 {
287   *(u32 *) p = r[index];
288 }
289
290 static_always_inline u8x32
291 u8x32_is_greater (u8x32 v1, u8x32 v2)
292 {
293   return (u8x32) _mm256_cmpgt_epi8 ((__m256i) v1, (__m256i) v2);
294 }
295
296 static_always_inline u8x32
297 u8x32_blend (u8x32 v1, u8x32 v2, u8x32 mask)
298 {
299   return (u8x32) _mm256_blendv_epi8 ((__m256i) v1, (__m256i) v2,
300                                      (__m256i) mask);
301 }
302
303 #define u32x8_permute_lanes(a, b, m) \
304   (u32x8) _mm256_permute2x128_si256 ((__m256i) a, (__m256i) b, m)
305 #define u64x4_permute_lanes(a, b, m) \
306   (u64x4) _mm256_permute2x128_si256 ((__m256i) a, (__m256i) b, m)
307
308 static_always_inline u32x8
309 u32x8_min (u32x8 a, u32x8 b)
310 {
311   return (u32x8) _mm256_min_epu32 ((__m256i) a, (__m256i) b);
312 }
313
314 static_always_inline u32
315 u32x8_min_scalar (u32x8 v)
316 {
317   return u32x4_min_scalar (u32x4_min (u32x8_extract_lo (v),
318                                       u32x8_extract_hi (v)));
319 }
320
321 static_always_inline void
322 u32x8_transpose (u32x8 a[8])
323 {
324   u64x4 r[8], x, y;
325
326   r[0] = (u64x4) u32x8_interleave_lo (a[0], a[1]);
327   r[1] = (u64x4) u32x8_interleave_hi (a[0], a[1]);
328   r[2] = (u64x4) u32x8_interleave_lo (a[2], a[3]);
329   r[3] = (u64x4) u32x8_interleave_hi (a[2], a[3]);
330   r[4] = (u64x4) u32x8_interleave_lo (a[4], a[5]);
331   r[5] = (u64x4) u32x8_interleave_hi (a[4], a[5]);
332   r[6] = (u64x4) u32x8_interleave_lo (a[6], a[7]);
333   r[7] = (u64x4) u32x8_interleave_hi (a[6], a[7]);
334
335   x = u64x4_interleave_lo (r[0], r[2]);
336   y = u64x4_interleave_lo (r[4], r[6]);
337   a[0] = u32x8_permute_lanes (x, y, 0x20);
338   a[4] = u32x8_permute_lanes (x, y, 0x31);
339
340   x = u64x4_interleave_hi (r[0], r[2]);
341   y = u64x4_interleave_hi (r[4], r[6]);
342   a[1] = u32x8_permute_lanes (x, y, 0x20);
343   a[5] = u32x8_permute_lanes (x, y, 0x31);
344
345   x = u64x4_interleave_lo (r[1], r[3]);
346   y = u64x4_interleave_lo (r[5], r[7]);
347   a[2] = u32x8_permute_lanes (x, y, 0x20);
348   a[6] = u32x8_permute_lanes (x, y, 0x31);
349
350   x = u64x4_interleave_hi (r[1], r[3]);
351   y = u64x4_interleave_hi (r[5], r[7]);
352   a[3] = u32x8_permute_lanes (x, y, 0x20);
353   a[7] = u32x8_permute_lanes (x, y, 0x31);
354 }
355
356 static_always_inline void
357 u64x4_transpose (u64x4 a[8])
358 {
359   u64x4 r[4];
360
361   r[0] = u64x4_interleave_lo (a[0], a[1]);
362   r[1] = u64x4_interleave_hi (a[0], a[1]);
363   r[2] = u64x4_interleave_lo (a[2], a[3]);
364   r[3] = u64x4_interleave_hi (a[2], a[3]);
365
366   a[0] = u64x4_permute_lanes (r[0], r[2], 0x20);
367   a[1] = u64x4_permute_lanes (r[1], r[3], 0x20);
368   a[2] = u64x4_permute_lanes (r[0], r[2], 0x31);
369   a[3] = u64x4_permute_lanes (r[1], r[3], 0x31);
370 }
371
372 #endif /* included_vector_avx2_h */
373
374 /*
375  * fd.io coding-style-patch-verification: ON
376  *
377  * Local Variables:
378  * eval: (c-set-style "gnu")
379  * End:
380  */