From d6493c277eb1104aaf72a8e0e6959ce3d1cc4932 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 12 Feb 2025 19:13:23 +0100 Subject: [PATCH 01/17] fix: fix build, improve error handling Signed-off-by: Henry Gressmann --- CHANGELOG.md | 7 +++--- crates/tinywasm/src/error.rs | 17 ++++++++++--- .../tinywasm/src/interpreter/no_std_floats.rs | 9 ------- crates/types/src/lib.rs | 12 ++++++++++ examples/rust/Cargo.toml | 4 ++++ examples/rust/build.sh | 4 ++-- examples/rust/src/argon2id.rs | 2 +- examples/rust/src/fibonacci.rs | 4 ++-- examples/rust/src/hello.rs | 8 +++---- examples/rust/src/host_fn.rs | 11 +++++++++ examples/rust/src/print.rs | 4 ++-- examples/rust/src/tinywasm.rs | 4 ++-- examples/rust/src/tinywasm_no_std.rs | 6 ++--- examples/wasm-rust.rs | 24 +++++++++++++++++++ 14 files changed, 85 insertions(+), 31 deletions(-) create mode 100644 examples/rust/src/host_fn.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0222a0b..c01787f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for the custom memory page sizes proposal ([#22](https://github.com/explodingcamera/tinywasm/pull/22) by [@danielstuart14](https://github.com/danielstuart14)) -### Changed +### Breaking Changes -- **Breaking:**: New backwards-incompatible version of the twasm format based on `postcard` (thanks [@dragonnn](https://github.com/dragonnn)) -- **Breaking:**: `RefNull` has been removed and replaced with new `FuncRef` and `ExternRef` structs +- New backwards-incompatible version of the twasm format based on `postcard` (thanks [@dragonnn](https://github.com/dragonnn)) +- `RefNull` has been removed and replaced with new `FuncRef` and `ExternRef` structs - Increased MSRV to 1.83.0 +- `tinywasm::Error` is now `non_exhaustive`, `Error::ParseError` has been rename to `Error::Parser` and `Error::Twasm` has been added. ### Fixed diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs index e0510b2..1d488d8 100644 --- a/crates/tinywasm/src/error.rs +++ b/crates/tinywasm/src/error.rs @@ -1,6 +1,7 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::{fmt::Display, ops::ControlFlow}; +use tinywasm_types::archive::TwasmError; use tinywasm_types::FuncType; #[cfg(feature = "parser")] @@ -8,6 +9,7 @@ pub use tinywasm_parser::ParseError; /// Errors that can occur for `TinyWasm` operations #[derive(Debug)] +#[non_exhaustive] pub enum Error { /// A WebAssembly trap occurred Trap(Trap), @@ -41,7 +43,10 @@ pub enum Error { #[cfg(feature = "parser")] /// A parsing error occurred - ParseError(ParseError), + Parser(ParseError), + + /// A serialization error occurred + Twasm(TwasmError), } #[derive(Debug)] @@ -169,6 +174,11 @@ impl From for Error { } } +impl From for Error { + fn from(value: TwasmError) -> Self { + Self::Twasm(value) + } +} impl From for Error { fn from(value: Trap) -> Self { Self::Trap(value) @@ -179,11 +189,12 @@ impl Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { #[cfg(feature = "parser")] - Self::ParseError(err) => write!(f, "error parsing module: {err:?}"), + Self::Parser(err) => write!(f, "error parsing module: {err:?}"), #[cfg(feature = "std")] Self::Io(err) => write!(f, "I/O error: {err}"), + Self::Twasm(err) => write!(f, "serialization error: {err}"), Self::Trap(trap) => write!(f, "trap: {trap}"), Self::Linker(err) => write!(f, "linking error: {err}"), Self::InvalidLabelType => write!(f, "invalid label type"), @@ -238,7 +249,7 @@ impl core::error::Error for Error {} #[cfg(feature = "parser")] impl From for Error { fn from(value: tinywasm_parser::ParseError) -> Self { - Self::ParseError(value) + Self::Parser(value) } } diff --git a/crates/tinywasm/src/interpreter/no_std_floats.rs b/crates/tinywasm/src/interpreter/no_std_floats.rs index 5b9471e..e273184 100644 --- a/crates/tinywasm/src/interpreter/no_std_floats.rs +++ b/crates/tinywasm/src/interpreter/no_std_floats.rs @@ -1,34 +1,25 @@ pub(super) trait NoStdFloatExt { fn round(self) -> Self; - fn abs(self) -> Self; - fn signum(self) -> Self; fn ceil(self) -> Self; fn floor(self) -> Self; fn trunc(self) -> Self; fn sqrt(self) -> Self; - fn copysign(self, other: Self) -> Self; } #[rustfmt::skip] impl NoStdFloatExt for f64 { #[inline] fn round(self) -> Self { libm::round(self) } - #[inline] fn abs(self) -> Self { libm::fabs(self) } - #[inline] fn signum(self) -> Self { libm::copysign(1.0, self) } #[inline] fn ceil(self) -> Self { libm::ceil(self) } #[inline] fn floor(self) -> Self { libm::floor(self) } #[inline] fn trunc(self) -> Self { libm::trunc(self) } #[inline] fn sqrt(self) -> Self { libm::sqrt(self) } - #[inline] fn copysign(self, other: Self) -> Self { libm::copysign(self, other) } } #[rustfmt::skip] impl NoStdFloatExt for f32 { #[inline] fn round(self) -> Self { libm::roundf(self) } - #[inline] fn abs(self) -> Self { libm::fabsf(self) } - #[inline] fn signum(self) -> Self { libm::copysignf(1.0, self) } #[inline] fn ceil(self) -> Self { libm::ceilf(self) } #[inline] fn floor(self) -> Self { libm::floorf(self) } #[inline] fn trunc(self) -> Self { libm::truncf(self) } #[inline] fn sqrt(self) -> Self { libm::sqrtf(self) } - #[inline] fn copysign(self, other: Self) -> Self { libm::copysignf(self, other) } } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 81eec13..d9f2234 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -45,6 +45,18 @@ pub use value::*; #[cfg(feature = "archive")] pub mod archive; +#[cfg(not(feature = "archive"))] +pub mod archive { + #[derive(Debug)] + pub enum TwasmError {} + impl core::fmt::Display for TwasmError { + fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + Err(core::fmt::Error) + } + } + impl core::error::Error for TwasmError {} +} + /// A `TinyWasm` WebAssembly Module /// /// This is the internal representation of a WebAssembly module in `TinyWasm`. diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index 5c6b710..da238ad 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -22,6 +22,10 @@ std=["tinywasm/std"] name="hello" path="src/hello.rs" +[[bin]] +name="host_fn" +path="src/host_fn.rs" + [[bin]] name="print" path="src/print.rs" diff --git a/examples/rust/build.sh b/examples/rust/build.sh index d0415ac..e1d320f 100755 --- a/examples/rust/build.sh +++ b/examples/rust/build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -cd "$(dirname "$0")" +cd "$(dirname "$0")" || exit -bins=("hello" "fibonacci" "print" "tinywasm" "argon2id") +bins=("host_fn" "hello" "fibonacci" "print" "tinywasm" "argon2id") exclude_wat=("tinywasm") out_dir="./target/wasm32-unknown-unknown/wasm" dest_dir="out" diff --git a/examples/rust/src/argon2id.rs b/examples/rust/src/argon2id.rs index 01ea7ca..ff17d04 100644 --- a/examples/rust/src/argon2id.rs +++ b/examples/rust/src/argon2id.rs @@ -1,6 +1,6 @@ #![no_main] -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn argon2id(m_cost: i32, t_cost: i32, p_cost: i32) -> i32 { let password = b"password"; let salt = b"some random salt"; diff --git a/examples/rust/src/fibonacci.rs b/examples/rust/src/fibonacci.rs index b847ad5..ec4a371 100644 --- a/examples/rust/src/fibonacci.rs +++ b/examples/rust/src/fibonacci.rs @@ -1,6 +1,6 @@ #![no_main] -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn fibonacci(n: i32) -> i32 { let mut sum = 0; let mut last = 0; @@ -13,7 +13,7 @@ pub extern "C" fn fibonacci(n: i32) -> i32 { sum } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn fibonacci_recursive(n: i32) -> i32 { if n <= 1 { return n; diff --git a/examples/rust/src/hello.rs b/examples/rust/src/hello.rs index c8e2ac3..3d9f400 100644 --- a/examples/rust/src/hello.rs +++ b/examples/rust/src/hello.rs @@ -1,23 +1,23 @@ #![no_main] #[link(wasm_import_module = "env")] -extern "C" { +unsafe extern "C" { fn print_utf8(location: i64, len: i32); } const ARG: &[u8] = &[0u8; 100]; -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn arg_ptr() -> i32 { ARG.as_ptr() as i32 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn arg_size() -> i32 { ARG.len() as i32 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn hello(len: i32) { let arg = core::str::from_utf8(&ARG[0..len as usize]).unwrap(); let res = format!("Hello, {}!", arg).as_bytes().to_vec(); diff --git a/examples/rust/src/host_fn.rs b/examples/rust/src/host_fn.rs new file mode 100644 index 0000000..ada74bd --- /dev/null +++ b/examples/rust/src/host_fn.rs @@ -0,0 +1,11 @@ +#![no_main] + +#[link(wasm_import_module = "env")] +unsafe extern "C" { + fn bar(left: i64, right: i32) -> i32; +} + +#[unsafe(no_mangle)] +pub fn foo() -> i32 { + unsafe { bar(1, 2) } +} diff --git a/examples/rust/src/print.rs b/examples/rust/src/print.rs index d04daa3..d2934f0 100644 --- a/examples/rust/src/print.rs +++ b/examples/rust/src/print.rs @@ -1,11 +1,11 @@ #![no_main] #[link(wasm_import_module = "env")] -extern "C" { +unsafe extern "C" { fn printi32(x: i32); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn add_and_print(lh: i32, rh: i32) { printi32(lh + rh); } diff --git a/examples/rust/src/tinywasm.rs b/examples/rust/src/tinywasm.rs index c3bf2d2..d3b3f8c 100644 --- a/examples/rust/src/tinywasm.rs +++ b/examples/rust/src/tinywasm.rs @@ -2,11 +2,11 @@ use tinywasm::{Extern, FuncContext}; #[link(wasm_import_module = "env")] -extern "C" { +unsafe extern "C" { fn printi32(x: i32); } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn hello() { let _ = run(); } diff --git a/examples/rust/src/tinywasm_no_std.rs b/examples/rust/src/tinywasm_no_std.rs index 9a31d20..46f1785 100644 --- a/examples/rust/src/tinywasm_no_std.rs +++ b/examples/rust/src/tinywasm_no_std.rs @@ -16,11 +16,11 @@ static ALLOCATOR: AssumeSingleThreaded = unsafe { AssumeSingleThreaded::new(FreeListAllocator::new()) }; #[link(wasm_import_module = "env")] -extern "C" { +unsafe extern "C" { fn printi32(x: i32); } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn hello() { let _ = run(); } @@ -30,7 +30,7 @@ fn run() -> tinywasm::Result<()> { let mut imports = tinywasm::Imports::new(); let res = tinywasm::parser::Parser::new().parse_module_bytes(include_bytes!("./print.wasm"))?; - let twasm = res.serialize_twasm(); + let twasm = res.serialize_twasm()?; let module = tinywasm::Module::parse_bytes(&twasm)?; imports.define( diff --git a/examples/wasm-rust.rs b/examples/wasm-rust.rs index 429bdcb..95769f4 100644 --- a/examples/wasm-rust.rs +++ b/examples/wasm-rust.rs @@ -33,6 +33,7 @@ fn main() -> Result<()> { println!("Available examples:"); println!(" hello"); println!(" printi32"); + println!(" host_fn"); println!(" fibonacci - calculate fibonacci(30)"); println!(" tinywasm - run printi32 inside of tinywasm inside of itself"); println!(" argon2id - run argon2id(1000, 2, 1)"); @@ -46,6 +47,7 @@ fn main() -> Result<()> { "tinywasm" => tinywasm()?, "tinywasm_no_std" => tinywasm_no_std()?, "argon2id" => argon2id()?, + "host_fn" => host_fn()?, "all" => { println!("Running all examples"); println!("\nhello.wasm:"); @@ -60,6 +62,8 @@ fn main() -> Result<()> { tinywasm_no_std()?; println!("argon2id.wasm:"); argon2id()?; + println!("\nhost_fn.wasm:"); + host_fn()?; } _ => {} } @@ -126,6 +130,26 @@ fn hello() -> Result<()> { Ok(()) } +fn host_fn() -> Result<()> { + let module = Module::parse_file("./examples/rust/out/host_fn.wasm")?; + let mut store = Store::default(); + let mut imports = Imports::new(); + imports.define( + "env", + "bar", + Extern::typed_func(|_: FuncContext<'_>, (left, right): (i64, i32)| { + assert_eq!(left, 1); + assert_eq!(right, 2); + Ok(left as i32 + right) + }), + )?; + + let instance = module.instantiate(&mut store, Some(imports))?; + let host_fn = instance.exported_func::<(), i32>(&store, "foo")?; + assert_eq!(host_fn.call(&mut store, ())?, 3); + Ok(()) +} + fn printi32() -> Result<()> { let module = Module::parse_file("./examples/rust/out/print.opt.wasm")?; let mut store = Store::default(); From 60bea1e5e52d6672509dc394ab0df1e8b8423b00 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Tue, 25 Feb 2025 19:39:51 +0100 Subject: [PATCH 02/17] chore: update to rust 2024 Signed-off-by: Henry Gressmann --- Cargo.lock | 118 ++++++------------ Cargo.toml | 9 +- crates/parser/Cargo.toml | 2 +- crates/parser/src/conversion.rs | 4 +- crates/parser/src/lib.rs | 2 - crates/parser/src/module.rs | 2 +- crates/parser/src/visit.rs | 4 +- crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/benches/argon2id.rs | 4 +- crates/tinywasm/benches/fibonacci.rs | 7 +- crates/tinywasm/benches/tinywasm.rs | 6 +- crates/tinywasm/src/error.rs | 2 +- crates/tinywasm/src/func.rs | 2 +- crates/tinywasm/src/imports.rs | 6 +- .../src/interpreter/stack/call_stack.rs | 4 +- .../src/interpreter/stack/value_stack.rs | 2 +- crates/tinywasm/src/store/memory.rs | 2 +- crates/tinywasm/src/store/mod.rs | 2 +- crates/types/src/archive.rs | 4 +- 19 files changed, 71 insertions(+), 113 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccb8fa3..1178a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,18 +114,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.29" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.29" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstyle", "clap_lex", @@ -211,9 +211,9 @@ checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "either" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" [[package]] name = "embedded-io" @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "eyre" @@ -345,12 +345,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -359,9 +353,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libm" @@ -371,9 +365,9 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "log" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "memchr" @@ -404,9 +398,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "owo-colors" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" [[package]] name = "postcard" @@ -526,18 +520,18 @@ checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", @@ -546,9 +540,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", "memchr", @@ -602,7 +596,7 @@ dependencies = [ "tinywasm-parser", "tinywasm-types", "wasm-testsuite", - "wast 225.0.0", + "wast", "wat", ] @@ -615,7 +609,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast 225.0.0", + "wast", ] [[package]] @@ -624,7 +618,7 @@ version = "0.9.0-alpha.0" dependencies = [ "log", "tinywasm-types", - "wasmparser 0.225.0", + "wasmparser", ] [[package]] @@ -648,9 +642,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "unicode-width" @@ -670,89 +664,55 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.224.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab7a13a23790fe91ea4eb7526a1f3131001d874e3e00c2976c48861f2e82920" -dependencies = [ - "leb128", - "wasmparser 0.224.1", -] - -[[package]] -name = "wasm-encoder" -version = "0.225.0" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f7eac0445cac73bcf09e6a97f83248d64356dccf9f2b100199769b6b42464e5" +checksum = "f7d81b727619aec227dce83e7f7420d4e56c79acd044642a356ea045b98d4e13" dependencies = [ "leb128fmt", - "wasmparser 0.225.0", + "wasmparser", ] [[package]] name = "wasm-testsuite" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a4e25e8fd04d2da04479453bb74448dfffb960c5a0ed74df97a4cdddcaab85c" +checksum = "fea6edc2d1ffad1d673091e3e3e98961e7c1a8c0f24cbf2431fa02d861e071bd" dependencies = [ "include_dir", - "wast 224.0.1", + "wast", ] [[package]] name = "wasmparser" -version = "0.224.1" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11" +checksum = "bc28600dcb2ba68d7e5f1c3ba4195c2bddc918c0243fd702d0b6dbd05689b681" dependencies = [ "bitflags", "indexmap", "semver", ] -[[package]] -name = "wasmparser" -version = "0.225.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae" -dependencies = [ - "bitflags", - "indexmap", - "semver", -] - -[[package]] -name = "wast" -version = "224.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf8e902015ff670011613811be3310408d2dba911217eea711aa98c89584aca" -dependencies = [ - "bumpalo", - "leb128", - "memchr", - "unicode-width", - "wasm-encoder 0.224.1", -] - [[package]] name = "wast" -version = "225.0.0" +version = "226.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61496027ff707f9fa9e0b22c34ec163eb7adb1070df565e32a9180a76e4300b" +checksum = "0bb903956d0151eabb6c30a2304dd61e5c8d7182805226120c2b6d611fb09a26" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.225.0", + "wasm-encoder", ] [[package]] name = "wat" -version = "1.225.0" +version = "1.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e72a33942234fd0794bcdac30e43b448de3187512414267678e511c6755f11" +checksum = "5f89a90ef2c401b8b5b2b704020bfa7a7f69b93c3034c7a4b4a88e21e9966581" dependencies = [ - "wast 225.0.0", + "wast", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e92c4ad..e433260 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,9 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"] resolver="2" [workspace.dependencies] -wast="225" -wat="1.225" +wast="226" +wat="1.226" +wasmparser={version="0.226", default-features=false} eyre="0.6" log="0.4" pretty_env_logger="0.5" @@ -13,8 +14,8 @@ criterion={version="0.5", default-features=false, features=["cargo_bench_support [workspace.package] version="0.9.0-alpha.0" -rust-version="1.81" -edition="2021" +rust-version="1.85" +edition="2024" license="MIT OR Apache-2.0" authors=["Henry Gressmann "] repository="https://github.com/explodingcamera/tinywasm" diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index fec21b3..7bd9cad 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -9,7 +9,7 @@ repository.workspace=true rust-version.workspace=true [dependencies] -wasmparser={version="0.225", default-features=false, features=["validate", "features", "simd"]} +wasmparser={workspace=true, features=["validate", "features", "simd"]} log={workspace=true, optional=true} tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false} diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 273dd44..86548d6 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -92,7 +92,7 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result { - return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported import kind: {ty:?}"))) + return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported import kind: {ty:?}"))); } }, }) @@ -157,7 +157,7 @@ pub(crate) fn convert_module_export(export: wasmparser::Export<'_>) -> Result ExternalKind::Memory, wasmparser::ExternalKind::Global => ExternalKind::Global, wasmparser::ExternalKind::Tag => { - return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported export kind: {:?}", export.kind))) + return Err(crate::ParseError::UnsupportedOperator(format!("Unsupported export kind: {:?}", export.kind))); } }; diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 04da9da..e5022c5 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -72,14 +72,12 @@ impl Parser { component_model: false, component_model_nested_names: false, component_model_values: false, - component_model_more_flags: false, exceptions: false, gc: false, memory_control: false, relaxed_simd: false, threads: false, shared_everything_threads: false, - component_model_multiple_returns: false, legacy_exceptions: false, component_model_async: false, }; diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 9b31f9e..ff6b22b 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -1,5 +1,5 @@ use crate::log::debug; -use crate::{conversion, ParseError, Result}; +use crate::{ParseError, Result, conversion}; use alloc::string::ToString; use alloc::{boxed::Box, format, vec::Vec}; use tinywasm_types::{ diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 89c27d1..2830d3a 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -531,11 +531,11 @@ impl wasmparser::VisitSimdOperator<'_> for FunctionBuild fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { self.v128_constants.push(u128::from_le_bytes(lanes)); - self.instructions.push(Instruction::I8x16Shuffle(self.v128_constants.len() as u32 - 1).into()); + self.instructions.push(Instruction::I8x16Shuffle(self.v128_constants.len() as u32 - 1)); } fn visit_v128_const(&mut self, value: wasmparser::V128) -> Self::Output { self.v128_constants.push(value.i128() as u128); - self.instructions.push(Instruction::V128Const(self.v128_constants.len() as u32 - 1).into()); + self.instructions.push(Instruction::V128Const(self.v128_constants.len() as u32 - 1)); } } diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 0623f35..2cad2e4 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false libm={version="0.2", default-features=false} [dev-dependencies] -wasm-testsuite={version="0.4.2"} +wasm-testsuite={version="0.4.4"} indexmap="2.7" wast={workspace=true} wat={workspace=true} diff --git a/crates/tinywasm/benches/argon2id.rs b/crates/tinywasm/benches/argon2id.rs index d977352..aa8b38b 100644 --- a/crates/tinywasm/benches/argon2id.rs +++ b/crates/tinywasm/benches/argon2id.rs @@ -1,6 +1,6 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use eyre::Result; -use tinywasm::{types, ModuleInstance, Store}; +use tinywasm::{ModuleInstance, Store, types}; use types::TinyWasmModule; const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.opt.wasm"); diff --git a/crates/tinywasm/benches/fibonacci.rs b/crates/tinywasm/benches/fibonacci.rs index dcf6eb9..a5f1c72 100644 --- a/crates/tinywasm/benches/fibonacci.rs +++ b/crates/tinywasm/benches/fibonacci.rs @@ -1,6 +1,6 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use eyre::Result; -use tinywasm::{types, ModuleInstance, Store}; +use tinywasm::{ModuleInstance, Store, types}; use types::TinyWasmModule; const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.opt.wasm"); @@ -17,8 +17,7 @@ fn fibonacci_to_twasm(module: &TinyWasmModule) -> Result> { } fn fibonacci_from_twasm(twasm: &[u8]) -> Result { - let module = TinyWasmModule::from_twasm(&twasm)?; - Ok(module) + Ok(TinyWasmModule::from_twasm(twasm)?) } fn fibonacci_run(module: TinyWasmModule, recursive: bool, n: i32) -> Result<()> { diff --git a/crates/tinywasm/benches/tinywasm.rs b/crates/tinywasm/benches/tinywasm.rs index 8552d6c..4848a4a 100644 --- a/crates/tinywasm/benches/tinywasm.rs +++ b/crates/tinywasm/benches/tinywasm.rs @@ -1,6 +1,6 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use eyre::Result; -use tinywasm::{types, Extern, FuncContext, Imports, ModuleInstance, Store}; +use tinywasm::{Extern, FuncContext, Imports, ModuleInstance, Store, types}; use types::TinyWasmModule; const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.opt.wasm"); @@ -17,7 +17,7 @@ fn tinywasm_to_twasm(module: &TinyWasmModule) -> Result> { } fn tinywasm_from_twasm(twasm: &[u8]) -> Result { - let module = TinyWasmModule::from_twasm(&twasm)?; + let module = TinyWasmModule::from_twasm(twasm)?; Ok(module) } diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs index 1d488d8..9637521 100644 --- a/crates/tinywasm/src/error.rs +++ b/crates/tinywasm/src/error.rs @@ -1,8 +1,8 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::{fmt::Display, ops::ControlFlow}; -use tinywasm_types::archive::TwasmError; use tinywasm_types::FuncType; +use tinywasm_types::archive::TwasmError; #[cfg(feature = "parser")] pub use tinywasm_parser::ParseError; diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index f5a9873..2eeabca 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -1,6 +1,6 @@ use crate::interpreter::stack::{CallFrame, Stack}; -use crate::{log, unlikely, Function}; use crate::{Error, FuncContext, Result, Store}; +use crate::{Function, log, unlikely}; use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec}; use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, ValType, WasmValue}; diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index 0797470..12876c8 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -6,7 +6,7 @@ use alloc::vec::Vec; use core::fmt::Debug; use crate::func::{FromWasmValueTuple, IntoWasmValueTuple, ValTypesFromTuple}; -use crate::{log, LinkingError, MemoryRef, MemoryRefMut, Result}; +use crate::{LinkingError, MemoryRef, MemoryRefMut, Result, log}; use tinywasm_types::*; /// The internal representation of a function @@ -322,7 +322,7 @@ impl Imports { match (expected.size_max, actual.size_max) { (None, Some(_)) => return Err(LinkingError::incompatible_import_type(import).into()), (Some(expected_max), Some(actual_max)) if actual_max < expected_max => { - return Err(LinkingError::incompatible_import_type(import).into()) + return Err(LinkingError::incompatible_import_type(import).into()); } _ => {} } @@ -339,7 +339,7 @@ impl Imports { Self::compare_types(import, &expected.arch(), &actual.arch())?; if actual.page_count_initial() > expected.page_count_initial() - && real_size.map_or(true, |size| actual.page_count_initial() > size as u64) + && real_size.is_none_or(|size| actual.page_count_initial() > size as u64) { return Err(LinkingError::incompatible_import_type(import).into()); } diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index f0e8d18..9b6c3fd 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -1,9 +1,9 @@ use core::ops::ControlFlow; use super::BlockType; -use crate::interpreter::values::*; use crate::Trap; -use crate::{unlikely, Error}; +use crate::interpreter::values::*; +use crate::{Error, unlikely}; use alloc::boxed::Box; use alloc::{rc::Rc, vec, vec::Vec}; diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index ea6a082..9830c01 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -1,7 +1,7 @@ use alloc::vec::Vec; use tinywasm_types::{ExternRef, FuncRef, ValType, ValueCounts, ValueCountsSmall, WasmValue}; -use crate::{interpreter::*, Result}; +use crate::{Result, interpreter::*}; use super::Locals; pub(crate) const STACK_32_SIZE: usize = 1024 * 32; diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index 4826b65..d204c67 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -2,7 +2,7 @@ use alloc::vec; use alloc::vec::Vec; use tinywasm_types::{MemoryType, ModuleInstanceAddr}; -use crate::{cold, log, Error, Result}; +use crate::{Error, Result, cold, log}; /// A WebAssembly Memory Instance /// diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 86cbb5d..5730631 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use tinywasm_types::*; use crate::interpreter::{self, InterpreterRuntime, TinyWasmValue}; -use crate::{cold, Error, Function, ModuleInstance, Result, Trap}; +use crate::{Error, Function, ModuleInstance, Result, Trap, cold}; mod data; mod element; diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs index a725e3d..cbc22ad 100644 --- a/crates/types/src/archive.rs +++ b/crates/types/src/archive.rs @@ -52,13 +52,13 @@ impl TinyWasmModule { pub fn from_twasm(wasm: &[u8]) -> Result { let len = validate_magic(wasm)?; - postcard::from_bytes(&wasm[len..]).map_err(|e| TwasmError::InvalidArchive(e)) + postcard::from_bytes(&wasm[len..]).map_err(TwasmError::InvalidArchive) } /// Serializes the `TinyWasmModule` into a vector of bytes. pub fn serialize_twasm(&self) -> Result, TwasmError> { let buf = Vec::from(TWASM_MAGIC); - postcard::to_extend(self, buf).map_err(|e| TwasmError::InvalidArchive(e)) + postcard::to_extend(self, buf).map_err(TwasmError::InvalidArchive) } } From d0264fcae4ba4ffb7e5417ddce464e663de66940 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 28 Feb 2025 23:28:19 +0100 Subject: [PATCH 03/17] wip: initial simd support Signed-off-by: Henry Gressmann --- crates/cli/src/args.rs | 1 + crates/tinywasm/Cargo.toml | 3 +- crates/tinywasm/src/interpreter/executor.rs | 78 ++++++++++++++++++- crates/tinywasm/src/interpreter/mod.rs | 3 + crates/tinywasm/src/interpreter/simd.rs | 18 +++++ .../src/interpreter/stack/value_stack.rs | 12 ++- crates/tinywasm/src/interpreter/values.rs | 36 ++++++++- crates/tinywasm/src/lib.rs | 2 +- crates/tinywasm/tests/generated/wasm-3.csv | 2 +- crates/types/src/instructions.rs | 7 +- 10 files changed, 150 insertions(+), 12 deletions(-) create mode 100644 crates/tinywasm/src/interpreter/simd.rs diff --git a/crates/cli/src/args.rs b/crates/cli/src/args.rs index 96c3605..a23f1f4 100644 --- a/crates/cli/src/args.rs +++ b/crates/cli/src/args.rs @@ -25,6 +25,7 @@ impl FromStr for WasmArg { "i64" => val.parse::().map_err(|e| format!("invalid argument value for i64: {e:?}"))?.into(), "f32" => val.parse::().map_err(|e| format!("invalid argument value for f32: {e:?}"))?.into(), "f64" => val.parse::().map_err(|e| format!("invalid argument value for f64: {e:?}"))?.into(), + "v128" => val.parse::().map_err(|e| format!("invalid argument value for v128: {e:?}"))?.into(), t => return Err(format!("Invalid arg type: {t}")), }; diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 2cad2e4..0ea406c 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -32,11 +32,12 @@ serde_json={version="1.0"} serde={version="1.0", features=["derive"]} [features] -default=["std", "parser", "logging", "archive"] +default=["std", "parser", "logging", "archive", "simd"] logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] parser=["dep:tinywasm-parser"] archive=["tinywasm-types/archive"] +simd=[] [[test]] name="test-wasm-1" diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 3c579c1..291ab64 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -3,10 +3,15 @@ use super::no_std_floats::NoStdFloatExt; use alloc::{format, rc::Rc, string::ToString}; -use core::ops::ControlFlow; +use core::ops::{ControlFlow, Not}; +use core::simd::cmp::{SimdPartialEq, SimdPartialOrd}; +use core::simd::num::SimdUint; use interpreter::stack::CallFrame; use tinywasm_types::*; +#[cfg(feature = "simd")] +use super::simd::*; + use super::num_helpers::*; use super::stack::{BlockFrame, BlockType, Stack}; use super::values::*; @@ -41,6 +46,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[inline(always)] fn exec_next(&mut self) -> ControlFlow> { use tinywasm_types::Instruction::*; + + #[rustfmt::skip] match self.cf.fetch_instr() { Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} Unreachable => self.exec_unreachable()?, @@ -302,6 +309,75 @@ impl<'store, 'stack> Executor<'store, 'stack> { LocalCopy128(from, to) => self.exec_local_copy::(*from, *to), LocalCopyRef(from, to) => self.exec_local_copy::(*from, *to), + V128Not => self.stack.values.replace_top_same::(|v| Ok(!v)).to_cf()?, + V128And => self.stack.values.calculate_same::(|a, b| Ok(a & b)).to_cf()?, + V128AndNot => self.stack.values.calculate_same::(|a, b| Ok(a & (!b))).to_cf()?, + V128Or => self.stack.values.calculate_same::(|a, b| Ok(a | b)).to_cf()?, + V128Xor => self.stack.values.calculate_same::(|a, b| Ok(a ^ b)).to_cf()?, + V128Bitselect => self.stack.values.calculate_same_3::(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?, + V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_sum() != 0) as i32)).to_cf()?, + + I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, + + I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8).to_ne_bytes())).to_cf()?, + I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16).to_ne_bytes())).to_cf()?, + I32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, + I64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, + F32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, + F64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, + + I8x16Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, + I16x8Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, + I32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, + F32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, + F64x2Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, + I16x8Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, + I32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, + F32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, + F64x2Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + I16x8LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + I32x4LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + I64x2LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + F32x4Lt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + F64x2Lt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + I16x8LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + I32x4LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, + I64x2GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + F32x4Gt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + F64x2Gt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + I16x8GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + I32x4GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + I64x2LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + F32x4Le => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + F64x2Le => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + I16x8GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + I32x4GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, + I64x2GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + F32x4Ge => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + F64x2Ge => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + I16x8LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + I32x4LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + I16x8LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + I32x4LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, + + I8x16GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + I16x8GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + I32x4GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; diff --git a/crates/tinywasm/src/interpreter/mod.rs b/crates/tinywasm/src/interpreter/mod.rs index 0b7df2f..269bcfb 100644 --- a/crates/tinywasm/src/interpreter/mod.rs +++ b/crates/tinywasm/src/interpreter/mod.rs @@ -6,6 +6,9 @@ mod values; #[cfg(not(feature = "std"))] mod no_std_floats; +#[cfg(feature = "simd")] +mod simd; + use crate::{Result, Store}; pub use values::*; diff --git a/crates/tinywasm/src/interpreter/simd.rs b/crates/tinywasm/src/interpreter/simd.rs new file mode 100644 index 0000000..53c64e3 --- /dev/null +++ b/crates/tinywasm/src/interpreter/simd.rs @@ -0,0 +1,18 @@ +pub(super) use core::ops::Neg; + +pub(super) use core::simd::Simd; +pub(super) use core::simd::ToBytes; +pub(super) use core::simd::num::SimdFloat; +pub(super) use core::simd::num::SimdInt; + +macro_rules! impl_wasm_simd_val { + ($($v:ident),*) => { + $( + pub(super) fn $v(f: core::simd::u8x16) -> core::simd::$v { + core::simd::$v::from_ne_bytes(f) + } + )* + }; +} + +impl_wasm_simd_val!(i8x16, i16x8, i32x4, i64x2, f32x4, f64x2); diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index 9830c01..843723a 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -71,6 +71,11 @@ impl ValueStack { T::stack_calculate(self, func) } + #[inline] + pub(crate) fn calculate_same_3(&mut self, func: impl FnOnce(T, T, T) -> Result) -> Result<()> { + T::stack_calculate3(self, func) + } + #[inline] pub(crate) fn calculate( &mut self, @@ -170,11 +175,16 @@ impl ValueStack { match val_type { ValType::I32 => WasmValue::I32(self.pop()), ValType::I64 => WasmValue::I64(self.pop()), - ValType::V128 => WasmValue::V128(self.pop()), ValType::F32 => WasmValue::F32(self.pop()), ValType::F64 => WasmValue::F64(self.pop()), ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.pop())), ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.pop())), + + #[cfg(not(feature = "simd"))] + ValType::V128 => WasmValue::V128(self.pop()), + + #[cfg(feature = "simd")] + ValType::V128 => WasmValue::V128(u128::from_ne_bytes(self.pop::().to_array())), } } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 712baf7..7a2a916 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -5,9 +5,13 @@ use super::stack::{Locals, ValueStack}; pub(crate) type Value32 = u32; pub(crate) type Value64 = u64; -pub(crate) type Value128 = u128; pub(crate) type ValueRef = Option; +#[cfg(feature = "simd")] +pub(crate) type Value128 = core::simd::u8x16; +#[cfg(not(feature = "simd"))] +pub(crate) type Value128 = u128; + #[derive(Debug, Clone, Copy, PartialEq)] /// A untyped WebAssembly value pub enum TinyWasmValue { @@ -106,9 +110,14 @@ impl TinyWasmValue { ValType::I64 => WasmValue::I64(self.unwrap_64() as i64), ValType::F32 => WasmValue::F32(f32::from_bits(self.unwrap_32())), ValType::F64 => WasmValue::F64(f64::from_bits(self.unwrap_64())), - ValType::V128 => WasmValue::V128(self.unwrap_128()), ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.unwrap_ref())), ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.unwrap_ref())), + + #[cfg(feature = "simd")] + ValType::V128 => WasmValue::V128(u128::from_ne_bytes(self.unwrap_128().to_array())), + + #[cfg(not(feature = "simd"))] + ValType::V128 => WasmValue::V128(self.unwrap_128()), } } } @@ -118,11 +127,16 @@ impl From<&WasmValue> for TinyWasmValue { match value { WasmValue::I32(v) => TinyWasmValue::Value32(*v as u32), WasmValue::I64(v) => TinyWasmValue::Value64(*v as u64), - WasmValue::V128(v) => TinyWasmValue::Value128(*v), WasmValue::F32(v) => TinyWasmValue::Value32(v.to_bits()), WasmValue::F64(v) => TinyWasmValue::Value64(v.to_bits()), WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(v.addr()), WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(v.addr()), + + #[cfg(not(feature = "simd"))] + WasmValue::V128(v) => TinyWasmValue::Value128(*v), + + #[cfg(feature = "simd")] + WasmValue::V128(v) => TinyWasmValue::Value128(v.to_ne_bytes().into()), } } } @@ -144,6 +158,9 @@ pub(crate) trait InternalValue: sealed::Sealed + Into { where Self: Sized; fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result) -> Result<()> + where + Self: Sized; + fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result) -> Result<()> where Self: Sized; @@ -202,6 +219,19 @@ macro_rules! impl_internalvalue { return Ok(()) } + #[inline(always)] + fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result) -> Result<()> { + let v3 = stack.$stack.pop(); + let v2 = stack.$stack.pop(); + let v1 = stack.$stack.last_mut(); + let (Some(v1), Some(v2), Some(v3)) = (v1, v2, v3) else { + unreachable!("ValueStack underflow, this is a bug"); + }; + + *v1 = $to_internal(func($to_outer(*v1), $to_outer(v2), $to_outer(v3))?); + return Ok(()) + } + #[inline(always)] fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result) -> Result<()> { let Some(v) = stack.$stack.last_mut() else { diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index d3431e2..72c38cd 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -5,7 +5,7 @@ ))] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)] #![forbid(unsafe_code)] -// #![cfg_attr(feature = "nightly", feature(portable_simd))] +#![cfg_attr(feature = "simd", feature(portable_simd))] //! A tiny WebAssembly Runtime written in Rust //! diff --git a/crates/tinywasm/tests/generated/wasm-3.csv b/crates/tinywasm/tests/generated/wasm-3.csv index ed301e4..26f2937 100644 --- a/crates/tinywasm/tests/generated/wasm-3.csv +++ b/crates/tinywasm/tests/generated/wasm-3.csv @@ -1 +1 @@ -0.9.0-alpha.0,32305,2591,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":126,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":49,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":169,"failed":90},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":118,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":89,"failed":0},{"name":"memory64.wast","passed":14,"failed":53},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":11,"failed":34},{"name":"return_call_indirect.wast","passed":26,"failed":50},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table.wast","passed":47,"failed":9},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":780,"failed":96},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,32305,2598,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":126,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":49,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":169,"failed":90},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":118,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory64.wast","passed":14,"failed":55},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":11,"failed":34},{"name":"return_call_indirect.wast","passed":26,"failed":50},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table.wast","passed":47,"failed":13},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":780,"failed":96},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index c61a02f..e3e30f6 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -206,12 +206,11 @@ pub enum Instruction { F32x4ExtractLane(u8), F32x4ReplaceLane(u8), F64x2ExtractLane(u8), F64x2ReplaceLane(u8), - V128Not, V128And, V128AndNot, V128Or, V128Xor, V128Bitselect, V128AnyTrue, - - I8x16Splat, I8x16Swizzle, I8x16Eq, I8x16Ne, I8x16LtS, I8x16LtU, I8x16GtS, I8x16GtU, I8x16LeS, I8x16LeU, I8x16GeS, I8x16GeU, + V128Not, V128And, V128AndNot, V128Or, V128Xor, V128Bitselect, V128AnyTrue, I8x16Swizzle, + I8x16Splat, I8x16Eq, I8x16Ne, I8x16LtS, I8x16LtU, I8x16GtS, I8x16GtU, I8x16LeS, I8x16LeU, I8x16GeS, I8x16GeU, I16x8Splat, I16x8Eq, I16x8Ne, I16x8LtS, I16x8LtU, I16x8GtS, I16x8GtU, I16x8LeS, I16x8LeU, I16x8GeS, I16x8GeU, I32x4Splat, I32x4Eq, I32x4Ne, I32x4LtS, I32x4LtU, I32x4GtS, I32x4GtU, I32x4LeS, I32x4LeU, I32x4GeS, I32x4GeU, - I64x2Splat, I64x2Eq, I64x2Ne, I64x2LtS, I64x2GtS, I64x2LeS, I64x2GeS, + I64x2Splat, I64x2Eq, I64x2Ne, I64x2LtS, I64x2GtS, I64x2LeS, I64x2GeS, F32x4Splat, F32x4Eq, F32x4Ne, F32x4Lt, F32x4Gt, F32x4Le, F32x4Ge, F64x2Splat, F64x2Eq, F64x2Ne, F64x2Lt, F64x2Gt, F64x2Le, F64x2Ge, From 741a3d6e94970f097d0cd19cbe9f9a7266b67fb4 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 1 Mar 2025 00:34:17 +0100 Subject: [PATCH 04/17] chore: add back simd testsuite Signed-off-by: Henry Gressmann --- Cargo.lock | 6 +- crates/tinywasm/Cargo.toml | 7 +- crates/tinywasm/src/interpreter/executor.rs | 124 +++++++++--------- crates/tinywasm/src/interpreter/simd.rs | 17 +-- crates/tinywasm/src/interpreter/values.rs | 20 ++- crates/tinywasm/tests/generated/wasm-simd.csv | 2 +- crates/tinywasm/tests/test-wasm-simd.rs | 13 ++ crates/types/src/instructions.rs | 2 +- 8 files changed, 108 insertions(+), 83 deletions(-) create mode 100644 crates/tinywasm/tests/test-wasm-simd.rs diff --git a/Cargo.lock b/Cargo.lock index 1178a8a..6aca5b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -674,9 +674,9 @@ dependencies = [ [[package]] name = "wasm-testsuite" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea6edc2d1ffad1d673091e3e3e98961e7c1a8c0f24cbf2431fa02d861e071bd" +checksum = "3439010f90930c46aead98a232d3e38c147d9543db7e6a40289297b2eda13941" dependencies = [ "include_dir", "wast", diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 0ea406c..734a962 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false libm={version="0.2", default-features=false} [dev-dependencies] -wasm-testsuite={version="0.4.4"} +wasm-testsuite={version="0.4.5"} indexmap="2.7" wast={workspace=true} wat={workspace=true} @@ -78,6 +78,11 @@ name="test-wasm-relaxed-simd" harness=false test=false +[[test]] +name="test-wasm-simd" +harness=false +test=false + [[test]] name="test-wast" harness=false diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 291ab64..100075b 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -3,7 +3,7 @@ use super::no_std_floats::NoStdFloatExt; use alloc::{format, rc::Rc, string::ToString}; -use core::ops::{ControlFlow, Not}; +use core::ops::ControlFlow; use core::simd::cmp::{SimdPartialEq, SimdPartialOrd}; use core::simd::num::SimdUint; use interpreter::stack::CallFrame; @@ -316,67 +316,71 @@ impl<'store, 'stack> Executor<'store, 'stack> { V128Xor => self.stack.values.calculate_same::(|a, b| Ok(a ^ b)).to_cf()?, V128Bitselect => self.stack.values.calculate_same_3::(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?, V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_sum() != 0) as i32)).to_cf()?, - I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, - I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8).to_ne_bytes())).to_cf()?, - I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16).to_ne_bytes())).to_cf()?, - I32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, - I64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, - F32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, - F64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v).to_ne_bytes())).to_cf()?, - - I8x16Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, - I16x8Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, - I32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, - F32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, - F64x2Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, - I16x8Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, - I32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, - F32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, - F64x2Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - I16x8LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - I32x4LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - I64x2LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - F32x4Lt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - F64x2Lt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - I16x8LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - I32x4LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?, - I64x2GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - F32x4Gt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - F64x2Gt => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - I16x8GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - I32x4GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - I64x2LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - F32x4Le => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - F64x2Le => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - I16x8GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - I32x4GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?, - I64x2GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, - F32x4Ge => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, - F64x2Ge => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - I16x8LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - I32x4LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - I16x8LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - I32x4LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?, - - I8x16GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, - I16x8GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, - I32x4GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?, + I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8))).to_cf()?, + I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16))).to_cf()?, + I32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + I64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + F32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + F64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + + I8x16Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + I16x8Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + I32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + F32x4Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + F64x2Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + + I8x16Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + I16x8Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + I32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + F32x4Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + F64x2Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + + I8x16LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + I16x8LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + I32x4LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + I64x2LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + I8x16LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + I16x8LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + I32x4LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + F32x4Lt => self.stack.values.calculate::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + F64x2Lt => self.stack.values.calculate::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + + I64x2GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + F32x4Gt => self.stack.values.calculate::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + F64x2Gt => self.stack.values.calculate::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + + I8x16GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + I16x8GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + I32x4GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + I64x2LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + F32x4Le => self.stack.values.calculate::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + F64x2Le => self.stack.values.calculate::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + + I8x16GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + I16x8GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + I32x4GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + I64x2GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + F32x4Ge => self.stack.values.calculate::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + F64x2Ge => self.stack.values.calculate::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + + I8x16LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + I16x8LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + I32x4LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + + I8x16LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + I16x8LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + I32x4LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + + I8x16GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + I16x8GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + I32x4GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + + I8x16Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + I16x8Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + I32x4Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + I64x2Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; diff --git a/crates/tinywasm/src/interpreter/simd.rs b/crates/tinywasm/src/interpreter/simd.rs index 53c64e3..2042bc6 100644 --- a/crates/tinywasm/src/interpreter/simd.rs +++ b/crates/tinywasm/src/interpreter/simd.rs @@ -1,18 +1,3 @@ -pub(super) use core::ops::Neg; - -pub(super) use core::simd::Simd; -pub(super) use core::simd::ToBytes; pub(super) use core::simd::num::SimdFloat; pub(super) use core::simd::num::SimdInt; - -macro_rules! impl_wasm_simd_val { - ($($v:ident),*) => { - $( - pub(super) fn $v(f: core::simd::u8x16) -> core::simd::$v { - core::simd::$v::from_ne_bytes(f) - } - )* - }; -} - -impl_wasm_simd_val!(i8x16, i16x8, i32x4, i64x2, f32x4, f64x2); +pub(super) use core::simd::*; diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 7a2a916..98d40af 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -1,7 +1,7 @@ use crate::Result; -use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, WasmValue}; use super::stack::{Locals, ValueStack}; +use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, WasmValue}; pub(crate) type Value32 = u32; pub(crate) type Value64 = u64; @@ -272,3 +272,21 @@ impl_internalvalue! { Value128, stack_128, locals_128, Value128, Value128, |v| v, |v| v ValueRef, stack_ref, locals_ref, ValueRef, ValueRef, |v| v, |v| v } + +#[cfg(feature = "simd")] +use core::simd::{num::SimdUint, *}; + +#[cfg(feature = "simd")] +impl_internalvalue! { + Value128, stack_128, locals_128, u8x16, u128, |v: u128| v.to_ne_bytes().into(), |v: u8x16| u128::from_ne_bytes(v.into()) + Value128, stack_128, locals_128, u8x16, i8x16, |v: i8x16| v.to_ne_bytes(), |v: u8x16| v.cast() + Value128, stack_128, locals_128, u8x16, i16x8, |v: i16x8| v.to_ne_bytes(), |v: u8x16| i16x8::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, i32x4, |v: i32x4| v.to_ne_bytes(), |v: u8x16| i32x4::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, i64x2, |v: i64x2| v.to_ne_bytes(), |v: u8x16| i64x2::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, f32x4, |v: f32x4| v.to_ne_bytes(), |v: u8x16| f32x4::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, f64x2, |v: f64x2| v.to_ne_bytes(), |v: u8x16| f64x2::from_ne_bytes(v) + + Value128, stack_128, locals_128, u8x16, u16x8, |v: u16x8| v.to_ne_bytes(), |v: u8x16| u16x8::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, u32x4, |v: u32x4| v.to_ne_bytes(), |v: u8x16| u32x4::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, u64x2, |v: u64x2| v.to_ne_bytes(), |v: u8x16| u64x2::from_ne_bytes(v) +} diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index d695dfa..210564b 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,1741,24238,[{"name":"simd_address.wast","passed":7,"failed":42},{"name":"simd_align.wast","passed":93,"failed":7},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":30,"failed":139},{"name":"simd_boolean.wast","passed":18,"failed":259},{"name":"simd_const.wast","passed":551,"failed":206},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":18,"failed":772},{"name":"simd_f32x4_arith.wast","passed":19,"failed":1803},{"name":"simd_f32x4_cmp.wast","passed":26,"failed":2581},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":25,"failed":176},{"name":"simd_f64x2.wast","passed":10,"failed":793},{"name":"simd_f64x2_arith.wast","passed":19,"failed":1806},{"name":"simd_f64x2_cmp.wast","passed":26,"failed":2659},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":25,"failed":176},{"name":"simd_i16x8_arith.wast","passed":13,"failed":181},{"name":"simd_i16x8_arith2.wast","passed":21,"failed":151},{"name":"simd_i16x8_cmp.wast","passed":32,"failed":433},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":13,"failed":187},{"name":"simd_i64x2_arith2.wast","passed":4,"failed":21},{"name":"simd_i64x2_cmp.wast","passed":11,"failed":102},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":10,"failed":121},{"name":"simd_i8x16_arith2.wast","passed":27,"failed":184},{"name":"simd_i8x16_cmp.wast","passed":32,"failed":413},{"name":"simd_i8x16_sat_arith.wast","passed":26,"failed":188},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":209,"failed":266},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":24,"failed":15},{"name":"simd_load16_lane.wast","passed":4,"failed":32},{"name":"simd_load32_lane.wast","passed":4,"failed":20},{"name":"simd_load64_lane.wast","passed":4,"failed":12},{"name":"simd_load8_lane.wast","passed":4,"failed":48},{"name":"simd_load_extend.wast","passed":24,"failed":80},{"name":"simd_load_splat.wast","passed":17,"failed":109},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_splat.wast","passed":37,"failed":148},{"name":"simd_store.wast","passed":20,"failed":8},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] +0.9.0-alpha.0,1808,24172,[{"name":"simd_address.wast","passed":7,"failed":42},{"name":"simd_align.wast","passed":92,"failed":8},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":30,"failed":139},{"name":"simd_boolean.wast","passed":123,"failed":154},{"name":"simd_const.wast","passed":551,"failed":206},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":18,"failed":772},{"name":"simd_f32x4_arith.wast","passed":19,"failed":1803},{"name":"simd_f32x4_cmp.wast","passed":26,"failed":2581},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":25,"failed":176},{"name":"simd_f64x2.wast","passed":10,"failed":793},{"name":"simd_f64x2_arith.wast","passed":19,"failed":1806},{"name":"simd_f64x2_cmp.wast","passed":26,"failed":2659},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":25,"failed":176},{"name":"simd_i16x8_arith.wast","passed":13,"failed":181},{"name":"simd_i16x8_arith2.wast","passed":21,"failed":151},{"name":"simd_i16x8_cmp.wast","passed":32,"failed":433},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":13,"failed":187},{"name":"simd_i64x2_arith2.wast","passed":4,"failed":21},{"name":"simd_i64x2_cmp.wast","passed":11,"failed":102},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":10,"failed":121},{"name":"simd_i8x16_arith2.wast","passed":27,"failed":184},{"name":"simd_i8x16_cmp.wast","passed":32,"failed":413},{"name":"simd_i8x16_sat_arith.wast","passed":26,"failed":188},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":200,"failed":275},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":22,"failed":17},{"name":"simd_load16_lane.wast","passed":4,"failed":32},{"name":"simd_load32_lane.wast","passed":4,"failed":20},{"name":"simd_load64_lane.wast","passed":4,"failed":12},{"name":"simd_load8_lane.wast","passed":4,"failed":48},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":26,"failed":159},{"name":"simd_store.wast","passed":11,"failed":17},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] diff --git a/crates/tinywasm/tests/test-wasm-simd.rs b/crates/tinywasm/tests/test-wasm-simd.rs new file mode 100644 index 0000000..d8f15ea --- /dev/null +++ b/crates/tinywasm/tests/test-wasm-simd.rs @@ -0,0 +1,13 @@ +mod testsuite; +use eyre::Result; +use testsuite::TestSuite; +use wasm_testsuite::data::{Proposal, proposal}; + +fn main() -> Result<()> { + TestSuite::set_log_level(log::LevelFilter::Off); + + let mut test_suite = TestSuite::new(); + test_suite.run_files(proposal(&Proposal::Simd))?; + test_suite.save_csv("./tests/generated/wasm-simd.csv", env!("CARGO_PKG_VERSION"))?; + test_suite.report_status() +} diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index e3e30f6..24116e8 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -216,7 +216,7 @@ pub enum Instruction { I8x16Abs, I8x16Neg, I8x16AllTrue, I8x16Bitmask, I8x16Shl, I8x16ShrS, I8x16ShrU, I8x16Add, I8x16Sub, I8x16MinS, I8x16MinU, I8x16MaxS, I8x16MaxU, I16x8Abs, I16x8Neg, I16x8AllTrue, I16x8Bitmask, I16x8Shl, I16x8ShrS, I16x8ShrU, I16x8Add, I16x8Sub, I16x8MinS, I16x8MinU, I16x8MaxS, I16x8MaxU, - I32x4Abs, I32x4Neg, I32x4AllTrue, I32x4Bitmask, I32x4Shl, I32x4ShrS, I32x4ShrU, I32x4Add, I32x4Sub, I32x4MinS, I32x4MinU, I32x4MaxS, I32x4MaxU, + I32x4Abs, I32x4Neg, I32x4AllTrue, I32x4Bitmask, I32x4Shl, I32x4ShrS, I32x4ShrU, I32x4Add, I32x4Sub, I32x4MinS, I32x4MinU, I32x4MaxS, I32x4MaxU, I64x2Abs, I64x2Neg, I64x2AllTrue, I64x2Bitmask, I64x2Shl, I64x2ShrS, I64x2ShrU, I64x2Add, I64x2Sub, I64x2Mul, I8x16NarrowI16x8S, I8x16NarrowI16x8U, I8x16AddSatS, I8x16AddSatU, I8x16SubSatS, I8x16SubSatU, I8x16AvgrU, From afc76e44457975e3d20b3a490c5029dec6f4983a Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 1 Mar 2025 19:49:41 +0100 Subject: [PATCH 05/17] feat: add most basic simd instructions Signed-off-by: Henry Gressmann --- crates/cli/src/args.rs | 2 +- crates/parser/src/conversion.rs | 1 + crates/parser/src/visit.rs | 10 +- crates/tinywasm/src/interpreter/executor.rs | 162 +++++++++++++++++- crates/tinywasm/src/interpreter/mod.rs | 3 - crates/tinywasm/src/interpreter/simd.rs | 3 - .../src/interpreter/stack/call_stack.rs | 7 +- .../src/interpreter/stack/value_stack.rs | 2 +- crates/tinywasm/src/interpreter/values.rs | 31 ++-- crates/tinywasm/src/store/memory.rs | 45 +++-- crates/tinywasm/tests/generated/wasm-simd.csv | 2 +- crates/tinywasm/tests/testsuite/util.rs | 28 +-- crates/types/src/instructions.rs | 1 + crates/types/src/lib.rs | 2 +- crates/types/src/value.rs | 8 +- 15 files changed, 245 insertions(+), 62 deletions(-) delete mode 100644 crates/tinywasm/src/interpreter/simd.rs diff --git a/crates/cli/src/args.rs b/crates/cli/src/args.rs index a23f1f4..1fec2d5 100644 --- a/crates/cli/src/args.rs +++ b/crates/cli/src/args.rs @@ -25,7 +25,7 @@ impl FromStr for WasmArg { "i64" => val.parse::().map_err(|e| format!("invalid argument value for i64: {e:?}"))?.into(), "f32" => val.parse::().map_err(|e| format!("invalid argument value for f32: {e:?}"))?.into(), "f64" => val.parse::().map_err(|e| format!("invalid argument value for f64: {e:?}"))?.into(), - "v128" => val.parse::().map_err(|e| format!("invalid argument value for v128: {e:?}"))?.into(), + "v128" => val.parse::().map_err(|e| format!("invalid argument value for v128: {e:?}"))?.into(), t => return Err(format!("Invalid arg type: {t}")), }; diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 86548d6..a4e3b35 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -261,6 +261,7 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result Ok(ConstInstruction::I64Const(*value)), wasmparser::Operator::F32Const { value } => Ok(ConstInstruction::F32Const(f32::from_bits(value.bits()))), wasmparser::Operator::F64Const { value } => Ok(ConstInstruction::F64Const(f64::from_bits(value.bits()))), + wasmparser::Operator::V128Const { value } => Ok(ConstInstruction::V128Const(value.i128())), wasmparser::Operator::GlobalGet { global_index } => Ok(ConstInstruction::GlobalGet(*global_index)), op => Err(crate::ParseError::UnsupportedOperator(format!("Unsupported const instruction: {op:?}"))), } diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 2830d3a..270f6c6 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -111,7 +111,7 @@ macro_rules! define_mem_operands_simd_lane { pub(crate) struct FunctionBuilder { validator: FuncValidator, instructions: Vec, - v128_constants: Vec, + v128_constants: Vec, label_ptrs: Vec, local_addr_map: Vec, errors: Vec, @@ -530,12 +530,12 @@ impl wasmparser::VisitSimdOperator<'_> for FunctionBuild } fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { - self.v128_constants.push(u128::from_le_bytes(lanes)); - self.instructions.push(Instruction::I8x16Shuffle(self.v128_constants.len() as u32 - 1)); + self.instructions.push(Instruction::I8x16Shuffle(self.v128_constants.len() as u32)); + self.v128_constants.push(i128::from_le_bytes(lanes)); } fn visit_v128_const(&mut self, value: wasmparser::V128) -> Self::Output { - self.v128_constants.push(value.i128() as u128); - self.instructions.push(Instruction::V128Const(self.v128_constants.len() as u32 - 1)); + self.instructions.push(Instruction::V128Const(self.v128_constants.len() as u32)); + self.v128_constants.push(value.i128()); } } diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 100075b..932fad9 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -3,14 +3,21 @@ use super::no_std_floats::NoStdFloatExt; use alloc::{format, rc::Rc, string::ToString}; -use core::ops::ControlFlow; -use core::simd::cmp::{SimdPartialEq, SimdPartialOrd}; -use core::simd::num::SimdUint; +use core::ops::{ControlFlow, IndexMut, Shl, Shr}; + use interpreter::stack::CallFrame; use tinywasm_types::*; #[cfg(feature = "simd")] -use super::simd::*; +mod simd { + #[cfg(feature = "std")] + pub(super) use crate::std::simd::StdFloat; + pub(super) use core::simd::cmp::{SimdOrd, SimdPartialEq, SimdPartialOrd}; + pub(super) use core::simd::num::{SimdFloat, SimdInt, SimdUint}; + pub(super) use core::simd::*; +} +#[cfg(feature = "simd")] +use simd::*; use super::num_helpers::*; use super::stack::{BlockFrame, BlockType, Stack}; @@ -315,8 +322,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { V128Or => self.stack.values.calculate_same::(|a, b| Ok(a | b)).to_cf()?, V128Xor => self.stack.values.calculate_same::(|a, b| Ok(a ^ b)).to_cf()?, V128Bitselect => self.stack.values.calculate_same_3::(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?, - V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_sum() != 0) as i32)).to_cf()?, + V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_or() != 0) as i32)).to_cf()?, I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, + V128Load(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| v)?, + V128Store(arg) => self.exec_mem_store::(arg.mem_addr(), arg.offset(), |v| v)?, + V128Const(arg) => self.exec_const::( self.cf.data().v128_constants[*arg as usize].to_le_bytes().into()), + + V128Load8Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + V128Load16Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + V128Load32Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + V128Load64Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8))).to_cf()?, I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16))).to_cf()?, @@ -373,6 +388,10 @@ impl<'store, 'stack> Executor<'store, 'stack> { I16x8LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, I32x4LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + I8x16GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + I16x8GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + I32x4GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + I8x16GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, I16x8GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, I32x4GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, @@ -382,6 +401,98 @@ impl<'store, 'stack> Executor<'store, 'stack> { I32x4Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, I64x2Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + I8x16Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + I16x8Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + I32x4Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + I64x2Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + + I8x16AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, + I16x8AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, + I32x4AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, + I64x2AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, + + I8x16Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + I16x8Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + I32x4Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + I64x2Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + + I8x16Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, + I16x8Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, + I32x4Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, + I64x2Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, + + I8x16ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I16x8ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I32x4ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I64x2ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + + I8x16ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I16x8ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I32x4ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I64x2ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + + I8x16Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + I16x8Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + I32x4Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + I64x2Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + + I8x16Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + I16x8Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + I32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + I64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + + I8x16MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + I16x8MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + I32x4MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + + I8x16MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + I16x8MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + I32x4MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + + I8x16MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + I16x8MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + I32x4MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + + I8x16MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + I16x8MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + I32x4MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + + I64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + + I8x16AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + I16x8AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + I8x16AddSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + I16x8AddSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + I8x16SubSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + I16x8SubSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + I8x16SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + I16x8SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + + F32x4Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, + F64x2Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, + F32x4Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, + F64x2Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, + F32x4Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, + F64x2Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, + F32x4Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, + F64x2Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, + F32x4Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, + F64x2Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, + F32x4Sqrt => self.stack.values.replace_top_same::(|v| Ok(v.sqrt())).to_cf()?, + F64x2Sqrt => self.stack.values.replace_top_same::(|v| Ok(v.sqrt())).to_cf()?, + F32x4Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + F64x2Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + F32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + F64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + F32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + F64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + F32x4Div => self.stack.values.calculate_same::(|a, b| Ok(a / b)).to_cf()?, + F64x2Div => self.stack.values.calculate_same::(|a, b| Ok(a / b)).to_cf()?, + F32x4Min => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + F64x2Min => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + F32x4Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + F64x2Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; @@ -689,6 +800,47 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(()) } + fn exec_mem_load_lane< + LOAD: MemLoadable, + INTO: InternalValue + IndexMut, + const LOAD_SIZE: usize, + >( + &mut self, + mem_addr: tinywasm_types::MemAddr, + offset: u64, + lanes: u8, + ) -> ControlFlow> { + let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); + let mut imm = self.stack.values.pop::(); + let val = self.stack.values.pop::() as u64; + let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else { + cold(); + return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds { + offset: val as usize, + len: LOAD_SIZE, + max: 0, + }))); + }; + let val = mem.load_as::(addr).to_cf()?; + imm[lanes as usize] = val; + self.stack.values.push(imm); + ControlFlow::Continue(()) + } + + // fn mem_load, const LOAD_SIZE: usize, TARGET: InternalValue>( + // &mut self, + // mem_addr: tinywasm_types::MemAddr, + // offset: u64, + // ) -> Result { + // let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); + // let val = self.stack.values.pop::() as u64; + // let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else { + // cold(); + // return Err(Error::Trap(Trap::MemoryOutOfBounds { offset: val as usize, len: LOAD_SIZE, max: 0 })); + // }; + // mem.load_as::(addr) + // } + fn exec_mem_load, const LOAD_SIZE: usize, TARGET: InternalValue>( &mut self, mem_addr: tinywasm_types::MemAddr, diff --git a/crates/tinywasm/src/interpreter/mod.rs b/crates/tinywasm/src/interpreter/mod.rs index 269bcfb..0b7df2f 100644 --- a/crates/tinywasm/src/interpreter/mod.rs +++ b/crates/tinywasm/src/interpreter/mod.rs @@ -6,9 +6,6 @@ mod values; #[cfg(not(feature = "std"))] mod no_std_floats; -#[cfg(feature = "simd")] -mod simd; - use crate::{Result, Store}; pub use values::*; diff --git a/crates/tinywasm/src/interpreter/simd.rs b/crates/tinywasm/src/interpreter/simd.rs deleted file mode 100644 index 2042bc6..0000000 --- a/crates/tinywasm/src/interpreter/simd.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub(super) use core::simd::num::SimdFloat; -pub(super) use core::simd::num::SimdInt; -pub(super) use core::simd::*; diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index 9b6c3fd..25ad81f 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -7,7 +7,7 @@ use crate::{Error, unlikely}; use alloc::boxed::Box; use alloc::{rc::Rc, vec, vec::Vec}; -use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmValue}; +use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmFunctionData, WasmValue}; pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024; @@ -70,6 +70,11 @@ impl CallFrame { self.instr_ptr } + #[inline] + pub(crate) fn data(&self) -> &WasmFunctionData { + &self.func_instance.data + } + #[inline] pub(crate) fn incr_instr_ptr(&mut self) { self.instr_ptr += 1; diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index 843723a..bb5b2ea 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -184,7 +184,7 @@ impl ValueStack { ValType::V128 => WasmValue::V128(self.pop()), #[cfg(feature = "simd")] - ValType::V128 => WasmValue::V128(u128::from_ne_bytes(self.pop::().to_array())), + ValType::V128 => WasmValue::V128(i128::from_le_bytes(self.pop::().to_array())), } } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 98d40af..335da59 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -10,7 +10,7 @@ pub(crate) type ValueRef = Option; #[cfg(feature = "simd")] pub(crate) type Value128 = core::simd::u8x16; #[cfg(not(feature = "simd"))] -pub(crate) type Value128 = u128; +pub(crate) type Value128 = i128; #[derive(Debug, Clone, Copy, PartialEq)] /// A untyped WebAssembly value @@ -114,7 +114,7 @@ impl TinyWasmValue { ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.unwrap_ref())), #[cfg(feature = "simd")] - ValType::V128 => WasmValue::V128(u128::from_ne_bytes(self.unwrap_128().to_array())), + ValType::V128 => WasmValue::V128(i128::from_le_bytes(self.unwrap_128().to_array())), #[cfg(not(feature = "simd"))] ValType::V128 => WasmValue::V128(self.unwrap_128()), @@ -136,7 +136,7 @@ impl From<&WasmValue> for TinyWasmValue { WasmValue::V128(v) => TinyWasmValue::Value128(*v), #[cfg(feature = "simd")] - WasmValue::V128(v) => TinyWasmValue::Value128(v.to_ne_bytes().into()), + WasmValue::V128(v) => TinyWasmValue::Value128(v.to_le_bytes().into()), } } } @@ -269,8 +269,8 @@ impl_internalvalue! { Value64, stack_64, locals_64, u64, i64, |v| v as u64, |v| v as i64 Value32, stack_32, locals_32, u32, f32, f32::to_bits, f32::from_bits Value64, stack_64, locals_64, u64, f64, f64::to_bits, f64::from_bits - Value128, stack_128, locals_128, Value128, Value128, |v| v, |v| v ValueRef, stack_ref, locals_ref, ValueRef, ValueRef, |v| v, |v| v + Value128, stack_128, locals_128, Value128, Value128, |v| v, |v| v } #[cfg(feature = "simd")] @@ -278,15 +278,16 @@ use core::simd::{num::SimdUint, *}; #[cfg(feature = "simd")] impl_internalvalue! { - Value128, stack_128, locals_128, u8x16, u128, |v: u128| v.to_ne_bytes().into(), |v: u8x16| u128::from_ne_bytes(v.into()) - Value128, stack_128, locals_128, u8x16, i8x16, |v: i8x16| v.to_ne_bytes(), |v: u8x16| v.cast() - Value128, stack_128, locals_128, u8x16, i16x8, |v: i16x8| v.to_ne_bytes(), |v: u8x16| i16x8::from_ne_bytes(v) - Value128, stack_128, locals_128, u8x16, i32x4, |v: i32x4| v.to_ne_bytes(), |v: u8x16| i32x4::from_ne_bytes(v) - Value128, stack_128, locals_128, u8x16, i64x2, |v: i64x2| v.to_ne_bytes(), |v: u8x16| i64x2::from_ne_bytes(v) - Value128, stack_128, locals_128, u8x16, f32x4, |v: f32x4| v.to_ne_bytes(), |v: u8x16| f32x4::from_ne_bytes(v) - Value128, stack_128, locals_128, u8x16, f64x2, |v: f64x2| v.to_ne_bytes(), |v: u8x16| f64x2::from_ne_bytes(v) - - Value128, stack_128, locals_128, u8x16, u16x8, |v: u16x8| v.to_ne_bytes(), |v: u8x16| u16x8::from_ne_bytes(v) - Value128, stack_128, locals_128, u8x16, u32x4, |v: u32x4| v.to_ne_bytes(), |v: u8x16| u32x4::from_ne_bytes(v) - Value128, stack_128, locals_128, u8x16, u64x2, |v: u64x2| v.to_ne_bytes(), |v: u8x16| u64x2::from_ne_bytes(v) + Value128, stack_128, locals_128, u8x16, i128, |v: i128| v.to_le_bytes().into(), |v: u8x16| i128::from_le_bytes(v.into()) + Value128, stack_128, locals_128, u8x16, u128, |v: u128| v.to_le_bytes().into(), |v: u8x16| u128::from_le_bytes(v.into()) + Value128, stack_128, locals_128, u8x16, i8x16, |v: i8x16| v.to_le_bytes(), |v: u8x16| v.cast() + Value128, stack_128, locals_128, u8x16, i16x8, |v: i16x8| v.to_le_bytes(), |v: u8x16| i16x8::from_le_bytes(v) + Value128, stack_128, locals_128, u8x16, i32x4, |v: i32x4| v.to_le_bytes(), |v: u8x16| i32x4::from_le_bytes(v) + Value128, stack_128, locals_128, u8x16, i64x2, |v: i64x2| v.to_le_bytes(), |v: u8x16| i64x2::from_le_bytes(v) + Value128, stack_128, locals_128, u8x16, f32x4, |v: f32x4| v.to_le_bytes(), |v: u8x16| f32x4::from_le_bytes(v) + Value128, stack_128, locals_128, u8x16, f64x2, |v: f64x2| v.to_le_bytes(), |v: u8x16| f64x2::from_le_bytes(v) + + Value128, stack_128, locals_128, u8x16, u16x8, |v: u16x8| v.to_le_bytes(), |v: u8x16| u16x8::from_le_bytes(v) + Value128, stack_128, locals_128, u8x16, u32x4, |v: u32x4| v.to_le_bytes(), |v: u8x16| u32x4::from_le_bytes(v) + Value128, stack_128, locals_128, u8x16, u64x2, |v: u64x2| v.to_le_bytes(), |v: u8x16| u64x2::from_le_bytes(v) } diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index d204c67..a1c7994 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -2,7 +2,10 @@ use alloc::vec; use alloc::vec::Vec; use tinywasm_types::{MemoryType, ModuleInstanceAddr}; -use crate::{Error, Result, cold, log}; +use crate::{Error, Result, cold, interpreter::Value128, log}; + +#[cfg(feature = "simd")] +use core::simd::ToBytes; /// A WebAssembly Memory Instance /// @@ -80,7 +83,7 @@ impl MemoryInstance { return Err(self.trap_oob(addr, SIZE)); } - Ok(T::from_le_bytes(match self.data[addr..end].try_into() { + Ok(T::from_mem_bytes(match self.data[addr..end].try_into() { Ok(bytes) => bytes, Err(_) => return Err(self.trap_oob(addr, SIZE)), })) @@ -158,30 +161,52 @@ pub(crate) trait MemStorable { /// A trait for types that can be loaded from memory pub(crate) trait MemLoadable: Sized + Copy { /// Load a value from memory - fn from_le_bytes(bytes: [u8; N]) -> Self; + fn from_mem_bytes(bytes: [u8; N]) -> Self; } macro_rules! impl_mem_traits { - ($($type:ty, $size:expr),*) => { + ($($ty:ty, $size:expr),*) => { $( - impl MemLoadable<$size> for $type { + impl MemLoadable<$size> for $ty { #[inline(always)] - fn from_le_bytes(bytes: [u8; $size]) -> Self { - <$type>::from_le_bytes(bytes) + fn from_mem_bytes(bytes: [u8; $size]) -> Self { + <$ty>::from_le_bytes(bytes.into()) } } - impl MemStorable<$size> for $type { + impl MemStorable<$size> for $ty { #[inline(always)] fn to_mem_bytes(self) -> [u8; $size] { - self.to_ne_bytes() + self.to_le_bytes().into() } } )* } } -impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, u128, 16, i128, 16); +impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, Value128, 16); + +#[cfg(feature = "simd")] +impl_mem_traits!( + core::simd::i8x16, + 16, + core::simd::i16x8, + 16, + core::simd::i32x4, + 16, + core::simd::i64x2, + 16, + core::simd::u16x8, + 16, + core::simd::u32x4, + 16, + core::simd::u64x2, + 16, + core::simd::f32x4, + 16, + core::simd::f64x2, + 16 +); #[cfg(test)] mod memory_instance_tests { diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index 210564b..6f37f4d 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,1808,24172,[{"name":"simd_address.wast","passed":7,"failed":42},{"name":"simd_align.wast","passed":92,"failed":8},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":30,"failed":139},{"name":"simd_boolean.wast","passed":123,"failed":154},{"name":"simd_const.wast","passed":551,"failed":206},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":18,"failed":772},{"name":"simd_f32x4_arith.wast","passed":19,"failed":1803},{"name":"simd_f32x4_cmp.wast","passed":26,"failed":2581},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":25,"failed":176},{"name":"simd_f64x2.wast","passed":10,"failed":793},{"name":"simd_f64x2_arith.wast","passed":19,"failed":1806},{"name":"simd_f64x2_cmp.wast","passed":26,"failed":2659},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":25,"failed":176},{"name":"simd_i16x8_arith.wast","passed":13,"failed":181},{"name":"simd_i16x8_arith2.wast","passed":21,"failed":151},{"name":"simd_i16x8_cmp.wast","passed":32,"failed":433},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":13,"failed":187},{"name":"simd_i64x2_arith2.wast","passed":4,"failed":21},{"name":"simd_i64x2_cmp.wast","passed":11,"failed":102},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":10,"failed":121},{"name":"simd_i8x16_arith2.wast","passed":27,"failed":184},{"name":"simd_i8x16_cmp.wast","passed":32,"failed":413},{"name":"simd_i8x16_sat_arith.wast","passed":26,"failed":188},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":200,"failed":275},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":22,"failed":17},{"name":"simd_load16_lane.wast","passed":4,"failed":32},{"name":"simd_load32_lane.wast","passed":4,"failed":20},{"name":"simd_load64_lane.wast","passed":4,"failed":12},{"name":"simd_load8_lane.wast","passed":4,"failed":48},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":26,"failed":159},{"name":"simd_store.wast","passed":11,"failed":17},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] +0.9.0-alpha.0,14613,11367,[{"name":"simd_address.wast","passed":48,"failed":1},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":241,"failed":36},{"name":"simd_const.wast","passed":751,"failed":6},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1357,"failed":465},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1360,"failed":465},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":138,"failed":56},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":138,"failed":56},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":148,"failed":63},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":213,"failed":262},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":34,"failed":5},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":157,"failed":28},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index f8f862b..91a1e41 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -1,9 +1,9 @@ use std::panic::{self, AssertUnwindSafe}; -use eyre::{bail, eyre, Result}; +use eyre::{Result, bail, eyre}; use tinywasm_types::{ExternRef, FuncRef, ModuleInstanceAddr, TinyWasmModule, ValType, WasmValue}; use wasm_testsuite::wast; -use wasm_testsuite::wast::{core::AbstractHeapType, QuoteWat}; +use wasm_testsuite::wast::{QuoteWat, core::AbstractHeapType}; pub fn try_downcast_panic(panic: Box) -> String { let info = panic.downcast_ref::().or(None).map(ToString::to_string).clone(); @@ -96,7 +96,7 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result WasmValue::F32(f32::from_bits(f.bits)), F64(f) => WasmValue::F64(f64::from_bits(f.bits)), @@ -117,19 +117,21 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result u128 { - match i { +fn wast_i128_to_i128(i: wast::core::V128Pattern) -> i128 { + let res: Vec = match i { wast::core::V128Pattern::F32x4(f) => { - f.iter().fold(0, |acc, &f| (acc << 32) | nanpattern2tinywasmvalue(f).unwrap().as_f32().unwrap() as u128) + f.iter().map(|v| nanpattern2tinywasmvalue(*v).unwrap().as_f32().unwrap().to_le_bytes()).flatten().collect() } wast::core::V128Pattern::F64x2(f) => { - f.iter().fold(0, |acc, &f| (acc << 64) | nanpattern2tinywasmvalue(f).unwrap().as_f64().unwrap() as u128) + f.iter().map(|v| nanpattern2tinywasmvalue(*v).unwrap().as_f64().unwrap().to_le_bytes()).flatten().collect() } - wast::core::V128Pattern::I16x8(f) => f.iter().fold(0, |acc, &f| (acc << 16) | f as u128), - wast::core::V128Pattern::I32x4(f) => f.iter().fold(0, |acc, &f| (acc << 32) | f as u128), - wast::core::V128Pattern::I64x2(f) => f.iter().fold(0, |acc, &f| (acc << 64) | f as u128), - wast::core::V128Pattern::I8x16(f) => f.iter().fold(0, |acc, &f| (acc << 8) | f as u128), - } + wast::core::V128Pattern::I16x8(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), + wast::core::V128Pattern::I32x4(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), + wast::core::V128Pattern::I64x2(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), + wast::core::V128Pattern::I8x16(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), + }; + + i128::from_le_bytes(res.try_into().unwrap()) } fn wastret2tinywasmvalue(ret: wast::WastRet) -> Result { @@ -137,7 +139,7 @@ fn wastret2tinywasmvalue(ret: wast::WastRet) -> Result nanpattern2tinywasmvalue(f)?, F64(f) => nanpattern2tinywasmvalue(f)?, diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 24116e8..593af2f 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -36,6 +36,7 @@ pub enum ConstInstruction { I64Const(i64), F32Const(f32), F64Const(f64), + V128Const(i128), GlobalGet(GlobalAddr), RefFunc(Option), RefExtern(Option), diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index d9f2234..470c631 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -259,7 +259,7 @@ pub struct WasmFunction { #[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct WasmFunctionData { - pub v128_constants: Box<[u128]>, + pub v128_constants: Box<[i128]>, } /// A WebAssembly Module Export diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index 01a31d5..a9498cc 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -17,7 +17,7 @@ pub enum WasmValue { /// A 64-bit float. F64(f64), // /// A 128-bit vector - V128(u128), + V128(i128), RefExtern(ExternRef), RefFunc(FuncRef), @@ -112,6 +112,7 @@ impl WasmValue { Self::I64(i) => ConstInstruction::I64Const(*i), Self::F32(i) => ConstInstruction::F32Const(*i), Self::F64(i) => ConstInstruction::F64Const(*i), + Self::V128(i) => ConstInstruction::V128Const(*i), Self::RefFunc(i) => ConstInstruction::RefFunc(i.addr()), _ => unimplemented!("no const_instr for {:?}", self), } @@ -137,6 +138,7 @@ impl WasmValue { match (self, other) { (Self::I32(a), Self::I32(b)) => a == b, (Self::I64(a), Self::I64(b)) => a == b, + (Self::V128(a), Self::V128(b)) => a == b, (Self::RefExtern(addr), Self::RefExtern(addr2)) => addr == addr2, (Self::RefFunc(addr), Self::RefFunc(addr2)) => addr == addr2, (Self::F32(a), Self::F32(b)) => { @@ -190,7 +192,7 @@ impl WasmValue { } #[doc(hidden)] - pub fn as_v128(&self) -> Option { + pub fn as_v128(&self) -> Option { match self { Self::V128(i) => Some(*i), _ => None, @@ -309,4 +311,4 @@ macro_rules! impl_conversion_for_wasmvalue { } } -impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, u128 => V128, ExternRef => RefExtern, FuncRef => RefFunc } +impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, i128 => V128, ExternRef => RefExtern, FuncRef => RefFunc } From 569e0b42bde426f83ad0329d4d6ec7a4c0793b36 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 1 Mar 2025 22:01:02 +0100 Subject: [PATCH 06/17] feat: support the tail call proposal (#37) Signed-off-by: Henry Gressmann --- CHANGELOG.md | 1 + README.md | 3 +- crates/parser/src/visit.rs | 6 +- crates/tinywasm/Cargo.toml | 4 + crates/tinywasm/src/interpreter/executor.rs | 110 +++++++++--------- .../src/interpreter/stack/call_stack.rs | 14 +++ crates/tinywasm/tests/generated/wasm-3.csv | 2 +- .../generated/wasm-custom-page-sizes.csv | 2 +- .../tests/generated/wasm-tail-call.csv | 1 + .../tests/test-wasm-custom-page-sizes.rs | 10 +- crates/tinywasm/tests/test-wasm-tail-call.rs | 13 +++ crates/types/src/instructions.rs | 4 +- 12 files changed, 110 insertions(+), 60 deletions(-) create mode 100644 crates/tinywasm/tests/generated/wasm-tail-call.csv create mode 100644 crates/tinywasm/tests/test-wasm-tail-call.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c01787f..e63ff2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Support for the custom memory page sizes proposal ([#22](https://github.com/explodingcamera/tinywasm/pull/22) by [@danielstuart14](https://github.com/danielstuart14)) +- Support for the `tail_call` proposal ### Breaking Changes diff --git a/README.md b/README.md index 8db5a84..6b72448 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,9 @@ TinyWasm passes all WebAssembly MVP tests from the [WebAssembly core testsuite]( | [**Reference Types**](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md) | 🟢 | 0.7.0 | | [**Multiple Memories**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) | 🟢 | 0.8.0 | | [**Custom Page Sizes**](https://github.com/WebAssembly/custom-page-sizes/blob/main/proposals/custom-page-sizes/Overview.md) | 🟢 | `next` | +| [**Tail Call**](https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md) | 🟢 | `next` | | [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🚧 | N/A | -| [**Fixed-Width SIMD**](https://github.com/webassembly/simd) | 🌑 | N/A | +| [**Fixed-Width SIMD**](https://github.com/webassembly/simd) | 🚧 | N/A | ## Usage diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 2830d3a..8ed44be 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -158,6 +158,7 @@ macro_rules! impl_visit_operator { (@@saturating_float_to_int $($rest:tt)* ) => {}; (@@bulk_memory $($rest:tt)* ) => {}; (@@simd $($rest:tt)* ) => {}; + (@@tail_call $($rest:tt)* ) => {}; (@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => { #[cold] @@ -181,7 +182,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild define_operands! { // basic instructions - visit_br(Br, u32), visit_br_if(BrIf, u32), visit_global_get(GlobalGet, u32), visit_i32_const(I32Const, i32), visit_i64_const(I64Const, i64), visit_call(Call, u32), visit_memory_size(MemorySize, u32), visit_memory_grow(MemoryGrow, u32), visit_unreachable(Unreachable), visit_nop(Nop), visit_return(Return), visit_i32_eqz(I32Eqz), visit_i32_eq(I32Eq), visit_i32_ne(I32Ne), visit_i32_lt_s(I32LtS), visit_i32_lt_u(I32LtU), visit_i32_gt_s(I32GtS), visit_i32_gt_u(I32GtU), visit_i32_le_s(I32LeS), visit_i32_le_u(I32LeU), visit_i32_ge_s(I32GeS), visit_i32_ge_u(I32GeU), visit_i64_eqz(I64Eqz), visit_i64_eq(I64Eq), visit_i64_ne(I64Ne), visit_i64_lt_s(I64LtS), visit_i64_lt_u(I64LtU), visit_i64_gt_s(I64GtS), visit_i64_gt_u(I64GtU), visit_i64_le_s(I64LeS), visit_i64_le_u(I64LeU), visit_i64_ge_s(I64GeS), visit_i64_ge_u(I64GeU), visit_f32_eq(F32Eq), visit_f32_ne(F32Ne), visit_f32_lt(F32Lt), visit_f32_gt(F32Gt), visit_f32_le(F32Le), visit_f32_ge(F32Ge), visit_f64_eq(F64Eq), visit_f64_ne(F64Ne), visit_f64_lt(F64Lt), visit_f64_gt(F64Gt), visit_f64_le(F64Le), visit_f64_ge(F64Ge), visit_i32_clz(I32Clz), visit_i32_ctz(I32Ctz), visit_i32_popcnt(I32Popcnt), visit_i32_add(I32Add), visit_i32_sub(I32Sub), visit_i32_mul(I32Mul), visit_i32_div_s(I32DivS), visit_i32_div_u(I32DivU), visit_i32_rem_s(I32RemS), visit_i32_rem_u(I32RemU), visit_i32_and(I32And), visit_i32_or(I32Or), visit_i32_xor(I32Xor), visit_i32_shl(I32Shl), visit_i32_shr_s(I32ShrS), visit_i32_shr_u(I32ShrU), visit_i32_rotl(I32Rotl), visit_i32_rotr(I32Rotr), visit_i64_clz(I64Clz), visit_i64_ctz(I64Ctz), visit_i64_popcnt(I64Popcnt), visit_i64_add(I64Add), visit_i64_sub(I64Sub), visit_i64_mul(I64Mul), visit_i64_div_s(I64DivS), visit_i64_div_u(I64DivU), visit_i64_rem_s(I64RemS), visit_i64_rem_u(I64RemU), visit_i64_and(I64And), visit_i64_or(I64Or), visit_i64_xor(I64Xor), visit_i64_shl(I64Shl), visit_i64_shr_s(I64ShrS), visit_i64_shr_u(I64ShrU), visit_i64_rotl(I64Rotl), visit_i64_rotr(I64Rotr), visit_f32_abs(F32Abs), visit_f32_neg(F32Neg), visit_f32_ceil(F32Ceil), visit_f32_floor(F32Floor), visit_f32_trunc(F32Trunc), visit_f32_nearest(F32Nearest), visit_f32_sqrt(F32Sqrt), visit_f32_add(F32Add), visit_f32_sub(F32Sub), visit_f32_mul(F32Mul), visit_f32_div(F32Div), visit_f32_min(F32Min), visit_f32_max(F32Max), visit_f32_copysign(F32Copysign), visit_f64_abs(F64Abs), visit_f64_neg(F64Neg), visit_f64_ceil(F64Ceil), visit_f64_floor(F64Floor), visit_f64_trunc(F64Trunc), visit_f64_nearest(F64Nearest), visit_f64_sqrt(F64Sqrt), visit_f64_add(F64Add), visit_f64_sub(F64Sub), visit_f64_mul(F64Mul), visit_f64_div(F64Div), visit_f64_min(F64Min), visit_f64_max(F64Max), visit_f64_copysign(F64Copysign), visit_i32_wrap_i64(I32WrapI64), visit_i32_trunc_f32_s(I32TruncF32S), visit_i32_trunc_f32_u(I32TruncF32U), visit_i32_trunc_f64_s(I32TruncF64S), visit_i32_trunc_f64_u(I32TruncF64U), visit_i64_extend_i32_s(I64ExtendI32S), visit_i64_extend_i32_u(I64ExtendI32U), visit_i64_trunc_f32_s(I64TruncF32S), visit_i64_trunc_f32_u(I64TruncF32U), visit_i64_trunc_f64_s(I64TruncF64S), visit_i64_trunc_f64_u(I64TruncF64U), visit_f32_convert_i32_s(F32ConvertI32S), visit_f32_convert_i32_u(F32ConvertI32U), visit_f32_convert_i64_s(F32ConvertI64S), visit_f32_convert_i64_u(F32ConvertI64U), visit_f32_demote_f64(F32DemoteF64), visit_f64_convert_i32_s(F64ConvertI32S), visit_f64_convert_i32_u(F64ConvertI32U), visit_f64_convert_i64_s(F64ConvertI64S), visit_f64_convert_i64_u(F64ConvertI64U), visit_f64_promote_f32(F64PromoteF32), visit_i32_reinterpret_f32(I32ReinterpretF32), visit_i64_reinterpret_f64(I64ReinterpretF64), visit_f32_reinterpret_i32(F32ReinterpretI32), visit_f64_reinterpret_i64(F64ReinterpretI64), + visit_br(Br, u32), visit_br_if(BrIf, u32), visit_global_get(GlobalGet, u32), visit_i32_const(I32Const, i32), visit_i64_const(I64Const, i64), visit_call(Call, u32), visit_return_call(ReturnCall, u32), visit_memory_size(MemorySize, u32), visit_memory_grow(MemoryGrow, u32), visit_unreachable(Unreachable), visit_nop(Nop), visit_return(Return), visit_i32_eqz(I32Eqz), visit_i32_eq(I32Eq), visit_i32_ne(I32Ne), visit_i32_lt_s(I32LtS), visit_i32_lt_u(I32LtU), visit_i32_gt_s(I32GtS), visit_i32_gt_u(I32GtU), visit_i32_le_s(I32LeS), visit_i32_le_u(I32LeU), visit_i32_ge_s(I32GeS), visit_i32_ge_u(I32GeU), visit_i64_eqz(I64Eqz), visit_i64_eq(I64Eq), visit_i64_ne(I64Ne), visit_i64_lt_s(I64LtS), visit_i64_lt_u(I64LtU), visit_i64_gt_s(I64GtS), visit_i64_gt_u(I64GtU), visit_i64_le_s(I64LeS), visit_i64_le_u(I64LeU), visit_i64_ge_s(I64GeS), visit_i64_ge_u(I64GeU), visit_f32_eq(F32Eq), visit_f32_ne(F32Ne), visit_f32_lt(F32Lt), visit_f32_gt(F32Gt), visit_f32_le(F32Le), visit_f32_ge(F32Ge), visit_f64_eq(F64Eq), visit_f64_ne(F64Ne), visit_f64_lt(F64Lt), visit_f64_gt(F64Gt), visit_f64_le(F64Le), visit_f64_ge(F64Ge), visit_i32_clz(I32Clz), visit_i32_ctz(I32Ctz), visit_i32_popcnt(I32Popcnt), visit_i32_add(I32Add), visit_i32_sub(I32Sub), visit_i32_mul(I32Mul), visit_i32_div_s(I32DivS), visit_i32_div_u(I32DivU), visit_i32_rem_s(I32RemS), visit_i32_rem_u(I32RemU), visit_i32_and(I32And), visit_i32_or(I32Or), visit_i32_xor(I32Xor), visit_i32_shl(I32Shl), visit_i32_shr_s(I32ShrS), visit_i32_shr_u(I32ShrU), visit_i32_rotl(I32Rotl), visit_i32_rotr(I32Rotr), visit_i64_clz(I64Clz), visit_i64_ctz(I64Ctz), visit_i64_popcnt(I64Popcnt), visit_i64_add(I64Add), visit_i64_sub(I64Sub), visit_i64_mul(I64Mul), visit_i64_div_s(I64DivS), visit_i64_div_u(I64DivU), visit_i64_rem_s(I64RemS), visit_i64_rem_u(I64RemU), visit_i64_and(I64And), visit_i64_or(I64Or), visit_i64_xor(I64Xor), visit_i64_shl(I64Shl), visit_i64_shr_s(I64ShrS), visit_i64_shr_u(I64ShrU), visit_i64_rotl(I64Rotl), visit_i64_rotr(I64Rotr), visit_f32_abs(F32Abs), visit_f32_neg(F32Neg), visit_f32_ceil(F32Ceil), visit_f32_floor(F32Floor), visit_f32_trunc(F32Trunc), visit_f32_nearest(F32Nearest), visit_f32_sqrt(F32Sqrt), visit_f32_add(F32Add), visit_f32_sub(F32Sub), visit_f32_mul(F32Mul), visit_f32_div(F32Div), visit_f32_min(F32Min), visit_f32_max(F32Max), visit_f32_copysign(F32Copysign), visit_f64_abs(F64Abs), visit_f64_neg(F64Neg), visit_f64_ceil(F64Ceil), visit_f64_floor(F64Floor), visit_f64_trunc(F64Trunc), visit_f64_nearest(F64Nearest), visit_f64_sqrt(F64Sqrt), visit_f64_add(F64Add), visit_f64_sub(F64Sub), visit_f64_mul(F64Mul), visit_f64_div(F64Div), visit_f64_min(F64Min), visit_f64_max(F64Max), visit_f64_copysign(F64Copysign), visit_i32_wrap_i64(I32WrapI64), visit_i32_trunc_f32_s(I32TruncF32S), visit_i32_trunc_f32_u(I32TruncF32U), visit_i32_trunc_f64_s(I32TruncF64S), visit_i32_trunc_f64_u(I32TruncF64U), visit_i64_extend_i32_s(I64ExtendI32S), visit_i64_extend_i32_u(I64ExtendI32U), visit_i64_trunc_f32_s(I64TruncF32S), visit_i64_trunc_f32_u(I64TruncF32U), visit_i64_trunc_f64_s(I64TruncF64S), visit_i64_trunc_f64_u(I64TruncF64U), visit_f32_convert_i32_s(F32ConvertI32S), visit_f32_convert_i32_u(F32ConvertI32U), visit_f32_convert_i64_s(F32ConvertI64S), visit_f32_convert_i64_u(F32ConvertI64U), visit_f32_demote_f64(F32DemoteF64), visit_f64_convert_i32_s(F64ConvertI32S), visit_f64_convert_i32_u(F64ConvertI32U), visit_f64_convert_i64_s(F64ConvertI64S), visit_f64_convert_i64_u(F64ConvertI64U), visit_f64_promote_f32(F64PromoteF32), visit_i32_reinterpret_f32(I32ReinterpretF32), visit_i64_reinterpret_f64(I64ReinterpretF64), visit_f32_reinterpret_i32(F32ReinterpretI32), visit_f64_reinterpret_i64(F64ReinterpretI64), // sign_extension visit_i32_extend8_s(I32Extend8S), visit_i32_extend16_s(I32Extend16S), visit_i64_extend8_s(I64Extend8S), visit_i64_extend16_s(I64Extend16S), visit_i64_extend32_s(I64Extend32S), @@ -431,6 +432,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild fn visit_call_indirect(&mut self, ty: u32, table: u32) -> Self::Output { self.instructions.push(Instruction::CallIndirect(ty, table)); } + fn visit_return_call_indirect(&mut self, ty: u32, table: u32) -> Self::Output { + self.instructions.push(Instruction::ReturnCallIndirect(ty, table)); + } fn visit_f32_const(&mut self, val: wasmparser::Ieee32) -> Self::Output { self.instructions.push(Instruction::F32Const(f32::from_bits(val.bits()))); diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 2cad2e4..d004760 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -62,6 +62,10 @@ harness=false name="test-wasm-custom-page-sizes" harness=false +[[test]] +name="test-wasm-tail-call" +harness=false + [[test]] name="test-wasm-memory64" harness=false diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 3c579c1..c776710 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -55,8 +55,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { Select128 => self.stack.values.select::(), SelectRef => self.stack.values.select::(), - Call(v) => return self.exec_call_direct(*v), - CallIndirect(ty, table) => return self.exec_call_indirect(*ty, *table), + Call(v) => return self.exec_call_direct::(*v), + CallIndirect(ty, table) => return self.exec_call_indirect::(*ty, *table), + + ReturnCall(v) => return self.exec_call_direct::(*v), + ReturnCallIndirect(ty, table) => return self.exec_call_indirect::(*ty, *table), If(end, el) => self.exec_if(*end, *el, (StackHeight::default(), StackHeight::default())), IfWithType(ty, end, el) => self.exec_if(*end, *el, (StackHeight::default(), (*ty).into())), @@ -314,50 +317,71 @@ impl<'store, 'stack> Executor<'store, 'stack> { ControlFlow::Break(Some(Trap::Unreachable.into())) } - fn exec_call(&mut self, wasm_func: Rc, owner: ModuleInstanceAddr) -> ControlFlow> { - let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals); - let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.stack.blocks.len() as u32); - self.cf.incr_instr_ptr(); // skip the call instruction - self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; - self.module.swap_with(self.cf.module_addr(), self.store); + fn exec_call( + &mut self, + wasm_func: Rc, + owner: ModuleInstanceAddr, + ) -> ControlFlow> { + if !IS_RETURN_CALL { + let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals); + let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.stack.blocks.len() as u32); + self.cf.incr_instr_ptr(); // skip the call instruction + self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; + self.module.swap_with(self.cf.module_addr(), self.store); + } else { + let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals); + self.cf.reuse_for(wasm_func, locals, self.stack.blocks.len() as u32, owner); + self.module.swap_with(self.cf.module_addr(), self.store); + } + ControlFlow::Continue(()) } - fn exec_call_direct(&mut self, v: u32) -> ControlFlow> { + fn exec_call_host(&mut self, host_func: Rc) -> ControlFlow> { + let params = self.stack.values.pop_params(&host_func.ty.params); + let res = host_func + .clone() + .call(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms) + .to_cf()?; + self.stack.values.extend_from_wasmvalues(&res); + self.cf.incr_instr_ptr(); + ControlFlow::Continue(()) + } + fn exec_call_direct(&mut self, v: u32) -> ControlFlow> { let func_inst = self.store.get_func(self.module.resolve_func_addr(v)); - let wasm_func = match &func_inst.func { - crate::Function::Wasm(wasm_func) => wasm_func, - crate::Function::Host(host_func) => { - let func = &host_func.clone(); - let params = self.stack.values.pop_params(&host_func.ty.params); - let res = - func.call(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms).to_cf()?; - self.stack.values.extend_from_wasmvalues(&res); - self.cf.incr_instr_ptr(); - return ControlFlow::Continue(()); - } - }; - - self.exec_call(wasm_func.clone(), func_inst.owner) + match func_inst.func.clone() { + crate::Function::Wasm(wasm_func) => self.exec_call::(wasm_func, func_inst.owner), + crate::Function::Host(host_func) => self.exec_call_host(host_func), + } } - fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> ControlFlow> { + fn exec_call_indirect( + &mut self, + type_addr: u32, + table_addr: u32, + ) -> ControlFlow> { // verify that the table is of the right type, this should be validated by the parser already let func_ref = { let table = self.store.get_table(self.module.resolve_table_addr(table_addr)); let table_idx: u32 = self.stack.values.pop::() as u32; assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref"); - table - .get(table_idx) - .map_err(|_| Error::Trap(Trap::UndefinedElement { index: table_idx as usize })) - .to_cf()? - .addr() - .ok_or(Error::Trap(Trap::UninitializedElement { index: table_idx as usize })) - .to_cf()? + let table = table.get(table_idx).map_err(|_| Trap::UndefinedElement { index: table_idx as usize }.into()); + let table = table.to_cf()?; + table.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize }.into()).to_cf()? }; let func_inst = self.store.get_func(func_ref); let call_ty = self.module.func_ty(type_addr); - let wasm_func = match &func_inst.func { - crate::Function::Wasm(f) => f, + + match func_inst.func.clone() { + crate::Function::Wasm(wasm_func) => { + if unlikely(wasm_func.ty != *call_ty) { + return ControlFlow::Break(Some( + Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() } + .into(), + )); + } + + self.exec_call::(wasm_func, func_inst.owner) + } crate::Function::Host(host_func) => { if unlikely(host_func.ty != *call_ty) { return ControlFlow::Break(Some( @@ -366,27 +390,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { )); } - let host_func = host_func.clone(); - let params = self.stack.values.pop_params(&host_func.ty.params); - let res = - match host_func.call(FuncContext { store: self.store, module_addr: self.module.id() }, ¶ms) { - Ok(res) => res, - Err(e) => return ControlFlow::Break(Some(e)), - }; - - self.stack.values.extend_from_wasmvalues(&res); - self.cf.incr_instr_ptr(); - return ControlFlow::Continue(()); + self.exec_call_host(host_func) } - }; - - if unlikely(wasm_func.ty != *call_ty) { - return ControlFlow::Break(Some( - Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into(), - )); } - - self.exec_call(wasm_func.clone(), func_inst.owner) } fn exec_if(&mut self, else_offset: u32, end_offset: u32, (params, results): (StackHeight, StackHeight)) { diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index 9b6c3fd..11bbe29 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -98,6 +98,20 @@ impl CallFrame { } } + pub(crate) fn reuse_for( + &mut self, + func: Rc, + locals: Locals, + block_depth: u32, + module_addr: ModuleInstanceAddr, + ) { + self.func_instance = func; + self.module_addr = module_addr; + self.locals = locals; + self.block_ptr = block_depth; + self.instr_ptr = 0; // Reset to function entry + } + /// Break to a block at the given index (relative to the current frame) /// Returns `None` if there is no block at the given index (e.g. if we need to return, this is handled by the caller) #[inline] diff --git a/crates/tinywasm/tests/generated/wasm-3.csv b/crates/tinywasm/tests/generated/wasm-3.csv index ed301e4..a1df609 100644 --- a/crates/tinywasm/tests/generated/wasm-3.csv +++ b/crates/tinywasm/tests/generated/wasm-3.csv @@ -1 +1 @@ -0.9.0-alpha.0,32305,2591,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":126,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":49,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":169,"failed":90},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":118,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":89,"failed":0},{"name":"memory64.wast","passed":14,"failed":53},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":11,"failed":34},{"name":"return_call_indirect.wast","passed":26,"failed":50},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table.wast","passed":47,"failed":9},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":780,"failed":96},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,32377,2526,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":126,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":49,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":169,"failed":90},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":118,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory64.wast","passed":14,"failed":55},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":40,"failed":5},{"name":"return_call_indirect.wast","passed":69,"failed":7},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table.wast","passed":47,"failed":13},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":780,"failed":96},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv b/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv index 7f168a1..5ba121e 100644 --- a/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv +++ b/crates/tinywasm/tests/generated/wasm-custom-page-sizes.csv @@ -1,2 +1,2 @@ 0.8.0,57,0,[{"name":"custom-page-sizes-invalid.wast","passed":22,"failed":0},{"name":"custom-page-sizes.wast","passed":35,"failed":0}] -0.9.0-alpha.0,57,0,[{"name":"custom-page-sizes-invalid.wast","passed":22,"failed":0},{"name":"custom-page-sizes.wast","passed":35,"failed":0}] +0.9.0-alpha.0,76,0,[{"name":"custom-page-sizes-invalid.wast","passed":23,"failed":0},{"name":"custom-page-sizes.wast","passed":45,"failed":0},{"name":"memory_max.wast","passed":4,"failed":0},{"name":"memory_max_i64.wast","passed":4,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-tail-call.csv b/crates/tinywasm/tests/generated/wasm-tail-call.csv new file mode 100644 index 0000000..c9f0910 --- /dev/null +++ b/crates/tinywasm/tests/generated/wasm-tail-call.csv @@ -0,0 +1 @@ +0.9.0-alpha.0,119,0,[{"name":"return_call.wast","passed":44,"failed":0},{"name":"return_call_indirect.wast","passed":75,"failed":0}] diff --git a/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs b/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs index d49d89a..e4aacfc 100644 --- a/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs +++ b/crates/tinywasm/tests/test-wasm-custom-page-sizes.rs @@ -1,7 +1,13 @@ mod testsuite; use eyre::Result; +use testsuite::TestSuite; +use wasm_testsuite::data::{Proposal, proposal}; fn main() -> Result<()> { - println!("Skipping Wasm Custom Page Sizes tests (Wast doesn't support the syntax yet)"); - Ok(()) + TestSuite::set_log_level(log::LevelFilter::Off); + + let mut test_suite = TestSuite::new(); + test_suite.run_files(proposal(&Proposal::CustomPageSizes))?; + test_suite.save_csv("./tests/generated/wasm-custom-page-sizes.csv", env!("CARGO_PKG_VERSION"))?; + test_suite.report_status() } diff --git a/crates/tinywasm/tests/test-wasm-tail-call.rs b/crates/tinywasm/tests/test-wasm-tail-call.rs new file mode 100644 index 0000000..f888f38 --- /dev/null +++ b/crates/tinywasm/tests/test-wasm-tail-call.rs @@ -0,0 +1,13 @@ +mod testsuite; +use eyre::Result; +use testsuite::TestSuite; +use wasm_testsuite::data::{Proposal, proposal}; + +fn main() -> Result<()> { + TestSuite::set_log_level(log::LevelFilter::Off); + + let mut test_suite = TestSuite::new(); + test_suite.run_files(proposal(&Proposal::TailCall))?; + test_suite.save_csv("./tests/generated/wasm-tail-call.csv", env!("CARGO_PKG_VERSION"))?; + test_suite.report_status() +} diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index c61a02f..899be65 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -86,8 +86,8 @@ pub enum Instruction { Return, Call(FuncAddr), CallIndirect(TypeAddr, TableAddr), - // ReturnCall(FuncAddr), - // ReturnCallIndirect(TypeAddr, TableAddr), + ReturnCall(FuncAddr), + ReturnCallIndirect(TypeAddr, TableAddr), // > Parametric Instructions // See From 1252a8936eb2a69496efc849f3eb59e72b964920 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sun, 2 Mar 2025 14:43:02 +0100 Subject: [PATCH 07/17] feat: memory64 support (#38) Signed-off-by: Henry Gressmann --- Cargo.lock | 6 +- README.md | 12 ++-- crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/src/interpreter/executor.rs | 55 ++++++++++++++----- crates/tinywasm/src/reference.rs | 2 +- crates/tinywasm/src/store/memory.rs | 19 ++++--- crates/tinywasm/src/store/mod.rs | 28 +++++----- crates/tinywasm/src/store/table.rs | 2 +- crates/tinywasm/tests/generated/wasm-3.csv | 2 +- .../tests/generated/wasm-memory64.csv | 2 +- crates/tinywasm/tests/test-wasm-memory64.rs | 15 +---- 11 files changed, 83 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1178a8a..8bdb809 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -674,9 +674,9 @@ dependencies = [ [[package]] name = "wasm-testsuite" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea6edc2d1ffad1d673091e3e3e98961e7c1a8c0f24cbf2431fa02d861e071bd" +checksum = "e01c897a970135c086793fa320de6632534ad7b4a519a3ca51c7ef40e6a567d7" dependencies = [ "include_dir", "wast", diff --git a/README.md b/README.md index 6b72448..27eb8f5 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,15 @@ - **Tiny**: TinyWasm is designed to be as small as possible without significantly compromising performance or functionality (< 4000 LLOC). - **Portable**: TinyWasm runs on any platform that Rust can target, including `no_std`, with minimal external dependencies. -- **Safe**: No unsafe code is used in the runtime (`rkyv`, which uses unsafe code, can be used for serialization but is optional). +- **Safe**: No unsafe code is used in the runtime -## Status +## Current Status -TinyWasm passes all WebAssembly MVP tests from the [WebAssembly core testsuite](https://github.com/WebAssembly/testsuite) and is able to run most WebAssembly programs. Additionally, the current 2.0 Draft is mostly supported, with the exception of Fixed-Width SIMD and Memory64/Multiple Memories. See the [Supported Proposals](#supported-proposals) section for more information. +TinyWasm passes all WebAssembly MVP tests from the [WebAssembly core testsuite](https://github.com/WebAssembly/testsuite) and is able to run most WebAssembly programs. Additionally, the current 2.0 WebAssembly is mostly supported, with the exception of the SIMD and Memory64 proposals. See the [Supported Proposals](#supported-proposals) section for more information. + +## Safety + +Safety wise, TinyWasm doesn't use any unsafe code and is designed to be completly memory-safe. Untrusted WebAssembly code should not be able to crash the runtime or access memory outside of its sandbox, however currently there is no protection against infinite loops or excessive memory usage. Unvalidated Wasm and untrusted, precompilled twasm bytecode is safe to run too but can crash the runtime. ## Supported Proposals @@ -38,7 +42,7 @@ TinyWasm passes all WebAssembly MVP tests from the [WebAssembly core testsuite]( | [**Multiple Memories**](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md) | 🟢 | 0.8.0 | | [**Custom Page Sizes**](https://github.com/WebAssembly/custom-page-sizes/blob/main/proposals/custom-page-sizes/Overview.md) | 🟢 | `next` | | [**Tail Call**](https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md) | 🟢 | `next` | -| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🚧 | N/A | +| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🟢 | `next` | | [**Fixed-Width SIMD**](https://github.com/webassembly/simd) | 🚧 | N/A | ## Usage diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index d004760..9be8233 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false libm={version="0.2", default-features=false} [dev-dependencies] -wasm-testsuite={version="0.4.4"} +wasm-testsuite={version="0.5.0"} indexmap="2.7" wast={workspace=true} wat={workspace=true} diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index c776710..4ba4556 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -518,16 +518,31 @@ impl<'store, 'stack> Executor<'store, 'stack> { fn exec_memory_size(&mut self, addr: u32) { let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)); - self.stack.values.push::(mem.page_count as i32); + + match mem.is_64bit() { + true => self.stack.values.push::(mem.page_count as i64), + false => self.stack.values.push::(mem.page_count as i32), + } } fn exec_memory_grow(&mut self, addr: u32) { let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(addr)); - let prev_size = mem.page_count as i32; - let pages_delta = self.stack.values.pop::(); - self.stack.values.push::(match mem.grow(pages_delta) { - Some(_) => prev_size, - None => -1, - }); + let prev_size = mem.page_count; + + let pages_delta = match mem.is_64bit() { + true => self.stack.values.pop::(), + false => self.stack.values.pop::() as i64, + }; + + match ( + mem.is_64bit(), + match mem.grow(pages_delta) { + Some(_) => prev_size as i64, + None => -1_i64, + }, + ) { + (true, size) => self.stack.values.push::(size), + (false, size) => self.stack.values.push::(size as i32), + }; } fn exec_memory_copy(&mut self, from: u32, to: u32) -> Result<()> { @@ -605,14 +620,13 @@ impl<'store, 'stack> Executor<'store, 'stack> { dst as usize, src as usize, size as usize, - )?; + ) } else { // copy between two memories let (table_from, table_to) = self.store.get_tables_mut(self.module.resolve_table_addr(from), self.module.resolve_table_addr(to))?; - table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?)?; + table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?) } - Ok(()) } fn exec_mem_load, const LOAD_SIZE: usize, TARGET: InternalValue>( @@ -622,11 +636,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { cast: fn(LOAD) -> TARGET, ) -> ControlFlow> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); - let val = self.stack.values.pop::() as u64; - let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else { + + let addr = match mem.is_64bit() { + true => self.stack.values.pop::() as u64, + false => self.stack.values.pop::() as u32 as u64, + }; + + let Some(Ok(addr)) = offset.checked_add(addr).map(TryInto::try_into) else { cold(); return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds { - offset: val as usize, + offset: addr as usize, len: LOAD_SIZE, max: 0, }))); @@ -644,10 +663,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr)); let val = self.stack.values.pop::(); let val = (cast(val)).to_mem_bytes(); - let addr = self.stack.values.pop::() as u64; + + let addr = match mem.is_64bit() { + true => self.stack.values.pop::() as u64, + false => self.stack.values.pop::() as u32 as u64, + }; + if let Err(e) = mem.store((offset + addr) as usize, val.len(), &val) { return ControlFlow::Break(Some(e)); } + ControlFlow::Continue(()) } @@ -707,7 +732,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); }; - table.init(dst, &items[offset as usize..(offset + size) as usize]) + table.init(dst as i64, &items[offset as usize..(offset + size) as usize]) } fn exec_table_grow(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index)); diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs index e151c87..e32a2f3 100644 --- a/crates/tinywasm/src/reference.rs +++ b/crates/tinywasm/src/reference.rs @@ -54,7 +54,7 @@ impl MemoryRefMut<'_> { } /// Grow the memory by the given number of pages - pub fn grow(&mut self, delta_pages: i32) -> Option { + pub fn grow(&mut self, delta_pages: i64) -> Option { self.0.grow(delta_pages) } diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index d204c67..53c1133 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -1,6 +1,6 @@ use alloc::vec; use alloc::vec::Vec; -use tinywasm_types::{MemoryType, ModuleInstanceAddr}; +use tinywasm_types::{MemoryArch, MemoryType, ModuleInstanceAddr}; use crate::{Error, Result, cold, log}; @@ -28,6 +28,11 @@ impl MemoryInstance { } } + #[inline] + pub(crate) fn is_64bit(&self) -> bool { + matches!(self.kind.arch(), MemoryArch::I64) + } + #[inline(always)] pub(crate) fn len(&self) -> usize { self.data.len() @@ -124,15 +129,13 @@ impl MemoryInstance { } #[inline] - pub(crate) fn grow(&mut self, pages_delta: i32) -> Option { + pub(crate) fn grow(&mut self, pages_delta: i64) -> Option { let current_pages = self.page_count; - let new_pages = current_pages as i64 + pages_delta as i64; - debug_assert!(new_pages <= i32::MAX as i64, "page count should never be greater than i32::MAX"); + let new_pages = current_pages as i64 + pages_delta; if new_pages < 0 || new_pages as usize > self.max_pages() { log::debug!("memory.grow failed: new_pages={}, max_pages={}", new_pages, self.max_pages()); log::debug!("{} {}", self.kind.page_count_max(), self.kind.page_size()); - return None; } @@ -145,7 +148,7 @@ impl MemoryInstance { self.data.reserve_exact(new_size); self.data.resize_with(new_size, Default::default); self.page_count = new_pages as usize; - Some(current_pages as i32) + Some(current_pages as i64) } } @@ -241,14 +244,14 @@ mod memory_instance_tests { fn test_memory_grow() { let mut memory = create_test_memory(); let original_pages = memory.page_count; - assert_eq!(memory.grow(1), Some(original_pages as i32)); + assert_eq!(memory.grow(1), Some(original_pages as i64)); assert_eq!(memory.page_count, original_pages + 1); } #[test] fn test_memory_grow_out_of_bounds() { let mut memory = create_test_memory(); - assert!(memory.grow(memory.kind.max_size() as i32 + 1).is_none()); + assert!(memory.grow(memory.kind.max_size() as i64 + 1).is_none()); } #[test] diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 5730631..358cbef 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -243,9 +243,6 @@ impl Store { let mem_count = self.data.memories.len(); let mut mem_addrs = Vec::with_capacity(mem_count); for (i, mem) in memories.into_iter().enumerate() { - if let MemoryArch::I64 = mem.arch() { - return Err(Error::UnsupportedFeature("64-bit memories".to_string())); - } self.data.memories.push(MemoryInstance::new(mem, idx)); mem_addrs.push((i + mem_count) as MemAddr); } @@ -325,7 +322,7 @@ impl Store { // this one is active, so we need to initialize it (essentially a `table.init` instruction) ElementKind::Active { offset, table } => { - let offset = self.eval_i32_const(offset)?; + let offset = self.eval_size_const(offset)?; let table_addr = table_addrs .get(table as usize) .copied() @@ -373,7 +370,7 @@ impl Store { return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}"))); }; - let offset = self.eval_i32_const(offset)?; + let offset = self.eval_size_const(offset)?; let Some(mem) = self.data.memories.get_mut(*mem_addr as usize) else { return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}"))); }; @@ -418,15 +415,18 @@ impl Store { Ok(self.data.funcs.len() as FuncAddr - 1) } - /// Evaluate a constant expression, only supporting i32 globals and i32.const - pub(crate) fn eval_i32_const(&self, const_instr: tinywasm_types::ConstInstruction) -> Result { - use tinywasm_types::ConstInstruction::*; - let val = match const_instr { - I32Const(i) => i, - GlobalGet(addr) => self.data.globals[addr as usize].value.get().unwrap_32() as i32, - _ => return Err(Error::Other("expected i32".to_string())), - }; - Ok(val) + /// Evaluate a constant expression that's either a i32 or a i64 as a global or a const instruction + pub(crate) fn eval_size_const(&self, const_instr: tinywasm_types::ConstInstruction) -> Result { + Ok(match const_instr { + ConstInstruction::I32Const(i) => i as i64, + ConstInstruction::I64Const(i) => i, + ConstInstruction::GlobalGet(addr) => match self.data.globals[addr as usize].value.get() { + TinyWasmValue::Value32(i) => i as i64, + TinyWasmValue::Value64(i) => i as i64, + o => return Err(Error::Other(format!("expected i32 or i64, got {o:?}"))), + }, + o => return Err(Error::Other(format!("expected i32, got {o:?}"))), + }) } /// Evaluate a constant expression diff --git a/crates/tinywasm/src/store/table.rs b/crates/tinywasm/src/store/table.rs index 0cbd054..f83de9b 100644 --- a/crates/tinywasm/src/store/table.rs +++ b/crates/tinywasm/src/store/table.rs @@ -134,7 +134,7 @@ impl TableInstance { .expect("error initializing table: function not found. This should have been caught by the validator") } - pub(crate) fn init(&mut self, offset: i32, init: &[TableElement]) -> Result<()> { + pub(crate) fn init(&mut self, offset: i64, init: &[TableElement]) -> Result<()> { let offset = offset as usize; let end = offset.checked_add(init.len()).ok_or({ Error::Trap(crate::Trap::TableOutOfBounds { offset, len: init.len(), max: self.elements.len() }) diff --git a/crates/tinywasm/tests/generated/wasm-3.csv b/crates/tinywasm/tests/generated/wasm-3.csv index a1df609..5d4d068 100644 --- a/crates/tinywasm/tests/generated/wasm-3.csv +++ b/crates/tinywasm/tests/generated/wasm-3.csv @@ -1 +1 @@ -0.9.0-alpha.0,32377,2526,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":126,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":49,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":169,"failed":90},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":118,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory64.wast","passed":14,"failed":55},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":40,"failed":5},{"name":"return_call_indirect.wast","passed":69,"failed":7},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table.wast","passed":47,"failed":13},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":780,"failed":96},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,33714,1189,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":242,"failed":0},{"name":"align.wast","passed":161,"failed":0},{"name":"align64.wast","passed":156,"failed":0},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":93,"failed":0},{"name":"binary.wast","passed":126,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":172,"failed":1},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"endianness64.wast","passed":69,"failed":0},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_memory64.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":169,"failed":90},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":118,"failed":0},{"name":"load64.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory64.wast","passed":68,"failed":1},{"name":"memory_copy.wast","passed":8628,"failed":272},{"name":"memory_fill.wast","passed":184,"failed":16},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":49,"failed":0},{"name":"memory_init.wast","passed":439,"failed":41},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_redundancy64.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"memory_trap64.wast","passed":172,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":45,"failed":0},{"name":"return_call_indirect.wast","passed":76,"failed":0},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table.wast","passed":47,"failed":13},{"name":"table_copy.wast","passed":1750,"failed":22},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":783,"failed":93},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-memory64.csv b/crates/tinywasm/tests/generated/wasm-memory64.csv index 6638c85..039fe8c 100644 --- a/crates/tinywasm/tests/generated/wasm-memory64.csv +++ b/crates/tinywasm/tests/generated/wasm-memory64.csv @@ -1,2 +1,2 @@ 0.8.0,15081,3214,[{"name":"address.wast","passed":260,"failed":0},{"name":"address0.wast","passed":92,"failed":0},{"name":"address1.wast","passed":127,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align0.wast","passed":5,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"array_copy.wast","passed":4,"failed":31},{"name":"array_fill.wast","passed":3,"failed":14},{"name":"array_init_data.wast","passed":2,"failed":31},{"name":"array_init_elem.wast","passed":3,"failed":20},{"name":"binary-gc.wast","passed":1,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":124,"failed":0},{"name":"binary0.wast","passed":7,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_cast.wast","passed":6,"failed":31},{"name":"br_on_cast_fail.wast","passed":6,"failed":31},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"call_indirect.wast","passed":47,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"data.wast","passed":59,"failed":6},{"name":"data0.wast","passed":7,"failed":0},{"name":"data1.wast","passed":14,"failed":0},{"name":"data_drop0.wast","passed":11,"failed":0},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"exports0.wast","passed":8,"failed":0},{"name":"float_exprs0.wast","passed":14,"failed":0},{"name":"float_exprs1.wast","passed":3,"failed":0},{"name":"float_memory0.wast","passed":30,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"func.wast","passed":175,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":99,"failed":82},{"name":"imports0.wast","passed":8,"failed":0},{"name":"imports1.wast","passed":5,"failed":0},{"name":"imports2.wast","passed":20,"failed":0},{"name":"imports3.wast","passed":10,"failed":0},{"name":"imports4.wast","passed":16,"failed":0},{"name":"linking.wast","passed":122,"failed":41},{"name":"linking0.wast","passed":6,"failed":0},{"name":"linking1.wast","passed":14,"failed":0},{"name":"linking2.wast","passed":11,"failed":0},{"name":"linking3.wast","passed":14,"failed":0},{"name":"load.wast","passed":118,"failed":0},{"name":"load0.wast","passed":3,"failed":0},{"name":"load1.wast","passed":18,"failed":0},{"name":"load2.wast","passed":38,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":86,"failed":0},{"name":"memory64.wast","passed":10,"failed":53},{"name":"memory64/array.wast (skipped)","passed":0,"failed":0},{"name":"memory64/extern.wast (skipped)","passed":0,"failed":0},{"name":"memory64/global.wast (skipped)","passed":0,"failed":0},{"name":"memory64/i31.wast (skipped)","passed":0,"failed":0},{"name":"memory64/ref_null.wast (skipped)","passed":0,"failed":0},{"name":"memory64/select.wast (skipped)","passed":0,"failed":0},{"name":"memory64/simd_address.wast (skipped)","passed":0,"failed":0},{"name":"memory64/simd_lane.wast (skipped)","passed":0,"failed":0},{"name":"memory64/struct.wast (skipped)","passed":0,"failed":0},{"name":"memory64/table.wast (skipped)","passed":0,"failed":0},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_copy0.wast","passed":29,"failed":0},{"name":"memory_copy1.wast","passed":14,"failed":0},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_fill0.wast","passed":16,"failed":0},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_init0.wast","passed":13,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_size0.wast","passed":8,"failed":0},{"name":"memory_size1.wast","passed":15,"failed":0},{"name":"memory_size2.wast","passed":21,"failed":0},{"name":"memory_size3.wast","passed":2,"failed":0},{"name":"memory_trap0.wast","passed":14,"failed":0},{"name":"memory_trap1.wast","passed":168,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_cast.wast","passed":0,"failed":45},{"name":"ref_eq.wast","passed":6,"failed":83},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_test.wast","passed":0,"failed":71},{"name":"return_call.wast","passed":18,"failed":27},{"name":"return_call_indirect.wast","passed":31,"failed":45},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"simd_memory-multi.wast","passed":0,"failed":1},{"name":"start0.wast","passed":9,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"store0.wast","passed":5,"failed":0},{"name":"store1.wast","passed":13,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":3,"failed":1},{"name":"table_fill.wast","passed":9,"failed":71},{"name":"table_get.wast","passed":5,"failed":12},{"name":"table_grow.wast","passed":36,"failed":43},{"name":"table_init.wast","passed":588,"failed":288},{"name":"table_set.wast","passed":7,"failed":21},{"name":"table_size.wast","passed":2,"failed":38},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps0.wast","passed":15,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type-subtyping.wast","passed":16,"failed":86},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11}] -0.9.0-alpha.0,12505,1919,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align64.wast","passed":83,"failed":73},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":126,"failed":0},{"name":"binary0.wast","passed":7,"failed":0},{"name":"call_indirect.wast","passed":47,"failed":124},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"imports.wast","passed":169,"failed":90},{"name":"load64.wast","passed":59,"failed":38},{"name":"memory.wast","passed":86,"failed":0},{"name":"memory64.wast","passed":10,"failed":53},{"name":"memory64/simd_address.wast (skipped)","passed":0,"failed":0},{"name":"memory64/table.wast (skipped)","passed":0,"failed":0},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":4,"failed":0},{"name":"table_fill.wast","passed":45,"failed":35},{"name":"table_get.wast","passed":16,"failed":1},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_init.wast","passed":780,"failed":96},{"name":"table_set.wast","passed":26,"failed":2},{"name":"table_size.wast","passed":39,"failed":1}] +0.9.0-alpha.0,1556,42,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":242,"failed":0},{"name":"align64.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":93,"failed":0},{"name":"binary.wast","passed":169,"failed":0},{"name":"endianness64.wast","passed":69,"failed":0},{"name":"float_memory64.wast","passed":90,"failed":0},{"name":"load64.wast","passed":97,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory64.wast","passed":65,"failed":0},{"name":"memory_grow64.wast","passed":49,"failed":0},{"name":"memory_redundancy64.wast","passed":8,"failed":0},{"name":"memory_trap64.wast","passed":172,"failed":0},{"name":"simd_address.wast","passed":7,"failed":42}] diff --git a/crates/tinywasm/tests/test-wasm-memory64.rs b/crates/tinywasm/tests/test-wasm-memory64.rs index 391a1ef..447bbfc 100644 --- a/crates/tinywasm/tests/test-wasm-memory64.rs +++ b/crates/tinywasm/tests/test-wasm-memory64.rs @@ -1,22 +1,11 @@ mod testsuite; -use eyre::{eyre, Result}; -use owo_colors::OwoColorize; +use eyre::Result; use testsuite::TestSuite; +use wasm_testsuite::data::{Proposal, proposal}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); - let mut test_suite = TestSuite::new(); - test_suite.skip("memory64/array.wast"); - test_suite.skip("memory64/extern.wast"); - test_suite.skip("memory64/global.wast"); - test_suite.skip("memory64/i31.wast"); - test_suite.skip("memory64/ref_null.wast"); - test_suite.skip("memory64/select.wast"); - test_suite.skip("memory64/simd_address.wast"); - test_suite.skip("memory64/simd_lane.wast"); - test_suite.skip("memory64/struct.wast"); - test_suite.skip("memory64/table.wast"); test_suite.run_files(proposal(&Proposal::Memory64))?; test_suite.save_csv("./tests/generated/wasm-memory64.csv", env!("CARGO_PKG_VERSION"))?; From 374db44a6b7666353875df17f44ec4da7ff317d5 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 6 Mar 2025 23:40:16 +0100 Subject: [PATCH 08/17] chore: update wasmparser Signed-off-by: Henry Gressmann --- Cargo.lock | 6 +++--- Cargo.toml | 6 +++--- crates/tinywasm/tests/generated/wasm-memory64.csv | 2 +- crates/tinywasm/tests/generated/wasm-relaxed-simd.csv | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 crates/tinywasm/tests/generated/wasm-relaxed-simd.csv diff --git a/Cargo.lock b/Cargo.lock index e2c5d3f..00d3aaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,7 +596,7 @@ dependencies = [ "tinywasm-parser", "tinywasm-types", "wasm-testsuite", - "wast 226.0.0", + "wast 227.0.0", "wat", ] @@ -609,7 +609,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast 226.0.0", + "wast 227.0.0", ] [[package]] @@ -618,7 +618,7 @@ version = "0.9.0-alpha.0" dependencies = [ "log", "tinywasm-types", - "wasmparser 0.226.0", + "wasmparser 0.227.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e433260..74ad676 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,9 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"] resolver="2" [workspace.dependencies] -wast="226" -wat="1.226" -wasmparser={version="0.226", default-features=false} +wast="227" +wat="1.227" +wasmparser={version="0.227", default-features=false} eyre="0.6" log="0.4" pretty_env_logger="0.5" diff --git a/crates/tinywasm/tests/generated/wasm-memory64.csv b/crates/tinywasm/tests/generated/wasm-memory64.csv index 039fe8c..20afc3b 100644 --- a/crates/tinywasm/tests/generated/wasm-memory64.csv +++ b/crates/tinywasm/tests/generated/wasm-memory64.csv @@ -1,2 +1,2 @@ 0.8.0,15081,3214,[{"name":"address.wast","passed":260,"failed":0},{"name":"address0.wast","passed":92,"failed":0},{"name":"address1.wast","passed":127,"failed":0},{"name":"address64.wast","passed":0,"failed":242},{"name":"align.wast","passed":161,"failed":0},{"name":"align0.wast","passed":5,"failed":0},{"name":"align64.wast","passed":83,"failed":73},{"name":"annotations.wast","passed":74,"failed":0},{"name":"array_copy.wast","passed":4,"failed":31},{"name":"array_fill.wast","passed":3,"failed":14},{"name":"array_init_data.wast","passed":2,"failed":31},{"name":"array_init_elem.wast","passed":3,"failed":20},{"name":"binary-gc.wast","passed":1,"failed":0},{"name":"binary-leb128.wast","passed":92,"failed":1},{"name":"binary.wast","passed":124,"failed":0},{"name":"binary0.wast","passed":7,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_cast.wast","passed":6,"failed":31},{"name":"br_on_cast_fail.wast","passed":6,"failed":31},{"name":"br_on_non_null.wast","passed":1,"failed":9},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"call_indirect.wast","passed":47,"failed":124},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"data.wast","passed":59,"failed":6},{"name":"data0.wast","passed":7,"failed":0},{"name":"data1.wast","passed":14,"failed":0},{"name":"data_drop0.wast","passed":11,"failed":0},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness64.wast","passed":0,"failed":69},{"name":"exports.wast","passed":97,"failed":0},{"name":"exports0.wast","passed":8,"failed":0},{"name":"float_exprs0.wast","passed":14,"failed":0},{"name":"float_exprs1.wast","passed":3,"failed":0},{"name":"float_memory0.wast","passed":30,"failed":0},{"name":"float_memory64.wast","passed":0,"failed":90},{"name":"func.wast","passed":175,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":99,"failed":82},{"name":"imports0.wast","passed":8,"failed":0},{"name":"imports1.wast","passed":5,"failed":0},{"name":"imports2.wast","passed":20,"failed":0},{"name":"imports3.wast","passed":10,"failed":0},{"name":"imports4.wast","passed":16,"failed":0},{"name":"linking.wast","passed":122,"failed":41},{"name":"linking0.wast","passed":6,"failed":0},{"name":"linking1.wast","passed":14,"failed":0},{"name":"linking2.wast","passed":11,"failed":0},{"name":"linking3.wast","passed":14,"failed":0},{"name":"load.wast","passed":118,"failed":0},{"name":"load0.wast","passed":3,"failed":0},{"name":"load1.wast","passed":18,"failed":0},{"name":"load2.wast","passed":38,"failed":0},{"name":"load64.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":86,"failed":0},{"name":"memory64.wast","passed":10,"failed":53},{"name":"memory64/array.wast (skipped)","passed":0,"failed":0},{"name":"memory64/extern.wast (skipped)","passed":0,"failed":0},{"name":"memory64/global.wast (skipped)","passed":0,"failed":0},{"name":"memory64/i31.wast (skipped)","passed":0,"failed":0},{"name":"memory64/ref_null.wast (skipped)","passed":0,"failed":0},{"name":"memory64/select.wast (skipped)","passed":0,"failed":0},{"name":"memory64/simd_address.wast (skipped)","passed":0,"failed":0},{"name":"memory64/simd_lane.wast (skipped)","passed":0,"failed":0},{"name":"memory64/struct.wast (skipped)","passed":0,"failed":0},{"name":"memory64/table.wast (skipped)","passed":0,"failed":0},{"name":"memory_copy.wast","passed":8385,"failed":515},{"name":"memory_copy0.wast","passed":29,"failed":0},{"name":"memory_copy1.wast","passed":14,"failed":0},{"name":"memory_fill.wast","passed":164,"failed":36},{"name":"memory_fill0.wast","passed":16,"failed":0},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_grow64.wast","passed":0,"failed":49},{"name":"memory_init.wast","passed":307,"failed":173},{"name":"memory_init0.wast","passed":13,"failed":0},{"name":"memory_redundancy64.wast","passed":0,"failed":8},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_size0.wast","passed":8,"failed":0},{"name":"memory_size1.wast","passed":15,"failed":0},{"name":"memory_size2.wast","passed":21,"failed":0},{"name":"memory_size3.wast","passed":2,"failed":0},{"name":"memory_trap0.wast","passed":14,"failed":0},{"name":"memory_trap1.wast","passed":168,"failed":0},{"name":"memory_trap64.wast","passed":0,"failed":172},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_cast.wast","passed":0,"failed":45},{"name":"ref_eq.wast","passed":6,"failed":83},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_test.wast","passed":0,"failed":71},{"name":"return_call.wast","passed":18,"failed":27},{"name":"return_call_indirect.wast","passed":31,"failed":45},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"simd_memory-multi.wast","passed":0,"failed":1},{"name":"start0.wast","passed":9,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"store0.wast","passed":5,"failed":0},{"name":"store1.wast","passed":13,"failed":0},{"name":"table-sub.wast","passed":2,"failed":1},{"name":"table_copy.wast","passed":1742,"failed":30},{"name":"table_copy_mixed.wast","passed":3,"failed":1},{"name":"table_fill.wast","passed":9,"failed":71},{"name":"table_get.wast","passed":5,"failed":12},{"name":"table_grow.wast","passed":36,"failed":43},{"name":"table_init.wast","passed":588,"failed":288},{"name":"table_set.wast","passed":7,"failed":21},{"name":"table_size.wast","passed":2,"failed":38},{"name":"tag.wast","passed":1,"failed":8},{"name":"throw.wast","passed":3,"failed":10},{"name":"throw_ref.wast","passed":2,"failed":13},{"name":"token.wast","passed":61,"failed":0},{"name":"traps0.wast","passed":15,"failed":0},{"name":"try_table.wast","passed":11,"failed":51},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":6,"failed":14},{"name":"type-subtyping.wast","passed":16,"failed":86},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11}] -0.9.0-alpha.0,1556,42,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":242,"failed":0},{"name":"align64.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":93,"failed":0},{"name":"binary.wast","passed":169,"failed":0},{"name":"endianness64.wast","passed":69,"failed":0},{"name":"float_memory64.wast","passed":90,"failed":0},{"name":"load64.wast","passed":97,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory64.wast","passed":65,"failed":0},{"name":"memory_grow64.wast","passed":49,"failed":0},{"name":"memory_redundancy64.wast","passed":8,"failed":0},{"name":"memory_trap64.wast","passed":172,"failed":0},{"name":"simd_address.wast","passed":7,"failed":42}] +0.9.0-alpha.0,1598,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"address64.wast","passed":242,"failed":0},{"name":"align64.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":93,"failed":0},{"name":"binary.wast","passed":169,"failed":0},{"name":"endianness64.wast","passed":69,"failed":0},{"name":"float_memory64.wast","passed":90,"failed":0},{"name":"load64.wast","passed":97,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory64.wast","passed":65,"failed":0},{"name":"memory_grow64.wast","passed":49,"failed":0},{"name":"memory_redundancy64.wast","passed":8,"failed":0},{"name":"memory_trap64.wast","passed":172,"failed":0},{"name":"simd_address.wast","passed":49,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv b/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv new file mode 100644 index 0000000..a6e6228 --- /dev/null +++ b/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv @@ -0,0 +1 @@ +0.9.0-alpha.0,0,93,[{"name":"i16x8_relaxed_q15mulr_s.wast","passed":0,"failed":3},{"name":"i32x4_relaxed_trunc.wast","passed":0,"failed":17},{"name":"i8x16_relaxed_swizzle.wast","passed":0,"failed":6},{"name":"relaxed_dot_product.wast","passed":0,"failed":11},{"name":"relaxed_laneselect.wast","passed":0,"failed":12},{"name":"relaxed_madd_nmadd.wast","passed":0,"failed":19},{"name":"relaxed_min_max.wast","passed":0,"failed":25}] From 904aa393a7c1f50d247d8af778244a7e76fa665d Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sun, 9 Mar 2025 18:26:50 +0100 Subject: [PATCH 09/17] chore: progress on more simd instructions Signed-off-by: Henry Gressmann --- crates/tinywasm/src/interpreter/executor.rs | 61 ++++++++++++++----- .../src/interpreter/stack/value_stack.rs | 11 ++++ crates/tinywasm/src/store/mod.rs | 1 + crates/tinywasm/tests/generated/wasm-simd.csv | 2 +- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 70c3d97..aff1696 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -331,6 +331,15 @@ impl<'store, 'stack> Executor<'store, 'stack> { V128Store(arg) => self.exec_mem_store::(arg.mem_addr(), arg.offset(), |v| v)?, V128Const(arg) => self.exec_const::( self.cf.data().v128_constants[*arg as usize].to_le_bytes().into()), + I8x16ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + I8x16ExtractLaneU(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + I16x8ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + I16x8ExtractLaneU(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + I32x4ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + I64x2ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + F32x4ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + F64x2ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + V128Load8Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, V128Load16Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, V128Load32Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, @@ -409,30 +418,30 @@ impl<'store, 'stack> Executor<'store, 'stack> { I32x4Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, I64x2Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, - I8x16AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, - I16x8AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, - I32x4AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, - I64x2AllTrue => self.stack.values.replace_top::(|v| Ok((v != Simd::splat(0)) as i32)).to_cf()?, + I8x16AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + I16x8AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + I32x4AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + I64x2AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, I8x16Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, I16x8Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, I32x4Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, I64x2Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, - I8x16Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, - I16x8Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, - I32x4Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, - I64x2Shl => self.stack.values.calculate_same::(|a, b| Ok(a.shl(b))).to_cf()?, + I8x16Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i8))).to_cf()?, + I16x8Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i16))).to_cf()?, + I32x4Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i32))).to_cf()?, + I64x2Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i64))).to_cf()?, - I8x16ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, - I16x8ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, - I32x4ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, - I64x2ShrS => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I8x16ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i8))).to_cf()?, + I16x8ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i16))).to_cf()?, + I32x4ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i32))).to_cf()?, + I64x2ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i64))).to_cf()?, - I8x16ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, - I16x8ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, - I32x4ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, - I64x2ShrU => self.stack.values.calculate_same::(|a, b| Ok(a.shr(b))).to_cf()?, + I8x16ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u8))).to_cf()?, + I16x8ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u16))).to_cf()?, + I32x4ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u32))).to_cf()?, + I64x2ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u64))).to_cf()?, I8x16Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, I16x8Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, @@ -471,6 +480,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { I8x16SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, I16x8SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + I16x8Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + I32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + F32x4Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, F64x2Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, F32x4Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, @@ -496,6 +508,23 @@ impl<'store, 'stack> Executor<'store, 'stack> { F32x4Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, F64x2Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + F32x4PMin => unimplemented!(), + F32x4PMax => unimplemented!(), + F64x2PMin => unimplemented!(), + F64x2PMax => unimplemented!(), + + // not correct + I32x4TruncSatF32x4S => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, + I32x4TruncSatF32x4U => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, + F32x4ConvertI32x4S => {}, + F32x4ConvertI32x4U => {}, + F64x2ConvertLowI32x4S => {}, + F64x2ConvertLowI32x4U => {}, + F32x4DemoteF64x2Zero => {}, + F64x2PromoteLowF32x4 => {}, + I32x4TruncSatF64x2SZero => unimplemented!(), + I32x4TruncSatF64x2UZero => unimplemented!(), + i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index bb5b2ea..01cea1c 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -87,6 +87,17 @@ impl ValueStack { Ok(()) } + #[inline] + pub(crate) fn calculate_diff( + &mut self, + func: impl FnOnce(A, B) -> Result, + ) -> Result<()> { + let v2 = B::stack_pop(self); + let v1 = A::stack_pop(self); + RES::stack_push(self, func(v1, v2)?); + Ok(()) + } + #[inline] pub(crate) fn replace_top( &mut self, diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 358cbef..d53654e 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -442,6 +442,7 @@ impl Store { F64Const(f) => (*f).into(), I32Const(i) => (*i).into(), I64Const(i) => (*i).into(), + V128Const(i) => (*i).into(), GlobalGet(addr) => { let addr = module_global_addrs.get(*addr as usize).ok_or_else(|| { Error::Other(format!("global {addr} not found. This should have been caught by the validator")) diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index 6f37f4d..79adc36 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,14613,11367,[{"name":"simd_address.wast","passed":48,"failed":1},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":241,"failed":36},{"name":"simd_const.wast","passed":751,"failed":6},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1357,"failed":465},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1360,"failed":465},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":138,"failed":56},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":138,"failed":56},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":148,"failed":63},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":213,"failed":262},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":34,"failed":5},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":157,"failed":28},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] +0.9.0-alpha.0,15151,10829,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1357,"failed":465},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1360,"failed":465},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":148,"failed":63},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":4,"failed":48}] From 7806d394d645af9d9d830d4b3662d4abef4df347 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sun, 9 Mar 2025 19:02:35 +0100 Subject: [PATCH 10/17] chore: progress on more simd instructions Signed-off-by: Henry Gressmann --- crates/tinywasm/src/interpreter/executor.rs | 107 +++++++++++++++++- crates/tinywasm/tests/generated/wasm-simd.csv | 2 +- 2 files changed, 102 insertions(+), 7 deletions(-) diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index aff1696..a00b693 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -470,6 +470,13 @@ impl<'store, 'stack> Executor<'store, 'stack> { I32x4MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, I64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + I16x8Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + I32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + + I8x16NarrowI16x8S => unimplemented!(), + I8x16NarrowI16x8U => unimplemented!(), + I16x8NarrowI32x4S => unimplemented!(), + I16x8NarrowI32x4U => unimplemented!(), I8x16AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, I16x8AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, @@ -480,8 +487,72 @@ impl<'store, 'stack> Executor<'store, 'stack> { I8x16SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, I16x8SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, - I16x8Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, - I32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + I16x8ExtAddPairwiseI8x16S => unimplemented!(), + I16x8ExtAddPairwiseI8x16U => unimplemented!(), + I32x4ExtAddPairwiseI16x8S => unimplemented!(), + I32x4ExtAddPairwiseI16x8U => unimplemented!(), + + I16x8ExtMulLowI8x16S => unimplemented!(), + I16x8ExtMulLowI8x16U => unimplemented!(), + I16x8ExtMulHighI8x16S => unimplemented!(), + I16x8ExtMulHighI8x16U => unimplemented!(), + I32x4ExtMulLowI16x8S => unimplemented!(), + I32x4ExtMulLowI16x8U => unimplemented!(), + I32x4ExtMulHighI16x8S => unimplemented!(), + I32x4ExtMulHighI16x8U => unimplemented!(), + I64x2ExtMulLowI32x4S => unimplemented!(), + I64x2ExtMulLowI32x4U => unimplemented!(), + I64x2ExtMulHighI32x4S => unimplemented!(), + I64x2ExtMulHighI32x4U => unimplemented!(), + + I16x8ExtendLowI8x16S => unimplemented!(), + I16x8ExtendLowI8x16U => unimplemented!(), + I16x8ExtendHighI8x16S => unimplemented!(), + I16x8ExtendHighI8x16U => unimplemented!(), + I32x4ExtendLowI16x8S => unimplemented!(), + I32x4ExtendLowI16x8U => unimplemented!(), + I32x4ExtendHighI16x8S => unimplemented!(), + I32x4ExtendHighI16x8U => unimplemented!(), + I64x2ExtendLowI32x4S => unimplemented!(), + I64x2ExtendLowI32x4U => unimplemented!(), + I64x2ExtendHighI32x4S => unimplemented!(), + I64x2ExtendHighI32x4U => unimplemented!(), + + I8x16Popcnt => self.stack.values.replace_top::(|v| Ok(v.count_ones())).to_cf()?, + + I16x8Q15MulrSatS => self.stack.values.calculate_same::(|a, b| { + let subq15mulr = |a,b| { + let a = a as i32; + let b = b as i32; + let r = (a * b + 0x4000) >> 15; + if r > i16::MAX as i32 { + i16::MAX + } else if r < i16::MIN as i32 { + i16::MIN + } else { + r as i16 + } + }; + Ok(Simd::::from_array([ + subq15mulr(a[0], b[0]), + subq15mulr(a[1], b[1]), + subq15mulr(a[2], b[2]), + subq15mulr(a[3], b[3]), + subq15mulr(a[4], b[4]), + subq15mulr(a[5], b[5]), + subq15mulr(a[6], b[6]), + subq15mulr(a[7], b[7]), + ])) + }).to_cf()?, + + I32x4DotI16x8S => self.stack.values.calculate::(|a, b| { + Ok(Simd::::from_array([ + i32::from(a[0] * b[0] + a[1] * b[1]), + i32::from(a[2] * b[2] + a[3] * b[3]), + i32::from(a[4] * b[4] + a[5] * b[5]), + i32::from(a[6] * b[6] + a[7] * b[7]), + ])) + }).to_cf()?, F32x4Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, F64x2Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, @@ -508,10 +579,34 @@ impl<'store, 'stack> Executor<'store, 'stack> { F32x4Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, F64x2Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - F32x4PMin => unimplemented!(), - F32x4PMax => unimplemented!(), - F64x2PMin => unimplemented!(), - F64x2PMax => unimplemented!(), + F32x4PMin => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + if b[0] < a[0] { b[0] } else { a[0]}, + if b[1] < a[1] { b[1] } else { a[1]}, + if b[2] < a[2] { b[2] } else { a[2]}, + if b[3] < a[3] { b[3] } else { a[3]}, + ])) + }).to_cf()?, + F32x4PMax => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + if b[0] > a[0] { b[0] } else { a[0]}, + if b[1] > a[1] { b[1] } else { a[1]}, + if b[2] > a[2] { b[2] } else { a[2]}, + if b[3] > a[3] { b[3] } else { a[3]}, + ])) + }).to_cf()?, + F64x2PMin => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + if b[0] < a[0] { b[0] } else { a[0]}, + if b[1] < a[1] { b[1] } else { a[1]}, + ])) + }).to_cf()?, + F64x2PMax => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + if b[0] > a[0] { b[0] } else { a[0]}, + if b[1] > a[1] { b[1] } else { a[1]}, + ])) + }).to_cf()?, // not correct I32x4TruncSatF32x4S => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index 79adc36..6a25709 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,15151,10829,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1357,"failed":465},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1360,"failed":465},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":26},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":148,"failed":63},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":4,"failed":48}] +0.9.0-alpha.0,22962,3018,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1357,"failed":465},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1360,"failed":465},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":16},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":179,"failed":32},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":4,"failed":48}] From 353a676cc58473a6a0292d48b32335d8f6c75504 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sun, 9 Mar 2025 20:05:17 +0100 Subject: [PATCH 11/17] chore: progress on more simd instructions Signed-off-by: Henry Gressmann --- crates/tinywasm/src/interpreter/executor.rs | 91 +++++++++++-------- .../tinywasm/src/interpreter/num_helpers.rs | 18 ++++ crates/tinywasm/tests/generated/wasm-simd.csv | 2 +- 3 files changed, 74 insertions(+), 37 deletions(-) diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index a00b693..b5521e7 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -3,21 +3,15 @@ use super::no_std_floats::NoStdFloatExt; use alloc::{format, rc::Rc, string::ToString}; -use core::ops::{ControlFlow, IndexMut, Shl, Shr}; +use core::ops::{ControlFlow, Index, IndexMut, Shl, Shr}; use interpreter::stack::CallFrame; use tinywasm_types::*; +#[cfg(all(feature = "std", feature = "simd"))] +use crate::std::simd::StdFloat; #[cfg(feature = "simd")] -mod simd { - #[cfg(feature = "std")] - pub(super) use crate::std::simd::StdFloat; - pub(super) use core::simd::cmp::{SimdOrd, SimdPartialEq, SimdPartialOrd}; - pub(super) use core::simd::num::{SimdFloat, SimdInt, SimdUint}; - pub(super) use core::simd::*; -} -#[cfg(feature = "simd")] -use simd::*; +use core::simd::{cmp::*, num::*, *}; use super::num_helpers::*; use super::stack::{BlockFrame, BlockType, Stack}; @@ -329,6 +323,22 @@ impl<'store, 'stack> Executor<'store, 'stack> { I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, V128Load(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| v)?, V128Store(arg) => self.exec_mem_store::(arg.mem_addr(), arg.offset(), |v| v)?, + + V128Store8Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + V128Store16Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + V128Store32Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + V128Store64Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + + // Load a single 32-bit or 64-bit element into the lowest bits of a v128 vector, and initialize all other bits of the v128 vector to zero. + V128Load32Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| { + let bytes = v.to_le_bytes(); + u8x16::from_array([bytes[0], bytes[1], bytes[2], bytes[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + })?, + V128Load64Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| { + let bytes = v.to_le_bytes(); + u8x16::from_array([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], 0, 0, 0, 0, 0, 0, 0, 0]) + })?, + V128Const(arg) => self.exec_const::( self.cf.data().v128_constants[*arg as usize].to_le_bytes().into()), I8x16ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, @@ -564,16 +574,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { F64x2Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, F32x4Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, F64x2Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, - F32x4Sqrt => self.stack.values.replace_top_same::(|v| Ok(v.sqrt())).to_cf()?, - F64x2Sqrt => self.stack.values.replace_top_same::(|v| Ok(v.sqrt())).to_cf()?, - F32x4Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, - F64x2Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, - F32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, - F64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, - F32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, - F64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, - F32x4Div => self.stack.values.calculate_same::(|a, b| Ok(a / b)).to_cf()?, - F64x2Div => self.stack.values.calculate_same::(|a, b| Ok(a / b)).to_cf()?, + F32x4Sqrt => self.stack.values.replace_top_same::(|v| Ok(canonicalize_f32x4(v.sqrt()))).to_cf()?, + F64x2Sqrt => self.stack.values.replace_top_same::(|v| Ok(canonicalize_f64x2(v.sqrt()))).to_cf()?, + F32x4Add => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a + b))).to_cf()?, + F64x2Add => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a + b))).to_cf()?, + F32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a - b))).to_cf()?, + F64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a - b))).to_cf()?, + F32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a * b))).to_cf()?, + F64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a * b))).to_cf()?, + F32x4Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a / b))).to_cf()?, + F64x2Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a / b))).to_cf()?, F32x4Min => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, F64x2Min => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, F32x4Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, @@ -952,7 +962,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { &mut self, mem_addr: tinywasm_types::MemAddr, offset: u64, - lanes: u8, + lane: u8, ) -> ControlFlow> { let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); let mut imm = self.stack.values.pop::(); @@ -966,25 +976,11 @@ impl<'store, 'stack> Executor<'store, 'stack> { }))); }; let val = mem.load_as::(addr).to_cf()?; - imm[lanes as usize] = val; + imm[lane as usize] = val; self.stack.values.push(imm); ControlFlow::Continue(()) } - // fn mem_load, const LOAD_SIZE: usize, TARGET: InternalValue>( - // &mut self, - // mem_addr: tinywasm_types::MemAddr, - // offset: u64, - // ) -> Result { - // let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); - // let val = self.stack.values.pop::() as u64; - // let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else { - // cold(); - // return Err(Error::Trap(Trap::MemoryOutOfBounds { offset: val as usize, len: LOAD_SIZE, max: 0 })); - // }; - // mem.load_as::(addr) - // } - fn exec_mem_load, const LOAD_SIZE: usize, TARGET: InternalValue>( &mut self, mem_addr: tinywasm_types::MemAddr, @@ -1010,6 +1006,29 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.stack.values.push(cast(val)); ControlFlow::Continue(()) } + + fn exec_mem_store_lane, U: MemStorable + Copy, const N: usize>( + &mut self, + mem_addr: tinywasm_types::MemAddr, + offset: u64, + lane: u8, + ) -> ControlFlow> { + let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr)); + let val = self.stack.values.pop::(); + let val = val[lane as usize].to_mem_bytes(); + + let addr = match mem.is_64bit() { + true => self.stack.values.pop::() as u64, + false => self.stack.values.pop::() as u32 as u64, + }; + + if let Err(e) = mem.store((offset + addr) as usize, val.len(), &val) { + return ControlFlow::Break(Some(e)); + } + + ControlFlow::Continue(()) + } + fn exec_mem_store, const N: usize>( &mut self, mem_addr: tinywasm_types::MemAddr, diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index 02fbc24..9b6345c 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -180,3 +180,21 @@ macro_rules! impl_checked_wrapping_rem { } impl_checked_wrapping_rem! { i32 i64 u32 u64 } + +#[cfg(feature = "simd")] +/// replace all NaNs in a f32x4 with f32::NAN +pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { + use core::simd::{Simd, num::SimdFloat}; + let nan = Simd::splat(f32::NAN); + let mask = x.is_nan(); + mask.select(nan, x) +} + +#[cfg(feature = "simd")] +/// replace all NaNs in a f64x2 with f64::NAN +pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 { + use core::simd::{Simd, num::SimdFloat}; + let nan = Simd::splat(f64::NAN); + let mask = x.is_nan(); + mask.select(nan, x) +} diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index 6a25709..c3f307c 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,22962,3018,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1357,"failed":465},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1360,"failed":465},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":16},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":179,"failed":32},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":4,"failed":48}] +0.9.0-alpha.0,24030,1950,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1822,"failed":0},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1824,"failed":1},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":16},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":179,"failed":32},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":36,"failed":0},{"name":"simd_store32_lane.wast","passed":24,"failed":0},{"name":"simd_store64_lane.wast","passed":16,"failed":0},{"name":"simd_store8_lane.wast","passed":52,"failed":0}] From 9b3e8fee9731d1f21fd573b562775a841f7d1209 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Tue, 11 Mar 2025 20:11:35 +0100 Subject: [PATCH 12/17] fix: canonicalize simd nan values Signed-off-by: Henry Gressmann --- crates/tinywasm/src/interpreter/executor.rs | 32 ++++++++++++++++--- .../tinywasm/src/interpreter/num_helpers.rs | 9 ++++-- crates/tinywasm/tests/generated/wasm-simd.csv | 2 +- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index b5521e7..d6d8089 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -584,10 +584,34 @@ impl<'store, 'stack> Executor<'store, 'stack> { F64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a * b))).to_cf()?, F32x4Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a / b))).to_cf()?, F64x2Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a / b))).to_cf()?, - F32x4Min => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - F64x2Min => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - F32x4Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - F64x2Max => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + F32x4Min => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + b[0].tw_minimum(a[0]), + b[1].tw_minimum(a[1]), + b[2].tw_minimum(a[2]), + b[3].tw_minimum(a[3]), + ])) + }).to_cf()?, + F64x2Min => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + b[0].tw_minimum(a[0]), + b[1].tw_minimum(a[1]), + ])) + }).to_cf()?, + F32x4Max => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + b[0].tw_maximum(a[0]), + b[1].tw_maximum(a[1]), + b[2].tw_maximum(a[2]), + b[3].tw_maximum(a[3]), + ])) + }).to_cf()?, + F64x2Max => self.stack.values.calculate_same::(|a, b| { + Ok(Simd::::from_array([ + b[0].tw_maximum(a[0]), + b[1].tw_maximum(a[1]), + ])) + }).to_cf()?, F32x4PMin => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index 9b6345c..bba35cb 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -74,7 +74,8 @@ macro_rules! impl_wasm_float_ops { // https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest fn tw_nearest(self) -> Self { match self { - x if x.is_nan() => x, // preserve NaN + // x if x.is_nan() => x, // preserve NaN + x if x.is_nan() => Self::NAN, // Do not preserve NaN x if x.is_infinite() || x == 0.0 => x, // preserve infinities and zeros x if (0.0..=0.5).contains(&x) => 0.0, x if (-0.5..0.0).contains(&x) => -0.0, @@ -99,7 +100,8 @@ macro_rules! impl_wasm_float_ops { Some(core::cmp::Ordering::Less) => self, Some(core::cmp::Ordering::Greater) => other, Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { self } else { other }, - None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + // None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + None => Self::NAN, // Do not preserve NaN } } @@ -111,7 +113,8 @@ macro_rules! impl_wasm_float_ops { Some(core::cmp::Ordering::Greater) => self, Some(core::cmp::Ordering::Less) => other, Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { other } else { self }, - None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + // None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + None => Self::NAN, // Do not preserve NaN } } } diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index c3f307c..86b7780 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,24030,1950,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":629,"failed":161},{"name":"simd_f32x4_arith.wast","passed":1822,"failed":0},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":639,"failed":164},{"name":"simd_f64x2_arith.wast","passed":1824,"failed":1},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":16},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":179,"failed":32},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":36,"failed":0},{"name":"simd_store32_lane.wast","passed":24,"failed":0},{"name":"simd_store64_lane.wast","passed":16,"failed":0},{"name":"simd_store8_lane.wast","passed":52,"failed":0}] +0.9.0-alpha.0,24355,1625,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":56,"failed":226},{"name":"simd_f32x4.wast","passed":790,"failed":0},{"name":"simd_f32x4_arith.wast","passed":1822,"failed":0},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f32x4_rounding.wast","passed":148,"failed":53},{"name":"simd_f64x2.wast","passed":803,"failed":0},{"name":"simd_f64x2_arith.wast","passed":1824,"failed":1},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f64x2_rounding.wast","passed":148,"failed":53},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":142,"failed":30},{"name":"simd_i16x8_cmp.wast","passed":436,"failed":29},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":450,"failed":25},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":16},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":17,"failed":90},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":97,"failed":16},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":179,"failed":32},{"name":"simd_i8x16_cmp.wast","passed":409,"failed":36},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":331,"failed":144},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":37,"failed":2},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_splat.wast","passed":183,"failed":2},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":36,"failed":0},{"name":"simd_store32_lane.wast","passed":24,"failed":0},{"name":"simd_store64_lane.wast","passed":16,"failed":0},{"name":"simd_store8_lane.wast","passed":52,"failed":0}] From cdc0015b7752b5404f6edd2777ad62a9eb2e6244 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 3 Apr 2025 00:52:27 +0200 Subject: [PATCH 13/17] chore: update deps, cargo fmt Signed-off-by: Henry Gressmann --- Cargo.lock | 128 +++++++----------- Cargo.toml | 6 +- crates/cli/src/bin.rs | 2 +- crates/cli/src/wat.rs | 2 +- crates/parser/src/lib.rs | 8 +- crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/src/interpreter/executor.rs | 4 +- .../tests/host_func_signature_check.rs | 2 +- crates/tinywasm/tests/test-wasm-1.rs | 2 +- crates/tinywasm/tests/test-wasm-2.rs | 2 +- crates/tinywasm/tests/test-wasm-3.rs | 2 +- .../tinywasm/tests/test-wasm-annotations.rs | 2 +- .../tests/test-wasm-extended-const.rs | 2 +- .../tinywasm/tests/test-wasm-multi-memory.rs | 2 +- .../tinywasm/tests/test-wasm-relaxed-simd.rs | 2 +- crates/tinywasm/tests/test-wast.rs | 2 +- crates/tinywasm/tests/testsuite/mod.rs | 2 +- crates/tinywasm/tests/testsuite/run.rs | 4 +- crates/tinywasm/tests/testsuite/util.rs | 14 +- examples/archive.rs | 2 +- examples/funcref_callbacks.rs | 2 +- examples/wasm-rust.rs | 2 +- 22 files changed, 82 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00d3aaa..48bfcf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,18 +114,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.31" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" dependencies = [ "anstyle", "clap_lex", @@ -258,9 +258,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "cfg-if", "crunchy", @@ -274,15 +274,15 @@ checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" [[package]] name = "humantime" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "include_dir" @@ -311,9 +311,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown", @@ -321,9 +321,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", @@ -353,9 +353,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libm" @@ -365,9 +365,9 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -386,15 +386,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "owo-colors" @@ -435,9 +435,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -520,18 +520,18 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -552,9 +552,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.99" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -596,7 +596,7 @@ dependencies = [ "tinywasm-parser", "tinywasm-types", "wasm-testsuite", - "wast 227.0.0", + "wast", "wat", ] @@ -609,7 +609,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast 227.0.0", + "wast", ] [[package]] @@ -618,7 +618,7 @@ version = "0.9.0-alpha.0" dependencies = [ "log", "tinywasm-types", - "wasmparser 0.227.0", + "wasmparser", ] [[package]] @@ -664,50 +664,29 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.226.0" +version = "0.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d81b727619aec227dce83e7f7420d4e56c79acd044642a356ea045b98d4e13" +checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" dependencies = [ "leb128fmt", - "wasmparser 0.226.0", -] - -[[package]] -name = "wasm-encoder" -version = "0.227.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829806010c17fa417fa56a42b76efadb35d70dbd972de9f07373b87d2729b698" -dependencies = [ - "leb128fmt", - "wasmparser 0.227.0", + "wasmparser", ] [[package]] name = "wasm-testsuite" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01c897a970135c086793fa320de6632534ad7b4a519a3ca51c7ef40e6a567d7" +checksum = "ec81df5b65371f919b41f3682861d98f1c90d081cfd8cb68784eb5d942dc1e36" dependencies = [ "include_dir", - "wast 226.0.0", -] - -[[package]] -name = "wasmparser" -version = "0.226.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc28600dcb2ba68d7e5f1c3ba4195c2bddc918c0243fd702d0b6dbd05689b681" -dependencies = [ - "bitflags", - "indexmap", - "semver", + "wast", ] [[package]] name = "wasmparser" -version = "0.227.0" +version = "0.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15e32b1ab55e5e112f7c1dabd0d3f57c61992bfb0c4d4a6f141fe65c10ba750" +checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" dependencies = [ "bitflags", "indexmap", @@ -716,37 +695,24 @@ dependencies = [ [[package]] name = "wast" -version = "226.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb903956d0151eabb6c30a2304dd61e5c8d7182805226120c2b6d611fb09a26" -dependencies = [ - "bumpalo", - "leb128fmt", - "memchr", - "unicode-width", - "wasm-encoder 0.226.0", -] - -[[package]] -name = "wast" -version = "227.0.0" +version = "228.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9ba0f7fe54ce2895314110aac579043d43175f66201153a0549badfa0fb04e" +checksum = "9e5aae124478cb51439f6587f074a3a5e835afd22751c59a87b2e2a882727c97" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.227.0", + "wasm-encoder", ] [[package]] name = "wat" -version = "1.227.0" +version = "1.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc4d0762d835bf25be727f4320a8b08ce4451fb1e5868940ad7708503c6a6c9" +checksum = "7ec29c89a8d055df988de7236483bf569988ac3d6905899f6af5ef920f9385ad" dependencies = [ - "wast 227.0.0", + "wast", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 74ad676..56e0be1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,9 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"] resolver="2" [workspace.dependencies] -wast="227" -wat="1.227" -wasmparser={version="0.227", default-features=false} +wast="228" +wat="1.228" +wasmparser={version="0.228", default-features=false} eyre="0.6" log="0.4" pretty_env_logger="0.5" diff --git a/crates/cli/src/bin.rs b/crates/cli/src/bin.rs index 6efbba1..8c0fe93 100644 --- a/crates/cli/src/bin.rs +++ b/crates/cli/src/bin.rs @@ -4,7 +4,7 @@ use argh::FromArgs; use args::WasmArg; use eyre::Result; use log::{debug, info}; -use tinywasm::{types::WasmValue, Module}; +use tinywasm::{Module, types::WasmValue}; use crate::args::to_wasm_args; mod args; diff --git a/crates/cli/src/wat.rs b/crates/cli/src/wat.rs index fd00a8e..8d2998d 100644 --- a/crates/cli/src/wat.rs +++ b/crates/cli/src/wat.rs @@ -1,6 +1,6 @@ use wast::{ - parser::{self, ParseBuffer}, Wat, + parser::{self, ParseBuffer}, }; pub fn wat2wasm(wat: &str) -> Vec { diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index e5022c5..1292fa6 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -70,8 +70,6 @@ impl Parser { gc_types: true, stack_switching: false, component_model: false, - component_model_nested_names: false, - component_model_values: false, exceptions: false, gc: false, memory_control: false, @@ -79,7 +77,11 @@ impl Parser { threads: false, shared_everything_threads: false, legacy_exceptions: false, - component_model_async: false, + cm_async: false, + cm_async_builtins: false, + cm_async_stackful: false, + cm_nested_names: false, + cm_values: false, }; Validator::new_with_features(features.into()) } diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 8af013d..5810f0e 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false libm={version="0.2", default-features=false} [dev-dependencies] -wasm-testsuite={version="0.5.0"} +wasm-testsuite={version="0.5.2"} indexmap="2.7" wast={workspace=true} wat={workspace=true} diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index d6d8089..a0153af 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -440,12 +440,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { I8x16Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i8))).to_cf()?, I16x8Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i16))).to_cf()?, - I32x4Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i32))).to_cf()?, + I32x4Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a))).to_cf()?, I64x2Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i64))).to_cf()?, I8x16ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i8))).to_cf()?, I16x8ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i16))).to_cf()?, - I32x4ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i32))).to_cf()?, + I32x4ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a))).to_cf()?, I64x2ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i64))).to_cf()?, I8x16ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u8))).to_cf()?, diff --git a/crates/tinywasm/tests/host_func_signature_check.rs b/crates/tinywasm/tests/host_func_signature_check.rs index c60ade2..698ad61 100644 --- a/crates/tinywasm/tests/host_func_signature_check.rs +++ b/crates/tinywasm/tests/host_func_signature_check.rs @@ -1,8 +1,8 @@ use eyre::Result; use std::fmt::Write; use tinywasm::{ - types::{FuncType, ValType, WasmValue}, Extern, FuncContext, Imports, Module, Store, + types::{FuncType, ValType, WasmValue}, }; use tinywasm_types::ExternRef; diff --git a/crates/tinywasm/tests/test-wasm-1.rs b/crates/tinywasm/tests/test-wasm-1.rs index 94c83f9..be235ae 100644 --- a/crates/tinywasm/tests/test-wasm-1.rs +++ b/crates/tinywasm/tests/test-wasm-1.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{spec, SpecVersion}; +use wasm_testsuite::data::{SpecVersion, spec}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); diff --git a/crates/tinywasm/tests/test-wasm-2.rs b/crates/tinywasm/tests/test-wasm-2.rs index 9b30ac0..0379ca6 100644 --- a/crates/tinywasm/tests/test-wasm-2.rs +++ b/crates/tinywasm/tests/test-wasm-2.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{spec, SpecVersion}; +use wasm_testsuite::data::{SpecVersion, spec}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); diff --git a/crates/tinywasm/tests/test-wasm-3.rs b/crates/tinywasm/tests/test-wasm-3.rs index a0e2543..3e63dc5 100644 --- a/crates/tinywasm/tests/test-wasm-3.rs +++ b/crates/tinywasm/tests/test-wasm-3.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{spec, SpecVersion}; +use wasm_testsuite::data::{SpecVersion, spec}; fn main() -> Result<()> { if !std::env::args().any(|x| &x == "--enable") { diff --git a/crates/tinywasm/tests/test-wasm-annotations.rs b/crates/tinywasm/tests/test-wasm-annotations.rs index 3170241..beac9eb 100644 --- a/crates/tinywasm/tests/test-wasm-annotations.rs +++ b/crates/tinywasm/tests/test-wasm-annotations.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{proposal, Proposal}; +use wasm_testsuite::data::{Proposal, proposal}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); diff --git a/crates/tinywasm/tests/test-wasm-extended-const.rs b/crates/tinywasm/tests/test-wasm-extended-const.rs index 7c9a304..888a49f 100644 --- a/crates/tinywasm/tests/test-wasm-extended-const.rs +++ b/crates/tinywasm/tests/test-wasm-extended-const.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{proposal, Proposal}; +use wasm_testsuite::data::{Proposal, proposal}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); diff --git a/crates/tinywasm/tests/test-wasm-multi-memory.rs b/crates/tinywasm/tests/test-wasm-multi-memory.rs index d491fb1..30052b0 100644 --- a/crates/tinywasm/tests/test-wasm-multi-memory.rs +++ b/crates/tinywasm/tests/test-wasm-multi-memory.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{proposal, Proposal}; +use wasm_testsuite::data::{Proposal, proposal}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); diff --git a/crates/tinywasm/tests/test-wasm-relaxed-simd.rs b/crates/tinywasm/tests/test-wasm-relaxed-simd.rs index 7af830a..0851d18 100644 --- a/crates/tinywasm/tests/test-wasm-relaxed-simd.rs +++ b/crates/tinywasm/tests/test-wasm-relaxed-simd.rs @@ -1,7 +1,7 @@ mod testsuite; use eyre::Result; use testsuite::TestSuite; -use wasm_testsuite::data::{proposal, Proposal}; +use wasm_testsuite::data::{Proposal, proposal}; fn main() -> Result<()> { TestSuite::set_log_level(log::LevelFilter::Off); diff --git a/crates/tinywasm/tests/test-wast.rs b/crates/tinywasm/tests/test-wast.rs index 33c716c..40b0e04 100644 --- a/crates/tinywasm/tests/test-wast.rs +++ b/crates/tinywasm/tests/test-wast.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use eyre::{bail, eyre, Result}; +use eyre::{Result, bail, eyre}; use owo_colors::OwoColorize; use testsuite::TestSuite; diff --git a/crates/tinywasm/tests/testsuite/mod.rs b/crates/tinywasm/tests/testsuite/mod.rs index ee0336e..c1ba46e 100644 --- a/crates/tinywasm/tests/testsuite/mod.rs +++ b/crates/tinywasm/tests/testsuite/mod.rs @@ -1,5 +1,5 @@ #![allow(unused)] -use eyre::{eyre, Result}; +use eyre::{Result, eyre}; use indexmap::IndexMap; use owo_colors::OwoColorize; use std::io::{BufRead, Seek, SeekFrom}; diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index 0804266..d09efdb 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -2,14 +2,14 @@ use crate::testsuite::util::*; use std::{borrow::Cow, collections::HashMap, fs::canonicalize, path::PathBuf}; use super::TestSuite; -use eyre::{eyre, Result}; +use eyre::{Result, eyre}; use indexmap::IndexMap; use log::{debug, error, info}; use tinywasm::{Extern, Imports, ModuleInstance}; use tinywasm_types::{ExternVal, MemoryType, ModuleInstanceAddr, TableType, ValType, WasmValue}; use wasm_testsuite::data::TestFile; use wasm_testsuite::wast; -use wasm_testsuite::wast::{lexer::Lexer, parser::ParseBuffer, Wast}; +use wasm_testsuite::wast::{Wast, lexer::Lexer, parser::ParseBuffer}; #[derive(Default)] struct ModuleRegistry { diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index 91a1e41..5e8558a 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -102,7 +102,7 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result WasmValue::F64(f64::from_bits(f.bits)), I32(i) => WasmValue::I32(i), I64(i) => WasmValue::I64(i), - V128(i) => WasmValue::V128(i128::from_le_bytes(i.to_le_bytes()).try_into().unwrap()), + V128(i) => WasmValue::V128(i128::from_le_bytes(i.to_le_bytes())), RefExtern(v) => WasmValue::RefExtern(ExternRef::new(Some(v))), RefNull(t) => match t { wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Func } => { @@ -120,15 +120,15 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result i128 { let res: Vec = match i { wast::core::V128Pattern::F32x4(f) => { - f.iter().map(|v| nanpattern2tinywasmvalue(*v).unwrap().as_f32().unwrap().to_le_bytes()).flatten().collect() + f.iter().flat_map(|v| nanpattern2tinywasmvalue(*v).unwrap().as_f32().unwrap().to_le_bytes()).collect() } wast::core::V128Pattern::F64x2(f) => { - f.iter().map(|v| nanpattern2tinywasmvalue(*v).unwrap().as_f64().unwrap().to_le_bytes()).flatten().collect() + f.iter().flat_map(|v| nanpattern2tinywasmvalue(*v).unwrap().as_f64().unwrap().to_le_bytes()).collect() } - wast::core::V128Pattern::I16x8(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), - wast::core::V128Pattern::I32x4(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), - wast::core::V128Pattern::I64x2(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), - wast::core::V128Pattern::I8x16(f) => f.iter().map(|v| v.to_le_bytes()).flatten().collect(), + wast::core::V128Pattern::I16x8(f) => f.iter().flat_map(|v| v.to_le_bytes()).collect(), + wast::core::V128Pattern::I32x4(f) => f.iter().flat_map(|v| v.to_le_bytes()).collect(), + wast::core::V128Pattern::I64x2(f) => f.iter().flat_map(|v| v.to_le_bytes()).collect(), + wast::core::V128Pattern::I8x16(f) => f.iter().flat_map(|v| v.to_le_bytes()).collect(), }; i128::from_le_bytes(res.try_into().unwrap()) diff --git a/examples/archive.rs b/examples/archive.rs index 6a3d54e..7a1021b 100644 --- a/examples/archive.rs +++ b/examples/archive.rs @@ -1,5 +1,5 @@ use eyre::Result; -use tinywasm::{parser::Parser, types::TinyWasmModule, Module, Store}; +use tinywasm::{Module, Store, parser::Parser, types::TinyWasmModule}; const WASM: &str = r#" (module diff --git a/examples/funcref_callbacks.rs b/examples/funcref_callbacks.rs index df50e75..01f833c 100644 --- a/examples/funcref_callbacks.rs +++ b/examples/funcref_callbacks.rs @@ -1,5 +1,5 @@ use eyre::Result; -use tinywasm::{types::FuncRef, Extern, FuncContext, Imports, Module, Store}; +use tinywasm::{Extern, FuncContext, Imports, Module, Store, types::FuncRef}; fn main() -> Result<()> { by_func_ref_passed()?; diff --git a/examples/wasm-rust.rs b/examples/wasm-rust.rs index 95769f4..d5a6b2a 100644 --- a/examples/wasm-rust.rs +++ b/examples/wasm-rust.rs @@ -1,6 +1,6 @@ use std::hint::black_box; -use eyre::{eyre, Result}; +use eyre::{Result, eyre}; use tinywasm::{Extern, FuncContext, Imports, MemoryStringExt, Module, Store}; /// Examples of using WebAssembly compiled from Rust with tinywasm. From 3664c8b79918ffad109ccec32336d38c299f1351 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 23 Apr 2025 20:46:50 +0200 Subject: [PATCH 14/17] chore: update deps, properly feature gate simd Signed-off-by: Henry Gressmann --- Cargo.lock | 36 +- Cargo.toml | 6 +- crates/parser/src/lib.rs | 1 + crates/parser/src/module.rs | 2 +- crates/parser/src/visit.rs | 6 +- crates/tinywasm/Cargo.toml | 8 +- crates/tinywasm/src/interpreter/executor.rs | 511 +++++++++--------- .../tinywasm/src/interpreter/num_helpers.rs | 4 +- .../src/interpreter/stack/call_stack.rs | 1 + .../src/interpreter/stack/value_stack.rs | 6 +- crates/tinywasm/src/interpreter/values.rs | 17 +- crates/tinywasm/src/lib.rs | 2 +- crates/tinywasm/src/store/memory.rs | 4 +- crates/tinywasm/tests/generated/wasm-1.csv | 2 +- crates/tinywasm/tests/generated/wasm-2.csv | 2 +- .../tests/generated/wasm-multi-memory.csv | 2 +- crates/types/src/instructions.rs | 1 - 17 files changed, 317 insertions(+), 294 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48bfcf9..acdc41b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,18 +114,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstyle", "clap_lex", @@ -258,9 +258,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -311,9 +311,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -664,9 +664,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.228.0" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" +checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2" dependencies = [ "leb128fmt", "wasmparser", @@ -674,9 +674,9 @@ dependencies = [ [[package]] name = "wasm-testsuite" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec81df5b65371f919b41f3682861d98f1c90d081cfd8cb68784eb5d942dc1e36" +checksum = "735333508bfc70a3cc7a7ed86b3cd53e4a775cbf78511eaec8ac4926ed3a0bf7" dependencies = [ "include_dir", "wast", @@ -684,9 +684,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.228.0" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" +checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c" dependencies = [ "bitflags", "indexmap", @@ -695,9 +695,9 @@ dependencies = [ [[package]] name = "wast" -version = "228.0.0" +version = "229.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5aae124478cb51439f6587f074a3a5e835afd22751c59a87b2e2a882727c97" +checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9" dependencies = [ "bumpalo", "leb128fmt", @@ -708,9 +708,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.228.0" +version = "1.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec29c89a8d055df988de7236483bf569988ac3d6905899f6af5ef920f9385ad" +checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0" dependencies = [ "wast", ] diff --git a/Cargo.toml b/Cargo.toml index 56e0be1..1f645cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,9 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"] resolver="2" [workspace.dependencies] -wast="228" -wat="1.228" -wasmparser={version="0.228", default-features=false} +wast="229" +wat="1.229" +wasmparser={version="0.229", default-features=false} eyre="0.6" log="0.4" pretty_env_logger="0.5" diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 1292fa6..aa33995 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -82,6 +82,7 @@ impl Parser { cm_async_stackful: false, cm_nested_names: false, cm_values: false, + cm_error_context: false, }; Validator::new_with_features(features.into()) } diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index ff6b22b..0e17ad9 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -130,7 +130,7 @@ impl ModuleReader { return Err(ParseError::DuplicateSection("Code section".into())); } self.code.reserve(count as usize); - validator.code_section_start(count, &range)?; + validator.code_section_start(&range)?; } CodeSectionEntry(function) => { debug!("Found code section entry"); diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 3e6fa4b..10005c0 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -46,7 +46,7 @@ pub(crate) fn process_operators_and_validate( reader.visit_operator(&mut ValidateThenVisit(reader.original_position(), &mut builder))??; } - builder.validator_finish(reader.original_position())?; + reader.finish()?; if !builder.errors.is_empty() { return Err(builder.errors.remove(0)); } @@ -124,10 +124,6 @@ impl FunctionBuilder { ) -> impl VisitOperator<'_, Output = Result<(), wasmparser::BinaryReaderError>> + VisitSimdOperator<'_> { self.validator.simd_visitor(offset) } - - pub(crate) fn validator_finish(&mut self, offset: usize) -> Result<(), wasmparser::BinaryReaderError> { - self.validator.finish(offset) - } } impl FunctionBuilder { diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 5810f0e..3281476 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false libm={version="0.2", default-features=false} [dev-dependencies] -wasm-testsuite={version="0.5.2"} +wasm-testsuite={version="0.5.3"} indexmap="2.7" wast={workspace=true} wat={workspace=true} @@ -32,12 +32,14 @@ serde_json={version="1.0"} serde={version="1.0", features=["derive"]} [features] -default=["std", "parser", "logging", "archive", "simd"] +default=["std", "parser", "logging", "archive"] logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] parser=["dep:tinywasm-parser"] archive=["tinywasm-types/archive"] -simd=[] + +# enable simd support (unstable / unfinished) +__simd=[] [[test]] name="test-wasm-1" diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index a0153af..4bf4f5d 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -3,16 +3,19 @@ use super::no_std_floats::NoStdFloatExt; use alloc::{format, rc::Rc, string::ToString}; -use core::ops::{ControlFlow, Index, IndexMut, Shl, Shr}; +use core::ops::ControlFlow; use interpreter::stack::CallFrame; use tinywasm_types::*; -#[cfg(all(feature = "std", feature = "simd"))] +#[cfg(all(feature = "std", feature = "__simd"))] use crate::std::simd::StdFloat; -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] use core::simd::{cmp::*, num::*, *}; +#[cfg(feature = "__simd")] +use core::ops::{Index, IndexMut, Shl, Shr}; + use super::num_helpers::*; use super::stack::{BlockFrame, BlockType, Stack}; use super::values::*; @@ -313,234 +316,235 @@ impl<'store, 'stack> Executor<'store, 'stack> { LocalCopy128(from, to) => self.exec_local_copy::(*from, *to), LocalCopyRef(from, to) => self.exec_local_copy::(*from, *to), - V128Not => self.stack.values.replace_top_same::(|v| Ok(!v)).to_cf()?, - V128And => self.stack.values.calculate_same::(|a, b| Ok(a & b)).to_cf()?, - V128AndNot => self.stack.values.calculate_same::(|a, b| Ok(a & (!b))).to_cf()?, - V128Or => self.stack.values.calculate_same::(|a, b| Ok(a | b)).to_cf()?, - V128Xor => self.stack.values.calculate_same::(|a, b| Ok(a ^ b)).to_cf()?, - V128Bitselect => self.stack.values.calculate_same_3::(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?, - V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_or() != 0) as i32)).to_cf()?, - I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, - V128Load(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| v)?, - V128Store(arg) => self.exec_mem_store::(arg.mem_addr(), arg.offset(), |v| v)?, - - V128Store8Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, - V128Store16Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, - V128Store32Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, - V128Store64Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Not => self.stack.values.replace_top_same::(|v| Ok(!v)).to_cf()?, + #[cfg(feature = "__simd")] V128And => self.stack.values.calculate_same::(|a, b| Ok(a & b)).to_cf()?, + #[cfg(feature = "__simd")] V128AndNot => self.stack.values.calculate_same::(|a, b| Ok(a & (!b))).to_cf()?, + #[cfg(feature = "__simd")] V128Or => self.stack.values.calculate_same::(|a, b| Ok(a | b)).to_cf()?, + #[cfg(feature = "__simd")] V128Xor => self.stack.values.calculate_same::(|a, b| Ok(a ^ b)).to_cf()?, + #[cfg(feature = "__simd")] V128Bitselect => self.stack.values.calculate_same_3::(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?, + #[cfg(feature = "__simd")] V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_or() != 0) as i32)).to_cf()?, + #[cfg(feature = "__simd")] I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, + #[cfg(feature = "__simd")] V128Load(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| v)?, + #[cfg(feature = "__simd")] V128Store(arg) => self.exec_mem_store::(arg.mem_addr(), arg.offset(), |v| v)?, + + #[cfg(feature = "__simd")] V128Store8Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Store16Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Store32Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Store64Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, // Load a single 32-bit or 64-bit element into the lowest bits of a v128 vector, and initialize all other bits of the v128 vector to zero. - V128Load32Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| { + #[cfg(feature = "__simd")] V128Load32Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| { let bytes = v.to_le_bytes(); u8x16::from_array([bytes[0], bytes[1], bytes[2], bytes[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) })?, - V128Load64Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| { + #[cfg(feature = "__simd")] V128Load64Zero(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| { let bytes = v.to_le_bytes(); u8x16::from_array([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], 0, 0, 0, 0, 0, 0, 0, 0]) })?, - V128Const(arg) => self.exec_const::( self.cf.data().v128_constants[*arg as usize].to_le_bytes().into()), - - I8x16ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - I8x16ExtractLaneU(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - I16x8ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - I16x8ExtractLaneU(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - I32x4ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, - I64x2ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, - F32x4ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, - F64x2ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, - - V128Load8Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, - V128Load16Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, - V128Load32Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, - V128Load64Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, - - I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8))).to_cf()?, - I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16))).to_cf()?, - I32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, - I64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, - F32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, - F64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, - - I8x16Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, - I16x8Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, - I32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, - F32x4Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, - F64x2Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, - - I8x16Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, - I16x8Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, - I32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, - F32x4Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, - F64x2Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, - - I8x16LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - I16x8LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - I32x4LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - I64x2LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - I8x16LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - I16x8LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - I32x4LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - F32x4Lt => self.stack.values.calculate::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - F64x2Lt => self.stack.values.calculate::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, - - I64x2GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - F32x4Gt => self.stack.values.calculate::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - F64x2Gt => self.stack.values.calculate::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - - I8x16GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - I16x8GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - I32x4GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - I64x2LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - F32x4Le => self.stack.values.calculate::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - F64x2Le => self.stack.values.calculate::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - - I8x16GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - I16x8GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - I32x4GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, - I64x2GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - F32x4Ge => self.stack.values.calculate::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - F64x2Ge => self.stack.values.calculate::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - - I8x16LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - I16x8LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - I32x4LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - - I8x16LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - I16x8LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - I32x4LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, - - I8x16GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - I16x8GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - I32x4GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - - I8x16GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - I16x8GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - I32x4GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, - - I8x16Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, - I16x8Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, - I32x4Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, - I64x2Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, - - I8x16Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, - I16x8Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, - I32x4Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, - I64x2Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, - - I8x16AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, - I16x8AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, - I32x4AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, - I64x2AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, - - I8x16Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, - I16x8Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, - I32x4Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, - I64x2Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, - - I8x16Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i8))).to_cf()?, - I16x8Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i16))).to_cf()?, - I32x4Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a))).to_cf()?, - I64x2Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i64))).to_cf()?, - - I8x16ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i8))).to_cf()?, - I16x8ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i16))).to_cf()?, - I32x4ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a))).to_cf()?, - I64x2ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i64))).to_cf()?, - - I8x16ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u8))).to_cf()?, - I16x8ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u16))).to_cf()?, - I32x4ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u32))).to_cf()?, - I64x2ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u64))).to_cf()?, - - I8x16Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, - I16x8Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, - I32x4Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, - I64x2Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, - - I8x16Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, - I16x8Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, - I32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, - I64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, - - I8x16MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - I16x8MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - I32x4MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - - I8x16MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - I16x8MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - I32x4MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, - - I8x16MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - I16x8MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - I32x4MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - - I8x16MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - I16x8MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - I32x4MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, - - I64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, - I16x8Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, - I32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, - - I8x16NarrowI16x8S => unimplemented!(), - I8x16NarrowI16x8U => unimplemented!(), - I16x8NarrowI32x4S => unimplemented!(), - I16x8NarrowI32x4U => unimplemented!(), - - I8x16AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, - I16x8AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, - I8x16AddSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, - I16x8AddSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, - I8x16SubSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, - I16x8SubSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, - I8x16SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, - I16x8SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, - - I16x8ExtAddPairwiseI8x16S => unimplemented!(), - I16x8ExtAddPairwiseI8x16U => unimplemented!(), - I32x4ExtAddPairwiseI16x8S => unimplemented!(), - I32x4ExtAddPairwiseI16x8U => unimplemented!(), - - I16x8ExtMulLowI8x16S => unimplemented!(), - I16x8ExtMulLowI8x16U => unimplemented!(), - I16x8ExtMulHighI8x16S => unimplemented!(), - I16x8ExtMulHighI8x16U => unimplemented!(), - I32x4ExtMulLowI16x8S => unimplemented!(), - I32x4ExtMulLowI16x8U => unimplemented!(), - I32x4ExtMulHighI16x8S => unimplemented!(), - I32x4ExtMulHighI16x8U => unimplemented!(), - I64x2ExtMulLowI32x4S => unimplemented!(), - I64x2ExtMulLowI32x4U => unimplemented!(), - I64x2ExtMulHighI32x4S => unimplemented!(), - I64x2ExtMulHighI32x4U => unimplemented!(), - - I16x8ExtendLowI8x16S => unimplemented!(), - I16x8ExtendLowI8x16U => unimplemented!(), - I16x8ExtendHighI8x16S => unimplemented!(), - I16x8ExtendHighI8x16U => unimplemented!(), - I32x4ExtendLowI16x8S => unimplemented!(), - I32x4ExtendLowI16x8U => unimplemented!(), - I32x4ExtendHighI16x8S => unimplemented!(), - I32x4ExtendHighI16x8U => unimplemented!(), - I64x2ExtendLowI32x4S => unimplemented!(), - I64x2ExtendLowI32x4U => unimplemented!(), - I64x2ExtendHighI32x4S => unimplemented!(), - I64x2ExtendHighI32x4U => unimplemented!(), - - I8x16Popcnt => self.stack.values.replace_top::(|v| Ok(v.count_ones())).to_cf()?, - + #[cfg(feature = "__simd")] V128Const(arg) => self.exec_const::( self.cf.data().v128_constants[*arg as usize].to_le_bytes().into()), + + #[cfg(feature = "__simd")] I8x16ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + #[cfg(feature = "__simd")] I8x16ExtractLaneU(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + #[cfg(feature = "__simd")] I16x8ExtractLaneS(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + #[cfg(feature = "__simd")] I16x8ExtractLaneU(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize] as i32)).to_cf()?, + #[cfg(feature = "__simd")] I32x4ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + #[cfg(feature = "__simd")] I64x2ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + #[cfg(feature = "__simd")] F32x4ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + #[cfg(feature = "__simd")] F64x2ExtractLane(lane) => self.stack.values.replace_top::(|v| Ok(v[*lane as usize])).to_cf()?, + + #[cfg(feature = "__simd")] V128Load8Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Load16Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Load32Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] V128Load64Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + + #[cfg(feature = "__simd")] I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8))).to_cf()?, + #[cfg(feature = "__simd")] I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16))).to_cf()?, + #[cfg(feature = "__simd")] I32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + #[cfg(feature = "__simd")] I64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + #[cfg(feature = "__simd")] F64x2Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I64x2LtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I8x16LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4LtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Lt => self.stack.values.calculate::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Lt => self.stack.values.calculate::(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I64x2GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Gt => self.stack.values.calculate::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Gt => self.stack.values.calculate::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4GtS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I64x2LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Le => self.stack.values.calculate::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Le => self.stack.values.calculate::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4GtU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I64x2GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Ge => self.stack.values.calculate::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Ge => self.stack.values.calculate::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4LeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4LeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4GeS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I16x8GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I32x4GeU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + #[cfg(feature = "__simd")] I16x8Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + #[cfg(feature = "__simd")] I32x4Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + #[cfg(feature = "__simd")] I64x2Abs => self.stack.values.replace_top_same::(|a| Ok(a.abs())).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + #[cfg(feature = "__simd")] I16x8Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + #[cfg(feature = "__simd")] I32x4Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + #[cfg(feature = "__simd")] I64x2Neg => self.stack.values.replace_top_same::(|a| Ok(-a)).to_cf()?, + + #[cfg(feature = "__simd")] I8x16AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + #[cfg(feature = "__simd")] I16x8AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + #[cfg(feature = "__simd")] I32x4AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + #[cfg(feature = "__simd")] I64x2AllTrue => self.stack.values.replace_top::(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + #[cfg(feature = "__simd")] I16x8Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + #[cfg(feature = "__simd")] I32x4Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + #[cfg(feature = "__simd")] I64x2Bitmask => self.stack.values.replace_top::(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i8))).to_cf()?, + #[cfg(feature = "__simd")] I16x8Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i16))).to_cf()?, + #[cfg(feature = "__simd")] I32x4Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a))).to_cf()?, + #[cfg(feature = "__simd")] I64x2Shl => self.stack.values.calculate_diff::(|a, b| Ok(b.shl(a as i64))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i8))).to_cf()?, + #[cfg(feature = "__simd")] I16x8ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i16))).to_cf()?, + #[cfg(feature = "__simd")] I32x4ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a))).to_cf()?, + #[cfg(feature = "__simd")] I64x2ShrS => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as i64))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u8))).to_cf()?, + #[cfg(feature = "__simd")] I16x8ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u16))).to_cf()?, + #[cfg(feature = "__simd")] I32x4ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u32))).to_cf()?, + #[cfg(feature = "__simd")] I64x2ShrU => self.stack.values.calculate_diff::(|a, b| Ok(b.shr(a as u64))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + #[cfg(feature = "__simd")] I16x8Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + #[cfg(feature = "__simd")] I32x4Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + #[cfg(feature = "__simd")] I64x2Add => self.stack.values.calculate_same::(|a, b| Ok(a + b)).to_cf()?, + + #[cfg(feature = "__simd")] I8x16Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + #[cfg(feature = "__simd")] I16x8Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + #[cfg(feature = "__simd")] I32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + #[cfg(feature = "__simd")] I64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(a - b)).to_cf()?, + + #[cfg(feature = "__simd")] I8x16MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + #[cfg(feature = "__simd")] I32x4MinS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + #[cfg(feature = "__simd")] I32x4MinU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_min(b))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + #[cfg(feature = "__simd")] I32x4MaxS => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + + #[cfg(feature = "__simd")] I8x16MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + #[cfg(feature = "__simd")] I32x4MaxU => self.stack.values.calculate_same::(|a, b| Ok(a.simd_max(b))).to_cf()?, + + #[cfg(feature = "__simd")] I64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + #[cfg(feature = "__simd")] I16x8Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + #[cfg(feature = "__simd")] I32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(a * b)).to_cf()?, + + #[cfg(feature = "__simd")] I8x16NarrowI16x8S => unimplemented!(), + #[cfg(feature = "__simd")] I8x16NarrowI16x8U => unimplemented!(), + #[cfg(feature = "__simd")] I16x8NarrowI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] I16x8NarrowI32x4U => unimplemented!(), + + #[cfg(feature = "__simd")] I8x16AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8AddSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + #[cfg(feature = "__simd")] I8x16AddSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8AddSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_add(b))).to_cf()?, + #[cfg(feature = "__simd")] I8x16SubSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8SubSatS => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + #[cfg(feature = "__simd")] I8x16SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + #[cfg(feature = "__simd")] I16x8SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + + #[cfg(feature = "__simd")] I16x8ExtAddPairwiseI8x16S => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtAddPairwiseI8x16U => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtAddPairwiseI16x8S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtAddPairwiseI16x8U => unimplemented!(), + + #[cfg(feature = "__simd")] I16x8ExtMulLowI8x16S => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtMulLowI8x16U => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtMulHighI8x16S => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtMulHighI8x16U => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtMulLowI16x8S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtMulLowI16x8U => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtMulHighI16x8S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtMulHighI16x8U => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtMulLowI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtMulLowI32x4U => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtMulHighI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtMulHighI32x4U => unimplemented!(), + + #[cfg(feature = "__simd")] I16x8ExtendLowI8x16S => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtendLowI8x16U => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtendHighI8x16S => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtendHighI8x16U => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtendLowI16x8S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtendLowI16x8U => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtendHighI16x8S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ExtendHighI16x8U => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtendLowI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtendLowI32x4U => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtendHighI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ExtendHighI32x4U => unimplemented!(), + + #[cfg(feature = "__simd")] I8x16Popcnt => self.stack.values.replace_top::(|v| Ok(v.count_ones())).to_cf()?, + + #[cfg(feature = "__simd")] I16x8Q15MulrSatS => self.stack.values.calculate_same::(|a, b| { let subq15mulr = |a,b| { let a = a as i32; let b = b as i32; let r = (a * b + 0x4000) >> 15; if r > i16::MAX as i32 { - i16::MAX + i16::MAX } else if r < i16::MIN as i32 { - i16::MIN + i16::MIN } else { - r as i16 + r as i16 } }; Ok(Simd::::from_array([ @@ -555,6 +559,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { ])) }).to_cf()?, + #[cfg(feature = "__simd")] I32x4DotI16x8S => self.stack.values.calculate::(|a, b| { Ok(Simd::::from_array([ i32::from(a[0] * b[0] + a[1] * b[1]), @@ -564,26 +569,27 @@ impl<'store, 'stack> Executor<'store, 'stack> { ])) }).to_cf()?, - F32x4Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, - F64x2Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, - F32x4Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, - F64x2Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, - F32x4Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, - F64x2Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, - F32x4Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, - F64x2Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, - F32x4Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, - F64x2Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, - F32x4Sqrt => self.stack.values.replace_top_same::(|v| Ok(canonicalize_f32x4(v.sqrt()))).to_cf()?, - F64x2Sqrt => self.stack.values.replace_top_same::(|v| Ok(canonicalize_f64x2(v.sqrt()))).to_cf()?, - F32x4Add => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a + b))).to_cf()?, - F64x2Add => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a + b))).to_cf()?, - F32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a - b))).to_cf()?, - F64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a - b))).to_cf()?, - F32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a * b))).to_cf()?, - F64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a * b))).to_cf()?, - F32x4Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a / b))).to_cf()?, - F64x2Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a / b))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Ceil => self.stack.values.replace_top_same::(|v| Ok(v.ceil())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, + #[cfg(feature = "__simd")] F64x2Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, + #[cfg(feature = "__simd")] F32x4Sqrt => self.stack.values.replace_top_same::(|v| Ok(canonicalize_f32x4(v.sqrt()))).to_cf()?, + #[cfg(feature = "__simd")] F64x2Sqrt => self.stack.values.replace_top_same::(|v| Ok(canonicalize_f64x2(v.sqrt()))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Add => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a + b))).to_cf()?, + #[cfg(feature = "__simd")] F64x2Add => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a + b))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Sub => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a - b))).to_cf()?, + #[cfg(feature = "__simd")] F64x2Sub => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a - b))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a * b))).to_cf()?, + #[cfg(feature = "__simd")] F64x2Mul => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a * b))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f32x4(a / b))).to_cf()?, + #[cfg(feature = "__simd")] F64x2Div => self.stack.values.calculate_same::(|a, b| Ok(canonicalize_f64x2(a / b))).to_cf()?, + #[cfg(feature = "__simd")] F32x4Min => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ b[0].tw_minimum(a[0]), @@ -592,12 +598,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { b[3].tw_minimum(a[3]), ])) }).to_cf()?, + + #[cfg(feature = "__simd")] F64x2Min => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ b[0].tw_minimum(a[0]), b[1].tw_minimum(a[1]), ])) }).to_cf()?, + + #[cfg(feature = "__simd")] F32x4Max => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ b[0].tw_maximum(a[0]), @@ -606,6 +616,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { b[3].tw_maximum(a[3]), ])) }).to_cf()?, + + #[cfg(feature = "__simd")] F64x2Max => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ b[0].tw_maximum(a[0]), @@ -613,6 +625,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { ])) }).to_cf()?, + #[cfg(feature = "__simd")] F32x4PMin => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ if b[0] < a[0] { b[0] } else { a[0]}, @@ -621,6 +634,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { if b[3] < a[3] { b[3] } else { a[3]}, ])) }).to_cf()?, + + #[cfg(feature = "__simd")] F32x4PMax => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ if b[0] > a[0] { b[0] } else { a[0]}, @@ -629,12 +644,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { if b[3] > a[3] { b[3] } else { a[3]}, ])) }).to_cf()?, + + #[cfg(feature = "__simd")] F64x2PMin => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ if b[0] < a[0] { b[0] } else { a[0]}, if b[1] < a[1] { b[1] } else { a[1]}, ])) }).to_cf()?, + + #[cfg(feature = "__simd")] F64x2PMax => self.stack.values.calculate_same::(|a, b| { Ok(Simd::::from_array([ if b[0] > a[0] { b[0] } else { a[0]}, @@ -643,16 +662,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { }).to_cf()?, // not correct - I32x4TruncSatF32x4S => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, - I32x4TruncSatF32x4U => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, - F32x4ConvertI32x4S => {}, - F32x4ConvertI32x4U => {}, - F64x2ConvertLowI32x4S => {}, - F64x2ConvertLowI32x4U => {}, - F32x4DemoteF64x2Zero => {}, - F64x2PromoteLowF32x4 => {}, - I32x4TruncSatF64x2SZero => unimplemented!(), - I32x4TruncSatF64x2UZero => unimplemented!(), + #[cfg(feature = "__simd")] I32x4TruncSatF32x4S => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, + #[cfg(feature = "__simd")] I32x4TruncSatF32x4U => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, + #[cfg(feature = "__simd")] F32x4ConvertI32x4S => {}, + #[cfg(feature = "__simd")] F32x4ConvertI32x4U => {}, + #[cfg(feature = "__simd")] F64x2ConvertLowI32x4S => {}, + #[cfg(feature = "__simd")] F64x2ConvertLowI32x4U => {}, + #[cfg(feature = "__simd")] F32x4DemoteF64x2Zero => {}, + #[cfg(feature = "__simd")] F64x2PromoteLowF32x4 => {}, + #[cfg(feature = "__simd")] I32x4TruncSatF64x2SZero => unimplemented!(), + #[cfg(feature = "__simd")] I32x4TruncSatF64x2UZero => unimplemented!(), i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; @@ -978,6 +997,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { } } + #[cfg(feature = "__simd")] fn exec_mem_load_lane< LOAD: MemLoadable, INTO: InternalValue + IndexMut, @@ -1018,7 +1038,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { false => self.stack.values.pop::() as u32 as u64, }; - let Some(Ok(addr)) = offset.checked_add(addr).map(TryInto::try_into) else { + let Some(Ok(addr)) = offset.checked_add(addr).map(|a| a.try_into()) else { cold(); return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds { offset: addr as usize, @@ -1031,6 +1051,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { ControlFlow::Continue(()) } + #[cfg(feature = "__simd")] fn exec_mem_store_lane, U: MemStorable + Copy, const N: usize>( &mut self, mem_addr: tinywasm_types::MemAddr, diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index bba35cb..678c32e 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -184,7 +184,7 @@ macro_rules! impl_checked_wrapping_rem { impl_checked_wrapping_rem! { i32 i64 u32 u64 } -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] /// replace all NaNs in a f32x4 with f32::NAN pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { use core::simd::{Simd, num::SimdFloat}; @@ -193,7 +193,7 @@ pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { mask.select(nan, x) } -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] /// replace all NaNs in a f64x2 with f64::NAN pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 { use core::simd::{Simd, num::SimdFloat}; diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index e94e401..c7f02b6 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -71,6 +71,7 @@ impl CallFrame { } #[inline] + #[allow(dead_code)] pub(crate) fn data(&self) -> &WasmFunctionData { &self.func_instance.data } diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index 01cea1c..481a88c 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -72,6 +72,7 @@ impl ValueStack { } #[inline] + #[allow(dead_code)] pub(crate) fn calculate_same_3(&mut self, func: impl FnOnce(T, T, T) -> Result) -> Result<()> { T::stack_calculate3(self, func) } @@ -88,6 +89,7 @@ impl ValueStack { } #[inline] + #[allow(dead_code)] pub(crate) fn calculate_diff( &mut self, func: impl FnOnce(A, B) -> Result, @@ -191,10 +193,10 @@ impl ValueStack { ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.pop())), ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.pop())), - #[cfg(not(feature = "simd"))] + #[cfg(not(feature = "__simd"))] ValType::V128 => WasmValue::V128(self.pop()), - #[cfg(feature = "simd")] + #[cfg(feature = "__simd")] ValType::V128 => WasmValue::V128(i128::from_le_bytes(self.pop::().to_array())), } } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 335da59..779fc60 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -7,9 +7,9 @@ pub(crate) type Value32 = u32; pub(crate) type Value64 = u64; pub(crate) type ValueRef = Option; -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] pub(crate) type Value128 = core::simd::u8x16; -#[cfg(not(feature = "simd"))] +#[cfg(not(feature = "__simd"))] pub(crate) type Value128 = i128; #[derive(Debug, Clone, Copy, PartialEq)] @@ -113,10 +113,10 @@ impl TinyWasmValue { ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.unwrap_ref())), ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.unwrap_ref())), - #[cfg(feature = "simd")] + #[cfg(feature = "__simd")] ValType::V128 => WasmValue::V128(i128::from_le_bytes(self.unwrap_128().to_array())), - #[cfg(not(feature = "simd"))] + #[cfg(not(feature = "__simd"))] ValType::V128 => WasmValue::V128(self.unwrap_128()), } } @@ -132,10 +132,10 @@ impl From<&WasmValue> for TinyWasmValue { WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(v.addr()), WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(v.addr()), - #[cfg(not(feature = "simd"))] + #[cfg(not(feature = "__simd"))] WasmValue::V128(v) => TinyWasmValue::Value128(*v), - #[cfg(feature = "simd")] + #[cfg(feature = "__simd")] WasmValue::V128(v) => TinyWasmValue::Value128(v.to_le_bytes().into()), } } @@ -160,6 +160,7 @@ pub(crate) trait InternalValue: sealed::Sealed + Into { fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result) -> Result<()> where Self: Sized; + #[allow(dead_code)] fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result) -> Result<()> where Self: Sized; @@ -273,10 +274,10 @@ impl_internalvalue! { Value128, stack_128, locals_128, Value128, Value128, |v| v, |v| v } -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] use core::simd::{num::SimdUint, *}; -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] impl_internalvalue! { Value128, stack_128, locals_128, u8x16, i128, |v: i128| v.to_le_bytes().into(), |v: u8x16| i128::from_le_bytes(v.into()) Value128, stack_128, locals_128, u8x16, u128, |v: u128| v.to_le_bytes().into(), |v: u8x16| u128::from_le_bytes(v.into()) diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 72c38cd..9cb6c0a 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -5,7 +5,7 @@ ))] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)] #![forbid(unsafe_code)] -#![cfg_attr(feature = "simd", feature(portable_simd))] +#![cfg_attr(feature = "__simd", feature(portable_simd))] //! A tiny WebAssembly Runtime written in Rust //! diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index df3d49e..7abd7b9 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -4,7 +4,7 @@ use tinywasm_types::{MemoryArch, MemoryType, ModuleInstanceAddr}; use crate::{Error, Result, cold, interpreter::Value128, log}; -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] use core::simd::ToBytes; /// A WebAssembly Memory Instance @@ -189,7 +189,7 @@ macro_rules! impl_mem_traits { impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, Value128, 16); -#[cfg(feature = "simd")] +#[cfg(feature = "__simd")] impl_mem_traits!( core::simd::i8x16, 16, diff --git a/crates/tinywasm/tests/generated/wasm-1.csv b/crates/tinywasm/tests/generated/wasm-1.csv index d403e3b..ebb511b 100644 --- a/crates/tinywasm/tests/generated/wasm-1.csv +++ b/crates/tinywasm/tests/generated/wasm-1.csv @@ -5,4 +5,4 @@ 0.6.1,27572,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.7.0,27572,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.8.0,20360,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":128,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":178,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":88,"failed":0},{"name":"memory_grow.wast","passed":104,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.9.0-alpha.0,19243,0,[{"name":"address.wast","passed":243,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":79,"failed":0},{"name":"binary.wast","passed":67,"failed":0},{"name":"block.wast","passed":171,"failed":0},{"name":"br.wast","passed":84,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":168,"failed":0},{"name":"break-drop.wast","passed":4,"failed":0},{"name":"call.wast","passed":82,"failed":0},{"name":"call_indirect.wast","passed":152,"failed":0},{"name":"comments.wast","passed":4,"failed":0},{"name":"const.wast","passed":668,"failed":0},{"name":"conversions.wast","passed":435,"failed":0},{"name":"custom.wast","passed":10,"failed":0},{"name":"data.wast","passed":45,"failed":0},{"name":"elem.wast","passed":55,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":82,"failed":0},{"name":"f32.wast","passed":2512,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2512,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":7,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":161,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":121,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"globals.wast","passed":78,"failed":0},{"name":"i32.wast","passed":443,"failed":0},{"name":"i64.wast","passed":389,"failed":0},{"name":"if.wast","passed":151,"failed":0},{"name":"imports.wast","passed":146,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":116,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":81,"failed":0},{"name":"memory.wast","passed":71,"failed":0},{"name":"memory_grow.wast","passed":94,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":173,"failed":0},{"name":"names.wast","passed":483,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":111,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":5,"failed":0},{"name":"start.wast","passed":19,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"token.wast","passed":2,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":62,"failed":0},{"name":"unreached-invalid.wast","passed":110,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,19241,0,[{"name":"address.wast","passed":243,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":77,"failed":0},{"name":"binary.wast","passed":67,"failed":0},{"name":"block.wast","passed":171,"failed":0},{"name":"br.wast","passed":84,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":168,"failed":0},{"name":"break-drop.wast","passed":4,"failed":0},{"name":"call.wast","passed":82,"failed":0},{"name":"call_indirect.wast","passed":152,"failed":0},{"name":"comments.wast","passed":4,"failed":0},{"name":"const.wast","passed":668,"failed":0},{"name":"conversions.wast","passed":435,"failed":0},{"name":"custom.wast","passed":10,"failed":0},{"name":"data.wast","passed":45,"failed":0},{"name":"elem.wast","passed":55,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":82,"failed":0},{"name":"f32.wast","passed":2512,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2512,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":7,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":161,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":121,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"globals.wast","passed":78,"failed":0},{"name":"i32.wast","passed":443,"failed":0},{"name":"i64.wast","passed":389,"failed":0},{"name":"if.wast","passed":151,"failed":0},{"name":"imports.wast","passed":146,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":116,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":81,"failed":0},{"name":"memory.wast","passed":71,"failed":0},{"name":"memory_grow.wast","passed":94,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":173,"failed":0},{"name":"names.wast","passed":483,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":111,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":5,"failed":0},{"name":"start.wast","passed":19,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"token.wast","passed":2,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":62,"failed":0},{"name":"unreached-invalid.wast","passed":110,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-2.csv b/crates/tinywasm/tests/generated/wasm-2.csv index b0949ec..8e228b4 100644 --- a/crates/tinywasm/tests/generated/wasm-2.csv +++ b/crates/tinywasm/tests/generated/wasm-2.csv @@ -10,4 +10,4 @@ 0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.7.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.8.0,28008,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":128,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":178,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":88,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":104,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1728,"failed":0},{"name":"table_fill.wast","passed":45,"failed":0},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":58,"failed":0},{"name":"table_init.wast","passed":780,"failed":0},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.9.0-alpha.0,27826,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":81,"failed":0},{"name":"binary.wast","passed":162,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":169,"failed":0},{"name":"comments.wast","passed":4,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":58,"failed":0},{"name":"elem.wast","passed":74,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":161,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":108,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":239,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":147,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1728,"failed":0},{"name":"table_fill.wast","passed":45,"failed":0},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":50,"failed":0},{"name":"table_init.wast","passed":780,"failed":0},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":2,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":6,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,27822,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":79,"failed":0},{"name":"binary.wast","passed":160,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":117,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":169,"failed":0},{"name":"comments.wast","passed":4,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":58,"failed":0},{"name":"elem.wast","passed":74,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":161,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":108,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":239,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":16,"failed":0},{"name":"ref_null.wast","passed":3,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":147,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1728,"failed":0},{"name":"table_fill.wast","passed":45,"failed":0},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":50,"failed":0},{"name":"table_init.wast","passed":780,"failed":0},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":2,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":6,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-multi-memory.csv b/crates/tinywasm/tests/generated/wasm-multi-memory.csv index ae9ba03..33debd6 100644 --- a/crates/tinywasm/tests/generated/wasm-multi-memory.csv +++ b/crates/tinywasm/tests/generated/wasm-multi-memory.csv @@ -1,2 +1,2 @@ 0.8.0,1872,0,[{"name":"address0.wast","passed":92,"failed":0},{"name":"address1.wast","passed":127,"failed":0},{"name":"align.wast","passed":160,"failed":0},{"name":"align0.wast","passed":5,"failed":0},{"name":"binary.wast","passed":126,"failed":0},{"name":"binary0.wast","passed":7,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"data0.wast","passed":7,"failed":0},{"name":"data1.wast","passed":14,"failed":0},{"name":"data_drop0.wast","passed":11,"failed":0},{"name":"exports0.wast","passed":8,"failed":0},{"name":"float_exprs0.wast","passed":14,"failed":0},{"name":"float_exprs1.wast","passed":3,"failed":0},{"name":"float_memory0.wast","passed":30,"failed":0},{"name":"imports.wast","passed":175,"failed":0},{"name":"imports0.wast","passed":8,"failed":0},{"name":"imports1.wast","passed":5,"failed":0},{"name":"imports2.wast","passed":20,"failed":0},{"name":"imports3.wast","passed":10,"failed":0},{"name":"imports4.wast","passed":16,"failed":0},{"name":"linking0.wast","passed":6,"failed":0},{"name":"linking1.wast","passed":14,"failed":0},{"name":"linking2.wast","passed":11,"failed":0},{"name":"linking3.wast","passed":14,"failed":0},{"name":"load.wast","passed":118,"failed":0},{"name":"load0.wast","passed":3,"failed":0},{"name":"load1.wast","passed":18,"failed":0},{"name":"load2.wast","passed":38,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":86,"failed":0},{"name":"memory_copy0.wast","passed":29,"failed":0},{"name":"memory_copy1.wast","passed":14,"failed":0},{"name":"memory_fill0.wast","passed":16,"failed":0},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_init0.wast","passed":13,"failed":0},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_size0.wast","passed":8,"failed":0},{"name":"memory_size1.wast","passed":15,"failed":0},{"name":"memory_size2.wast","passed":21,"failed":0},{"name":"memory_size3.wast","passed":2,"failed":0},{"name":"memory_trap0.wast","passed":14,"failed":0},{"name":"memory_trap1.wast","passed":168,"failed":0},{"name":"multi-memory/simd_memory-multi.wast (skipped)","passed":0,"failed":0},{"name":"start0.wast","passed":9,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"store0.wast","passed":5,"failed":0},{"name":"store1.wast","passed":13,"failed":0},{"name":"traps0.wast","passed":15,"failed":0}] -0.9.0-alpha.0,1872,0,[{"name":"address0.wast","passed":92,"failed":0},{"name":"address1.wast","passed":127,"failed":0},{"name":"align.wast","passed":160,"failed":0},{"name":"align0.wast","passed":5,"failed":0},{"name":"binary.wast","passed":126,"failed":0},{"name":"binary0.wast","passed":7,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"data0.wast","passed":7,"failed":0},{"name":"data1.wast","passed":14,"failed":0},{"name":"data_drop0.wast","passed":11,"failed":0},{"name":"exports0.wast","passed":8,"failed":0},{"name":"float_exprs0.wast","passed":14,"failed":0},{"name":"float_exprs1.wast","passed":3,"failed":0},{"name":"float_memory0.wast","passed":30,"failed":0},{"name":"imports.wast","passed":175,"failed":0},{"name":"imports0.wast","passed":8,"failed":0},{"name":"imports1.wast","passed":5,"failed":0},{"name":"imports2.wast","passed":20,"failed":0},{"name":"imports3.wast","passed":10,"failed":0},{"name":"imports4.wast","passed":16,"failed":0},{"name":"linking0.wast","passed":6,"failed":0},{"name":"linking1.wast","passed":14,"failed":0},{"name":"linking2.wast","passed":11,"failed":0},{"name":"linking3.wast","passed":14,"failed":0},{"name":"load.wast","passed":118,"failed":0},{"name":"load0.wast","passed":3,"failed":0},{"name":"load1.wast","passed":18,"failed":0},{"name":"load2.wast","passed":38,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":86,"failed":0},{"name":"memory_copy0.wast","passed":29,"failed":0},{"name":"memory_copy1.wast","passed":14,"failed":0},{"name":"memory_fill0.wast","passed":16,"failed":0},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_init0.wast","passed":13,"failed":0},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_size0.wast","passed":8,"failed":0},{"name":"memory_size1.wast","passed":15,"failed":0},{"name":"memory_size2.wast","passed":21,"failed":0},{"name":"memory_size3.wast","passed":2,"failed":0},{"name":"memory_trap0.wast","passed":14,"failed":0},{"name":"memory_trap1.wast","passed":168,"failed":0},{"name":"simd_memory-multi.wast (skipped)","passed":0,"failed":0},{"name":"start0.wast","passed":9,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"store0.wast","passed":5,"failed":0},{"name":"store1.wast","passed":13,"failed":0},{"name":"traps0.wast","passed":15,"failed":0}] +0.9.0-alpha.0,1871,0,[{"name":"address0.wast","passed":92,"failed":0},{"name":"address1.wast","passed":127,"failed":0},{"name":"align.wast","passed":160,"failed":0},{"name":"align0.wast","passed":5,"failed":0},{"name":"binary.wast","passed":126,"failed":0},{"name":"binary0.wast","passed":6,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"data0.wast","passed":7,"failed":0},{"name":"data1.wast","passed":14,"failed":0},{"name":"data_drop0.wast","passed":11,"failed":0},{"name":"exports0.wast","passed":8,"failed":0},{"name":"float_exprs0.wast","passed":14,"failed":0},{"name":"float_exprs1.wast","passed":3,"failed":0},{"name":"float_memory0.wast","passed":30,"failed":0},{"name":"imports.wast","passed":175,"failed":0},{"name":"imports0.wast","passed":8,"failed":0},{"name":"imports1.wast","passed":5,"failed":0},{"name":"imports2.wast","passed":20,"failed":0},{"name":"imports3.wast","passed":10,"failed":0},{"name":"imports4.wast","passed":16,"failed":0},{"name":"linking0.wast","passed":6,"failed":0},{"name":"linking1.wast","passed":14,"failed":0},{"name":"linking2.wast","passed":11,"failed":0},{"name":"linking3.wast","passed":14,"failed":0},{"name":"load.wast","passed":118,"failed":0},{"name":"load0.wast","passed":3,"failed":0},{"name":"load1.wast","passed":18,"failed":0},{"name":"load2.wast","passed":38,"failed":0},{"name":"memory-multi.wast","passed":6,"failed":0},{"name":"memory.wast","passed":86,"failed":0},{"name":"memory_copy0.wast","passed":29,"failed":0},{"name":"memory_copy1.wast","passed":14,"failed":0},{"name":"memory_fill0.wast","passed":16,"failed":0},{"name":"memory_grow.wast","passed":157,"failed":0},{"name":"memory_init0.wast","passed":13,"failed":0},{"name":"memory_size.wast","passed":49,"failed":0},{"name":"memory_size0.wast","passed":8,"failed":0},{"name":"memory_size1.wast","passed":15,"failed":0},{"name":"memory_size2.wast","passed":21,"failed":0},{"name":"memory_size3.wast","passed":2,"failed":0},{"name":"memory_trap0.wast","passed":14,"failed":0},{"name":"memory_trap1.wast","passed":168,"failed":0},{"name":"simd_memory-multi.wast (skipped)","passed":0,"failed":0},{"name":"start0.wast","passed":9,"failed":0},{"name":"store.wast","passed":111,"failed":0},{"name":"store0.wast","passed":5,"failed":0},{"name":"store1.wast","passed":13,"failed":0},{"name":"traps0.wast","passed":15,"failed":0}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index bf4f6fb..9db5ed5 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -4,7 +4,6 @@ use crate::{ConstIdx, DataAddr, ElemAddr, ExternAddr, MemAddr}; /// Represents a memory immediate in a WebAssembly memory instruction. #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] - pub struct MemoryArg([u8; 12]); impl MemoryArg { From e1b76386b7e323054d5e8844366ebad86bba693e Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 26 Apr 2025 17:43:23 +0200 Subject: [PATCH 15/17] feat: add canonicalize_nans feature Signed-off-by: Henry Gressmann --- CHANGELOG.md | 3 ++ Cargo.lock | 20 ++++++------- crates/tinywasm/Cargo.toml | 10 ++++++- .../tinywasm/src/interpreter/num_helpers.rs | 29 ++++++++++++++++--- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e63ff2b..8c47dea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for the custom memory page sizes proposal ([#22](https://github.com/explodingcamera/tinywasm/pull/22) by [@danielstuart14](https://github.com/danielstuart14)) - Support for the `tail_call` proposal +- Support for the `memory64` proposal +- Groundwork for the `simd` proposal +- New `canonicalize_nans` feature flag to enable canonicalizing NaN values in the `f32`, `f64`, and `v128` types ### Breaking Changes diff --git a/Cargo.lock b/Cargo.lock index acdc41b..f194530 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,18 +114,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstyle", "clap_lex", @@ -353,15 +353,15 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "log" @@ -426,9 +426,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 3281476..10a3099 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -32,12 +32,20 @@ serde_json={version="1.0"} serde={version="1.0", features=["derive"]} [features] -default=["std", "parser", "logging", "archive"] +default=["std", "parser", "logging", "archive", "canonicalize_nans"] + logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] + +# support for parsing WebAssembly parser=["dep:tinywasm-parser"] + +# support for "archiving" tinywasm bytecode archive=["tinywasm-types/archive"] +# canonicalize all NaN values to a single representation +canonicalize_nans=[] + # enable simd support (unstable / unfinished) __simd=[] diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index 678c32e..7e8a461 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -72,9 +72,12 @@ macro_rules! impl_wasm_float_ops { ($($t:ty)*) => ($( impl TinywasmFloatExt for $t { // https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest + #[inline] fn tw_nearest(self) -> Self { match self { - // x if x.is_nan() => x, // preserve NaN + #[cfg(not(feature = "canonicalize_nans"))] + x if x.is_nan() => x, // preserve NaN + #[cfg(feature = "canonicalize_nans")] x if x.is_nan() => Self::NAN, // Do not preserve NaN x if x.is_infinite() || x == 0.0 => x, // preserve infinities and zeros x if (0.0..=0.5).contains(&x) => 0.0, @@ -100,7 +103,9 @@ macro_rules! impl_wasm_float_ops { Some(core::cmp::Ordering::Less) => self, Some(core::cmp::Ordering::Greater) => other, Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { self } else { other }, - // None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(not(feature = "canonicalize_nans"))] + None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(feature = "canonicalize_nans")] None => Self::NAN, // Do not preserve NaN } } @@ -113,7 +118,9 @@ macro_rules! impl_wasm_float_ops { Some(core::cmp::Ordering::Greater) => self, Some(core::cmp::Ordering::Less) => other, Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { other } else { self }, - // None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(not(feature = "canonicalize_nans"))] + None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(feature = "canonicalize_nans")] None => Self::NAN, // Do not preserve NaN } } @@ -184,8 +191,15 @@ macro_rules! impl_checked_wrapping_rem { impl_checked_wrapping_rem! { i32 i64 u32 u64 } -#[cfg(feature = "__simd")] +#[cfg(all(feature = "__simd", not(feature = "canonicalize_nans")))] +#[inline] +pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { + x // No need to do anything, as we are not replacing NaNs +} + +#[cfg(all(feature = "__simd", feature = "canonicalize_nans"))] /// replace all NaNs in a f32x4 with f32::NAN +#[inline] pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { use core::simd::{Simd, num::SimdFloat}; let nan = Simd::splat(f32::NAN); @@ -193,8 +207,15 @@ pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { mask.select(nan, x) } +#[cfg(all(feature = "__simd", not(feature = "canonicalize_nans")))] +#[inline] +pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 { + x // No need to do anything, as we are not replacing NaNs +} + #[cfg(feature = "__simd")] /// replace all NaNs in a f64x2 with f64::NAN +#[inline] pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 { use core::simd::{Simd, num::SimdFloat}; let nan = Simd::splat(f64::NAN); From 0f3581ef8fdb55ad21fdfd132eaefadaec242f85 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Tue, 6 May 2025 20:14:50 +0200 Subject: [PATCH 16/17] chore: update deps, update nightly Signed-off-by: Henry Gressmann --- Cargo.lock | 36 +++++++++---------- Cargo.toml | 6 ++-- crates/cli/src/bin.rs | 2 +- crates/parser/src/lib.rs | 2 ++ crates/parser/src/module.rs | 2 +- crates/parser/src/visit.rs | 15 ++++++++ crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/src/error.rs | 4 +-- crates/tinywasm/src/func.rs | 2 +- crates/tinywasm/src/instance.rs | 4 +-- crates/tinywasm/src/store/table.rs | 3 +- .../tests/host_func_signature_check.rs | 2 +- crates/tinywasm/tests/testsuite/run.rs | 24 ++++++------- crates/types/src/archive.rs | 2 +- crates/types/src/value.rs | 4 +-- 15 files changed, 63 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f194530..d1cbed1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -268,15 +268,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "hermit-abi" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "humantime" @@ -359,9 +359,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" +checksum = "a25169bd5913a4b437588a7e3d127cd6e90127b60e0ffbd834a38f1599e016b8" [[package]] name = "log" @@ -552,9 +552,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -664,9 +664,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.229.0" +version = "0.230.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2" +checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660" dependencies = [ "leb128fmt", "wasmparser", @@ -674,9 +674,9 @@ dependencies = [ [[package]] name = "wasm-testsuite" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "735333508bfc70a3cc7a7ed86b3cd53e4a775cbf78511eaec8ac4926ed3a0bf7" +checksum = "77cf162d75d8af40f1e44215c84edd30f895538741c29d1c890249665b310d94" dependencies = [ "include_dir", "wast", @@ -684,9 +684,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.229.0" +version = "0.230.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c" +checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed" dependencies = [ "bitflags", "indexmap", @@ -695,9 +695,9 @@ dependencies = [ [[package]] name = "wast" -version = "229.0.0" +version = "230.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9" +checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1" dependencies = [ "bumpalo", "leb128fmt", @@ -708,9 +708,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.229.0" +version = "1.230.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0" +checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894" dependencies = [ "wast", ] diff --git a/Cargo.toml b/Cargo.toml index 1f645cf..198c885 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,9 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"] resolver="2" [workspace.dependencies] -wast="229" -wat="1.229" -wasmparser={version="0.229", default-features=false} +wast="230" +wat="1.230" +wasmparser={version="0.230", default-features=false} eyre="0.6" log="0.4" pretty_env_logger="0.5" diff --git a/crates/cli/src/bin.rs b/crates/cli/src/bin.rs index 8c0fe93..d00848e 100644 --- a/crates/cli/src/bin.rs +++ b/crates/cli/src/bin.rs @@ -82,7 +82,7 @@ fn main() -> Result<()> { match args.nested { TinyWasmSubcommand::Run(Run { wasm_file, engine, args, func }) => { - debug!("args: {:?}", args); + debug!("args: {args:?}"); let path = cwd.join(wasm_file.clone()); let module = match wasm_file.ends_with(".wat") { diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index aa33995..f0196b6 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -83,6 +83,8 @@ impl Parser { cm_nested_names: false, cm_values: false, cm_error_context: false, + cm_fixed_size_list: false, + cm_gc: false, }; Validator::new_with_features(features.into()) } diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 0e17ad9..3a3becd 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -125,7 +125,7 @@ impl ModuleReader { self.code_type_addrs = reader.into_iter().map(|f| Ok(f?)).collect::>>()?; } CodeSectionStart { count, range, .. } => { - debug!("Found code section ({} functions)", count); + debug!("Found code section ({count} functions)"); if !self.code.is_empty() { return Err(ParseError::DuplicateSection("Code section".into())); } diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 10005c0..1635d2d 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -453,6 +453,21 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild self.instructions.push(Instruction::RefIsNull); } + fn visit_typed_select_multi(&mut self, _tys: Vec) -> Self::Output { + self.errors.push(crate::ParseError::UnsupportedOperator( + "Typed select with multiple types is not supported".to_string(), + )); + + // self.instructions.extend(tys.into_iter().map(|ty| match ty { + // wasmparser::ValType::I32 => Instruction::Select32, + // wasmparser::ValType::F32 => Instruction::Select32, + // wasmparser::ValType::I64 => Instruction::Select64, + // wasmparser::ValType::F64 => Instruction::Select64, + // wasmparser::ValType::V128 => Instruction::Select128, + // wasmparser::ValType::Ref(_) => Instruction::SelectRef, + // })); + } + fn visit_typed_select(&mut self, ty: wasmparser::ValType) -> Self::Output { self.instructions.push(match ty { wasmparser::ValType::I32 => Instruction::Select32, diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 10a3099..427b45e 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false libm={version="0.2", default-features=false} [dev-dependencies] -wasm-testsuite={version="0.5.3"} +wasm-testsuite={version="0.5.4"} indexmap="2.7" wast={workspace=true} wat={workspace=true} diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs index 9637521..fcaac1a 100644 --- a/crates/tinywasm/src/error.rs +++ b/crates/tinywasm/src/error.rs @@ -211,9 +211,9 @@ impl Display for Error { impl Display for LinkingError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Self::UnknownImport { module, name } => write!(f, "unknown import: {}.{}", module, name), + Self::UnknownImport { module, name } => write!(f, "unknown import: {module}.{name}"), Self::IncompatibleImportType { module, name } => { - write!(f, "incompatible import type: {}.{}", module, name) + write!(f, "incompatible import type: {module}.{name}") } } } diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 2eeabca..642377a 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -39,7 +39,7 @@ impl FuncHandle { // 5. For each value type and the corresponding value, check if types match if !(func_ty.params.iter().zip(params).enumerate().all(|(_i, (ty, param))| { if ty != ¶m.val_type() { - log::error!("param type mismatch at index {}: expected {:?}, got {:?}", _i, ty, param); + log::error!("param type mismatch at index {_i}: expected {ty:?}, got {param:?}"); false } else { true diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index eebf5ff..9a0d1e2 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -192,7 +192,7 @@ impl ModuleInstance { pub fn exported_memory<'a>(&self, store: &'a mut Store, name: &str) -> Result> { let export = self.export_addr(name).ok_or_else(|| Error::Other(format!("Export not found: {name}")))?; let ExternVal::Memory(mem_addr) = export else { - return Err(Error::Other(format!("Export is not a memory: {}", name))); + return Err(Error::Other(format!("Export is not a memory: {name}"))); }; self.memory(store, mem_addr) @@ -202,7 +202,7 @@ impl ModuleInstance { pub fn exported_memory_mut<'a>(&self, store: &'a mut Store, name: &str) -> Result> { let export = self.export_addr(name).ok_or_else(|| Error::Other(format!("Export not found: {name}")))?; let ExternVal::Memory(mem_addr) = export else { - return Err(Error::Other(format!("Export is not a memory: {}", name))); + return Err(Error::Other(format!("Export is not a memory: {name}"))); }; self.memory_mut(store, mem_addr) diff --git a/crates/tinywasm/src/store/table.rs b/crates/tinywasm/src/store/table.rs index f83de9b..6192119 100644 --- a/crates/tinywasm/src/store/table.rs +++ b/crates/tinywasm/src/store/table.rs @@ -250,8 +250,7 @@ mod tests { let elem = table_instance.get(i); assert!( elem.is_ok() && matches!(elem.unwrap(), &TableElement::Initialized(_)), - "Element not initialized correctly at index {}", - i + "Element not initialized correctly at index {i}" ); } } diff --git a/crates/tinywasm/tests/host_func_signature_check.rs b/crates/tinywasm/tests/host_func_signature_check.rs index 698ad61..9389435 100644 --- a/crates/tinywasm/tests/host_func_signature_check.rs +++ b/crates/tinywasm/tests/host_func_signature_check.rs @@ -147,7 +147,7 @@ fn proxy_module(func_ty: &FuncType) -> Module { let params_text = join_surround(params, "param"); let params_gets: String = params.iter().enumerate().fold(String::new(), |mut acc, (num, _)| { - let _ = writeln!(acc, "(local.get {num})", num = num); + let _ = writeln!(acc, "(local.get {num})"); acc }); diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index d09efdb..c46a276 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -31,7 +31,7 @@ impl ModuleRegistry { } } fn register(&mut self, name: String, addr: ModuleInstanceAddr) { - log::debug!("registering module: {}", name); + log::debug!("registering module: {name}"); self.modules.insert(name.clone(), addr); self.last_module = Some(addr); @@ -99,22 +99,22 @@ impl TestSuite { }); let print_i32 = Extern::typed_func(|_ctx: tinywasm::FuncContext, arg: i32| { - log::debug!("print_i32: {}", arg); + log::debug!("print_i32: {arg}"); Ok(()) }); let print_i64 = Extern::typed_func(|_ctx: tinywasm::FuncContext, arg: i64| { - log::debug!("print_i64: {}", arg); + log::debug!("print_i64: {arg}"); Ok(()) }); let print_f32 = Extern::typed_func(|_ctx: tinywasm::FuncContext, arg: f32| { - log::debug!("print_f32: {}", arg); + log::debug!("print_f32: {arg}"); Ok(()) }); let print_f64 = Extern::typed_func(|_ctx: tinywasm::FuncContext, arg: f64| { - log::debug!("print_f64: {}", arg); + log::debug!("print_f64: {arg}"); Ok(()) }); @@ -148,7 +148,7 @@ impl TestSuite { .define("spectest", "print_f64_f64", print_f64_f64)?; for (name, addr) in modules { - log::debug!("registering module: {}", name); + log::debug!("registering module: {name}"); imports.link_module(name, *addr)?; } @@ -158,7 +158,7 @@ impl TestSuite { pub fn run_files<'a>(&mut self, tests: impl IntoIterator>) -> Result<()> { tests.into_iter().for_each(|group| { let name = group.name(); - println!("running group: {}", name); + println!("running group: {name}"); if self.1.contains(&name.to_string()) { info!("skipping group: {name}"); self.test_group(&format!("{name} (skipped)"), name); @@ -217,7 +217,7 @@ impl TestSuite { .map_err(|e| eyre!("failed to parse wat module: {:?}", try_downcast_panic(e))); match &result { - Err(err) => debug!("failed to parse module: {:?}", err), + Err(err) => debug!("failed to parse module: {err:?}"), Ok((name, module)) => module_registry.update_last_module(module.id(), name.clone()), }; @@ -402,7 +402,7 @@ impl TestSuite { let args = convert_wastargs(invoke.args)?; let module = module_registry.get_idx(invoke.module); exec_fn_instance(module, &mut store, invoke.name, &args).map_err(|e| { - error!("failed to execute function: {:?}", e); + error!("failed to execute function: {e:?}"); e })?; Ok(()) @@ -413,7 +413,7 @@ impl TestSuite { } AssertReturn { span, exec, results } => { - info!("AssertReturn: {:?}", exec); + info!("AssertReturn: {exec:?}"); let expected = match convert_wastret(results.into_iter()) { Err(err) => { test_group.add_result( @@ -489,11 +489,11 @@ impl TestSuite { let invoke_name = invoke.name; let res: Result, _> = catch_unwind_silent(|| { - debug!("invoke: {:?}", invoke); + debug!("invoke: {invoke:?}"); let args = convert_wastargs(invoke.args)?; let module = module_registry.get_idx(invoke.module); let outcomes = exec_fn_instance(module, &mut store, invoke.name, &args).map_err(|e| { - error!("failed to execute function: {:?}", e); + error!("failed to execute function: {e:?}"); e })?; diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs index cbc22ad..b190d43 100644 --- a/crates/types/src/archive.rs +++ b/crates/types/src/archive.rs @@ -37,7 +37,7 @@ impl Display for TwasmError { TwasmError::InvalidMagic => write!(f, "Invalid twasm: invalid magic number"), TwasmError::InvalidVersion => write!(f, "Invalid twasm: invalid version"), TwasmError::InvalidPadding => write!(f, "Invalid twasm: invalid padding"), - TwasmError::InvalidArchive(e) => write!(f, "Invalid twasm: {}", e), + TwasmError::InvalidArchive(e) => write!(f, "Invalid twasm: {e}"), } } } diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index a9498cc..b68836b 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -32,7 +32,7 @@ pub struct FuncRef(Option); impl Debug for ExternRef { fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { match self.0 { - Some(addr) => write!(f, "extern({:?})", addr), + Some(addr) => write!(f, "extern({addr:?})"), None => write!(f, "extern(null)"), } } @@ -41,7 +41,7 @@ impl Debug for ExternRef { impl Debug for FuncRef { fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { match self.0 { - Some(addr) => write!(f, "func({:?})", addr), + Some(addr) => write!(f, "func({addr:?})"), None => write!(f, "func(null)"), } } From f9f760f487cfb08aa7992439bf748f7dcd46466b Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Tue, 6 May 2025 21:36:25 +0200 Subject: [PATCH 17/17] chore: cleanup Signed-off-by: Henry Gressmann --- Cargo.toml | 2 + crates/cli/Cargo.toml | 2 + crates/parser/Cargo.toml | 2 + crates/parser/src/module.rs | 2 +- crates/parser/src/visit.rs | 18 ++- crates/tinywasm/Cargo.toml | 4 +- crates/tinywasm/src/error.rs | 2 + crates/tinywasm/src/func.rs | 8 +- crates/tinywasm/src/imports.rs | 4 +- crates/tinywasm/src/instance.rs | 4 +- crates/tinywasm/src/interpreter/executor.rs | 132 +++++++++++++------- crates/tinywasm/src/interpreter/values.rs | 33 +++-- crates/tinywasm/src/lib.rs | 2 +- crates/tinywasm/src/reference.rs | 9 +- crates/tinywasm/src/store/mod.rs | 8 +- crates/tinywasm/src/store/table.rs | 12 +- crates/tinywasm/tests/testsuite/mod.rs | 2 +- crates/tinywasm/tests/testsuite/util.rs | 6 +- crates/types/Cargo.toml | 2 + crates/types/src/archive.rs | 10 +- crates/types/src/instructions.rs | 2 +- crates/types/src/lib.rs | 26 ++-- crates/types/src/value.rs | 28 ++--- 23 files changed, 188 insertions(+), 132 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 198c885..135dbd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ edition="2024" license="MIT OR Apache-2.0" authors=["Henry Gressmann "] repository="https://github.com/explodingcamera/tinywasm" +categories=["wasm", "no-std"] +keywords=["tinywasm"] [package] name="tinywasm-root" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index d5e64a8..097a7c4 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -7,6 +7,8 @@ license.workspace=true authors.workspace=true repository.workspace=true rust-version.workspace=true +keywords.workspace=true +categories=["wasm"] [[bin]] name="tinywasm-cli" diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 7bd9cad..3cbeee1 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -7,6 +7,8 @@ license.workspace=true authors.workspace=true repository.workspace=true rust-version.workspace=true +keywords.workspace=true +categories.workspace=true [dependencies] wasmparser={workspace=true, features=["validate", "features", "simd"]} diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 3a3becd..1651bf0 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -30,7 +30,7 @@ pub(crate) struct ModuleReader { } impl ModuleReader { - pub(crate) fn new() -> ModuleReader { + pub(crate) fn new() -> Self { Self::default() } diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 1635d2d..4ae2cc1 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -370,17 +370,13 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild let if_instruction = &mut self.instructions[if_label_pointer]; - let (else_offset, end_offset) = match if_instruction { - Instruction::If(else_offset, end_offset) - | Instruction::IfWithFuncType(_, else_offset, end_offset) - | Instruction::IfWithType(_, else_offset, end_offset) => (else_offset, end_offset), - _ => { - self.errors.push(crate::ParseError::UnsupportedOperator( - "Expected to end an if block, but the last label was not an if".to_string(), - )); - - return; - } + let (Instruction::If(else_offset, end_offset) + | Instruction::IfWithFuncType(_, else_offset, end_offset) + | Instruction::IfWithType(_, else_offset, end_offset)) = if_instruction + else { + return self.errors.push(crate::ParseError::UnsupportedOperator( + "Expected to end an if block, but the last label was not an if".to_string(), + )); }; *else_offset = (label_pointer - if_label_pointer) diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 427b45e..19e75ff 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -7,6 +7,8 @@ license.workspace=true authors.workspace=true repository.workspace=true rust-version.workspace=true +keywords.workspace=true +categories.workspace=true readme="../../README.md" [lib] @@ -32,7 +34,7 @@ serde_json={version="1.0"} serde={version="1.0", features=["derive"]} [features] -default=["std", "parser", "logging", "archive", "canonicalize_nans"] +default=["std", "parser", "logging", "archive", "canonicalize_nans", "__simd"] logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs index fcaac1a..4b3a969 100644 --- a/crates/tinywasm/src/error.rs +++ b/crates/tinywasm/src/error.rs @@ -51,6 +51,7 @@ pub enum Error { #[derive(Debug)] /// Errors that can occur when linking a WebAssembly module +#[non_exhaustive] pub enum LinkingError { /// An unknown import was encountered UnknownImport { @@ -83,6 +84,7 @@ impl LinkingError { /// A WebAssembly trap /// /// See +#[non_exhaustive] pub enum Trap { /// An unreachable instruction was executed Unreachable, diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 642377a..5e5eb25 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -1,6 +1,6 @@ use crate::interpreter::stack::{CallFrame, Stack}; +use crate::{log, unlikely, Function}; use crate::{Error, FuncContext, Result, Store}; -use crate::{Function, log, unlikely}; use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec}; use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, ValType, WasmValue}; @@ -38,11 +38,11 @@ impl FuncHandle { // 5. For each value type and the corresponding value, check if types match if !(func_ty.params.iter().zip(params).enumerate().all(|(_i, (ty, param))| { - if ty != ¶m.val_type() { + if ty == ¶m.val_type() { + true + } else { log::error!("param type mismatch at index {_i}: expected {ty:?}, got {param:?}"); false - } else { - true } })) { return Err(Error::Other("Type mismatch".into())); diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index 12876c8..90f4971 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -170,7 +170,7 @@ impl Extern { let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue]| -> Result> { let args = P::from_wasm_value_tuple(args)?; let result = func(ctx, args)?; - Ok(result.into_wasm_value_tuple().to_vec()) + Ok(result.into_wasm_value_tuple()) }; let ty = tinywasm_types::FuncType { params: P::val_types(), results: R::val_types() }; @@ -263,7 +263,7 @@ impl ResolvedImports { impl Imports { /// Create a new empty import set pub fn new() -> Self { - Imports { values: BTreeMap::new(), modules: BTreeMap::new() } + Self { values: BTreeMap::new(), modules: BTreeMap::new() } } /// Merge two import sets diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index 9a0d1e2..75c12d6 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -12,7 +12,7 @@ use crate::{Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, MemoryRefMut #[derive(Debug, Clone)] pub struct ModuleInstance(pub(crate) Rc); -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub(crate) struct ModuleInstanceInner { pub(crate) failed_to_instantiate: bool, @@ -90,7 +90,7 @@ impl ModuleInstance { exports: module.0.exports, }; - let instance = ModuleInstance::new(instance); + let instance = Self::new(instance); store.add_instance(instance.clone()); match (elem_trapped, data_trapped) { diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 4bf4f5d..10e9ddd 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -142,16 +142,16 @@ impl<'store, 'stack> Executor<'store, 'stack> { I64Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, F32Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, F64Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, - I32Load8S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, - I32Load8U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, - I32Load16S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, - I32Load16U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, - I64Load8S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, - I64Load8U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, - I64Load16S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, - I64Load16U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, - I64Load32S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, - I64Load32U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, + I32Load8S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i32::from)?, + I32Load8U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i32::from)?, + I32Load16S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i32::from)?, + I32Load16U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i32::from)?, + I64Load8S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i64::from)?, + I64Load8U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i64::from)?, + I64Load16S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i64::from)?, + I64Load16U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i64::from)?, + I64Load32S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i64::from)?, + I64Load32U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), i64::from)?, I64Eqz => self.stack.values.replace_top::(|v| Ok(i32::from(v == 0))).to_cf()?, I32Eqz => self.stack.values.replace_top_same::(|v| Ok(i32::from(v == 0))).to_cf()?, @@ -238,32 +238,32 @@ impl<'store, 'stack> Executor<'store, 'stack> { I64Rotr => self.stack.values.calculate_same::(|a, b| Ok(a.wasm_rotr(b))).to_cf()?, I32Clz => self.stack.values.replace_top_same::(|v| Ok(v.leading_zeros() as i32)).to_cf()?, - I64Clz => self.stack.values.replace_top_same::(|v| Ok(v.leading_zeros() as i64)).to_cf()?, + I64Clz => self.stack.values.replace_top_same::(|v| Ok(i64::from(v.leading_zeros()))).to_cf()?, I32Ctz => self.stack.values.replace_top_same::(|v| Ok(v.trailing_zeros() as i32)).to_cf()?, - I64Ctz => self.stack.values.replace_top_same::(|v| Ok(v.trailing_zeros() as i64)).to_cf()?, + I64Ctz => self.stack.values.replace_top_same::(|v| Ok(i64::from(v.trailing_zeros()))).to_cf()?, I32Popcnt => self.stack.values.replace_top_same::(|v| Ok(v.count_ones() as i32)).to_cf()?, - I64Popcnt => self.stack.values.replace_top_same::(|v| Ok(v.count_ones() as i64)).to_cf()?, + I64Popcnt => self.stack.values.replace_top_same::(|v| Ok(i64::from(v.count_ones()))).to_cf()?, F32ConvertI32S => self.stack.values.replace_top::(|v| Ok(v as f32)).to_cf()?, F32ConvertI64S => self.stack.values.replace_top::(|v| Ok(v as f32)).to_cf()?, - F64ConvertI32S => self.stack.values.replace_top::(|v| Ok(v as f64)).to_cf()?, + F64ConvertI32S => self.stack.values.replace_top::(|v| Ok(f64::from(v))).to_cf()?, F64ConvertI64S => self.stack.values.replace_top::(|v| Ok(v as f64)).to_cf()?, F32ConvertI32U => self.stack.values.replace_top::(|v| Ok(v as f32)).to_cf()?, F32ConvertI64U => self.stack.values.replace_top::(|v| Ok(v as f32)).to_cf()?, - F64ConvertI32U => self.stack.values.replace_top::(|v| Ok(v as f64)).to_cf()?, + F64ConvertI32U => self.stack.values.replace_top::(|v| Ok(f64::from(v))).to_cf()?, F64ConvertI64U => self.stack.values.replace_top::(|v| Ok(v as f64)).to_cf()?, - I32Extend8S => self.stack.values.replace_top_same::(|v| Ok((v as i8) as i32)).to_cf()?, - I32Extend16S => self.stack.values.replace_top_same::(|v| Ok((v as i16) as i32)).to_cf()?, - I64Extend8S => self.stack.values.replace_top_same::(|v| Ok((v as i8) as i64)).to_cf()?, - I64Extend16S => self.stack.values.replace_top_same::(|v| Ok((v as i16) as i64)).to_cf()?, - I64Extend32S => self.stack.values.replace_top_same::(|v| Ok((v as i32) as i64)).to_cf()?, - I64ExtendI32U => self.stack.values.replace_top::(|v| Ok(v as i64)).to_cf()?, - I64ExtendI32S => self.stack.values.replace_top::(|v| Ok(v as i64)).to_cf()?, + I32Extend8S => self.stack.values.replace_top_same::(|v| Ok(i32::from(v as i8))).to_cf()?, + I32Extend16S => self.stack.values.replace_top_same::(|v| Ok(i32::from(v as i16))).to_cf()?, + I64Extend8S => self.stack.values.replace_top_same::(|v| Ok(i64::from(v as i8))).to_cf()?, + I64Extend16S => self.stack.values.replace_top_same::(|v| Ok(i64::from(v as i16))).to_cf()?, + I64Extend32S => self.stack.values.replace_top_same::(|v| Ok(i64::from(v as i32))).to_cf()?, + I64ExtendI32U => self.stack.values.replace_top::(|v| Ok(i64::from(v))).to_cf()?, + I64ExtendI32S => self.stack.values.replace_top::(|v| Ok(i64::from(v))).to_cf()?, I32WrapI64 => self.stack.values.replace_top::(|v| Ok(v as i32)).to_cf()?, F32DemoteF64 => self.stack.values.replace_top::(|v| Ok(v as f32)).to_cf()?, - F64PromoteF32 => self.stack.values.replace_top::(|v| Ok(v as f64)).to_cf()?, + F64PromoteF32 => self.stack.values.replace_top::(|v| Ok(f64::from(v))).to_cf()?, F32Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, F64Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, @@ -324,7 +324,19 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[cfg(feature = "__simd")] V128Bitselect => self.stack.values.calculate_same_3::(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?, #[cfg(feature = "__simd")] V128AnyTrue => self.stack.values.replace_top::(|v| Ok((v.reduce_or() != 0) as i32)).to_cf()?, #[cfg(feature = "__simd")] I8x16Swizzle => self.stack.values.calculate_same::(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?, + #[cfg(feature = "__simd")] V128Load(arg) => self.exec_mem_load::(arg.mem_addr(), arg.offset(), |v| v)?, + #[cfg(feature = "__simd")] V128Load8x8S(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load8x8U(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load16x4S(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load16x4U(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load32x2S(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load32x2U(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load8Splat(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load16Splat(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load32Splat(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Load64Splat(_arg) => unimplemented!(), + #[cfg(feature = "__simd")] V128Store(arg) => self.exec_mem_store::(arg.mem_addr(), arg.offset(), |v| v)?, #[cfg(feature = "__simd")] V128Store8Lane(arg, lane) => self.exec_mem_store_lane::(arg.mem_addr(), arg.offset(), *lane)?, @@ -358,6 +370,13 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[cfg(feature = "__simd")] V128Load32Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, #[cfg(feature = "__simd")] V128Load64Lane(arg, lane) => self.exec_mem_load_lane::(arg.mem_addr(), arg.offset(), *lane)?, + #[cfg(feature = "__simd")] I8x16ReplaceLane(_lane) => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ReplaceLane(_lane) => unimplemented!(), + #[cfg(feature = "__simd")] I32x4ReplaceLane(_lane) => unimplemented!(), + #[cfg(feature = "__simd")] I64x2ReplaceLane(_lane) => unimplemented!(), + #[cfg(feature = "__simd")] F32x4ReplaceLane(_lane) => unimplemented!(), + #[cfg(feature = "__simd")] F64x2ReplaceLane(_lane) => unimplemented!(), + #[cfg(feature = "__simd")] I8x16Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i8))).to_cf()?, #[cfg(feature = "__simd")] I16x8Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v as i16))).to_cf()?, #[cfg(feature = "__simd")] I32x4Splat => self.stack.values.replace_top::(|v| Ok(Simd::::splat(v))).to_cf()?, @@ -368,12 +387,14 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[cfg(feature = "__simd")] I8x16Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] I16x8Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] I32x4Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I64x2Eq => self.stack.values.calculate_same::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] F32x4Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] F64x2Eq => self.stack.values.calculate::(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] I8x16Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] I16x8Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] I32x4Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, + #[cfg(feature = "__simd")] I64x2Ne => self.stack.values.calculate_same::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] F32x4Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, #[cfg(feature = "__simd")] F64x2Ne => self.stack.values.calculate::(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?, @@ -500,6 +521,9 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[cfg(feature = "__simd")] I8x16SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, #[cfg(feature = "__simd")] I16x8SubSatU => self.stack.values.calculate_same::(|a, b| Ok(a.saturating_sub(b))).to_cf()?, + #[cfg(feature = "__simd")] I8x16AvgrU => unimplemented!(), + #[cfg(feature = "__simd")] I16x8AvgrU => unimplemented!(), + #[cfg(feature = "__simd")] I16x8ExtAddPairwiseI8x16S => unimplemented!(), #[cfg(feature = "__simd")] I16x8ExtAddPairwiseI8x16U => unimplemented!(), #[cfg(feature = "__simd")] I32x4ExtAddPairwiseI16x8S => unimplemented!(), @@ -532,6 +556,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[cfg(feature = "__simd")] I64x2ExtendHighI32x4U => unimplemented!(), #[cfg(feature = "__simd")] I8x16Popcnt => self.stack.values.replace_top::(|v| Ok(v.count_ones())).to_cf()?, + #[cfg(feature = "__simd")] I8x16Shuffle(_idx) => unimplemented!(), #[cfg(feature = "__simd")] I16x8Q15MulrSatS => self.stack.values.calculate_same::(|a, b| { @@ -575,6 +600,8 @@ impl<'store, 'stack> Executor<'store, 'stack> { #[cfg(feature = "__simd")] F64x2Floor => self.stack.values.replace_top_same::(|v| Ok(v.floor())).to_cf()?, #[cfg(feature = "__simd")] F32x4Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, #[cfg(feature = "__simd")] F64x2Trunc => self.stack.values.replace_top_same::(|v| Ok(v.trunc())).to_cf()?, + #[cfg(feature = "__simd")] F32x4Nearest => self.stack.values.replace_top_same::(|v| Ok(v.round())).to_cf()?, + #[cfg(feature = "__simd")] F64x2Nearest => self.stack.values.replace_top_same::(|v| Ok(v.round())).to_cf()?, #[cfg(feature = "__simd")] F32x4Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, #[cfg(feature = "__simd")] F64x2Abs => self.stack.values.replace_top_same::(|v| Ok(v.abs())).to_cf()?, #[cfg(feature = "__simd")] F32x4Neg => self.stack.values.replace_top_same::(|v| Ok(-v)).to_cf()?, @@ -664,15 +691,37 @@ impl<'store, 'stack> Executor<'store, 'stack> { // not correct #[cfg(feature = "__simd")] I32x4TruncSatF32x4S => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, #[cfg(feature = "__simd")] I32x4TruncSatF32x4U => self.stack.values.replace_top::(|v| Ok(v.trunc())).to_cf()?, - #[cfg(feature = "__simd")] F32x4ConvertI32x4S => {}, - #[cfg(feature = "__simd")] F32x4ConvertI32x4U => {}, - #[cfg(feature = "__simd")] F64x2ConvertLowI32x4S => {}, - #[cfg(feature = "__simd")] F64x2ConvertLowI32x4U => {}, - #[cfg(feature = "__simd")] F32x4DemoteF64x2Zero => {}, - #[cfg(feature = "__simd")] F64x2PromoteLowF32x4 => {}, + #[cfg(feature = "__simd")] F32x4ConvertI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] F32x4ConvertI32x4U => unimplemented!(), + #[cfg(feature = "__simd")] F64x2ConvertLowI32x4S => unimplemented!(), + #[cfg(feature = "__simd")] F64x2ConvertLowI32x4U => unimplemented!(), + #[cfg(feature = "__simd")] F32x4DemoteF64x2Zero => unimplemented!(), + #[cfg(feature = "__simd")] F64x2PromoteLowF32x4 => unimplemented!(), #[cfg(feature = "__simd")] I32x4TruncSatF64x2SZero => unimplemented!(), #[cfg(feature = "__simd")] I32x4TruncSatF64x2UZero => unimplemented!(), + #[cfg(feature = "__simd")] I8x16RelaxedSwizzle => unimplemented!(), + #[cfg(feature = "__simd")] I32x4RelaxedTruncF32x4S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4RelaxedTruncF32x4U => unimplemented!(), + #[cfg(feature = "__simd")] I32x4RelaxedTruncF64x2SZero => unimplemented!(), + #[cfg(feature = "__simd")] I32x4RelaxedTruncF64x2UZero => unimplemented!(), + #[cfg(feature = "__simd")] F32x4RelaxedMadd => unimplemented!(), + #[cfg(feature = "__simd")] F32x4RelaxedNmadd => unimplemented!(), + #[cfg(feature = "__simd")] F64x2RelaxedMadd => unimplemented!(), + #[cfg(feature = "__simd")] F64x2RelaxedNmadd => unimplemented!(), + #[cfg(feature = "__simd")] I8x16RelaxedLaneselect => unimplemented!(), + #[cfg(feature = "__simd")] I16x8RelaxedLaneselect => unimplemented!(), + #[cfg(feature = "__simd")] I32x4RelaxedLaneselect => unimplemented!(), + #[cfg(feature = "__simd")] I64x2RelaxedLaneselect => unimplemented!(), + #[cfg(feature = "__simd")] F32x4RelaxedMin => unimplemented!(), + #[cfg(feature = "__simd")] F32x4RelaxedMax => unimplemented!(), + #[cfg(feature = "__simd")] F64x2RelaxedMin => unimplemented!(), + #[cfg(feature = "__simd")] F64x2RelaxedMax => unimplemented!(), + #[cfg(feature = "__simd")] I16x8RelaxedQ15mulrS => unimplemented!(), + #[cfg(feature = "__simd")] I16x8RelaxedDotI8x16I7x16S => unimplemented!(), + #[cfg(feature = "__simd")] I32x4RelaxedDotI8x16I7x16AddS => unimplemented!(), + + #[allow(unreachable_patterns)] i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; @@ -690,18 +739,17 @@ impl<'store, 'stack> Executor<'store, 'stack> { wasm_func: Rc, owner: ModuleInstanceAddr, ) -> ControlFlow> { - if !IS_RETURN_CALL { - let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals); + let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals); + + if IS_RETURN_CALL { + self.cf.reuse_for(wasm_func, locals, self.stack.blocks.len() as u32, owner); + } else { let new_call_frame = CallFrame::new_raw(wasm_func, owner, locals, self.stack.blocks.len() as u32); self.cf.incr_instr_ptr(); // skip the call instruction self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?; - self.module.swap_with(self.cf.module_addr(), self.store); - } else { - let locals = self.stack.values.pop_locals(wasm_func.params, wasm_func.locals); - self.cf.reuse_for(wasm_func, locals, self.stack.blocks.len() as u32, owner); - self.module.swap_with(self.cf.module_addr(), self.store); } + self.module.swap_with(self.cf.module_addr(), self.store); ControlFlow::Continue(()) } fn exec_call_host(&mut self, host_func: Rc) -> ControlFlow> { @@ -880,7 +928,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { self.stack.values.push(val); } fn exec_ref_is_null(&mut self) { - let is_null = self.stack.values.pop::().is_none() as i32; + let is_null = i32::from(self.stack.values.pop::().is_none()); self.stack.values.push::(is_null); } @@ -898,7 +946,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let pages_delta = match mem.is_64bit() { true => self.stack.values.pop::(), - false => self.stack.values.pop::() as i64, + false => i64::from(self.stack.values.pop::()), }; match ( @@ -1035,7 +1083,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let addr = match mem.is_64bit() { true => self.stack.values.pop::() as u64, - false => self.stack.values.pop::() as u32 as u64, + false => u64::from(self.stack.values.pop::() as u32), }; let Some(Ok(addr)) = offset.checked_add(addr).map(|a| a.try_into()) else { @@ -1086,7 +1134,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let addr = match mem.is_64bit() { true => self.stack.values.pop::() as u64, - false => self.stack.values.pop::() as u32 as u64, + false => u64::from(self.stack.values.pop::() as u32), }; if let Err(e) = mem.store((offset + addr) as usize, val.len(), &val) { @@ -1152,7 +1200,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); }; - table.init(dst as i64, &items[offset as usize..(offset + size) as usize]) + table.init(i64::from(dst), &items[offset as usize..(offset + size) as usize]) } fn exec_table_grow(&mut self, table_index: u32) -> Result<()> { let table = self.store.get_table_mut(self.module.resolve_table_addr(table_index)); @@ -1162,7 +1210,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { let val = self.stack.values.pop::(); match table.grow(n, val.into()) { - Ok(_) => self.stack.values.push(sz), + Ok(()) => self.stack.values.push(sz), Err(_) => self.stack.values.push(-1_i32), } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 779fc60..957b4bb 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -12,7 +12,7 @@ pub(crate) type Value128 = core::simd::u8x16; #[cfg(not(feature = "__simd"))] pub(crate) type Value128 = i128; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] /// A untyped WebAssembly value pub enum TinyWasmValue { /// A 32-bit value @@ -74,7 +74,7 @@ impl TinyWasmValue { /// Asserts that the value is a 32-bit value and returns it (panics if the value is the wrong size) pub fn unwrap_32(&self) -> Value32 { match self { - TinyWasmValue::Value32(v) => *v, + Self::Value32(v) => *v, _ => unreachable!("Expected Value32"), } } @@ -82,7 +82,7 @@ impl TinyWasmValue { /// Asserts that the value is a 64-bit value and returns it (panics if the value is the wrong size) pub fn unwrap_64(&self) -> Value64 { match self { - TinyWasmValue::Value64(v) => *v, + Self::Value64(v) => *v, _ => unreachable!("Expected Value64"), } } @@ -90,7 +90,7 @@ impl TinyWasmValue { /// Asserts that the value is a 128-bit value and returns it (panics if the value is the wrong size) pub fn unwrap_128(&self) -> Value128 { match self { - TinyWasmValue::Value128(v) => *v, + Self::Value128(v) => *v, _ => unreachable!("Expected Value128"), } } @@ -98,7 +98,7 @@ impl TinyWasmValue { /// Asserts that the value is a reference value and returns it (panics if the value is the wrong size) pub fn unwrap_ref(&self) -> ValueRef { match self { - TinyWasmValue::ValueRef(v) => *v, + Self::ValueRef(v) => *v, _ => unreachable!("Expected ValueRef"), } } @@ -125,15 +125,15 @@ impl TinyWasmValue { impl From<&WasmValue> for TinyWasmValue { fn from(value: &WasmValue) -> Self { match value { - WasmValue::I32(v) => TinyWasmValue::Value32(*v as u32), - WasmValue::I64(v) => TinyWasmValue::Value64(*v as u64), - WasmValue::F32(v) => TinyWasmValue::Value32(v.to_bits()), - WasmValue::F64(v) => TinyWasmValue::Value64(v.to_bits()), - WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(v.addr()), - WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(v.addr()), + WasmValue::I32(v) => Self::Value32(*v as u32), + WasmValue::I64(v) => Self::Value64(*v as u64), + WasmValue::F32(v) => Self::Value32(v.to_bits()), + WasmValue::F64(v) => Self::Value64(v.to_bits()), + WasmValue::RefExtern(v) => Self::ValueRef(v.addr()), + WasmValue::RefFunc(v) => Self::ValueRef(v.addr()), #[cfg(not(feature = "__simd"))] - WasmValue::V128(v) => TinyWasmValue::Value128(*v), + WasmValue::V128(v) => Self::Value128(*v), #[cfg(feature = "__simd")] WasmValue::V128(v) => TinyWasmValue::Value128(v.to_le_bytes().into()), @@ -143,12 +143,12 @@ impl From<&WasmValue> for TinyWasmValue { impl From for TinyWasmValue { fn from(value: WasmValue) -> Self { - TinyWasmValue::from(&value) + Self::from(&value) } } mod sealed { - #[allow(unreachable_pub)] + #[expect(unreachable_pub)] pub trait Sealed {} } @@ -160,7 +160,6 @@ pub(crate) trait InternalValue: sealed::Sealed + Into { fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result) -> Result<()> where Self: Sized; - #[allow(dead_code)] fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result) -> Result<()> where Self: Sized; @@ -266,8 +265,8 @@ macro_rules! impl_internalvalue { impl_internalvalue! { Value32, stack_32, locals_32, u32, u32, |v| v, |v| v Value64, stack_64, locals_64, u64, u64, |v| v, |v| v - Value32, stack_32, locals_32, u32, i32, |v| v as u32, |v: u32| v as i32 - Value64, stack_64, locals_64, u64, i64, |v| v as u64, |v| v as i64 + Value32, stack_32, locals_32, u32, i32, |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: u32| i32::from_ne_bytes(v.to_ne_bytes()) + Value64, stack_64, locals_64, u64, i64, |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: u64| i64::from_ne_bytes(v.to_ne_bytes()) Value32, stack_32, locals_32, u32, f32, f32::to_bits, f32::from_bits Value64, stack_64, locals_64, u64, f64, f64::to_bits, f64::from_bits ValueRef, stack_ref, locals_ref, ValueRef, ValueRef, |v| v, |v| v diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 9cb6c0a..b44a15e 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -75,7 +75,7 @@ extern crate alloc; // log for logging (optional). #[cfg(feature = "logging")] -#[allow(clippy::single_component_path_imports)] +#[expect(clippy::single_component_path_imports)] use log; // noop fallback if logging is disabled. diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs index e32a2f3..790c313 100644 --- a/crates/tinywasm/src/reference.rs +++ b/crates/tinywasm/src/reference.rs @@ -1,8 +1,7 @@ use core::ffi::CStr; -use alloc::ffi::CString; use alloc::string::{String, ToString}; -use alloc::vec::Vec; +use alloc::{ffi::CString, format, vec::Vec}; use crate::{MemoryInstance, Result}; @@ -92,19 +91,19 @@ pub trait MemoryStringExt: MemoryRefLoad { /// Load a C-style string from memory fn load_cstr(&self, offset: usize, len: usize) -> Result<&CStr> { let bytes = self.load(offset, len)?; - CStr::from_bytes_with_nul(bytes).map_err(|_| crate::Error::Other("Invalid C-style string".to_string())) + CStr::from_bytes_with_nul(bytes).map_err(|e| crate::Error::Other(format!("Invalid C-style string: {e}"))) } /// Load a C-style string from memory, stopping at the first nul byte fn load_cstr_until_nul(&self, offset: usize, max_len: usize) -> Result<&CStr> { let bytes = self.load(offset, max_len)?; - CStr::from_bytes_until_nul(bytes).map_err(|_| crate::Error::Other("Invalid C-style string".to_string())) + CStr::from_bytes_until_nul(bytes).map_err(|e| crate::Error::Other(format!("Invalid C-style string: {e}"))) } /// Load a UTF-8 string from memory fn load_string(&self, offset: usize, len: usize) -> Result { let bytes = self.load(offset, len)?; - String::from_utf8(bytes.to_vec()).map_err(|_| crate::Error::Other("Invalid UTF-8 string".to_string())) + String::from_utf8(bytes.to_vec()).map_err(|e| crate::Error::Other(format!("Invalid UTF-8 string: {e}"))) } /// Load a C-style string from memory diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index d53654e..634fdfe 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -288,7 +288,9 @@ impl Store { })?; self.data.globals[addr as usize].value.get().unwrap_ref() } - _ => return Err(Error::UnsupportedFeature(format!("const expression other than ref: {item:?}"))), + ElementItem::Expr(item) => { + return Err(Error::UnsupportedFeature(format!("const expression other than ref: {item:?}"))); + } }; Ok(res) @@ -418,10 +420,10 @@ impl Store { /// Evaluate a constant expression that's either a i32 or a i64 as a global or a const instruction pub(crate) fn eval_size_const(&self, const_instr: tinywasm_types::ConstInstruction) -> Result { Ok(match const_instr { - ConstInstruction::I32Const(i) => i as i64, + ConstInstruction::I32Const(i) => i64::from(i), ConstInstruction::I64Const(i) => i, ConstInstruction::GlobalGet(addr) => match self.data.globals[addr as usize].value.get() { - TinyWasmValue::Value32(i) => i as i64, + TinyWasmValue::Value32(i) => i64::from(i), TinyWasmValue::Value64(i) => i as i64, o => return Err(Error::Other(format!("expected i32 or i64, got {o:?}"))), }, diff --git a/crates/tinywasm/src/store/table.rs b/crates/tinywasm/src/store/table.rs index 6192119..bc4429d 100644 --- a/crates/tinywasm/src/store/table.rs +++ b/crates/tinywasm/src/store/table.rs @@ -159,8 +159,8 @@ pub(crate) enum TableElement { impl From> for TableElement { fn from(addr: Option) -> Self { match addr { - None => TableElement::Uninitialized, - Some(addr) => TableElement::Initialized(addr), + None => Self::Uninitialized, + Some(addr) => Self::Initialized(addr), } } } @@ -168,15 +168,15 @@ impl From> for TableElement { impl TableElement { pub(crate) fn addr(&self) -> Option { match self { - TableElement::Uninitialized => None, - TableElement::Initialized(addr) => Some(*addr), + Self::Uninitialized => None, + Self::Initialized(addr) => Some(*addr), } } pub(crate) fn map(self, f: impl FnOnce(Addr) -> Addr) -> Self { match self { - TableElement::Uninitialized => TableElement::Uninitialized, - TableElement::Initialized(addr) => TableElement::Initialized(f(addr)), + Self::Uninitialized => Self::Uninitialized, + Self::Initialized(addr) => Self::Initialized(f(addr)), } } } diff --git a/crates/tinywasm/tests/testsuite/mod.rs b/crates/tinywasm/tests/testsuite/mod.rs index c1ba46e..140b063 100644 --- a/crates/tinywasm/tests/testsuite/mod.rs +++ b/crates/tinywasm/tests/testsuite/mod.rs @@ -41,7 +41,7 @@ impl TestSuite { pub fn print_errors(&self) { for (group_name, group) in &self.0 { let tests = &group.tests; - for (test_name, test) in tests.iter() { + for (test_name, test) in tests { if let Err(e) = &test.result { eprintln!( "{} {} failed: {:?}", diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index 5e8558a..59013ad 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -74,7 +74,7 @@ pub fn encode_quote_wat(module: QuoteWat) -> (Option, Vec) { }; (module.id.map(|id| id.name().to_string()), wat.encode().expect("failed to encode module")) } - _ => unimplemented!("Not supported"), + QuoteWat::QuoteComponent(..) => unimplemented!("components are not supported"), } } @@ -96,7 +96,7 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result WasmValue::F32(f32::from_bits(f.bits)), F64(f) => WasmValue::F64(f64::from_bits(f.bits)), @@ -113,7 +113,7 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result bail!("unsupported arg type: refnull: {:?}", t), }, - v => bail!("unsupported arg type: {:?}", v), + RefHost(v) => bail!("unsupported arg type: RefHost"), }) } diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index fda8a86..b986c2a 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -7,6 +7,8 @@ license.workspace=true authors.workspace=true repository.workspace=true rust-version.workspace=true +keywords.workspace=true +categories.workspace=true [dependencies] log={workspace=true, optional=true} diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs index b190d43..7d52049 100644 --- a/crates/types/src/archive.rs +++ b/crates/types/src/archive.rs @@ -34,10 +34,10 @@ pub enum TwasmError { impl Display for TwasmError { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { - TwasmError::InvalidMagic => write!(f, "Invalid twasm: invalid magic number"), - TwasmError::InvalidVersion => write!(f, "Invalid twasm: invalid version"), - TwasmError::InvalidPadding => write!(f, "Invalid twasm: invalid padding"), - TwasmError::InvalidArchive(e) => write!(f, "Invalid twasm: {e}"), + Self::InvalidMagic => write!(f, "Invalid twasm: invalid magic number"), + Self::InvalidVersion => write!(f, "Invalid twasm: invalid version"), + Self::InvalidPadding => write!(f, "Invalid twasm: invalid padding"), + Self::InvalidArchive(e) => write!(f, "Invalid twasm: {e}"), } } } @@ -49,7 +49,7 @@ impl core::error::Error for TwasmError {} impl TinyWasmModule { /// Creates a `TinyWasmModule` from a slice of bytes. - pub fn from_twasm(wasm: &[u8]) -> Result { + pub fn from_twasm(wasm: &[u8]) -> Result { let len = validate_magic(wasm)?; postcard::from_bytes(&wasm[len..]).map_err(TwasmError::InvalidArchive) diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 9db5ed5..aa57dfa 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -2,7 +2,7 @@ use super::{FuncAddr, GlobalAddr, LabelAddr, LocalAddr, TableAddr, TypeAddr, Val use crate::{ConstIdx, DataAddr, ElemAddr, ExternAddr, MemAddr}; /// Represents a memory immediate in a WebAssembly memory instruction. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct MemoryArg([u8; 12]); diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 470c631..c34b705 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -119,7 +119,7 @@ pub struct TinyWasmModule { /// A WebAssembly External Kind. /// /// See -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub enum ExternalKind { /// A WebAssembly Function. @@ -191,14 +191,14 @@ impl ExternVal { /// The type of a WebAssembly Function. /// /// See -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct FuncType { pub params: Box<[ValType]>, pub results: Box<[ValType]>, } -#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct ValueCounts { pub c32: u32, @@ -207,7 +207,7 @@ pub struct ValueCounts { pub cref: u32, } -#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct ValueCountsSmall { pub c32: u16, @@ -218,7 +218,7 @@ pub struct ValueCountsSmall { impl<'a, T: IntoIterator> From for ValueCounts { fn from(types: T) -> Self { - let mut counts = ValueCounts::default(); + let mut counts = Self::default(); for ty in types { match ty { ValType::I32 | ValType::F32 => counts.c32 += 1, @@ -233,7 +233,7 @@ impl<'a, T: IntoIterator> From for ValueCounts { impl<'a, T: IntoIterator> From for ValueCountsSmall { fn from(types: T) -> Self { - let mut counts = ValueCountsSmall::default(); + let mut counts = Self::default(); for ty in types { match ty { ValType::I32 | ValType::F32 => counts.c32 += 1, @@ -256,14 +256,14 @@ pub struct WasmFunction { pub ty: FuncType, } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct WasmFunctionData { pub v128_constants: Box<[i128]>, } /// A WebAssembly Module Export -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct Export { /// The name of the export. @@ -281,14 +281,14 @@ pub struct Global { pub init: ConstInstruction, } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct GlobalType { pub mutable: bool, pub ty: ValType, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct TableType { pub element_type: ValType, @@ -307,7 +307,7 @@ impl TableType { } /// Represents a memory's type. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct MemoryType { arch: MemoryArch, @@ -353,7 +353,7 @@ pub enum MemoryArch { I64, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct Import { pub module: Box, @@ -361,7 +361,7 @@ pub struct Import { pub kind: ImportKind, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub enum ImportKind { Function(TypeAddr), diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index b68836b..22bb4eb 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -23,14 +23,14 @@ pub enum WasmValue { RefFunc(FuncRef), } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct ExternRef(Option); -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct FuncRef(Option); impl Debug for ExternRef { - fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self.0 { Some(addr) => write!(f, "extern({addr:?})"), None => write!(f, "extern(null)"), @@ -39,7 +39,7 @@ impl Debug for ExternRef { } impl Debug for FuncRef { - fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self.0 { Some(addr) => write!(f, "func({addr:?})"), None => write!(f, "func(null)"), @@ -114,7 +114,7 @@ impl WasmValue { Self::F64(i) => ConstInstruction::F64Const(*i), Self::V128(i) => ConstInstruction::V128Const(*i), Self::RefFunc(i) => ConstInstruction::RefFunc(i.addr()), - _ => unimplemented!("no const_instr for {:?}", self), + Self::RefExtern(_) => unimplemented!("no const_instr for RefExtern"), } } @@ -220,15 +220,15 @@ impl WasmValue { fn cold() {} impl Debug for WasmValue { - fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - WasmValue::I32(i) => write!(f, "i32({i})"), - WasmValue::I64(i) => write!(f, "i64({i})"), - WasmValue::F32(i) => write!(f, "f32({i})"), - WasmValue::F64(i) => write!(f, "f64({i})"), - WasmValue::V128(i) => write!(f, "v128({i:?})"), - WasmValue::RefExtern(i) => write!(f, "ref({i:?})"), - WasmValue::RefFunc(i) => write!(f, "func({i:?})"), + Self::I32(i) => write!(f, "i32({i})"), + Self::I64(i) => write!(f, "i64({i})"), + Self::F32(i) => write!(f, "f32({i})"), + Self::F64(i) => write!(f, "f64({i})"), + Self::V128(i) => write!(f, "v128({i:?})"), + Self::RefExtern(i) => write!(f, "ref({i:?})"), + Self::RefFunc(i) => write!(f, "func({i:?})"), } } } @@ -278,7 +278,7 @@ impl ValType { #[doc(hidden)] #[inline] pub fn is_simd(&self) -> bool { - matches!(self, ValType::V128) + matches!(self, Self::V128) } }