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 pub fn all() -> EnumSet<Self> {
132 EnumSet::all()
133 }
134}
135
136impl FromStr for CpuFeature {
143 type Err = ParseCpuFeatureError;
144
145 fn from_str(s: &str) -> Result<Self, Self::Err> {
146 match s {
147 "sse2" => Ok(Self::SSE2),
148 "sse3" => Ok(Self::SSE3),
149 "ssse3" => Ok(Self::SSSE3),
150 "sse4.1" => Ok(Self::SSE41),
151 "sse4.2" => Ok(Self::SSE42),
152 "popcnt" => Ok(Self::POPCNT),
153 "avx" => Ok(Self::AVX),
154 "bmi" => Ok(Self::BMI1),
155 "bmi2" => Ok(Self::BMI2),
156 "avx2" => Ok(Self::AVX2),
157 "avx512dq" => Ok(Self::AVX512DQ),
158 "avx512vl" => Ok(Self::AVX512VL),
159 "avx512f" => Ok(Self::AVX512F),
160 "lzcnt" => Ok(Self::LZCNT),
161 "neon" => Ok(Self::NEON),
162 _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
163 }
164 }
165}
166
167impl std::fmt::Display for CpuFeature {
168 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
169 write!(
170 f,
171 "{}",
172 match self {
173 Self::SSE2 => "sse2",
174 Self::SSE3 => "sse3",
175 Self::SSSE3 => "ssse3",
176 Self::SSE41 => "sse4.1",
177 Self::SSE42 => "sse4.2",
178 Self::POPCNT => "popcnt",
179 Self::AVX => "avx",
180 Self::BMI1 => "bmi",
181 Self::BMI2 => "bmi2",
182 Self::AVX2 => "avx2",
183 Self::AVX512DQ => "avx512dq",
184 Self::AVX512VL => "avx512vl",
185 Self::AVX512F => "avx512f",
186 Self::LZCNT => "lzcnt",
187 Self::NEON => "neon",
188 }
189 )
190 }
191}
192
193#[derive(Clone, Debug, PartialEq, Eq, Hash)]
196pub struct Target {
197 triple: Triple,
198 cpu_features: EnumSet<CpuFeature>,
199}
200
201impl Target {
202 pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
204 Self {
205 triple,
206 cpu_features,
207 }
208 }
209
210 pub fn triple(&self) -> &Triple {
212 &self.triple
213 }
214
215 pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
217 &self.cpu_features
218 }
219
220 pub fn is_native(&self) -> bool {
222 let host = Triple::host();
223 host.operating_system == self.triple.operating_system
224 && host.architecture == self.triple.architecture
225 }
226}
227
228impl Default for Target {
230 fn default() -> Self {
231 Self {
232 triple: Triple::host(),
233 cpu_features: CpuFeature::for_host(),
234 }
235 }
236}
237
238#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
243pub struct UserCompilerOptimizations {
244 pub pass_params: Option<bool>,
246}