From e1b76386b7e323054d5e8844366ebad86bba693e Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 26 Apr 2025 17:43:23 +0200 Subject: feat: add canonicalize_nans feature Signed-off-by: Henry Gressmann --- crates/tinywasm/Cargo.toml | 10 ++++++++- crates/tinywasm/src/interpreter/num_helpers.rs | 29 ++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 3281476..10a3099 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -32,12 +32,20 @@ serde_json={version="1.0"} serde={version="1.0", features=["derive"]} [features] -default=["std", "parser", "logging", "archive"] +default=["std", "parser", "logging", "archive", "canonicalize_nans"] + logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] + +# support for parsing WebAssembly parser=["dep:tinywasm-parser"] + +# support for "archiving" tinywasm bytecode archive=["tinywasm-types/archive"] +# canonicalize all NaN values to a single representation +canonicalize_nans=[] + # enable simd support (unstable / unfinished) __simd=[] diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs index 678c32e..7e8a461 100644 --- a/crates/tinywasm/src/interpreter/num_helpers.rs +++ b/crates/tinywasm/src/interpreter/num_helpers.rs @@ -72,9 +72,12 @@ macro_rules! impl_wasm_float_ops { ($($t:ty)*) => ($( impl TinywasmFloatExt for $t { // https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest + #[inline] fn tw_nearest(self) -> Self { match self { - // x if x.is_nan() => x, // preserve NaN + #[cfg(not(feature = "canonicalize_nans"))] + x if x.is_nan() => x, // preserve NaN + #[cfg(feature = "canonicalize_nans")] x if x.is_nan() => Self::NAN, // Do not preserve NaN x if x.is_infinite() || x == 0.0 => x, // preserve infinities and zeros x if (0.0..=0.5).contains(&x) => 0.0, @@ -100,7 +103,9 @@ macro_rules! impl_wasm_float_ops { Some(core::cmp::Ordering::Less) => self, Some(core::cmp::Ordering::Greater) => other, Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { self } else { other }, - // None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(not(feature = "canonicalize_nans"))] + None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(feature = "canonicalize_nans")] None => Self::NAN, // Do not preserve NaN } } @@ -113,7 +118,9 @@ macro_rules! impl_wasm_float_ops { Some(core::cmp::Ordering::Greater) => self, Some(core::cmp::Ordering::Less) => other, Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { other } else { self }, - // None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(not(feature = "canonicalize_nans"))] + None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting. + #[cfg(feature = "canonicalize_nans")] None => Self::NAN, // Do not preserve NaN } } @@ -184,8 +191,15 @@ macro_rules! impl_checked_wrapping_rem { impl_checked_wrapping_rem! { i32 i64 u32 u64 } -#[cfg(feature = "__simd")] +#[cfg(all(feature = "__simd", not(feature = "canonicalize_nans")))] +#[inline] +pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { + x // No need to do anything, as we are not replacing NaNs +} + +#[cfg(all(feature = "__simd", feature = "canonicalize_nans"))] /// replace all NaNs in a f32x4 with f32::NAN +#[inline] pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { use core::simd::{Simd, num::SimdFloat}; let nan = Simd::splat(f32::NAN); @@ -193,8 +207,15 @@ pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 { mask.select(nan, x) } +#[cfg(all(feature = "__simd", not(feature = "canonicalize_nans")))] +#[inline] +pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 { + x // No need to do anything, as we are not replacing NaNs +} + #[cfg(feature = "__simd")] /// replace all NaNs in a f64x2 with f64::NAN +#[inline] pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 { use core::simd::{Simd, num::SimdFloat}; let nan = Simd::splat(f64::NAN); -- cgit v1.3.1