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

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


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

>From 1160693f68300437d9643cdcc2fa8ead80ee3df2 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 19 Aug 2024 13:03:12 -0700
Subject: [PATCH] [flang] Fix IEEE_NEAREST_AFTER folding edge cases

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.
---
 flang/include/flang/Evaluate/real.h  |  2 +-
 flang/lib/Evaluate/fold-real.cpp     | 12 +++++-------
 flang/test/Evaluate/fold-nearest.f90 | 15 +++++++++++++++
 3 files changed, 21 insertions(+), 8 deletions(-)

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



More information about the flang-commits mailing list