diff --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h --- a/flang/include/flang/Evaluate/real.h +++ b/flang/include/flang/Evaluate/real.h @@ -170,7 +170,7 @@ static constexpr int MINEXPONENT{2 - exponentBias}; Real RRSPACING() const; Real SPACING() const; - Real SET_EXPONENT(int) const; + Real SET_EXPONENT(std::int64_t) const; Real FRACTION() const; // SCALE(); also known as IEEE_SCALB and (in IEEE-754 '08) ScaleB. @@ -182,16 +182,20 @@ // be subnormal.) auto adjust{exponentBias + binaryPrecision - 1}; auto expo{adjust + by.ToInt64()}; + Real twoPow; + RealFlags flags; + int rMask{1}; if (IsZero()) { expo = exponentBias; // ignore by, don't overflow } else if (by > INT{maxExponent}) { expo = maxExponent + binaryPrecision - 1; - } else if (by < INT{-adjust}) { - expo = -1; + } else if (by < INT{-adjust}) { // underflow + expo = 0; + rMask = 0; + flags.set(RealFlag::Underflow); } - Real twoPow; - RealFlags flags{ - twoPow.Normalize(false, static_cast(expo), Fraction::MASKR(1))}; + flags |= + twoPow.Normalize(false, static_cast(expo), Fraction::MASKR(rMask)); ValueWithRealFlags result{Multiply(twoPow, rounding)}; result.flags |= flags; return result; diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp --- a/flang/lib/Evaluate/fold-real.cpp +++ b/flang/lib/Evaluate/fold-real.cpp @@ -257,11 +257,18 @@ byExpr->u); } } else if (name == "set_exponent") { - return FoldElementalIntrinsic(context, std::move(funcRef), - ScalarFunc( - [&](const Scalar &x, const Scalar &i) -> Scalar { - return x.SET_EXPONENT(i.ToInt64()); - })); + if (const auto *iExpr{UnwrapExpr>(args[1])}) { + return common::visit( + [&](const auto &iVal) { + using TY = ResultType; + return FoldElementalIntrinsic(context, std::move(funcRef), + ScalarFunc( + [&](const Scalar &x, const Scalar &i) -> Scalar { + return x.SET_EXPONENT(i.ToInt64()); + })); + }, + iExpr->u); + } } else if (name == "sign") { return FoldElementalIntrinsic( context, std::move(funcRef), &Scalar::SIGN); diff --git a/flang/lib/Evaluate/real.cpp b/flang/lib/Evaluate/real.cpp --- a/flang/lib/Evaluate/real.cpp +++ b/flang/lib/Evaluate/real.cpp @@ -756,7 +756,7 @@ // 16.9.171 template -Real Real::SET_EXPONENT(int expo) const { +Real Real::SET_EXPONENT(std::int64_t expo) const { if (IsNotANumber()) { return *this; } else if (IsInfinite()) { @@ -764,7 +764,7 @@ } else if (IsZero()) { return *this; } else { - return SCALE(Integer<32>(expo - UnbiasedExponent() - 1)).value; + return SCALE(Integer<64>(expo - UnbiasedExponent() - 1)).value; } }