Skip to content

Commit 1e1cf25

Browse files
authored
[flang] Fix IEEE_NEAREST_AFTER folding edge cases (#104846)
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.
1 parent 143be4e commit 1e1cf25

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

flang/include/flang/Evaluate/real.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ template <typename WORD, int PREC> class Real {
281281
}
282282
if constexpr (bits == 80) { // x87
283283
// 7FFF8000000000000000 is Infinity, not NaN, on 80387 & later.
284-
infinity.IBSET(63);
284+
infinity = infinity.IBSET(63);
285285
}
286286
return {infinity};
287287
}

flang/lib/Evaluate/fold-real.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -468,11 +468,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
468468
return FoldElementalIntrinsic<T, T, TY>(context, std::move(funcRef),
469469
ScalarFunc<T, T, TY>([&](const Scalar<T> &x,
470470
const Scalar<TY> &y) -> Scalar<T> {
471-
bool reverseCompare{
472-
Scalar<T>::binaryPrecision < Scalar<TY>::binaryPrecision};
473-
switch (reverseCompare
474-
? y.Compare(Scalar<TY>::Convert(x).value)
475-
: x.Compare(Scalar<T>::Convert(y).value)) {
471+
auto xBig{Scalar<LargestReal>::Convert(x).value};
472+
auto yBig{Scalar<LargestReal>::Convert(y).value};
473+
switch (xBig.Compare(yBig)) {
476474
case Relation::Unordered:
477475
if (context.languageFeatures().ShouldWarn(
478476
common::UsageWarning::FoldingValueChecks)) {
@@ -483,9 +481,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
483481
case Relation::Equal:
484482
break;
485483
case Relation::Less:
486-
return x.NEAREST(!reverseCompare).value;
484+
return x.NEAREST(true).value;
487485
case Relation::Greater:
488-
return x.NEAREST(reverseCompare).value;
486+
return x.NEAREST(false).value;
489487
}
490488
return x; // dodge bogus "missing return" GCC warning
491489
}));

flang/test/Evaluate/fold-nearest.f90

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,18 @@ module m3
9191
real(kind(0.d0)), parameter :: x14 = ieee_next_down(nan)
9292
logical, parameter :: test_14 = .not. (x14 == x14)
9393
end module
94+
95+
module m4
96+
use ieee_arithmetic
97+
real(8), parameter :: neg_inf_8 = real(z'fff0000000000000',8)
98+
real(8), parameter :: neg_huge_8 = real(z'ffefffffffffffff',8)
99+
real(10), parameter :: neg_one_10 = real(z'bfff8000000000000000',10)
100+
real(10), parameter :: neg_inf_10 = real(z'ffff8000000000000000',10)
101+
real(2), parameter :: neg_inf_2 = real(z'fc00',2)
102+
real(2), parameter :: neg_huge_2 = real(z'fbff',2)
103+
real(3), parameter :: neg_huge_3 = real(z'ff7f',3)
104+
logical, parameter :: test_1 = ieee_next_after(neg_inf_8,neg_one_10) == neg_huge_8
105+
logical, parameter :: test_2 = ieee_next_after(neg_inf_2, neg_huge_3) == neg_huge_2
106+
logical, parameter :: test_3 = ieee_next_after(neg_one_10, neg_inf_10) == &
107+
real(z'bfff8000000000000001', 10)
108+
end module

0 commit comments

Comments
 (0)