Skip to main content

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