wasmer_compiler/types/
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 enumset::{EnumSet, EnumSetType};
12use std::str::FromStr;
13pub use target_lexicon::{
14    Aarch64Architecture, Architecture, BinaryFormat, CallingConvention, Endianness, Environment,
15    OperatingSystem, PointerWidth, Triple, Vendor,
16};
17use wasmer_types::error::ParseCpuFeatureError;
18
19/// The nomenclature is inspired by the [`cpuid` crate].
20/// The list of supported features was initially retrieved from
21/// [`cranelift-native`].
22///
23/// The `CpuFeature` enum values are likely to grow closer to the
24/// original `cpuid`. However, we prefer to start small and grow from there.
25///
26/// If you would like to use a flag that doesn't exist yet here, please
27/// open a PR.
28///
29/// [`cpuid` crate]: https://docs.rs/cpuid/0.1.1/cpuid/enum.CpuFeature.html
30/// [`cranelift-native`]: https://github.com/bytecodealliance/cranelift/blob/6988545fd20249b084c53f4761b8c861266f5d31/cranelift-native/src/lib.rs#L51-L92
31#[allow(missing_docs, clippy::derived_hash_with_manual_eq)]
32#[derive(EnumSetType, Debug, Hash)]
33pub enum CpuFeature {
34    // X86 features
35    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    // ARM features
50    NEON,
51    // Risc-V features
52}
53
54impl CpuFeature {
55    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
56    /// Retrieves the features for the current Host
57    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    /// Retrieves the features for the current Host
107    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    /// Retrieves the features for the current Host
119    pub fn for_host() -> EnumSet<Self> {
120        // We default to an empty hash set
121        EnumSet::new()
122    }
123
124    /// Retrieves an empty set of `CpuFeature`s.
125    pub fn set() -> EnumSet<Self> {
126        // We default to an empty hash set
127        EnumSet::new()
128    }
129}
130
131// This options should map exactly the GCC options indicated
132// here by architectures:
133//
134// X86: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
135// ARM: https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
136// Aarch64: https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
137impl 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/// This is the target that we will use for compiling
189/// the WebAssembly ModuleInfo, and then run it.
190#[derive(Clone, Debug, PartialEq, Eq, Hash)]
191pub struct Target {
192    triple: Triple,
193    cpu_features: EnumSet<CpuFeature>,
194}
195
196impl Target {
197    /// Creates a new target given a triple
198    pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
199        Self {
200            triple,
201            cpu_features,
202        }
203    }
204
205    /// The triple associated for the target.
206    pub fn triple(&self) -> &Triple {
207        &self.triple
208    }
209
210    /// The triple associated for the target.
211    pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
212        &self.cpu_features
213    }
214
215    /// Check if target is a native (eq to host) or not
216    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
223/// The default for the Target will use the HOST as the triple
224impl Default for Target {
225    fn default() -> Self {
226        Self {
227            triple: Triple::host(),
228            cpu_features: CpuFeature::for_host(),
229        }
230    }
231}