Skip to main content

target_features/
lib.rs

1//! Types and constants for working with target features.
2//!
3//! Target feature constants are provided in a module named for the target
4//! architecture, such as `x86_64` or `aarch64`. Each constant includes the
5//! target feature it names and any implicitly enabled target features.
6//!
7//! ```
8//! # #[cfg(target_arch = "x86_64")] {
9//! use target_features::{TargetFeatures, x86_64::{AVX, BMI2, FMA}};
10//!
11//! const REQUIRED: TargetFeatures = AVX.with(FMA).with(BMI2);
12//! assert!(REQUIRED.contains(AVX));
13//! # }
14//! ```
15//!
16#![doc = include_str!("../rustc-version.md")]
17#![no_std]
18
19#[allow(unknown_lints, unexpected_cfgs)]
20mod database;
21pub use database::*;
22
23#[allow(unknown_lints, unexpected_cfgs)]
24mod simd;
25pub use simd::*;
26
27/// A set of target features.
28#[derive(Copy, Clone, PartialEq, Eq, Hash)]
29pub struct TargetFeatures {
30    bits: [u64; database::FEATURE_WORDS],
31}
32
33impl TargetFeatures {
34    /// Returns a set containing no target features.
35    pub const fn empty() -> Self {
36        Self {
37            bits: [0; database::FEATURE_WORDS],
38        }
39    }
40
41    pub(crate) const fn with_bit(mut self, index: usize) -> Self {
42        self.bits[index / 64] |= 1 << (index % 64);
43        self
44    }
45
46    /// Returns the target features enabled at compile time.
47    ///
48    /// This includes features enabled by the target specification, target CPU,
49    /// and `-C target-feature` compiler options.
50    pub const fn enabled_for_target() -> Self {
51        database::enabled_for_target()
52    }
53
54    /// Returns whether `self` contains every target feature in `required`.
55    pub const fn contains(self, required: Self) -> bool {
56        let mut i = 0;
57        while i < self.bits.len() {
58            if self.bits[i] & required.bits[i] != required.bits[i] {
59                return false;
60            }
61            i += 1;
62        }
63        true
64    }
65
66    /// Returns `self` with all target features in `additional`.
67    #[must_use]
68    pub const fn with(mut self, additional: Self) -> Self {
69        let mut i = 0;
70        while i < self.bits.len() {
71            self.bits[i] |= additional.bits[i];
72            i += 1;
73        }
74        self
75    }
76}
77
78impl core::fmt::Debug for TargetFeatures {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        struct Basis<'a>(&'a TargetFeatures);
81
82        impl core::fmt::Debug for Basis<'_> {
83            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84                let all = database::features();
85                let mut list = f.debug_list();
86
87                for (index, feature) in all.iter().enumerate() {
88                    if !self.0.contains(feature.features) {
89                        continue;
90                    }
91
92                    let mut redundant = false;
93                    for (other_index, other) in all.iter().enumerate() {
94                        if !self.0.contains(other.features)
95                            || !other.features.contains(feature.features)
96                        {
97                            continue;
98                        }
99
100                        // Do not display a feature that another feature in the
101                        // set implicitly enables. Equal sets are aliases or
102                        // tied features; display the first name.
103                        if other.features != feature.features || other_index < index {
104                            redundant = true;
105                            break;
106                        }
107                    }
108
109                    if !redundant {
110                        list.entry(&feature.name);
111                    }
112                }
113
114                list.finish()
115            }
116        }
117
118        f.debug_tuple("TargetFeatures").field(&Basis(self)).finish()
119    }
120}