1use crate::{SIMD128, SIMD256, SIMD64};
2
3pub unsafe trait InstructionSet: Copy + 'static {
4 const ID: InstructionSetTypeId;
5 const ARCH: bool;
6
7 unsafe fn new() -> Self;
8
9 fn is_enabled() -> bool;
10}
11
12#[inline(always)]
13#[must_use]
14pub fn detect<S: InstructionSet>() -> Option<S> {
15 S::is_enabled().then(|| unsafe { S::new() })
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum InstructionSetTypeId {
20 Fallback,
21 SSE2,
22 SSSE3,
23 SSE41,
24 AVX2,
25 NEON,
26 WASM128,
27}
28
29#[doc(hidden)]
30#[inline]
31#[must_use]
32pub const fn matches_isa_impl<S, U>() -> bool
33where
34 S: InstructionSet,
35 U: InstructionSet,
36{
37 #[allow(clippy::enum_glob_use)]
38 use InstructionSetTypeId::*;
39
40 let (self_ty, super_ty) = (S::ID, U::ID);
41 let inherits = match self_ty {
42 Fallback => matches!(super_ty, Fallback),
43 SSE2 => matches!(super_ty, Fallback | SSE2),
44 SSSE3 => matches!(super_ty, Fallback | SSE2 | SSSE3),
45 SSE41 => matches!(super_ty, Fallback | SSE2 | SSSE3 | SSE41),
46 AVX2 => matches!(super_ty, Fallback | SSE2 | SSSE3 | SSE41 | AVX2),
47 NEON => matches!(super_ty, Fallback | NEON),
48 WASM128 => matches!(super_ty, Fallback | WASM128),
49 };
50
51 S::ARCH && U::ARCH && inherits
52}
53
54#[macro_export]
55macro_rules! is_isa_type {
56 ($self:ident, $isa:ident) => {{
57 matches!(
58 <$self as $crate::isa::InstructionSet>::ID,
59 <$isa as $crate::isa::InstructionSet>::ID
60 )
61 }};
62}
63
64#[macro_export]
65macro_rules! matches_isa {
66 ($self:ident, $super:ident $(| $other:ident)*) => {{
67 use $crate::isa::InstructionSet;
69 struct MatchesISA<S>(S);
70 impl<S: InstructionSet> MatchesISA<S> {
71 const VALUE: bool = { $crate::isa::matches_isa_impl::<S, $super>() $(||$crate::isa::matches_isa_impl::<S, $other>())* };
72 }
73 MatchesISA::<$self>::VALUE
74 }};
75}
76
77#[derive(Debug, Clone, Copy)]
78pub struct Fallback(());
79
80unsafe impl InstructionSet for Fallback {
81 const ID: InstructionSetTypeId = InstructionSetTypeId::Fallback;
82 const ARCH: bool = true;
83
84 #[inline(always)]
85 unsafe fn new() -> Self {
86 Self(())
87 }
88
89 #[inline(always)]
90 fn is_enabled() -> bool {
91 true
92 }
93}
94
95#[allow(unused_macros)]
96macro_rules! is_feature_detected {
97 ($feature:tt) => {{
98 #[cfg(target_feature = $feature)]
99 {
100 true
101 }
102 #[cfg(not(target_feature = $feature))]
103 {
104 #[cfg(feature = "detect")]
105 {
106 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
107 {
108 std::arch::is_x86_feature_detected!($feature)
109 }
110 #[cfg(target_arch = "arm")]
111 {
112 std::arch::is_arm_feature_detected!($feature)
113 }
114 #[cfg(target_arch = "aarch64")]
115 {
116 std::arch::is_aarch64_feature_detected!($feature)
117 }
118 #[cfg(not(any(
119 target_arch = "x86",
120 target_arch = "x86_64",
121 target_arch = "arm",
122 target_arch = "aarch64"
123 )))]
124 {
125 false
126 }
127 }
128 #[cfg(not(feature = "detect"))]
129 {
130 false
131 }
132 }
133 }};
134}
135
136macro_rules! x86_is_enabled {
137 ($feature:tt) => {{
138 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
139 {
140 is_feature_detected!($feature)
141 }
142 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
143 {
144 false
145 }
146 }};
147}
148
149#[derive(Debug, Clone, Copy)]
150pub struct SSE2(());
151
152unsafe impl InstructionSet for SSE2 {
153 const ID: InstructionSetTypeId = InstructionSetTypeId::SSE2;
154 const ARCH: bool = cfg!(any(target_arch = "x86", target_arch = "x86_64"));
155
156 #[inline(always)]
157 unsafe fn new() -> Self {
158 Self(())
159 }
160
161 #[inline(always)]
162 fn is_enabled() -> bool {
163 x86_is_enabled!("sse2")
164 }
165}
166
167unsafe impl SIMD64 for SSE2 {}
168unsafe impl SIMD128 for SSE2 {}
169unsafe impl SIMD256 for SSE2 {}
170
171#[derive(Debug, Clone, Copy)]
172pub struct SSSE3(());
173
174unsafe impl InstructionSet for SSSE3 {
175 const ID: InstructionSetTypeId = InstructionSetTypeId::SSSE3;
176 const ARCH: bool = cfg!(any(target_arch = "x86", target_arch = "x86_64"));
177
178 #[inline(always)]
179 unsafe fn new() -> Self {
180 Self(())
181 }
182
183 #[inline(always)]
184 fn is_enabled() -> bool {
185 x86_is_enabled!("ssse3")
186 }
187}
188
189unsafe impl SIMD64 for SSSE3 {}
190unsafe impl SIMD128 for SSSE3 {}
191unsafe impl SIMD256 for SSSE3 {}
192
193#[derive(Debug, Clone, Copy)]
194pub struct SSE41(());
195
196unsafe impl InstructionSet for SSE41 {
197 const ID: InstructionSetTypeId = InstructionSetTypeId::SSE41;
198 const ARCH: bool = cfg!(any(target_arch = "x86", target_arch = "x86_64"));
199
200 #[inline(always)]
201 unsafe fn new() -> Self {
202 Self(())
203 }
204
205 #[inline(always)]
206 fn is_enabled() -> bool {
207 x86_is_enabled!("sse4.1")
208 }
209}
210
211unsafe impl SIMD64 for SSE41 {}
212unsafe impl SIMD128 for SSE41 {}
213unsafe impl SIMD256 for SSE41 {}
214
215#[derive(Debug, Clone, Copy)]
216pub struct AVX2(());
217
218unsafe impl InstructionSet for AVX2 {
219 const ID: InstructionSetTypeId = InstructionSetTypeId::AVX2;
220 const ARCH: bool = cfg!(any(target_arch = "x86", target_arch = "x86_64"));
221
222 #[inline(always)]
223 unsafe fn new() -> Self {
224 Self(())
225 }
226
227 #[inline(always)]
228 fn is_enabled() -> bool {
229 x86_is_enabled!("avx2")
230 }
231}
232
233unsafe impl SIMD64 for AVX2 {}
234unsafe impl SIMD128 for AVX2 {}
235unsafe impl SIMD256 for AVX2 {}
236
237#[allow(clippy::upper_case_acronyms)]
238#[derive(Debug, Clone, Copy)]
239pub struct NEON(());
240
241unsafe impl InstructionSet for NEON {
242 const ID: InstructionSetTypeId = InstructionSetTypeId::NEON;
243 const ARCH: bool = cfg!(any(target_arch = "arm", target_arch = "aarch64"));
244
245 #[inline(always)]
246 unsafe fn new() -> Self {
247 Self(())
248 }
249
250 #[inline(always)]
251 fn is_enabled() -> bool {
252 #[cfg(target_arch = "arm")]
253 {
254 #[cfg(feature = "unstable")]
255 {
256 is_feature_detected!("neon")
257 }
258 #[cfg(not(feature = "unstable"))]
259 {
260 false
261 }
262 }
263 #[cfg(target_arch = "aarch64")]
264 {
265 is_feature_detected!("neon")
266 }
267 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
268 {
269 false
270 }
271 }
272}
273
274unsafe impl SIMD64 for NEON {}
275unsafe impl SIMD128 for NEON {}
276unsafe impl SIMD256 for NEON {}
277
278#[derive(Debug, Clone, Copy)]
279pub struct WASM128(());
280
281unsafe impl InstructionSet for WASM128 {
282 const ID: InstructionSetTypeId = InstructionSetTypeId::WASM128;
283 const ARCH: bool = cfg!(target_arch = "wasm32");
284
285 #[inline(always)]
286 unsafe fn new() -> Self {
287 Self(())
288 }
289
290 #[inline(always)]
291 fn is_enabled() -> bool {
292 #[cfg(target_arch = "wasm32")]
293 {
294 is_feature_detected!("simd128")
295 }
296 #[cfg(not(target_arch = "wasm32"))]
297 {
298 false
299 }
300 }
301}
302
303unsafe impl SIMD64 for WASM128 {}
304unsafe impl SIMD128 for WASM128 {}
305unsafe impl SIMD256 for WASM128 {}