1#![allow(non_camel_case_types)]
6
7#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
8mod aarch64;
9#[cfg(not(any(
10 all(
11 target_arch = "x86_64",
12 target_feature = "avx",
13 target_feature = "avx2",
14 target_feature = "fma",
15 ),
16 all(target_arch = "aarch64", target_feature = "neon"),
17 all(target_arch = "wasm32", target_feature = "simd128"),
18)))]
19mod auto;
20#[cfg(all(
21 target_arch = "x86_64",
22 target_feature = "avx",
23 target_feature = "avx2",
24 target_feature = "fma"
25))]
26mod avx;
27#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
28mod wasm32;
29
30#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
31pub use aarch64::*;
32#[cfg(not(any(
33 all(
34 target_arch = "x86_64",
35 target_feature = "avx",
36 target_feature = "avx2",
37 target_feature = "fma",
38 ),
39 all(target_arch = "aarch64", target_feature = "neon"),
40 all(target_arch = "wasm32", target_feature = "simd128"),
41)))]
42pub use auto::*;
43#[cfg(all(
44 target_arch = "x86_64",
45 target_feature = "avx",
46 target_feature = "avx2",
47 target_feature = "fma",
48))]
49pub use avx::*;
50#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
51pub use wasm32::*;
52
53pub trait Simd {
54 const LANES: usize;
55}
56
57impl Simd for u8x32 {
58 const LANES: usize = 32;
59}
60
61impl Simd for i8x16 {
62 const LANES: usize = 16;
63}
64
65impl Simd for i16x16 {
66 const LANES: usize = 16;
67}
68
69impl Simd for i32x8 {
70 const LANES: usize = 8;
71}
72
73impl Simd for f32x8 {
74 const LANES: usize = 8;
75}
76
77#[cfg(test)]
78mod tests {
79 use std::f32::INFINITY;
80
81 use super::*;
82
83 #[test]
84 fn f32x8_splat() {
85 for v in [1.0, 0.0, f32::INFINITY, f32::NEG_INFINITY] {
86 assert_eq!(f32x8::splat(v).to_array(), [v; 8]);
87 }
88 }
89
90 #[test]
91 fn f32x8_indexed() {
92 let index: Vec<f32> = (0..8).map(|v| v as f32).collect();
93 assert_eq!(f32x8::indexed().to_array(), index[..]);
94 }
95
96 #[test]
97 fn f32x8_from_array() {
98 let value = [-5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0];
99 assert_eq!(f32x8::from_array(value).to_array(), value);
100 }
101
102 #[test]
103 fn u32x8_splat() {
104 assert_eq!([0; 8], u32x8::splat(0).to_array());
105 assert_eq!([u32::MAX; 8], u32x8::splat(u32::MAX).to_array());
106 assert_eq!([u32::MIN; 8], u32x8::splat(u32::MIN).to_array());
107 }
108
109 #[test]
110 fn u32x8_mul_add() {
111 let a = u32x8::from(f32x8::from_array([10.0, 20.0, 30.0, 50.0, 70.0, 110.0, 130.0, 170.0]));
112 let b = u32x8::from(f32x8::from_array([19.0, 23.0, 29.0, 31.0, 37.0, 41.0, 43.0, 47.0]));
113 let c = u32x8::from(f32x8::from_array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]));
114 let expected = [191, 462, 873, 1554, 2595, 4516, 5597, 7998];
115 assert_eq!(expected, u32x8::mul_add(a, b, c).to_array());
116
117 let a = u32x8::from(f32x8::splat(0x007f_ffff as f32));
118 let b = u32x8::from(f32x8::splat(0x200 as f32));
119 let c = u32x8::from(f32x8::splat(0x1ff as f32));
120 let expected = [u32::MAX; 8];
121 assert_eq!(expected, u32x8::mul_add(a, b, c).to_array());
122 }
123
124 #[test]
125 fn u32x8_from_f32x8() {
126 let values = u32x8::from(f32x8::from_array([
127 -INFINITY,
128 -f32::MAX,
129 -2.5,
130 -1.0,
131 -0.5,
132 -f32::MIN_POSITIVE,
133 -0.0,
134 0.0,
135 ]));
136 assert_eq!(values.to_array(), [0u32; 8]);
137
138 let f32_before = |f| f32::from_bits(f32::to_bits(f) - 1);
139 let values = u32x8::from(f32x8::from_array([
140 0.0,
141 f32::MIN_POSITIVE,
142 0.4,
143 0.5,
144 0.6,
145 0.7,
146 0.8,
147 f32_before(1.),
148 ]));
149 assert_eq!(values.to_array(), [0u32; 8]);
150
151 let values = u32x8::from(f32x8::from_array([
152 1.0,
153 1.4,
154 1.5,
155 f32_before(2.0),
156 2.0,
157 2.4,
158 2.5,
159 f32_before(3.0),
160 ]));
161 assert_eq!(values.to_array(), [1, 1, 1, 1, 2, 2, 2, 2]);
162
163 const MAX_INT_F32: u32 = 1u32 << 24;
164 for value in (MAX_INT_F32 - 255)..MAX_INT_F32 {
165 assert_eq!([value; 8], u32x8::from(f32x8::splat(value as f32)).to_array());
166 }
167 }
168}