Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/native/src/lib.rs
1692 views
1
//! Performs autodetection of the host for the purposes of running
2
//! Cranelift to generate code to run on the same machine.
3
4
#![deny(missing_docs)]
5
6
use cranelift_codegen::isa;
7
use cranelift_codegen::settings::Configurable;
8
use target_lexicon::Triple;
9
10
#[cfg(all(target_arch = "riscv64", target_os = "linux"))]
11
mod riscv;
12
13
/// Return an `isa` builder configured for the current host
14
/// machine, or `Err(())` if the host machine is not supported
15
/// in the current configuration.
16
pub fn builder() -> Result<isa::Builder, &'static str> {
17
builder_with_options(true)
18
}
19
20
/// Return an `isa` builder configured for the current host
21
/// machine, or `Err(())` if the host machine is not supported
22
/// in the current configuration.
23
///
24
/// Selects the given backend variant specifically; this is
25
/// useful when more than one backend exists for a given target
26
/// (e.g., on x86-64).
27
pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> {
28
let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err {
29
isa::LookupError::SupportDisabled => "support for architecture disabled at compile time",
30
isa::LookupError::Unsupported => "unsupported architecture",
31
})?;
32
if infer_native_flags {
33
self::infer_native_flags(&mut isa_builder)?;
34
}
35
Ok(isa_builder)
36
}
37
38
/// Return an `isa` builder configured for the current host
39
/// machine, or `Err(())` if the host machine is not supported
40
/// in the current configuration.
41
///
42
/// Selects the given backend variant specifically; this is
43
/// useful when more than one backend exists for a given target
44
/// (e.g., on x86-64).
45
pub fn infer_native_flags(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> {
46
#[cfg(target_arch = "x86_64")]
47
{
48
if !std::is_x86_feature_detected!("sse2") {
49
return Err("x86 support requires SSE2");
50
}
51
52
if std::is_x86_feature_detected!("cmpxchg16b") {
53
isa_builder.enable("has_cmpxchg16b").unwrap();
54
}
55
if std::is_x86_feature_detected!("sse3") {
56
isa_builder.enable("has_sse3").unwrap();
57
}
58
if std::is_x86_feature_detected!("ssse3") {
59
isa_builder.enable("has_ssse3").unwrap();
60
}
61
if std::is_x86_feature_detected!("sse4.1") {
62
isa_builder.enable("has_sse41").unwrap();
63
}
64
if std::is_x86_feature_detected!("sse4.2") {
65
isa_builder.enable("has_sse42").unwrap();
66
}
67
if std::is_x86_feature_detected!("popcnt") {
68
isa_builder.enable("has_popcnt").unwrap();
69
}
70
if std::is_x86_feature_detected!("avx") {
71
isa_builder.enable("has_avx").unwrap();
72
}
73
if std::is_x86_feature_detected!("avx2") {
74
isa_builder.enable("has_avx2").unwrap();
75
}
76
if std::is_x86_feature_detected!("fma") {
77
isa_builder.enable("has_fma").unwrap();
78
}
79
if std::is_x86_feature_detected!("bmi1") {
80
isa_builder.enable("has_bmi1").unwrap();
81
}
82
if std::is_x86_feature_detected!("bmi2") {
83
isa_builder.enable("has_bmi2").unwrap();
84
}
85
if std::is_x86_feature_detected!("avx512bitalg") {
86
isa_builder.enable("has_avx512bitalg").unwrap();
87
}
88
if std::is_x86_feature_detected!("avx512dq") {
89
isa_builder.enable("has_avx512dq").unwrap();
90
}
91
if std::is_x86_feature_detected!("avx512f") {
92
isa_builder.enable("has_avx512f").unwrap();
93
}
94
if std::is_x86_feature_detected!("avx512vl") {
95
isa_builder.enable("has_avx512vl").unwrap();
96
}
97
if std::is_x86_feature_detected!("avx512vbmi") {
98
isa_builder.enable("has_avx512vbmi").unwrap();
99
}
100
if std::is_x86_feature_detected!("lzcnt") {
101
isa_builder.enable("has_lzcnt").unwrap();
102
}
103
}
104
105
#[cfg(target_arch = "aarch64")]
106
{
107
if std::arch::is_aarch64_feature_detected!("lse") {
108
isa_builder.enable("has_lse").unwrap();
109
}
110
111
if std::arch::is_aarch64_feature_detected!("paca") {
112
isa_builder.enable("has_pauth").unwrap();
113
}
114
115
if std::arch::is_aarch64_feature_detected!("fp16") {
116
isa_builder.enable("has_fp16").unwrap();
117
}
118
119
if cfg!(target_os = "macos") {
120
// Pointer authentication is always available on Apple Silicon.
121
isa_builder.enable("sign_return_address").unwrap();
122
// macOS enforces the use of the B key for return addresses.
123
isa_builder.enable("sign_return_address_with_bkey").unwrap();
124
}
125
}
126
127
// `is_s390x_feature_detected` is nightly only for now, so use the
128
// STORE FACILITY LIST EXTENDED instruction as a temporary measure.
129
#[cfg(target_arch = "s390x")]
130
{
131
let mut facility_list: [u64; 4] = [0; 4];
132
unsafe {
133
core::arch::asm!(
134
"stfle 0({})",
135
in(reg_addr) facility_list.as_mut_ptr() ,
136
inout("r0") facility_list.len() as u64 - 1 => _,
137
options(nostack)
138
);
139
}
140
let get_facility_bit = |n: usize| {
141
// NOTE: bits are numbered from the left.
142
facility_list[n / 64] & (1 << (63 - (n % 64))) != 0
143
};
144
145
if get_facility_bit(61) {
146
isa_builder.enable("has_mie3").unwrap();
147
}
148
if get_facility_bit(84) {
149
isa_builder.enable("has_mie4").unwrap();
150
}
151
if get_facility_bit(148) {
152
isa_builder.enable("has_vxrs_ext2").unwrap();
153
}
154
if get_facility_bit(198) {
155
isa_builder.enable("has_vxrs_ext3").unwrap();
156
}
157
}
158
159
// `is_riscv_feature_detected` is nightly only for now, use
160
// getauxval from the libc crate directly as a temporary measure.
161
#[cfg(all(target_arch = "riscv64", target_os = "linux"))]
162
{
163
// Try both hwcap and cpuinfo
164
// HWCAP only returns single letter extensions, cpuinfo returns all of
165
// them but may not be available in some systems (QEMU < 8.1).
166
riscv::hwcap_detect(isa_builder)?;
167
168
// Ignore errors for cpuinfo. QEMU versions prior to 8.1 do not emulate
169
// the cpuinfo interface, so we can't rely on it being present for now.
170
let _ = riscv::cpuinfo_detect(isa_builder);
171
}
172
173
// On all other architectures (e.g. wasm32) we won't infer any native flags,
174
// but still need to use the `isa_builder` to avoid compiler warnings.
175
let _ = isa_builder;
176
Ok(())
177
}
178
179
/// Version number of this crate.
180
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
181
182
#[cfg(test)]
183
mod tests {
184
use super::builder;
185
use cranelift_codegen::isa::CallConv;
186
use cranelift_codegen::settings;
187
188
#[test]
189
fn test() {
190
if let Ok(isa_builder) = builder() {
191
let flag_builder = settings::builder();
192
let isa = isa_builder
193
.finish(settings::Flags::new(flag_builder))
194
.unwrap();
195
196
if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
197
assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
198
} else if cfg!(unix) {
199
assert_eq!(isa.default_call_conv(), CallConv::SystemV);
200
} else if cfg!(windows) {
201
assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
202
}
203
204
if cfg!(target_pointer_width = "64") {
205
assert_eq!(isa.pointer_bits(), 64);
206
} else if cfg!(target_pointer_width = "32") {
207
assert_eq!(isa.pointer_bits(), 32);
208
} else if cfg!(target_pointer_width = "16") {
209
assert_eq!(isa.pointer_bits(), 16);
210
}
211
}
212
}
213
}
214
215