From 727c08faf01da99d57dfe86b3fb0fee9db415f41 Mon Sep 17 00:00:00 2001 From: JF Bastien Date: Thu, 5 May 2016 15:54:23 -0700 Subject: Fix NaN / 0 (#442) As discussed in: https://github.com/WebAssembly/spec/pull/282#issuecomment-217280544 --- src/wasm.h | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/wasm.h b/src/wasm.h index 6b171f8bd..9c3bc9022 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -246,11 +246,37 @@ private: } } + static uint32_t NaNPayload(float f) { + assert(std::isnan(f) && "expected a NaN"); + // SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + // NaN has all-one exponent and non-zero fraction. + return ~0xff800000u & bit_cast(f); + } + + static uint64_t NaNPayload(double f) { + assert(std::isnan(f) && "expected a NaN"); + // SEEEEEEE EEEEFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF + // NaN has all-one exponent and non-zero fraction. + return ~0xfff0000000000000ull & bit_cast(f); + } + + static float setQuietNaN(float f) { + assert(std::isnan(f) && "expected a NaN"); + // An SNaN is a NaN with the most significant fraction bit clear. + return bit_cast(0x00400000u | bit_cast(f)); + } + + static double setQuietNaN(double f) { + assert(std::isnan(f) && "expected a NaN"); + // An SNaN is a NaN with the most significant fraction bit clear. + return bit_cast(0x0008000000000000ull | bit_cast(f)); + } + static void printFloat(std::ostream &o, float f) { if (std::isnan(f)) { const char *sign = std::signbit(f) ? "-" : ""; o << sign << "nan"; - if (uint32_t payload = ~0xff800000u & bit_cast(f)) { + if (uint32_t payload = NaNPayload(f)) { o << ":0x" << std::hex << payload << std::dec; } return; @@ -266,7 +292,7 @@ private: if (std::isnan(d)) { const char *sign = std::signbit(d) ? "-" : ""; o << sign << "nan"; - if (uint64_t payload = ~0xfff0000000000000ull & bit_cast(d)) { + if (uint64_t payload = NaNPayload(d)) { o << ":0x" << std::hex << payload << std::dec; } return; @@ -448,7 +474,7 @@ private: switch (std::fpclassify(rhs)) { case FP_ZERO: switch (std::fpclassify(lhs)) { - case FP_NAN: return *this; + case FP_NAN: return Literal(setQuietNaN(lhs)); case FP_ZERO: return Literal(std::copysign(std::numeric_limits::quiet_NaN(), sign)); case FP_NORMAL: // fallthrough case FP_SUBNORMAL: // fallthrough @@ -468,7 +494,7 @@ private: switch (std::fpclassify(rhs)) { case FP_ZERO: switch (std::fpclassify(lhs)) { - case FP_NAN: return *this; + case FP_NAN: return Literal(setQuietNaN(lhs)); case FP_ZERO: return Literal(std::copysign(std::numeric_limits::quiet_NaN(), sign)); case FP_NORMAL: // fallthrough case FP_SUBNORMAL: // fallthrough -- cgit v1.2.3