Skip to content

Commit e1b7638

Browse files
feat: add canonicalize_nans feature
Signed-off-by: Henry Gressmann <[email protected]>
1 parent c1a8cfa commit e1b7638

File tree

4 files changed

+47
-15
lines changed

4 files changed

+47
-15
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Support for the custom memory page sizes proposal ([#22](https://github.com/explodingcamera/tinywasm/pull/22) by [@danielstuart14](https://github.com/danielstuart14))
1313
- Support for the `tail_call` proposal
14+
- Support for the `memory64` proposal
15+
- Groundwork for the `simd` proposal
16+
- New `canonicalize_nans` feature flag to enable canonicalizing NaN values in the `f32`, `f64`, and `v128` types
1417

1518
### Breaking Changes
1619

Cargo.lock

+10-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/tinywasm/Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,20 @@ serde_json={version="1.0"}
3232
serde={version="1.0", features=["derive"]}
3333

3434
[features]
35-
default=["std", "parser", "logging", "archive"]
35+
default=["std", "parser", "logging", "archive", "canonicalize_nans"]
36+
3637
logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"]
3738
std=["tinywasm-parser?/std", "tinywasm-types/std"]
39+
40+
# support for parsing WebAssembly
3841
parser=["dep:tinywasm-parser"]
42+
43+
# support for "archiving" tinywasm bytecode
3944
archive=["tinywasm-types/archive"]
4045

46+
# canonicalize all NaN values to a single representation
47+
canonicalize_nans=[]
48+
4149
# enable simd support (unstable / unfinished)
4250
__simd=[]
4351

crates/tinywasm/src/interpreter/num_helpers.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,12 @@ macro_rules! impl_wasm_float_ops {
7272
($($t:ty)*) => ($(
7373
impl TinywasmFloatExt for $t {
7474
// https://webassembly.github.io/spec/core/exec/numerics.html#op-fnearest
75+
#[inline]
7576
fn tw_nearest(self) -> Self {
7677
match self {
77-
// x if x.is_nan() => x, // preserve NaN
78+
#[cfg(not(feature = "canonicalize_nans"))]
79+
x if x.is_nan() => x, // preserve NaN
80+
#[cfg(feature = "canonicalize_nans")]
7881
x if x.is_nan() => Self::NAN, // Do not preserve NaN
7982
x if x.is_infinite() || x == 0.0 => x, // preserve infinities and zeros
8083
x if (0.0..=0.5).contains(&x) => 0.0,
@@ -100,7 +103,9 @@ macro_rules! impl_wasm_float_ops {
100103
Some(core::cmp::Ordering::Less) => self,
101104
Some(core::cmp::Ordering::Greater) => other,
102105
Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { self } else { other },
103-
// None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
106+
#[cfg(not(feature = "canonicalize_nans"))]
107+
None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
108+
#[cfg(feature = "canonicalize_nans")]
104109
None => Self::NAN, // Do not preserve NaN
105110
}
106111
}
@@ -113,7 +118,9 @@ macro_rules! impl_wasm_float_ops {
113118
Some(core::cmp::Ordering::Greater) => self,
114119
Some(core::cmp::Ordering::Less) => other,
115120
Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { other } else { self },
116-
// None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
121+
#[cfg(not(feature = "canonicalize_nans"))]
122+
None => self + other, // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
123+
#[cfg(feature = "canonicalize_nans")]
117124
None => Self::NAN, // Do not preserve NaN
118125
}
119126
}
@@ -184,17 +191,31 @@ macro_rules! impl_checked_wrapping_rem {
184191

185192
impl_checked_wrapping_rem! { i32 i64 u32 u64 }
186193

187-
#[cfg(feature = "__simd")]
194+
#[cfg(all(feature = "__simd", not(feature = "canonicalize_nans")))]
195+
#[inline]
196+
pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 {
197+
x // No need to do anything, as we are not replacing NaNs
198+
}
199+
200+
#[cfg(all(feature = "__simd", feature = "canonicalize_nans"))]
188201
/// replace all NaNs in a f32x4 with f32::NAN
202+
#[inline]
189203
pub(crate) fn canonicalize_f32x4(x: core::simd::f32x4) -> core::simd::f32x4 {
190204
use core::simd::{Simd, num::SimdFloat};
191205
let nan = Simd::splat(f32::NAN);
192206
let mask = x.is_nan();
193207
mask.select(nan, x)
194208
}
195209

210+
#[cfg(all(feature = "__simd", not(feature = "canonicalize_nans")))]
211+
#[inline]
212+
pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 {
213+
x // No need to do anything, as we are not replacing NaNs
214+
}
215+
196216
#[cfg(feature = "__simd")]
197217
/// replace all NaNs in a f64x2 with f64::NAN
218+
#[inline]
198219
pub(crate) fn canonicalize_f64x2(x: core::simd::f64x2) -> core::simd::f64x2 {
199220
use core::simd::{Simd, num::SimdFloat};
200221
let nan = Simd::splat(f64::NAN);

0 commit comments

Comments
 (0)