1use crate::simd_optimize::feature_detect::CpuFeatures;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum SimdImplementation {
11 Scalar,
13 SSE,
15 AVX,
17 AVX2,
19 AVX512,
21 NEON,
23 SVE,
25}
26
27impl SimdImplementation {
28 pub fn name(&self) -> &'static str {
30 match self {
31 SimdImplementation::Scalar => "Scalar",
32 SimdImplementation::SSE => "SSE",
33 SimdImplementation::AVX => "AVX",
34 SimdImplementation::AVX2 => "AVX2",
35 SimdImplementation::AVX512 => "AVX512",
36 SimdImplementation::NEON => "NEON",
37 SimdImplementation::SVE => "SVE",
38 }
39 }
40
41 pub fn is_avx2_or_better(&self) -> bool {
43 matches!(self, SimdImplementation::AVX2 | SimdImplementation::AVX512)
44 }
45
46 pub fn supports_fma(&self, features: &CpuFeatures) -> bool {
48 match self {
49 SimdImplementation::AVX2 | SimdImplementation::AVX512 => features.fma,
50 _ => false,
51 }
52 }
53
54 pub fn is_neon_or_better(&self) -> bool {
56 matches!(self, SimdImplementation::NEON | SimdImplementation::SVE)
57 }
58
59 pub fn vector_width(&self) -> usize {
61 match self {
62 SimdImplementation::Scalar => 0,
63 SimdImplementation::SSE => 128,
64 SimdImplementation::AVX => 256,
65 SimdImplementation::AVX2 => 256,
66 SimdImplementation::AVX512 => 512,
67 SimdImplementation::NEON => 128,
68 SimdImplementation::SVE => 128, }
70 }
71}
72
73pub fn select_simd_implementation(features: &CpuFeatures) -> SimdImplementation {
83 if features.avx512f {
85 return SimdImplementation::AVX512;
86 }
87
88 if features.avx2 {
89 return SimdImplementation::AVX2;
90 }
91
92 if features.avx {
93 return SimdImplementation::AVX;
94 }
95
96 if features.sse2 {
97 return SimdImplementation::SSE;
98 }
99
100 if features.sve {
102 return SimdImplementation::SVE;
103 }
104
105 if features.neon {
106 return SimdImplementation::NEON;
107 }
108
109 SimdImplementation::Scalar
111}
112
113#[allow(clippy::too_many_arguments)]
133pub fn apply_simd_strategy<T, S, SSE, AVX, AVX2, AVX512, NEON, SVE>(
134 features: &CpuFeatures,
135 scalar: S,
136 sse: SSE,
137 avx: AVX,
138 avx2: AVX2,
139 avx512: AVX512,
140 neon: NEON,
141 sve: SVE,
142) -> T
143where
144 S: FnOnce() -> T,
145 SSE: FnOnce() -> T,
146 AVX: FnOnce() -> T,
147 AVX2: FnOnce() -> T,
148 AVX512: FnOnce() -> T,
149 NEON: FnOnce() -> T,
150 SVE: FnOnce() -> T,
151{
152 let implementation = select_simd_implementation(features);
153
154 match implementation {
155 SimdImplementation::AVX512 => avx512(),
156 SimdImplementation::AVX2 => avx2(),
157 SimdImplementation::AVX => avx(),
158 SimdImplementation::SSE => sse(),
159 SimdImplementation::NEON => neon(),
160 SimdImplementation::SVE => sve(),
161 SimdImplementation::Scalar => scalar(),
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_simd_selection() {
171 let features = CpuFeatures::default();
173 assert_eq!(
174 select_simd_implementation(&features),
175 SimdImplementation::Scalar
176 );
177
178 let features = CpuFeatures {
180 sse2: true,
181 ..Default::default()
182 };
183 assert_eq!(
184 select_simd_implementation(&features),
185 SimdImplementation::SSE
186 );
187
188 let features = CpuFeatures {
190 sse2: true,
191 avx: true,
192 ..Default::default()
193 };
194 assert_eq!(
195 select_simd_implementation(&features),
196 SimdImplementation::AVX
197 );
198
199 let features = CpuFeatures {
201 sse2: true,
202 avx: true,
203 avx2: true,
204 ..Default::default()
205 };
206 assert_eq!(
207 select_simd_implementation(&features),
208 SimdImplementation::AVX2
209 );
210
211 let features = CpuFeatures {
213 sse2: true,
214 avx: true,
215 avx2: true,
216 avx512f: true,
217 ..Default::default()
218 };
219 assert_eq!(
220 select_simd_implementation(&features),
221 SimdImplementation::AVX512
222 );
223
224 let features = CpuFeatures {
226 neon: true,
227 ..Default::default()
228 };
229 assert_eq!(
230 select_simd_implementation(&features),
231 SimdImplementation::NEON
232 );
233
234 let features = CpuFeatures {
236 neon: true,
237 sve: true,
238 ..Default::default()
239 };
240 assert_eq!(
241 select_simd_implementation(&features),
242 SimdImplementation::SVE
243 );
244 }
245
246 #[test]
247 fn test_simd_strategy() {
248 let apply_test = |features: &CpuFeatures| {
250 apply_simd_strategy(
251 features,
252 || "scalar",
253 || "sse",
254 || "avx",
255 || "avx2",
256 || "avx512",
257 || "neon",
258 || "sve",
259 )
260 };
261
262 let features = CpuFeatures::default();
264 assert_eq!(apply_test(&features), "scalar");
265
266 let features = CpuFeatures {
268 sse2: true,
269 ..Default::default()
270 };
271 assert_eq!(apply_test(&features), "sse");
272
273 let features = CpuFeatures {
275 sse2: true,
276 avx: true,
277 ..Default::default()
278 };
279 assert_eq!(apply_test(&features), "avx");
280
281 let features = CpuFeatures {
283 sse2: true,
284 avx: true,
285 avx2: true,
286 ..Default::default()
287 };
288 assert_eq!(apply_test(&features), "avx2");
289 }
290}