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}