Skip to content

Commit 727c08f

Browse files
committed
Fix NaN / 0 (#442)
As discussed in: WebAssembly/spec#282 (comment)
1 parent 4dfa393 commit 727c08f

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

src/wasm.h

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,37 @@ class Literal {
246246
}
247247
}
248248

249+
static uint32_t NaNPayload(float f) {
250+
assert(std::isnan(f) && "expected a NaN");
251+
// SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
252+
// NaN has all-one exponent and non-zero fraction.
253+
return ~0xff800000u & bit_cast<uint32_t>(f);
254+
}
255+
256+
static uint64_t NaNPayload(double f) {
257+
assert(std::isnan(f) && "expected a NaN");
258+
// SEEEEEEE EEEEFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
259+
// NaN has all-one exponent and non-zero fraction.
260+
return ~0xfff0000000000000ull & bit_cast<uint64_t>(f);
261+
}
262+
263+
static float setQuietNaN(float f) {
264+
assert(std::isnan(f) && "expected a NaN");
265+
// An SNaN is a NaN with the most significant fraction bit clear.
266+
return bit_cast<float>(0x00400000u | bit_cast<uint32_t>(f));
267+
}
268+
269+
static double setQuietNaN(double f) {
270+
assert(std::isnan(f) && "expected a NaN");
271+
// An SNaN is a NaN with the most significant fraction bit clear.
272+
return bit_cast<double>(0x0008000000000000ull | bit_cast<uint64_t>(f));
273+
}
274+
249275
static void printFloat(std::ostream &o, float f) {
250276
if (std::isnan(f)) {
251277
const char *sign = std::signbit(f) ? "-" : "";
252278
o << sign << "nan";
253-
if (uint32_t payload = ~0xff800000u & bit_cast<uint32_t>(f)) {
279+
if (uint32_t payload = NaNPayload(f)) {
254280
o << ":0x" << std::hex << payload << std::dec;
255281
}
256282
return;
@@ -266,7 +292,7 @@ class Literal {
266292
if (std::isnan(d)) {
267293
const char *sign = std::signbit(d) ? "-" : "";
268294
o << sign << "nan";
269-
if (uint64_t payload = ~0xfff0000000000000ull & bit_cast<uint64_t>(d)) {
295+
if (uint64_t payload = NaNPayload(d)) {
270296
o << ":0x" << std::hex << payload << std::dec;
271297
}
272298
return;
@@ -448,7 +474,7 @@ class Literal {
448474
switch (std::fpclassify(rhs)) {
449475
case FP_ZERO:
450476
switch (std::fpclassify(lhs)) {
451-
case FP_NAN: return *this;
477+
case FP_NAN: return Literal(setQuietNaN(lhs));
452478
case FP_ZERO: return Literal(std::copysign(std::numeric_limits<float>::quiet_NaN(), sign));
453479
case FP_NORMAL: // fallthrough
454480
case FP_SUBNORMAL: // fallthrough
@@ -468,7 +494,7 @@ class Literal {
468494
switch (std::fpclassify(rhs)) {
469495
case FP_ZERO:
470496
switch (std::fpclassify(lhs)) {
471-
case FP_NAN: return *this;
497+
case FP_NAN: return Literal(setQuietNaN(lhs));
472498
case FP_ZERO: return Literal(std::copysign(std::numeric_limits<double>::quiet_NaN(), sign));
473499
case FP_NORMAL: // fallthrough
474500
case FP_SUBNORMAL: // fallthrough

0 commit comments

Comments
 (0)