[flang-commits] [flang] 1d1f5a5 - [flang] Handle subnormals while folding SCALE, SET_EXPONENT, & FRACTION

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Sun Aug 7 16:12:28 PDT 2022


Author: Peter Klausler
Date: 2022-08-07T16:12:14-07:00
New Revision: 1d1f5a5251f7570615f0669a56af0ac5b8b302bc

URL: https://github.com/llvm/llvm-project/commit/1d1f5a5251f7570615f0669a56af0ac5b8b302bc
DIFF: https://github.com/llvm/llvm-project/commit/1d1f5a5251f7570615f0669a56af0ac5b8b302bc.diff

LOG: [flang] Handle subnormals while folding SCALE, SET_EXPONENT, & FRACTION

The implementations of folding for the intrinsic functions SCALE and SET_EXPONENT
do not cope correctly with numbers in the subnormal range.  Fix SCALE,
then modify SET_EXPONENT to be a special case of SCALE.

Differential Revision: https://reviews.llvm.org/D131099

Added: 
    

Modified: 
    flang/include/flang/Evaluate/real.h
    flang/lib/Evaluate/real.cpp
    flang/test/Evaluate/folding07.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h
index 916b8bedfdab3..e727ac1ec7191 100644
--- a/flang/include/flang/Evaluate/real.h
+++ b/flang/include/flang/Evaluate/real.h
@@ -177,17 +177,21 @@ class Real : public common::RealDetails<PREC> {
   template <typename INT>
   ValueWithRealFlags<Real> SCALE(const INT &by,
       Rounding rounding = TargetCharacteristics::defaultRounding) const {
-    auto expo{exponentBias + by.ToInt64()};
+    // Normalize a fraction with just its LSB set and then multiply.
+    // (Set the LSB, not the MSB, in case the scale factor needs to
+    //  be subnormal.)
+    auto adjust{exponentBias + binaryPrecision - 1};
+    auto expo{adjust + by.ToInt64()};
     if (IsZero()) {
       expo = exponentBias; // ignore by, don't overflow
     } else if (by > INT{maxExponent}) {
-      expo = maxExponent;
-    } else if (by < INT{-exponentBias}) {
+      expo = maxExponent + binaryPrecision - 1;
+    } else if (by < INT{-adjust}) {
       expo = -1;
     }
     Real twoPow;
     RealFlags flags{
-        twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKL(1))};
+        twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKR(1))};
     ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};
     result.flags |= flags;
     return result;

diff  --git a/flang/lib/Evaluate/real.cpp b/flang/lib/Evaluate/real.cpp
index 5ffbf2fb16ee4..0af0ef2bf945b 100644
--- a/flang/lib/Evaluate/real.cpp
+++ b/flang/lib/Evaluate/real.cpp
@@ -765,9 +765,7 @@ Real<W, P> Real<W, P>::SET_EXPONENT(int expo) const {
   } else if (IsZero()) {
     return *this;
   } else {
-    Real result;
-    result.Normalize(IsNegative(), expo + exponentBias - 1, GetFraction());
-    return result;
+    return SCALE(Integer<32>(expo - UnbiasedExponent() - 1)).value;
   }
 }
 

diff  --git a/flang/test/Evaluate/folding07.f90 b/flang/test/Evaluate/folding07.f90
index d5ce9ac0d7897..fd106ab9bf016 100644
--- a/flang/test/Evaluate/folding07.f90
+++ b/flang/test/Evaluate/folding07.f90
@@ -280,5 +280,6 @@ module m
   logical, parameter :: test_set_exponent_0 = set_exponent(1., 0) == 0.5
   logical, parameter :: test_set_exponent_1 = set_exponent(1., 1) == 1.
   logical, parameter :: test_set_exponent_2 = set_exponent(1., 2) == 2.
+  logical, parameter :: test_set_exponent_min = set_exponent(1., -149) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45_4
 
 end module


        


More information about the flang-commits mailing list