diff --git a/cranelift/codegen/meta/src/gen_settings.rs b/cranelift/codegen/meta/src/gen_settings.rs index 2ed5941b80..a70ddccfe1 100644 --- a/cranelift/codegen/meta/src/gen_settings.rs +++ b/cranelift/codegen/meta/src/gen_settings.rs @@ -418,7 +418,7 @@ fn gen_display(group: &SettingGroup, fmt: &mut Formatter) { fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) { // Generate struct. - fmtln!(fmt, "#[derive(Clone)]"); + fmtln!(fmt, "#[derive(Clone, Hash)]"); fmt.doc_comment(format!("Flags group `{}`.", group.name)); fmtln!(fmt, "pub struct Flags {"); fmt.indent(|fmt| { diff --git a/cranelift/codegen/src/isa/aarch64/mod.rs b/cranelift/codegen/src/isa/aarch64/mod.rs index 11eb0a6ea6..af13cb70c0 100644 --- a/cranelift/codegen/src/isa/aarch64/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/mod.rs @@ -8,6 +8,7 @@ use crate::result::CodegenResult; use crate::settings; use alloc::boxed::Box; +use core::hash::{Hash, Hasher}; use regalloc::{PrettyPrint, RealRegUniverse}; use target_lexicon::{Aarch64Architecture, Architecture, Triple}; @@ -95,6 +96,10 @@ impl MachBackend for AArch64Backend { &self.flags } + fn hash_all_flags(&self, mut hasher: &mut dyn Hasher) { + self.flags.hash(&mut hasher); + } + fn reg_universe(&self) -> &RealRegUniverse { &self.reg_universe } diff --git a/cranelift/codegen/src/isa/arm32/mod.rs b/cranelift/codegen/src/isa/arm32/mod.rs index 6ab0f9c57c..3976d74ba6 100644 --- a/cranelift/codegen/src/isa/arm32/mod.rs +++ b/cranelift/codegen/src/isa/arm32/mod.rs @@ -8,6 +8,7 @@ use crate::result::CodegenResult; use crate::settings; use alloc::boxed::Box; +use core::hash::{Hash, Hasher}; use regalloc::{PrettyPrint, RealRegUniverse}; use target_lexicon::{Architecture, ArmArchitecture, Triple}; @@ -90,6 +91,10 @@ impl MachBackend for Arm32Backend { &self.flags } + fn hash_all_flags(&self, mut hasher: &mut dyn Hasher) { + self.flags.hash(&mut hasher); + } + fn reg_universe(&self) -> &RealRegUniverse { &self.reg_universe } diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs index 73a83dda34..bfc4e0d0d0 100644 --- a/cranelift/codegen/src/isa/mod.rs +++ b/cranelift/codegen/src/isa/mod.rs @@ -69,6 +69,7 @@ use alloc::boxed::Box; use core::any::Any; use core::fmt; use core::fmt::{Debug, Formatter}; +use core::hash::Hasher; use target_lexicon::{triple, Architecture, PointerWidth, Triple}; use thiserror::Error; @@ -265,6 +266,10 @@ pub trait TargetIsa: fmt::Display + Send + Sync { /// Get the ISA-independent flags that were used to make this trait object. fn flags(&self) -> &settings::Flags; + /// Hashes all flags, both ISA-independent and ISA-specific, into the + /// specified hasher. + fn hash_all_flags(&self, hasher: &mut dyn Hasher); + /// Get the default calling convention of this target. fn default_call_conv(&self) -> CallConv { CallConv::triple_default(self.triple()) diff --git a/cranelift/codegen/src/isa/riscv/mod.rs b/cranelift/codegen/src/isa/riscv/mod.rs index e69a3a0e12..500451c72e 100644 --- a/cranelift/codegen/src/isa/riscv/mod.rs +++ b/cranelift/codegen/src/isa/riscv/mod.rs @@ -19,6 +19,7 @@ use alloc::borrow::Cow; use alloc::boxed::Box; use core::any::Any; use core::fmt; +use core::hash::{Hash, Hasher}; use target_lexicon::{PointerWidth, Triple}; #[allow(dead_code)] @@ -69,6 +70,11 @@ impl TargetIsa for Isa { &self.shared_flags } + fn hash_all_flags(&self, mut hasher: &mut dyn Hasher) { + self.shared_flags.hash(&mut hasher); + self.isa_flags.hash(&mut hasher); + } + fn register_info(&self) -> RegInfo { registers::INFO.clone() } diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index ca809e2d55..28cd503615 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -11,6 +11,7 @@ use crate::machinst::{compile, MachBackend, MachCompileResult, TargetIsaAdapter, use crate::result::CodegenResult; use crate::settings::{self as shared_settings, Flags}; use alloc::boxed::Box; +use core::hash::{Hash, Hasher}; use regalloc::{PrettyPrint, RealRegUniverse, Reg}; use target_lexicon::Triple; @@ -82,6 +83,11 @@ impl MachBackend for X64Backend { &self.flags } + fn hash_all_flags(&self, mut hasher: &mut dyn Hasher) { + self.flags.hash(&mut hasher); + self.x64_flags.hash(&mut hasher); + } + fn name(&self) -> &'static str { "x64" } diff --git a/cranelift/codegen/src/isa/x86/mod.rs b/cranelift/codegen/src/isa/x86/mod.rs index cbdeb3069d..272c3dfe5d 100644 --- a/cranelift/codegen/src/isa/x86/mod.rs +++ b/cranelift/codegen/src/isa/x86/mod.rs @@ -25,6 +25,7 @@ use alloc::borrow::Cow; use alloc::boxed::Box; use core::any::Any; use core::fmt; +use core::hash::{Hash, Hasher}; use target_lexicon::{PointerWidth, Triple}; #[allow(dead_code)] @@ -78,6 +79,11 @@ impl TargetIsa for Isa { &self.shared_flags } + fn hash_all_flags(&self, mut hasher: &mut dyn Hasher) { + self.shared_flags.hash(&mut hasher); + self.isa_flags.hash(&mut hasher); + } + fn uses_cpu_flags(&self) -> bool { true } diff --git a/cranelift/codegen/src/machinst/adapter.rs b/cranelift/codegen/src/machinst/adapter.rs index 4b3be0f3c0..eb4760fae5 100644 --- a/cranelift/codegen/src/machinst/adapter.rs +++ b/cranelift/codegen/src/machinst/adapter.rs @@ -14,6 +14,7 @@ use crate::regalloc::RegDiversions; use crate::isa::unwind::systemv::RegisterMappingError; use core::any::Any; +use core::hash::Hasher; use std::borrow::Cow; use std::fmt; use target_lexicon::Triple; @@ -58,6 +59,10 @@ impl TargetIsa for TargetIsaAdapter { self.backend.flags() } + fn hash_all_flags(&self, hasher: &mut dyn Hasher) { + self.backend.hash_all_flags(hasher) + } + fn register_info(&self) -> RegInfo { // Called from function's Display impl, so we need a stub here. RegInfo { diff --git a/cranelift/codegen/src/machinst/mod.rs b/cranelift/codegen/src/machinst/mod.rs index 7ed2661dda..297d531955 100644 --- a/cranelift/codegen/src/machinst/mod.rs +++ b/cranelift/codegen/src/machinst/mod.rs @@ -76,6 +76,7 @@ use regalloc::{ RealReg, RealRegUniverse, Reg, RegClass, RegUsageMapper, SpillSlot, VirtualReg, Writable, }; use smallvec::{smallvec, SmallVec}; +use std::hash::Hasher; use std::string::String; use target_lexicon::Triple; @@ -373,6 +374,10 @@ pub trait MachBackend { /// Return flags for this backend. fn flags(&self) -> &Flags; + /// Hashes all flags, both ISA-independent and ISA-specific, into the + /// specified hasher. + fn hash_all_flags(&self, hasher: &mut dyn Hasher); + /// Return triple for this backend. fn triple(&self) -> Triple; diff --git a/cranelift/codegen/src/settings.rs b/cranelift/codegen/src/settings.rs index 6f25b134af..a1bc954c54 100644 --- a/cranelift/codegen/src/settings.rs +++ b/cranelift/codegen/src/settings.rs @@ -188,7 +188,7 @@ pub type SetResult = Result; /// The settings objects themselves are generated and appear in the `isa/*/settings.rs` modules. /// Each settings object provides a `predicate_view()` method that makes it possible to query /// ISA predicates by number. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Hash)] pub struct PredicateView<'a>(&'a [u8]); impl<'a> PredicateView<'a> { diff --git a/cranelift/native/src/lib.rs b/cranelift/native/src/lib.rs index 3bd5716dac..8dffd8ff79 100644 --- a/cranelift/native/src/lib.rs +++ b/cranelift/native/src/lib.rs @@ -34,7 +34,7 @@ use raw_cpuid::CpuId; /// machine, or `Err(())` if the host machine is not supported /// in the current configuration. pub fn builder() -> Result { - builder_with_backend_variant(isa::BackendVariant::Any) + builder_with_options(isa::BackendVariant::Any, true) } /// Return an `isa` builder configured for the current host @@ -44,8 +44,9 @@ pub fn builder() -> Result { /// Selects the given backend variant specifically; this is /// useful when more than oen backend exists for a given target /// (e.g., on x86-64). -pub fn builder_with_backend_variant( +pub fn builder_with_options( variant: isa::BackendVariant, + infer_native_flags: bool, ) -> Result { let mut isa_builder = isa::lookup_variant(Triple::host(), variant).map_err(|err| match err { @@ -55,7 +56,7 @@ pub fn builder_with_backend_variant( isa::LookupError::Unsupported => "unsupported architecture", })?; - if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + if infer_native_flags && cfg!(any(target_arch = "x86", target_arch = "x86_64")) { parse_x86_cpuid(&mut isa_builder)?; } diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 5adb0e8312..fe94c27c02 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -182,14 +182,10 @@ impl Hash for Compiler { // misc tunables. strategy.hash(hasher); isa.triple().hash(hasher); - features.hash(hasher); - // TODO: if this `to_string()` is too expensive then we should upstream - // a native hashing ability of flags into cranelift itself, but - // compilation and/or cache loading is relatively expensive so seems - // unlikely. - isa.flags().to_string().hash(hasher); + isa.hash_all_flags(hasher); isa.frontend_config().hash(hasher); tunables.hash(hasher); + features.hash(hasher); // Catch accidental bugs of reusing across crate versions. env!("CARGO_PKG_VERSION").hash(hasher); diff --git a/crates/jit/src/native.rs b/crates/jit/src/native.rs index 9d1fdd7b66..afcf83d3cc 100644 --- a/crates/jit/src/native.rs +++ b/crates/jit/src/native.rs @@ -6,6 +6,11 @@ pub fn builder() -> cranelift_codegen::isa::Builder { cranelift_native::builder().expect("host machine is not a supported target") } +pub fn builder_without_flags() -> cranelift_codegen::isa::Builder { + cranelift_native::builder_with_options(cranelift_codegen::isa::BackendVariant::Any, false) + .expect("host machine is not a supported target") +} + pub fn call_conv() -> cranelift_codegen::isa::CallConv { use target_lexicon::HOST; cranelift_codegen::isa::CallConv::triple_default(&HOST) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index e6e3f68952..80b10548ed 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -385,6 +385,20 @@ impl Config { self } + /// Clears native CPU flags inferred from the host. + /// + /// By default Wasmtime will tune generated code for the host that Wasmtime + /// itself is running on. If you're compiling on one host, however, and + /// shipping artifacts to another host then this behavior may not be + /// desired. This function will clear all inferred native CPU features. + /// + /// To enable CPU features afterwards it's recommended to use the + /// [`Config::cranelift_other_flag`] method. + pub fn cranelift_clear_cpu_flags(&mut self) -> &mut Self { + self.isa_flags = native::builder_without_flags(); + self + } + /// Allows settings another Cranelift flag defined by a flag name and value. This allows /// fine-tuning of Cranelift settings. /// diff --git a/tests/all/main.rs b/tests/all/main.rs index 414708144f..1f6cb80459 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -12,6 +12,7 @@ mod instance; mod invoke_func_via_table; mod linker; mod memory_creator; +mod module; mod module_linking; mod module_serialize; mod name; diff --git a/tests/all/module.rs b/tests/all/module.rs new file mode 100644 index 0000000000..64384e0de6 --- /dev/null +++ b/tests/all/module.rs @@ -0,0 +1,54 @@ +use wasmtime::*; + +#[test] +fn caches_across_engines() { + let mut c = Config::new(); + c.cranelift_clear_cpu_flags(); + + let bytes = Module::new(&Engine::new(&c), "(module)") + .unwrap() + .serialize() + .unwrap(); + + let res = Module::deserialize( + &Engine::new(&Config::new().cranelift_clear_cpu_flags()), + &bytes, + ); + assert!(res.is_ok()); + + // differ in shared cranelift flags + let res = Module::deserialize( + &Engine::new( + &Config::new() + .cranelift_clear_cpu_flags() + .cranelift_nan_canonicalization(true), + ), + &bytes, + ); + assert!(res.is_err()); + + // differ in cranelift settings + let res = Module::deserialize( + &Engine::new( + &Config::new() + .cranelift_clear_cpu_flags() + .cranelift_opt_level(OptLevel::None), + ), + &bytes, + ); + assert!(res.is_err()); + + // differ in cpu-specific flags + if cfg!(target_arch = "x86_64") { + let res = Module::deserialize( + &Engine::new(unsafe { + &Config::new() + .cranelift_clear_cpu_flags() + .cranelift_other_flag("has_sse3", "true") + .unwrap() + }), + &bytes, + ); + assert!(res.is_err()); + } +}