[flang-commits] [flang] [flang] Fix IEEE_NEAREST_AFTER folding edge cases (PR #104846)

via flang-commits flang-commits at lists.llvm.org
Mon Aug 19 13:08:20 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

Conversions of infinities from other kinds to real(10) were incorrect, and comparisons of real(2) vs real(3) are dicey as conversions in one direction can overflow and conversions in the other can lose precision.  Use real(16) as the common type for comparisons in IEEE_NEAREST_AFTER.

---
Full diff: https://github.com/llvm/llvm-project/pull/104846.diff


3 Files Affected:

- (modified) flang/include/flang/Evaluate/real.h (+1-1) 
- (modified) flang/lib/Evaluate/fold-real.cpp (+5-7) 
- (modified) flang/test/Evaluate/fold-nearest.f90 (+15) 


``````````diff
diff --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h
index cb3c0036e0cfae..11cc8f776b0e95 100644
--- a/flang/include/flang/Evaluate/real.h
+++ b/flang/include/flang/Evaluate/real.h
@@ -281,7 +281,7 @@ template <typename WORD, int PREC> class Real {
     }
     if constexpr (bits == 80) { // x87
       // 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later.
-      infinity.IBSET(63);
+      infinity = infinity.IBSET(63);
     }
     return {infinity};
   }
diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp
index 15a9bcf6dbd854..fd8eca28a679c1 100644
--- a/flang/lib/Evaluate/fold-real.cpp
+++ b/flang/lib/Evaluate/fold-real.cpp
@@ -468,11 +468,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
             return FoldElementalIntrinsic<T, T, TY>(context, std::move(funcRef),
                 ScalarFunc<T, T, TY>([&](const Scalar<T> &x,
                                          const Scalar<TY> &y) -> Scalar<T> {
-                  bool reverseCompare{
-                      Scalar<T>::binaryPrecision < Scalar<TY>::binaryPrecision};
-                  switch (reverseCompare
-                          ? y.Compare(Scalar<TY>::Convert(x).value)
-                          : x.Compare(Scalar<T>::Convert(y).value)) {
+                  auto xBig{Scalar<LargestReal>::Convert(x).value};
+                  auto yBig{Scalar<LargestReal>::Convert(y).value};
+                  switch (xBig.Compare(yBig)) {
                   case Relation::Unordered:
                     if (context.languageFeatures().ShouldWarn(
                             common::UsageWarning::FoldingValueChecks)) {
@@ -483,9 +481,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
                   case Relation::Equal:
                     break;
                   case Relation::Less:
-                    return x.NEAREST(!reverseCompare).value;
+                    return x.NEAREST(true).value;
                   case Relation::Greater:
-                    return x.NEAREST(reverseCompare).value;
+                    return x.NEAREST(false).value;
                   }
                   return x; // dodge bogus "missing return" GCC warning
                 }));
diff --git a/flang/test/Evaluate/fold-nearest.f90 b/flang/test/Evaluate/fold-nearest.f90
index 7ca7757f79664e..bb53db928443cc 100644
--- a/flang/test/Evaluate/fold-nearest.f90
+++ b/flang/test/Evaluate/fold-nearest.f90
@@ -91,3 +91,18 @@ module m3
   real(kind(0.d0)), parameter :: x14 = ieee_next_down(nan)
   logical, parameter :: test_14 = .not. (x14 == x14)
 end module
+
+module m4
+  use ieee_arithmetic
+  real(8), parameter :: neg_inf_8  = real(z'fff0000000000000',8)
+  real(8), parameter :: neg_huge_8 = real(z'ffefffffffffffff',8)
+  real(10), parameter :: neg_one_10 = real(z'bfff8000000000000000',10)
+  real(10), parameter :: neg_inf_10 = real(z'ffff8000000000000000',10)
+  real(2), parameter :: neg_inf_2 = real(z'fc00',2)
+  real(2), parameter :: neg_huge_2 = real(z'fbff',2)
+  real(3), parameter :: neg_huge_3 = real(z'ff7f',3)
+  logical, parameter :: test_1 = ieee_next_after(neg_inf_8,neg_one_10) == neg_huge_8
+  logical, parameter :: test_2 = ieee_next_after(neg_inf_2, neg_huge_3) == neg_huge_2
+  logical, parameter :: test_3 = ieee_next_after(neg_one_10, neg_inf_10) == &
+                                 real(z'bfff8000000000000001', 10)
+end module

``````````

</details>


https://github.com/llvm/llvm-project/pull/104846


More information about the flang-commits mailing list