[flang] complete new Fold

Original-commit: flang-compiler/f18@4d1726778f
Reviewed-on: https://github.com/flang-compiler/f18/pull/219
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-10-24 14:06:46 -07:00
parent 60c16541c2
commit a99e9c99f3
3 changed files with 143 additions and 38 deletions

View File

@ -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)

View File

@ -529,9 +529,12 @@ FOR_EACH_CHARACTER_KIND(extern template class Expr)
template<typename A>
struct Relational : public Operation<Relational<A>, LogicalResult, A, A> {
using Result = LogicalResult;
using Base = Operation<Relational, LogicalResult, A, A>;
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<Operand> &a, const Expr<Operand> &b)
@ -570,8 +573,9 @@ FOR_EACH_CHARACTER_KIND(extern template struct Relational)
extern template struct Relational<SomeType>;
// 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<int KIND>
class Expr<Type<TypeCategory::Logical, KIND>>
: public ExpressionBase<Type<TypeCategory::Logical, KIND>> {

View File

@ -36,45 +36,11 @@ using namespace Fortran::parser::literals;
// a canonicalized expression.
// When the operand is an Expr<A>, the result has the same type.
// Base cases
// Base no-op case
template<typename A> Expr<ResultType<A>> Fold(FoldingContext &, A &&x) {
return Expr<ResultType<A>>{std::move(x)};
}
template<typename A> Expr<A> Fold(FoldingContext &context, Expr<A> &&expr) {
static_assert(A::isSpecificIntrinsicType);
return std::visit(
[&](auto &&x) -> Expr<A> { return Fold(context, std::move(x)); },
std::move(expr.u));
}
template<TypeCategory CAT>
Expr<SomeKind<CAT>> Fold(FoldingContext &context, Expr<SomeKind<CAT>> &&expr) {
return std::visit(
[&](auto &&x) -> Expr<SomeKind<CAT>> {
if constexpr (CAT == TypeCategory::Derived) {
return Fold(context, std::move(x));
} else {
return Expr<SomeKind<CAT>>{Fold(context, std::move(x))};
}
},
std::move(expr.u));
}
template<>
inline Expr<SomeType> Fold(FoldingContext &context, Expr<SomeType> &&expr) {
return std::visit(
[&](auto &&x) -> Expr<SomeType> {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
BOZLiteralConstant>) {
return std::move(expr);
} else {
return Expr<SomeType>{Fold(context, std::move(x))};
}
},
std::move(expr.u));
}
// Unary operations
template<typename TO, TypeCategory FROMCAT>
@ -329,5 +295,108 @@ template<typename T> Expr<T> Fold(FoldingContext &context, Extremum<T> &&x) {
return Expr<T>{std::move(x)};
}
template<int KIND>
Expr<Type<TypeCategory::Complex, KIND>> Fold(
FoldingContext &context, ComplexConstructor<KIND> &&x) {
using COMPLEX = Type<TypeCategory::Complex, KIND>;
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
return Expr<COMPLEX>{
Constant<COMPLEX>{Scalar<COMPLEX>{folded->first, folded->second}}};
}
return Expr<COMPLEX>{std::move(x)};
}
template<int KIND>
Expr<Type<TypeCategory::Character, KIND>> Fold(
FoldingContext &context, Concat<KIND> &&x) {
using CHAR = Type<TypeCategory::Character, KIND>;
if (auto folded{FoldOperands(context, x.left(), x.right())}) {
return Expr<CHAR>{Constant<CHAR>{folded->first + folded->second}};
}
return Expr<CHAR>{std::move(x)};
}
template<typename T>
Expr<LogicalResult> FoldRelational(
FoldingContext &context, Relational<T> &&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<LogicalResult>{Constant<LogicalResult>{result}};
}
return Expr<LogicalResult>{Relational<SomeType>{std::move(relation)}};
}
template<>
inline Expr<LogicalResult> Fold(
FoldingContext &context, Relational<SomeType> &&relation) {
return std::visit(
[&](auto &&x) {
return Expr<LogicalResult>{FoldRelational(context, std::move(x))};
},
std::move(relation.u));
}
template<int KIND>
Expr<Type<TypeCategory::Logical, KIND>> Fold(
FoldingContext &context, LogicalOperation<KIND> &&x) {
using LOGICAL = Type<TypeCategory::Logical, KIND>;
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<LOGICAL>{Constant<LOGICAL>{result}};
}
return Expr<LOGICAL>{std::move(x)};
}
template<typename A> Expr<A> Fold(FoldingContext &context, Expr<A> &&expr) {
static_assert(A::isSpecificIntrinsicType);
return std::visit(
[&](auto &&x) -> Expr<A> { return Fold(context, std::move(x)); },
std::move(expr.u));
}
template<TypeCategory CAT>
Expr<SomeKind<CAT>> Fold(FoldingContext &context, Expr<SomeKind<CAT>> &&expr) {
return std::visit(
[&](auto &&x) -> Expr<SomeKind<CAT>> {
if constexpr (CAT == TypeCategory::Derived) {
return Fold(context, std::move(x));
} else {
return Expr<SomeKind<CAT>>{Fold(context, std::move(x))};
}
},
std::move(expr.u));
}
template<>
inline Expr<SomeType> Fold(FoldingContext &context, Expr<SomeType> &&expr) {
return std::visit(
[&](auto &&x) -> Expr<SomeType> {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
BOZLiteralConstant>) {
return std::move(expr);
} else {
return Expr<SomeType>{Fold(context, std::move(x))};
}
},
std::move(expr.u));
}
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_FOLD_H_