[flang-commits] [flang] 0e05ab6 - [flang] Fix interpretations of x87 80-bit Inf/NaN
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Wed May 31 09:22:23 PDT 2023
Author: Peter Klausler
Date: 2023-05-31T09:22:17-07:00
New Revision: 0e05ab6745e7c2c24ec163d1cdf6309b21621d70
URL: https://github.com/llvm/llvm-project/commit/0e05ab6745e7c2c24ec163d1cdf6309b21621d70
DIFF: https://github.com/llvm/llvm-project/commit/0e05ab6745e7c2c24ec163d1cdf6309b21621d70.diff
LOG: [flang] Fix interpretations of x87 80-bit Inf/NaN
Current implementations of x87 80-bit extended precision floating
point interpret 7FFF8000000000000000 as +Inf, not a Nan. The explicit
MSB in the significand must be set for an infinity.
Differential Revision: https://reviews.llvm.org/D151739
Added:
Modified:
flang/include/flang/Decimal/binary-floating-point.h
flang/include/flang/Evaluate/real.h
flang/lib/Decimal/big-radix-floating-point.h
flang/lib/Decimal/decimal-to-binary.cpp
flang/test/Evaluate/folding03.f90
flang/unittests/Evaluate/real.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Decimal/binary-floating-point.h b/flang/include/flang/Decimal/binary-floating-point.h
index b2ff4197ce701..28346e71828fd 100644
--- a/flang/include/flang/Decimal/binary-floating-point.h
+++ b/flang/include/flang/Decimal/binary-floating-point.h
@@ -79,10 +79,26 @@ class BinaryFloatingPointNumber : public common::RealDetails<BINARY_PRECISION> {
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
index d07b0b61c9aa0..a30d0dbfa8e1e 100644
--- a/flang/include/flang/Evaluate/real.h
+++ b/flang/include/flang/Evaluate/real.h
@@ -69,19 +69,60 @@ class Real : public common::RealDetails<PREC> {
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 @@ class Real : public common::RealDetails<PREC> {
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
index 03b76e9abe636..d6b1ccd791fbb 100644
--- a/flang/lib/Decimal/big-radix-floating-point.h
+++ b/flang/lib/Decimal/big-radix-floating-point.h
@@ -348,11 +348,26 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
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<Raw>(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
index d77ec7cbca6e7..c8c7b23329e00 100644
--- a/flang/lib/Decimal/decimal-to-binary.cpp
+++ b/flang/lib/Decimal/decimal-to-binary.cpp
@@ -298,7 +298,11 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
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<Raw>(isNegative) << (Binary::bits - 1);
diff --git a/flang/test/Evaluate/folding03.f90 b/flang/test/Evaluate/folding03.f90
index 26b0e4edff3e0..827bde86757c8 100644
--- a/flang/test/Evaluate/folding03.f90
+++ b/flang/test/Evaluate/folding03.f90
@@ -138,7 +138,7 @@ module real_tests
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 @@ module real_tests
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
index 60e5710b52a43..9701082898388 100644
--- a/flang/unittests/Evaluate/real.cpp
+++ b/flang/unittests/Evaluate/real.cpp
@@ -95,7 +95,15 @@ template <typename R> void basicTests(int rm, Rounding rounding) {
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 @@ template <typename R> void basicTests(int rm, Rounding rounding) {
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);
More information about the flang-commits
mailing list