diff --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h index 14f26dfb52ff..2f4f7b2c4775 100644 --- a/flang/include/flang/Evaluate/real.h +++ b/flang/include/flang/Evaluate/real.h @@ -196,6 +196,10 @@ public: .IBSET(significandBits - 2)}; } + static constexpr Real PositiveZero() { return Real{}; } + + static constexpr Real NegativeZero() { return {Word{}.MASKL(1)}; } + static constexpr Real Infinity(bool negative) { Word infinity{maxExponent}; infinity = infinity.SHIFTL(significandBits); diff --git a/flang/lib/Evaluate/real.cpp b/flang/lib/Evaluate/real.cpp index d273e76d70e1..eb6bd148e341 100644 --- a/flang/lib/Evaluate/real.cpp +++ b/flang/lib/Evaluate/real.cpp @@ -98,7 +98,7 @@ ValueWithRealFlags> Real::Add( if (order == Ordering::Equal) { // x + (-x) -> +0.0 unless rounding is directed downwards if (rounding.mode == common::RoundingMode::Down) { - result.value.word_ = result.value.word_.IBSET(bits - 1); // -0.0 + result.value = NegativeZero(); } return result; } @@ -221,7 +221,7 @@ ValueWithRealFlags> Real::Divide( } } else if (IsZero() || y.IsInfinite()) { // 0/x, x/Inf -> 0 if (isNegative) { - result.value.word_ = result.value.word_.IBSET(bits - 1); + result.value = NegativeZero(); } } else { // dividend and divisor are both finite and nonzero numbers @@ -272,13 +272,15 @@ ValueWithRealFlags> Real::SQRT(Rounding rounding) const { } else if (IsNegative()) { if (IsZero()) { // SQRT(-0) == -0 in IEEE-754. - result.value.word_ = result.value.word_.IBSET(bits - 1); + result.value = NegativeZero(); } else { result.value = NotANumber(); } } else if (IsInfinite()) { // SQRT(+Inf) == +Inf result.value = Infinity(false); + } else if (IsZero()) { + result.value = PositiveZero(); } else { int expo{UnbiasedExponent()}; if (expo < -1 || expo > 1) { diff --git a/flang/test/Evaluate/folding28.f90 b/flang/test/Evaluate/folding28.f90 index 95db37abe832..004c661692fe 100644 --- a/flang/test/Evaluate/folding28.f90 +++ b/flang/test/Evaluate/folding28.f90 @@ -44,4 +44,9 @@ module m logical, parameter :: test_before_1 = sqrt_before_1 == before_1 real(4), parameter :: sq_sqrt_before_1 = sqrt_before_1 * sqrt_before_1 logical, parameter :: test_sq_before_1 = sq_sqrt_before_1 < before_1 + ! ICE at 0.0 + real(4), parameter :: sqrt_zero_4 = sqrt(0.0) + logical, parameter :: test_sqrt_zero_4 = sqrt_zero_4 == 0.0 + real(8), parameter :: sqrt_zero_8 = sqrt(0.0) + logical, parameter :: test_sqrt_zero_8 = sqrt_zero_8 == 0.0 end module