wasmer_types/compilation/
target.rs

1//! Target configuration
2
3// The clippy::use_self exception is due to a false positive indicating that
4// `CpuFeature` should be replaced by `Self`. Attaching the allowance to the
5// type itself has no effect, therefore it's disabled for the whole module.
6// Feel free to remove this allow attribute once the bug is fixed.
7// See https://github.com/rust-lang/rust-clippy/issues/6902
8// Same things is now happening with unused-unit for the EnumSetType derivative
9#![allow(clippy::unused_unit, clippy::use_self)]
10
11use crate::error::ParseCpuFeatureError;
12use enumset::{EnumSet, EnumSetType};
13use std::str::FromStr;
14use std::string::{String, ToString};
15pub use target_lexicon::{
16    Aarch64Architecture, Architecture, BinaryFormat, CallingConvention, Endianness, Environment,
17    OperatingSystem, PointerWidth, Triple, Vendor,
18};
19
20/// The nomenclature is inspired by the [`cpuid` crate].
21/// The list of supported features was initially retrieved from
22/// [`cranelift-native`].
23///
24/// The `CpuFeature` enum values are likely to grow closer to the
25/// original `cpuid`. However, we prefer to start small and grow from there.
26///
27/// If you would like to use a flag that doesn't exist yet here, please
28/// open a PR.
29///
30/// [`cpuid` crate]: https://docs.rs/cpuid/0.1.1/cpuid/enum.CpuFeature.html
31/// [`cranelift-native`]: https://github.com/bytecodealliance/cranelift/blob/6988545fd20249b084c53f4761b8c861266f5d31/cranelift-native/src/lib.rs#L51-L92
32#[allow(missing_docs, clippy::derived_hash_with_manual_eq)]
33#[derive(EnumSetType, Debug, Hash)]
34pub enum CpuFeature {
35    // X86 features
36    SSE2,
37    SSE3,
38    SSSE3,
39    SSE41,
40    SSE42,
41    POPCNT,
42    AVX,
43    BMI1,
44    BMI2,
45    AVX2,
46    AVX512DQ,
47    AVX512VL,
48    AVX512F,
49    LZCNT,
50    // ARM features
51    NEON,
52    // Risc-V features
53}
54
55impl CpuFeature {
56    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
57    /// Retrieves the features for the current Host
58    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!("avx512dq") {
92            features.insert(Self::AVX512DQ);
93        }
94        if std::is_x86_feature_detected!("avx512vl") {
95            features.insert(Self::AVX512VL);
96        }
97        if std::is_x86_feature_detected!("avx512f") {
98            features.insert(Self::AVX512F);
99        }
100        if std::is_x86_feature_detected!("lzcnt") {
101            features.insert(Self::LZCNT);
102        }
103        features
104    }
105
106    #[cfg(target_arch = "aarch64")]
107    /// Retrieves the features for the current Host
108    pub fn for_host() -> EnumSet<Self> {
109        let mut features = EnumSet::new();
110
111        if std::arch::is_aarch64_feature_detected!("neon") {
112            features.insert(Self::NEON);
113        }
114
115        features
116    }
117
118    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
119    /// Retrieves the features for the current Host
120    pub fn for_host() -> EnumSet<Self> {
121        // We default to an empty hash set
122        EnumSet::new()
123    }
124
125    /// Retrieves an empty set of `CpuFeature`s.
126    pub fn set() -> EnumSet<Self> {
127        // We default to an empty hash set
128        EnumSet::new()
129    }
130}
131
132// This options should map exactly the GCC options indicated
133// here by architectures:
134//
135// X86: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
136// ARM: https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
137// Aarch64: https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
138impl FromStr for CpuFeature {
139    type Err = ParseCpuFeatureError;
140
141    fn from_str(s: &str) -> Result<Self, Self::Err> {
142        match s {
143            "sse2" => Ok(Self::SSE2),
144            "sse3" => Ok(Self::SSE3),
145            "ssse3" => Ok(Self::SSSE3),
146            "sse4.1" => Ok(Self::SSE41),
147            "sse4.2" => Ok(Self::SSE42),
148            "popcnt" => Ok(Self::POPCNT),
149            "avx" => Ok(Self::AVX),
150            "bmi" => Ok(Self::BMI1),
151            "bmi2" => Ok(Self::BMI2),
152            "avx2" => Ok(Self::AVX2),
153            "avx512dq" => Ok(Self::AVX512DQ),
154            "avx512vl" => Ok(Self::AVX512VL),
155            "avx512f" => Ok(Self::AVX512F),
156            "lzcnt" => Ok(Self::LZCNT),
157            "neon" => Ok(Self::NEON),
158            _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
159        }
160    }
161}
162
163impl ToString for CpuFeature {
164    fn to_string(&self) -> String {
165        match self {
166            Self::SSE2 => "sse2",
167            Self::SSE3 => "sse3",
168            Self::SSSE3 => "ssse3",
169            Self::SSE41 => "sse4.1",
170            Self::SSE42 => "sse4.2",
171            Self::POPCNT => "popcnt",
172            Self::AVX => "avx",
173            Self::BMI1 => "bmi",
174            Self::BMI2 => "bmi2",
175            Self::AVX2 => "avx2",
176            Self::AVX512DQ => "avx512dq",
177            Self::AVX512VL => "avx512vl",
178            Self::AVX512F => "avx512f",
179            Self::LZCNT => "lzcnt",
180            Self::NEON => "neon",
181        }
182        .to_string()
183    }
184}
185
186/// This is the target that we will use for compiling
187/// the WebAssembly ModuleInfo, and then run it.
188#[derive(Clone, Debug, PartialEq, Eq, Hash)]
189pub struct Target {
190    triple: Triple,
191    cpu_features: EnumSet<CpuFeature>,
192}
193
194impl Target {
195    /// Creates a new target given a triple
196    pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
197        Self {
198            triple,
199            cpu_features,
200        }
201    }
202
203    /// The triple associated for the target.
204    pub fn triple(&self) -> &Triple {
205        &self.triple
206    }
207
208    /// The triple associated for the target.
209    pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
210        &self.cpu_features
211    }
212
213    /// Check if target is a native (eq to host) or not
214    pub fn is_native(&self) -> bool {
215        let host = Triple::host();
216        host.operating_system == self.triple.operating_system
217            && host.architecture == self.triple.architecture
218    }
219}
220
221/// The default for the Target will use the HOST as the triple
222impl Default for Target {
223    fn default() -> Self {
224        Self {
225            triple: Triple::host(),
226            cpu_features: CpuFeature::for_host(),
227        }
228    }
229}