Skip to content

Commit a218fb6

Browse files
committed
Cranelift: ensure ISA level needed for SIMD is present when SIMD is enabled.
Addresses #3809: when we are asked to create a Cranelift backend with shared flags that indicate support for SIMD, we should check that the ISA level needed for our SIMD lowerings is present.
1 parent db9e3ce commit a218fb6

File tree

8 files changed

+53
-16
lines changed

8 files changed

+53
-16
lines changed

cranelift/codegen/src/isa/aarch64/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ pub fn isa_builder(triple: Triple) -> IsaBuilder {
172172
constructor: |triple, shared_flags, builder| {
173173
let isa_flags = aarch64_settings::Flags::new(&shared_flags, builder);
174174
let backend = AArch64Backend::new_with_flags(triple, shared_flags, isa_flags);
175-
Box::new(backend)
175+
Ok(Box::new(backend))
176176
},
177177
}
178178
}

cranelift/codegen/src/isa/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ impl fmt::Display for LookupError {
139139
pub struct Builder {
140140
triple: Triple,
141141
setup: settings::Builder,
142-
constructor: fn(Triple, settings::Flags, settings::Builder) -> Box<dyn TargetIsa>,
142+
constructor:
143+
fn(Triple, settings::Flags, settings::Builder) -> CodegenResult<Box<dyn TargetIsa>>,
143144
}
144145

145146
impl Builder {
@@ -153,9 +154,13 @@ impl Builder {
153154
self.setup.iter()
154155
}
155156

156-
/// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a
157-
/// fully configured `TargetIsa` trait object.
158-
pub fn finish(self, shared_flags: settings::Flags) -> Box<dyn TargetIsa> {
157+
/// Combine the ISA-specific settings with the provided
158+
/// ISA-independent settings and allocate a fully configured
159+
/// `TargetIsa` trait object. May return an error if some of the
160+
/// flags are inconsistent or incompatible: for example, some
161+
/// platform-independent features, like general SIMD support, may
162+
/// need certain ISA extensions to be enabled.
163+
pub fn finish(self, shared_flags: settings::Flags) -> CodegenResult<Box<dyn TargetIsa>> {
159164
(self.constructor)(self.triple, shared_flags, self.setup)
160165
}
161166
}

cranelift/codegen/src/isa/s390x/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ pub fn isa_builder(triple: Triple) -> IsaBuilder {
179179
constructor: |triple, shared_flags, builder| {
180180
let isa_flags = s390x_settings::Flags::new(&shared_flags, builder);
181181
let backend = S390xBackend::new_with_flags(triple, shared_flags, isa_flags);
182-
Box::new(backend)
182+
Ok(Box::new(backend))
183183
},
184184
}
185185
}

cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ mod tests {
112112
fn test_simple_func() {
113113
let isa = lookup(triple!("x86_64"))
114114
.expect("expect x86 ISA")
115-
.finish(Flags::new(builder()));
115+
.finish(Flags::new(builder()))
116+
.expect("expect backend creation to succeed");
116117

117118
let mut context = Context::for_function(create_function(
118119
CallConv::SystemV,
@@ -154,7 +155,8 @@ mod tests {
154155
fn test_multi_return_func() {
155156
let isa = lookup(triple!("x86_64"))
156157
.expect("expect x86 ISA")
157-
.finish(Flags::new(builder()));
158+
.finish(Flags::new(builder()))
159+
.expect("expect backend creation to succeed");
158160

159161
let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
160162

cranelift/codegen/src/isa/x64/mod.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::isa::Builder as IsaBuilder;
1111
use crate::machinst::{
1212
compile, MachCompileResult, MachTextSectionBuilder, TextSectionBuilder, VCode,
1313
};
14-
use crate::result::CodegenResult;
14+
use crate::result::{CodegenError, CodegenResult};
1515
use crate::settings::{self as shared_settings, Flags};
1616
use alloc::{boxed::Box, vec::Vec};
1717
use core::fmt;
@@ -174,10 +174,21 @@ fn isa_constructor(
174174
triple: Triple,
175175
shared_flags: Flags,
176176
builder: shared_settings::Builder,
177-
) -> Box<dyn TargetIsa> {
177+
) -> CodegenResult<Box<dyn TargetIsa>> {
178178
let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
179+
180+
// Check for compatibility between flags and ISA level
181+
// requested. In particular, SIMD support requires SSE4.1.
182+
if shared_flags.enable_simd() {
183+
if !isa_flags.has_sse3() || !isa_flags.has_ssse3() || !isa_flags.has_sse41() {
184+
return Err(CodegenError::Unsupported(
185+
"SIMD support requires SSE3, SSSE3, and SSE4.1 on x86_64.".into(),
186+
));
187+
}
188+
}
189+
179190
let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
180-
Box::new(backend)
191+
Ok(Box::new(backend))
181192
}
182193

183194
#[cfg(test)]
@@ -332,4 +343,20 @@ mod test {
332343

333344
assert_eq!(code, &golden[..]);
334345
}
346+
347+
// Check that feature tests for SIMD work correctly.
348+
#[test]
349+
fn simd_required_features() {
350+
let mut shared_flags_builder = settings::builder();
351+
shared_flags_builder.set("enable_simd", "true").unwrap();
352+
let shared_flags = settings::Flags::new(shared_flags_builder);
353+
let mut isa_builder = crate::isa::lookup_by_name("x86_64").unwrap();
354+
isa_builder.set("has_sse3", "false").unwrap();
355+
isa_builder.set("has_ssse3", "false").unwrap();
356+
isa_builder.set("has_sse41", "false").unwrap();
357+
assert!(matches!(
358+
isa_builder.finish(shared_flags),
359+
Err(CodegenError::Unsupported(_)),
360+
));
361+
}
335362
}

crates/cranelift/src/builder.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,15 @@ impl CompilerBuilder for Builder {
101101
Ok(())
102102
}
103103

104-
fn build(&self) -> Box<dyn wasmtime_environ::Compiler> {
104+
fn build(&self) -> Result<Box<dyn wasmtime_environ::Compiler>> {
105105
let isa = self
106106
.isa_flags
107107
.clone()
108-
.finish(settings::Flags::new(self.flags.clone()));
109-
Box::new(crate::compiler::Compiler::new(isa, self.linkopts.clone()))
108+
.finish(settings::Flags::new(self.flags.clone()))?;
109+
Ok(Box::new(crate::compiler::Compiler::new(
110+
isa,
111+
self.linkopts.clone(),
112+
)))
110113
}
111114

112115
fn settings(&self) -> Vec<Setting> {

crates/environ/src/compilation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ pub trait CompilerBuilder: Send + Sync + fmt::Debug {
104104
fn settings(&self) -> Vec<Setting>;
105105

106106
/// Builds a new [`Compiler`] object from this configuration.
107-
fn build(&self) -> Box<dyn Compiler>;
107+
fn build(&self) -> Result<Box<dyn Compiler>>;
108108
}
109109

110110
/// Description of compiler settings returned by [`CompilerBuilder::settings`].

crates/wasmtime/src/engine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl Engine {
6464
Ok(Engine {
6565
inner: Arc::new(EngineInner {
6666
#[cfg(compiler)]
67-
compiler: config.compiler.build(),
67+
compiler: config.compiler.build()?,
6868
config,
6969
allocator,
7070
signatures: registry,

0 commit comments

Comments
 (0)