summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2025-04-26 17:43:23 +0200
committerHenry Gressmann <mail@henrygressmann.de>2025-04-26 17:43:23 +0200
commite1b76386b7e323054d5e8844366ebad86bba693e (patch)
treeed5ab4829ce1c20dc3bfe7bd4e1f65f0febbc07c /crates
parentc1a8cfad737cc79772b44a99088bcccd0ab6ee02 (diff)
feat: add canonicalize_nans feature
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/tinywasm/Cargo.toml10
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs29
2 files changed, 34 insertions, 5 deletions
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);