1use crate::types::*;
4use core::arch::x86_64::{__m128i, __m256i};
5
6mod sse2;
7
8#[derive(Copy, Clone)]
9pub struct YesS3;
10#[derive(Copy, Clone)]
11pub struct NoS3;
12
13#[derive(Copy, Clone)]
14pub struct YesS4;
15#[derive(Copy, Clone)]
16pub struct NoS4;
17
18#[derive(Copy, Clone)]
19pub struct YesA1;
20#[derive(Copy, Clone)]
21pub struct NoA1;
22
23#[derive(Copy, Clone)]
24pub struct YesA2;
25#[derive(Copy, Clone)]
26pub struct NoA2;
27
28#[derive(Copy, Clone)]
29pub struct YesNI;
30#[derive(Copy, Clone)]
31pub struct NoNI;
32
33use core::marker::PhantomData;
34
35#[derive(Copy, Clone)]
36pub struct SseMachine<S3, S4, NI>(PhantomData<(S3, S4, NI)>);
37impl<S3: Copy, S4: Copy, NI: Copy> Machine for SseMachine<S3, S4, NI>
38where
39 sse2::u128x1_sse2<S3, S4, NI>: Swap64,
40 sse2::u64x2_sse2<S3, S4, NI>: BSwap + RotateEachWord32 + MultiLane<[u64; 2]> + Vec2<u64>,
41 sse2::u32x4_sse2<S3, S4, NI>: BSwap + RotateEachWord32 + MultiLane<[u32; 4]> + Vec4<u32>,
42 sse2::u64x4_sse2<S3, S4, NI>: BSwap + Words4,
43 sse2::u128x1_sse2<S3, S4, NI>: BSwap,
44 sse2::u128x2_sse2<S3, S4, NI>: Into<sse2::u64x2x2_sse2<S3, S4, NI>>,
45 sse2::u128x2_sse2<S3, S4, NI>: Into<sse2::u64x4_sse2<S3, S4, NI>>,
46 sse2::u128x2_sse2<S3, S4, NI>: Into<sse2::u32x4x2_sse2<S3, S4, NI>>,
47 sse2::u128x4_sse2<S3, S4, NI>: Into<sse2::u64x2x4_sse2<S3, S4, NI>>,
48 sse2::u128x4_sse2<S3, S4, NI>: Into<sse2::u32x4x4_sse2<S3, S4, NI>>,
49{
50 type u32x4 = sse2::u32x4_sse2<S3, S4, NI>;
51 type u64x2 = sse2::u64x2_sse2<S3, S4, NI>;
52 type u128x1 = sse2::u128x1_sse2<S3, S4, NI>;
53
54 type u32x4x2 = sse2::u32x4x2_sse2<S3, S4, NI>;
55 type u64x2x2 = sse2::u64x2x2_sse2<S3, S4, NI>;
56 type u64x4 = sse2::u64x4_sse2<S3, S4, NI>;
57 type u128x2 = sse2::u128x2_sse2<S3, S4, NI>;
58
59 type u32x4x4 = sse2::u32x4x4_sse2<S3, S4, NI>;
60 type u64x2x4 = sse2::u64x2x4_sse2<S3, S4, NI>;
61 type u128x4 = sse2::u128x4_sse2<S3, S4, NI>;
62
63 #[inline(always)]
64 unsafe fn instance() -> Self {
65 SseMachine(PhantomData)
66 }
67}
68
69#[derive(Copy, Clone)]
70pub struct Avx2Machine<NI>(PhantomData<NI>);
71impl<NI: Copy> Machine for Avx2Machine<NI>
72where
73 sse2::u128x1_sse2<YesS3, YesS4, NI>: BSwap + Swap64,
74 sse2::u64x2_sse2<YesS3, YesS4, NI>: BSwap + RotateEachWord32 + MultiLane<[u64; 2]> + Vec2<u64>,
75 sse2::u32x4_sse2<YesS3, YesS4, NI>: BSwap + RotateEachWord32 + MultiLane<[u32; 4]> + Vec4<u32>,
76 sse2::u64x4_sse2<YesS3, YesS4, NI>: BSwap + Words4,
77{
78 type u32x4 = sse2::u32x4_sse2<YesS3, YesS4, NI>;
79 type u64x2 = sse2::u64x2_sse2<YesS3, YesS4, NI>;
80 type u128x1 = sse2::u128x1_sse2<YesS3, YesS4, NI>;
81
82 type u32x4x2 = sse2::avx2::u32x4x2_avx2<NI>;
83 type u64x2x2 = sse2::u64x2x2_sse2<YesS3, YesS4, NI>;
84 type u64x4 = sse2::u64x4_sse2<YesS3, YesS4, NI>;
85 type u128x2 = sse2::u128x2_sse2<YesS3, YesS4, NI>;
86
87 type u32x4x4 = sse2::avx2::u32x4x4_avx2<NI>;
88 type u64x2x4 = sse2::u64x2x4_sse2<YesS3, YesS4, NI>;
89 type u128x4 = sse2::u128x4_sse2<YesS3, YesS4, NI>;
90
91 #[inline(always)]
92 unsafe fn instance() -> Self {
93 Avx2Machine(PhantomData)
94 }
95}
96
97pub type SSE2 = SseMachine<NoS3, NoS4, NoNI>;
98pub type SSSE3 = SseMachine<YesS3, NoS4, NoNI>;
99pub type SSE41 = SseMachine<YesS3, YesS4, NoNI>;
100pub type AVX = SseMachine<YesS3, YesS4, NoNI>;
103pub type AVX2 = Avx2Machine<NoNI>;
104
105#[allow(non_camel_case_types)]
109#[derive(Copy, Clone)]
110pub union vec128_storage {
111 u32x4: [u32; 4],
112 u64x2: [u64; 2],
113 u128x1: [u128; 1],
114 sse2: __m128i,
115}
116impl Store<vec128_storage> for vec128_storage {
117 #[inline(always)]
118 unsafe fn unpack(p: vec128_storage) -> Self {
119 p
120 }
121}
122impl<'a> From<&'a vec128_storage> for &'a [u32; 4] {
123 #[inline(always)]
124 fn from(x: &'a vec128_storage) -> Self {
125 unsafe { &x.u32x4 }
126 }
127}
128impl From<[u32; 4]> for vec128_storage {
129 #[inline(always)]
130 fn from(u32x4: [u32; 4]) -> Self {
131 vec128_storage { u32x4 }
132 }
133}
134impl Default for vec128_storage {
135 #[inline(always)]
136 fn default() -> Self {
137 vec128_storage { u128x1: [0] }
138 }
139}
140impl Eq for vec128_storage {}
141impl PartialEq for vec128_storage {
142 #[inline(always)]
143 fn eq(&self, rhs: &Self) -> bool {
144 unsafe { self.u128x1 == rhs.u128x1 }
145 }
146}
147
148#[allow(non_camel_case_types)]
149#[derive(Copy, Clone)]
150pub union vec256_storage {
151 u32x8: [u32; 8],
152 u64x4: [u64; 4],
153 u128x2: [u128; 2],
154 sse2: [vec128_storage; 2],
155 avx: __m256i,
156}
157impl From<[u64; 4]> for vec256_storage {
158 #[inline(always)]
159 fn from(u64x4: [u64; 4]) -> Self {
160 vec256_storage { u64x4 }
161 }
162}
163impl Default for vec256_storage {
164 #[inline(always)]
165 fn default() -> Self {
166 vec256_storage { u128x2: [0, 0] }
167 }
168}
169impl vec256_storage {
170 #[inline(always)]
171 pub fn new128(xs: [vec128_storage; 2]) -> Self {
172 Self { sse2: xs }
173 }
174 #[inline(always)]
175 pub fn split128(self) -> [vec128_storage; 2] {
176 unsafe { self.sse2 }
177 }
178}
179impl Eq for vec256_storage {}
180impl PartialEq for vec256_storage {
181 #[inline(always)]
182 fn eq(&self, rhs: &Self) -> bool {
183 unsafe { self.sse2 == rhs.sse2 }
184 }
185}
186
187#[allow(non_camel_case_types)]
188#[derive(Copy, Clone)]
189pub union vec512_storage {
190 u32x16: [u32; 16],
191 u64x8: [u64; 8],
192 u128x4: [u128; 4],
193 sse2: [vec128_storage; 4],
194 avx: [vec256_storage; 2],
195}
196impl Default for vec512_storage {
197 #[inline(always)]
198 fn default() -> Self {
199 vec512_storage {
200 u128x4: [0, 0, 0, 0],
201 }
202 }
203}
204impl vec512_storage {
205 #[inline(always)]
206 pub fn new128(xs: [vec128_storage; 4]) -> Self {
207 Self { sse2: xs }
208 }
209 #[inline(always)]
210 pub fn split128(self) -> [vec128_storage; 4] {
211 unsafe { self.sse2 }
212 }
213}
214impl Eq for vec512_storage {}
215impl PartialEq for vec512_storage {
216 #[inline(always)]
217 fn eq(&self, rhs: &Self) -> bool {
218 unsafe { self.avx == rhs.avx }
219 }
220}
221
222macro_rules! impl_into {
223 ($storage:ident, $array:ty, $name:ident) => {
224 impl From<$storage> for $array {
225 #[inline(always)]
226 fn from(vec: $storage) -> Self {
227 unsafe { vec.$name }
228 }
229 }
230 };
231}
232impl_into!(vec128_storage, [u32; 4], u32x4);
233impl_into!(vec128_storage, [u64; 2], u64x2);
234impl_into!(vec128_storage, [u128; 1], u128x1);
235impl_into!(vec256_storage, [u32; 8], u32x8);
236impl_into!(vec256_storage, [u64; 4], u64x4);
237impl_into!(vec256_storage, [u128; 2], u128x2);
238impl_into!(vec512_storage, [u32; 16], u32x16);
239impl_into!(vec512_storage, [u64; 8], u64x8);
240impl_into!(vec512_storage, [u128; 4], u128x4);
241
242#[macro_export]
247macro_rules! dispatch {
248 ($mach:ident, $MTy:ident, { $([$pub:tt$(($krate:tt))*])* fn $name:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty $body:block }) => {
249 #[cfg(feature = "std")]
250 $($pub$(($krate))*)* fn $name($($arg: $argty),*) -> $ret {
251 #[inline(always)]
252 fn fn_impl<$MTy: $crate::Machine>($mach: $MTy, $($arg: $argty),*) -> $ret $body
253 use std::arch::x86_64::*;
254 #[target_feature(enable = "avx2")]
255 unsafe fn impl_avx2($($arg: $argty),*) -> $ret {
256 let ret = fn_impl($crate::x86_64::AVX2::instance(), $($arg),*);
257 _mm256_zeroupper();
258 ret
259 }
260 #[target_feature(enable = "avx")]
261 #[target_feature(enable = "sse4.1")]
262 #[target_feature(enable = "ssse3")]
263 unsafe fn impl_avx($($arg: $argty),*) -> $ret {
264 let ret = fn_impl($crate::x86_64::AVX::instance(), $($arg),*);
265 _mm256_zeroupper();
266 ret
267 }
268 #[target_feature(enable = "sse4.1")]
269 #[target_feature(enable = "ssse3")]
270 unsafe fn impl_sse41($($arg: $argty),*) -> $ret {
271 fn_impl($crate::x86_64::SSE41::instance(), $($arg),*)
272 }
273 #[target_feature(enable = "ssse3")]
274 unsafe fn impl_ssse3($($arg: $argty),*) -> $ret {
275 fn_impl($crate::x86_64::SSSE3::instance(), $($arg),*)
276 }
277 #[target_feature(enable = "sse2")]
278 unsafe fn impl_sse2($($arg: $argty),*) -> $ret {
279 fn_impl($crate::x86_64::SSE2::instance(), $($arg),*)
280 }
281 unsafe {
282 if is_x86_feature_detected!("avx2") {
283 impl_avx2($($arg),*)
284 } else if is_x86_feature_detected!("avx") {
285 impl_avx($($arg),*)
286 } else if is_x86_feature_detected!("sse4.1") {
287 impl_sse41($($arg),*)
288 } else if is_x86_feature_detected!("ssse3") {
289 impl_ssse3($($arg),*)
290 } else if is_x86_feature_detected!("sse2") {
291 impl_sse2($($arg),*)
292 } else {
293 unimplemented!()
294 }
295 }
296 }
297 #[cfg(not(feature = "std"))]
298 #[inline(always)]
299 $($pub$(($krate))*)* fn $name($($arg: $argty),*) -> $ret {
300 unsafe fn fn_impl<$MTy: $crate::Machine>($mach: $MTy, $($arg: $argty),*) -> $ret $body
301 unsafe {
302 if cfg!(target_feature = "avx2") {
303 fn_impl($crate::x86_64::AVX2::instance(), $($arg),*)
304 } else if cfg!(target_feature = "avx") {
305 fn_impl($crate::x86_64::AVX::instance(), $($arg),*)
306 } else if cfg!(target_feature = "sse4.1") {
307 fn_impl($crate::x86_64::SSE41::instance(), $($arg),*)
308 } else if cfg!(target_feature = "ssse3") {
309 fn_impl($crate::x86_64::SSSE3::instance(), $($arg),*)
310 } else {
311 fn_impl($crate::x86_64::SSE2::instance(), $($arg),*)
312 }
313 }
314 }
315 };
316 ($mach:ident, $MTy:ident, { $([$pub:tt $(($krate:tt))*])* fn $name:ident($($arg:ident: $argty:ty),* $(,)*) $body:block }) => {
317 dispatch!($mach, $MTy, {
318 $([$pub $(($krate))*])* fn $name($($arg: $argty),*) -> () $body
319 });
320 }
321}
322
323#[macro_export]
330macro_rules! dispatch_light128 {
331 ($mach:ident, $MTy:ident, { $([$pub:tt$(($krate:tt))*])* fn $name:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty $body:block }) => {
332 #[cfg(feature = "std")]
333 $($pub $(($krate))*)* fn $name($($arg: $argty),*) -> $ret {
334 #[inline(always)]
335 fn fn_impl<$MTy: $crate::Machine>($mach: $MTy, $($arg: $argty),*) -> $ret $body
336 use std::arch::x86_64::*;
337 #[target_feature(enable = "avx")]
338 unsafe fn impl_avx($($arg: $argty),*) -> $ret {
339 fn_impl($crate::x86_64::AVX::instance(), $($arg),*)
340 }
341 #[target_feature(enable = "sse2")]
342 unsafe fn impl_sse2($($arg: $argty),*) -> $ret {
343 fn_impl($crate::x86_64::SSE2::instance(), $($arg),*)
344 }
345 unsafe {
346 if is_x86_feature_detected!("avx") {
347 impl_avx($($arg),*)
348 } else if is_x86_feature_detected!("sse2") {
349 impl_sse2($($arg),*)
350 } else {
351 unimplemented!()
352 }
353 }
354 }
355 #[cfg(not(feature = "std"))]
356 #[inline(always)]
357 $($pub$(($krate))*)* fn $name($($arg: $argty),*) -> $ret {
358 unsafe fn fn_impl<$MTy: $crate::Machine>($mach: $MTy, $($arg: $argty),*) -> $ret $body
359 unsafe {
360 if cfg!(target_feature = "avx2") {
361 fn_impl($crate::x86_64::AVX2::instance(), $($arg),*)
362 } else if cfg!(target_feature = "avx") {
363 fn_impl($crate::x86_64::AVX::instance(), $($arg),*)
364 } else if cfg!(target_feature = "sse4.1") {
365 fn_impl($crate::x86_64::SSE41::instance(), $($arg),*)
366 } else if cfg!(target_feature = "ssse3") {
367 fn_impl($crate::x86_64::SSSE3::instance(), $($arg),*)
368 } else {
369 fn_impl($crate::x86_64::SSE2::instance(), $($arg),*)
370 }
371 }
372 }
373 };
374 ($mach:ident, $MTy:ident, { $([$pub:tt$(($krate:tt))*])* fn $name:ident($($arg:ident: $argty:ty),* $(,)*) $body:block }) => {
375 dispatch_light128!($mach, $MTy, {
376 $([$pub $(($krate))*])* fn $name($($arg: $argty),*) -> () $body
377 });
378 }
379}
380
381#[macro_export]
388macro_rules! dispatch_light256 {
389 ($mach:ident, $MTy:ident, { $([$pub:tt$(($krate:tt))*])* fn $name:ident($($arg:ident: $argty:ty),* $(,)*) -> $ret:ty $body:block }) => {
390 #[cfg(feature = "std")]
391 $([$pub $(($krate))*])* fn $name($($arg: $argty),*) -> $ret {
392 #[inline(always)]
393 fn fn_impl<$MTy: $crate::Machine>($mach: $MTy, $($arg: $argty),*) -> $ret $body
394 use std::arch::x86_64::*;
395 #[target_feature(enable = "avx")]
396 unsafe fn impl_avx($($arg: $argty),*) -> $ret {
397 fn_impl($crate::x86_64::AVX::instance(), $($arg),*)
398 }
399 #[target_feature(enable = "sse2")]
400 unsafe fn impl_sse2($($arg: $argty),*) -> $ret {
401 fn_impl($crate::x86_64::SSE2::instance(), $($arg),*)
402 }
403 unsafe {
404 if is_x86_feature_detected!("avx") {
405 impl_avx($($arg),*)
406 } else if is_x86_feature_detected!("sse2") {
407 impl_sse2($($arg),*)
408 } else {
409 unimplemented!()
410 }
411 }
412 }
413 #[cfg(not(feature = "std"))]
414 #[inline(always)]
415 $($pub$(($krate))*)* fn $name($($arg: $argty),*) -> $ret {
416 unsafe fn fn_impl<$MTy: $crate::Machine>($mach: $MTy, $($arg: $argty),*) -> $ret $body
417 unsafe {
418 if cfg!(target_feature = "avx2") {
419 fn_impl($crate::x86_64::AVX2::instance(), $($arg),*)
420 } else if cfg!(target_feature = "avx") {
421 fn_impl($crate::x86_64::AVX::instance(), $($arg),*)
422 } else if cfg!(target_feature = "sse4.1") {
423 fn_impl($crate::x86_64::SSE41::instance(), $($arg),*)
424 } else if cfg!(target_feature = "ssse3") {
425 fn_impl($crate::x86_64::SSSE3::instance(), $($arg),*)
426 } else {
427 fn_impl($crate::x86_64::SSE2::instance(), $($arg),*)
428 }
429 }
430 }
431 };
432 ($mach:ident, $MTy:ident, { $([$pub:tt$(($krate:tt))*])* fn $name:ident($($arg:ident: $argty:ty),* $(,)*) $body:block }) => {
433 dispatch_light256!($mach, $MTy, {
434 $([$pub $(($krate))*])* fn $name($($arg: $argty),*) -> () $body
435 });
436 }
437}