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 FMA,
50 NEON,
52}
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!("fma") {
91 features.insert(Self::FMA);
92 }
93 if std::is_x86_feature_detected!("avx512dq") {
94 features.insert(Self::AVX512DQ);
95 }
96 if std::is_x86_feature_detected!("avx512vl") {
97 features.insert(Self::AVX512VL);
98 }
99 if std::is_x86_feature_detected!("avx512f") {
100 features.insert(Self::AVX512F);
101 }
102 if std::is_x86_feature_detected!("lzcnt") {
103 features.insert(Self::LZCNT);
104 }
105 features
106 }
107
108 #[cfg(target_arch = "aarch64")]
109 pub fn for_host() -> EnumSet<Self> {
111 let mut features = EnumSet::new();
112
113 if std::arch::is_aarch64_feature_detected!("neon") {
114 features.insert(Self::NEON);
115 }
116
117 features
118 }
119
120 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
121 pub fn for_host() -> EnumSet<Self> {
123 EnumSet::new()
125 }
126
127 pub fn set() -> EnumSet<Self> {
129 EnumSet::new()
131 }
132
133 pub fn all() -> EnumSet<Self> {
135 EnumSet::all()
136 }
137}
138
139impl FromStr for CpuFeature {
146 type Err = ParseCpuFeatureError;
147
148 fn from_str(s: &str) -> Result<Self, Self::Err> {
149 match s {
150 "sse2" => Ok(Self::SSE2),
151 "sse3" => Ok(Self::SSE3),
152 "ssse3" => Ok(Self::SSSE3),
153 "sse4.1" => Ok(Self::SSE41),
154 "sse4.2" => Ok(Self::SSE42),
155 "popcnt" => Ok(Self::POPCNT),
156 "avx" => Ok(Self::AVX),
157 "bmi" => Ok(Self::BMI1),
158 "bmi2" => Ok(Self::BMI2),
159 "avx2" => Ok(Self::AVX2),
160 "fma" => Ok(Self::FMA),
161 "avx512dq" => Ok(Self::AVX512DQ),
162 "avx512vl" => Ok(Self::AVX512VL),
163 "avx512f" => Ok(Self::AVX512F),
164 "lzcnt" => Ok(Self::LZCNT),
165 "neon" => Ok(Self::NEON),
166 _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
167 }
168 }
169}
170
171impl std::fmt::Display for CpuFeature {
172 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
173 write!(
174 f,
175 "{}",
176 match self {
177 Self::SSE2 => "sse2",
178 Self::SSE3 => "sse3",
179 Self::SSSE3 => "ssse3",
180 Self::SSE41 => "sse4.1",
181 Self::SSE42 => "sse4.2",
182 Self::POPCNT => "popcnt",
183 Self::AVX => "avx",
184 Self::BMI1 => "bmi",
185 Self::BMI2 => "bmi2",
186 Self::AVX2 => "avx2",
187 Self::FMA => "fma",
188 Self::AVX512DQ => "avx512dq",
189 Self::AVX512VL => "avx512vl",
190 Self::AVX512F => "avx512f",
191 Self::LZCNT => "lzcnt",
192 Self::NEON => "neon",
193 }
194 )
195 }
196}
197
198#[derive(Clone, Debug, PartialEq, Eq, Hash)]
201pub struct Target {
202 triple: Triple,
203 cpu_features: EnumSet<CpuFeature>,
204}
205
206impl Target {
207 pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
209 Self {
210 triple,
211 cpu_features,
212 }
213 }
214
215 pub fn triple(&self) -> &Triple {
217 &self.triple
218 }
219
220 pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
222 &self.cpu_features
223 }
224
225 pub fn is_native(&self) -> bool {
227 let host = Triple::host();
228 host.operating_system == self.triple.operating_system
229 && host.architecture == self.triple.architecture
230 }
231}
232
233impl Default for Target {
235 fn default() -> Self {
236 Self {
237 triple: Triple::host(),
238 cpu_features: CpuFeature::for_host(),
239 }
240 }
241}
242
243#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
248pub struct UserCompilerOptimizations {
249 pub pass_params: Option<bool>,
251}