Skip to content

Commit cbed13d

Browse files
committed
Make nondeterministic SIMD lowering an option and add a test.
1 parent c3dea26 commit cbed13d

File tree

2 files changed

+82
-6
lines changed

2 files changed

+82
-6
lines changed

src/lib.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const DEFAULT_WASM_MULTI_VALUE: bool = true;
4343
const DEFAULT_WASM_MULTI_MEMORY: bool = true;
4444
const DEFAULT_WASM_BULK_MEMORY: bool = true;
4545
const DEFAULT_WASM_SIMD: bool = true;
46+
const DEFAULT_WASM_RELAXED_SIMD: bool = false;
4647
const DEFAULT_WASM_REFERENCE_TYPES: bool = true;
4748

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

144+
/// Use deterministic behavior for relaxed SIMD instructions.
145+
///
146+
/// The relaxed SIMD instructions in Wasm are instructions which are
147+
/// permitted to have different results when run on different host
148+
/// CPU architectures. This flag tells wizer to instead execute relaxed
149+
/// SIMD instructions according to the [deterministic profile], which
150+
/// ensures that they're deterministic and platform-independent.
151+
///
152+
/// [deterministic profile]: https://webassembly.github.io/spec/core/appendix/profiles.html#deterministic-profile-small-mathrm-det
153+
#[cfg_attr(feature = "structopt", structopt(long = "relaxed-simd-deterministic"))]
154+
relaxed_simd_deterministic: bool,
155+
143156
/// Provide an additional preloaded module that is available to the
144157
/// main module.
145158
///
@@ -252,6 +265,13 @@ pub struct Wizer {
252265
#[cfg_attr(feature = "structopt", structopt(long, value_name = "true|false"))]
253266
wasm_simd: Option<bool>,
254267

268+
/// Enable or disable the Wasm relaxed SIMD proposal.
269+
///
270+
/// Disabled by default. When enabled, by default relaxed SIMD instructions
271+
/// will produce different results on different platforms. For deterministic
272+
/// results, additionally enable the `--relaxed-simd-deterministic` flag.
273+
wasm_relaxed_simd: Option<bool>,
274+
255275
/// Enable or disable the Wasm reference-types proposal.
256276
///
257277
/// Currently does not implement snapshotting or the use of references,
@@ -269,6 +289,7 @@ impl std::fmt::Debug for Wizer {
269289
init_func,
270290
func_renames,
271291
allow_wasi,
292+
relaxed_simd_deterministic,
272293
preload,
273294
preload_bytes,
274295
make_linker: _,
@@ -281,12 +302,14 @@ impl std::fmt::Debug for Wizer {
281302
wasm_multi_value,
282303
wasm_bulk_memory,
283304
wasm_simd,
305+
wasm_relaxed_simd,
284306
wasm_reference_types,
285307
} = self;
286308
f.debug_struct("Wizer")
287309
.field("init_func", &init_func)
288310
.field("func_renames", &func_renames)
289311
.field("allow_wasi", &allow_wasi)
312+
.field("relaxed_simd_deterministic", &relaxed_simd_deterministic)
290313
.field("preload", &preload)
291314
.field("preload_bytes", &preload_bytes)
292315
.field("make_linker", &"..")
@@ -299,6 +322,7 @@ impl std::fmt::Debug for Wizer {
299322
.field("wasm_multi_value", &wasm_multi_value)
300323
.field("wasm_bulk_memory", &wasm_bulk_memory)
301324
.field("wasm_simd", &wasm_simd)
325+
.field("wasm_relaxed_simd", &wasm_relaxed_simd)
302326
.field("wasm_reference_types", &wasm_reference_types)
303327
.finish()
304328
}
@@ -352,6 +376,7 @@ impl Wizer {
352376
init_func: "wizer.initialize".into(),
353377
func_renames: vec![],
354378
allow_wasi: false,
379+
relaxed_simd_deterministic: false,
355380
preload: vec![],
356381
preload_bytes: vec![],
357382
make_linker: None,
@@ -364,6 +389,7 @@ impl Wizer {
364389
wasm_multi_value: None,
365390
wasm_bulk_memory: None,
366391
wasm_simd: None,
392+
wasm_relaxed_simd: None,
367393
wasm_reference_types: None,
368394
}
369395
}
@@ -405,6 +431,19 @@ impl Wizer {
405431
Ok(self)
406432
}
407433

434+
/// Use deterministic behavior for relaxed SIMD instructions.
435+
///
436+
/// The relaxed SIMD instructions in Wasm are instructions which are
437+
/// permitted to have different results when run on different host
438+
/// CPU architectures. This flag tells wizer to instead execute relaxed
439+
/// SIMD instructions according to the [deterministic profile], which
440+
/// ensures that they're deterministic and platform-independent.
441+
///
442+
/// [deterministic profile]: https://webassembly.github.io/spec/core/appendix/profiles.html#deterministic-profile-small-mathrm-det
443+
pub fn relaxed_simd_deterministic(&mut self, deterministic: bool) {
444+
self.relaxed_simd_deterministic = deterministic;
445+
}
446+
408447
/// Provide an additional preloaded module that is available to the
409448
/// main module.
410449
///
@@ -583,6 +622,15 @@ impl Wizer {
583622
self
584623
}
585624

625+
/// Enable or disable the Wasm relaxed SIMD proposal.
626+
///
627+
/// Defaults to `false`. When enabling, consdider whether to additionally
628+
/// use `relaxed_simd_deterministic`.
629+
pub fn wasm_relaxed_simd(&mut self, enable: bool) -> &mut Self {
630+
self.wasm_relaxed_simd = Some(enable);
631+
self
632+
}
633+
586634
/// Initialize the given Wasm, snapshot it, and return the serialized
587635
/// snapshot as a new, pre-initialized Wasm module.
588636
pub fn run(&self, wasm: &[u8]) -> anyhow::Result<Vec<u8>> {
@@ -658,6 +706,7 @@ impl Wizer {
658706
config.wasm_bulk_memory(self.wasm_bulk_memory.unwrap_or(DEFAULT_WASM_BULK_MEMORY));
659707

660708
config.wasm_simd(self.wasm_simd.unwrap_or(DEFAULT_WASM_SIMD));
709+
config.wasm_relaxed_simd(self.wasm_relaxed_simd.unwrap_or(DEFAULT_WASM_RELAXED_SIMD));
661710

662711
// Note that reference_types are not actually supported,
663712
// but many compilers now enable them by default
@@ -669,12 +718,8 @@ impl Wizer {
669718
config.wasm_tail_call(true);
670719
config.wasm_extended_const(true);
671720

672-
// The spec requires relaxed-simd instructions to be deterministic
673-
// within a run. We don't have any way configure the nondeterminism
674-
// of the code after a snapshot restore, however we can at least
675-
// use deterministic lowerings so that if the subsequent engine
676-
// also uses deterministic lowerings, it'll match.
677-
config.relaxed_simd_deterministic(true);
721+
// Enable `relaxed_simd_deterministic` if requested.
722+
config.relaxed_simd_deterministic(self.relaxed_simd_deterministic);
678723

679724
// Proposals that we should add support for.
680725
config.wasm_threads(false);
@@ -710,6 +755,7 @@ impl Wizer {
710755

711756
features.set(WasmFeatures::TAIL_CALL, true);
712757
features.set(WasmFeatures::EXTENDED_CONST, true);
758+
features.set(WasmFeatures::RELAXED_SIMD, true);
713759

714760
return features;
715761
}

tests/tests.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,3 +829,33 @@ fn accept_simd128() -> Result<()> {
829829
"#,
830830
)
831831
}
832+
833+
#[test]
834+
fn relaxed_simd_deterministic() -> Result<()> {
835+
let _ = env_logger::try_init();
836+
let wasm = wat_to_wasm(
837+
r#"
838+
(module
839+
(global $g (mut i32) i32.const 0)
840+
(func (export "wizer.initialize")
841+
(v128.const f32x4 2796203.5 0.0 0.0 0.0)
842+
(v128.const f32x4 3.0 0.0 0.0 0.0)
843+
(v128.const f32x4 8388611.0 0.0 0.0 0.0)
844+
f32x4.relaxed_madd
845+
f32x4.extract_lane 0
846+
i32.reinterpret_f32
847+
global.set $g)
848+
(func (export "run") (result i32)
849+
global.get $g
850+
)
851+
)
852+
"#,
853+
)?;
854+
let mut wizer = get_wizer();
855+
wizer.wasm_relaxed_simd(true);
856+
wizer.relaxed_simd_deterministic(true);
857+
858+
// We'll get 0x4b000003 if we have the deterministic `relaxed_madd`
859+
// semantics. We might get 0x4b000002 if we don't.
860+
wizen_and_run_wasm(&[], 0x4b800003, &wasm, wizer)
861+
}

0 commit comments

Comments
 (0)