Skip to content

Commit

Permalink
[flang] Fold SCALE()
Browse files Browse the repository at this point in the history
Fold references to the intrinsic function SCALE().

(Also work around some MSVC headaches somehow exposed by
this patch: disable a bogus MSVC warning that began to appear
in unrelated source files, and avoid the otherwise-necessary
use of the "template" keyword in a call to a template member
function of a class template.)

Differential Revision: https://reviews.llvm.org/D117150
  • Loading branch information
klausler committed Jan 15, 2022
1 parent cba72e4 commit 5c5bde1
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 1 deletion.
20 changes: 20 additions & 0 deletions flang/include/flang/Evaluate/real.h
Expand Up @@ -155,6 +155,26 @@ class Real : public common::RealDetails<PREC> {
static constexpr int MAXEXPONENT{maxExponent - exponentBias};
static constexpr int MINEXPONENT{2 - exponentBias};

// SCALE(); also known as IEEE_SCALB and (in IEEE-754 '08) ScaleB.
template <typename INT>
ValueWithRealFlags<Real> SCALE(
const INT &by, Rounding rounding = defaultRounding) const {
auto expo{exponentBias + by.ToInt64()};
if (IsZero()) {
expo = exponentBias; // ignore by, don't overflow
} else if (by > INT{maxExponent}) {
expo = maxExponent;
} else if (by < INT{-exponentBias}) {
expo = -1;
}
Real twoPow;
RealFlags flags{
twoPow.Normalize(false, static_cast<int>(expo), Fraction::MASKL(1))};
ValueWithRealFlags<Real> result{Multiply(twoPow, rounding)};
result.flags |= flags;
return result;
}

constexpr Real FlushSubnormalToZero() const {
if (IsSubnormal()) {
return Real{};
Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/constant.cpp
Expand Up @@ -342,5 +342,8 @@ bool ComponentCompare::operator()(SymbolRef x, SymbolRef y) const {
return semantics::SymbolSourcePositionCompare{}(x, y);
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
INSTANTIATE_CONSTANT_TEMPLATES
} // namespace Fortran::evaluate
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/expression.cpp
Expand Up @@ -324,5 +324,8 @@ std::optional<Expr<SubscriptInteger>> Expr<SomeCharacter>::LEN() const {
return std::visit([](const auto &kx) { return kx.LEN(); }, u);
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
INSTANTIATE_EXPRESSION_TEMPLATES
} // namespace Fortran::evaluate
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/fold-character.cpp
Expand Up @@ -140,6 +140,9 @@ Expr<Type<TypeCategory::Character, KIND>> FoldOperation(
return Expr<Result>{std::move(x)};
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
FOR_EACH_CHARACTER_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeCharacter>;
} // namespace Fortran::evaluate
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/fold-complex.cpp
Expand Up @@ -78,6 +78,9 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldOperation(
return Expr<Result>{std::move(x)};
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
FOR_EACH_COMPLEX_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeComplex>;
} // namespace Fortran::evaluate
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/fold-integer.cpp
Expand Up @@ -1020,6 +1020,9 @@ std::optional<std::int64_t> ToInt64(const Expr<SomeType> &expr) {
}
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
FOR_EACH_INTEGER_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeInteger>;
} // namespace Fortran::evaluate
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/fold-logical.cpp
Expand Up @@ -254,6 +254,9 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldOperation(
return Expr<LOGICAL>{std::move(operation)};
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
FOR_EACH_LOGICAL_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeLogical>;
} // namespace Fortran::evaluate
30 changes: 29 additions & 1 deletion flang/lib/Evaluate/fold-real.cpp
Expand Up @@ -130,6 +130,31 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (auto *expr{args[0].value().UnwrapExpr()}) {
return ToReal<KIND>(context, std::move(*expr));
}
} else if (name == "scale") {
if (const auto *byExpr{UnwrapExpr<Expr<SomeInteger>>(args[1])}) {
return std::visit(
[&](const auto &byVal) {
using TBY = ResultType<decltype(byVal)>;
return FoldElementalIntrinsic<T, T, TBY>(context,
std::move(funcRef),
ScalarFunc<T, T, TBY>(
[&](const Scalar<T> &x, const Scalar<TBY> &y) -> Scalar<T> {
ValueWithRealFlags<Scalar<T>> result{x.
// MSVC chokes on the keyword "template" here in a call to a
// member function template.
#ifndef _MSC_VER
template
#endif
SCALE(y)};
if (result.flags.test(RealFlag::Overflow)) {
context.messages().Say(
"SCALE intrinsic folding overflow"_en_US);
}
return result.value;
}));
},
byExpr->u);
}
} else if (name == "sign") {
return FoldElementalIntrinsic<T, T, T>(
context, std::move(funcRef), &Scalar<T>::SIGN);
Expand All @@ -143,7 +168,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
return Expr<T>{Scalar<T>::TINY()};
}
// TODO: dim, dot_product, fraction, matmul,
// modulo, nearest, norm2, rrspacing, scale,
// modulo, nearest, norm2, rrspacing,
// __builtin_next_after/down/up,
// set_exponent, spacing, transfer,
// bessel_jn (transformational) and bessel_yn (transformational)
Expand Down Expand Up @@ -175,6 +200,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(
return Expr<Part>{std::move(x)};
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
FOR_EACH_REAL_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeReal>;
} // namespace Fortran::evaluate
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/formatting.cpp
Expand Up @@ -785,6 +785,9 @@ llvm::raw_ostream &Assignment::AsFortran(llvm::raw_ostream &o) const {
return o;
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
INSTANTIATE_CONSTANT_TEMPLATES
INSTANTIATE_EXPRESSION_TEMPLATES
INSTANTIATE_VARIABLE_TEMPLATES
Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Evaluate/variable.cpp
Expand Up @@ -685,6 +685,9 @@ bool DescriptorInquiry::operator==(const DescriptorInquiry &that) const {
dimension_ == that.dimension_;
}

#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
INSTANTIATE_VARIABLE_TEMPLATES
} // namespace Fortran::evaluate

Expand Down
6 changes: 6 additions & 0 deletions flang/test/Evaluate/errors01.f90
Expand Up @@ -100,4 +100,10 @@ subroutine s9
!CHECK: error: DIM=4 argument to SPREAD must be between 1 and 3
integer, parameter :: bad3 = spread(matrix, 4, 1)
end subroutine
subroutine warnings
real, parameter :: ok1 = scale(0.0, 99999) ! 0.0
real, parameter :: ok2 = scale(1.0, -99999) ! 0.0
!CHECK: SCALE intrinsic folding overflow
real, parameter :: bad1 = scale(1.0, 99999)
end subroutine
end module
11 changes: 11 additions & 0 deletions flang/test/Evaluate/fold-scale.f90
@@ -0,0 +1,11 @@
! RUN: %python %S/test_folding.py %s %flang_fc1
! Tests folding of SCALE()
module m
logical, parameter :: test_1 = scale(1.0, 1) == 2.0
logical, parameter :: test_2 = scale(0.0, 1) == 0.0
logical, parameter :: test_3 = sign(1.0, scale(-0.0, 1)) == -1.0
logical, parameter :: test_4 = sign(1.0, scale(0.0, 0)) == 1.0
logical, parameter :: test_5 = scale(1.0, -1) == 0.5
logical, parameter :: test_6 = scale(2.0, -1) == 1.0
end module

0 comments on commit 5c5bde1

Please sign in to comment.