summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2026-01-05 21:22:31 +0100
committerHenry Gressmann <mail@henrygressmann.de>2026-01-05 21:22:31 +0100
commitdd8f0cad73c690be7d4c441e0d8f4aba6ceec227 (patch)
tree07e54522ff0a0d02ec86195911be461c741264cc
parent2911204b3b2508c729c2584016cccd3ef57ffc91 (diff)
chore: more simd stuff
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--Cargo.lock58
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs160
-rw-r--r--crates/tinywasm/src/interpreter/value128.rs180
-rw-r--r--crates/tinywasm/tests/generated/wasm-simd.csv2
4 files changed, 289 insertions, 111 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bc5a5fd..bd7be3a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -78,9 +78,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bumpalo"
-version = "3.19.0"
+version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "cast"
@@ -90,9 +90,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
-version = "1.2.49"
+version = "1.2.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
+checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -133,18 +133,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.53"
+version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.53"
+version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
dependencies = [
"anstyle",
"clap_lex",
@@ -279,9 +279,9 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
-version = "0.1.5"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
+checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
[[package]]
name = "half"
@@ -369,9 +369,9 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.15"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "leb128fmt"
@@ -381,9 +381,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libc"
-version = "0.2.178"
+version = "0.2.179"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
+checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
[[package]]
name = "libm"
@@ -393,9 +393,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "log"
-version = "0.4.28"
+version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "memchr"
@@ -464,9 +464,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.103"
+version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
dependencies = [
"unicode-ident",
]
@@ -536,12 +536,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2"
[[package]]
-name = "ryu"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
-
-[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -588,15 +582,15 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.145"
+version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
dependencies = [
"itoa",
"memchr",
- "ryu",
"serde",
"serde_core",
+ "zmij",
]
[[package]]
@@ -607,9 +601,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
-version = "2.0.111"
+version = "2.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
+checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
dependencies = [
"proc-macro2",
"quote",
@@ -855,3 +849,9 @@ dependencies = [
"quote",
"syn",
]
+
+[[package]]
+name = "zmij"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcb2c125bd7365735bebeb420ccb880265ed2d2bddcbcd49f597fdfe6bd5e577"
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index f026244..c186c01 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -338,30 +338,24 @@ impl<'store, 'stack> Executor<'store, 'stack> {
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| {
- let bytes = v.to_le_bytes();
- Value128::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
- })?,
- V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| {
- let bytes = v.to_le_bytes();
- Value128::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], 0, 0, 0, 0, 0, 0, 0, 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()),
- // I8x16ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?,
- // I8x16ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?,
- // I16x8ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?,
- // I16x8ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?,
- // I32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize])).to_cf()?,
- // I64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, i64>(|v| Ok(v[*lane as usize])).to_cf()?,
- // F32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, f32>(|v| Ok(v[*lane as usize])).to_cf()?,
- // F64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, f64>(|v| Ok(v[*lane as usize])).to_cf()?,
+ 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()?,
- // V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, i8x16, 1>(arg.mem_addr(), arg.offset(), *lane)?,
- // V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, i16x8, 2>(arg.mem_addr(), arg.offset(), *lane)?,
- // V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, i32x4, 4>(arg.mem_addr(), arg.offset(), *lane)?,
- // V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, i64x2, 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!(),
@@ -370,12 +364,12 @@ impl<'store, 'stack> Executor<'store, 'stack> {
// F32x4ReplaceLane(_lane) => unimplemented!(),
// F64x2ReplaceLane(_lane) => unimplemented!(),
- // I8x16Splat => self.stack.values.replace_top::<i32, i8x16>(|v| Ok(Simd::<i8, 16>::splat(v as i8))).to_cf()?,
- // I16x8Splat => self.stack.values.replace_top::<i32, i16x8>(|v| Ok(Simd::<i16, 8>::splat(v as i16))).to_cf()?,
- // I32x4Splat => self.stack.values.replace_top::<i32, i32x4>(|v| Ok(Simd::<i32, 4>::splat(v))).to_cf()?,
- // I64x2Splat => self.stack.values.replace_top::<i64, i64x2>(|v| Ok(Simd::<i64, 2>::splat(v))).to_cf()?,
- // F32x4Splat => self.stack.values.replace_top::<f32, f32x4>(|v| Ok(Simd::<f32, 4>::splat(v))).to_cf()?,
- // F64x2Splat => self.stack.values.replace_top::<f64, f64x2>(|v| Ok(Simd::<f64, 2>::splat(v))).to_cf()?,
+ 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()?,
// 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()?,
@@ -551,41 +545,44 @@ impl<'store, 'stack> Executor<'store, 'stack> {
// I8x16Popcnt => self.stack.values.replace_top::<i8x16, _>(|v| Ok(v.count_ones())).to_cf()?,
// I8x16Shuffle(_idx) => unimplemented!(),
-
- // I16x8Q15MulrSatS => self.stack.values.calculate_same::<i16x8>(|a, b| {
- // let subq15mulr = |a,b| {
- // let a = a as i32;
- // let b = b as i32;
- // let r = (a * b + 0x4000) >> 15;
- // if r > i16::MAX as i32 {
- // i16::MAX
- // } else if r < i16::MIN as i32 {
- // i16::MIN
- // } else {
- // r as i16
- // }
- // };
- // Ok(Simd::<i16, 8>::from_array([
- // subq15mulr(a[0], b[0]),
- // subq15mulr(a[1], b[1]),
- // subq15mulr(a[2], b[2]),
- // subq15mulr(a[3], b[3]),
- // subq15mulr(a[4], b[4]),
- // subq15mulr(a[5], b[5]),
- // subq15mulr(a[6], b[6]),
- // subq15mulr(a[7], b[7]),
- // ]))
- // }).to_cf()?,
+ 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()?,
- // I32x4DotI16x8S => self.stack.values.calculate::<i16x8, i32x4>(|a, b| {
- // Ok(Simd::<i32, 4>::from_array([
- // i32::from(a[0] * b[0] + a[1] * b[1]),
- // i32::from(a[2] * b[2] + a[3] * b[3]),
- // i32::from(a[4] * b[4] + a[5] * b[5]),
- // i32::from(a[6] * b[6] + a[7] * b[7]),
- // ]))
- // }).to_cf()?,
+ 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()?,
// 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()?,
@@ -1038,30 +1035,31 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
}
- // fn exec_mem_load_lane<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize>(
- // &mut self,
- // mem_addr: tinywasm_types::MemAddr,
- // offset: u64,
- // lane: u8,
- // ) -> ControlFlow<Option<Error>> {
- // let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr));
- // let mut imm = self.stack.values.pop::<Value128>().to_mem_bytes();
- // let val = self.stack.values.pop::<i32>() as u64;
- // let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else {
- // cold();
- // return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
- // offset: val as usize,
- // len: LOAD_SIZE,
- // max: 0,
- // })));
- // };
- // let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?.to_mem_bytes();
+ fn exec_mem_load_lane<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize>(
+ &mut self,
+ mem_addr: tinywasm_types::MemAddr,
+ offset: u64,
+ lane: u8,
+ ) -> ControlFlow<Option<Error>> {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr));
+ let mut imm = self.stack.values.pop::<Value128>().to_mem_bytes();
+ let val = self.stack.values.pop::<i32>() as u64;
+ let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else {
+ cold();
+ return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
+ offset: val as usize,
+ len: LOAD_SIZE,
+ max: 0,
+ })));
+ };
+ let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?.to_mem_bytes();
- // // imm[lane as usize] = val;
+ let offset = lane as usize * LOAD_SIZE;
+ imm[offset..offset + LOAD_SIZE].copy_from_slice(&val);
- // self.stack.values.push(Value128::from_mem_bytes(imm));
- // ControlFlow::Continue(())
- // }
+ self.stack.values.push(Value128::from_mem_bytes(imm));
+ ControlFlow::Continue(())
+ }
fn exec_mem_load<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize, TARGET: InternalValue>(
&mut self,
diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs
index b9c96a9..fcd208f 100644
--- a/crates/tinywasm/src/interpreter/value128.rs
+++ b/crates/tinywasm/src/interpreter/value128.rs
@@ -10,6 +10,115 @@ impl Value128 {
self.0.to_le_bytes()
}
+ #[rustfmt::skip]
+ pub const fn as_i8x16(self) -> [i8; 16] {
+ let b = self.to_le_bytes();
+ [b[0] as i8, b[1] as i8, b[2] as i8, b[3] as i8, b[4] as i8, b[5] as i8, b[6] as i8, b[7] as i8, b[8] as i8, b[9] as i8, b[10] as i8, b[11] as i8, b[12] as i8, b[13] as i8, b[14] as i8, b[15] as i8]
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_u8x16(self) -> [u8; 16] {
+ self.to_le_bytes()
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_i8x16(x: [i8; 16]) -> Self {
+ Self::from_le_bytes([x[0] as u8, x[1] as u8, x[2] as u8, x[3] as u8, x[4] as u8, x[5] as u8, x[6] as u8, x[7] as u8, x[8] as u8, x[9] as u8, x[10] as u8, x[11] as u8, x[12] as u8, x[13] as u8, x[14] as u8, x[15] as u8])
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_u8x16(x: [u8; 16]) -> Self {
+ Self::from_le_bytes(x)
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_i16x8(self) -> [i16; 8] {
+ let b = self.to_le_bytes();
+ [i16::from_le_bytes([b[0], b[1]]), i16::from_le_bytes([b[2], b[3]]), i16::from_le_bytes([b[4], b[5]]), i16::from_le_bytes([b[6], b[7]]), i16::from_le_bytes([b[8], b[9]]), i16::from_le_bytes([b[10], b[11]]), i16::from_le_bytes([b[12], b[13]]), i16::from_le_bytes([b[14], b[15]])]
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_u16x8(self) -> [u16; 8] {
+ let b = self.to_le_bytes();
+ [u16::from_le_bytes([b[0], b[1]]), u16::from_le_bytes([b[2], b[3]]), u16::from_le_bytes([b[4], b[5]]), u16::from_le_bytes([b[6], b[7]]), u16::from_le_bytes([b[8], b[9]]), u16::from_le_bytes([b[10], b[11]]), u16::from_le_bytes([b[12], b[13]]), u16::from_le_bytes([b[14], b[15]])]
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_i16x8(x: [i16; 8]) -> Self {
+ Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_u16x8(x: [u16; 8]) -> Self {
+ Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_i32x4(self) -> [i32; 4] {
+ let b = self.to_le_bytes();
+ [i32::from_le_bytes([b[0], b[1], b[2], b[3]]), i32::from_le_bytes([b[4], b[5], b[6], b[7]]), i32::from_le_bytes([b[8], b[9], b[10], b[11]]), i32::from_le_bytes([b[12], b[13], b[14], b[15]])]
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_u32x4(self) -> [u32; 4] {
+ let b = self.to_le_bytes();
+ [u32::from_le_bytes([b[0], b[1], b[2], b[3]]), u32::from_le_bytes([b[4], b[5], b[6], b[7]]), u32::from_le_bytes([b[8], b[9], b[10], b[11]]), u32::from_le_bytes([b[12], b[13], b[14], b[15]])]
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_f32x4(self) -> [f32; 4] {
+ let b = self.to_le_bytes();
+ [f32::from_bits(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), f32::from_bits(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), f32::from_bits(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), f32::from_bits(u32::from_le_bytes([b[12], b[13], b[14], b[15]]))]
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_i32x4(x: [i32; 4]) -> Self {
+ Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_u32x4(x: [u32; 4]) -> Self {
+ Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_f32x4(x: [f32; 4]) -> Self {
+ 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[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[2].to_bits().to_le_bytes()[0], x[2].to_bits().to_le_bytes()[1], x[2].to_bits().to_le_bytes()[2], x[2].to_bits().to_le_bytes()[3], x[3].to_bits().to_le_bytes()[0], x[3].to_bits().to_le_bytes()[1], x[3].to_bits().to_le_bytes()[2], x[3].to_bits().to_le_bytes()[3]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_i64x2(self) -> [i64; 2] {
+ let b = self.to_le_bytes();
+ [i64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), i64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])]
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_u64x2(self) -> [u64; 2] {
+ let b = self.to_le_bytes();
+ [u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])]
+ }
+
+ #[rustfmt::skip]
+ pub const fn as_f64x2(self) -> [f64; 2] {
+ let b = self.to_le_bytes();
+ [f64::from_bits(u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])), f64::from_bits(u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]]))]
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_i64x2(x: [i64; 2]) -> Self {
+ Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_u64x2(x: [u64; 2]) -> Self {
+ Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]])
+ }
+
+ #[rustfmt::skip]
+ pub const fn from_f64x2(x: [f64; 2]) -> Self {
+ 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]])
+ }
+
pub const fn reduce_or(self) -> u8 {
let mut result = 0u8;
let bytes = self.to_le_bytes();
@@ -174,6 +283,77 @@ impl Value128 {
}
Self::from_le_bytes(result_bytes)
}
+
+ pub const fn splat_f32(src: f32) -> Self {
+ Self::splat_i32(src.to_bits() as i32)
+ }
+
+ pub const fn splat_f64(src: f64) -> Self {
+ Self::splat_i64(src.to_bits() as i64)
+ }
+
+ pub const fn extract_lane_i8(self, lane: u8) -> i8 {
+ debug_assert!(lane < 16);
+ let lane = lane as usize;
+ let bytes = self.to_le_bytes();
+ bytes[lane] as i8
+ }
+
+ pub const fn extract_lane_u8(self, lane: u8) -> u8 {
+ debug_assert!(lane < 16);
+ let lane = lane as usize;
+ let bytes = self.to_le_bytes();
+ bytes[lane]
+ }
+
+ pub const fn extract_lane_i16(self, lane: u8) -> i16 {
+ debug_assert!(lane < 8);
+ let lane = lane as usize;
+ let bytes = self.to_le_bytes();
+ let start = lane * 2;
+ i16::from_le_bytes([bytes[start], bytes[start + 1]])
+ }
+
+ pub const fn extract_lane_u16(self, lane: u8) -> u16 {
+ debug_assert!(lane < 8);
+ let lane = lane as usize;
+ let bytes = self.to_le_bytes();
+ let start = lane * 2;
+ u16::from_le_bytes([bytes[start], bytes[start + 1]])
+ }
+
+ pub const fn extract_lane_i32(self, lane: u8) -> i32 {
+ debug_assert!(lane < 4);
+ let lane = lane as usize;
+ let bytes = self.to_le_bytes();
+ let start = lane * 4;
+ i32::from_le_bytes([bytes[start], bytes[start + 1], bytes[start + 2], bytes[start + 3]])
+ }
+
+ pub const fn extract_lane_i64(self, lane: u8) -> i64 {
+ debug_assert!(lane < 2);
+ let lane = lane as usize;
+ let bytes = self.to_le_bytes();
+ let start = lane * 8;
+ i64::from_le_bytes([
+ bytes[start],
+ bytes[start + 1],
+ bytes[start + 2],
+ bytes[start + 3],
+ bytes[start + 4],
+ bytes[start + 5],
+ bytes[start + 6],
+ bytes[start + 7],
+ ])
+ }
+
+ pub const fn extract_lane_f32(self, lane: u8) -> f32 {
+ f32::from_bits(self.extract_lane_i32(lane) as u32)
+ }
+
+ pub const fn extract_lane_f64(self, lane: u8) -> f64 {
+ f64::from_bits(self.extract_lane_i64(lane) as u64)
+ }
}
impl From<Value128> for i128 {
diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv
index f87cc69..5603ed0 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,2460,23529,[{"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":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":28},{"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":213,"failed":262},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":29,"failed":10},{"name":"simd_load16_lane.wast","passed":4,"failed":32},{"name":"simd_load32_lane.wast","passed":4,"failed":20},{"name":"simd_load64_lane.wast","passed":4,"failed":12},{"name":"simd_load8_lane.wast","passed":4,"failed":48},{"name":"simd_load_extend.wast","passed":30,"failed":74},{"name":"simd_load_splat.wast","passed":122,"failed":4},{"name":"simd_load_zero.wast","passed":37,"failed":2},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":27,"failed":158},{"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,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}]