Skip to content

Commit a7fd052

Browse files
Canonicalize NaNs when casting between float and double (#8645)
Fixes #8626. Also part of #8261. The bug is due to the fact that C++ doesn't guarantee a bitwise representation for NaNs that are casted from double -> float or vice versa. From https://en.cppreference.com/cpp/language/implicit_conversion: > Floating-point promotion A [prvalue](https://en.cppreference.com/cpp/language/value_category#prvalue) of type float can be converted to a prvalue of type double. The value does not change. In the case of NaNs, the value (NaN) is preserved regardless of the particular NaN that is picked, so we have no guarantee of the bitwise representation. And for double -> float: > If the conversion is listed under floating-point promotions, it is a promotion and not a conversion. > * If the source value can be represented exactly in the destination type, it does not change. > * If the source value is between two representable values of the destination type, the result is one of those two values (it is implementation-defined which one, although if IEEE arithmetic is supported, rounding defaults [to nearest](https://en.cppreference.com/cpp/numeric/fenv/FE_round)). > * Otherwise, the behavior is undefined. I assume NaN conversions again fall under case 1 meaning that the "value" (NaN) is preserved but not the bitwise representation. Canonicalize NaNs after promotion or demotion to ensure that the quiet bit remains set.
1 parent 35ba23c commit a7fd052

1 file changed

Lines changed: 4 additions & 3 deletions

File tree

src/wasm/literal.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ Literal Literal::extendToUI64() const {
864864

865865
Literal Literal::extendToF64() const {
866866
assert(type == Type::f32);
867-
return Literal(double(getf32()));
867+
return standardizeNaN(Literal(static_cast<double>(getf32())));
868868
}
869869

870870
Literal Literal::extendS8() const {
@@ -1164,7 +1164,7 @@ Literal Literal::sqrt() const {
11641164
Literal Literal::demote() const {
11651165
auto f64 = getf64();
11661166
if (std::isnan(f64)) {
1167-
return Literal(float(f64));
1167+
return standardizeNaN(Literal(static_cast<float>(f64)));
11681168
}
11691169
if (std::isinf(f64)) {
11701170
return Literal(float(f64));
@@ -2786,7 +2786,8 @@ template<LaneOrder Side> Literal extendF32(const Literal& vec) {
27862786
LaneArray<2> result;
27872787
for (size_t i = 0; i < 2; ++i) {
27882788
size_t idx = (Side == LaneOrder::Low) ? i : i + 2;
2789-
result[i] = Literal((double)lanes[idx].getf32());
2789+
result[i] = Literal::standardizeNaN(
2790+
Literal(static_cast<double>(lanes[idx].getf32())));
27902791
}
27912792
return Literal(result);
27922793
}

0 commit comments

Comments
 (0)