[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