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 FMA,
53}
54
55impl CpuFeature {
56 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
57 pub fn for_host() -> EnumSet<Self> {
59 let mut features = EnumSet::new();
60
61 if std::is_x86_feature_detected!("sse2") {
62 features.insert(Self::SSE2);
63 }
64 if std::is_x86_feature_detected!("sse3") {
65 features.insert(Self::SSE3);
66 }
67 if std::is_x86_feature_detected!("ssse3") {
68 features.insert(Self::SSSE3);
69 }
70 if std::is_x86_feature_detected!("sse4.1") {
71 features.insert(Self::SSE41);
72 }
73 if std::is_x86_feature_detected!("sse4.2") {
74 features.insert(Self::SSE42);
75 }
76 if std::is_x86_feature_detected!("popcnt") {
77 features.insert(Self::POPCNT);
78 }
79 if std::is_x86_feature_detected!("avx") {
80 features.insert(Self::AVX);
81 }
82 if std::is_x86_feature_detected!("bmi1") {
83 features.insert(Self::BMI1);
84 }
85 if std::is_x86_feature_detected!("bmi2") {
86 features.insert(Self::BMI2);
87 }
88 if std::is_x86_feature_detected!("avx2") {
89 features.insert(Self::AVX2);
90 }
91 if std::is_x86_feature_detected!("fma") {
92 features.insert(Self::FMA);
93 }
94 if std::is_x86_feature_detected!("avx512dq") {
95 features.insert(Self::AVX512DQ);
96 }
97 if std::is_x86_feature_detected!("avx512vl") {
98 features.insert(Self::AVX512VL);
99 }
100 if std::is_x86_feature_detected!("avx512f") {
101 features.insert(Self::AVX512F);
102 }
103 if std::is_x86_feature_detected!("lzcnt") {
104 features.insert(Self::LZCNT);
105 }
106 features
107 }
108
109 #[cfg(target_arch = "aarch64")]
110 pub fn for_host() -> EnumSet<Self> {
112 let mut features = EnumSet::new();
113
114 if std::arch::is_aarch64_feature_detected!("neon") {
115 features.insert(Self::NEON);
116 }
117
118 features
119 }
120
121 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
122 pub fn for_host() -> EnumSet<Self> {
124 EnumSet::new()
126 }
127
128 pub fn set() -> EnumSet<Self> {
130 EnumSet::new()
132 }
133
134 pub fn all() -> EnumSet<Self> {
136 EnumSet::all()
137 }
138}
139
140impl FromStr for CpuFeature {
147 type Err = ParseCpuFeatureError;
148
149 fn from_str(s: &str) -> Result<Self, Self::Err> {
150 match s {
151 "sse2" => Ok(Self::SSE2),
152 "sse3" => Ok(Self::SSE3),
153 "ssse3" => Ok(Self::SSSE3),
154 "sse4.1" => Ok(Self::SSE41),
155 "sse4.2" => Ok(Self::SSE42),
156 "popcnt" => Ok(Self::POPCNT),
157 "avx" => Ok(Self::AVX),
158 "bmi" => Ok(Self::BMI1),
159 "bmi2" => Ok(Self::BMI2),
160 "avx2" => Ok(Self::AVX2),
161 "fma" => Ok(Self::FMA),
162 "avx512dq" => Ok(Self::AVX512DQ),
163 "avx512vl" => Ok(Self::AVX512VL),
164 "avx512f" => Ok(Self::AVX512F),
165 "lzcnt" => Ok(Self::LZCNT),
166 "neon" => Ok(Self::NEON),
167 _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
168 }
169 }
170}
171
172impl std::fmt::Display for CpuFeature {
173 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174 write!(
175 f,
176 "{}",
177 match self {
178 Self::SSE2 => "sse2",
179 Self::SSE3 => "sse3",
180 Self::SSSE3 => "ssse3",
181 Self::SSE41 => "sse4.1",
182 Self::SSE42 => "sse4.2",
183 Self::POPCNT => "popcnt",
184 Self::AVX => "avx",
185 Self::BMI1 => "bmi",
186 Self::BMI2 => "bmi2",
187 Self::AVX2 => "avx2",
188 Self::FMA => "fma",
189 Self::AVX512DQ => "avx512dq",
190 Self::AVX512VL => "avx512vl",
191 Self::AVX512F => "avx512f",
192 Self::LZCNT => "lzcnt",
193 Self::NEON => "neon",
194 }
195 )
196 }
197}
198
199#[derive(Clone, Debug, PartialEq, Eq, Hash)]
202pub struct Target {
203 triple: Triple,
204 cpu_features: EnumSet<CpuFeature>,
205}
206
207impl Target {
208 pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
210 Self {
211 triple,
212 cpu_features,
213 }
214 }
215
216 pub fn triple(&self) -> &Triple {
218 &self.triple
219 }
220
221 pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
223 &self.cpu_features
224 }
225
226 pub fn is_native(&self) -> bool {
228 let host = Triple::host();
229 host.operating_system == self.triple.operating_system
230 && host.architecture == self.triple.architecture
231 }
232}
233
234impl Default for Target {
236 fn default() -> Self {
237 Self {
238 triple: Triple::host(),
239 cpu_features: CpuFeature::for_host(),
240 }
241 }
242}
243
244#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
249pub struct UserCompilerOptimizations {
250 pub pass_params: Option<bool>,
252}