wasmer_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 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/// 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    // X86 features (TODO: reorganize at some point)
52    FMA,
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!("fma") {
92            features.insert(Self::FMA);
93        }
94        if std::is_x86_feature_detected!("avx512dq") {
95            features.insert(Self::AVX512DQ);
96        }
97        if std::is_x86_feature_detected!("avx512vl") {
98            features.insert(Self::AVX512VL);
99        }
100        if std::is_x86_feature_detected!("avx512f") {
101            features.insert(Self::AVX512F);
102        }
103        if std::is_x86_feature_detected!("lzcnt") {
104            features.insert(Self::LZCNT);
105        }
106        features
107    }
108
109    #[cfg(target_arch = "aarch64")]
110    /// Retrieves the features for the current Host
111    pub fn for_host() -> EnumSet<Self> {
112        let mut features = EnumSet::new();
113
114        if std::arch::is_aarch64_feature_detected!("neon") {
115            features.insert(Self::NEON);
116        }
117
118        features
119    }
120
121    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
122    /// Retrieves the features for the current Host
123    pub fn for_host() -> EnumSet<Self> {
124        // We default to an empty hash set
125        EnumSet::new()
126    }
127
128    /// Retrieves an empty set of `CpuFeature`s.
129    pub fn set() -> EnumSet<Self> {
130        // We default to an empty hash set
131        EnumSet::new()
132    }
133
134    /// Build a set of all available `CpuFeature`s.
135    pub fn all() -> EnumSet<Self> {
136        EnumSet::all()
137    }
138}
139
140// This options should map exactly the GCC options indicated
141// here by architectures:
142//
143// X86: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
144// ARM: https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
145// Aarch64: https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
146impl FromStr for CpuFeature {
147    type Err = ParseCpuFeatureError;
148
149    fn from_str(s: &str) -> Result<Self, Self::Err> {
150        match s {
151            "sse2" => Ok(Self::SSE2),
152            "sse3" => Ok(Self::SSE3),
153            "ssse3" => Ok(Self::SSSE3),
154            "sse4.1" => Ok(Self::SSE41),
155            "sse4.2" => Ok(Self::SSE42),
156            "popcnt" => Ok(Self::POPCNT),
157            "avx" => Ok(Self::AVX),
158            "bmi" => Ok(Self::BMI1),
159            "bmi2" => Ok(Self::BMI2),
160            "avx2" => Ok(Self::AVX2),
161            "fma" => Ok(Self::FMA),
162            "avx512dq" => Ok(Self::AVX512DQ),
163            "avx512vl" => Ok(Self::AVX512VL),
164            "avx512f" => Ok(Self::AVX512F),
165            "lzcnt" => Ok(Self::LZCNT),
166            "neon" => Ok(Self::NEON),
167            _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
168        }
169    }
170}
171
172impl std::fmt::Display for CpuFeature {
173    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174        write!(
175            f,
176            "{}",
177            match self {
178                Self::SSE2 => "sse2",
179                Self::SSE3 => "sse3",
180                Self::SSSE3 => "ssse3",
181                Self::SSE41 => "sse4.1",
182                Self::SSE42 => "sse4.2",
183                Self::POPCNT => "popcnt",
184                Self::AVX => "avx",
185                Self::BMI1 => "bmi",
186                Self::BMI2 => "bmi2",
187                Self::AVX2 => "avx2",
188                Self::FMA => "fma",
189                Self::AVX512DQ => "avx512dq",
190                Self::AVX512VL => "avx512vl",
191                Self::AVX512F => "avx512f",
192                Self::LZCNT => "lzcnt",
193                Self::NEON => "neon",
194            }
195        )
196    }
197}
198
199/// This is the target that we will use for compiling
200/// the WebAssembly ModuleInfo, and then run it.
201#[derive(Clone, Debug, PartialEq, Eq, Hash)]
202pub struct Target {
203    triple: Triple,
204    cpu_features: EnumSet<CpuFeature>,
205}
206
207impl Target {
208    /// Creates a new target given a triple
209    pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
210        Self {
211            triple,
212            cpu_features,
213        }
214    }
215
216    /// The triple associated for the target.
217    pub fn triple(&self) -> &Triple {
218        &self.triple
219    }
220
221    /// The triple associated for the target.
222    pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
223        &self.cpu_features
224    }
225
226    /// Check if target is a native (eq to host) or not
227    pub fn is_native(&self) -> bool {
228        let host = Triple::host();
229        host.operating_system == self.triple.operating_system
230            && host.architecture == self.triple.architecture
231    }
232}
233
234/// The default for the Target will use the HOST as the triple
235impl Default for Target {
236    fn default() -> Self {
237        Self {
238            triple: Triple::host(),
239            cpu_features: CpuFeature::for_host(),
240        }
241    }
242}
243
244/// User-suggested optimization that might be operated on the module when (and if) compiled.
245///
246// Note: This type is a copy of `wasmer_config::package::SuggestedCompilerOptimizations`, so to
247// avoid dependencies on `wasmer_config` for crates that already depend on `wasmer_types`.
248#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
249pub struct UserCompilerOptimizations {
250    /// Suggest the `pass_params` (also known as g0m0) optimization pass.
251    pub pass_params: Option<bool>,
252}