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 @@ -160,6 +160,8 @@ static constexpr int RANGE{Details::decimalRange}; static constexpr int MAXEXPONENT{maxExponent - exponentBias}; static constexpr int MINEXPONENT{2 - exponentBias}; + Real RRSPACING() const; + Real SPACING() const; // SCALE(); also known as IEEE_SCALB and (in IEEE-754 '08) ScaleB. template 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 @@ -190,6 +190,10 @@ if (auto *expr{args[0].value().UnwrapExpr()}) { return ToReal(context, std::move(*expr)); } + } else if (name == "rrspacing") { + return FoldElementalIntrinsic(context, std::move(funcRef), + ScalarFunc( + [](const Scalar &x) -> Scalar { return x.RRSPACING(); })); } else if (name == "scale") { if (const auto *byExpr{UnwrapExpr>(args[1])}) { return common::visit( @@ -218,6 +222,10 @@ } else if (name == "sign") { return FoldElementalIntrinsic( context, std::move(funcRef), &Scalar::SIGN); + } else if (name == "spacing") { + return FoldElementalIntrinsic(context, std::move(funcRef), + ScalarFunc( + [](const Scalar &x) -> Scalar { return x.SPACING(); })); } else if (name == "sqrt") { return FoldElementalIntrinsic(context, std::move(funcRef), ScalarFunc( @@ -277,8 +285,7 @@ })); } // TODO: dim, dot_product, fraction, matmul, - // modulo, norm2, rrspacing, - // set_exponent, spacing, transfer, + // modulo, norm2, set_exponent, transfer, return Expr{std::move(funcRef)}; } 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 @@ -686,6 +686,35 @@ return o; } +// 16.9.180 +template Real Real::RRSPACING() const { + if (IsNotANumber()) { + return *this; + } else if (IsInfinite()) { + return NotANumber(); + } else { + Real result; + result.Normalize(false, binaryPrecision + exponentBias - 1, GetFraction()); + return result; + } +} + +// 16.9.180 +template Real Real::SPACING() const { + if (IsNotANumber()) { + return *this; + } else if (IsInfinite()) { + return NotANumber(); + } else if (IsZero()) { + return TINY(); + } else { + Real result; + result.Normalize( + false, Exponent() - binaryPrecision + 1, Fraction::MASKL(1)); + return result; + } +} + template class Real, 11>; template class Real, 8>; template class Real, 24>; diff --git a/flang/test/Evaluate/fold-spacing.f90 b/flang/test/Evaluate/fold-spacing.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Evaluate/fold-spacing.f90 @@ -0,0 +1,12 @@ +! RUN: %python %S/test_folding.py %s %flang_fc1 +! Tests folding of SPACING() and RRSPACING +module m + logical, parameter :: test_1 = spacing(3.0) == scale(1.0, -22) + logical, parameter :: test_2 = spacing(-3.0) == scale(1.0, -22) + logical, parameter :: test_3 = spacing(3.0d0) == scale(1.0, -51) + logical, parameter :: test_4 = spacing(0.) == tiny(0.) + logical, parameter :: test_11 = rrspacing(3.0) == scale(0.75, 24) + logical, parameter :: test_12 = rrspacing(-3.0) == scale(0.75, 24) + logical, parameter :: test_13 = rrspacing(3.0d0) == scale(0.75, 53) + logical, parameter :: test_14 = rrspacing(0.) == 0. +end module