unc_vm_compiler/
target.rs

1//! Target configuration
2use crate::error::ParseCpuFeatureError;
3use crate::lib::std::str::FromStr;
4use crate::lib::std::string::{String, ToString};
5use enumset::{EnumSet, EnumSetType};
6pub use target_lexicon::{
7    Architecture, BinaryFormat, CallingConvention, Endianness, OperatingSystem, PointerWidth,
8    Triple,
9};
10
11/// The nomenclature is inspired by the [`cpuid` crate].
12/// The list of supported features was initially retrieved from
13/// [`cranelift-native`].
14///
15/// The `CpuFeature` enum values are likely to grow closer to the
16/// original `cpuid`. However, we prefer to start small and grow from there.
17///
18/// If you would like to use a flag that doesn't exist yet here, please
19/// open a PR.
20///
21/// [`cpuid` crate]: https://docs.rs/cpuid/0.1.1/cpuid/enum.CpuFeature.html
22/// [`cranelift-native`]: https://github.com/bytecodealliance/cranelift/blob/6988545fd20249b084c53f4761b8c861266f5d31/cranelift-native/src/lib.rs#L51-L92
23#[allow(missing_docs, clippy::derived_hash_with_manual_eq)]
24#[derive(EnumSetType, Debug, Hash)]
25pub enum CpuFeature {
26    // X86 features
27    SSE2,
28    SSE3,
29    SSSE3,
30    SSE41,
31    SSE42,
32    POPCNT,
33    AVX,
34    BMI1,
35    BMI2,
36    AVX2,
37    AVX512DQ,
38    AVX512VL,
39    AVX512F,
40    LZCNT,
41    // ARM features
42    // Risc-V features
43}
44
45impl CpuFeature {
46    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
47    /// Retrieves the features for the current Host
48    pub fn for_host() -> EnumSet<Self> {
49        let mut features = EnumSet::new();
50
51        if std::is_x86_feature_detected!("sse2") {
52            features.insert(Self::SSE2);
53        }
54        if std::is_x86_feature_detected!("sse3") {
55            features.insert(Self::SSE3);
56        }
57        if std::is_x86_feature_detected!("ssse3") {
58            features.insert(Self::SSSE3);
59        }
60        if std::is_x86_feature_detected!("sse4.1") {
61            features.insert(Self::SSE41);
62        }
63        if std::is_x86_feature_detected!("sse4.2") {
64            features.insert(Self::SSE42);
65        }
66        if std::is_x86_feature_detected!("popcnt") {
67            features.insert(Self::POPCNT);
68        }
69        if std::is_x86_feature_detected!("avx") {
70            features.insert(Self::AVX);
71        }
72        if std::is_x86_feature_detected!("bmi1") {
73            features.insert(Self::BMI1);
74        }
75        if std::is_x86_feature_detected!("bmi2") {
76            features.insert(Self::BMI2);
77        }
78        if std::is_x86_feature_detected!("avx2") {
79            features.insert(Self::AVX2);
80        }
81        if std::is_x86_feature_detected!("avx512dq") {
82            features.insert(Self::AVX512DQ);
83        }
84        if std::is_x86_feature_detected!("avx512vl") {
85            features.insert(Self::AVX512VL);
86        }
87        if std::is_x86_feature_detected!("avx512f") {
88            features.insert(Self::AVX512F);
89        }
90        if std::is_x86_feature_detected!("lzcnt") {
91            features.insert(Self::LZCNT);
92        }
93        features
94    }
95    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
96    /// Retrieves the features for the current Host
97    pub fn for_host() -> EnumSet<Self> {
98        // We default to an empty hash set
99        EnumSet::new()
100    }
101
102    /// Retrieves an empty set of `CpuFeature`s.
103    pub fn set() -> EnumSet<Self> {
104        // We default to an empty hash set
105        EnumSet::new()
106    }
107}
108
109// This options should map exactly the GCC options indicated
110// here by architectures:
111//
112// X86: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
113// ARM: https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
114// Aarch64: https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
115impl FromStr for CpuFeature {
116    type Err = ParseCpuFeatureError;
117
118    fn from_str(s: &str) -> Result<Self, Self::Err> {
119        match s {
120            "sse2" => Ok(Self::SSE2),
121            "sse3" => Ok(Self::SSE3),
122            "ssse3" => Ok(Self::SSSE3),
123            "sse4.1" => Ok(Self::SSE41),
124            "sse4.2" => Ok(Self::SSE42),
125            "popcnt" => Ok(Self::POPCNT),
126            "avx" => Ok(Self::AVX),
127            "bmi" => Ok(Self::BMI1),
128            "bmi2" => Ok(Self::BMI2),
129            "avx2" => Ok(Self::AVX2),
130            "avx512dq" => Ok(Self::AVX512DQ),
131            "avx512vl" => Ok(Self::AVX512VL),
132            "avx512f" => Ok(Self::AVX512F),
133            "lzcnt" => Ok(Self::LZCNT),
134            _ => Err(ParseCpuFeatureError::Missing(s.to_string())),
135        }
136    }
137}
138
139impl ToString for CpuFeature {
140    fn to_string(&self) -> String {
141        match self {
142            Self::SSE2 => "sse2",
143            Self::SSE3 => "sse3",
144            Self::SSSE3 => "ssse3",
145            Self::SSE41 => "sse4.1",
146            Self::SSE42 => "sse4.2",
147            Self::POPCNT => "popcnt",
148            Self::AVX => "avx",
149            Self::BMI1 => "bmi",
150            Self::BMI2 => "bmi2",
151            Self::AVX2 => "avx2",
152            Self::AVX512DQ => "avx512dq",
153            Self::AVX512VL => "avx512vl",
154            Self::AVX512F => "avx512f",
155            Self::LZCNT => "lzcnt",
156        }
157        .to_string()
158    }
159}
160
161/// This is the target that we will use for compiling
162/// the WebAssembly ModuleInfo, and then run it.
163#[derive(Clone, Debug, PartialEq, Eq, Hash)]
164pub struct Target {
165    triple: Triple,
166    cpu_features: EnumSet<CpuFeature>,
167}
168
169impl Target {
170    /// Creates a new target given a triple
171    pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
172        Self { triple, cpu_features }
173    }
174
175    /// The triple associated for the target.
176    pub fn triple(&self) -> &Triple {
177        &self.triple
178    }
179
180    /// The triple associated for the target.
181    pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
182        &self.cpu_features
183    }
184}
185
186/// The default for the Target will use the HOST as the triple
187impl Default for Target {
188    fn default() -> Self {
189        Self { triple: Triple::host(), cpu_features: CpuFeature::for_host() }
190    }
191}