1use std::arch::x86_64::{
2 __m512, __m512i, __mmask16, __mmask32, __mmask64, _CMP_EQ_OQ, _CMP_GE_OQ, _CMP_GT_OQ,
3 _CMP_LE_OQ, _CMP_LT_OQ, _MM_CMPINT_EQ, _MM_CMPINT_NLE, _MM_CMPINT_NLT,
4 _MM_FROUND_TO_NEAREST_INT, _MM_HINT_ET0, _MM_HINT_T0, _mm_prefetch, _mm512_add_epi8,
5 _mm512_add_epi16, _mm512_add_epi32, _mm512_add_ps, _mm512_and_ps, _mm512_and_si512,
6 _mm512_andnot_ps, _mm512_andnot_si512, _mm512_castsi256_si512, _mm512_castsi512_si256,
7 _mm512_cmp_epi16_mask, _mm512_cmp_epi32_mask, _mm512_cmp_epu16_mask, _mm512_cmp_ps_mask,
8 _mm512_cmpeq_epi8_mask, _mm512_cmpeq_epu8_mask, _mm512_cmpge_epi8_mask, _mm512_cmpge_epu8_mask,
9 _mm512_cmpgt_epi8_mask, _mm512_cmpgt_epu8_mask, _mm512_cvtepi8_epi16, _mm512_cvtepi16_epi8,
10 _mm512_cvtepi16_epi32, _mm512_cvtepi32_ps, _mm512_cvtepu8_epi16, _mm512_cvtph_ps,
11 _mm512_cvtps_epi32, _mm512_cvtps_ph, _mm512_cvttps_epi32, _mm512_div_ps,
12 _mm512_extracti64x4_epi64, _mm512_fmadd_ps, _mm512_fnmadd_ps, _mm512_inserti64x4,
13 _mm512_loadu_ps, _mm512_loadu_si512, _mm512_mask_blend_epi8, _mm512_mask_blend_epi16,
14 _mm512_mask_blend_epi32, _mm512_mask_blend_ps, _mm512_mask_loadu_epi8, _mm512_mask_loadu_epi16,
15 _mm512_mask_loadu_epi32, _mm512_mask_loadu_ps, _mm512_mask_storeu_epi8,
16 _mm512_mask_storeu_epi16, _mm512_mask_storeu_epi32, _mm512_mask_storeu_ps, _mm512_max_ps,
17 _mm512_min_ps, _mm512_mul_ps, _mm512_mullo_epi16, _mm512_mullo_epi32, _mm512_or_ps,
18 _mm512_or_si512, _mm512_packs_epi32, _mm512_packus_epi16, _mm512_permutex2var_epi32,
19 _mm512_permutexvar_epi64, _mm512_reduce_add_ps, _mm512_roundscale_ps, _mm512_set1_epi8,
20 _mm512_set1_epi16, _mm512_set1_epi32, _mm512_set1_ps, _mm512_setr_epi32, _mm512_setr_epi64,
21 _mm512_setzero_si512, _mm512_sllv_epi16, _mm512_sllv_epi32, _mm512_srav_epi16,
22 _mm512_srav_epi32, _mm512_srlv_epi16, _mm512_storeu_ps, _mm512_storeu_si512, _mm512_sub_epi8,
23 _mm512_sub_epi16, _mm512_sub_epi32, _mm512_sub_ps, _mm512_unpackhi_epi8, _mm512_unpackhi_epi16,
24 _mm512_unpacklo_epi8, _mm512_unpacklo_epi16, _mm512_xor_ps, _mm512_xor_si512,
25};
26use std::mem::transmute;
27
28use super::super::{lanes, simd_type};
29use crate::f16;
30use crate::ops::{
31 BitOps, Concat, Extend, FloatOps, IntOps, Interleave, MaskOps, Narrow, NarrowSaturate, NumOps,
32 SignedIntOps, ToFloat,
33};
34use crate::{Isa, Mask, Simd};
35
36simd_type!(F32x16, __m512, f32, __mmask16, Avx512Isa);
37simd_type!(F16x32, __m512i, f16, __mmask32, Avx512Isa);
38simd_type!(I32x16, __m512i, i32, __mmask16, Avx512Isa);
39simd_type!(I16x32, __m512i, i16, __mmask32, Avx512Isa);
40simd_type!(I8x64, __m512i, i8, __mmask64, Avx512Isa);
41simd_type!(U8x64, __m512i, u8, __mmask64, Avx512Isa);
42simd_type!(U16x32, __m512i, u16, __mmask32, Avx512Isa);
43simd_type!(U32x16, __m512i, u32, __mmask16, Avx512Isa);
44
45#[derive(Copy, Clone)]
46pub struct Avx512Isa {
47 _private: (),
48}
49
50impl Avx512Isa {
51 pub fn new() -> Option<Self> {
52 if crate::is_avx512_supported() && std::is_x86_feature_detected!("f16c") {
53 Some(Avx512Isa { _private: () })
54 } else {
55 None
56 }
57 }
58}
59
60unsafe impl Isa for Avx512Isa {
62 type M32 = __mmask16;
63 type M16 = __mmask32;
64 type M8 = __mmask64;
65 type F32 = F32x16;
66 type I32 = I32x16;
67 type I16 = I16x32;
68 type I8 = I8x64;
69 type U8 = U8x64;
70 type U16 = U16x32;
71 type U32 = U32x16;
72 type F16 = F16x32;
73 type Bits = I32x16;
74
75 fn f32(
76 self,
77 ) -> impl FloatOps<f32, Simd = Self::F32, Int = Self::I32>
78 + NarrowSaturate<f32, f16, Output = Self::F16> {
79 self
80 }
81
82 fn f16(self) -> impl Extend<f16, Output = Self::F32, Simd = Self::F16> {
83 self
84 }
85
86 fn i32(
87 self,
88 ) -> impl SignedIntOps<i32, Simd = Self::I32>
89 + NarrowSaturate<i32, i16, Output = Self::I16>
90 + Concat<i32>
91 + ToFloat<i32, Output = Self::F32> {
92 self
93 }
94
95 fn i16(
96 self,
97 ) -> impl SignedIntOps<i16, Simd = Self::I16>
98 + NarrowSaturate<i16, u8, Output = Self::U8>
99 + Extend<i16, Output = Self::I32>
100 + Interleave<i16> {
101 self
102 }
103
104 fn i8(
105 self,
106 ) -> impl SignedIntOps<i8, Simd = Self::I8> + Extend<i8, Output = Self::I16> + Interleave<i8>
107 {
108 self
109 }
110
111 fn u8(
112 self,
113 ) -> impl IntOps<u8, Simd = Self::U8> + Extend<u8, Output = Self::U16> + Interleave<u8> {
114 self
115 }
116
117 fn u16(self) -> impl IntOps<u16, Simd = Self::U16> {
118 self
119 }
120
121 fn m32(self) -> impl MaskOps<Self::M32> {
122 self
123 }
124
125 fn m16(self) -> impl MaskOps<Self::M16> {
126 self
127 }
128
129 fn m8(self) -> impl MaskOps<Self::M8> {
130 self
131 }
132}
133
134macro_rules! simd_ops_common {
135 ($simd:ty, $mask:ty) => {
136 type Simd = $simd;
137
138 #[inline]
139 fn len(self) -> usize {
140 lanes::<$simd>()
141 }
142
143 #[inline]
144 fn first_n_mask(self, n: usize) -> $mask {
145 let mut mask = 0;
146 for i in 0..n {
147 mask |= 1 << i;
148 }
149 mask
150 }
151
152 #[inline]
153 fn prefetch(self, ptr: *const <$simd as Simd>::Elem) {
154 unsafe { _mm_prefetch(ptr as *const i8, _MM_HINT_T0) }
155 }
156
157 #[inline]
158 fn prefetch_write(self, ptr: *mut <$simd as Simd>::Elem) {
159 unsafe { _mm_prefetch(ptr as *const i8, _MM_HINT_ET0) }
160 }
161 };
162}
163
164macro_rules! simd_int_ops_common {
165 ($simd:ty) => {
166 #[inline]
167 fn and(self, x: $simd, y: $simd) -> $simd {
168 unsafe { _mm512_and_si512(x.0, y.0) }.into()
169 }
170
171 #[inline]
172 fn or(self, x: $simd, y: $simd) -> $simd {
173 unsafe { _mm512_or_si512(x.0, y.0) }.into()
174 }
175
176 #[inline]
177 fn xor(self, x: $simd, y: $simd) -> $simd {
178 unsafe { _mm512_xor_si512(x.0, y.0) }.into()
179 }
180
181 #[inline]
182 fn not(self, x: $simd) -> $simd {
183 unsafe { _mm512_andnot_si512(x.0, _mm512_set1_epi8(-1)) }.into()
184 }
185 };
186}
187
188unsafe impl BitOps<f32> for Avx512Isa {
189 simd_ops_common!(F32x16, __mmask16);
190
191 #[inline]
192 fn and(self, x: F32x16, y: F32x16) -> F32x16 {
193 unsafe { _mm512_and_ps(x.0, y.0) }.into()
194 }
195
196 #[inline]
197 fn not(self, x: F32x16) -> F32x16 {
198 let all_ones: F32x16 = self.splat(f32::from_bits(0xFFFFFFFF));
199 unsafe { _mm512_andnot_ps(x.0, all_ones.0) }.into()
200 }
201
202 #[inline]
203 fn or(self, x: F32x16, y: F32x16) -> F32x16 {
204 unsafe { _mm512_or_ps(x.0, y.0) }.into()
205 }
206
207 #[inline]
208 fn xor(self, x: F32x16, y: F32x16) -> F32x16 {
209 unsafe { _mm512_xor_ps(x.0, y.0) }.into()
210 }
211
212 #[inline]
213 fn splat(self, x: f32) -> F32x16 {
214 unsafe { _mm512_set1_ps(x) }.into()
215 }
216
217 #[inline]
218 unsafe fn load_ptr(self, ptr: *const f32) -> F32x16 {
219 unsafe { _mm512_loadu_ps(ptr) }.into()
220 }
221
222 #[inline]
223 fn select(self, x: F32x16, y: F32x16, mask: <F32x16 as Simd>::Mask) -> F32x16 {
224 unsafe { _mm512_mask_blend_ps(mask, y.0, x.0) }.into()
225 }
226
227 #[inline]
228 unsafe fn load_ptr_mask(self, ptr: *const f32, mask: __mmask16) -> F32x16 {
229 unsafe { _mm512_mask_loadu_ps(_mm512_set1_ps(0.), mask, ptr) }.into()
230 }
231
232 #[inline]
233 unsafe fn store_ptr_mask(self, x: F32x16, ptr: *mut f32, mask: __mmask16) {
234 unsafe { _mm512_mask_storeu_ps(ptr, mask, x.0) }
235 }
236
237 #[inline]
238 unsafe fn store_ptr(self, x: F32x16, ptr: *mut f32) {
239 unsafe { _mm512_storeu_ps(ptr, x.0) }
240 }
241}
242
243unsafe impl NumOps<f32> for Avx512Isa {
244 #[inline]
245 fn add(self, x: F32x16, y: F32x16) -> F32x16 {
246 unsafe { _mm512_add_ps(x.0, y.0) }.into()
247 }
248
249 #[inline]
250 fn sub(self, x: F32x16, y: F32x16) -> F32x16 {
251 unsafe { _mm512_sub_ps(x.0, y.0) }.into()
252 }
253
254 #[inline]
255 fn mul(self, x: F32x16, y: F32x16) -> F32x16 {
256 unsafe { _mm512_mul_ps(x.0, y.0) }.into()
257 }
258
259 #[inline]
260 fn mul_add(self, a: F32x16, b: F32x16, c: F32x16) -> F32x16 {
261 unsafe { _mm512_fmadd_ps(a.0, b.0, c.0) }.into()
262 }
263
264 #[inline]
265 fn lt(self, x: F32x16, y: F32x16) -> __mmask16 {
266 unsafe { _mm512_cmp_ps_mask(x.0, y.0, _CMP_LT_OQ) }
267 }
268
269 #[inline]
270 fn le(self, x: F32x16, y: F32x16) -> __mmask16 {
271 unsafe { _mm512_cmp_ps_mask(x.0, y.0, _CMP_LE_OQ) }
272 }
273
274 #[inline]
275 fn eq(self, x: F32x16, y: F32x16) -> __mmask16 {
276 unsafe { _mm512_cmp_ps_mask(x.0, y.0, _CMP_EQ_OQ) }
277 }
278
279 #[inline]
280 fn ge(self, x: F32x16, y: F32x16) -> __mmask16 {
281 unsafe { _mm512_cmp_ps_mask(x.0, y.0, _CMP_GE_OQ) }
282 }
283
284 #[inline]
285 fn gt(self, x: F32x16, y: F32x16) -> __mmask16 {
286 unsafe { _mm512_cmp_ps_mask(x.0, y.0, _CMP_GT_OQ) }
287 }
288
289 #[inline]
290 fn min(self, x: F32x16, y: F32x16) -> F32x16 {
291 unsafe { _mm512_min_ps(x.0, y.0) }.into()
292 }
293
294 #[inline]
295 fn max(self, x: F32x16, y: F32x16) -> F32x16 {
296 unsafe { _mm512_max_ps(x.0, y.0) }.into()
297 }
298
299 #[inline]
300 fn sum(self, x: F32x16) -> f32 {
301 unsafe { _mm512_reduce_add_ps(x.0) }
302 }
303}
304
305impl FloatOps<f32> for Avx512Isa {
306 type Int = <Self as Isa>::I32;
307
308 #[inline]
309 fn div(self, x: F32x16, y: F32x16) -> F32x16 {
310 unsafe { _mm512_div_ps(x.0, y.0) }.into()
311 }
312
313 #[inline]
314 fn abs(self, x: F32x16) -> F32x16 {
315 unsafe { _mm512_andnot_ps(_mm512_set1_ps(-0.0), x.0) }.into()
316 }
317
318 #[inline]
319 fn neg(self, x: F32x16) -> F32x16 {
320 unsafe { _mm512_xor_ps(x.0, _mm512_set1_ps(-0.0)) }.into()
321 }
322
323 #[inline]
324 fn mul_sub_from(self, a: F32x16, b: F32x16, c: F32x16) -> F32x16 {
325 unsafe { _mm512_fnmadd_ps(a.0, b.0, c.0) }.into()
326 }
327
328 #[inline]
329 fn round_ties_even(self, x: F32x16) -> F32x16 {
330 unsafe { _mm512_roundscale_ps(x.0, _MM_FROUND_TO_NEAREST_INT) }.into()
331 }
332
333 #[inline]
334 fn to_int_trunc(self, x: F32x16) -> Self::Int {
335 unsafe { _mm512_cvttps_epi32(x.0) }.into()
336 }
337
338 #[inline]
339 fn to_int_round(self, x: F32x16) -> Self::Int {
340 unsafe { _mm512_cvtps_epi32(x.0) }.into()
341 }
342}
343
344unsafe impl BitOps<i32> for Avx512Isa {
345 simd_ops_common!(I32x16, __mmask16);
346 simd_int_ops_common!(I32x16);
347
348 #[inline]
349 fn splat(self, x: i32) -> I32x16 {
350 unsafe { _mm512_set1_epi32(x) }.into()
351 }
352
353 #[inline]
354 unsafe fn load_ptr(self, ptr: *const i32) -> I32x16 {
355 unsafe { _mm512_loadu_si512(ptr as *const __m512i) }.into()
356 }
357
358 #[inline]
359 fn select(self, x: I32x16, y: I32x16, mask: <I32x16 as Simd>::Mask) -> I32x16 {
360 unsafe { _mm512_mask_blend_epi32(mask, y.0, x.0) }.into()
361 }
362
363 #[inline]
364 unsafe fn store_ptr(self, x: I32x16, ptr: *mut i32) {
365 unsafe { _mm512_storeu_si512(ptr as *mut __m512i, x.0) }
366 }
367
368 #[inline]
369 unsafe fn load_ptr_mask(self, ptr: *const i32, mask: __mmask16) -> I32x16 {
370 unsafe { _mm512_mask_loadu_epi32(_mm512_set1_epi32(0), mask, ptr) }.into()
371 }
372
373 #[inline]
374 unsafe fn store_ptr_mask(self, x: I32x16, ptr: *mut i32, mask: __mmask16) {
375 unsafe { _mm512_mask_storeu_epi32(ptr, mask, x.0) }
376 }
377}
378
379unsafe impl NumOps<i32> for Avx512Isa {
380 #[inline]
381 fn add(self, x: I32x16, y: I32x16) -> I32x16 {
382 unsafe { _mm512_add_epi32(x.0, y.0) }.into()
383 }
384
385 #[inline]
386 fn sub(self, x: I32x16, y: I32x16) -> I32x16 {
387 unsafe { _mm512_sub_epi32(x.0, y.0) }.into()
388 }
389
390 #[inline]
391 fn mul(self, x: I32x16, y: I32x16) -> I32x16 {
392 unsafe { _mm512_mullo_epi32(x.0, y.0) }.into()
393 }
394
395 #[inline]
396 fn eq(self, x: I32x16, y: I32x16) -> __mmask16 {
397 unsafe { _mm512_cmp_epi32_mask(x.0, y.0, _MM_CMPINT_EQ) }
398 }
399
400 #[inline]
401 fn ge(self, x: I32x16, y: I32x16) -> __mmask16 {
402 unsafe { _mm512_cmp_epi32_mask(x.0, y.0, _MM_CMPINT_NLT) }
403 }
404
405 #[inline]
406 fn gt(self, x: I32x16, y: I32x16) -> __mmask16 {
407 unsafe { _mm512_cmp_epi32_mask(x.0, y.0, _MM_CMPINT_NLE) }
408 }
409}
410
411impl IntOps<i32> for Avx512Isa {
412 #[inline]
413 fn shift_left<const SHIFT: i32>(self, x: I32x16) -> I32x16 {
414 let count: I32x16 = self.splat(SHIFT);
415 unsafe { _mm512_sllv_epi32(x.0, count.0) }.into()
416 }
417
418 #[inline]
419 fn shift_right<const SHIFT: i32>(self, x: I32x16) -> I32x16 {
420 let count: I32x16 = self.splat(SHIFT);
421 unsafe { _mm512_srav_epi32(x.0, count.0) }.into()
422 }
423}
424
425impl SignedIntOps<i32> for Avx512Isa {
426 #[inline]
427 fn neg(self, x: I32x16) -> I32x16 {
428 unsafe { _mm512_sub_epi32(_mm512_setzero_si512(), x.0) }.into()
429 }
430}
431
432impl NarrowSaturate<i32, i16> for Avx512Isa {
433 type Output = I16x32;
434
435 #[inline]
436 fn narrow_saturate(self, low: I32x16, high: I32x16) -> I16x32 {
437 unsafe {
438 let packed = _mm512_packs_epi32(low.0, high.0);
443 let permutation = _mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7);
444 _mm512_permutexvar_epi64(permutation, packed)
445 }
446 .into()
447 }
448}
449
450impl Concat<i32> for Avx512Isa {
451 #[inline]
452 fn concat_low(self, a: I32x16, b: I32x16) -> I32x16 {
453 unsafe {
454 let a_lo = _mm512_castsi512_si256(a.0);
455 let b_lo = _mm512_castsi512_si256(b.0);
456 _mm512_inserti64x4(_mm512_castsi256_si512(a_lo), b_lo, 1)
457 }
458 .into()
459 }
460
461 #[inline]
462 fn concat_high(self, a: I32x16, b: I32x16) -> I32x16 {
463 unsafe {
464 let a_hi = _mm512_extracti64x4_epi64(a.0, 1);
465 let b_hi = _mm512_extracti64x4_epi64(b.0, 1);
466 _mm512_inserti64x4(_mm512_castsi256_si512(a_hi), b_hi, 1)
467 }
468 .into()
469 }
470}
471
472impl ToFloat<i32> for Avx512Isa {
473 type Output = F32x16;
474
475 #[inline]
476 fn to_float(self, x: I32x16) -> F32x16 {
477 unsafe { _mm512_cvtepi32_ps(x.0) }.into()
478 }
479}
480
481unsafe impl BitOps<i16> for Avx512Isa {
482 simd_ops_common!(I16x32, __mmask32);
483 simd_int_ops_common!(I16x32);
484
485 #[inline]
486 fn splat(self, x: i16) -> I16x32 {
487 unsafe { _mm512_set1_epi16(x) }.into()
488 }
489
490 #[inline]
491 unsafe fn load_ptr(self, ptr: *const i16) -> I16x32 {
492 unsafe { _mm512_loadu_si512(ptr as *const __m512i) }.into()
493 }
494
495 #[inline]
496 fn select(self, x: I16x32, y: I16x32, mask: <I16x32 as Simd>::Mask) -> I16x32 {
497 unsafe { _mm512_mask_blend_epi16(mask, y.0, x.0) }.into()
498 }
499
500 #[inline]
501 unsafe fn store_ptr(self, x: I16x32, ptr: *mut i16) {
502 unsafe { _mm512_storeu_si512(ptr as *mut __m512i, x.0) }
503 }
504
505 #[inline]
506 unsafe fn load_ptr_mask(self, ptr: *const i16, mask: __mmask32) -> I16x32 {
507 unsafe { _mm512_mask_loadu_epi16(_mm512_set1_epi16(0), mask, ptr) }.into()
508 }
509
510 #[inline]
511 unsafe fn store_ptr_mask(self, x: I16x32, ptr: *mut i16, mask: __mmask32) {
512 unsafe { _mm512_mask_storeu_epi16(ptr, mask, x.0) }
513 }
514}
515
516unsafe impl NumOps<i16> for Avx512Isa {
517 #[inline]
518 fn add(self, x: I16x32, y: I16x32) -> I16x32 {
519 unsafe { _mm512_add_epi16(x.0, y.0) }.into()
520 }
521
522 #[inline]
523 fn sub(self, x: I16x32, y: I16x32) -> I16x32 {
524 unsafe { _mm512_sub_epi16(x.0, y.0) }.into()
525 }
526
527 #[inline]
528 fn mul(self, x: I16x32, y: I16x32) -> I16x32 {
529 unsafe { _mm512_mullo_epi16(x.0, y.0) }.into()
530 }
531
532 #[inline]
533 fn eq(self, x: I16x32, y: I16x32) -> __mmask32 {
534 unsafe { _mm512_cmp_epi16_mask(x.0, y.0, _MM_CMPINT_EQ) }
535 }
536
537 #[inline]
538 fn ge(self, x: I16x32, y: I16x32) -> __mmask32 {
539 unsafe { _mm512_cmp_epi16_mask(x.0, y.0, _MM_CMPINT_NLT) }
540 }
541
542 #[inline]
543 fn gt(self, x: I16x32, y: I16x32) -> __mmask32 {
544 unsafe { _mm512_cmp_epi16_mask(x.0, y.0, _MM_CMPINT_NLE) }
545 }
546}
547
548impl IntOps<i16> for Avx512Isa {
549 #[inline]
550 fn shift_left<const SHIFT: i32>(self, x: I16x32) -> I16x32 {
551 let count: I16x32 = self.splat(SHIFT as i16);
552 unsafe { _mm512_sllv_epi16(x.0, count.0) }.into()
553 }
554
555 #[inline]
556 fn shift_right<const SHIFT: i32>(self, x: I16x32) -> I16x32 {
557 let count: I16x32 = self.splat(SHIFT as i16);
558 unsafe { _mm512_srav_epi16(x.0, count.0) }.into()
559 }
560}
561
562impl SignedIntOps<i16> for Avx512Isa {
563 #[inline]
564 fn neg(self, x: I16x32) -> I16x32 {
565 unsafe { _mm512_sub_epi16(_mm512_setzero_si512(), x.0) }.into()
566 }
567}
568
569impl NarrowSaturate<i16, u8> for Avx512Isa {
570 type Output = U8x64;
571
572 #[inline]
573 fn narrow_saturate(self, low: I16x32, high: I16x32) -> U8x64 {
574 unsafe {
575 let packed = _mm512_packus_epi16(low.0, high.0);
580 let permutation = _mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7);
581 _mm512_permutexvar_epi64(permutation, packed)
582 }
583 .into()
584 }
585}
586
587impl Interleave<i16> for Avx512Isa {
588 #[inline]
589 fn interleave_low(self, a: I16x32, b: I16x32) -> I16x32 {
590 unsafe {
591 let lo = _mm512_unpacklo_epi16(a.0, b.0); let hi = _mm512_unpackhi_epi16(a.0, b.0); let idx = _mm512_setr_epi32(0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23);
595 _mm512_permutex2var_epi32(lo, idx, hi) }
597 .into()
598 }
599
600 #[inline]
601 fn interleave_high(self, a: I16x32, b: I16x32) -> I16x32 {
602 unsafe {
603 let lo = _mm512_unpacklo_epi16(a.0, b.0); let hi = _mm512_unpackhi_epi16(a.0, b.0); let idx =
607 _mm512_setr_epi32(8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31);
608 _mm512_permutex2var_epi32(lo, idx, hi) }
610 .into()
611 }
612}
613
614unsafe impl BitOps<i8> for Avx512Isa {
615 simd_ops_common!(I8x64, __mmask64);
616 simd_int_ops_common!(I8x64);
617
618 #[inline]
619 fn splat(self, x: i8) -> I8x64 {
620 unsafe { _mm512_set1_epi8(x) }.into()
621 }
622
623 #[inline]
624 unsafe fn load_ptr(self, ptr: *const i8) -> I8x64 {
625 unsafe { _mm512_loadu_si512(ptr as *const __m512i) }.into()
626 }
627
628 #[inline]
629 fn select(self, x: I8x64, y: I8x64, mask: <I8x64 as Simd>::Mask) -> I8x64 {
630 unsafe { _mm512_mask_blend_epi8(mask, y.0, x.0) }.into()
631 }
632
633 #[inline]
634 unsafe fn store_ptr(self, x: I8x64, ptr: *mut i8) {
635 unsafe { _mm512_storeu_si512(ptr as *mut __m512i, x.0) }
636 }
637
638 #[inline]
639 unsafe fn load_ptr_mask(self, ptr: *const i8, mask: __mmask64) -> I8x64 {
640 unsafe { _mm512_mask_loadu_epi8(_mm512_set1_epi8(0), mask, ptr) }.into()
641 }
642
643 #[inline]
644 unsafe fn store_ptr_mask(self, x: I8x64, ptr: *mut i8, mask: __mmask64) {
645 unsafe { _mm512_mask_storeu_epi8(ptr, mask, x.0) }
646 }
647}
648
649unsafe impl NumOps<i8> for Avx512Isa {
650 #[inline]
651 fn add(self, x: I8x64, y: I8x64) -> I8x64 {
652 unsafe { _mm512_add_epi8(x.0, y.0) }.into()
653 }
654
655 #[inline]
656 fn sub(self, x: I8x64, y: I8x64) -> I8x64 {
657 unsafe { _mm512_sub_epi8(x.0, y.0) }.into()
658 }
659
660 #[inline]
661 fn mul(self, x: I8x64, y: I8x64) -> I8x64 {
662 let x_lo = Extend::<i8>::extend_low(self, x);
663 let x_hi = Extend::<i8>::extend_high(self, x);
664 let y_lo = Extend::<i8>::extend_low(self, y);
665 let y_hi = Extend::<i8>::extend_high(self, y);
666
667 let i16_ops = self.i16();
668 let prod_lo = i16_ops.mul(x_lo, y_lo);
669 let prod_hi = i16_ops.mul(x_hi, y_hi);
670
671 self.narrow_truncate(prod_lo, prod_hi)
672 }
673
674 #[inline]
675 fn eq(self, x: I8x64, y: I8x64) -> __mmask64 {
676 unsafe { _mm512_cmpeq_epi8_mask(x.0, y.0) }
677 }
678
679 #[inline]
680 fn ge(self, x: I8x64, y: I8x64) -> __mmask64 {
681 unsafe { _mm512_cmpge_epi8_mask(x.0, y.0) }
682 }
683
684 #[inline]
685 fn gt(self, x: I8x64, y: I8x64) -> __mmask64 {
686 unsafe { _mm512_cmpgt_epi8_mask(x.0, y.0) }
687 }
688}
689
690impl IntOps<i8> for Avx512Isa {
691 #[inline]
692 fn shift_left<const SHIFT: i32>(self, x: I8x64) -> I8x64 {
693 let x_lo = Extend::<i8>::extend_low(self, x);
694 let x_hi = Extend::<i8>::extend_high(self, x);
695
696 let i16_ops = self.i16();
697 let (y_lo, y_hi) = (
698 i16_ops.shift_left::<SHIFT>(x_lo),
699 i16_ops.shift_left::<SHIFT>(x_hi),
700 );
701
702 self.narrow_truncate(y_lo, y_hi)
703 }
704
705 #[inline]
706 fn shift_right<const SHIFT: i32>(self, x: I8x64) -> I8x64 {
707 let x_lo = Extend::<i8>::extend_low(self, x);
708 let x_hi = Extend::<i8>::extend_high(self, x);
709
710 let i16_ops = self.i16();
711 let (y_lo, y_hi) = (
712 i16_ops.shift_right::<SHIFT>(x_lo),
713 i16_ops.shift_right::<SHIFT>(x_hi),
714 );
715
716 self.narrow_truncate(y_lo, y_hi)
717 }
718}
719
720impl SignedIntOps<i8> for Avx512Isa {
721 #[inline]
722 fn neg(self, x: I8x64) -> I8x64 {
723 unsafe { _mm512_sub_epi8(_mm512_setzero_si512(), x.0) }.into()
724 }
725}
726
727#[inline]
728fn interleave_low_x8(a: __m512i, b: __m512i) -> __m512i {
729 unsafe {
730 let lo = _mm512_unpacklo_epi8(a, b); let hi = _mm512_unpackhi_epi8(a, b); let idx = _mm512_setr_epi32(0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23);
734 _mm512_permutex2var_epi32(lo, idx, hi) }
736}
737
738#[inline]
739fn interleave_high_x8(a: __m512i, b: __m512i) -> __m512i {
740 unsafe {
741 let lo = _mm512_unpacklo_epi8(a, b); let hi = _mm512_unpackhi_epi8(a, b); let idx = _mm512_setr_epi32(8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31);
745 _mm512_permutex2var_epi32(lo, idx, hi) }
747}
748
749impl Interleave<i8> for Avx512Isa {
750 #[inline]
751 fn interleave_low(self, a: I8x64, b: I8x64) -> I8x64 {
752 interleave_low_x8(a.0, b.0).into()
753 }
754
755 #[inline]
756 fn interleave_high(self, a: I8x64, b: I8x64) -> I8x64 {
757 interleave_high_x8(a.0, b.0).into()
758 }
759}
760
761unsafe impl BitOps<u8> for Avx512Isa {
762 simd_ops_common!(U8x64, __mmask64);
763 simd_int_ops_common!(U8x64);
764
765 #[inline]
766 fn splat(self, x: u8) -> U8x64 {
767 unsafe { _mm512_set1_epi8(x as i8) }.into()
768 }
769
770 #[inline]
771 unsafe fn load_ptr(self, ptr: *const u8) -> U8x64 {
772 unsafe { _mm512_loadu_si512(ptr as *const __m512i) }.into()
773 }
774
775 #[inline]
776 fn select(self, x: U8x64, y: U8x64, mask: <U8x64 as Simd>::Mask) -> U8x64 {
777 unsafe { _mm512_mask_blend_epi8(mask, y.0, x.0) }.into()
778 }
779
780 #[inline]
781 unsafe fn store_ptr(self, x: U8x64, ptr: *mut u8) {
782 unsafe { _mm512_storeu_si512(ptr as *mut __m512i, x.0) }
783 }
784
785 #[inline]
786 unsafe fn load_ptr_mask(self, ptr: *const u8, mask: __mmask64) -> U8x64 {
787 unsafe { _mm512_mask_loadu_epi8(_mm512_set1_epi8(0), mask, ptr as *const i8) }.into()
788 }
789
790 #[inline]
791 unsafe fn store_ptr_mask(self, x: U8x64, ptr: *mut u8, mask: __mmask64) {
792 unsafe { _mm512_mask_storeu_epi8(ptr as *mut i8, mask, x.0) }
793 }
794}
795
796unsafe impl NumOps<u8> for Avx512Isa {
797 #[inline]
798 fn add(self, x: U8x64, y: U8x64) -> U8x64 {
799 unsafe { _mm512_add_epi8(x.0, y.0) }.into()
800 }
801
802 #[inline]
803 fn sub(self, x: U8x64, y: U8x64) -> U8x64 {
804 unsafe { _mm512_sub_epi8(x.0, y.0) }.into()
805 }
806
807 #[inline]
808 fn mul(self, x: U8x64, y: U8x64) -> U8x64 {
809 let x_lo = Extend::<u8>::extend_low(self, x);
810 let x_hi = Extend::<u8>::extend_high(self, x);
811 let y_lo = Extend::<u8>::extend_low(self, y);
812 let y_hi = Extend::<u8>::extend_high(self, y);
813
814 let u16_ops = self.u16();
815 let prod_lo = u16_ops.mul(x_lo, y_lo);
816 let prod_hi = u16_ops.mul(x_hi, y_hi);
817
818 self.narrow_truncate(prod_lo, prod_hi)
819 }
820
821 #[inline]
822 fn eq(self, x: U8x64, y: U8x64) -> __mmask64 {
823 unsafe { _mm512_cmpeq_epu8_mask(x.0, y.0) }
824 }
825
826 #[inline]
827 fn ge(self, x: U8x64, y: U8x64) -> __mmask64 {
828 unsafe { _mm512_cmpge_epu8_mask(x.0, y.0) }
829 }
830
831 #[inline]
832 fn gt(self, x: U8x64, y: U8x64) -> __mmask64 {
833 unsafe { _mm512_cmpgt_epu8_mask(x.0, y.0) }
834 }
835}
836
837impl Extend<i16> for Avx512Isa {
838 type Output = I32x16;
839
840 #[inline]
841 fn extend_low(self, x: I16x32) -> Self::Output {
842 unsafe { _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(x.0, 0)).into() }
843 }
844
845 #[inline]
846 fn extend_high(self, x: I16x32) -> Self::Output {
847 unsafe { _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(x.0, 1)).into() }
848 }
849}
850
851impl Extend<i8> for Avx512Isa {
852 type Output = I16x32;
853
854 #[inline]
855 fn extend_low(self, x: I8x64) -> I16x32 {
856 unsafe { _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(x.0, 0)).into() }
857 }
858
859 #[inline]
860 fn extend_high(self, x: I8x64) -> I16x32 {
861 unsafe { _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(x.0, 1)).into() }
862 }
863}
864
865impl Extend<u8> for Avx512Isa {
866 type Output = U16x32;
867
868 #[inline]
869 fn extend_low(self, x: U8x64) -> U16x32 {
870 unsafe { _mm512_cvtepu8_epi16(_mm512_extracti64x4_epi64(x.0, 0)).into() }
871 }
872
873 #[inline]
874 fn extend_high(self, x: U8x64) -> U16x32 {
875 unsafe { _mm512_cvtepu8_epi16(_mm512_extracti64x4_epi64(x.0, 1)).into() }
876 }
877}
878
879impl IntOps<u8> for Avx512Isa {
880 #[inline]
881 fn shift_left<const SHIFT: i32>(self, x: U8x64) -> U8x64 {
882 let x_lo = Extend::<u8>::extend_low(self, x);
883 let x_hi = Extend::<u8>::extend_high(self, x);
884
885 let u16_ops = self.u16();
886 let (y_lo, y_hi) = (
887 u16_ops.shift_left::<SHIFT>(x_lo),
888 u16_ops.shift_left::<SHIFT>(x_hi),
889 );
890
891 self.narrow_truncate(y_lo, y_hi)
892 }
893
894 #[inline]
895 fn shift_right<const SHIFT: i32>(self, x: U8x64) -> U8x64 {
896 let x_lo = Extend::<u8>::extend_low(self, x);
897 let x_hi = Extend::<u8>::extend_high(self, x);
898
899 let u16_ops = self.u16();
900 let (y_lo, y_hi) = (
901 u16_ops.shift_right::<SHIFT>(x_lo),
902 u16_ops.shift_right::<SHIFT>(x_hi),
903 );
904
905 self.narrow_truncate(y_lo, y_hi)
906 }
907}
908
909impl Interleave<u8> for Avx512Isa {
910 #[inline]
911 fn interleave_low(self, a: U8x64, b: U8x64) -> U8x64 {
912 unsafe {
913 let lo = _mm512_unpacklo_epi8(a.0, b.0); let hi = _mm512_unpackhi_epi8(a.0, b.0); let idx = _mm512_setr_epi32(0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23);
917 _mm512_permutex2var_epi32(lo, idx, hi) }
919 .into()
920 }
921
922 #[inline]
923 fn interleave_high(self, a: U8x64, b: U8x64) -> U8x64 {
924 unsafe {
925 let lo = _mm512_unpacklo_epi8(a.0, b.0); let hi = _mm512_unpackhi_epi8(a.0, b.0); let idx =
929 _mm512_setr_epi32(8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31);
930 _mm512_permutex2var_epi32(lo, idx, hi) }
932 .into()
933 }
934}
935
936impl Narrow<I16x32> for Avx512Isa {
937 type Output = I8x64;
938
939 #[inline]
940 fn narrow_truncate(self, a: I16x32, b: I16x32) -> I8x64 {
941 let y = unsafe {
942 let lo_i8 = _mm512_cvtepi16_epi8(a.0);
943 let hi_i8 = _mm512_cvtepi16_epi8(b.0);
944 _mm512_inserti64x4(_mm512_castsi256_si512(lo_i8), hi_i8, 1)
945 };
946 I8x64(y)
947 }
948}
949
950impl Narrow<U16x32> for Avx512Isa {
951 type Output = U8x64;
952
953 #[inline]
954 fn narrow_truncate(self, a: U16x32, b: U16x32) -> U8x64 {
955 let y = unsafe {
956 let lo_u8 = _mm512_cvtepi16_epi8(a.0);
957 let hi_u8 = _mm512_cvtepi16_epi8(b.0);
958 _mm512_inserti64x4(_mm512_castsi256_si512(lo_u8), hi_u8, 1)
959 };
960 U8x64(y)
961 }
962}
963
964unsafe impl BitOps<u16> for Avx512Isa {
965 simd_ops_common!(U16x32, __mmask32);
966 simd_int_ops_common!(U16x32);
967
968 #[inline]
969 fn splat(self, x: u16) -> U16x32 {
970 unsafe { _mm512_set1_epi16(x as i16) }.into()
971 }
972
973 #[inline]
974 unsafe fn load_ptr(self, ptr: *const u16) -> U16x32 {
975 unsafe { _mm512_loadu_si512(ptr as *const __m512i) }.into()
976 }
977
978 #[inline]
979 fn select(self, x: U16x32, y: U16x32, mask: <U16x32 as Simd>::Mask) -> U16x32 {
980 unsafe { _mm512_mask_blend_epi16(mask, y.0, x.0) }.into()
981 }
982
983 #[inline]
984 unsafe fn store_ptr(self, x: U16x32, ptr: *mut u16) {
985 unsafe { _mm512_storeu_si512(ptr as *mut __m512i, x.0) }
986 }
987
988 #[inline]
989 unsafe fn load_ptr_mask(self, ptr: *const u16, mask: __mmask32) -> U16x32 {
990 unsafe { _mm512_mask_loadu_epi16(_mm512_set1_epi16(0), mask, ptr as *const i16) }.into()
991 }
992
993 #[inline]
994 unsafe fn store_ptr_mask(self, x: U16x32, ptr: *mut u16, mask: __mmask32) {
995 unsafe { _mm512_mask_storeu_epi16(ptr as *mut i16, mask, x.0) }
996 }
997}
998
999unsafe impl NumOps<u16> for Avx512Isa {
1000 #[inline]
1001 fn add(self, x: U16x32, y: U16x32) -> U16x32 {
1002 unsafe { _mm512_add_epi16(x.0, y.0) }.into()
1003 }
1004
1005 #[inline]
1006 fn sub(self, x: U16x32, y: U16x32) -> U16x32 {
1007 unsafe { _mm512_sub_epi16(x.0, y.0) }.into()
1008 }
1009
1010 #[inline]
1011 fn mul(self, x: U16x32, y: U16x32) -> U16x32 {
1012 unsafe { _mm512_mullo_epi16(x.0, y.0) }.into()
1013 }
1014
1015 #[inline]
1016 fn eq(self, x: U16x32, y: U16x32) -> __mmask32 {
1017 unsafe { _mm512_cmp_epu16_mask(x.0, y.0, _MM_CMPINT_EQ) }
1018 }
1019
1020 #[inline]
1021 fn ge(self, x: U16x32, y: U16x32) -> __mmask32 {
1022 unsafe { _mm512_cmp_epu16_mask(x.0, y.0, _MM_CMPINT_NLT) }
1023 }
1024
1025 #[inline]
1026 fn gt(self, x: U16x32, y: U16x32) -> __mmask32 {
1027 unsafe { _mm512_cmp_epu16_mask(x.0, y.0, _MM_CMPINT_NLE) }
1028 }
1029}
1030
1031impl IntOps<u16> for Avx512Isa {
1032 #[inline]
1033 fn shift_left<const SHIFT: i32>(self, x: U16x32) -> U16x32 {
1034 let count: I16x32 = self.splat(SHIFT as i16);
1035 unsafe { _mm512_sllv_epi16(x.0, count.0) }.into()
1036 }
1037
1038 #[inline]
1039 fn shift_right<const SHIFT: i32>(self, x: U16x32) -> U16x32 {
1040 let count: I16x32 = self.splat(SHIFT as i16);
1041 unsafe { _mm512_srlv_epi16(x.0, count.0) }.into()
1042 }
1043}
1044
1045unsafe impl BitOps<f16> for Avx512Isa {
1046 simd_ops_common!(F16x32, __mmask32);
1047 simd_int_ops_common!(F16x32);
1048
1049 #[inline]
1050 fn splat(self, x: f16) -> F16x32 {
1051 unsafe { _mm512_set1_epi16(x.to_bits() as i16) }.into()
1052 }
1053
1054 #[inline]
1055 unsafe fn load_ptr(self, ptr: *const f16) -> F16x32 {
1056 unsafe { _mm512_loadu_si512(ptr as *const __m512i) }.into()
1057 }
1058
1059 #[inline]
1060 fn select(self, x: F16x32, y: F16x32, mask: <F16x32 as Simd>::Mask) -> F16x32 {
1061 unsafe { _mm512_mask_blend_epi16(mask, y.0, x.0) }.into()
1062 }
1063
1064 #[inline]
1065 unsafe fn store_ptr(self, x: F16x32, ptr: *mut f16) {
1066 unsafe { _mm512_storeu_si512(ptr as *mut __m512i, x.0) }
1067 }
1068
1069 #[inline]
1070 unsafe fn load_ptr_mask(self, ptr: *const f16, mask: __mmask32) -> F16x32 {
1071 unsafe { _mm512_mask_loadu_epi16(_mm512_set1_epi16(0), mask, ptr as *const i16) }.into()
1072 }
1073
1074 #[inline]
1075 unsafe fn store_ptr_mask(self, x: F16x32, ptr: *mut f16, mask: __mmask32) {
1076 unsafe { _mm512_mask_storeu_epi16(ptr as *mut i16, mask, x.0) }
1077 }
1078}
1079
1080impl Extend<f16> for Avx512Isa {
1081 type Output = F32x16;
1082
1083 #[inline]
1084 fn extend_low(self, x: F16x32) -> F32x16 {
1085 unsafe { _mm512_cvtph_ps(_mm512_castsi512_si256(x.0)).into() }
1086 }
1087
1088 #[inline]
1089 fn extend_high(self, x: F16x32) -> F32x16 {
1090 unsafe { _mm512_cvtph_ps(_mm512_extracti64x4_epi64(x.0, 1)).into() }
1091 }
1092}
1093
1094impl NarrowSaturate<f32, f16> for Avx512Isa {
1095 type Output = F16x32;
1096
1097 #[inline]
1098 fn narrow_saturate(self, low: F32x16, high: F32x16) -> F16x32 {
1099 unsafe {
1100 let low_i256 = _mm512_cvtps_ph::<_MM_FROUND_TO_NEAREST_INT>(low.0);
1101 let high_i256 = _mm512_cvtps_ph::<_MM_FROUND_TO_NEAREST_INT>(high.0);
1102 _mm512_inserti64x4(_mm512_castsi256_si512(low_i256), high_i256, 1).into()
1103 }
1104 }
1105}
1106
1107macro_rules! impl_mask {
1108 ($mask:ty) => {
1109 impl Mask for $mask {
1110 type Array = [bool; size_of::<$mask>() * 8];
1111
1112 #[inline]
1113 fn to_array(self) -> Self::Array {
1114 std::array::from_fn(|i| self & (1 << i) != 0)
1115 }
1116 }
1117
1118 unsafe impl MaskOps<$mask> for Avx512Isa {
1119 #[inline]
1120 fn and(self, x: $mask, y: $mask) -> $mask {
1121 x & y
1122 }
1123
1124 #[inline]
1125 fn any(self, x: $mask) -> bool {
1126 x != 0
1127 }
1128
1129 #[inline]
1130 fn all(self, x: $mask) -> bool {
1131 x == !0
1132 }
1133 }
1134 };
1135}
1136
1137impl_mask!(__mmask16);
1138impl_mask!(__mmask32);
1139impl_mask!(__mmask64);