Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add optional NaN canonicalization #1236

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ pub use self::{
typed::{Typed, TypedVal},
units::Pages,
untyped::{DecodeUntypedSlice, EncodeUntypedSlice, UntypedError, UntypedVal},
value::ValType,
value::{CanonicalizeNan, ValType},
};
20 changes: 20 additions & 0 deletions crates/core/src/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,19 +299,23 @@ impl TypedVal {

fn f32_abs(f32) -> f32;
fn f32_neg(f32) -> f32;
fn f32_neg_canonicalize_nan(f32) -> f32;
fn f32_ceil(f32) -> f32;
fn f32_floor(f32) -> f32;
fn f32_trunc(f32) -> f32;
fn f32_nearest(f32) -> f32;
fn f32_sqrt(f32) -> f32;
fn f32_sqrt_canonicalize_nan(f32) -> f32;

fn f64_abs(f64) -> f64;
fn f64_neg(f64) -> f64;
fn f64_neg_canonicalize_nan(f64) -> f64;
fn f64_ceil(f64) -> f64;
fn f64_floor(f64) -> f64;
fn f64_trunc(f64) -> f64;
fn f64_nearest(f64) -> f64;
fn f64_sqrt(f64) -> f64;
fn f64_sqrt_canonicalize_nan(f64) -> f64;

fn f32_add(f32, f32) -> f32;
fn f32_sub(f32, f32) -> f32;
Expand All @@ -321,6 +325,14 @@ impl TypedVal {
fn f32_max(f32, f32) -> f32;
fn f32_copysign(f32, f32) -> f32;

fn f32_add_canonicalize_nan(f32, f32) -> f32;
fn f32_sub_canonicalize_nan(f32, f32) -> f32;
fn f32_mul_canonicalize_nan(f32, f32) -> f32;
fn f32_div_canonicalize_nan(f32, f32) -> f32;
fn f32_min_canonicalize_nan(f32, f32) -> f32;
fn f32_max_canonicalize_nan(f32, f32) -> f32;
fn f32_copysign_canonicalize_nan(f32, f32) -> f32;

fn f64_add(f64, f64) -> f64;
fn f64_sub(f64, f64) -> f64;
fn f64_mul(f64, f64) -> f64;
Expand All @@ -329,6 +341,14 @@ impl TypedVal {
fn f64_max(f64, f64) -> f64;
fn f64_copysign(f64, f64) -> f64;

fn f64_add_canonicalize_nan(f64, f64) -> f64;
fn f64_sub_canonicalize_nan(f64, f64) -> f64;
fn f64_mul_canonicalize_nan(f64, f64) -> f64;
fn f64_div_canonicalize_nan(f64, f64) -> f64;
fn f64_min_canonicalize_nan(f64, f64) -> f64;
fn f64_max_canonicalize_nan(f64, f64) -> f64;
fn f64_copysign_canonicalize_nan(f64, f64) -> f64;

// Conversions

fn i32_wrap_i64(i64) -> i32;
Expand Down
121 changes: 120 additions & 1 deletion crates/core/src/untyped.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
value::{LoadInto, StoreFrom},
ArithmeticOps,
CanonicalizeNan,
ExtendInto,
Float,
Integer,
Expand Down Expand Up @@ -931,6 +932,11 @@
self.execute_unary(<f32 as Neg>::neg)
}

/// Execute `f32.neg` Wasm operation.
pub fn f32_neg_canonicalize_nan(self) -> Self {
self.execute_unary(|value| <f32 as Neg>::neg(value).canonicalize_nan())

Check warning on line 937 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L936-L937

Added lines #L936 - L937 were not covered by tests
}

/// Execute `f32.ceil` Wasm operation.
pub fn f32_ceil(self) -> Self {
self.execute_unary(<f32 as Float>::ceil)
Expand All @@ -953,7 +959,12 @@

/// Execute `f32.sqrt` Wasm operation.
pub fn f32_sqrt(self) -> Self {
self.execute_unary(<f32 as Float>::sqrt)
self.execute_unary(<F32 as Float>::sqrt)
}

/// Execute `f32.sqrt` Wasm operation.
pub fn f32_sqrt_canonicalize_nan(self) -> Self {
self.execute_unary(|value| <f32 as Float>::sqrt(value).canonicalize_nan())

Check warning on line 967 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L966-L967

Added lines #L966 - L967 were not covered by tests
}

/// Execute `f64.abs` Wasm operation.
Expand All @@ -966,6 +977,11 @@
self.execute_unary(<f64 as Neg>::neg)
}

/// Execute `f64.neg` Wasm operation.
pub fn f64_neg_canonicalize_nan(self) -> Self {
self.execute_unary(|value| <f64 as Neg>::neg(value).canonicalize_nan())

Check warning on line 982 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L981-L982

Added lines #L981 - L982 were not covered by tests
}

/// Execute `f64.ceil` Wasm operation.
pub fn f64_ceil(self) -> Self {
self.execute_unary(<f64 as Float>::ceil)
Expand All @@ -991,76 +1007,179 @@
self.execute_unary(<f64 as Float>::sqrt)
}

/// Execute `f64.sqrt` Wasm operation.
pub fn f64_sqrt_canonicalize_nan(self) -> Self {
self.execute_unary(|value| <f64 as Float>::sqrt(value).canonicalize_nan())

Check warning on line 1012 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1011-L1012

Added lines #L1011 - L1012 were not covered by tests
}

/// Execute `f32.add` Wasm operation.
pub fn f32_add(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f32 as ArithmeticOps>::add)
}

/// Execute `f32.add` Wasm operation with NaN canonicalization.
pub fn f32_add_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as ArithmeticOps>::add(lhs, rhs).canonicalize_nan()

Check warning on line 1023 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1021-L1023

Added lines #L1021 - L1023 were not covered by tests
})
}

/// Execute `f64.add` Wasm operation.
pub fn f64_add(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f64 as ArithmeticOps>::add)
}

/// Execute `f64.add` Wasm operation with NaN canonicalization.
pub fn f64_add_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as ArithmeticOps>::add(lhs, rhs).canonicalize_nan()

Check warning on line 1035 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1033-L1035

Added lines #L1033 - L1035 were not covered by tests
})
}

/// Execute `f32.sub` Wasm operation.
pub fn f32_sub(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f32 as ArithmeticOps>::sub)
}

/// Execute `f32.sub` Wasm operation with NaN canonicalization.
pub fn f32_sub_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as ArithmeticOps>::sub(lhs, rhs).canonicalize_nan()

Check warning on line 1047 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1045-L1047

Added lines #L1045 - L1047 were not covered by tests
})
}

/// Execute `f64.sub` Wasm operation.
pub fn f64_sub(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f64 as ArithmeticOps>::sub)
}

/// Execute `f64.sub` Wasm operation with NaN canonicalization.
pub fn f64_sub_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as ArithmeticOps>::sub(lhs, rhs).canonicalize_nan()

Check warning on line 1059 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1057-L1059

Added lines #L1057 - L1059 were not covered by tests
})
}

/// Execute `f32.mul` Wasm operation.
pub fn f32_mul(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f32 as ArithmeticOps>::mul)
}

/// Execute `f32.mul` Wasm operation with NaN canonicalization.
pub fn f32_mul_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as ArithmeticOps>::mul(lhs, rhs).canonicalize_nan()

Check warning on line 1071 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1069-L1071

Added lines #L1069 - L1071 were not covered by tests
})
}

/// Execute `f64.mul` Wasm operation.
pub fn f64_mul(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f64 as ArithmeticOps>::mul)
}

/// Execute `f64.mul` Wasm operation with NaN canonicalization.
pub fn f64_mul_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as ArithmeticOps>::mul(lhs, rhs).canonicalize_nan()

Check warning on line 1083 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1081-L1083

Added lines #L1081 - L1083 were not covered by tests
})
}

/// Execute `f32.div` Wasm operation.
pub fn f32_div(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f32 as Float>::div)
}

/// Execute `f32.div` Wasm operation with NaN canonicalization.
pub fn f32_div_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as Float>::div(lhs, rhs).canonicalize_nan()

Check warning on line 1095 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1093-L1095

Added lines #L1093 - L1095 were not covered by tests
})
}

/// Execute `f64.div` Wasm operation.
pub fn f64_div(self, rhs: Self) -> Self {
self.execute_binary(rhs, <f64 as Float>::div)
}

/// Execute `f64.div` Wasm operation with NaN canonicalization.
pub fn f64_div_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as Float>::div(lhs, rhs).canonicalize_nan()

Check warning on line 1107 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1105-L1107

Added lines #L1105 - L1107 were not covered by tests
})
}

/// Execute `f32.min` Wasm operation.
pub fn f32_min(self, other: Self) -> Self {
self.execute_binary(other, <f32 as Float>::min)
}

/// Execute `f32.min` Wasm operation with NaN canonicalization.
pub fn f32_min_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as Float>::min(lhs, rhs).canonicalize_nan()

Check warning on line 1119 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1117-L1119

Added lines #L1117 - L1119 were not covered by tests
})
}

/// Execute `f64.min` Wasm operation.
pub fn f64_min(self, other: Self) -> Self {
self.execute_binary(other, <f64 as Float>::min)
}

/// Execute `f64.min` Wasm operation with NaN canonicalization.
pub fn f64_min_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as Float>::min(lhs, rhs).canonicalize_nan()

Check warning on line 1131 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1129-L1131

Added lines #L1129 - L1131 were not covered by tests
})
}

/// Execute `f32.max` Wasm operation.
pub fn f32_max(self, other: Self) -> Self {
self.execute_binary(other, <f32 as Float>::max)
}

/// Execute `f32.max` Wasm operation with NaN canonicalization.
pub fn f32_max_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as Float>::max(lhs, rhs).canonicalize_nan()

Check warning on line 1143 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1141-L1143

Added lines #L1141 - L1143 were not covered by tests
})
}

/// Execute `f64.max` Wasm operation.
pub fn f64_max(self, other: Self) -> Self {
self.execute_binary(other, <f64 as Float>::max)
}

/// Execute `f64.max` Wasm operation with NaN canonicalization.
pub fn f64_max_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as Float>::max(lhs, rhs).canonicalize_nan()

Check warning on line 1155 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1153-L1155

Added lines #L1153 - L1155 were not covered by tests
})
}

/// Execute `f32.copysign` Wasm operation.
pub fn f32_copysign(self, other: Self) -> Self {
self.execute_binary(other, <f32 as Float>::copysign)
}

/// Execute `f32.copysign` Wasm operation with NaN canonicalization.
pub fn f32_copysign_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f32 as Float>::copysign(lhs, rhs).canonicalize_nan()

Check warning on line 1167 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1165-L1167

Added lines #L1165 - L1167 were not covered by tests
})
}

/// Execute `f64.copysign` Wasm operation.
pub fn f64_copysign(self, other: Self) -> Self {
self.execute_binary(other, <f64 as Float>::copysign)
}

/// Execute `f64.copysign` Wasm operation with NaN canonicalization.
pub fn f64_copysign_canonicalize_nan(self, rhs: Self) -> Self {
self.execute_binary(rhs, |lhs, rhs| {
<f64 as Float>::copysign(lhs, rhs).canonicalize_nan()

Check warning on line 1179 in crates/core/src/untyped.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/untyped.rs#L1177-L1179

Added lines #L1177 - L1179 were not covered by tests
})
}

/// Execute `i32.wrap_i64` Wasm operation.
pub fn i32_wrap_i64(self) -> Self {
self.execute_unary(<i64 as WrapInto<i32>>::wrap_into)
Expand Down
31 changes: 31 additions & 0 deletions crates/core/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,3 +791,34 @@
)
}
}

/// Trait implemented by floating point types for NaN canonicalization.
pub trait CanonicalizeNan {
/// Canonicalizes `self` if it is NaN.
fn canonicalize_nan(self) -> Self;
}

macro_rules! impl_caninocalize_nan {
( $( $ty:ty as $nan_val:literal),* $(,)? ) => {
$(
impl CanonicalizeNan for $ty {
fn canonicalize_nan(self) -> Self {
if self.is_nan() {
let canonicalized = Self::from_bits($nan_val);
debug_assert!(canonicalized.is_nan());
return canonicalized

Check warning on line 809 in crates/core/src/value.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/value.rs#L805-L809

Added lines #L805 - L809 were not covered by tests
}
self

Check warning on line 811 in crates/core/src/value.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/value.rs#L811

Added line #L811 was not covered by tests
}
}
)*
};
}
impl_caninocalize_nan! {
// Note: These patterns ensures that the sign bit can be either 0 or 1,
// the exponent bits are all set to 1 (indicating an infinity or NaN),
// and the fraction (mantissa) bits are all zero, except the most significant bit
// of the fraction is set to 1 to indicate a quiet NaN.
f32 as 0x7FC00000_u32,
f64 as 0x7FF8000000000000_u64,
}
Loading
Loading