target_features/
simd.rs

1use crate::Architecture;
2
3#[doc(hidden)]
4pub enum SimdTypeImpl {
5    Float32,
6    Float64,
7    Other,
8}
9
10/// Types which can be SIMD vector elements.
11pub trait SimdType {
12    #[doc(hidden)]
13    const IMPL: SimdTypeImpl;
14}
15
16impl SimdType for u8 {
17    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
18}
19
20impl SimdType for u16 {
21    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
22}
23
24impl SimdType for u32 {
25    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
26}
27
28impl SimdType for u64 {
29    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
30}
31
32impl SimdType for usize {
33    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
34}
35
36impl SimdType for i8 {
37    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
38}
39
40impl SimdType for i16 {
41    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
42}
43
44impl SimdType for i32 {
45    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
46}
47
48impl SimdType for i64 {
49    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
50}
51
52impl SimdType for isize {
53    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
54}
55
56impl SimdType for f32 {
57    const IMPL: SimdTypeImpl = SimdTypeImpl::Float32;
58}
59
60impl SimdType for f64 {
61    const IMPL: SimdTypeImpl = SimdTypeImpl::Float64;
62}
63
64impl<T> SimdType for *const T {
65    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
66}
67
68impl<T> SimdType for *mut T {
69    const IMPL: SimdTypeImpl = SimdTypeImpl::Other;
70}
71
72impl crate::Target {
73    /// Returns a suggested number of elements for a SIMD vector of the provided type.
74    ///
75    /// The returned value is an approximation and not necessarily indicative of the
76    /// optimal vector width.  A few caveats:
77    /// * Every instruction set is different, and this function doesn't take into account any
78    /// particular operations--it's just a guess, and should be accurate at least for basic arithmetic.
79    /// * Variable length vector instruction sets (ARM SVE and RISC-V V) only return the minimum
80    /// vector length.
81    pub const fn suggested_simd_width<T: SimdType>(&self) -> Option<usize> {
82        let is_f32 = T::IMPL as u8 == SimdTypeImpl::Float32 as u8;
83        let is_f64 = T::IMPL as u8 == SimdTypeImpl::Float64 as u8;
84
85        let v128 = 16 / core::mem::size_of::<T>();
86        let v256 = 32 / core::mem::size_of::<T>();
87        let v512 = 64 / core::mem::size_of::<T>();
88        let v1024 = 128 / core::mem::size_of::<T>();
89
90        if let Architecture::Arm = self.architecture() {
91            // Neon on arm doesn't support f64
92            if self.supports_feature_str("neon") && !is_f64 {
93                Some(v128)
94            } else {
95                None
96            }
97        } else if let Architecture::AArch64 = self.architecture() {
98            if self.supports_feature_str("neon") {
99                Some(v128)
100            } else {
101                None
102            }
103        } else if let Architecture::Hexagon = self.architecture() {
104            // HVX doesn't support floats
105            if is_f32 || is_f64 {
106                None
107            } else if self.supports_feature_str("hvx-length128b") {
108                Some(v1024)
109            } else if self.supports_feature_str("hvx") {
110                Some(v512)
111            } else {
112                None
113            }
114        } else if let Architecture::Mips = self.architecture() {
115            if self.supports_feature_str("msa") {
116                Some(v128)
117            } else {
118                None
119            }
120        } else if let Architecture::PowerPC = self.architecture() {
121            // Altivec without VSX doesn't support f64
122            if self.supports_feature_str("vsx") || (self.supports_feature_str("altivec") && !is_f64)
123            {
124                Some(v128)
125            } else {
126                None
127            }
128        } else if let Architecture::RiscV = self.architecture() {
129            // V provides at least 128-bit vectors
130            if self.supports_feature_str("v") {
131                Some(v128)
132            } else {
133                None
134            }
135        } else if let Architecture::Wasm = self.architecture() {
136            if self.supports_feature_str("simd128") {
137                Some(v128)
138            } else {
139                None
140            }
141        } else if let Architecture::X86 = self.architecture() {
142            if self.supports_feature_str("avx512f") {
143                Some(v512)
144            } else if self.supports_feature_str("avx2")
145                || (is_f32 || is_f64) && self.supports_feature_str("avx")
146            {
147                // AVX supports f32 and f64
148                Some(v256)
149            } else if self.supports_feature_str("sse2")
150                || is_f32 && self.supports_feature_str("sse")
151            {
152                // SSE supports f32
153                Some(v128)
154            } else {
155                None
156            }
157        } else {
158            None
159        }
160    }
161}