-
Notifications
You must be signed in to change notification settings - Fork 291
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
Implement optional NaN canonicalization mode #19
Comments
I'm assuming this issue tries to solve the non-determinism problem like so: WebAssembly/design#582 (comment)
Doing this after every operation might be excessive, NaNs with different bit patterns still mostly behave the same. It should be enough to canonicalize in the few places where they don't: Although it would be fun to write a contract that pays out when someone mines it with ARM instead of x86. Might be good for an ARM node bounty! 🤡 |
Yep, the motivation is to prevent non-determinism still having some base2 floats. it's not very important atm, since we can ban floats on the embedder and/or use soft floats in the user space But still might be useful! |
Interesting idea, but how would you actually proof that? : D |
I don't think NaN is only non-determinism part of float points in WebAssembly. Operations like |
Wasm's The ARM subnormal issue is only on 32-bit ARM, and only NEON, not VFP, so wasm's current scalar operations aren't affected. This is a potential concern for the SIMD proposal, however. WebAssembly also fully specifies the behavior of conversion from floats to integers, and the behavior in all the cases where hardware is known to differ is covered in the testsuite too. So while wasm could add rsqrt approximations or other things in the future, and SIMD will have to cope with 32-bit ARM NEON, in the current spec, NaN bit patterns really are the only floating-point nondeterminism. |
@sunfishcode Thank you for so detail clarifying! Now you had dispelled any doubts) |
I thought about how this could be implemented efficiently for Wasmi. Design
This way no performance is lost when NaN canonicalization is disabled but users who require the additional determinism can enable it with minor runtime costs since there won't be runtime checks during execution. NaN canonicalization is a post-processing of a pub trait CanonicalizeNan {
fn canonicalize_nan(self) -> Self;
}
impl CanonicalizeNan for f32 {
fn canonicalize_nan(self) -> Self {
if self.is_nan() {
// Note: This pattern 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.
let canonicalized = Self::from_bits(0x7FC00000_u32);
debug_asssert!(canonicalized.is_nan());
return canonicalized
}
self
}
}
impl CanonicalizeNan for f64 {
fn canonicalize_nan(self) -> Self {
if self.is_nan() {
// Note: This pattern 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.
let canonicalized = Self::from_bits(0x7FF8000000000000);
debug_asssert!(canonicalized.is_nan());
return canonicalized
}
self
}
} |
No description provided.
The text was updated successfully, but these errors were encountered: