target_features/
lib.rs

1//! # Target features
2//! A database of target features available to the Rust compiler.
3//!
4#![doc = include_str!(concat!(env!("OUT_DIR"), "/generated.md"))]
5#![no_std]
6
7include!(concat!(env!("OUT_DIR"), "/generated.rs"));
8
9/// List of features available for each architecture.
10pub mod docs {
11    include!(concat!(env!("OUT_DIR"), "/docs.rs"));
12}
13
14mod simd;
15pub use simd::*;
16
17const fn str_eq(a: &str, b: &str) -> bool {
18    let a = a.as_bytes();
19    let b = b.as_bytes();
20
21    if a.len() != b.len() {
22        return false;
23    }
24
25    let mut i = 0;
26    while i < a.len() {
27        if a[i] != b[i] {
28            return false;
29        }
30        i += 1;
31    }
32    true
33}
34
35/// A target architecture.
36#[derive(Copy, Clone, PartialEq, Eq, Debug)]
37pub enum Architecture {
38    /// Arm
39    Arm,
40    /// AArch64
41    AArch64,
42    /// BPF
43    Bpf,
44    /// Hexagon
45    Hexagon,
46    /// MIPS
47    Mips,
48    /// PowerPC
49    PowerPC,
50    /// RISC-V
51    RiscV,
52    /// WASM
53    Wasm,
54    /// x86 and x86-64
55    X86,
56    /// Another target, which doesn't have features
57    Unsupported,
58}
59
60impl Architecture {
61    /// Create a new `Architecture` from its name.
62    pub const fn from_str(architecture: &str) -> Self {
63        if str_eq(architecture, "arm") {
64            Self::Arm
65        } else if str_eq(architecture, "aarch64") {
66            Self::AArch64
67        } else if str_eq(architecture, "bpf") {
68            Self::Bpf
69        } else if str_eq(architecture, "hexagon") {
70            Self::Hexagon
71        } else if str_eq(architecture, "mips") || str_eq(architecture, "mips64") {
72            Self::Mips
73        } else if str_eq(architecture, "powerpc") || str_eq(architecture, "powerpc64") {
74            Self::PowerPC
75        } else if str_eq(architecture, "riscv32") || str_eq(architecture, "riscv64") {
76            Self::RiscV
77        } else if str_eq(architecture, "wasm32") || str_eq(architecture, "wasm64") {
78            Self::Wasm
79        } else if str_eq(architecture, "x86") || str_eq(architecture, "x86_64") {
80            Self::X86
81        } else {
82            Self::Unsupported
83        }
84    }
85}
86
87/// Returned by [`Feature::new`] when the requested feature can't be found.
88#[derive(Copy, Clone, Debug)]
89pub struct UnknownFeature;
90
91impl core::fmt::Display for UnknownFeature {
92    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
93        write!(f, "unknown target feature")
94    }
95}
96
97/// Returned by [`Target::from_cpu`] when the requested CPU can't be found.
98#[derive(Copy, Clone, Debug)]
99pub struct UnknownCpu;
100
101impl core::fmt::Display for UnknownCpu {
102    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
103        write!(f, "unknown target CPU")
104    }
105}
106
107/// A target feature.
108#[derive(Copy, Clone, PartialEq, Eq)]
109pub struct Feature(usize);
110
111impl core::fmt::Debug for Feature {
112    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
113        f.debug_struct("Feature")
114            .field("architecture", &self.architecture())
115            .field("name", &self.name())
116            .finish()
117    }
118}
119
120impl Feature {
121    /// Look up a feature.
122    pub const fn new(architecture: Architecture, feature: &str) -> Result<Self, UnknownFeature> {
123        let mut i = 0;
124        while i < FEATURES.len() {
125            if (architecture as u8) == (FEATURES[i].0 as u8) && str_eq(feature, FEATURES[i].1) {
126                return Ok(Self(i));
127            }
128            i += 1;
129        }
130
131        Err(UnknownFeature)
132    }
133
134    /// Get the name of the feature.
135    pub const fn name(&self) -> &'static str {
136        FEATURES[self.0].1
137    }
138
139    /// Get the architecture this feature is for.
140    pub const fn architecture(&self) -> Architecture {
141        FEATURES[self.0].0
142    }
143
144    /// Get a human-readable description of the feature.
145    pub const fn description(&self) -> &'static str {
146        FEATURES[self.0].2
147    }
148
149    /// Return all features which are implied by the existence of this feature.
150    ///
151    /// For example, "avx2" implies the existence of "avx" on x86 architectures.
152    pub const fn implies(&self) -> &'static [Feature] {
153        FEATURES[self.0].3
154    }
155}
156
157/// Iterator returned by [`Target::features`].
158pub struct FeaturesIter {
159    target: Target,
160    index: usize,
161}
162
163impl Iterator for FeaturesIter {
164    type Item = Feature;
165
166    fn next(&mut self) -> Option<Self::Item> {
167        while self.index < self.target.features.len() {
168            let feature = if self.target.features[self.index] {
169                Some(Feature(self.index))
170            } else {
171                None
172            };
173            self.index += 1;
174            if feature.is_some() {
175                return feature;
176            }
177        }
178        None
179    }
180}
181
182impl core::fmt::Debug for Target {
183    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
184        struct FeaturesHelper(Target);
185        impl core::fmt::Debug for FeaturesHelper {
186            fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
187                f.debug_list().entries(self.0.features()).finish()
188            }
189        }
190
191        f.debug_struct("Target")
192            .field("architecture", &self.architecture())
193            .field("features", &FeaturesHelper(*self))
194            .finish()
195    }
196}
197
198/// A target architecture with optional features.
199#[derive(Copy, Clone, PartialEq, Eq)]
200pub struct Target {
201    architecture: Architecture,
202    features: [bool; FEATURES.len()],
203}
204
205impl Target {
206    /// Create a target with no specified features.
207    pub const fn new(architecture: Architecture) -> Self {
208        Self {
209            architecture,
210            features: [false; FEATURES.len()],
211        }
212    }
213
214    /// Create a target based on a particular CPU.
215    pub const fn from_cpu(architecture: Architecture, cpu: &str) -> Result<Self, UnknownCpu> {
216        let mut target = Self::new(architecture);
217        let mut i = 0;
218        while i < CPUS.len() {
219            if architecture as u8 == CPUS[i].0 as u8 && str_eq(cpu, CPUS[i].1) {
220                let mut j = 0;
221                while j < CPUS[i].2.len() {
222                    target = target.with_feature(CPUS[i].2[j]);
223                    j += 1;
224                }
225                return Ok(target);
226            }
227            i += 1;
228        }
229        Err(UnknownCpu)
230    }
231
232    /// Returns the target architecture.
233    pub const fn architecture(&self) -> Architecture {
234        self.architecture
235    }
236
237    /// Returns an iterator over the features.
238    pub const fn features(&self) -> FeaturesIter {
239        FeaturesIter {
240            target: *self,
241            index: 0,
242        }
243    }
244
245    /// Returns whether the target supports the specified feature.
246    pub const fn supports_feature(&self, feature: Feature) -> bool {
247        self.features[feature.0]
248    }
249
250    /// Returns whether the target supports the specified feature.
251    ///
252    /// # Panics
253    /// Panics if the feature doesn't belong to the target architecture.
254    pub const fn supports_feature_str(&self, feature: &str) -> bool {
255        if let Ok(feature) = Feature::new(self.architecture, feature) {
256            self.supports_feature(feature)
257        } else {
258            panic!("unknown feature");
259        }
260    }
261
262    /// Add a feature to the target.
263    ///
264    /// # Panics
265    /// Panics if the feature doesn't belong to the target architecture.
266    pub const fn with_feature(mut self, feature: Feature) -> Self {
267        assert!(feature.architecture() as u8 == self.architecture as u8);
268        self.features[feature.0] = true;
269
270        let mut i = 0;
271        let implies = feature.implies();
272        while i < implies.len() {
273            self.features[implies[i].0] = true;
274            i += 1;
275        }
276
277        self
278    }
279
280    /// Add a feature to the target.
281    ///
282    /// # Panics
283    /// Panics if the requested feature name doesn't exist for the target architecture.
284    pub const fn with_feature_str(self, feature: &str) -> Self {
285        if let Ok(feature) = Feature::new(self.architecture, feature) {
286            self.with_feature(feature)
287        } else {
288            panic!("unknown feature");
289        }
290    }
291}