1#![allow(clippy::unused_unit, clippy::use_self)]
10
11use crate::error::ParseCpuFeatureError;
12use enumset::{EnumSet, EnumSetType};
13use std::str::FromStr;
14pub use target_lexicon::{
15    Aarch64Architecture, Architecture, BinaryFormat, CallingConvention, Endianness, Environment,
16    OperatingSystem, PointerWidth, Triple, Vendor,
17};
18
19#[allow(missing_docs, clippy::derived_hash_with_manual_eq)]
32#[derive(EnumSetType, Debug, Hash)]
33pub enum CpuFeature {
34    SSE2,
36    SSE3,
37    SSSE3,
38    SSE41,
39    SSE42,
40    POPCNT,
41    AVX,
42    BMI1,
43    BMI2,
44    AVX2,
45    AVX512DQ,
46    AVX512VL,
47    AVX512F,
48    LZCNT,
49    NEON,
51    }
53
54impl CpuFeature {
55    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
56    pub fn for_host() -> EnumSet<Self> {
58        let mut features = EnumSet::new();
59
60        if std::is_x86_feature_detected!("sse2") {
61            features.insert(Self::SSE2);
62        }
63        if std::is_x86_feature_detected!("sse3") {
64            features.insert(Self::SSE3);
65        }
66        if std::is_x86_feature_detected!("ssse3") {
67            features.insert(Self::SSSE3);
68        }
69        if std::is_x86_feature_detected!("sse4.1") {
70            features.insert(Self::SSE41);
71        }
72        if std::is_x86_feature_detected!("sse4.2") {
73            features.insert(Self::SSE42);
74        }
75        if std::is_x86_feature_detected!("popcnt") {
76            features.insert(Self::POPCNT);
77        }
78        if std::is_x86_feature_detected!("avx") {
79            features.insert(Self::AVX);
80        }
81        if std::is_x86_feature_detected!("bmi1") {
82            features.insert(Self::BMI1);
83        }
84        if std::is_x86_feature_detected!("bmi2") {
85            features.insert(Self::BMI2);
86        }
87        if std::is_x86_feature_detected!("avx2") {
88            features.insert(Self::AVX2);
89        }
90        if std::is_x86_feature_detected!("avx512dq") {
91            features.insert(Self::AVX512DQ);
92        }
93        if std::is_x86_feature_detected!("avx512vl") {
94            features.insert(Self::AVX512VL);
95        }
96        if std::is_x86_feature_detected!("avx512f") {
97            features.insert(Self::AVX512F);
98        }
99        if std::is_x86_feature_detected!("lzcnt") {
100            features.insert(Self::LZCNT);
101        }
102        features
103    }
104
105    #[cfg(target_arch = "aarch64")]
106    pub fn for_host() -> EnumSet<Self> {
108        let mut features = EnumSet::new();
109
110        if std::arch::is_aarch64_feature_detected!("neon") {
111            features.insert(Self::NEON);
112        }
113
114        features
115    }
116
117    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
118    pub fn for_host() -> EnumSet<Self> {
120        EnumSet::new()
122    }
123
124    pub fn set() -> EnumSet<Self> {
126        EnumSet::new()
128    }
129}
130
131impl FromStr for CpuFeature {
138    type Err = ParseCpuFeatureError;
139
140    fn from_str(s: &str) -> Result<Self, Self::Err> {
141        match s {
142            "sse2" => Ok(Self::SSE2),
143            "sse3" => Ok(Self::SSE3),
144            "ssse3" => Ok(Self::SSSE3),
145            "sse4.1" => Ok(Self::SSE41),
146            "sse4.2" => Ok(Self::SSE42),
147            "popcnt" => Ok(Self::POPCNT),
148            "avx" => Ok(Self::AVX),
149            "bmi" => Ok(Self::BMI1),
150            "bmi2" => Ok(Self::BMI2),
151            "avx2" => Ok(Self::AVX2),
152            "avx512dq" => Ok(Self::AVX512DQ),
153            "avx512vl" => Ok(Self::AVX512VL),
154            "avx512f" => Ok(Self::AVX512F),
155            "lzcnt" => Ok(Self::LZCNT),
156            "neon" => Ok(Self::NEON),
157            _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
158        }
159    }
160}
161
162impl std::fmt::Display for CpuFeature {
163    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
164        write!(
165            f,
166            "{}",
167            match self {
168                Self::SSE2 => "sse2",
169                Self::SSE3 => "sse3",
170                Self::SSSE3 => "ssse3",
171                Self::SSE41 => "sse4.1",
172                Self::SSE42 => "sse4.2",
173                Self::POPCNT => "popcnt",
174                Self::AVX => "avx",
175                Self::BMI1 => "bmi",
176                Self::BMI2 => "bmi2",
177                Self::AVX2 => "avx2",
178                Self::AVX512DQ => "avx512dq",
179                Self::AVX512VL => "avx512vl",
180                Self::AVX512F => "avx512f",
181                Self::LZCNT => "lzcnt",
182                Self::NEON => "neon",
183            }
184        )
185    }
186}
187
188#[derive(Clone, Debug, PartialEq, Eq, Hash)]
191pub struct Target {
192    triple: Triple,
193    cpu_features: EnumSet<CpuFeature>,
194}
195
196impl Target {
197    pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
199        Self {
200            triple,
201            cpu_features,
202        }
203    }
204
205    pub fn triple(&self) -> &Triple {
207        &self.triple
208    }
209
210    pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
212        &self.cpu_features
213    }
214
215    pub fn is_native(&self) -> bool {
217        let host = Triple::host();
218        host.operating_system == self.triple.operating_system
219            && host.architecture == self.triple.architecture
220    }
221}
222
223impl Default for Target {
225    fn default() -> Self {
226        Self {
227            triple: Triple::host(),
228            cpu_features: CpuFeature::for_host(),
229        }
230    }
231}
232
233#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
238pub struct UserCompilerOptimizations {
239    pub pass_params: Option<bool>,
241}