From a99e9c99f3e983d6de2a6fab377b6ef922e0ba89 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Wed, 24 Oct 2018 14:06:46 -0700 Subject: [PATCH] [flang] complete new Fold Original-commit: flang-compiler/f18@4d1726778f193c8813a8cc63fad0b46faf8d2fec Reviewed-on: https://github.com/flang-compiler/f18/pull/219 Tree-same-pre-rewrite: false --- flang/lib/evaluate/common.h | 32 +++++++++ flang/lib/evaluate/expression.h | 10 ++- flang/lib/evaluate/fold.h | 139 ++++++++++++++++++++++++++++++---------- 3 files changed, 143 insertions(+), 38 deletions(-) diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index 785068c..701c58b 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -16,6 +16,7 @@ #define FORTRAN_EVALUATE_COMMON_H_ #include "../common/enum-set.h" +#include "../common/fortran.h" #include "../common/idioms.h" #include "../common/indirection.h" #include "../parser/message.h" @@ -23,6 +24,8 @@ namespace Fortran::evaluate { +using common::RelationalOperator; + // Integers are always ordered; reals may not be. ENUM_CLASS(Ordering, Less, Equal, Greater) ENUM_CLASS(Relation, Less, Equal, Greater, Unordered) @@ -67,6 +70,35 @@ static constexpr Relation Reverse(Relation relation) { } } +static constexpr bool Satisfies(RelationalOperator op, Ordering order) { + switch (order) { + case Ordering::Less: + return op == RelationalOperator::LT || op == RelationalOperator::LE || + op == RelationalOperator::NE; + case Ordering::Equal: + return op == RelationalOperator::LE || op == RelationalOperator::EQ || + op == RelationalOperator::GE; + case Ordering::Greater: + return op == RelationalOperator::NE || op == RelationalOperator::GE || + op == RelationalOperator::GT; + } +} + +static constexpr bool Satisfies(RelationalOperator op, Relation relation) { + switch (relation) { + case Relation::Less: + return op == RelationalOperator::LT || op == RelationalOperator::LE || + op == RelationalOperator::NE; + case Relation::Equal: + return op == RelationalOperator::LE || op == RelationalOperator::EQ || + op == RelationalOperator::GE; + case Relation::Greater: + return op == RelationalOperator::NE || op == RelationalOperator::GE || + op == RelationalOperator::GT; + case Relation::Unordered: return false; + } +} + ENUM_CLASS( RealFlag, Overflow, DivideByZero, InvalidArgument, Underflow, Inexact) diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index d3f0042..1030dfc 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -529,9 +529,12 @@ FOR_EACH_CHARACTER_KIND(extern template class Expr) template struct Relational : public Operation, LogicalResult, A, A> { + using Result = LogicalResult; using Base = Operation; - using typename Base::Result; using Operand = typename Base::template Operand<0>; + static_assert(Operand::category == TypeCategory::Integer || + Operand::category == TypeCategory::Real || + Operand::category == TypeCategory::Character); CLASS_BOILERPLATE(Relational) Relational( RelationalOperator r, const Expr &a, const Expr &b) @@ -570,8 +573,9 @@ FOR_EACH_CHARACTER_KIND(extern template struct Relational) extern template struct Relational; // Logical expressions of a kind bigger than LogicalResult -// do not include Relational<> operations as possibilities -// since their results are always LogicalResult (kind=1). +// do not include Relational<> operations as possibilities, +// since the results of Relationals are always LogicalResult +// (kind=1). template class Expr> : public ExpressionBase> { diff --git a/flang/lib/evaluate/fold.h b/flang/lib/evaluate/fold.h index 4e3dc75..d148dcc 100644 --- a/flang/lib/evaluate/fold.h +++ b/flang/lib/evaluate/fold.h @@ -36,45 +36,11 @@ using namespace Fortran::parser::literals; // a canonicalized expression. // When the operand is an Expr, the result has the same type. -// Base cases +// Base no-op case template Expr> Fold(FoldingContext &, A &&x) { return Expr>{std::move(x)}; } -template Expr Fold(FoldingContext &context, Expr &&expr) { - static_assert(A::isSpecificIntrinsicType); - return std::visit( - [&](auto &&x) -> Expr { return Fold(context, std::move(x)); }, - std::move(expr.u)); -} - -template -Expr> Fold(FoldingContext &context, Expr> &&expr) { - return std::visit( - [&](auto &&x) -> Expr> { - if constexpr (CAT == TypeCategory::Derived) { - return Fold(context, std::move(x)); - } else { - return Expr>{Fold(context, std::move(x))}; - } - }, - std::move(expr.u)); -} - -template<> -inline Expr Fold(FoldingContext &context, Expr &&expr) { - return std::visit( - [&](auto &&x) -> Expr { - if constexpr (std::is_same_v, - BOZLiteralConstant>) { - return std::move(expr); - } else { - return Expr{Fold(context, std::move(x))}; - } - }, - std::move(expr.u)); -} - // Unary operations template @@ -329,5 +295,108 @@ template Expr Fold(FoldingContext &context, Extremum &&x) { return Expr{std::move(x)}; } +template +Expr> Fold( + FoldingContext &context, ComplexConstructor &&x) { + using COMPLEX = Type; + if (auto folded{FoldOperands(context, x.left(), x.right())}) { + return Expr{ + Constant{Scalar{folded->first, folded->second}}}; + } + return Expr{std::move(x)}; +} + +template +Expr> Fold( + FoldingContext &context, Concat &&x) { + using CHAR = Type; + if (auto folded{FoldOperands(context, x.left(), x.right())}) { + return Expr{Constant{folded->first + folded->second}}; + } + return Expr{std::move(x)}; +} + +template +Expr FoldRelational( + FoldingContext &context, Relational &&relation) { + if (auto folded{FoldOperands(context, relation.left(), relation.right())}) { + bool result{}; + if constexpr (T::category == TypeCategory::Integer) { + result = + Satisfies(relation.opr, folded->first.CompareSigned(folded->second)); + } else if constexpr (T::category == TypeCategory::Real) { + result = Satisfies(relation.opr, folded->first.Compare(folded->second)); + } else if constexpr (T::category == TypeCategory::Character) { + result = Satisfies(relation.opr, Compare(folded->first, folded->second)); + } else { + static_assert(T::category != TypeCategory::Complex && + T::category != TypeCategory::Logical); + } + return Expr{Constant{result}}; + } + return Expr{Relational{std::move(relation)}}; +} + +template<> +inline Expr Fold( + FoldingContext &context, Relational &&relation) { + return std::visit( + [&](auto &&x) { + return Expr{FoldRelational(context, std::move(x))}; + }, + std::move(relation.u)); +} + +template +Expr> Fold( + FoldingContext &context, LogicalOperation &&x) { + using LOGICAL = Type; + if (auto folded{FoldOperands(context, x.left(), x.right())}) { + bool xt{folded->first.IsTrue()}, yt{folded->second.IsTrue()}, result{}; + switch (x.logicalOperator) { + case LogicalOperator::And: result = xt && yt; break; + case LogicalOperator::Or: result = xt || yt; break; + case LogicalOperator::Eqv: result = xt == yt; break; + case LogicalOperator::Neqv: result = xt != yt; break; + } + return Expr{Constant{result}}; + } + return Expr{std::move(x)}; +} + +template Expr Fold(FoldingContext &context, Expr &&expr) { + static_assert(A::isSpecificIntrinsicType); + return std::visit( + [&](auto &&x) -> Expr { return Fold(context, std::move(x)); }, + std::move(expr.u)); +} + +template +Expr> Fold(FoldingContext &context, Expr> &&expr) { + return std::visit( + [&](auto &&x) -> Expr> { + if constexpr (CAT == TypeCategory::Derived) { + return Fold(context, std::move(x)); + } else { + return Expr>{Fold(context, std::move(x))}; + } + }, + std::move(expr.u)); +} + +template<> +inline Expr Fold(FoldingContext &context, Expr &&expr) { + return std::visit( + [&](auto &&x) -> Expr { + if constexpr (std::is_same_v, + BOZLiteralConstant>) { + return std::move(expr); + } else { + return Expr{Fold(context, std::move(x))}; + } + }, + std::move(expr.u)); +} + } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_FOLD_H_ -- 2.7.4