diff --git a/flang/include/flang/Decimal/binary-floating-point.h b/flang/include/flang/Decimal/binary-floating-point.h --- a/flang/include/flang/Decimal/binary-floating-point.h +++ b/flang/include/flang/Decimal/binary-floating-point.h @@ -79,10 +79,26 @@ return (raw_ & ((RawType{1} << (bits - 1)) - 1)) == 0; } constexpr bool IsNaN() const { - return BiasedExponent() == maxExponent && Significand() != 0; + auto expo{BiasedExponent()}; + auto sig{Significand()}; + if constexpr (bits == 80) { // x87 + if (expo == maxExponent) { + return sig != (significandMask >> 1) + 1; + } else { + return expo != 0 && !(sig & (RawType{1} << (significandBits - 1))); + ; + } + } else { + return expo == maxExponent && sig != 0; + } } constexpr bool IsInfinite() const { - return BiasedExponent() == maxExponent && Significand() == 0; + if constexpr (bits == 80) { // x87 + return BiasedExponent() == maxExponent && + Significand() == ((significandMask >> 1) + 1); + } else { + return BiasedExponent() == maxExponent && Significand() == 0; + } } constexpr bool IsMaximalFiniteMagnitude() const { return BiasedExponent() == maxExponent - 1 && diff --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h --- a/flang/include/flang/Evaluate/real.h +++ b/flang/include/flang/Evaluate/real.h @@ -69,19 +69,60 @@ return !IsNotANumber() && IsSignBitSet(); } constexpr bool IsNotANumber() const { - return Exponent() == maxExponent && !GetSignificand().IsZero(); + auto expo{Exponent()}; + auto sig{GetSignificand()}; + if constexpr (bits == 80) { // x87 + // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later. + if (expo == maxExponent) { + return sig != Significand{}.IBSET(63); + } else { + return expo != 0 && !sig.BTEST(63); + } + } else { + return expo == maxExponent && !sig.IsZero(); + } } constexpr bool IsQuietNaN() const { - return Exponent() == maxExponent && - GetSignificand().BTEST(significandBits - 1); + auto expo{Exponent()}; + auto sig{GetSignificand()}; + if constexpr (bits == 80) { // x87 + if (expo == maxExponent) { + return sig.IBITS(62, 2) == 3; + } else { + return expo != 0 && !sig.BTEST(63); + } + } else { + return expo == maxExponent && sig.BTEST(significandBits - 1); + } } constexpr bool IsSignalingNaN() const { - return IsNotANumber() && !GetSignificand().BTEST(significandBits - 1); + auto expo{Exponent()}; + auto sig{GetSignificand()}; + if constexpr (bits == 80) { // x87 + return expo == maxExponent && sig != Significand{}.IBSET(63) && + sig.IBITS(62, 2) != 3; + } else { + return expo == maxExponent && !sig.IsZero() && + !sig.BTEST(significandBits - 1); + } } constexpr bool IsInfinite() const { - return Exponent() == maxExponent && GetSignificand().IsZero(); + if constexpr (bits == 80) { // x87 + // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later. + return Exponent() == maxExponent && + GetSignificand() == Significand{}.IBSET(63); + } else { + return Exponent() == maxExponent && GetSignificand().IsZero(); + } + } + constexpr bool IsFinite() const { + auto expo{Exponent()}; + if constexpr (bits == 80) { // x87 + return expo != maxExponent && (expo == 0 || GetSignificand().BTEST(63)); + } else { + return expo != maxExponent; + } } - constexpr bool IsFinite() const { return Exponent() != maxExponent; } constexpr bool IsZero() const { return Exponent() == 0 && GetSignificand().IsZero(); } @@ -226,6 +267,10 @@ if (negative) { infinity = infinity.IBSET(infinity.bits - 1); } + if constexpr (bits == 80) { // x87 + // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later. + infinity.IBSET(63); + } return {infinity}; } diff --git a/flang/lib/Decimal/big-radix-floating-point.h b/flang/lib/Decimal/big-radix-floating-point.h --- a/flang/lib/Decimal/big-radix-floating-point.h +++ b/flang/lib/Decimal/big-radix-floating-point.h @@ -348,11 +348,26 @@ using Raw = typename Real::RawType; constexpr Raw SignBit() const { return Raw{isNegative_} << (Real::bits - 1); } constexpr Raw Infinity() const { - return (Raw{Real::maxExponent} << Real::significandBits) | SignBit(); + Raw result{static_cast(Real::maxExponent)}; + result <<= Real::significandBits; + result |= SignBit(); + if constexpr (Real::bits == 80) { // x87 + result |= Raw{1} << 63; + } + return result; } constexpr Raw NaN(bool isQuiet = true) { - return (Raw{Real::maxExponent} << Real::significandBits) | - (Raw{1} << (Real::significandBits - (isQuiet ? 1 : 2))) | SignBit(); + Raw result{Real::maxExponent}; + result <<= Real::significandBits; + result |= SignBit(); + if constexpr (Real::bits == 80) { // x87 + result |= Raw{isQuiet ? 3u : 2u} << 62; + } else { + Raw quiet{isQuiet ? Raw{2} : Raw{1}}; + quiet <<= Real::significandBits - 2; + result |= quiet; + } + return result; } Digit digit_[maxDigits]; // in little-endian order: digit_[0] is LSD diff --git a/flang/lib/Decimal/decimal-to-binary.cpp b/flang/lib/Decimal/decimal-to-binary.cpp --- a/flang/lib/Decimal/decimal-to-binary.cpp +++ b/flang/lib/Decimal/decimal-to-binary.cpp @@ -298,7 +298,11 @@ if (expo >= Binary::maxExponent) { expo = Binary::maxExponent; // Inf flags |= Overflow; - fraction = 0; + if constexpr (Binary::bits == 80) { // x87 + fraction = IntType{1} << 63; + } else { + fraction = 0; + } } using Raw = typename Binary::RawType; Raw raw = static_cast(isNegative) << (Binary::bits - 1); diff --git a/flang/test/Evaluate/folding03.f90 b/flang/test/Evaluate/folding03.f90 --- a/flang/test/Evaluate/folding03.f90 +++ b/flang/test/Evaluate/folding03.f90 @@ -138,7 +138,7 @@ real(4), parameter :: r4_nan_add2 = r4_pinf + r4_ninf TEST_ISNAN(r4_nan_add2) - ! No warnings expected here (quite NaN propagation) + ! No warnings expected here (quiet NaN propagation) real(4), parameter :: r4_nan_sub3 = 0._4 - r4_nan TEST_ISNAN(r4_nan_sub3) real(4), parameter :: r4_nan_sub4 = r4_nan - r4_pmax @@ -201,7 +201,7 @@ real(4), parameter :: r4_nan_mult2 = 0._4*r4_ninf TEST_ISNAN(r4_nan_mult2) - ! No warnings expected here (quite NaN propagation) + ! No warnings expected here (quiet NaN propagation) real(4), parameter :: r4_nan_div6 = 0._4/r4_nan TEST_ISNAN(r4_nan_div6) real(4), parameter :: r4_nan_div7 = r4_nan/r4_nan diff --git a/flang/unittests/Evaluate/real.cpp b/flang/unittests/Evaluate/real.cpp --- a/flang/unittests/Evaluate/real.cpp +++ b/flang/unittests/Evaluate/real.cpp @@ -95,7 +95,15 @@ int exponentBits{R::bits - significandBits - 1}; std::uint64_t maxExponent{(std::uint64_t{1} << exponentBits) - 1}; MATCH(nan.Exponent(), maxExponent)(desc); - R inf{Word{maxExponent}.SHIFTL(significandBits)}; + Word infWord{Word{maxExponent}.SHIFTL(significandBits)}; + Word negInfWord{ + Word{maxExponent}.SHIFTL(significandBits).IOR(Word::MASKL(1))}; + if constexpr (kind == 10) { // x87 + infWord = infWord.IBSET(63); + negInfWord = negInfWord.IBSET(63); + } + R inf{infWord}; + R negInf{negInfWord}; TEST(!inf.IsNegative())(desc); TEST(!inf.IsNotANumber())(desc); TEST(inf.IsInfinite())(desc); @@ -106,7 +114,6 @@ TEST(minusZero.Compare(inf) == Relation::Less)(desc); TEST(nan.Compare(inf) == Relation::Unordered)(desc); TEST(inf.Compare(inf) == Relation::Equal)(desc); - R negInf{Word{maxExponent}.SHIFTL(significandBits).IOR(Word::MASKL(1))}; TEST(negInf.IsNegative())(desc); TEST(!negInf.IsNotANumber())(desc); TEST(negInf.IsInfinite())(desc);