Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const DEFAULT_WASM_MULTI_VALUE: bool = true;
const DEFAULT_WASM_MULTI_MEMORY: bool = true;
const DEFAULT_WASM_BULK_MEMORY: bool = true;
const DEFAULT_WASM_SIMD: bool = true;
const DEFAULT_WASM_RELAXED_SIMD: bool = false;
const DEFAULT_WASM_REFERENCE_TYPES: bool = true;

/// The type of data that is stored in the `wasmtime::Store` during
Expand Down Expand Up @@ -140,6 +141,18 @@ pub struct Wizer {
#[cfg_attr(feature = "structopt", structopt(long = "allow-wasi"))]
allow_wasi: bool,

/// Use deterministic behavior for relaxed SIMD instructions.
///
/// The relaxed SIMD instructions in Wasm are instructions which are
/// permitted to have different results when run on different host
/// CPU architectures. This flag tells wizer to instead execute relaxed
/// SIMD instructions according to the [deterministic profile], which
/// ensures that they're deterministic and platform-independent.
///
/// [deterministic profile]: https://webassembly.github.io/spec/core/appendix/profiles.html#deterministic-profile-small-mathrm-det
#[cfg_attr(feature = "structopt", structopt(long = "relaxed-simd-deterministic"))]
relaxed_simd_deterministic: bool,
Comment on lines +144 to +154
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are enabling relaxed SIMD, would we ever want to disable the deterministic implementation? That is, does having this additional option on top of just wasm_relaxed_simd make sense?

Copy link
Member Author

@sunfishcode sunfishcode Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I interpreted your comment above to be asking for this to be a separate option. But I can also imagine a use case: if you're running wizer on the same architecture as the resulting wasm, and the resulting wasm will run with nondeterministic lowerings, then you presumably want the nondeterministic lowerings in wizer too, so that they match.

Copy link
Member

@fitzgen fitzgen Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I meant that we should have a knob for the relaxed-simd proposal, and it should be off by default, rather than simply always enabling the proposal. I had further assumed that we would always be enabling the deterministic mode in Wasmtime when the relaxed-simd proposal was enabled. But yeah I guess it can make sense to disable the deterministic mode if you know that you will run on the same underlying ISA during init and also post-init.


/// Provide an additional preloaded module that is available to the
/// main module.
///
Expand Down Expand Up @@ -252,6 +265,14 @@ pub struct Wizer {
#[cfg_attr(feature = "structopt", structopt(long, value_name = "true|false"))]
wasm_simd: Option<bool>,

/// Enable or disable the Wasm relaxed SIMD proposal.
///
/// Disabled by default. When enabled, by default relaxed SIMD instructions
/// will produce different results on different platforms. For deterministic
/// results, additionally enable the `--relaxed-simd-deterministic` flag.
#[cfg_attr(feature = "structopt", structopt(long, value_name = "true|false"))]
wasm_relaxed_simd: Option<bool>,

/// Enable or disable the Wasm reference-types proposal.
///
/// Currently does not implement snapshotting or the use of references,
Expand All @@ -269,6 +290,7 @@ impl std::fmt::Debug for Wizer {
init_func,
func_renames,
allow_wasi,
relaxed_simd_deterministic,
preload,
preload_bytes,
make_linker: _,
Expand All @@ -281,12 +303,14 @@ impl std::fmt::Debug for Wizer {
wasm_multi_value,
wasm_bulk_memory,
wasm_simd,
wasm_relaxed_simd,
wasm_reference_types,
} = self;
f.debug_struct("Wizer")
.field("init_func", &init_func)
.field("func_renames", &func_renames)
.field("allow_wasi", &allow_wasi)
.field("relaxed_simd_deterministic", &relaxed_simd_deterministic)
.field("preload", &preload)
.field("preload_bytes", &preload_bytes)
.field("make_linker", &"..")
Expand All @@ -299,6 +323,7 @@ impl std::fmt::Debug for Wizer {
.field("wasm_multi_value", &wasm_multi_value)
.field("wasm_bulk_memory", &wasm_bulk_memory)
.field("wasm_simd", &wasm_simd)
.field("wasm_relaxed_simd", &wasm_relaxed_simd)
.field("wasm_reference_types", &wasm_reference_types)
.finish()
}
Expand Down Expand Up @@ -352,6 +377,7 @@ impl Wizer {
init_func: "wizer.initialize".into(),
func_renames: vec![],
allow_wasi: false,
relaxed_simd_deterministic: false,
preload: vec![],
preload_bytes: vec![],
make_linker: None,
Expand All @@ -364,6 +390,7 @@ impl Wizer {
wasm_multi_value: None,
wasm_bulk_memory: None,
wasm_simd: None,
wasm_relaxed_simd: None,
wasm_reference_types: None,
}
}
Expand Down Expand Up @@ -405,6 +432,19 @@ impl Wizer {
Ok(self)
}

/// Use deterministic behavior for relaxed SIMD instructions.
///
/// The relaxed SIMD instructions in Wasm are instructions which are
/// permitted to have different results when run on different host
/// CPU architectures. This flag tells wizer to instead execute relaxed
/// SIMD instructions according to the [deterministic profile], which
/// ensures that they're deterministic and platform-independent.
///
/// [deterministic profile]: https://webassembly.github.io/spec/core/appendix/profiles.html#deterministic-profile-small-mathrm-det
pub fn relaxed_simd_deterministic(&mut self, deterministic: bool) {
self.relaxed_simd_deterministic = deterministic;
}

/// Provide an additional preloaded module that is available to the
/// main module.
///
Expand Down Expand Up @@ -583,6 +623,15 @@ impl Wizer {
self
}

/// Enable or disable the Wasm relaxed SIMD proposal.
///
/// Defaults to `false`. When enabling, consdider whether to additionally
/// use `relaxed_simd_deterministic`.
pub fn wasm_relaxed_simd(&mut self, enable: bool) -> &mut Self {
self.wasm_relaxed_simd = Some(enable);
self
}

/// Initialize the given Wasm, snapshot it, and return the serialized
/// snapshot as a new, pre-initialized Wasm module.
pub fn run(&self, wasm: &[u8]) -> anyhow::Result<Vec<u8>> {
Expand Down Expand Up @@ -658,6 +707,7 @@ impl Wizer {
config.wasm_bulk_memory(self.wasm_bulk_memory.unwrap_or(DEFAULT_WASM_BULK_MEMORY));

config.wasm_simd(self.wasm_simd.unwrap_or(DEFAULT_WASM_SIMD));
config.wasm_relaxed_simd(self.wasm_relaxed_simd.unwrap_or(DEFAULT_WASM_RELAXED_SIMD));

// Note that reference_types are not actually supported,
// but many compilers now enable them by default
Expand All @@ -669,6 +719,9 @@ impl Wizer {
config.wasm_tail_call(true);
config.wasm_extended_const(true);

// Enable `relaxed_simd_deterministic` if requested.
config.relaxed_simd_deterministic(self.relaxed_simd_deterministic);

// Proposals that we should add support for.
config.wasm_threads(false);

Expand Down Expand Up @@ -703,6 +756,10 @@ impl Wizer {

features.set(WasmFeatures::TAIL_CALL, true);
features.set(WasmFeatures::EXTENDED_CONST, true);
features.set(
WasmFeatures::RELAXED_SIMD,
self.wasm_relaxed_simd.unwrap_or(DEFAULT_WASM_RELAXED_SIMD),
);

return features;
}
Expand Down
30 changes: 30 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,3 +829,33 @@ fn accept_simd128() -> Result<()> {
"#,
)
}

#[test]
fn relaxed_simd_deterministic() -> Result<()> {
let _ = env_logger::try_init();
let wasm = wat_to_wasm(
r#"
(module
(global $g (mut i32) i32.const 0)
(func (export "wizer.initialize")
(v128.const f32x4 2796203.5 0.0 0.0 0.0)
(v128.const f32x4 3.0 0.0 0.0 0.0)
(v128.const f32x4 8388611.0 0.0 0.0 0.0)
f32x4.relaxed_madd
f32x4.extract_lane 0
i32.reinterpret_f32
global.set $g)
(func (export "run") (result i32)
global.get $g
)
)
"#,
)?;
let mut wizer = get_wizer();
wizer.wasm_relaxed_simd(true);
wizer.relaxed_simd_deterministic(true);

// We'll get 0x4b000003 if we have the deterministic `relaxed_madd`
// semantics. We might get 0x4b000002 if we don't.
wizen_and_run_wasm(&[], 0x4b800003, &wasm, wizer)
}
Loading