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