From 03ff4138e38512df0e6d33aae55a7f9cb83e2949 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 26 Dec 2023 00:07:48 +0100 Subject: [PATCH] feat: pass all float tests Signed-off-by: Henry --- crates/tinywasm/src/runtime/executor/mod.rs | 43 +++++++--- .../tinywasm/src/runtime/executor/traits.rs | 78 ++++++++++++++++--- crates/tinywasm/tests/generated/mvp.csv | 2 +- .../tinywasm/tests/generated/progress-mvp.svg | 6 +- crates/tinywasm/tests/testsuite/run.rs | 22 ++++-- crates/tinywasm/tests/testsuite/util.rs | 35 +++++++-- crates/types/src/lib.rs | 19 ++++- 7 files changed, 164 insertions(+), 41 deletions(-) diff --git a/crates/tinywasm/src/runtime/executor/mod.rs b/crates/tinywasm/src/runtime/executor/mod.rs index 95c17cb..67129f8 100644 --- a/crates/tinywasm/src/runtime/executor/mod.rs +++ b/crates/tinywasm/src/runtime/executor/mod.rs @@ -1,4 +1,4 @@ -use core::ops::{BitAnd, BitOr, BitXor}; +use core::ops::{BitAnd, BitOr, BitXor, Neg}; use super::{DefaultRuntime, Stack}; use crate::{ @@ -332,16 +332,16 @@ fn exec_one( I64Or => arithmetic_method!(bitor, i64, stack), I32Xor => arithmetic_method!(bitxor, i32, stack), I64Xor => arithmetic_method!(bitxor, i64, stack), - I32Shl => arithmetic_method!(wrapping_shl_self, i32, stack), - I64Shl => arithmetic_method!(wrapping_shl_self, i64, stack), - I32ShrS => arithmetic_method!(wrapping_shr_self, i32, stack), - I64ShrS => arithmetic_method!(wrapping_shr_self, i64, stack), - I32ShrU => arithmetic_method_cast!(wrapping_shr_self, i32, u32, stack), - I64ShrU => arithmetic_method_cast!(wrapping_shr_self, i64, u64, stack), - I32Rotl => arithmetic_method!(wrapping_rotl_self, i32, stack), - I64Rotl => arithmetic_method!(wrapping_rotl_self, i64, stack), - I32Rotr => arithmetic_method!(wrapping_rotr_self, i32, stack), - I64Rotr => arithmetic_method!(wrapping_rotr_self, i64, stack), + I32Shl => arithmetic_method!(wasm_shl, i32, stack), + I64Shl => arithmetic_method!(wasm_shl, i64, stack), + I32ShrS => arithmetic_method!(wasm_shr, i32, stack), + I64ShrS => arithmetic_method!(wasm_shr, i64, stack), + I32ShrU => arithmetic_method_cast!(wasm_shr, i32, u32, stack), + I64ShrU => arithmetic_method_cast!(wasm_shr, i64, u64, stack), + I32Rotl => arithmetic_method!(wasm_rotl, i32, stack), + I64Rotl => arithmetic_method!(wasm_rotl, i64, stack), + I32Rotr => arithmetic_method!(wasm_rotr, i32, stack), + I64Rotr => arithmetic_method!(wasm_rotr, i64, stack), I32Clz => arithmetic_method_self!(leading_zeros, i32, stack), I64Clz => arithmetic_method_self!(leading_zeros, i64, stack), @@ -367,6 +367,27 @@ fn exec_one( I64ExtendI32S => conv_1!(i32, i64, stack), I32WrapI64 => conv_1!(i64, i32, stack), + F32Abs => arithmetic_method_self!(abs, f32, stack), + F64Abs => arithmetic_method_self!(abs, f64, stack), + F32Neg => arithmetic_method_self!(neg, f32, stack), + F64Neg => arithmetic_method_self!(neg, f64, stack), + F32Ceil => arithmetic_method_self!(ceil, f32, stack), + F64Ceil => arithmetic_method_self!(ceil, f64, stack), + F32Floor => arithmetic_method_self!(floor, f32, stack), + F64Floor => arithmetic_method_self!(floor, f64, stack), + F32Trunc => arithmetic_method_self!(trunc, f32, stack), + F64Trunc => arithmetic_method_self!(trunc, f64, stack), + F32Nearest => arithmetic_method_self!(wasm_nearest, f32, stack), + F64Nearest => arithmetic_method_self!(wasm_nearest, f64, stack), + F32Sqrt => arithmetic_method_self!(sqrt, f32, stack), + F64Sqrt => arithmetic_method_self!(sqrt, f64, stack), + F32Min => arithmetic_method!(wasm_min, f32, stack), + F64Min => arithmetic_method!(wasm_min, f64, stack), + F32Max => arithmetic_method!(wasm_max, f32, stack), + F64Max => arithmetic_method!(wasm_max, f64, stack), + F32Copysign => arithmetic_method!(copysign, f32, stack), + F64Copysign => arithmetic_method!(copysign, f64, stack), + // no-op instructions since types are erased at runtime I32ReinterpretF32 => {} I64ReinterpretF64 => {} diff --git a/crates/tinywasm/src/runtime/executor/traits.rs b/crates/tinywasm/src/runtime/executor/traits.rs index bbba2cb..d37cd85 100644 --- a/crates/tinywasm/src/runtime/executor/traits.rs +++ b/crates/tinywasm/src/runtime/executor/traits.rs @@ -5,33 +5,91 @@ where fn checked_wrapping_rem(self, rhs: Self) -> Option; } -pub(crate) trait WrappingSelfOps { - fn wrapping_shl_self(self, rhs: Self) -> Self; - fn wrapping_shr_self(self, rhs: Self) -> Self; - fn wrapping_rotl_self(self, rhs: Self) -> Self; - fn wrapping_rotr_self(self, rhs: Self) -> Self; +pub(crate) trait WasmFloatOps { + fn wasm_min(self, other: Self) -> Self; + fn wasm_max(self, other: Self) -> Self; + fn wasm_nearest(self) -> Self; +} + +macro_rules! impl_wasm_float_ops { + ($($t:ty)*) => ($( + impl WasmFloatOps for $t { + // https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest + fn wasm_nearest(self) -> Self { + log::info!("wasm_nearest: {}", self); + match self { + x if x.is_nan() => x, + x if x.is_infinite() || x == 0.0 => x, + x if x > 0.0 && x <= 0.5 => 0.0, + x if x < 0.0 && x >= -0.5 => -0.0, + x => x.round(), + } + } + + // https://webassembly.github.io/spec/core/exec/numerics.html#op-fmin + // Based on f32::minimum (which is not yet stable) + #[inline] + fn wasm_min(self, other: Self) -> Self { + if self < other { + self + } else if other < self { + other + } else if self == other { + if self.is_sign_negative() && other.is_sign_positive() { self } else { other } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + self + other + } + } + + // https://webassembly.github.io/spec/core/exec/numerics.html#op-fmax + // Based on f32::maximum (which is not yet stable) + #[inline] + fn wasm_max(self, other: Self) -> Self { + if self > other { + self + } else if other > self { + other + } else if self == other { + if self.is_sign_negative() && other.is_sign_positive() { other } else { self } + } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + self + other + } + } + } + )*) +} + +impl_wasm_float_ops! { f32 f64 } + +pub(crate) trait WasmIntOps { + fn wasm_shl(self, rhs: Self) -> Self; + fn wasm_shr(self, rhs: Self) -> Self; + fn wasm_rotl(self, rhs: Self) -> Self; + fn wasm_rotr(self, rhs: Self) -> Self; } macro_rules! impl_wrapping_self_sh { ($($t:ty)*) => ($( - impl WrappingSelfOps for $t { + impl WasmIntOps for $t { #[inline] - fn wrapping_shl_self(self, rhs: Self) -> Self { + fn wasm_shl(self, rhs: Self) -> Self { self.wrapping_shl(rhs as u32) } #[inline] - fn wrapping_shr_self(self, rhs: Self) -> Self { + fn wasm_shr(self, rhs: Self) -> Self { self.wrapping_shr(rhs as u32) } #[inline] - fn wrapping_rotl_self(self, rhs: Self) -> Self { + fn wasm_rotl(self, rhs: Self) -> Self { self.rotate_left(rhs as u32) } #[inline] - fn wrapping_rotr_self(self, rhs: Self) -> Self { + fn wasm_rotr(self, rhs: Self) -> Self { self.rotate_right(rhs as u32) } } diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 47cb8ec..f9c6768 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -1,4 +1,4 @@ 0.0.3,9258,7567,[{"name":"address.wast","passed":0,"failed":54},{"name":"align.wast","passed":0,"failed":109},{"name":"binary-leb128.wast","passed":66,"failed":25},{"name":"binary.wast","passed":104,"failed":8},{"name":"block.wast","passed":0,"failed":171},{"name":"br.wast","passed":0,"failed":21},{"name":"br_if.wast","passed":0,"failed":30},{"name":"br_table.wast","passed":0,"failed":25},{"name":"call.wast","passed":0,"failed":22},{"name":"call_indirect.wast","passed":0,"failed":56},{"name":"comments.wast","passed":4,"failed":4},{"name":"const.wast","passed":702,"failed":76},{"name":"conversions.wast","passed":0,"failed":93},{"name":"custom.wast","passed":10,"failed":1},{"name":"data.wast","passed":0,"failed":61},{"name":"elem.wast","passed":0,"failed":76},{"name":"endianness.wast","passed":0,"failed":1},{"name":"exports.wast","passed":21,"failed":73},{"name":"f32.wast","passed":1005,"failed":1509},{"name":"f32_bitwise.wast","passed":1,"failed":363},{"name":"f32_cmp.wast","passed":2401,"failed":6},{"name":"f64.wast","passed":1005,"failed":1509},{"name":"f64_bitwise.wast","passed":1,"failed":363},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":0,"failed":2},{"name":"float_exprs.wast","passed":269,"failed":591},{"name":"float_literals.wast","passed":34,"failed":129},{"name":"float_memory.wast","passed":0,"failed":6},{"name":"float_misc.wast","passed":138,"failed":303},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":4,"failed":75},{"name":"func_ptrs.wast","passed":0,"failed":16},{"name":"global.wast","passed":4,"failed":49},{"name":"i32.wast","passed":0,"failed":96},{"name":"i64.wast","passed":0,"failed":42},{"name":"if.wast","passed":0,"failed":118},{"name":"imports.wast","passed":1,"failed":156},{"name":"inline-module.wast","passed":0,"failed":1},{"name":"int_exprs.wast","passed":38,"failed":70},{"name":"int_literals.wast","passed":5,"failed":46},{"name":"labels.wast","passed":1,"failed":28},{"name":"left-to-right.wast","passed":0,"failed":1},{"name":"linking.wast","passed":1,"failed":66},{"name":"load.wast","passed":0,"failed":60},{"name":"local_get.wast","passed":2,"failed":34},{"name":"local_set.wast","passed":5,"failed":48},{"name":"local_tee.wast","passed":0,"failed":42},{"name":"loop.wast","passed":0,"failed":43},{"name":"memory.wast","passed":0,"failed":34},{"name":"memory_grow.wast","passed":0,"failed":19},{"name":"memory_redundancy.wast","passed":0,"failed":1},{"name":"memory_size.wast","passed":0,"failed":6},{"name":"memory_trap.wast","passed":0,"failed":172},{"name":"names.wast","passed":484,"failed":1},{"name":"nop.wast","passed":0,"failed":5},{"name":"return.wast","passed":0,"failed":21},{"name":"select.wast","passed":0,"failed":32},{"name":"skip-stack-guard-page.wast","passed":0,"failed":11},{"name":"stack.wast","passed":0,"failed":2},{"name":"start.wast","passed":0,"failed":10},{"name":"store.wast","passed":0,"failed":59},{"name":"switch.wast","passed":1,"failed":27},{"name":"token.wast","passed":16,"failed":42},{"name":"traps.wast","passed":3,"failed":33},{"name":"type.wast","passed":1,"failed":2},{"name":"unreachable.wast","passed":0,"failed":59},{"name":"unreached-invalid.wast","passed":0,"failed":118},{"name":"unwind.wast","passed":1,"failed":49},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":0,"failed":176}] 0.0.4,9258,10909,[{"name":"address.wast","passed":0,"failed":54},{"name":"align.wast","passed":0,"failed":109},{"name":"binary-leb128.wast","passed":66,"failed":25},{"name":"binary.wast","passed":104,"failed":8},{"name":"block.wast","passed":0,"failed":171},{"name":"br.wast","passed":0,"failed":21},{"name":"br_if.wast","passed":0,"failed":30},{"name":"br_table.wast","passed":0,"failed":25},{"name":"call.wast","passed":0,"failed":22},{"name":"call_indirect.wast","passed":0,"failed":56},{"name":"comments.wast","passed":4,"failed":4},{"name":"const.wast","passed":702,"failed":76},{"name":"conversions.wast","passed":0,"failed":93},{"name":"custom.wast","passed":10,"failed":1},{"name":"data.wast","passed":0,"failed":61},{"name":"elem.wast","passed":0,"failed":76},{"name":"endianness.wast","passed":0,"failed":1},{"name":"exports.wast","passed":21,"failed":73},{"name":"f32.wast","passed":1005,"failed":1509},{"name":"f32_bitwise.wast","passed":1,"failed":363},{"name":"f32_cmp.wast","passed":2401,"failed":6},{"name":"f64.wast","passed":1005,"failed":1509},{"name":"f64_bitwise.wast","passed":1,"failed":363},{"name":"f64_cmp.wast","passed":2401,"failed":6},{"name":"fac.wast","passed":0,"failed":2},{"name":"float_exprs.wast","passed":269,"failed":591},{"name":"float_literals.wast","passed":34,"failed":129},{"name":"float_memory.wast","passed":0,"failed":6},{"name":"float_misc.wast","passed":138,"failed":303},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":4,"failed":75},{"name":"func_ptrs.wast","passed":0,"failed":16},{"name":"global.wast","passed":4,"failed":49},{"name":"i32.wast","passed":0,"failed":96},{"name":"i64.wast","passed":0,"failed":42},{"name":"if.wast","passed":0,"failed":118},{"name":"imports.wast","passed":1,"failed":156},{"name":"inline-module.wast","passed":0,"failed":1},{"name":"int_exprs.wast","passed":38,"failed":70},{"name":"int_literals.wast","passed":5,"failed":46},{"name":"labels.wast","passed":1,"failed":28},{"name":"left-to-right.wast","passed":0,"failed":1},{"name":"linking.wast","passed":1,"failed":66},{"name":"load.wast","passed":0,"failed":60},{"name":"local_get.wast","passed":2,"failed":34},{"name":"local_set.wast","passed":5,"failed":48},{"name":"local_tee.wast","passed":0,"failed":42},{"name":"loop.wast","passed":0,"failed":43},{"name":"memory.wast","passed":0,"failed":34},{"name":"memory_grow.wast","passed":0,"failed":19},{"name":"memory_redundancy.wast","passed":0,"failed":1},{"name":"memory_size.wast","passed":0,"failed":6},{"name":"memory_trap.wast","passed":0,"failed":172},{"name":"names.wast","passed":484,"failed":1},{"name":"nop.wast","passed":0,"failed":5},{"name":"return.wast","passed":0,"failed":21},{"name":"select.wast","passed":0,"failed":32},{"name":"skip-stack-guard-page.wast","passed":0,"failed":11},{"name":"stack.wast","passed":0,"failed":2},{"name":"start.wast","passed":0,"failed":10},{"name":"store.wast","passed":0,"failed":59},{"name":"switch.wast","passed":1,"failed":27},{"name":"token.wast","passed":16,"failed":42},{"name":"traps.wast","passed":3,"failed":33},{"name":"type.wast","passed":1,"failed":2},{"name":"unreachable.wast","passed":0,"failed":59},{"name":"unreached-invalid.wast","passed":0,"failed":118},{"name":"unwind.wast","passed":1,"failed":49},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":0,"failed":176}] 0.0.5,11135,9093,[{"name":"address.wast","passed":1,"failed":259},{"name":"align.wast","passed":108,"failed":48},{"name":"binary-leb128.wast","passed":78,"failed":13},{"name":"binary.wast","passed":107,"failed":5},{"name":"block.wast","passed":170,"failed":53},{"name":"br.wast","passed":20,"failed":77},{"name":"br_if.wast","passed":29,"failed":89},{"name":"br_table.wast","passed":24,"failed":150},{"name":"call.wast","passed":18,"failed":73},{"name":"call_indirect.wast","passed":34,"failed":136},{"name":"comments.wast","passed":5,"failed":3},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":25,"failed":594},{"name":"custom.wast","passed":10,"failed":1},{"name":"data.wast","passed":22,"failed":39},{"name":"elem.wast","passed":27,"failed":72},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":90,"failed":6},{"name":"f32.wast","passed":1018,"failed":1496},{"name":"f32_bitwise.wast","passed":4,"failed":360},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":1018,"failed":1496},{"name":"f64_bitwise.wast","passed":4,"failed":360},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":1,"failed":7},{"name":"float_exprs.wast","passed":275,"failed":625},{"name":"float_literals.wast","passed":112,"failed":51},{"name":"float_memory.wast","passed":0,"failed":90},{"name":"float_misc.wast","passed":138,"failed":303},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":81,"failed":91},{"name":"func_ptrs.wast","passed":7,"failed":29},{"name":"global.wast","passed":50,"failed":60},{"name":"i32.wast","passed":85,"failed":375},{"name":"i64.wast","passed":31,"failed":385},{"name":"if.wast","passed":116,"failed":125},{"name":"imports.wast","passed":23,"failed":160},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":38,"failed":70},{"name":"int_literals.wast","passed":25,"failed":26},{"name":"labels.wast","passed":13,"failed":16},{"name":"left-to-right.wast","passed":0,"failed":96},{"name":"linking.wast","passed":5,"failed":127},{"name":"load.wast","passed":59,"failed":38},{"name":"local_get.wast","passed":18,"failed":18},{"name":"local_set.wast","passed":38,"failed":15},{"name":"local_tee.wast","passed":41,"failed":56},{"name":"loop.wast","passed":42,"failed":78},{"name":"memory.wast","passed":30,"failed":49},{"name":"memory_grow.wast","passed":11,"failed":85},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":6,"failed":36},{"name":"memory_trap.wast","passed":1,"failed":181},{"name":"names.wast","passed":484,"failed":2},{"name":"nop.wast","passed":4,"failed":84},{"name":"return.wast","passed":20,"failed":64},{"name":"select.wast","passed":28,"failed":120},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":2,"failed":5},{"name":"start.wast","passed":4,"failed":16},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":2,"failed":26},{"name":"token.wast","passed":39,"failed":19},{"name":"traps.wast","passed":4,"failed":32},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":0,"failed":64},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unwind.wast","passed":9,"failed":41},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.0.6-alpha.0,13518,6710,[{"name":"address.wast","passed":5,"failed":255},{"name":"align.wast","passed":108,"failed":48},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":110,"failed":2},{"name":"block.wast","passed":193,"failed":30},{"name":"br.wast","passed":84,"failed":13},{"name":"br_if.wast","passed":90,"failed":28},{"name":"br_table.wast","passed":25,"failed":149},{"name":"call.wast","passed":29,"failed":62},{"name":"call_indirect.wast","passed":36,"failed":134},{"name":"comments.wast","passed":7,"failed":1},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":187,"failed":432},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":47,"failed":14},{"name":"elem.wast","passed":50,"failed":49},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":92,"failed":4},{"name":"f32.wast","passed":1174,"failed":1340},{"name":"f32_bitwise.wast","passed":4,"failed":360},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":1018,"failed":1496},{"name":"f64_bitwise.wast","passed":4,"failed":360},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":2,"failed":6},{"name":"float_exprs.wast","passed":511,"failed":389},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":328,"failed":113},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":122,"failed":50},{"name":"func_ptrs.wast","passed":10,"failed":26},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":120,"failed":121},{"name":"imports.wast","passed":74,"failed":109},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":14,"failed":15},{"name":"left-to-right.wast","passed":1,"failed":95},{"name":"linking.wast","passed":21,"failed":111},{"name":"load.wast","passed":60,"failed":37},{"name":"local_get.wast","passed":31,"failed":5},{"name":"local_set.wast","passed":50,"failed":3},{"name":"local_tee.wast","passed":66,"failed":31},{"name":"loop.wast","passed":93,"failed":27},{"name":"memory.wast","passed":34,"failed":45},{"name":"memory_grow.wast","passed":12,"failed":84},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":6,"failed":36},{"name":"memory_trap.wast","passed":2,"failed":180},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":46,"failed":42},{"name":"return.wast","passed":73,"failed":11},{"name":"select.wast","passed":86,"failed":62},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":2,"failed":5},{"name":"start.wast","passed":9,"failed":11},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":2,"failed":26},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":14,"failed":22},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":50,"failed":14},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unwind.wast","passed":35,"failed":15},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.0.6-alpha.0,17394,2834,[{"name":"address.wast","passed":5,"failed":255},{"name":"align.wast","passed":108,"failed":48},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":110,"failed":2},{"name":"block.wast","passed":193,"failed":30},{"name":"br.wast","passed":84,"failed":13},{"name":"br_if.wast","passed":90,"failed":28},{"name":"br_table.wast","passed":25,"failed":149},{"name":"call.wast","passed":29,"failed":62},{"name":"call_indirect.wast","passed":36,"failed":134},{"name":"comments.wast","passed":7,"failed":1},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":187,"failed":432},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":47,"failed":14},{"name":"elem.wast","passed":50,"failed":49},{"name":"endianness.wast","passed":1,"failed":68},{"name":"exports.wast","passed":92,"failed":4},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":2,"failed":6},{"name":"float_exprs.wast","passed":717,"failed":183},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":6,"failed":84},{"name":"float_misc.wast","passed":437,"failed":4},{"name":"forward.wast","passed":1,"failed":4},{"name":"func.wast","passed":124,"failed":48},{"name":"func_ptrs.wast","passed":10,"failed":26},{"name":"global.wast","passed":51,"failed":59},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":120,"failed":121},{"name":"imports.wast","passed":74,"failed":109},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":14,"failed":15},{"name":"left-to-right.wast","passed":1,"failed":95},{"name":"linking.wast","passed":21,"failed":111},{"name":"load.wast","passed":60,"failed":37},{"name":"local_get.wast","passed":32,"failed":4},{"name":"local_set.wast","passed":50,"failed":3},{"name":"local_tee.wast","passed":68,"failed":29},{"name":"loop.wast","passed":93,"failed":27},{"name":"memory.wast","passed":34,"failed":45},{"name":"memory_grow.wast","passed":12,"failed":84},{"name":"memory_redundancy.wast","passed":1,"failed":7},{"name":"memory_size.wast","passed":6,"failed":36},{"name":"memory_trap.wast","passed":2,"failed":180},{"name":"names.wast","passed":485,"failed":1},{"name":"nop.wast","passed":46,"failed":42},{"name":"return.wast","passed":73,"failed":11},{"name":"select.wast","passed":86,"failed":62},{"name":"skip-stack-guard-page.wast","passed":1,"failed":10},{"name":"stack.wast","passed":2,"failed":5},{"name":"start.wast","passed":9,"failed":11},{"name":"store.wast","passed":59,"failed":9},{"name":"switch.wast","passed":2,"failed":26},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":14,"failed":22},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":50,"failed":14},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unwind.wast","passed":35,"failed":15},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/progress-mvp.svg b/crates/tinywasm/tests/generated/progress-mvp.svg index 5525902..f36ee56 100644 --- a/crates/tinywasm/tests/generated/progress-mvp.svg +++ b/crates/tinywasm/tests/generated/progress-mvp.svg @@ -49,11 +49,11 @@ v0.0.5 (11135) -v0.0.6-alpha.0 (13410) +v0.0.6-alpha.0 (17394) - + + - diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index b7a1336..adaf697 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -192,18 +192,30 @@ impl TestSuite { debug!("expected: {:?}", expected); if outcomes.len() != expected.len() { - error!("expected {} results, got {}", expected.len(), outcomes.len()); - return Err(eyre!("expected {} results, got {}", expected.len(), outcomes.len())); + return Err(eyre!( + "span: {:?} expected {} results, got {}", + span, + expected.len(), + outcomes.len() + )); } + println!("expected: {:?}", expected); + println!("outcomes: {:?}", outcomes); + outcomes .iter() .zip(expected) .enumerate() .try_for_each(|(i, (outcome, exp))| { - (outcome.eq_bits(&exp)).then_some(()).ok_or_else(|| { - error!("result {} did not match: {:?} != {:?}", i, outcome, exp); - eyre!("result {} did not match: {:?} != {:?}", i, outcome, exp) + (outcome.eq_loose(&exp)).then_some(()).ok_or_else(|| { + eyre!( + "span: {:?}: result {} did not match: {:?} != {:?}", + span.linecol_in(&wast), + i, + outcome, + exp + ) }) }) }); diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index ab2ffa3..623510e 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -1,7 +1,7 @@ use std::panic; use eyre::{eyre, Result}; -use tinywasm_types::TinyWasmModule; +use tinywasm_types::{TinyWasmModule, WasmValue}; pub fn exec_fn( module: Option<&TinyWasmModule>, @@ -69,16 +69,40 @@ enum Bits { } trait FloatToken { fn bits(&self) -> Bits; + fn canonical_nan() -> WasmValue; + fn arithmetic_nan() -> WasmValue; + fn value(&self) -> WasmValue { + match self.bits() { + Bits::U32(v) => WasmValue::F32(f32::from_bits(v)), + Bits::U64(v) => WasmValue::F64(f64::from_bits(v)), + } + } } impl FloatToken for wast::token::Float32 { fn bits(&self) -> Bits { Bits::U32(self.bits) } + + fn canonical_nan() -> WasmValue { + WasmValue::F32(f32::NAN) + } + + fn arithmetic_nan() -> WasmValue { + WasmValue::F32(f32::NAN) + } } impl FloatToken for wast::token::Float64 { fn bits(&self) -> Bits { Bits::U64(self.bits) } + + fn canonical_nan() -> WasmValue { + WasmValue::F64(f64::NAN) + } + + fn arithmetic_nan() -> WasmValue { + WasmValue::F64(f64::NAN) + } } fn nanpattern2tinywasmvalue(arg: wast::core::NanPattern) -> Result @@ -87,11 +111,8 @@ where { use wast::core::NanPattern::*; Ok(match arg { - CanonicalNan => tinywasm_types::WasmValue::F32(f32::NAN), - ArithmeticNan => tinywasm_types::WasmValue::F32(f32::NAN), - Value(v) => match v.bits() { - Bits::U32(v) => tinywasm_types::WasmValue::F32(f32::from_bits(v)), - Bits::U64(v) => tinywasm_types::WasmValue::F64(f64::from_bits(v)), - }, + CanonicalNan => T::canonical_nan(), + ArithmeticNan => T::arithmetic_nan(), + Value(v) => v.value(), }) } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 12cdbfb..ad82bd4 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -104,13 +104,24 @@ impl WasmValue { } } - pub fn eq_bits(&self, other: &Self) -> bool { + pub fn eq_loose(&self, other: &Self) -> bool { match (self, other) { (Self::I32(a), Self::I32(b)) => a == b, (Self::I64(a), Self::I64(b)) => a == b, - (Self::F32(a), Self::F32(b)) => a.to_bits() == b.to_bits(), - (Self::F64(a), Self::F64(b)) => a.to_bits() == b.to_bits(), - // (Self::V128(a), Self::V128(b)) => a == b, + (Self::F32(a), Self::F32(b)) => { + if a.is_nan() && b.is_nan() { + true // Both are NaN, treat them as equal + } else { + a.to_bits() == b.to_bits() + } + } + (Self::F64(a), Self::F64(b)) => { + if a.is_nan() && b.is_nan() { + true // Both are NaN, treat them as equal + } else { + a.to_bits() == b.to_bits() + } + } _ => false, } }