summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-04-03 23:40:04 +0200
committerHenry <mail@henrygressmann.de>2026-04-03 23:40:04 +0200
commit1f741ba37d8217de333488d0a66fa6cc7f8537a7 (patch)
tree0c37368d8160668b3a79bee4bc2b068be41e6cea
parenta15acabfc1e23282d8fba9ec660f593b96709b2a (diff)
feat: add relaxed simd
Signed-off-by: Henry <mail@henrygressmann.de>
-rw-r--r--README.md2
-rw-r--r--crates/parser/src/lib.rs2
-rw-r--r--crates/parser/src/visit.rs15
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs28
-rw-r--r--crates/tinywasm/src/interpreter/value128.rs128
-rw-r--r--crates/tinywasm/tests/generated/wasm-relaxed-simd.csv2
-rw-r--r--crates/tinywasm/tests/test-wast.rs3
-rw-r--r--crates/tinywasm/tests/testsuite/run.rs32
-rw-r--r--crates/tinywasm/tests/testsuite/util.rs34
-rw-r--r--crates/types/src/instructions.rs28
-rwxr-xr-xprofile.sh3
-rw-r--r--tinywasm.pngbin115910 -> 0 bytes
12 files changed, 234 insertions, 43 deletions
diff --git a/README.md b/README.md
index f8f4f7f..cb3a475 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ Untrusted WebAssembly code should not be able to crash the runtime or access mem
| [**Fixed-Width SIMD**](https://github.com/WebAssembly/simd/blob/main/proposals/simd/Overview.md) | 🟢 | `next` |
| [**Memory64**](https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md) | 🟢 | `next` |
| [**Tail Call**](https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md) | 🟢 | `next` |
-| [**Relaxed SIMD**](https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md) | 🚧 | - |
+| [**Relaxed SIMD**](https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md) | 🟢 | `next` |
| [**Wide Arithmetic**](https://github.com/WebAssembly/wide-arithmetic/blob/main/proposals/wide-arithmetic/Overview.md) | 🚧 | - |
| [**Custom Descriptors**](https://github.com/WebAssembly/custom-descriptors/blob/main/proposals/custom-descriptors/Overview.md) | 🌑 | - |
| [**Exception Handling**](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md) | 🌑 | - |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index ff2cacf..a799f69 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -79,7 +79,7 @@ impl Parser {
exceptions: false,
gc: false,
memory_control: false,
- relaxed_simd: false,
+ relaxed_simd: true,
threads: false,
shared_everything_threads: false,
legacy_exceptions: false,
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 7eefa1c..e3de009 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -363,6 +363,7 @@ macro_rules! impl_visit_operator {
(@@saturating_float_to_int $($rest:tt)* ) => {};
(@@bulk_memory $($rest:tt)* ) => {};
(@@simd $($rest:tt)* ) => {};
+ (@@relaxed_simd $($rest:tt)* ) => {};
(@@tail_call $($rest:tt)* ) => {};
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => {
@@ -830,6 +831,7 @@ macro_rules! impl_visit_simd_operator {
};
(@@simd $($rest:tt)* ) => {};
+ (@@relaxed_simd $($rest:tt)* ) => {};
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => {
fn $visit(&mut self $($(,$arg: $argty)*)?) {
self.unsupported(stringify!($visit))
@@ -879,6 +881,19 @@ impl<R: WasmModuleResources> wasmparser::VisitSimdOperator<'_> for FunctionBuild
visit_f64x2_convert_low_i32x4_s(F64x2ConvertLowI32x4S), visit_f64x2_convert_low_i32x4_u(F64x2ConvertLowI32x4U),
visit_f32x4_demote_f64x2_zero(F32x4DemoteF64x2Zero), visit_f64x2_promote_low_f32x4(F64x2PromoteLowF32x4),
+ visit_i8x16_relaxed_swizzle(I8x16RelaxedSwizzle),
+ visit_i32x4_relaxed_trunc_f32x4_s(I32x4RelaxedTruncF32x4S), visit_i32x4_relaxed_trunc_f32x4_u(I32x4RelaxedTruncF32x4U),
+ visit_i32x4_relaxed_trunc_f64x2_s_zero(I32x4RelaxedTruncF64x2SZero), visit_i32x4_relaxed_trunc_f64x2_u_zero(I32x4RelaxedTruncF64x2UZero),
+ visit_f32x4_relaxed_madd(F32x4RelaxedMadd), visit_f32x4_relaxed_nmadd(F32x4RelaxedNmadd),
+ visit_f64x2_relaxed_madd(F64x2RelaxedMadd), visit_f64x2_relaxed_nmadd(F64x2RelaxedNmadd),
+ visit_i8x16_relaxed_laneselect(I8x16RelaxedLaneselect), visit_i16x8_relaxed_laneselect(I16x8RelaxedLaneselect),
+ visit_i32x4_relaxed_laneselect(I32x4RelaxedLaneselect), visit_i64x2_relaxed_laneselect(I64x2RelaxedLaneselect),
+ visit_f32x4_relaxed_min(F32x4RelaxedMin), visit_f32x4_relaxed_max(F32x4RelaxedMax),
+ visit_f64x2_relaxed_min(F64x2RelaxedMin), visit_f64x2_relaxed_max(F64x2RelaxedMax),
+ visit_i16x8_relaxed_q15mulr_s(I16x8RelaxedQ15mulrS),
+ visit_i16x8_relaxed_dot_i8x16_i7x16_s(I16x8RelaxedDotI8x16I7x16S),
+ visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(I32x4RelaxedDotI8x16I7x16AddS),
+
visit_i8x16_extract_lane_s(I8x16ExtractLaneS, u8), visit_i8x16_extract_lane_u(I8x16ExtractLaneU, u8), visit_i8x16_replace_lane(I8x16ReplaceLane, u8),
visit_i16x8_extract_lane_s(I16x8ExtractLaneS, u8), visit_i16x8_extract_lane_u(I16x8ExtractLaneU, u8), visit_i16x8_replace_lane(I16x8ReplaceLane, u8),
visit_i32x4_extract_lane(I32x4ExtractLane, u8), visit_i32x4_replace_lane(I32x4ReplaceLane, u8),
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 85208bf..17343ee 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -152,12 +152,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
LocalCopy64(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value64>(&self.cf, *from)),
LocalCopy128(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value128>(&self.cf, *from)),
LocalCopyRef(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<ValueRef>(&self.cf, *from)),
- I32AddLocals(a, b) => self.store.stack.values.push(
- self.store.stack.values.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i32>(&self.cf, *b)),
- )?,
- I64AddLocals(a, b) => self.store.stack.values.push(
- self.store.stack.values.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i64>(&self.cf, *b)),
- )?,
+ I32AddLocals(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i32>(&self.cf, *b)))?,
+ I64AddLocals(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i64>(&self.cf, *b)))?,
I32AddConst(c) => stack_op!(unary i32, |v| v.wrapping_add(*c)),
I64AddConst(c) => stack_op!(unary i64, |v| v.wrapping_add(*c)),
I32StoreLocalLocal(m, addr_local, value_local) => {
@@ -394,6 +390,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
V128Bitselect => stack_op!(ternary Value128, |v1, v2, c| Value128::v128_bitselect(v1, v2, c)),
V128AnyTrue => stack_op!(unary Value128 => i32, |v| v.v128_any_true() as i32),
I8x16Swizzle => stack_op!(binary Value128, |a, s| a.i8x16_swizzle(s)),
+ I8x16RelaxedSwizzle => stack_op!(binary Value128, |a, s| a.i8x16_relaxed_swizzle(s)),
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()))?,
@@ -582,6 +579,13 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
I8x16Shuffle(idx) => { let idx = self.func.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)),
I32x4DotI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_dot_i16x8_s(b)),
+ I8x16RelaxedLaneselect => stack_op!(ternary Value128, |v1, v2, c| Value128::i8x16_relaxed_laneselect(v1, v2, c)),
+ I16x8RelaxedLaneselect => stack_op!(ternary Value128, |v1, v2, c| Value128::i16x8_relaxed_laneselect(v1, v2, c)),
+ I32x4RelaxedLaneselect => stack_op!(ternary Value128, |v1, v2, c| Value128::i32x4_relaxed_laneselect(v1, v2, c)),
+ I64x2RelaxedLaneselect => stack_op!(ternary Value128, |v1, v2, c| Value128::i64x2_relaxed_laneselect(v1, v2, c)),
+ I16x8RelaxedQ15mulrS => stack_op!(binary Value128, |a, b| a.i16x8_relaxed_q15mulr_s(b)),
+ I16x8RelaxedDotI8x16I7x16S => stack_op!(binary Value128, |a, b| a.i16x8_relaxed_dot_i8x16_i7x16_s(b)),
+ I32x4RelaxedDotI8x16I7x16AddS => stack_op!(ternary Value128, |a, b, c| a.i32x4_relaxed_dot_i8x16_i7x16_add_s(b, c)),
F32x4Ceil => stack_op!(simd_unary f32x4_ceil),
F64x2Ceil => stack_op!(simd_unary f64x2_ceil),
F32x4Floor => stack_op!(simd_unary f32x4_floor),
@@ -612,6 +616,14 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
F32x4PMax => stack_op!(simd_binary f32x4_pmax),
F64x2PMin => stack_op!(simd_binary f64x2_pmin),
F64x2PMax => stack_op!(simd_binary f64x2_pmax),
+ F32x4RelaxedMadd => stack_op!(ternary Value128, |a, b, c| a.f32x4_relaxed_madd(b, c)),
+ F32x4RelaxedNmadd => stack_op!(ternary Value128, |a, b, c| a.f32x4_relaxed_nmadd(b, c)),
+ F64x2RelaxedMadd => stack_op!(ternary Value128, |a, b, c| a.f64x2_relaxed_madd(b, c)),
+ F64x2RelaxedNmadd => stack_op!(ternary Value128, |a, b, c| a.f64x2_relaxed_nmadd(b, c)),
+ F32x4RelaxedMin => stack_op!(binary Value128, |a, b| a.f32x4_relaxed_min(b)),
+ F32x4RelaxedMax => stack_op!(binary Value128, |a, b| a.f32x4_relaxed_max(b)),
+ F64x2RelaxedMin => stack_op!(binary Value128, |a, b| a.f64x2_relaxed_min(b)),
+ F64x2RelaxedMax => stack_op!(binary Value128, |a, b| a.f64x2_relaxed_max(b)),
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()),
@@ -622,6 +634,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
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()),
+ I32x4RelaxedTruncF32x4S => stack_op!(unary Value128, |v| v.i32x4_relaxed_trunc_f32x4_s()),
+ I32x4RelaxedTruncF32x4U => stack_op!(unary Value128, |v| v.i32x4_relaxed_trunc_f32x4_u()),
+ I32x4RelaxedTruncF64x2SZero => stack_op!(unary Value128, |v| v.i32x4_relaxed_trunc_f64x2_s_zero()),
+ I32x4RelaxedTruncF64x2UZero => stack_op!(unary Value128, |v| v.i32x4_relaxed_trunc_f64x2_u_zero()),
};
self.cf.incr_instr_ptr();
diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs
index 9ccb7fc..c585b35 100644
--- a/crates/tinywasm/src/interpreter/value128.rs
+++ b/crates/tinywasm/src/interpreter/value128.rs
@@ -609,6 +609,11 @@ impl Value128 {
Self::from_le_bytes(out)
}
+ #[doc(alias = "i8x16.relaxed_swizzle")]
+ pub fn i8x16_relaxed_swizzle(self, s: Self) -> Self {
+ self.i8x16_swizzle(s)
+ }
+
#[doc(alias = "i8x16.shuffle")]
pub fn i8x16_shuffle(a: Self, b: Self, idx: [u8; 16]) -> Self {
let mut src = [0u8; 32];
@@ -938,6 +943,65 @@ impl Value128 {
Self::from_i32x4(out)
}
+ #[doc(alias = "i8x16.relaxed_laneselect")]
+ pub fn i8x16_relaxed_laneselect(v1: Self, v2: Self, c: Self) -> Self {
+ Self::v128_bitselect(v1, v2, c)
+ }
+
+ #[doc(alias = "i16x8.relaxed_laneselect")]
+ pub fn i16x8_relaxed_laneselect(v1: Self, v2: Self, c: Self) -> Self {
+ Self::v128_bitselect(v1, v2, c)
+ }
+
+ #[doc(alias = "i32x4.relaxed_laneselect")]
+ pub fn i32x4_relaxed_laneselect(v1: Self, v2: Self, c: Self) -> Self {
+ Self::v128_bitselect(v1, v2, c)
+ }
+
+ #[doc(alias = "i64x2.relaxed_laneselect")]
+ pub fn i64x2_relaxed_laneselect(v1: Self, v2: Self, c: Self) -> Self {
+ Self::v128_bitselect(v1, v2, c)
+ }
+
+ #[doc(alias = "i16x8.relaxed_q15mulr_s")]
+ pub fn i16x8_relaxed_q15mulr_s(self, rhs: Self) -> Self {
+ self.i16x8_q15mulr_sat_s(rhs)
+ }
+
+ #[doc(alias = "i16x8.relaxed_dot_i8x16_i7x16_s")]
+ pub fn i16x8_relaxed_dot_i8x16_i7x16_s(self, rhs: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let mut out = [0i16; 8];
+
+ for (dst, (a_pair, b_pair)) in out.iter_mut().zip(a.chunks_exact(2).zip(b.chunks_exact(2))) {
+ let prod0 = (a_pair[0] as i16) * (b_pair[0] as i16);
+ let prod1 = (a_pair[1] as i16) * (b_pair[1] as i16);
+ *dst = prod0.wrapping_add(prod1);
+ }
+
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.relaxed_dot_i8x16_i7x16_add_s")]
+ pub fn i32x4_relaxed_dot_i8x16_i7x16_add_s(self, rhs: Self, acc: Self) -> Self {
+ let a = self.as_i8x16();
+ let b = rhs.as_i8x16();
+ let c = acc.as_i32x4();
+ let mut out = [0i32; 4];
+
+ for (i, dst) in out.iter_mut().enumerate() {
+ let base = i * 4;
+ let mut sum = 0i32;
+ for j in 0..4 {
+ sum = sum.wrapping_add((a[base + j] as i32).wrapping_mul(b[base + j] as i32));
+ }
+ *dst = sum.wrapping_add(c[i]);
+ }
+
+ Self::from_i32x4(out)
+ }
+
simd_cmp_mask!(i8x16_eq, "i8x16.eq", i8x16_eq, i8, 16, as_i8x16, from_i8x16, ==);
simd_cmp_mask!(i16x8_eq, "i16x8.eq", i16x8_eq, i16, 8, as_i16x8, from_i16x8, ==);
simd_cmp_mask!(i32x4_eq, "i32x4.eq", i32x4_eq, i32, 4, as_i32x4, from_i32x4, ==);
@@ -1058,6 +1122,70 @@ impl Value128 {
simd_float_binary!(f32x4_pmax, "f32x4.pmax", zip_f32x4, |a, b| if b > a { b } else { a });
simd_float_binary!(f64x2_pmax, "f64x2.pmax", zip_f64x2, |a, b| if b > a { b } else { a });
+ #[doc(alias = "f32x4.relaxed_madd")]
+ pub fn f32x4_relaxed_madd(self, b: Self, c: Self) -> Self {
+ self.zip_f32x4(b, |x, y| canonicalize_simd_f32_nan(x * y))
+ .zip_f32x4(c, |xy, z| canonicalize_simd_f32_nan(xy + z))
+ }
+
+ #[doc(alias = "f32x4.relaxed_nmadd")]
+ pub fn f32x4_relaxed_nmadd(self, b: Self, c: Self) -> Self {
+ self.zip_f32x4(b, |x, y| canonicalize_simd_f32_nan(-(x * y)))
+ .zip_f32x4(c, |neg_xy, z| canonicalize_simd_f32_nan(neg_xy + z))
+ }
+
+ #[doc(alias = "f64x2.relaxed_madd")]
+ pub fn f64x2_relaxed_madd(self, b: Self, c: Self) -> Self {
+ self.zip_f64x2(b, |x, y| canonicalize_simd_f64_nan(x * y))
+ .zip_f64x2(c, |xy, z| canonicalize_simd_f64_nan(xy + z))
+ }
+
+ #[doc(alias = "f64x2.relaxed_nmadd")]
+ pub fn f64x2_relaxed_nmadd(self, b: Self, c: Self) -> Self {
+ self.zip_f64x2(b, |x, y| canonicalize_simd_f64_nan(-(x * y)))
+ .zip_f64x2(c, |neg_xy, z| canonicalize_simd_f64_nan(neg_xy + z))
+ }
+
+ #[doc(alias = "f32x4.relaxed_min")]
+ pub fn f32x4_relaxed_min(self, rhs: Self) -> Self {
+ self.f32x4_min(rhs)
+ }
+
+ #[doc(alias = "f64x2.relaxed_min")]
+ pub fn f64x2_relaxed_min(self, rhs: Self) -> Self {
+ self.f64x2_min(rhs)
+ }
+
+ #[doc(alias = "f32x4.relaxed_max")]
+ pub fn f32x4_relaxed_max(self, rhs: Self) -> Self {
+ self.f32x4_max(rhs)
+ }
+
+ #[doc(alias = "f64x2.relaxed_max")]
+ pub fn f64x2_relaxed_max(self, rhs: Self) -> Self {
+ self.f64x2_max(rhs)
+ }
+
+ #[doc(alias = "i32x4.relaxed_trunc_f32x4_s")]
+ pub fn i32x4_relaxed_trunc_f32x4_s(self) -> Self {
+ self.i32x4_trunc_sat_f32x4_s()
+ }
+
+ #[doc(alias = "i32x4.relaxed_trunc_f32x4_u")]
+ pub fn i32x4_relaxed_trunc_f32x4_u(self) -> Self {
+ self.i32x4_trunc_sat_f32x4_u()
+ }
+
+ #[doc(alias = "i32x4.relaxed_trunc_f64x2_s_zero")]
+ pub fn i32x4_relaxed_trunc_f64x2_s_zero(self) -> Self {
+ self.i32x4_trunc_sat_f64x2_s_zero()
+ }
+
+ #[doc(alias = "i32x4.relaxed_trunc_f64x2_u_zero")]
+ pub fn i32x4_relaxed_trunc_f64x2_u_zero(self) -> Self {
+ self.i32x4_trunc_sat_f64x2_u_zero()
+ }
+
#[doc(alias = "i32x4.trunc_sat_f32x4_s")]
pub fn i32x4_trunc_sat_f32x4_s(self) -> Self {
let v = self.as_f32x4();
diff --git a/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv b/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv
index a6e6228..6b89d8a 100644
--- a/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv
+++ b/crates/tinywasm/tests/generated/wasm-relaxed-simd.csv
@@ -1 +1 @@
-0.9.0-alpha.0,0,93,[{"name":"i16x8_relaxed_q15mulr_s.wast","passed":0,"failed":3},{"name":"i32x4_relaxed_trunc.wast","passed":0,"failed":17},{"name":"i8x16_relaxed_swizzle.wast","passed":0,"failed":6},{"name":"relaxed_dot_product.wast","passed":0,"failed":11},{"name":"relaxed_laneselect.wast","passed":0,"failed":12},{"name":"relaxed_madd_nmadd.wast","passed":0,"failed":19},{"name":"relaxed_min_max.wast","passed":0,"failed":25}]
+0.9.0-alpha.0,93,0,[{"name":"i16x8_relaxed_q15mulr_s.wast","passed":3,"failed":0},{"name":"i32x4_relaxed_trunc.wast","passed":17,"failed":0},{"name":"i8x16_relaxed_swizzle.wast","passed":6,"failed":0},{"name":"relaxed_dot_product.wast","passed":11,"failed":0},{"name":"relaxed_laneselect.wast","passed":12,"failed":0},{"name":"relaxed_madd_nmadd.wast","passed":19,"failed":0},{"name":"relaxed_min_max.wast","passed":25,"failed":0}]
diff --git a/crates/tinywasm/tests/test-wast.rs b/crates/tinywasm/tests/test-wast.rs
index 40b0e04..ff2b2ed 100644
--- a/crates/tinywasm/tests/test-wast.rs
+++ b/crates/tinywasm/tests/test-wast.rs
@@ -1,7 +1,6 @@
use std::path::PathBuf;
-use eyre::{Result, bail, eyre};
-use owo_colors::OwoColorize;
+use eyre::{Result, bail};
use testsuite::TestSuite;
mod testsuite;
diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs
index 6352730..d13c59b 100644
--- a/crates/tinywasm/tests/testsuite/run.rs
+++ b/crates/tinywasm/tests/testsuite/run.rs
@@ -410,7 +410,7 @@ impl TestSuite {
AssertReturn { span, exec, results } => {
info!("AssertReturn: {exec:?}");
- let expected = match convert_wastret(results.into_iter()) {
+ let expected_alternatives = match convert_wastret(results.into_iter()) {
Err(err) => {
test_group.add_result(
&format!("AssertReturn(unsupported-{i})"),
@@ -449,14 +449,19 @@ impl TestSuite {
continue;
}
};
- let expected = expected.first().expect("expected global value");
- let module_global = module_global.attach_type(expected.val_type());
+ let expected = expected_alternatives
+ .iter()
+ .filter_map(|alts| alts.first())
+ .find(|exp| module_global.attach_type(exp.val_type()).eq_loose(exp));
- if !module_global.eq_loose(expected) {
+ if expected.is_none() {
test_group.add_result(
&format!("AssertReturn(unsupported-{i})"),
span.linecol_in(wast_raw),
- Err(eyre!("global value did not match: {:?} != {:?}", module_global, expected)),
+ Err(eyre!(
+ "global value did not match any expected alternative: {:?}",
+ module_global
+ )),
);
continue;
}
@@ -493,20 +498,23 @@ impl TestSuite {
e
})?;
- if outcomes.len() != expected.len() {
+ if !expected_alternatives.iter().any(|expected| expected.len() == outcomes.len()) {
return Err(eyre!(
"span: {:?} expected {} results, got {}",
span,
- expected.len(),
+ expected_alternatives.first().map_or(0, |v| v.len()),
outcomes.len()
));
}
- outcomes.iter().zip(expected).enumerate().try_for_each(|(i, (outcome, exp))| {
- (outcome.eq_loose(&exp))
- .then_some(())
- .ok_or_else(|| eyre!(" result {} did not match: {:?} != {:?}", i, outcome, exp))
- })
+ if expected_alternatives.iter().any(|expected| {
+ expected.len() == outcomes.len()
+ && outcomes.iter().zip(expected.iter()).all(|(outcome, exp)| outcome.eq_loose(exp))
+ }) {
+ Ok(())
+ } else {
+ Err(eyre!("results did not match any expected alternative"))
+ }
});
let res = res.map_err(|e| eyre!("test panicked: {:?}", try_downcast_panic(e))).and_then(|r| r);
diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs
index 4699d69..851fa20 100644
--- a/crates/tinywasm/tests/testsuite/util.rs
+++ b/crates/tinywasm/tests/testsuite/util.rs
@@ -87,8 +87,27 @@ pub fn convert_wastargs(args: Vec<wast::WastArg>) -> Result<Vec<tinywasm_types::
args.into_iter().map(|a| wastarg2tinywasmvalue(a)).collect()
}
-pub fn convert_wastret<'a>(args: impl Iterator<Item = wast::WastRet<'a>>) -> Result<Vec<tinywasm_types::WasmValue>> {
- args.map(|a| wastret2tinywasmvalue(a)).collect()
+pub fn convert_wastret<'a>(
+ args: impl Iterator<Item = wast::WastRet<'a>>,
+) -> Result<Vec<Vec<tinywasm_types::WasmValue>>> {
+ let mut alternatives = vec![Vec::new()];
+
+ for arg in args {
+ let choices = wastret2tinywasmvalues(arg)?;
+ let mut next = Vec::with_capacity(alternatives.len() * choices.len());
+
+ for prefix in alternatives {
+ for choice in &choices {
+ let mut candidate = prefix.clone();
+ candidate.push(*choice);
+ next.push(candidate);
+ }
+ }
+
+ alternatives = next;
+ }
+
+ Ok(alternatives)
}
fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result<tinywasm_types::WasmValue> {
@@ -134,11 +153,20 @@ fn wast_i128_to_i128(i: wast::core::V128Pattern) -> i128 {
i128::from_le_bytes(res.try_into().unwrap())
}
-fn wastret2tinywasmvalue(ret: wast::WastRet) -> Result<tinywasm_types::WasmValue> {
+fn wastret2tinywasmvalues(ret: wast::WastRet) -> Result<Vec<tinywasm_types::WasmValue>> {
let wast::WastRet::Core(ret) = ret else {
bail!("unsupported arg type");
};
+ match ret {
+ wast::core::WastRetCore::Either(options) => {
+ options.into_iter().map(wastretcore2tinywasmvalue).collect::<Result<Vec<_>>>()
+ }
+ ret => Ok(vec![wastretcore2tinywasmvalue(ret)?]),
+ }
+}
+
+fn wastretcore2tinywasmvalue(ret: wast::core::WastRetCore) -> Result<tinywasm_types::WasmValue> {
use wast::core::WastRetCore::{F32, F64, I32, I64, RefExtern, RefFunc, RefNull, V128};
Ok(match ret {
F32(f) => nanpattern2tinywasmvalue(f)?,
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 83d0da8..59dc49f 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -237,18 +237,18 @@ pub enum Instruction {
F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4,
// > Relaxed SIMD
- // I8x16RelaxedSwizzle,
- // I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U,
- // I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero,
- // F32x4RelaxedMadd, F32x4RelaxedNmadd,
- // F64x2RelaxedMadd, F64x2RelaxedNmadd,
- // I8x16RelaxedLaneselect,
- // I16x8RelaxedLaneselect,
- // I32x4RelaxedLaneselect,
- // I64x2RelaxedLaneselect,
- // F32x4RelaxedMin, F32x4RelaxedMax,
- // F64x2RelaxedMin, F64x2RelaxedMax,
- // I16x8RelaxedQ15mulrS,
- // I16x8RelaxedDotI8x16I7x16S,
- // I32x4RelaxedDotI8x16I7x16AddS
+ I8x16RelaxedSwizzle,
+ I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U,
+ I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero,
+ F32x4RelaxedMadd, F32x4RelaxedNmadd,
+ F64x2RelaxedMadd, F64x2RelaxedNmadd,
+ I8x16RelaxedLaneselect,
+ I16x8RelaxedLaneselect,
+ I32x4RelaxedLaneselect,
+ I64x2RelaxedLaneselect,
+ F32x4RelaxedMin, F32x4RelaxedMax,
+ F64x2RelaxedMin, F64x2RelaxedMax,
+ I16x8RelaxedQ15mulrS,
+ I16x8RelaxedDotI8x16I7x16S,
+ I32x4RelaxedDotI8x16I7x16AddS
}
diff --git a/profile.sh b/profile.sh
deleted file mode 100755
index 91bb946..0000000
--- a/profile.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env bash
-cargo build --example wasm-rust --profile profiling
-samply record -r 10000 ./target/profiling/examples/wasm-rust $@
diff --git a/tinywasm.png b/tinywasm.png
deleted file mode 100644
index 782b9d4..0000000
--- a/tinywasm.png
+++ /dev/null
Binary files differ