summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock100
-rw-r--r--Cargo.toml2
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs877
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs2
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs14
-rw-r--r--crates/tinywasm/src/interpreter/value128.rs2212
-rw-r--r--crates/tinywasm/src/store/memory.rs2
-rw-r--r--crates/tinywasm/tests/generated/wasm-simd.csv2
8 files changed, 2683 insertions, 528 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3bbbe56..2271ac2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -28,15 +28,15 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstyle"
-version = "1.0.13"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "argh"
-version = "0.1.14"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f384d96bfd3c0b3c41f24dae69ee9602c091d64fc432225cf5295b5abbe0036"
+checksum = "211818e820cda9ca6f167a64a5c808837366a6dfd807157c64c1304c486cd033"
dependencies = [
"argh_derive",
"argh_shared",
@@ -44,9 +44,9 @@ dependencies = [
[[package]]
name = "argh_derive"
-version = "0.1.14"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "938e5f66269c1f168035e29ed3fb437b084e476465e9314a0328f4005d7be599"
+checksum = "c442a9d18cef5dde467405d27d461d080d68972d6d0dfd0408265b6749ec427d"
dependencies = [
"argh_shared",
"proc-macro2",
@@ -56,9 +56,9 @@ dependencies = [
[[package]]
name = "argh_shared"
-version = "0.1.14"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5127f8a5bc1cfb0faf1f6248491452b8a5b6901068d8da2d47cbb285986ae683"
+checksum = "e5ade012bac4db278517a0132c8c10c6427025868dca16c801087c28d5a411f1"
dependencies = [
"serde",
]
@@ -71,15 +71,15 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
-version = "2.10.0"
+version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "bumpalo"
-version = "3.19.1"
+version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]]
name = "cast"
@@ -89,9 +89,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
-version = "1.2.55"
+version = "1.2.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
+checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -132,18 +132,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.57"
+version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
+checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.57"
+version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstyle",
"clap_lex",
@@ -151,9 +151,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.7"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "cobs"
@@ -380,9 +380,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libc"
-version = "0.2.180"
+version = "0.2.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "libm"
@@ -413,9 +413,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.21.3"
+version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "oorandom"
@@ -425,9 +425,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "owo-colors"
-version = "4.2.3"
+version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
+checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d"
[[package]]
name = "page_size"
@@ -472,9 +472,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.44"
+version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
@@ -524,9 +524,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.9"
+version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "same-file"
@@ -594,9 +594,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
-version = "2.0.114"
+version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
@@ -704,9 +704,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
-version = "1.0.22"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-width"
@@ -726,9 +726,9 @@ dependencies = [
[[package]]
name = "wasm-encoder"
-version = "0.245.0"
+version = "0.245.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95d568e113f706ee7a7df9b33547bb80721f55abffc79b3dc4d09c368690e662"
+checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c"
dependencies = [
"leb128fmt",
"wasmparser",
@@ -736,9 +736,9 @@ dependencies = [
[[package]]
name = "wasm-testsuite"
-version = "0.6.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cad9eeaabcdbbe221f3fd9a90eabab05362d8f444dc09bc0930a341ea9779e9e"
+checksum = "921e4ecec67cf5017034abf411b7458c9f8ded6221d2af804994e8b282f3ff92"
dependencies = [
"include_dir",
"wast",
@@ -746,9 +746,9 @@ dependencies = [
[[package]]
name = "wasmparser"
-version = "0.245.0"
+version = "0.245.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48a767a48974f0c8b66f211b96e01aa77feed58b8ccce4e7f0cff0ae55b174d4"
+checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e"
dependencies = [
"bitflags",
"indexmap",
@@ -757,9 +757,9 @@ dependencies = [
[[package]]
name = "wast"
-version = "245.0.0"
+version = "245.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75ffc7471e16a6f3c7a3c3a230314915b5dcd158e5ef13ccda2f43358a9df00c"
+checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf"
dependencies = [
"bumpalo",
"leb128fmt",
@@ -770,9 +770,9 @@ dependencies = [
[[package]]
name = "wat"
-version = "1.245.0"
+version = "1.245.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6bcac6f915e2a84a4c0d9df9d41ad7518d99cda13f3bb83e3b8c22bf8726ab6"
+checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be"
dependencies = [
"wast",
]
@@ -825,18 +825,18 @@ dependencies = [
[[package]]
name = "zerocopy"
-version = "0.8.39"
+version = "0.8.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a"
+checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.39"
+version = "0.8.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
+checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89"
dependencies = [
"proc-macro2",
"quote",
@@ -845,6 +845,6 @@ dependencies = [
[[package]]
name = "zmij"
-version = "1.0.19"
+version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/Cargo.toml b/Cargo.toml
index 1563d6c..f47f1f4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ pretty_env_logger="0.5"
criterion={version="0.8", default-features=false, features=["cargo_bench_support", "rayon"]}
wasm-testsuite={version="0.6"}
indexmap="2.13"
-owo-colors={version="4.2"}
+owo-colors={version="4.3"}
serde_json={version="1.0"}
serde={version="1.0", features=["derive"]}
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index c186c01..08089f4 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -44,6 +44,36 @@ impl<'store, 'stack> Executor<'store, 'stack> {
fn exec_next(&mut self) -> ControlFlow<Option<Error>> {
use tinywasm_types::Instruction::*;
+ macro_rules! stack_op {
+ (simd_unary $method:ident) => {
+ self.stack.values.unary_same::<Value128>(|v| Ok(v.$method())).to_cf()?
+ };
+ (simd_binary $method:ident) => {
+ self.stack.values.binary_same::<Value128>(|a, b| Ok(a.$method(b))).to_cf()?
+ };
+ (unary $ty:ty, |$v:ident| $expr:expr) => {
+ self.stack.values.unary_same::<$ty>(|$v| Ok($expr)).to_cf()?
+ };
+ (binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
+ self.stack.values.binary_same::<$ty>(|$a, $b| Ok($expr)).to_cf()?
+ };
+ (binary_try $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
+ self.stack.values.binary_same::<$ty>(|$a, $b| $expr).to_cf()?
+ };
+ (unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {
+ self.stack.values.unary::<$from, $to>(|$v| Ok($expr)).to_cf()?
+ };
+ (binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => {
+ self.stack.values.binary::<$from, $to>(|$a, $b| Ok($expr)).to_cf()?
+ };
+ (binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
+ self.stack.values.binary_diff::<$a, $b, $b>(|$lhs, $rhs| Ok($expr)).to_cf()?
+ };
+ (binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
+ self.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
+ };
+ }
+
#[rustfmt::skip]
match self.cf.fetch_instr() {
Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
@@ -106,6 +136,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
I64Const(val) => self.exec_const(*val),
F32Const(val) => self.exec_const(*val),
F64Const(val) => self.exec_const(*val),
+
+ // Reference types
RefFunc(func_idx) => self.exec_const::<ValueRef>(Some(*func_idx)),
RefNull(_) => self.exec_const::<ValueRef>(None),
RefIsNull => self.exec_ref_is_null(),
@@ -119,8 +151,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx).to_cf()?,
DataDrop(data_index) => self.exec_data_drop(*data_index),
ElemDrop(elem_index) => self.exec_elem_drop(*elem_index),
+
+ // Table instructions
+ TableGet(table_idx) => self.exec_table_get(*table_idx).to_cf()?,
+ TableSet(table_idx) => self.exec_table_set(*table_idx).to_cf()?,
+ TableSize(table_idx) => self.exec_table_size(*table_idx).to_cf()?,
+ TableInit(elem_idx, table_idx) => self.exec_table_init(*elem_idx, *table_idx).to_cf()?,
+ TableGrow(table_idx) => self.exec_table_grow(*table_idx).to_cf()?,
+ TableFill(table_idx) => self.exec_table_fill(*table_idx).to_cf()?,
TableCopy { from, to } => self.exec_table_copy(*from, *to).to_cf()?,
+ // Core memory load/store operations
I32Store(m) => self.exec_mem_store::<i32, i32, 4>(m.mem_addr(), m.offset(), |v| v)?,
I64Store(m) => self.exec_mem_store::<i64, i64, 8>(m.mem_addr(), m.offset(), |v| v)?,
F32Store(m) => self.exec_mem_store::<f32, f32, 4>(m.mem_addr(), m.offset(), |v| v)?,
@@ -146,138 +187,140 @@ impl<'store, 'stack> Executor<'store, 'stack> {
I64Load32S(m) => self.exec_mem_load::<i32, 4, _>(m.mem_addr(), m.offset(), i64::from)?,
I64Load32U(m) => self.exec_mem_load::<u32, 4, _>(m.mem_addr(), m.offset(), i64::from)?,
- I64Eqz => self.stack.values.replace_top::<i64, _>(|v| Ok(i32::from(v == 0))).to_cf()?,
- I32Eqz => self.stack.values.replace_top_same::<i32>(|v| Ok(i32::from(v == 0))).to_cf()?,
- I32Eq => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a == b))).to_cf()?,
- I64Eq => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a == b))).to_cf()?,
- F32Eq => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a == b))).to_cf()?,
- F64Eq => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a == b))).to_cf()?,
+ I64Eqz => stack_op!(unary i64 => i32, |v| i32::from(v == 0)),
+ I32Eqz => stack_op!(unary i32, |v| i32::from(v == 0)),
+ I32Eq => stack_op!(binary i32, |a, b| i32::from(a == b)),
+ I64Eq => stack_op!(binary i64 => i32, |a, b| i32::from(a == b)),
+ F32Eq => stack_op!(binary f32 => i32, |a, b| i32::from(a == b)),
+ F64Eq => stack_op!(binary f64 => i32, |a, b| i32::from(a == b)),
- I32Ne => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a != b))).to_cf()?,
- I64Ne => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a != b))).to_cf()?,
- F32Ne => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a != b))).to_cf()?,
- F64Ne => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a != b))).to_cf()?,
+ I32Ne => stack_op!(binary i32, |a, b| i32::from(a != b)),
+ I64Ne => stack_op!(binary i64 => i32, |a, b| i32::from(a != b)),
+ F32Ne => stack_op!(binary f32 => i32, |a, b| i32::from(a != b)),
+ F64Ne => stack_op!(binary f64 => i32, |a, b| i32::from(a != b)),
- I32LtS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- I64LtS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- I32LtU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- I64LtU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- F32Lt => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- F64Lt => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
+ I32LtS => stack_op!(binary i32, |a, b| i32::from(a < b)),
+ I64LtS => stack_op!(binary i64 => i32, |a, b| i32::from(a < b)),
+ I32LtU => stack_op!(binary u32 => i32, |a, b| i32::from(a < b)),
+ I64LtU => stack_op!(binary u64 => i32, |a, b| i32::from(a < b)),
+ F32Lt => stack_op!(binary f32 => i32, |a, b| i32::from(a < b)),
+ F64Lt => stack_op!(binary f64 => i32, |a, b| i32::from(a < b)),
- I32LeS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- I64LeS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- I32LeU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- I64LeU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- F32Le => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- F64Le => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
+ I32LeS => stack_op!(binary i32, |a, b| i32::from(a <= b)),
+ I64LeS => stack_op!(binary i64 => i32, |a, b| i32::from(a <= b)),
+ I32LeU => stack_op!(binary u32 => i32, |a, b| i32::from(a <= b)),
+ I64LeU => stack_op!(binary u64 => i32, |a, b| i32::from(a <= b)),
+ F32Le => stack_op!(binary f32 => i32, |a, b| i32::from(a <= b)),
+ F64Le => stack_op!(binary f64 => i32, |a, b| i32::from(a <= b)),
- I32GeS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- I64GeS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- I32GeU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- I64GeU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- F32Ge => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- F64Ge => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
+ I32GeS => stack_op!(binary i32, |a, b| i32::from(a >= b)),
+ I64GeS => stack_op!(binary i64 => i32, |a, b| i32::from(a >= b)),
+ I32GeU => stack_op!(binary u32 => i32, |a, b| i32::from(a >= b)),
+ I64GeU => stack_op!(binary u64 => i32, |a, b| i32::from(a >= b)),
+ F32Ge => stack_op!(binary f32 => i32, |a, b| i32::from(a >= b)),
+ F64Ge => stack_op!(binary f64 => i32, |a, b| i32::from(a >= b)),
- I32GtS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- I64GtS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- I32GtU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- I64GtU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- F32Gt => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- F64Gt => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
+ I32GtS => stack_op!(binary i32, |a, b| i32::from(a > b)),
+ I64GtS => stack_op!(binary i64 => i32, |a, b| i32::from(a > b)),
+ I32GtU => stack_op!(binary u32 => i32, |a, b| i32::from(a > b)),
+ I64GtU => stack_op!(binary u64 => i32, |a, b| i32::from(a > b)),
+ F32Gt => stack_op!(binary f32 => i32, |a, b| i32::from(a > b)),
+ F64Gt => stack_op!(binary f64 => i32, |a, b| i32::from(a > b)),
- I32Add => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_add(b))).to_cf()?,
- I64Add => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_add(b))).to_cf()?,
- F32Add => self.stack.values.calculate_same::<f32>(|a, b| Ok(a + b)).to_cf()?,
- F64Add => self.stack.values.calculate_same::<f64>(|a, b| Ok(a + b)).to_cf()?,
+ I32Add => stack_op!(binary i32, |a, b| a.wrapping_add(b)),
+ I64Add => stack_op!(binary i64, |a, b| a.wrapping_add(b)),
+ F32Add => stack_op!(binary f32, |a, b| a + b),
+ F64Add => stack_op!(binary f64, |a, b| a + b),
- I32Sub => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_sub(b))).to_cf()?,
- I64Sub => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_sub(b))).to_cf()?,
- F32Sub => self.stack.values.calculate_same::<f32>(|a, b| Ok(a - b)).to_cf()?,
- F64Sub => self.stack.values.calculate_same::<f64>(|a, b| Ok(a - b)).to_cf()?,
+ I32Sub => stack_op!(binary i32, |a, b| a.wrapping_sub(b)),
+ I64Sub => stack_op!(binary i64, |a, b| a.wrapping_sub(b)),
+ F32Sub => stack_op!(binary f32, |a, b| a - b),
+ F64Sub => stack_op!(binary f64, |a, b| a - b),
- F32Div => self.stack.values.calculate_same::<f32>(|a, b| Ok(a / b)).to_cf()?,
- F64Div => self.stack.values.calculate_same::<f64>(|a, b| Ok(a / b)).to_cf()?,
+ F32Div => stack_op!(binary f32, |a, b| a / b),
+ F64Div => stack_op!(binary f64, |a, b| a / b),
- I32Mul => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_mul(b))).to_cf()?,
- I64Mul => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_mul(b))).to_cf()?,
- F32Mul => self.stack.values.calculate_same::<f32>(|a, b| Ok(a * b)).to_cf()?,
- F64Mul => self.stack.values.calculate_same::<f64>(|a, b| Ok(a * b)).to_cf()?,
+ I32Mul => stack_op!(binary i32, |a, b| a.wrapping_mul(b)),
+ I64Mul => stack_op!(binary i64, |a, b| a.wrapping_mul(b)),
+ F32Mul => stack_op!(binary f32, |a, b| a * b),
+ F64Mul => stack_op!(binary f64, |a, b| a * b),
- I32DivS => self.stack.values.calculate_same::<i32>(|a, b| a.wasm_checked_div(b)).to_cf()?,
- I64DivS => self.stack.values.calculate_same::<i64>(|a, b| a.wasm_checked_div(b)).to_cf()?,
- I32DivU => self.stack.values.calculate_same::<u32>(|a, b| a.checked_div(b).ok_or_else(trap_0)).to_cf()?,
- I64DivU => self.stack.values.calculate_same::<u64>(|a, b| a.checked_div(b).ok_or_else(trap_0)).to_cf()?,
- I32RemS => self.stack.values.calculate_same::<i32>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I64RemS => self.stack.values.calculate_same::<i64>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I32RemU => self.stack.values.calculate_same::<u32>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I64RemU => self.stack.values.calculate_same::<u64>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
+ I32DivS => stack_op!(binary_try i32, |a, b| a.wasm_checked_div(b)),
+ I64DivS => stack_op!(binary_try i64, |a, b| a.wasm_checked_div(b)),
+ I32DivU => stack_op!(binary_try u32, |a, b| a.checked_div(b).ok_or_else(trap_0)),
+ I64DivU => stack_op!(binary_try u64, |a, b| a.checked_div(b).ok_or_else(trap_0)),
+ I32RemS => stack_op!(binary_try i32, |a, b| a.checked_wrapping_rem(b)),
+ I64RemS => stack_op!(binary_try i64, |a, b| a.checked_wrapping_rem(b)),
+ I32RemU => stack_op!(binary_try u32, |a, b| a.checked_wrapping_rem(b)),
+ I64RemU => stack_op!(binary_try u64, |a, b| a.checked_wrapping_rem(b)),
- I32And => self.stack.values.calculate_same::<i32>(|a, b| Ok(a & b)).to_cf()?,
- I64And => self.stack.values.calculate_same::<i64>(|a, b| Ok(a & b)).to_cf()?,
- I32Or => self.stack.values.calculate_same::<i32>(|a, b| Ok(a | b)).to_cf()?,
- I64Or => self.stack.values.calculate_same::<i64>(|a, b| Ok(a | b)).to_cf()?,
- I32Xor => self.stack.values.calculate_same::<i32>(|a, b| Ok(a ^ b)).to_cf()?,
- I64Xor => self.stack.values.calculate_same::<i64>(|a, b| Ok(a ^ b)).to_cf()?,
- I32Shl => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_shl(b))).to_cf()?,
- I64Shl => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_shl(b))).to_cf()?,
- I32ShrS => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I64ShrS => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I32ShrU => self.stack.values.calculate_same::<u32>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I64ShrU => self.stack.values.calculate_same::<u64>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I32Rotl => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_rotl(b))).to_cf()?,
- I64Rotl => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_rotl(b))).to_cf()?,
- I32Rotr => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_rotr(b))).to_cf()?,
- I64Rotr => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_rotr(b))).to_cf()?,
+ I32And => stack_op!(binary i32, |a, b| a & b),
+ I64And => stack_op!(binary i64, |a, b| a & b),
+ I32Or => stack_op!(binary i32, |a, b| a | b),
+ I64Or => stack_op!(binary i64, |a, b| a | b),
+ I32Xor => stack_op!(binary i32, |a, b| a ^ b),
+ I64Xor => stack_op!(binary i64, |a, b| a ^ b),
+ I32Shl => stack_op!(binary i32, |a, b| a.wasm_shl(b)),
+ I64Shl => stack_op!(binary i64, |a, b| a.wasm_shl(b)),
+ I32ShrS => stack_op!(binary i32, |a, b| a.wasm_shr(b)),
+ I64ShrS => stack_op!(binary i64, |a, b| a.wasm_shr(b)),
+ I32ShrU => stack_op!(binary u32, |a, b| a.wasm_shr(b)),
+ I64ShrU => stack_op!(binary u64, |a, b| a.wasm_shr(b)),
+ I32Rotl => stack_op!(binary i32, |a, b| a.wasm_rotl(b)),
+ I64Rotl => stack_op!(binary i64, |a, b| a.wasm_rotl(b)),
+ I32Rotr => stack_op!(binary i32, |a, b| a.wasm_rotr(b)),
+ I64Rotr => stack_op!(binary i64, |a, b| a.wasm_rotr(b)),
- I32Clz => self.stack.values.replace_top_same::<i32>(|v| Ok(v.leading_zeros() as i32)).to_cf()?,
- I64Clz => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v.leading_zeros()))).to_cf()?,
- I32Ctz => self.stack.values.replace_top_same::<i32>(|v| Ok(v.trailing_zeros() as i32)).to_cf()?,
- I64Ctz => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v.trailing_zeros()))).to_cf()?,
- I32Popcnt => self.stack.values.replace_top_same::<i32>(|v| Ok(v.count_ones() as i32)).to_cf()?,
- I64Popcnt => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v.count_ones()))).to_cf()?,
+ I32Clz => stack_op!(unary i32, |v| v.leading_zeros() as i32),
+ I64Clz => stack_op!(unary i64, |v| i64::from(v.leading_zeros())),
+ I32Ctz => stack_op!(unary i32, |v| v.trailing_zeros() as i32),
+ I64Ctz => stack_op!(unary i64, |v| i64::from(v.trailing_zeros())),
+ I32Popcnt => stack_op!(unary i32, |v| v.count_ones() as i32),
+ I64Popcnt => stack_op!(unary i64, |v| i64::from(v.count_ones())),
- F32ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as f32)).to_cf()?,
- F32ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f32)).to_cf()?,
- F64ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(f64::from(v))).to_cf()?,
- F64ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f64)).to_cf()?,
- F32ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as f32)).to_cf()?,
- F32ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f32)).to_cf()?,
- F64ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(f64::from(v))).to_cf()?,
- F64ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f64)).to_cf()?,
+ // Numeric conversion operations
+ F32ConvertI32S => stack_op!(unary i32 => f32, |v| v as f32),
+ F32ConvertI64S => stack_op!(unary i64 => f32, |v| v as f32),
+ F64ConvertI32S => stack_op!(unary i32 => f64, |v| f64::from(v)),
+ F64ConvertI64S => stack_op!(unary i64 => f64, |v| v as f64),
+ F32ConvertI32U => stack_op!(unary u32 => f32, |v| v as f32),
+ F32ConvertI64U => stack_op!(unary u64 => f32, |v| v as f32),
+ F64ConvertI32U => stack_op!(unary u32 => f64, |v| f64::from(v)),
+ F64ConvertI64U => stack_op!(unary u64 => f64, |v| v as f64),
- I32Extend8S => self.stack.values.replace_top_same::<i32>(|v| Ok(i32::from(v as i8))).to_cf()?,
- I32Extend16S => self.stack.values.replace_top_same::<i32>(|v| Ok(i32::from(v as i16))).to_cf()?,
- I64Extend8S => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v as i8))).to_cf()?,
- I64Extend16S => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v as i16))).to_cf()?,
- I64Extend32S => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v as i32))).to_cf()?,
- I64ExtendI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(i64::from(v))).to_cf()?,
- I64ExtendI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(i64::from(v))).to_cf()?,
- I32WrapI64 => self.stack.values.replace_top::<i64, _>(|v| Ok(v as i32)).to_cf()?,
+ // Sign-extension operations
+ I32Extend8S => stack_op!(unary i32, |v| i32::from(v as i8)),
+ I32Extend16S => stack_op!(unary i32, |v| i32::from(v as i16)),
+ I64Extend8S => stack_op!(unary i64, |v| i64::from(v as i8)),
+ I64Extend16S => stack_op!(unary i64, |v| i64::from(v as i16)),
+ I64Extend32S => stack_op!(unary i64, |v| i64::from(v as i32)),
+ I64ExtendI32U => stack_op!(unary u32 => i64, |v| i64::from(v)),
+ I64ExtendI32S => stack_op!(unary i32 => i64, |v| i64::from(v)),
+ I32WrapI64 => stack_op!(unary i64 => i32, |v| v as i32),
- F32DemoteF64 => self.stack.values.replace_top::<f64, _>(|v| Ok(v as f32)).to_cf()?,
- F64PromoteF32 => self.stack.values.replace_top::<f32, _>(|v| Ok(f64::from(v))).to_cf()?,
+ F32DemoteF64 => stack_op!(unary f64 => f32, |v| v as f32),
+ F64PromoteF32 => stack_op!(unary f32 => f64, |v| f64::from(v)),
- F32Abs => self.stack.values.replace_top_same::<f32>(|v| Ok(v.abs())).to_cf()?,
- F64Abs => self.stack.values.replace_top_same::<f64>(|v| Ok(v.abs())).to_cf()?,
- F32Neg => self.stack.values.replace_top_same::<f32>(|v| Ok(-v)).to_cf()?,
- F64Neg => self.stack.values.replace_top_same::<f64>(|v| Ok(-v)).to_cf()?,
- F32Ceil => self.stack.values.replace_top_same::<f32>(|v| Ok(v.ceil())).to_cf()?,
- F64Ceil => self.stack.values.replace_top_same::<f64>(|v| Ok(v.ceil())).to_cf()?,
- F32Floor => self.stack.values.replace_top_same::<f32>(|v| Ok(v.floor())).to_cf()?,
- F64Floor => self.stack.values.replace_top_same::<f64>(|v| Ok(v.floor())).to_cf()?,
- F32Trunc => self.stack.values.replace_top_same::<f32>(|v| Ok(v.trunc())).to_cf()?,
- F64Trunc => self.stack.values.replace_top_same::<f64>(|v| Ok(v.trunc())).to_cf()?,
- F32Nearest => self.stack.values.replace_top_same::<f32>(|v| Ok(v.tw_nearest())).to_cf()?,
- F64Nearest => self.stack.values.replace_top_same::<f64>(|v| Ok(v.tw_nearest())).to_cf()?,
- F32Sqrt => self.stack.values.replace_top_same::<f32>(|v| Ok(v.sqrt())).to_cf()?,
- F64Sqrt => self.stack.values.replace_top_same::<f64>(|v| Ok(v.sqrt())).to_cf()?,
- F32Min => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.tw_minimum(b))).to_cf()?,
- F64Min => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.tw_minimum(b))).to_cf()?,
- F32Max => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.tw_maximum(b))).to_cf()?,
- F64Max => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.tw_maximum(b))).to_cf()?,
- F32Copysign => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.copysign(b))).to_cf()?,
- F64Copysign => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.copysign(b))).to_cf()?,
+ F32Abs => stack_op!(unary f32, |v| v.abs()),
+ F64Abs => stack_op!(unary f64, |v| v.abs()),
+ F32Neg => stack_op!(unary f32, |v| -v),
+ F64Neg => stack_op!(unary f64, |v| -v),
+ F32Ceil => stack_op!(unary f32, |v| v.ceil()),
+ F64Ceil => stack_op!(unary f64, |v| v.ceil()),
+ F32Floor => stack_op!(unary f32, |v| v.floor()),
+ F64Floor => stack_op!(unary f64, |v| v.floor()),
+ F32Trunc => stack_op!(unary f32, |v| v.trunc()),
+ F64Trunc => stack_op!(unary f64, |v| v.trunc()),
+ F32Nearest => stack_op!(unary f32, |v| v.tw_nearest()),
+ F64Nearest => stack_op!(unary f64, |v| v.tw_nearest()),
+ F32Sqrt => stack_op!(unary f32, |v| v.sqrt()),
+ F64Sqrt => stack_op!(unary f64, |v| v.sqrt()),
+ F32Min => stack_op!(binary f32, |a, b| a.tw_minimum(b)),
+ F64Min => stack_op!(binary f64, |a, b| a.tw_minimum(b)),
+ F32Max => stack_op!(binary f32, |a, b| a.tw_maximum(b)),
+ F64Max => stack_op!(binary f64, |a, b| a.tw_maximum(b)),
+ F32Copysign => stack_op!(binary f32, |a, b| a.copysign(b)),
+ F64Copysign => stack_op!(binary f64, |a, b| a.copysign(b)),
I32TruncF32S => checked_conv_float!(f32, i32, self),
I32TruncF64S => checked_conv_float!(f64, i32, self),
@@ -288,408 +331,306 @@ impl<'store, 'stack> Executor<'store, 'stack> {
I64TruncF32U => checked_conv_float!(f32, u64, i64, self),
I64TruncF64U => checked_conv_float!(f64, u64, i64, self),
- TableGet(table_idx) => self.exec_table_get(*table_idx).to_cf()?,
- TableSet(table_idx) => self.exec_table_set(*table_idx).to_cf()?,
- TableSize(table_idx) => self.exec_table_size(*table_idx).to_cf()?,
- TableInit(elem_idx, table_idx) => self.exec_table_init(*elem_idx, *table_idx).to_cf()?,
- TableGrow(table_idx) => self.exec_table_grow(*table_idx).to_cf()?,
- TableFill(table_idx) => self.exec_table_fill(*table_idx).to_cf()?,
-
- I32TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i32)).to_cf()?,
- I32TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u32)).to_cf()?,
- I32TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i32)).to_cf()?,
- I32TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u32)).to_cf()?,
- I64TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i64)).to_cf()?,
- I64TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u64)).to_cf()?,
- I64TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i64)).to_cf()?,
- I64TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u64)).to_cf()?,
+ // Non-trapping float-to-int conversions
+ I32TruncSatF32S => stack_op!(unary f32 => i32, |v| v.trunc() as i32),
+ I32TruncSatF32U => stack_op!(unary f32 => u32, |v| v.trunc() as u32),
+ I32TruncSatF64S => stack_op!(unary f64 => i32, |v| v.trunc() as i32),
+ I32TruncSatF64U => stack_op!(unary f64 => u32, |v| v.trunc() as u32),
+ I64TruncSatF32S => stack_op!(unary f32 => i64, |v| v.trunc() as i64),
+ I64TruncSatF32U => stack_op!(unary f32 => u64, |v| v.trunc() as u64),
+ I64TruncSatF64S => stack_op!(unary f64 => i64, |v| v.trunc() as i64),
+ I64TruncSatF64U => stack_op!(unary f64 => u64, |v| v.trunc() as u64),
LocalCopy32(from, to) => self.exec_local_copy::<Value32>(*from, *to),
LocalCopy64(from, to) => self.exec_local_copy::<Value64>(*from, *to),
LocalCopy128(from, to) => self.exec_local_copy::<Value128>(*from, *to),
LocalCopyRef(from, to) => self.exec_local_copy::<ValueRef>(*from, *to),
- V128Not => self.stack.values.replace_top_same::<Value128>(|v| Ok(!v)).to_cf()?,
- V128And => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a & b)).to_cf()?,
- V128AndNot => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a & (!b))).to_cf()?,
- V128Or => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a | b)).to_cf()?,
- V128Xor => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a ^ b)).to_cf()?,
- V128Bitselect => self.stack.values.calculate_same_3::<Value128>(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?,
- V128AnyTrue => self.stack.values.replace_top::<Value128, i32>(|v| Ok((v.reduce_or() != 0) as i32)).to_cf()?,
- I8x16Swizzle => self.stack.values.calculate_same::<Value128>(|a, s| Ok(a.swizzle(s))).to_cf()?,
+ // SIMD extension
+ V128Not => stack_op!(unary Value128, |v| v.v128_not()),
+ V128And => stack_op!(binary Value128, |a, b| a.v128_and(b)),
+ V128AndNot => stack_op!(binary Value128, |a, b| a.v128_andnot(b)),
+ V128Or => stack_op!(binary Value128, |a, b| a.v128_or(b)),
+ V128Xor => stack_op!(binary Value128, |a, b| a.v128_xor(b)),
+ V128Bitselect => self.stack.values.ternary_same::<Value128>(|v1, v2, c| Ok(Value128::v128_bitselect(v1, v2, c))).to_cf()?,
+ V128AnyTrue => stack_op!(unary Value128 => i32, |v| v.v128_any_true() as i32),
+ I8x16Swizzle => stack_op!(binary Value128, |a, s| a.i8x16_swizzle(s)),
- V128Load(arg) => self.exec_mem_load::<Value128, 16, _>(arg.mem_addr(), arg.offset(), |v| v)?,
- V128Load8x8S(arg) => self.exec_mem_load::<i8, 1, Value128>(arg.mem_addr(), arg.offset(), Value128::extend_8_i8)?,
- V128Load8x8U(_arg) => self.exec_mem_load::<u8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_8_u8)?,
- V128Load16x4S(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_4_i16)?,
- V128Load16x4U(_arg) => self.exec_mem_load::<u16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_4_u16)?,
- V128Load32x2S(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_2_i32)?,
- V128Load32x2U(_arg) => self.exec_mem_load::<u32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_2_u32)?,
- V128Load8Splat(_arg) => self.exec_mem_load::<i8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i8)?,
- V128Load16Splat(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i16)?,
- V128Load32Splat(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i32)?,
- V128Load64Splat(_arg) => self.exec_mem_load::<i64, 8, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i64)?,
+ V128Load(arg) => self.exec_mem_load::<Value128, 16, _>(arg.mem_addr(), arg.offset(), |v| v)?,
+ V128Load8x8S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load8x8_s(v.to_le_bytes()))?,
+ V128Load8x8U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load8x8_u(v.to_le_bytes()))?,
+ V128Load16x4S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load16x4_s(v.to_le_bytes()))?,
+ V128Load16x4U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load16x4_u(v.to_le_bytes()))?,
+ V128Load32x2S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load32x2_s(v.to_le_bytes()))?,
+ V128Load32x2U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load32x2_u(v.to_le_bytes()))?,
+ V128Load8Splat(_arg) => self.exec_mem_load::<i8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i8)?,
+ V128Load16Splat(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i16)?,
+ V128Load32Splat(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i32)?,
+ V128Load64Splat(_arg) => self.exec_mem_load::<i64, 8, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i64)?,
- V128Store(arg) => self.exec_mem_store::<Value128, Value128, 16>(arg.mem_addr(), arg.offset(), |v| v)?,
+ V128Store(arg) => self.exec_mem_store::<Value128, Value128, 16>(arg.mem_addr(), arg.offset(), |v| v)?,
- V128Store8Lane(arg, lane) => self.exec_mem_store_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Store16Lane(arg, lane) => self.exec_mem_store_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Store32Lane(arg, lane) => self.exec_mem_store_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store8Lane(arg, lane) => self.exec_mem_store_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store16Lane(arg, lane) => self.exec_mem_store_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store32Lane(arg, lane) => self.exec_mem_store_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(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::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?,
- V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?,
+ V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?,
+ V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?,
- V128Const(arg) => self.exec_const::<Value128>( self.cf.data().v128_constants[*arg as usize].into()),
+ V128Const(arg) => self.exec_const::<Value128>(self.cf.data().v128_constants[*arg as usize].into()),
- I8x16ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i8(*lane) as i32)).to_cf()?,
- I8x16ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_u8(*lane) as i32)).to_cf()?,
- I16x8ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i16(*lane) as i32)).to_cf()?,
- I16x8ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_u16(*lane) as i32)).to_cf()?,
- I32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i32(*lane))).to_cf()?,
- I64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, i64>(|v| Ok(v.extract_lane_i64(*lane))).to_cf()?,
- F32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, f32>(|v| Ok(v.extract_lane_f32(*lane))).to_cf()?,
- F64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, f64>(|v| Ok(v.extract_lane_f64(*lane))).to_cf()?,
+ I8x16ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i8(*lane) as i32),
+ I8x16ExtractLaneU(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_u8(*lane) as i32),
+ I16x8ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i16(*lane) as i32),
+ I16x8ExtractLaneU(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_u16(*lane) as i32),
+ I32x4ExtractLane(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i32(*lane)),
+ I64x2ExtractLane(lane) => stack_op!(unary Value128 => i64, |v| v.extract_lane_i64(*lane)),
+ F32x4ExtractLane(lane) => stack_op!(unary Value128 => f32, |v| v.extract_lane_f32(*lane)),
+ F64x2ExtractLane(lane) => stack_op!(unary Value128 => f64, |v| v.extract_lane_f64(*lane)),
- V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
- // I8x16ReplaceLane(_lane) => unimplemented!(),
- // I16x8ReplaceLane(_lane) => unimplemented!(),
- // I32x4ReplaceLane(_lane) => unimplemented!(),
- // I64x2ReplaceLane(_lane) => unimplemented!(),
- // F32x4ReplaceLane(_lane) => unimplemented!(),
- // F64x2ReplaceLane(_lane) => unimplemented!(),
+ I8x16ReplaceLane(lane) => stack_op!(binary i32, Value128, |value, vec| vec.i8x16_replace_lane(*lane, value as i8)),
+ I16x8ReplaceLane(lane) => stack_op!(binary i32, Value128, |value, vec| vec.i16x8_replace_lane(*lane, value as i16)),
+ I32x4ReplaceLane(lane) => stack_op!(binary i32, Value128, |value, vec| vec.i32x4_replace_lane(*lane, value)),
+ I64x2ReplaceLane(lane) => stack_op!(binary i64, Value128, |value, vec| vec.i64x2_replace_lane(*lane, value)),
+ F32x4ReplaceLane(lane) => stack_op!(binary f32, Value128, |value, vec| vec.f32x4_replace_lane(*lane, value)),
+ F64x2ReplaceLane(lane) => stack_op!(binary f64, Value128, |value, vec| vec.f64x2_replace_lane(*lane, value)),
- I8x16Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i8(v as i8))).to_cf()?,
- I16x8Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i16(v as i16))).to_cf()?,
- I32x4Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i32(v))).to_cf()?,
- I64x2Splat => self.stack.values.replace_top::<i64, Value128>(|v| Ok(Value128::splat_i64(v))).to_cf()?,
- F32x4Splat => self.stack.values.replace_top::<f32, Value128>(|v| Ok(Value128::splat_f32(v))).to_cf()?,
- F64x2Splat => self.stack.values.replace_top::<f64, Value128>(|v| Ok(Value128::splat_f64(v))).to_cf()?,
+ I8x16Splat => stack_op!(unary i32 => Value128, |v| Value128::splat_i8(v as i8)),
+ I16x8Splat => stack_op!(unary i32 => Value128, |v| Value128::splat_i16(v as i16)),
+ I32x4Splat => stack_op!(unary i32 => Value128, |v| Value128::splat_i32(v)),
+ I64x2Splat => stack_op!(unary i64 => Value128, |v| Value128::splat_i64(v)),
+ F32x4Splat => stack_op!(unary f32 => Value128, |v| Value128::splat_f32(v)),
+ F64x2Splat => stack_op!(unary f64 => Value128, |v| Value128::splat_f64(v)),
- // I8x16Eq => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // I16x8Eq => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // I32x4Eq => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // I64x2Eq => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // F32x4Eq => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // F64x2Eq => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
+ I8x16Eq => stack_op!(binary Value128, |a, b| a.i8x16_eq(b)),
+ I16x8Eq => stack_op!(binary Value128, |a, b| a.i16x8_eq(b)),
+ I32x4Eq => stack_op!(binary Value128, |a, b| a.i32x4_eq(b)),
+ I64x2Eq => stack_op!(binary Value128, |a, b| a.i64x2_eq(b)),
+ F32x4Eq => stack_op!(binary Value128, |a, b| a.f32x4_eq(b)),
+ F64x2Eq => stack_op!(binary Value128, |a, b| a.f64x2_eq(b)),
- // I8x16Ne => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // I16x8Ne => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // I32x4Ne => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // I64x2Ne => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // F32x4Ne => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // F64x2Ne => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
+ I8x16Ne => stack_op!(binary Value128, |a, b| a.i8x16_ne(b)),
+ I16x8Ne => stack_op!(binary Value128, |a, b| a.i16x8_ne(b)),
+ I32x4Ne => stack_op!(binary Value128, |a, b| a.i32x4_ne(b)),
+ I64x2Ne => stack_op!(binary Value128, |a, b| a.i64x2_ne(b)),
+ F32x4Ne => stack_op!(binary Value128, |a, b| a.f32x4_ne(b)),
+ F64x2Ne => stack_op!(binary Value128, |a, b| a.f64x2_ne(b)),
- // I8x16LtS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I16x8LtS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I32x4LtS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I64x2LtS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I8x16LtU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I16x8LtU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I32x4LtU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // F32x4Lt => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // F64x2Lt => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
+ I8x16LtS => stack_op!(binary Value128, |a, b| a.i8x16_lt_s(b)),
+ I16x8LtS => stack_op!(binary Value128, |a, b| a.i16x8_lt_s(b)),
+ I32x4LtS => stack_op!(binary Value128, |a, b| a.i32x4_lt_s(b)),
+ I64x2LtS => stack_op!(binary Value128, |a, b| a.i64x2_lt_s(b)),
+ I8x16LtU => stack_op!(binary Value128, |a, b| a.i8x16_lt_u(b)),
+ I16x8LtU => stack_op!(binary Value128, |a, b| a.i16x8_lt_u(b)),
+ I32x4LtU => stack_op!(binary Value128, |a, b| a.i32x4_lt_u(b)),
+ F32x4Lt => stack_op!(binary Value128, |a, b| a.f32x4_lt(b)),
+ F64x2Lt => stack_op!(binary Value128, |a, b| a.f64x2_lt(b)),
- // F32x4Gt => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // F64x2Gt => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
+ F32x4Gt => stack_op!(binary Value128, |a, b| a.f32x4_gt(b)),
+ F64x2Gt => stack_op!(binary Value128, |a, b| a.f64x2_gt(b)),
- // I8x16GtS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I16x8GtS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I32x4GtS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I64x2GtS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I64x2LeS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // F32x4Le => self.stack.values.calculate::<f32x4,_>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // F64x2Le => self.stack.values.calculate::<f64x2,_>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
+ I8x16GtS => stack_op!(binary Value128, |a, b| a.i8x16_gt_s(b)),
+ I16x8GtS => stack_op!(binary Value128, |a, b| a.i16x8_gt_s(b)),
+ I32x4GtS => stack_op!(binary Value128, |a, b| a.i32x4_gt_s(b)),
+ I64x2GtS => stack_op!(binary Value128, |a, b| a.i64x2_gt_s(b)),
+ I64x2LeS => stack_op!(binary Value128, |a, b| a.i64x2_le_s(b)),
+ F32x4Le => stack_op!(binary Value128, |a, b| a.f32x4_le(b)),
+ F64x2Le => stack_op!(binary Value128, |a, b| a.f64x2_le(b)),
- // I8x16GtU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I16x8GtU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I32x4GtU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // F32x4Ge => self.stack.values.calculate::<f32x4,_>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // F64x2Ge => self.stack.values.calculate::<f64x2,_>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
+ I8x16GtU => stack_op!(binary Value128, |a, b| a.i8x16_gt_u(b)),
+ I16x8GtU => stack_op!(binary Value128, |a, b| a.i16x8_gt_u(b)),
+ I32x4GtU => stack_op!(binary Value128, |a, b| a.i32x4_gt_u(b)),
+ F32x4Ge => stack_op!(binary Value128, |a, b| a.f32x4_ge(b)),
+ F64x2Ge => stack_op!(binary Value128, |a, b| a.f64x2_ge(b)),
- // I8x16LeS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I16x8LeS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I32x4LeS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
+ I8x16LeS => stack_op!(binary Value128, |a, b| a.i8x16_le_s(b)),
+ I16x8LeS => stack_op!(binary Value128, |a, b| a.i16x8_le_s(b)),
+ I32x4LeS => stack_op!(binary Value128, |a, b| a.i32x4_le_s(b)),
- // I8x16LeU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I16x8LeU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I32x4LeU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
+ I8x16LeU => stack_op!(binary Value128, |a, b| a.i8x16_le_u(b)),
+ I16x8LeU => stack_op!(binary Value128, |a, b| a.i16x8_le_u(b)),
+ I32x4LeU => stack_op!(binary Value128, |a, b| a.i32x4_le_u(b)),
- // I8x16GeS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I16x8GeS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I32x4GeS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I64x2GeS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
+ I8x16GeS => stack_op!(binary Value128, |a, b| a.i8x16_ge_s(b)),
+ I16x8GeS => stack_op!(binary Value128, |a, b| a.i16x8_ge_s(b)),
+ I32x4GeS => stack_op!(binary Value128, |a, b| a.i32x4_ge_s(b)),
+ I64x2GeS => stack_op!(binary Value128, |a, b| a.i64x2_ge_s(b)),
- // I8x16GeU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I16x8GeU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I32x4GeU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
+ I8x16GeU => stack_op!(binary Value128, |a, b| a.i8x16_ge_u(b)),
+ I16x8GeU => stack_op!(binary Value128, |a, b| a.i16x8_ge_u(b)),
+ I32x4GeU => stack_op!(binary Value128, |a, b| a.i32x4_ge_u(b)),
- // I8x16Abs => self.stack.values.replace_top_same::<i8x16>(|a| Ok(a.abs())).to_cf()?,
- // I16x8Abs => self.stack.values.replace_top_same::<i16x8>(|a| Ok(a.abs())).to_cf()?,
- // I32x4Abs => self.stack.values.replace_top_same::<i32x4>(|a| Ok(a.abs())).to_cf()?,
- // I64x2Abs => self.stack.values.replace_top_same::<i64x2>(|a| Ok(a.abs())).to_cf()?,
+ I8x16Abs => stack_op!(unary Value128, |a| a.i8x16_abs()),
+ I16x8Abs => stack_op!(unary Value128, |a| a.i16x8_abs()),
+ I32x4Abs => stack_op!(unary Value128, |a| a.i32x4_abs()),
+ I64x2Abs => stack_op!(unary Value128, |a| a.i64x2_abs()),
- // I8x16Neg => self.stack.values.replace_top_same::<i8x16>(|a| Ok(-a)).to_cf()?,
- // I16x8Neg => self.stack.values.replace_top_same::<i16x8>(|a| Ok(-a)).to_cf()?,
- // I32x4Neg => self.stack.values.replace_top_same::<i32x4>(|a| Ok(-a)).to_cf()?,
- // I64x2Neg => self.stack.values.replace_top_same::<i64x2>(|a| Ok(-a)).to_cf()?,
+ I8x16Neg => stack_op!(unary Value128, |a| a.i8x16_neg()),
+ I16x8Neg => stack_op!(unary Value128, |a| a.i16x8_neg()),
+ I32x4Neg => stack_op!(unary Value128, |a| a.i32x4_neg()),
+ I64x2Neg => stack_op!(unary Value128, |a| a.i64x2_neg()),
- // I8x16AllTrue => self.stack.values.replace_top::<i8x16, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
- // I16x8AllTrue => self.stack.values.replace_top::<i16x8, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
- // I32x4AllTrue => self.stack.values.replace_top::<i32x4, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
- // I64x2AllTrue => self.stack.values.replace_top::<i64x2, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
+ I8x16AllTrue => stack_op!(unary Value128 => i32, |v| v.i8x16_all_true() as i32),
+ I16x8AllTrue => stack_op!(unary Value128 => i32, |v| v.i16x8_all_true() as i32),
+ I32x4AllTrue => stack_op!(unary Value128 => i32, |v| v.i32x4_all_true() as i32),
+ I64x2AllTrue => stack_op!(unary Value128 => i32, |v| v.i64x2_all_true() as i32),
- // I8x16Bitmask => self.stack.values.replace_top::<i8x16, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
- // I16x8Bitmask => self.stack.values.replace_top::<i16x8, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
- // I32x4Bitmask => self.stack.values.replace_top::<i32x4, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
- // I64x2Bitmask => self.stack.values.replace_top::<i64x2, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
+ I8x16Bitmask => stack_op!(unary Value128 => i32, |v| v.i8x16_bitmask() as i32),
+ I16x8Bitmask => stack_op!(unary Value128 => i32, |v| v.i16x8_bitmask() as i32),
+ I32x4Bitmask => stack_op!(unary Value128 => i32, |v| v.i32x4_bitmask() as i32),
+ I64x2Bitmask => stack_op!(unary Value128 => i32, |v| v.i64x2_bitmask() as i32),
- // I8x16Shl => self.stack.values.calculate_diff::<i32, i8x16, i8x16>(|a, b| Ok(b.shl(a as i8))).to_cf()?,
- // I16x8Shl => self.stack.values.calculate_diff::<i32, i16x8, i16x8>(|a, b| Ok(b.shl(a as i16))).to_cf()?,
- // I32x4Shl => self.stack.values.calculate_diff::<i32, i32x4, i32x4>(|a, b| Ok(b.shl(a))).to_cf()?,
- // I64x2Shl => self.stack.values.calculate_diff::<i32, i64x2, i64x2>(|a, b| Ok(b.shl(a as i64))).to_cf()?,
+ I8x16Shl => stack_op!(binary i32, Value128, |a, b| b.i8x16_shl(a as u32)),
+ I16x8Shl => stack_op!(binary i32, Value128, |a, b| b.i16x8_shl(a as u32)),
+ I32x4Shl => stack_op!(binary i32, Value128, |a, b| b.i32x4_shl(a as u32)),
+ I64x2Shl => stack_op!(binary i32, Value128, |a, b| b.i64x2_shl(a as u32)),
- // I8x16ShrS => self.stack.values.calculate_diff::<i32, i8x16, i8x16>(|a, b| Ok(b.shr(a as i8))).to_cf()?,
- // I16x8ShrS => self.stack.values.calculate_diff::<i32, i16x8, i16x8>(|a, b| Ok(b.shr(a as i16))).to_cf()?,
- // I32x4ShrS => self.stack.values.calculate_diff::<i32, i32x4, i32x4>(|a, b| Ok(b.shr(a))).to_cf()?,
- // I64x2ShrS => self.stack.values.calculate_diff::<i32, i64x2, i64x2>(|a, b| Ok(b.shr(a as i64))).to_cf()?,
+ I8x16ShrS => stack_op!(binary i32, Value128, |a, b| b.i8x16_shr_s(a as u32)),
+ I16x8ShrS => stack_op!(binary i32, Value128, |a, b| b.i16x8_shr_s(a as u32)),
+ I32x4ShrS => stack_op!(binary i32, Value128, |a, b| b.i32x4_shr_s(a as u32)),
+ I64x2ShrS => stack_op!(binary i32, Value128, |a, b| b.i64x2_shr_s(a as u32)),
- // I8x16ShrU => self.stack.values.calculate_diff::<i32, u8x16, u8x16>(|a, b| Ok(b.shr(a as u8))).to_cf()?,
- // I16x8ShrU => self.stack.values.calculate_diff::<i32, u16x8, u16x8>(|a, b| Ok(b.shr(a as u16))).to_cf()?,
- // I32x4ShrU => self.stack.values.calculate_diff::<i32, u32x4, u32x4>(|a, b| Ok(b.shr(a as u32))).to_cf()?,
- // I64x2ShrU => self.stack.values.calculate_diff::<i32, u64x2, u64x2>(|a, b| Ok(b.shr(a as u64))).to_cf()?,
-
- // I8x16Add => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a + b)).to_cf()?,
- // I16x8Add => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a + b)).to_cf()?,
- // I32x4Add => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a + b)).to_cf()?,
- // I64x2Add => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a + b)).to_cf()?,
-
- // I8x16Sub => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a - b)).to_cf()?,
- // I16x8Sub => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a - b)).to_cf()?,
- // I32x4Sub => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a - b)).to_cf()?,
- // I64x2Sub => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a - b)).to_cf()?,
-
- // I8x16MinS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I16x8MinS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I32x4MinS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_min(b))).to_cf()?,
-
- // I8x16MinU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I16x8MinU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I32x4MinU => self.stack.values.calculate_same::<u32x4>(|a, b| Ok(a.simd_min(b))).to_cf()?,
-
- // I8x16MaxS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I16x8MaxS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I32x4MaxS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_max(b))).to_cf()?,
-
- // I8x16MaxU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I16x8MaxU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I32x4MaxU => self.stack.values.calculate_same::<u32x4>(|a, b| Ok(a.simd_max(b))).to_cf()?,
-
- // I64x2Mul => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a * b)).to_cf()?,
- // I16x8Mul => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a * b)).to_cf()?,
- // I32x4Mul => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a * b)).to_cf()?,
-
- // I8x16NarrowI16x8S => unimplemented!(),
- // I8x16NarrowI16x8U => unimplemented!(),
- // I16x8NarrowI32x4S => unimplemented!(),
- // I16x8NarrowI32x4U => unimplemented!(),
-
- // I8x16AddSatS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I16x8AddSatS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I8x16AddSatU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I16x8AddSatU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I8x16SubSatS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
- // I16x8SubSatS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
- // I8x16SubSatU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
- // I16x8SubSatU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
-
- // I8x16AvgrU => unimplemented!(),
- // I16x8AvgrU => unimplemented!(),
-
- // 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::<i8x16, _>(|v| Ok(v.count_ones())).to_cf()?,
- // I8x16Shuffle(_idx) => unimplemented!(),
-
- I16x8Q15MulrSatS => self.stack.values.calculate_same::<Value128>(|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
- }
- };
- let a = a.as_i16x8();
- let b = b.as_i16x8();
- Ok(Value128::from_i16x8([
- 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()?,
+ I8x16ShrU => stack_op!(binary i32, Value128, |a, b| b.i8x16_shr_u(a as u32)),
+ I16x8ShrU => stack_op!(binary i32, Value128, |a, b| b.i16x8_shr_u(a as u32)),
+ I32x4ShrU => stack_op!(binary i32, Value128, |a, b| b.i32x4_shr_u(a as u32)),
+ I64x2ShrU => stack_op!(binary i32, Value128, |a, b| b.i64x2_shr_u(a as u32)),
+ I8x16Add => stack_op!(binary Value128, |a, b| a.i8x16_add(b)),
+ I16x8Add => stack_op!(binary Value128, |a, b| a.i16x8_add(b)),
+ I32x4Add => stack_op!(binary Value128, |a, b| a.i32x4_add(b)),
+ I64x2Add => stack_op!(binary Value128, |a, b| a.i64x2_add(b)),
- I32x4DotI16x8S => self.stack.values.calculate::<Value128, Value128>(|a, b| {
- let a = a.as_i16x8();
- let b = b.as_i16x8();
- Ok(Value128::from_i32x4([
- 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()?,
+ I8x16Sub => stack_op!(binary Value128, |a, b| a.i8x16_sub(b)),
+ I16x8Sub => stack_op!(binary Value128, |a, b| a.i16x8_sub(b)),
+ I32x4Sub => stack_op!(binary Value128, |a, b| a.i32x4_sub(b)),
+ I64x2Sub => stack_op!(binary Value128, |a, b| a.i64x2_sub(b)),
- // F32x4Ceil => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.ceil())).to_cf()?,
- // F64x2Ceil => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.ceil())).to_cf()?,
- // F32x4Floor => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.floor())).to_cf()?,
- // F64x2Floor => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.floor())).to_cf()?,
- // F32x4Trunc => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.trunc())).to_cf()?,
- // F64x2Trunc => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.trunc())).to_cf()?,
- // F32x4Nearest => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.round())).to_cf()?,
- // F64x2Nearest => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.round())).to_cf()?,
- // F32x4Abs => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.abs())).to_cf()?,
- // F64x2Abs => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.abs())).to_cf()?,
- // F32x4Neg => self.stack.values.replace_top_same::<f32x4>(|v| Ok(-v)).to_cf()?,
- // F64x2Neg => self.stack.values.replace_top_same::<f64x2>(|v| Ok(-v)).to_cf()?,
- // F32x4Sqrt => self.stack.values.replace_top_same::<f32x4>(|v| Ok(canonicalize_f32x4(v.sqrt()))).to_cf()?,
- // F64x2Sqrt => self.stack.values.replace_top_same::<f64x2>(|v| Ok(canonicalize_f64x2(v.sqrt()))).to_cf()?,
- // F32x4Add => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a + b))).to_cf()?,
- // F64x2Add => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a + b))).to_cf()?,
- // F32x4Sub => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a - b))).to_cf()?,
- // F64x2Sub => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a - b))).to_cf()?,
- // F32x4Mul => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a * b))).to_cf()?,
- // F64x2Mul => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a * b))).to_cf()?,
- // F32x4Div => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a / b))).to_cf()?,
- // F64x2Div => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a / b))).to_cf()?,
+ I8x16MinS => stack_op!(binary Value128, |a, b| a.i8x16_min_s(b)),
+ I16x8MinS => stack_op!(binary Value128, |a, b| a.i16x8_min_s(b)),
+ I32x4MinS => stack_op!(binary Value128, |a, b| a.i32x4_min_s(b)),
- // F32x4Min => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::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()?,
+ I8x16MinU => stack_op!(binary Value128, |a, b| a.i8x16_min_u(b)),
+ I16x8MinU => stack_op!(binary Value128, |a, b| a.i16x8_min_u(b)),
+ I32x4MinU => stack_op!(binary Value128, |a, b| a.i32x4_min_u(b)),
+ I8x16MaxS => stack_op!(binary Value128, |a, b| a.i8x16_max_s(b)),
+ I16x8MaxS => stack_op!(binary Value128, |a, b| a.i16x8_max_s(b)),
+ I32x4MaxS => stack_op!(binary Value128, |a, b| a.i32x4_max_s(b)),
- // F64x2Min => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // b[0].tw_minimum(a[0]),
- // b[1].tw_minimum(a[1]),
- // ]))
- // }).to_cf()?,
+ I8x16MaxU => stack_op!(binary Value128, |a, b| a.i8x16_max_u(b)),
+ I16x8MaxU => stack_op!(binary Value128, |a, b| a.i16x8_max_u(b)),
+ I32x4MaxU => stack_op!(binary Value128, |a, b| a.i32x4_max_u(b)),
+ I64x2Mul => stack_op!(binary Value128, |a, b| a.i64x2_mul(b)),
+ I16x8Mul => stack_op!(binary Value128, |a, b| a.i16x8_mul(b)),
+ I32x4Mul => stack_op!(binary Value128, |a, b| a.i32x4_mul(b)),
- // F32x4Max => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::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()?,
+ I8x16NarrowI16x8S => stack_op!(binary Value128, |a, b| Value128::i8x16_narrow_i16x8_s(a, b)),
+ I8x16NarrowI16x8U => stack_op!(binary Value128, |a, b| Value128::i8x16_narrow_i16x8_u(a, b)),
+ I16x8NarrowI32x4S => stack_op!(binary Value128, |a, b| Value128::i16x8_narrow_i32x4_s(a, b)),
+ I16x8NarrowI32x4U => stack_op!(binary Value128, |a, b| Value128::i16x8_narrow_i32x4_u(a, b)),
+ I8x16AddSatS => stack_op!(binary Value128, |a, b| a.i8x16_add_sat_s(b)),
+ I16x8AddSatS => stack_op!(binary Value128, |a, b| a.i16x8_add_sat_s(b)),
+ I8x16AddSatU => stack_op!(binary Value128, |a, b| a.i8x16_add_sat_u(b)),
+ I16x8AddSatU => stack_op!(binary Value128, |a, b| a.i16x8_add_sat_u(b)),
+ I8x16SubSatS => stack_op!(binary Value128, |a, b| a.i8x16_sub_sat_s(b)),
+ I16x8SubSatS => stack_op!(binary Value128, |a, b| a.i16x8_sub_sat_s(b)),
+ I8x16SubSatU => stack_op!(binary Value128, |a, b| a.i8x16_sub_sat_u(b)),
+ I16x8SubSatU => stack_op!(binary Value128, |a, b| a.i16x8_sub_sat_u(b)),
- // F64x2Max => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // b[0].tw_maximum(a[0]),
- // b[1].tw_maximum(a[1]),
- // ]))
- // }).to_cf()?,
+ I8x16AvgrU => stack_op!(binary Value128, |a, b| a.i8x16_avgr_u(b)),
+ I16x8AvgrU => stack_op!(binary Value128, |a, b| a.i16x8_avgr_u(b)),
+ I16x8ExtAddPairwiseI8x16S => stack_op!(unary Value128, |a| a.i16x8_extadd_pairwise_i8x16_s()),
+ I16x8ExtAddPairwiseI8x16U => stack_op!(unary Value128, |a| a.i16x8_extadd_pairwise_i8x16_u()),
+ I32x4ExtAddPairwiseI16x8S => stack_op!(unary Value128, |a| a.i32x4_extadd_pairwise_i16x8_s()),
+ I32x4ExtAddPairwiseI16x8U => stack_op!(unary Value128, |a| a.i32x4_extadd_pairwise_i16x8_u()),
- // F32x4PMin => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::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()?,
+ I16x8ExtMulLowI8x16S => stack_op!(binary Value128, |a, b| a.i16x8_extmul_low_i8x16_s(b)),
+ I16x8ExtMulLowI8x16U => stack_op!(binary Value128, |a, b| a.i16x8_extmul_low_i8x16_u(b)),
+ I16x8ExtMulHighI8x16S => stack_op!(binary Value128, |a, b| a.i16x8_extmul_high_i8x16_s(b)),
+ I16x8ExtMulHighI8x16U => stack_op!(binary Value128, |a, b| a.i16x8_extmul_high_i8x16_u(b)),
+ I32x4ExtMulLowI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_extmul_low_i16x8_s(b)),
+ I32x4ExtMulLowI16x8U => stack_op!(binary Value128, |a, b| a.i32x4_extmul_low_i16x8_u(b)),
+ I32x4ExtMulHighI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_extmul_high_i16x8_s(b)),
+ I32x4ExtMulHighI16x8U => stack_op!(binary Value128, |a, b| a.i32x4_extmul_high_i16x8_u(b)),
+ I64x2ExtMulLowI32x4S => stack_op!(binary Value128, |a, b| a.i64x2_extmul_low_i32x4_s(b)),
+ I64x2ExtMulLowI32x4U => stack_op!(binary Value128, |a, b| a.i64x2_extmul_low_i32x4_u(b)),
+ I64x2ExtMulHighI32x4S => stack_op!(binary Value128, |a, b| a.i64x2_extmul_high_i32x4_s(b)),
+ I64x2ExtMulHighI32x4U => stack_op!(binary Value128, |a, b| a.i64x2_extmul_high_i32x4_u(b)),
+ I16x8ExtendLowI8x16S => stack_op!(unary Value128, |a| a.i16x8_extend_low_i8x16_s()),
+ I16x8ExtendLowI8x16U => stack_op!(unary Value128, |a| a.i16x8_extend_low_i8x16_u()),
+ I16x8ExtendHighI8x16S => stack_op!(unary Value128, |a| a.i16x8_extend_high_i8x16_s()),
+ I16x8ExtendHighI8x16U => stack_op!(unary Value128, |a| a.i16x8_extend_high_i8x16_u()),
+ I32x4ExtendLowI16x8S => stack_op!(unary Value128, |a| a.i32x4_extend_low_i16x8_s()),
+ I32x4ExtendLowI16x8U => stack_op!(unary Value128, |a| a.i32x4_extend_low_i16x8_u()),
+ I32x4ExtendHighI16x8S => stack_op!(unary Value128, |a| a.i32x4_extend_high_i16x8_s()),
+ I32x4ExtendHighI16x8U => stack_op!(unary Value128, |a| a.i32x4_extend_high_i16x8_u()),
+ I64x2ExtendLowI32x4S => stack_op!(unary Value128, |a| a.i64x2_extend_low_i32x4_s()),
+ I64x2ExtendLowI32x4U => stack_op!(unary Value128, |a| a.i64x2_extend_low_i32x4_u()),
+ I64x2ExtendHighI32x4S => stack_op!(unary Value128, |a| a.i64x2_extend_high_i32x4_s()),
+ I64x2ExtendHighI32x4U => stack_op!(unary Value128, |a| a.i64x2_extend_high_i32x4_u()),
- // F32x4PMax => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::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()?,
+ I8x16Popcnt => stack_op!(unary Value128, |v| v.i8x16_popcnt()),
+ I8x16Shuffle(idx) => { let idx = self.cf.data().v128_constants[*idx as usize].to_le_bytes(); stack_op!(binary Value128, |a, b| Value128::i8x16_shuffle(a, b, idx)) }
+ I16x8Q15MulrSatS => stack_op!(binary Value128, |a, b| a.i16x8_q15mulr_sat_s(b)),
- // F64x2PMin => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // if b[0] < a[0] { b[0] } else { a[0]},
- // if b[1] < a[1] { b[1] } else { a[1]},
- // ]))
- // }).to_cf()?,
+ I32x4DotI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_dot_i16x8_s(b)),
+ F32x4Ceil => stack_op!(simd_unary f32x4_ceil),
+ F64x2Ceil => stack_op!(simd_unary f64x2_ceil),
+ F32x4Floor => stack_op!(simd_unary f32x4_floor),
+ F64x2Floor => stack_op!(simd_unary f64x2_floor),
+ F32x4Trunc => stack_op!(simd_unary f32x4_trunc),
+ F64x2Trunc => stack_op!(simd_unary f64x2_trunc),
+ F32x4Nearest => stack_op!(simd_unary f32x4_nearest),
+ F64x2Nearest => stack_op!(simd_unary f64x2_nearest),
+ F32x4Abs => stack_op!(simd_unary f32x4_abs),
+ F64x2Abs => stack_op!(simd_unary f64x2_abs),
+ F32x4Neg => stack_op!(simd_unary f32x4_neg),
+ F64x2Neg => stack_op!(simd_unary f64x2_neg),
+ F32x4Sqrt => stack_op!(simd_unary f32x4_sqrt),
+ F64x2Sqrt => stack_op!(simd_unary f64x2_sqrt),
+ F32x4Add => stack_op!(simd_binary f32x4_add),
+ F64x2Add => stack_op!(simd_binary f64x2_add),
+ F32x4Sub => stack_op!(simd_binary f32x4_sub),
+ F64x2Sub => stack_op!(simd_binary f64x2_sub),
+ F32x4Mul => stack_op!(simd_binary f32x4_mul),
+ F64x2Mul => stack_op!(simd_binary f64x2_mul),
+ F32x4Div => stack_op!(simd_binary f32x4_div),
+ F64x2Div => stack_op!(simd_binary f64x2_div),
- // F64x2PMax => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // if b[0] > a[0] { b[0] } else { a[0]},
- // if b[1] > a[1] { b[1] } else { a[1]},
- // ]))
- // }).to_cf()?,
+ F32x4Min => stack_op!(simd_binary f32x4_min),
+ F64x2Min => stack_op!(simd_binary f64x2_min),
+ F32x4Max => stack_op!(simd_binary f32x4_max),
+ F64x2Max => stack_op!(simd_binary f64x2_max),
+ F32x4PMin => stack_op!(simd_binary f32x4_pmin),
+ F32x4PMax => stack_op!(simd_binary f32x4_pmax),
+ F64x2PMin => stack_op!(simd_binary f64x2_pmin),
+ F64x2PMax => stack_op!(simd_binary f64x2_pmax),
- // // not correct
- // I32x4TruncSatF32x4S => self.stack.values.replace_top::<f32x4, f32x4>(|v| Ok(v.trunc())).to_cf()?,
- // I32x4TruncSatF32x4U => self.stack.values.replace_top::<f32x4, f32x4>(|v| Ok(v.trunc())).to_cf()?,
- // F32x4ConvertI32x4S => unimplemented!(),
- // F32x4ConvertI32x4U => unimplemented!(),
- // F64x2ConvertLowI32x4S => unimplemented!(),
- // F64x2ConvertLowI32x4U => unimplemented!(),
- // F32x4DemoteF64x2Zero => unimplemented!(),
- // F64x2PromoteLowF32x4 => unimplemented!(),
- // I32x4TruncSatF64x2SZero => unimplemented!(),
- // I32x4TruncSatF64x2UZero => unimplemented!(),
+ I32x4TruncSatF32x4S => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f32x4_s()),
+ I32x4TruncSatF32x4U => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f32x4_u()),
+ F32x4ConvertI32x4S => stack_op!(unary Value128, |v| v.f32x4_convert_i32x4_s()),
+ F32x4ConvertI32x4U => stack_op!(unary Value128, |v| v.f32x4_convert_i32x4_u()),
+ F64x2ConvertLowI32x4S => stack_op!(unary Value128, |v| v.f64x2_convert_low_i32x4_s()),
+ F64x2ConvertLowI32x4U => stack_op!(unary Value128, |v| v.f64x2_convert_low_i32x4_u()),
+ F32x4DemoteF64x2Zero => stack_op!(unary Value128, |v| v.f32x4_demote_f64x2_zero()),
+ F64x2PromoteLowF32x4 => stack_op!(unary Value128, |v| v.f64x2_promote_low_f32x4()),
+ I32x4TruncSatF64x2SZero => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f64x2_s_zero()),
+ I32x4TruncSatF64x2UZero => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f64x2_u_zero()),
+ // Relaxed SIMD (not yet implemented)
// I8x16RelaxedSwizzle => unimplemented!(),
// I32x4RelaxedTruncF32x4S => unimplemented!(),
// I32x4RelaxedTruncF32x4U => unimplemented!(),
@@ -1094,8 +1035,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
lane: u8,
) -> ControlFlow<Option<Error>> {
let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
- let val = self.stack.values.pop::<Value128>().to_mem_bytes();
- let val = val[lane as usize].to_mem_bytes();
+ let bytes = self.stack.values.pop::<Value128>().to_mem_bytes();
+ let lane_offset = lane as usize * N;
+ let mut val = [0u8; N];
+ val.copy_from_slice(&bytes[lane_offset..lane_offset + N]);
let addr = match mem.is_64bit() {
true => self.stack.values.pop::<i64>() as u64,
diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs
index 0356403..5b9e7b9 100644
--- a/crates/tinywasm/src/interpreter/num_helpers.rs
+++ b/crates/tinywasm/src/interpreter/num_helpers.rs
@@ -37,7 +37,7 @@ macro_rules! checked_conv_float {
$self
.stack
.values
- .replace_top::<$from, $to>(|v| {
+ .unary::<$from, $to>(|v| {
let (min, max) = float_min_max!($from, $intermediate);
if unlikely(v.is_nan()) {
return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 6e02b0f..2850e91 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::{Result, StackConfig, interpreter::*};
+use crate::{interpreter::*, Result, StackConfig};
use super::Locals;
@@ -63,18 +63,18 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn calculate_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
+ pub(crate) fn binary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
T::stack_calculate(self, func)
}
#[inline]
#[allow(dead_code)]
- pub(crate) fn calculate_same_3<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
+ pub(crate) fn ternary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
T::stack_calculate3(self, func)
}
#[inline]
- pub(crate) fn calculate<T: InternalValue, U: InternalValue>(
+ pub(crate) fn binary<T: InternalValue, U: InternalValue>(
&mut self,
func: impl FnOnce(T, T) -> Result<U>,
) -> Result<()> {
@@ -86,7 +86,7 @@ impl ValueStack {
#[inline]
#[allow(dead_code)]
- pub(crate) fn calculate_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
+ pub(crate) fn binary_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
&mut self,
func: impl FnOnce(A, B) -> Result<RES>,
) -> Result<()> {
@@ -97,7 +97,7 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn replace_top<T: InternalValue, U: InternalValue>(
+ pub(crate) fn unary<T: InternalValue, U: InternalValue>(
&mut self,
func: impl FnOnce(T) -> Result<U>,
) -> Result<()> {
@@ -107,7 +107,7 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn replace_top_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
+ pub(crate) fn unary_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
T::replace_top(self, func)
}
diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs
index fcd208f..6b807c9 100644
--- a/crates/tinywasm/src/interpreter/value128.rs
+++ b/crates/tinywasm/src/interpreter/value128.rs
@@ -1,7 +1,84 @@
+use super::num_helpers::TinywasmFloatExt;
+
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Value128(i128);
impl Value128 {
+ #[inline]
+ fn canonicalize_simd_f32_nan(x: f32) -> f32 {
+ if x.is_nan() {
+ f32::from_bits(0x7fc0_0000)
+ } else {
+ x
+ }
+ }
+
+ #[inline]
+ fn canonicalize_simd_f64_nan(x: f64) -> f64 {
+ if x.is_nan() {
+ f64::from_bits(0x7ff8_0000_0000_0000)
+ } else {
+ x
+ }
+ }
+
+ const fn saturate_i16_to_i8(x: i16) -> i8 {
+ if x > i8::MAX as i16 {
+ i8::MAX
+ } else if x < i8::MIN as i16 {
+ i8::MIN
+ } else {
+ x as i8
+ }
+ }
+
+ const fn saturate_i16_to_u8(x: i16) -> u8 {
+ if x <= 0 {
+ 0
+ } else if x > u8::MAX as i16 {
+ u8::MAX
+ } else {
+ x as u8
+ }
+ }
+
+ const fn saturate_i32_to_i16(x: i32) -> i16 {
+ if x > i16::MAX as i32 {
+ i16::MAX
+ } else if x < i16::MIN as i32 {
+ i16::MIN
+ } else {
+ x as i16
+ }
+ }
+
+ const fn saturate_i32_to_u16(x: i32) -> u16 {
+ if x <= 0 {
+ 0
+ } else if x > u16::MAX as i32 {
+ u16::MAX
+ } else {
+ x as u16
+ }
+ }
+
+ const fn replace_lane_bytes<const LANE_BYTES: usize>(
+ self,
+ lane: u8,
+ value: [u8; LANE_BYTES],
+ lane_count: u8,
+ ) -> Self {
+ debug_assert!(lane < lane_count);
+ let mut bytes = self.to_le_bytes();
+ let mut i = 0;
+ let start = lane as usize * LANE_BYTES;
+ while i < LANE_BYTES {
+ bytes[start + i] = value[i];
+ i += 1;
+ }
+ Self::from_le_bytes(bytes)
+ }
+
pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
Self(i128::from_le_bytes(bytes))
}
@@ -119,6 +196,32 @@ impl Value128 {
Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[0].to_bits().to_le_bytes()[4], x[0].to_bits().to_le_bytes()[5], x[0].to_bits().to_le_bytes()[6], x[0].to_bits().to_le_bytes()[7], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[4], x[1].to_bits().to_le_bytes()[5], x[1].to_bits().to_le_bytes()[6], x[1].to_bits().to_le_bytes()[7]])
}
+ #[inline]
+ fn map_f32x4(self, mut op: impl FnMut(f32) -> f32) -> Self {
+ let lanes = self.as_f32x4();
+ Self::from_f32x4([op(lanes[0]), op(lanes[1]), op(lanes[2]), op(lanes[3])])
+ }
+
+ #[inline]
+ fn zip_f32x4(self, rhs: Self, mut op: impl FnMut(f32, f32) -> f32) -> Self {
+ let a = self.as_f32x4();
+ let b = rhs.as_f32x4();
+ Self::from_f32x4([op(a[0], b[0]), op(a[1], b[1]), op(a[2], b[2]), op(a[3], b[3])])
+ }
+
+ #[inline]
+ fn map_f64x2(self, mut op: impl FnMut(f64) -> f64) -> Self {
+ let lanes = self.as_f64x2();
+ Self::from_f64x2([op(lanes[0]), op(lanes[1])])
+ }
+
+ #[inline]
+ fn zip_f64x2(self, rhs: Self, mut op: impl FnMut(f64, f64) -> f64) -> Self {
+ let a = self.as_f64x2();
+ let b = rhs.as_f64x2();
+ Self::from_f64x2([op(a[0], b[0]), op(a[1], b[1])])
+ }
+
pub const fn reduce_or(self) -> u8 {
let mut result = 0u8;
let bytes = self.to_le_bytes();
@@ -130,7 +233,111 @@ impl Value128 {
result
}
+ #[doc(alias = "v128.any_true")]
+ pub const fn v128_any_true(self) -> bool {
+ self.reduce_or() != 0
+ }
+
+ #[doc(alias = "v128.not")]
+ pub const fn v128_not(self) -> Self {
+ Self(!self.0)
+ }
+
+ #[doc(alias = "v128.and")]
+ pub const fn v128_and(self, rhs: Self) -> Self {
+ Self(self.0 & rhs.0)
+ }
+
+ #[doc(alias = "v128.andnot")]
+ pub const fn v128_andnot(self, rhs: Self) -> Self {
+ Self(self.0 & !rhs.0)
+ }
+
+ #[doc(alias = "v128.or")]
+ pub const fn v128_or(self, rhs: Self) -> Self {
+ Self(self.0 | rhs.0)
+ }
+
+ #[doc(alias = "v128.xor")]
+ pub const fn v128_xor(self, rhs: Self) -> Self {
+ Self(self.0 ^ rhs.0)
+ }
+
+ #[doc(alias = "v128.bitselect")]
+ pub const fn v128_bitselect(v1: Self, v2: Self, c: Self) -> Self {
+ Self((v1.0 & c.0) | (v2.0 & !c.0))
+ }
+
pub const fn swizzle(self, s: Self) -> Self {
+ self.i8x16_swizzle(s)
+ }
+
+ #[doc(alias = "v128.load8x8_s")]
+ pub const fn v128_load8x8_s(src: [u8; 8]) -> Self {
+ Self::from_i16x8([
+ src[0] as i8 as i16,
+ src[1] as i8 as i16,
+ src[2] as i8 as i16,
+ src[3] as i8 as i16,
+ src[4] as i8 as i16,
+ src[5] as i8 as i16,
+ src[6] as i8 as i16,
+ src[7] as i8 as i16,
+ ])
+ }
+
+ #[doc(alias = "v128.load8x8_u")]
+ pub const fn v128_load8x8_u(src: [u8; 8]) -> Self {
+ Self::from_u16x8([
+ src[0] as u16,
+ src[1] as u16,
+ src[2] as u16,
+ src[3] as u16,
+ src[4] as u16,
+ src[5] as u16,
+ src[6] as u16,
+ src[7] as u16,
+ ])
+ }
+
+ #[doc(alias = "v128.load16x4_s")]
+ pub const fn v128_load16x4_s(src: [u8; 8]) -> Self {
+ Self::from_i32x4([
+ i16::from_le_bytes([src[0], src[1]]) as i32,
+ i16::from_le_bytes([src[2], src[3]]) as i32,
+ i16::from_le_bytes([src[4], src[5]]) as i32,
+ i16::from_le_bytes([src[6], src[7]]) as i32,
+ ])
+ }
+
+ #[doc(alias = "v128.load16x4_u")]
+ pub const fn v128_load16x4_u(src: [u8; 8]) -> Self {
+ Self::from_u32x4([
+ u16::from_le_bytes([src[0], src[1]]) as u32,
+ u16::from_le_bytes([src[2], src[3]]) as u32,
+ u16::from_le_bytes([src[4], src[5]]) as u32,
+ u16::from_le_bytes([src[6], src[7]]) as u32,
+ ])
+ }
+
+ #[doc(alias = "v128.load32x2_s")]
+ pub const fn v128_load32x2_s(src: [u8; 8]) -> Self {
+ Self::from_i64x2([
+ i32::from_le_bytes([src[0], src[1], src[2], src[3]]) as i64,
+ i32::from_le_bytes([src[4], src[5], src[6], src[7]]) as i64,
+ ])
+ }
+
+ #[doc(alias = "v128.load32x2_u")]
+ pub const fn v128_load32x2_u(src: [u8; 8]) -> Self {
+ Self::from_u64x2([
+ u32::from_le_bytes([src[0], src[1], src[2], src[3]]) as u64,
+ u32::from_le_bytes([src[4], src[5], src[6], src[7]]) as u64,
+ ])
+ }
+
+ #[doc(alias = "i8x16.swizzle")]
+ pub const fn i8x16_swizzle(self, s: Self) -> Self {
let a_bytes = self.to_le_bytes();
let s_bytes = s.to_le_bytes();
let mut result_bytes = [0u8; 16];
@@ -143,6 +350,20 @@ impl Value128 {
Self::from_le_bytes(result_bytes)
}
+ #[doc(alias = "i8x16.shuffle")]
+ pub const fn i8x16_shuffle(a: Self, b: Self, idx: [u8; 16]) -> Self {
+ let a_bytes = a.to_le_bytes();
+ let b_bytes = b.to_le_bytes();
+ let mut result_bytes = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ let index = idx[i] as usize;
+ result_bytes[i] = if index < 16 { a_bytes[index] } else { b_bytes[index - 16] };
+ i += 1;
+ }
+ Self::from_le_bytes(result_bytes)
+ }
+
pub const fn extend_8_i8(src: i8) -> Self {
let mut result_bytes = [0u8; 16];
let mut i = 0;
@@ -240,6 +461,1949 @@ impl Value128 {
Self::from_le_bytes(result_bytes)
}
+ #[doc(alias = "i8x16.replace_lane")]
+ pub const fn i8x16_replace_lane(self, lane: u8, value: i8) -> Self {
+ self.replace_lane_bytes::<1>(lane, [value as u8], 16)
+ }
+
+ #[doc(alias = "i16x8.replace_lane")]
+ pub const fn i16x8_replace_lane(self, lane: u8, value: i16) -> Self {
+ self.replace_lane_bytes::<2>(lane, value.to_le_bytes(), 8)
+ }
+
+ #[doc(alias = "i32x4.replace_lane")]
+ pub const fn i32x4_replace_lane(self, lane: u8, value: i32) -> Self {
+ self.replace_lane_bytes::<4>(lane, value.to_le_bytes(), 4)
+ }
+
+ #[doc(alias = "i64x2.replace_lane")]
+ pub const fn i64x2_replace_lane(self, lane: u8, value: i64) -> Self {
+ self.replace_lane_bytes::<8>(lane, value.to_le_bytes(), 2)
+ }
+
+ #[doc(alias = "f32x4.replace_lane")]
+ pub const fn f32x4_replace_lane(self, lane: u8, value: f32) -> Self {
+ self.replace_lane_bytes::<4>(lane, value.to_bits().to_le_bytes(), 4)
+ }
+
+ #[doc(alias = "f64x2.replace_lane")]
+ pub const fn f64x2_replace_lane(self, lane: u8, value: f64) -> Self {
+ self.replace_lane_bytes::<8>(lane, value.to_bits().to_le_bytes(), 2)
+ }
+
+ #[doc(alias = "i8x16.all_true")]
+ pub const fn i8x16_all_true(self) -> bool {
+ let lanes = self.as_i8x16();
+ let mut i = 0;
+ while i < 16 {
+ if lanes[i] == 0 {
+ return false;
+ }
+ i += 1;
+ }
+ true
+ }
+
+ #[doc(alias = "i16x8.all_true")]
+ pub const fn i16x8_all_true(self) -> bool {
+ let lanes = self.as_i16x8();
+ let mut i = 0;
+ while i < 8 {
+ if lanes[i] == 0 {
+ return false;
+ }
+ i += 1;
+ }
+ true
+ }
+
+ #[doc(alias = "i32x4.all_true")]
+ pub const fn i32x4_all_true(self) -> bool {
+ let lanes = self.as_i32x4();
+ let mut i = 0;
+ while i < 4 {
+ if lanes[i] == 0 {
+ return false;
+ }
+ i += 1;
+ }
+ true
+ }
+
+ #[doc(alias = "i64x2.all_true")]
+ pub const fn i64x2_all_true(self) -> bool {
+ let lanes = self.as_i64x2();
+ let mut i = 0;
+ while i < 2 {
+ if lanes[i] == 0 {
+ return false;
+ }
+ i += 1;
+ }
+ true
+ }
+
+ #[doc(alias = "i8x16.bitmask")]
+ pub const fn i8x16_bitmask(self) -> u32 {
+ let lanes = self.as_i8x16();
+ let mut mask = 0u32;
+ let mut i = 0;
+ while i < 16 {
+ mask |= ((lanes[i] < 0) as u32) << i;
+ i += 1;
+ }
+ mask
+ }
+
+ #[doc(alias = "i16x8.bitmask")]
+ pub const fn i16x8_bitmask(self) -> u32 {
+ let lanes = self.as_i16x8();
+ let mut mask = 0u32;
+ let mut i = 0;
+ while i < 8 {
+ mask |= ((lanes[i] < 0) as u32) << i;
+ i += 1;
+ }
+ mask
+ }
+
+ #[doc(alias = "i32x4.bitmask")]
+ pub const fn i32x4_bitmask(self) -> u32 {
+ let lanes = self.as_i32x4();
+ let mut mask = 0u32;
+ let mut i = 0;
+ while i < 4 {
+ mask |= ((lanes[i] < 0) as u32) << i;
+ i += 1;
+ }
+ mask
+ }
+
+ #[doc(alias = "i64x2.bitmask")]
+ pub const fn i64x2_bitmask(self) -> u32 {
+ let lanes = self.as_i64x2();
+ let mut mask = 0u32;
+ let mut i = 0;
+ while i < 2 {
+ mask |= ((lanes[i] < 0) as u32) << i;
+ i += 1;
+ }
+ mask
+ }
+
+ #[doc(alias = "i8x16.popcnt")]
+ pub const fn i8x16_popcnt(self) -> Self {
+ let lanes = self.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = lanes[i].count_ones() as u8;
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i8x16.shl")]
+ pub const fn i8x16_shl(self, shift: u32) -> Self {
+ let lanes = self.as_i8x16();
+ let s = shift & 7;
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = lanes[i].wrapping_shl(s);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.shl")]
+ pub const fn i16x8_shl(self, shift: u32) -> Self {
+ let lanes = self.as_i16x8();
+ let s = shift & 15;
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = lanes[i].wrapping_shl(s);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.shl")]
+ pub const fn i32x4_shl(self, shift: u32) -> Self {
+ let lanes = self.as_i32x4();
+ let s = shift & 31;
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = lanes[i].wrapping_shl(s);
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.shl")]
+ pub const fn i64x2_shl(self, shift: u32) -> Self {
+ let lanes = self.as_i64x2();
+ let s = shift & 63;
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = lanes[i].wrapping_shl(s);
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.shr_s")]
+ pub const fn i8x16_shr_s(self, shift: u32) -> Self {
+ let lanes = self.as_i8x16();
+ let s = shift & 7;
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.shr_s")]
+ pub const fn i16x8_shr_s(self, shift: u32) -> Self {
+ let lanes = self.as_i16x8();
+ let s = shift & 15;
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.shr_s")]
+ pub const fn i32x4_shr_s(self, shift: u32) -> Self {
+ let lanes = self.as_i32x4();
+ let s = shift & 31;
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.shr_s")]
+ pub const fn i64x2_shr_s(self, shift: u32) -> Self {
+ let lanes = self.as_i64x2();
+ let s = shift & 63;
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.shr_u")]
+ pub const fn i8x16_shr_u(self, shift: u32) -> Self {
+ let lanes = self.as_u8x16();
+ let s = shift & 7;
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.shr_u")]
+ pub const fn i16x8_shr_u(self, shift: u32) -> Self {
+ let lanes = self.as_u16x8();
+ let s = shift & 15;
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i32x4.shr_u")]
+ pub const fn i32x4_shr_u(self, shift: u32) -> Self {
+ let lanes = self.as_u32x4();
+ let s = shift & 31;
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_u32x4(out)
+ }
+
+ #[doc(alias = "i64x2.shr_u")]
+ pub const fn i64x2_shr_u(self, shift: u32) -> Self {
+ let lanes = self.as_u64x2();
+ let s = shift & 63;
+ let mut out = [0u64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::from_u64x2(out)
+ }
+
+ #[doc(alias = "i8x16.add")]
+ pub const fn i8x16_add(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].wrapping_add(b[i]);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.add")]
+ pub const fn i16x8_add(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].wrapping_add(b[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.add")]
+ pub const fn i32x4_add(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = a[i].wrapping_add(b[i]);
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.add")]
+ pub const fn i64x2_add(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = a[i].wrapping_add(b[i]);
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.sub")]
+ pub const fn i8x16_sub(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].wrapping_sub(b[i]);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.sub")]
+ pub const fn i16x8_sub(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].wrapping_sub(b[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.sub")]
+ pub const fn i32x4_sub(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = a[i].wrapping_sub(b[i]);
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.sub")]
+ pub const fn i64x2_sub(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = a[i].wrapping_sub(b[i]);
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i16x8.mul")]
+ pub const fn i16x8_mul(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].wrapping_mul(b[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.mul")]
+ pub const fn i32x4_mul(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = a[i].wrapping_mul(b[i]);
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.mul")]
+ pub const fn i64x2_mul(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = a[i].wrapping_mul(b[i]);
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.add_sat_s")]
+ pub const fn i8x16_add_sat_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].saturating_add(b[i]);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.add_sat_s")]
+ pub const fn i16x8_add_sat_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].saturating_add(b[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i8x16.add_sat_u")]
+ pub const fn i8x16_add_sat_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].saturating_add(b[i]);
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.add_sat_u")]
+ pub const fn i16x8_add_sat_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].saturating_add(b[i]);
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i8x16.sub_sat_s")]
+ pub const fn i8x16_sub_sat_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].saturating_sub(b[i]);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.sub_sat_s")]
+ pub const fn i16x8_sub_sat_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].saturating_sub(b[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i8x16.sub_sat_u")]
+ pub const fn i8x16_sub_sat_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].saturating_sub(b[i]);
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.sub_sat_u")]
+ pub const fn i16x8_sub_sat_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].saturating_sub(b[i]);
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i8x16.avgr_u")]
+ pub const fn i8x16_avgr_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = ((a[i] as u16 + b[i] as u16 + 1) >> 1) as u8;
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.avgr_u")]
+ pub const fn i16x8_avgr_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = ((a[i] as u32 + b[i] as u32 + 1) >> 1) as u16;
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i8x16.narrow_i16x8_s")]
+ pub const fn i8x16_narrow_i16x8_s(a: Self, b: Self) -> Self {
+ let av = a.as_i16x8();
+ let bv = b.as_i16x8();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = Self::saturate_i16_to_i8(av[i]);
+ out[i + 8] = Self::saturate_i16_to_i8(bv[i]);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i8x16.narrow_i16x8_u")]
+ pub const fn i8x16_narrow_i16x8_u(a: Self, b: Self) -> Self {
+ let av = a.as_i16x8();
+ let bv = b.as_i16x8();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = Self::saturate_i16_to_u8(av[i]);
+ out[i + 8] = Self::saturate_i16_to_u8(bv[i]);
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.narrow_i32x4_s")]
+ pub const fn i16x8_narrow_i32x4_s(a: Self, b: Self) -> Self {
+ let av = a.as_i32x4();
+ let bv = b.as_i32x4();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = Self::saturate_i32_to_i16(av[i]);
+ out[i + 4] = Self::saturate_i32_to_i16(bv[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i16x8.narrow_i32x4_u")]
+ pub const fn i16x8_narrow_i32x4_u(a: Self, b: Self) -> Self {
+ let av = a.as_i32x4();
+ let bv = b.as_i32x4();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = Self::saturate_i32_to_u16(av[i]);
+ out[i + 4] = Self::saturate_i32_to_u16(bv[i]);
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extadd_pairwise_i8x16_s")]
+ pub const fn i16x8_extadd_pairwise_i8x16_s(self) -> Self {
+ let lanes = self.as_i8x16();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ let j = i * 2;
+ out[i] = lanes[j] as i16 + lanes[j + 1] as i16;
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extadd_pairwise_i8x16_u")]
+ pub const fn i16x8_extadd_pairwise_i8x16_u(self) -> Self {
+ let lanes = self.as_u8x16();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ let j = i * 2;
+ out[i] = lanes[j] as u16 + lanes[j + 1] as u16;
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i32x4.extadd_pairwise_i16x8_s")]
+ pub const fn i32x4_extadd_pairwise_i16x8_s(self) -> Self {
+ let lanes = self.as_i16x8();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ let j = i * 2;
+ out[i] = lanes[j] as i32 + lanes[j + 1] as i32;
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i32x4.extadd_pairwise_i16x8_u")]
+ pub const fn i32x4_extadd_pairwise_i16x8_u(self) -> Self {
+ let lanes = self.as_u16x8();
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ let j = i * 2;
+ out[i] = lanes[j] as u32 + lanes[j + 1] as u32;
+ i += 1;
+ }
+ Self::from_u32x4(out)
+ }
+
+ #[doc(alias = "i16x8.extend_low_i8x16_s")]
+ pub const fn i16x8_extend_low_i8x16_s(self) -> Self {
+ let lanes = self.as_i8x16();
+ Self::from_i16x8([
+ lanes[0] as i16,
+ lanes[1] as i16,
+ lanes[2] as i16,
+ lanes[3] as i16,
+ lanes[4] as i16,
+ lanes[5] as i16,
+ lanes[6] as i16,
+ lanes[7] as i16,
+ ])
+ }
+
+ #[doc(alias = "i16x8.extend_low_i8x16_u")]
+ pub const fn i16x8_extend_low_i8x16_u(self) -> Self {
+ let lanes = self.as_u8x16();
+ Self::from_u16x8([
+ lanes[0] as u16,
+ lanes[1] as u16,
+ lanes[2] as u16,
+ lanes[3] as u16,
+ lanes[4] as u16,
+ lanes[5] as u16,
+ lanes[6] as u16,
+ lanes[7] as u16,
+ ])
+ }
+
+ #[doc(alias = "i16x8.extend_high_i8x16_s")]
+ pub const fn i16x8_extend_high_i8x16_s(self) -> Self {
+ let lanes = self.as_i8x16();
+ Self::from_i16x8([
+ lanes[8] as i16,
+ lanes[9] as i16,
+ lanes[10] as i16,
+ lanes[11] as i16,
+ lanes[12] as i16,
+ lanes[13] as i16,
+ lanes[14] as i16,
+ lanes[15] as i16,
+ ])
+ }
+
+ #[doc(alias = "i16x8.extend_high_i8x16_u")]
+ pub const fn i16x8_extend_high_i8x16_u(self) -> Self {
+ let lanes = self.as_u8x16();
+ Self::from_u16x8([
+ lanes[8] as u16,
+ lanes[9] as u16,
+ lanes[10] as u16,
+ lanes[11] as u16,
+ lanes[12] as u16,
+ lanes[13] as u16,
+ lanes[14] as u16,
+ lanes[15] as u16,
+ ])
+ }
+
+ #[doc(alias = "i32x4.extend_low_i16x8_s")]
+ pub const fn i32x4_extend_low_i16x8_s(self) -> Self {
+ let lanes = self.as_i16x8();
+ Self::from_i32x4([lanes[0] as i32, lanes[1] as i32, lanes[2] as i32, lanes[3] as i32])
+ }
+
+ #[doc(alias = "i32x4.extend_low_i16x8_u")]
+ pub const fn i32x4_extend_low_i16x8_u(self) -> Self {
+ let lanes = self.as_u16x8();
+ Self::from_u32x4([lanes[0] as u32, lanes[1] as u32, lanes[2] as u32, lanes[3] as u32])
+ }
+
+ #[doc(alias = "i32x4.extend_high_i16x8_s")]
+ pub const fn i32x4_extend_high_i16x8_s(self) -> Self {
+ let lanes = self.as_i16x8();
+ Self::from_i32x4([lanes[4] as i32, lanes[5] as i32, lanes[6] as i32, lanes[7] as i32])
+ }
+
+ #[doc(alias = "i32x4.extend_high_i16x8_u")]
+ pub const fn i32x4_extend_high_i16x8_u(self) -> Self {
+ let lanes = self.as_u16x8();
+ Self::from_u32x4([lanes[4] as u32, lanes[5] as u32, lanes[6] as u32, lanes[7] as u32])
+ }
+
+ #[doc(alias = "i64x2.extend_low_i32x4_s")]
+ pub const fn i64x2_extend_low_i32x4_s(self) -> Self {
+ let lanes = self.as_i32x4();
+ Self::from_i64x2([lanes[0] as i64, lanes[1] as i64])
+ }
+
+ #[doc(alias = "i64x2.extend_low_i32x4_u")]
+ pub const fn i64x2_extend_low_i32x4_u(self) -> Self {
+ let lanes = self.as_u32x4();
+ Self::from_u64x2([lanes[0] as u64, lanes[1] as u64])
+ }
+
+ #[doc(alias = "i64x2.extend_high_i32x4_s")]
+ pub const fn i64x2_extend_high_i32x4_s(self) -> Self {
+ let lanes = self.as_i32x4();
+ Self::from_i64x2([lanes[2] as i64, lanes[3] as i64])
+ }
+
+ #[doc(alias = "i64x2.extend_high_i32x4_u")]
+ pub const fn i64x2_extend_high_i32x4_u(self) -> Self {
+ let lanes = self.as_u32x4();
+ Self::from_u64x2([lanes[2] as u64, lanes[3] as u64])
+ }
+
+ #[doc(alias = "i16x8.extmul_low_i8x16_s")]
+ pub const fn i16x8_extmul_low_i8x16_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = (a[i] as i16).wrapping_mul(b[i] as i16);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extmul_low_i8x16_u")]
+ pub const fn i16x8_extmul_low_i8x16_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = (a[i] as u16) * (b[i] as u16);
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extmul_high_i8x16_s")]
+ pub const fn i16x8_extmul_high_i8x16_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = (a[i + 8] as i16).wrapping_mul(b[i + 8] as i16);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extmul_high_i8x16_u")]
+ pub const fn i16x8_extmul_high_i8x16_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = (a[i + 8] as u16) * (b[i + 8] as u16);
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i32x4.extmul_low_i16x8_s")]
+ pub const fn i32x4_extmul_low_i16x8_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = (a[i] as i32).wrapping_mul(b[i] as i32);
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i32x4.extmul_low_i16x8_u")]
+ pub const fn i32x4_extmul_low_i16x8_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = (a[i] as u32) * (b[i] as u32);
+ i += 1;
+ }
+ Self::from_u32x4(out)
+ }
+
+ #[doc(alias = "i32x4.extmul_high_i16x8_s")]
+ pub const fn i32x4_extmul_high_i16x8_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = (a[i + 4] as i32).wrapping_mul(b[i + 4] as i32);
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i32x4.extmul_high_i16x8_u")]
+ pub const fn i32x4_extmul_high_i16x8_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = (a[i + 4] as u32) * (b[i + 4] as u32);
+ i += 1;
+ }
+ Self::from_u32x4(out)
+ }
+
+ #[doc(alias = "i64x2.extmul_low_i32x4_s")]
+ pub const fn i64x2_extmul_low_i32x4_s(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = (a[i] as i64).wrapping_mul(b[i] as i64);
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i64x2.extmul_low_i32x4_u")]
+ pub const fn i64x2_extmul_low_i32x4_u(self, rhs: Self) -> Self {
+ let a = self.as_u32x4();
+ let b = rhs.as_u32x4();
+ let mut out = [0u64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = (a[i] as u64) * (b[i] as u64);
+ i += 1;
+ }
+ Self::from_u64x2(out)
+ }
+
+ #[doc(alias = "i64x2.extmul_high_i32x4_s")]
+ pub const fn i64x2_extmul_high_i32x4_s(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = (a[i + 2] as i64).wrapping_mul(b[i + 2] as i64);
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i64x2.extmul_high_i32x4_u")]
+ pub const fn i64x2_extmul_high_i32x4_u(self, rhs: Self) -> Self {
+ let a = self.as_u32x4();
+ let b = rhs.as_u32x4();
+ let mut out = [0u64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = (a[i + 2] as u64) * (b[i + 2] as u64);
+ i += 1;
+ }
+ Self::from_u64x2(out)
+ }
+
+ #[doc(alias = "i16x8.q15mulr_sat_s")]
+ pub const fn i16x8_q15mulr_sat_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ let r = ((a[i] as i32 * b[i] as i32) + 0x4000) >> 15;
+ out[i] = if r > i16::MAX as i32 {
+ i16::MAX
+ } else if r < i16::MIN as i32 {
+ i16::MIN
+ } else {
+ r as i16
+ };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.dot_i16x8_s")]
+ pub const fn i32x4_dot_i16x8_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ Self::from_i32x4([
+ (a[0] as i32).wrapping_mul(b[0] as i32).wrapping_add((a[1] as i32).wrapping_mul(b[1] as i32)),
+ (a[2] as i32).wrapping_mul(b[2] as i32).wrapping_add((a[3] as i32).wrapping_mul(b[3] as i32)),
+ (a[4] as i32).wrapping_mul(b[4] as i32).wrapping_add((a[5] as i32).wrapping_mul(b[5] as i32)),
+ (a[6] as i32).wrapping_mul(b[6] as i32).wrapping_add((a[7] as i32).wrapping_mul(b[7] as i32)),
+ ])
+ }
+
+ #[doc(alias = "i8x16.eq")]
+ pub const fn i8x16_eq(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] == b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.eq")]
+ pub const fn i16x8_eq(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] == b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.eq")]
+ pub const fn i32x4_eq(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] == b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.eq")]
+ pub const fn i64x2_eq(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] == b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.ne")]
+ pub const fn i8x16_ne(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] != b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.ne")]
+ pub const fn i16x8_ne(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] != b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.ne")]
+ pub const fn i32x4_ne(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] != b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.ne")]
+ pub const fn i64x2_ne(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] != b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.lt_s")]
+ pub const fn i8x16_lt_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.lt_s")]
+ pub const fn i16x8_lt_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.lt_s")]
+ pub const fn i32x4_lt_s(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.lt_s")]
+ pub const fn i64x2_lt_s(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.lt_u")]
+ pub const fn i8x16_lt_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.lt_u")]
+ pub const fn i16x8_lt_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.lt_u")]
+ pub const fn i32x4_lt_u(self, rhs: Self) -> Self {
+ let a = self.as_u32x4();
+ let b = rhs.as_u32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i8x16.gt_s")]
+ pub const fn i8x16_gt_s(self, rhs: Self) -> Self {
+ rhs.i8x16_lt_s(self)
+ }
+
+ #[doc(alias = "i16x8.gt_s")]
+ pub const fn i16x8_gt_s(self, rhs: Self) -> Self {
+ rhs.i16x8_lt_s(self)
+ }
+
+ #[doc(alias = "i32x4.gt_s")]
+ pub const fn i32x4_gt_s(self, rhs: Self) -> Self {
+ rhs.i32x4_lt_s(self)
+ }
+
+ #[doc(alias = "i64x2.gt_s")]
+ pub const fn i64x2_gt_s(self, rhs: Self) -> Self {
+ rhs.i64x2_lt_s(self)
+ }
+
+ #[doc(alias = "i8x16.gt_u")]
+ pub const fn i8x16_gt_u(self, rhs: Self) -> Self {
+ rhs.i8x16_lt_u(self)
+ }
+
+ #[doc(alias = "i16x8.gt_u")]
+ pub const fn i16x8_gt_u(self, rhs: Self) -> Self {
+ rhs.i16x8_lt_u(self)
+ }
+
+ #[doc(alias = "i32x4.gt_u")]
+ pub const fn i32x4_gt_u(self, rhs: Self) -> Self {
+ rhs.i32x4_lt_u(self)
+ }
+
+ #[doc(alias = "i8x16.le_s")]
+ pub const fn i8x16_le_s(self, rhs: Self) -> Self {
+ rhs.i8x16_ge_s(self)
+ }
+
+ #[doc(alias = "i16x8.le_s")]
+ pub const fn i16x8_le_s(self, rhs: Self) -> Self {
+ rhs.i16x8_ge_s(self)
+ }
+
+ #[doc(alias = "i32x4.le_s")]
+ pub const fn i32x4_le_s(self, rhs: Self) -> Self {
+ rhs.i32x4_ge_s(self)
+ }
+
+ #[doc(alias = "i64x2.le_s")]
+ pub const fn i64x2_le_s(self, rhs: Self) -> Self {
+ rhs.i64x2_ge_s(self)
+ }
+
+ #[doc(alias = "i8x16.le_u")]
+ pub const fn i8x16_le_u(self, rhs: Self) -> Self {
+ rhs.i8x16_ge_u(self)
+ }
+
+ #[doc(alias = "i16x8.le_u")]
+ pub const fn i16x8_le_u(self, rhs: Self) -> Self {
+ rhs.i16x8_ge_u(self)
+ }
+
+ #[doc(alias = "i32x4.le_u")]
+ pub const fn i32x4_le_u(self, rhs: Self) -> Self {
+ rhs.i32x4_ge_u(self)
+ }
+
+ #[doc(alias = "i8x16.ge_s")]
+ pub const fn i8x16_ge_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.ge_s")]
+ pub const fn i16x8_ge_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.ge_s")]
+ pub const fn i32x4_ge_s(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.ge_s")]
+ pub const fn i64x2_ge_s(self, rhs: Self) -> Self {
+ let a = self.as_i64x2();
+ let b = rhs.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.ge_u")]
+ pub const fn i8x16_ge_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.ge_u")]
+ pub const fn i16x8_ge_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.ge_u")]
+ pub const fn i32x4_ge_u(self, rhs: Self) -> Self {
+ let a = self.as_u32x4();
+ let b = rhs.as_u32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i8x16.abs")]
+ pub const fn i8x16_abs(self) -> Self {
+ let a = self.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].wrapping_abs();
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.abs")]
+ pub const fn i16x8_abs(self) -> Self {
+ let a = self.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].wrapping_abs();
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.abs")]
+ pub const fn i32x4_abs(self) -> Self {
+ let a = self.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = a[i].wrapping_abs();
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.abs")]
+ pub const fn i64x2_abs(self) -> Self {
+ let a = self.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = a[i].wrapping_abs();
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.neg")]
+ pub const fn i8x16_neg(self) -> Self {
+ let a = self.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = a[i].wrapping_neg();
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.neg")]
+ pub const fn i16x8_neg(self) -> Self {
+ let a = self.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = a[i].wrapping_neg();
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.neg")]
+ pub const fn i32x4_neg(self) -> Self {
+ let a = self.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = a[i].wrapping_neg();
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i64x2.neg")]
+ pub const fn i64x2_neg(self) -> Self {
+ let a = self.as_i64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = a[i].wrapping_neg();
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "i8x16.min_s")]
+ pub const fn i8x16_min_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] < b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.min_s")]
+ pub const fn i16x8_min_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] < b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.min_s")]
+ pub const fn i32x4_min_s(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] < b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i8x16.min_u")]
+ pub const fn i8x16_min_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] < b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.min_u")]
+ pub const fn i16x8_min_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] < b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i32x4.min_u")]
+ pub const fn i32x4_min_u(self, rhs: Self) -> Self {
+ let a = self.as_u32x4();
+ let b = rhs.as_u32x4();
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] < b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_u32x4(out)
+ }
+
+ #[doc(alias = "i8x16.max_s")]
+ pub const fn i8x16_max_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] > b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i16x8.max_s")]
+ pub const fn i16x8_max_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] > b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.max_s")]
+ pub const fn i32x4_max_s(self, rhs: Self) -> Self {
+ let a = self.as_i32x4();
+ let b = rhs.as_i32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] > b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i8x16.max_u")]
+ pub const fn i8x16_max_u(self, rhs: Self) -> Self {
+ let a = self.as_u8x16();
+ let b = rhs.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = if a[i] > b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.max_u")]
+ pub const fn i16x8_max_u(self, rhs: Self) -> Self {
+ let a = self.as_u16x8();
+ let b = rhs.as_u16x8();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = if a[i] > b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i32x4.max_u")]
+ pub const fn i32x4_max_u(self, rhs: Self) -> Self {
+ let a = self.as_u32x4();
+ let b = rhs.as_u32x4();
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] > b[i] { a[i] } else { b[i] };
+ i += 1;
+ }
+ Self::from_u32x4(out)
+ }
+
+ #[doc(alias = "f32x4.eq")]
+ pub fn f32x4_eq(self, rhs: Self) -> Self {
+ let a = self.as_f32x4();
+ let b = rhs.as_f32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] == b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "f64x2.eq")]
+ pub fn f64x2_eq(self, rhs: Self) -> Self {
+ let a = self.as_f64x2();
+ let b = rhs.as_f64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] == b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "f32x4.ne")]
+ pub fn f32x4_ne(self, rhs: Self) -> Self {
+ let a = self.as_f32x4();
+ let b = rhs.as_f32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] != b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "f64x2.ne")]
+ pub fn f64x2_ne(self, rhs: Self) -> Self {
+ let a = self.as_f64x2();
+ let b = rhs.as_f64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] != b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "f32x4.lt")]
+ pub fn f32x4_lt(self, rhs: Self) -> Self {
+ let a = self.as_f32x4();
+ let b = rhs.as_f32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "f64x2.lt")]
+ pub fn f64x2_lt(self, rhs: Self) -> Self {
+ let a = self.as_f64x2();
+ let b = rhs.as_f64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] < b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "f32x4.gt")]
+ pub fn f32x4_gt(self, rhs: Self) -> Self {
+ rhs.f32x4_lt(self)
+ }
+
+ #[doc(alias = "f64x2.gt")]
+ pub fn f64x2_gt(self, rhs: Self) -> Self {
+ rhs.f64x2_lt(self)
+ }
+
+ #[doc(alias = "f32x4.le")]
+ pub fn f32x4_le(self, rhs: Self) -> Self {
+ let a = self.as_f32x4();
+ let b = rhs.as_f32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] <= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "f64x2.le")]
+ pub fn f64x2_le(self, rhs: Self) -> Self {
+ let a = self.as_f64x2();
+ let b = rhs.as_f64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] <= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "f32x4.ge")]
+ pub fn f32x4_ge(self, rhs: Self) -> Self {
+ let a = self.as_f32x4();
+ let b = rhs.as_f32x4();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "f64x2.ge")]
+ pub fn f64x2_ge(self, rhs: Self) -> Self {
+ let a = self.as_f64x2();
+ let b = rhs.as_f64x2();
+ let mut out = [0i64; 2];
+ let mut i = 0;
+ while i < 2 {
+ out[i] = if a[i] >= b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::from_i64x2(out)
+ }
+
+ #[doc(alias = "f32x4.ceil")]
+ pub fn f32x4_ceil(self) -> Self {
+ self.map_f32x4(f32::ceil)
+ }
+
+ #[doc(alias = "f64x2.ceil")]
+ pub fn f64x2_ceil(self) -> Self {
+ self.map_f64x2(f64::ceil)
+ }
+
+ #[doc(alias = "f32x4.floor")]
+ pub fn f32x4_floor(self) -> Self {
+ self.map_f32x4(f32::floor)
+ }
+
+ #[doc(alias = "f64x2.floor")]
+ pub fn f64x2_floor(self) -> Self {
+ self.map_f64x2(f64::floor)
+ }
+
+ #[doc(alias = "f32x4.trunc")]
+ pub fn f32x4_trunc(self) -> Self {
+ self.map_f32x4(f32::trunc)
+ }
+
+ #[doc(alias = "f64x2.trunc")]
+ pub fn f64x2_trunc(self) -> Self {
+ self.map_f64x2(f64::trunc)
+ }
+
+ #[doc(alias = "f32x4.nearest")]
+ pub fn f32x4_nearest(self) -> Self {
+ self.map_f32x4(TinywasmFloatExt::tw_nearest)
+ }
+
+ #[doc(alias = "f64x2.nearest")]
+ pub fn f64x2_nearest(self) -> Self {
+ self.map_f64x2(TinywasmFloatExt::tw_nearest)
+ }
+
+ #[doc(alias = "f32x4.abs")]
+ pub fn f32x4_abs(self) -> Self {
+ self.map_f32x4(f32::abs)
+ }
+
+ #[doc(alias = "f64x2.abs")]
+ pub fn f64x2_abs(self) -> Self {
+ self.map_f64x2(f64::abs)
+ }
+
+ #[doc(alias = "f32x4.neg")]
+ pub fn f32x4_neg(self) -> Self {
+ self.map_f32x4(|x| -x)
+ }
+
+ #[doc(alias = "f64x2.neg")]
+ pub fn f64x2_neg(self) -> Self {
+ self.map_f64x2(|x| -x)
+ }
+
+ #[doc(alias = "f32x4.sqrt")]
+ pub fn f32x4_sqrt(self) -> Self {
+ self.map_f32x4(|x| Self::canonicalize_simd_f32_nan(x.sqrt()))
+ }
+
+ #[doc(alias = "f64x2.sqrt")]
+ pub fn f64x2_sqrt(self) -> Self {
+ self.map_f64x2(|x| Self::canonicalize_simd_f64_nan(x.sqrt()))
+ }
+
+ #[doc(alias = "f32x4.add")]
+ pub fn f32x4_add(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a + b))
+ }
+
+ #[doc(alias = "f64x2.add")]
+ pub fn f64x2_add(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a + b))
+ }
+
+ #[doc(alias = "f32x4.sub")]
+ pub fn f32x4_sub(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a - b))
+ }
+
+ #[doc(alias = "f64x2.sub")]
+ pub fn f64x2_sub(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a - b))
+ }
+
+ #[doc(alias = "f32x4.mul")]
+ pub fn f32x4_mul(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a * b))
+ }
+
+ #[doc(alias = "f64x2.mul")]
+ pub fn f64x2_mul(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a * b))
+ }
+
+ #[doc(alias = "f32x4.div")]
+ pub fn f32x4_div(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a / b))
+ }
+
+ #[doc(alias = "f64x2.div")]
+ pub fn f64x2_div(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a / b))
+ }
+
+ #[doc(alias = "f32x4.min")]
+ pub fn f32x4_min(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, TinywasmFloatExt::tw_minimum)
+ }
+
+ #[doc(alias = "f64x2.min")]
+ pub fn f64x2_min(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, TinywasmFloatExt::tw_minimum)
+ }
+
+ #[doc(alias = "f32x4.max")]
+ pub fn f32x4_max(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, TinywasmFloatExt::tw_maximum)
+ }
+
+ #[doc(alias = "f64x2.max")]
+ pub fn f64x2_max(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, TinywasmFloatExt::tw_maximum)
+ }
+
+ #[doc(alias = "f32x4.pmin")]
+ pub fn f32x4_pmin(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| if b < a { b } else { a })
+ }
+
+ #[doc(alias = "f64x2.pmin")]
+ pub fn f64x2_pmin(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| if b < a { b } else { a })
+ }
+
+ #[doc(alias = "f32x4.pmax")]
+ pub fn f32x4_pmax(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| if b > a { b } else { a })
+ }
+
+ #[doc(alias = "f64x2.pmax")]
+ pub fn f64x2_pmax(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| if b > a { b } else { a })
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f32x4_s")]
+ pub fn i32x4_trunc_sat_f32x4_s(self) -> Self {
+ let v = self.as_f32x4();
+ Self::from_i32x4([
+ trunc_sat_f32_to_i32(v[0]),
+ trunc_sat_f32_to_i32(v[1]),
+ trunc_sat_f32_to_i32(v[2]),
+ trunc_sat_f32_to_i32(v[3]),
+ ])
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f32x4_u")]
+ pub fn i32x4_trunc_sat_f32x4_u(self) -> Self {
+ let v = self.as_f32x4();
+ Self::from_u32x4([
+ trunc_sat_f32_to_u32(v[0]),
+ trunc_sat_f32_to_u32(v[1]),
+ trunc_sat_f32_to_u32(v[2]),
+ trunc_sat_f32_to_u32(v[3]),
+ ])
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f64x2_s_zero")]
+ pub fn i32x4_trunc_sat_f64x2_s_zero(self) -> Self {
+ let v = self.as_f64x2();
+ Self::from_i32x4([trunc_sat_f64_to_i32(v[0]), trunc_sat_f64_to_i32(v[1]), 0, 0])
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f64x2_u_zero")]
+ pub fn i32x4_trunc_sat_f64x2_u_zero(self) -> Self {
+ let v = self.as_f64x2();
+ Self::from_u32x4([trunc_sat_f64_to_u32(v[0]), trunc_sat_f64_to_u32(v[1]), 0, 0])
+ }
+
+ #[doc(alias = "f32x4.convert_i32x4_s")]
+ pub fn f32x4_convert_i32x4_s(self) -> Self {
+ let v = self.as_i32x4();
+ Self::from_f32x4([v[0] as f32, v[1] as f32, v[2] as f32, v[3] as f32])
+ }
+
+ #[doc(alias = "f32x4.convert_i32x4_u")]
+ pub fn f32x4_convert_i32x4_u(self) -> Self {
+ let v = self.as_u32x4();
+ Self::from_f32x4([v[0] as f32, v[1] as f32, v[2] as f32, v[3] as f32])
+ }
+
+ #[doc(alias = "f64x2.convert_low_i32x4_s")]
+ pub fn f64x2_convert_low_i32x4_s(self) -> Self {
+ let v = self.as_i32x4();
+ Self::from_f64x2([v[0] as f64, v[1] as f64])
+ }
+
+ #[doc(alias = "f64x2.convert_low_i32x4_u")]
+ pub fn f64x2_convert_low_i32x4_u(self) -> Self {
+ let v = self.as_u32x4();
+ Self::from_f64x2([v[0] as f64, v[1] as f64])
+ }
+
+ #[doc(alias = "f32x4.demote_f64x2_zero")]
+ pub fn f32x4_demote_f64x2_zero(self) -> Self {
+ let v = self.as_f64x2();
+ Self::from_f32x4([v[0] as f32, v[1] as f32, 0.0, 0.0])
+ }
+
+ #[doc(alias = "f64x2.promote_low_f32x4")]
+ pub fn f64x2_promote_low_f32x4(self) -> Self {
+ let v = self.as_f32x4();
+ Self::from_f64x2([v[0] as f64, v[1] as f64])
+ }
+
pub const fn splat_i16(src: i16) -> Self {
let mut result_bytes = [0u8; 16];
let bytes = src.to_le_bytes();
@@ -395,3 +2559,51 @@ impl core::ops::BitXor for Value128 {
Self(self.0 ^ rhs.0)
}
}
+
+#[inline]
+fn trunc_sat_f32_to_i32(v: f32) -> i32 {
+ if v.is_nan() {
+ 0
+ } else if v <= -2147483904.0_f32 {
+ i32::MIN
+ } else if v >= 2147483648.0_f32 {
+ i32::MAX
+ } else {
+ v.trunc() as i32
+ }
+}
+
+#[inline]
+fn trunc_sat_f32_to_u32(v: f32) -> u32 {
+ if v.is_nan() || v <= -1.0_f32 {
+ 0
+ } else if v >= 4294967296.0_f32 {
+ u32::MAX
+ } else {
+ v.trunc() as u32
+ }
+}
+
+#[inline]
+fn trunc_sat_f64_to_i32(v: f64) -> i32 {
+ if v.is_nan() {
+ 0
+ } else if v <= -2147483649.0_f64 {
+ i32::MIN
+ } else if v >= 2147483648.0_f64 {
+ i32::MAX
+ } else {
+ v.trunc() as i32
+ }
+}
+
+#[inline]
+fn trunc_sat_f64_to_u32(v: f64) -> u32 {
+ if v.is_nan() || v <= -1.0_f64 {
+ 0
+ } else if v >= 4294967296.0_f64 {
+ u32::MAX
+ } else {
+ v.trunc() as u32
+ }
+}
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index 8898212..65c4361 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::{MemoryArch, MemoryType, ModuleInstanceAddr};
-use crate::{Error, Result, cold, interpreter::Value128, log};
+use crate::{cold, interpreter::Value128, log, Error, Result};
/// A WebAssembly Memory Instance
///
diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv
index 5603ed0..96d9796 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,2867,23122,[{"name":"simd_address.wast","passed":49,"failed":0},{"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":139,"failed":138},{"name":"simd_const.wast","passed":755,"failed":2},{"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":30,"failed":0},{"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":14,"failed":18},{"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":328,"failed":147},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":30,"failed":9},{"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":36,"failed":68},{"name":"simd_load_splat.wast","passed":126,"failed":0},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":158,"failed":27},{"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":52,"failed":0}]
+0.9.0-alpha.0,25964,25,[{"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":276,"failed":6},{"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":192,"failed":9},{"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":192,"failed":9},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":172,"failed":0},{"name":"simd_i16x8_cmp.wast","passed":465,"failed":0},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":21,"failed":0},{"name":"simd_i16x8_extmul_i8x16.wast","passed":117,"failed":0},{"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":475,"failed":0},{"name":"simd_i32x4_dot_i16x8.wast","passed":32,"failed":0},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":21,"failed":0},{"name":"simd_i32x4_extmul_i16x8.wast","passed":117,"failed":0},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":107,"failed":0},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":107,"failed":0},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":113,"failed":0},{"name":"simd_i64x2_extmul_i32x4.wast","passed":117,"failed":0},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":211,"failed":0},{"name":"simd_i8x16_cmp.wast","passed":445,"failed":0},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":253,"failed":0},{"name":"simd_lane.wast","passed":475,"failed":0},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":39,"failed":0},{"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":104,"failed":0},{"name":"simd_load_splat.wast","passed":126,"failed":0},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":185,"failed":0},{"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}]