From c0d3a67fac0918d45797bb2b385ed8c063ed318e Mon Sep 17 00:00:00 2001 From: peter klausler Date: Fri, 17 Aug 2018 15:38:37 -0700 Subject: [PATCH] [flang] complex extraction of operator classes Original-commit: flang-compiler/f18@0506bb7a0c28cc9374c62eecfb7def724c5488fd Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false --- flang/lib/evaluate/expression.cc | 1018 ++++++++++++++++--------------------- flang/lib/evaluate/expression.h | 428 ++++++++-------- flang/lib/evaluate/type.h | 3 - flang/lib/evaluate/variable.cc | 2 +- flang/lib/semantics/expression.cc | 7 +- 5 files changed, 634 insertions(+), 824 deletions(-) diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 8fbaeec..13186a5 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -27,7 +27,7 @@ using namespace Fortran::parser::literals; namespace Fortran::evaluate { -// Folding +// Fold template auto Operation::Fold(FoldingContext &context) @@ -46,6 +46,159 @@ auto Operation::Fold(FoldingContext &context) return std::nullopt; } +template +auto Expr>::Fold(FoldingContext &context) + -> std::optional> { + if (auto c{ScalarValue()}) { + return c; + } + return std::visit( + [&](auto &x) -> std::optional> { + using Ty = std::decay_t; + if constexpr (evaluate::FoldableTrait) { + if (auto c{x.Fold(context)}) { + if constexpr (std::is_same_v>) { + // Preserve parentheses around constants. + u_ = Parentheses{Expr{*c}}; + } else { + u_ = *c; + } + return c; + } + } + return std::nullopt; + }, + u_); +} + +template +auto Expr>::Fold(FoldingContext &context) + -> std::optional> { + if (auto c{ScalarValue()}) { + return c; + } + return std::visit( + [&](auto &x) -> std::optional> { + using Ty = std::decay_t; + if constexpr (evaluate::FoldableTrait) { + if (auto c{x.Fold(context)}) { + if (context.flushDenormalsToZero) { + *c = c->FlushDenormalToZero(); + } + if constexpr (std::is_same_v>) { + // Preserve parentheses around constants. + u_ = Parentheses{Expr{*c}}; + } else { + u_ = *c; + } + return c; + } + } + return std::nullopt; + }, + u_); +} + +template +auto Expr>::Fold(FoldingContext &context) + -> std::optional> { + if (auto c{ScalarValue()}) { + return c; + } + return std::visit( + [&](auto &x) -> std::optional> { + using Ty = std::decay_t; + if constexpr (evaluate::FoldableTrait) { + if (auto c{x.Fold(context)}) { + if (context.flushDenormalsToZero) { + *c = c->FlushDenormalToZero(); + } + if constexpr (std::is_same_v>) { + // Preserve parentheses around constants. + u_ = Parentheses{Expr{*c}}; + } else { + u_ = *c; + } + return c; + } + } + return std::nullopt; + }, + u_); +} + +template +auto Expr>::Fold(FoldingContext &context) + -> std::optional> { + if (auto c{ScalarValue()}) { + return c; + } + return std::visit( + [&](auto &x) -> std::optional> { + using Ty = std::decay_t; + if constexpr (evaluate::FoldableTrait) { + if (auto c{x.Fold(context)}) { + u_ = *c; + return c; + } + } + return std::nullopt; + }, + u_); +} + +template +auto Expr>::Fold(FoldingContext &context) + -> std::optional> { + if (auto c{ScalarValue()}) { + return c; + } + return std::visit( + [&](auto &x) -> std::optional> { + using Ty = std::decay_t; + if constexpr (evaluate::FoldableTrait) { + if (auto c{x.Fold(context)}) { + Scalar result{c->IsTrue()}; + u_ = result; + return {result}; + } + } + return std::nullopt; + }, + u_); +} + +template +auto Expr>::Fold(FoldingContext &context) + -> std::optional> { + return std::visit( + [&](auto &x) -> std::optional> { + if (auto c{x.Fold(context)}) { + return {Scalar{std::move(*c)}}; + } + return std::nullopt; + }, + u); +} + +auto Expr::Fold(FoldingContext &context) + -> std::optional> { + return std::visit( + common::visitors{ + [](BOZLiteralConstant &) -> std::optional> { + return std::nullopt; + }, + [&](auto &x) -> std::optional> { + if (auto c{x.Fold(context)}) { + return {Scalar{std::move(*c)}}; + } + return std::nullopt; + }}, + u); +} + +// FoldScalar + template auto Convert::FoldScalar(FoldingContext &context, const Scalar &c) -> std::optional> { @@ -143,545 +296,148 @@ auto Add::FoldScalar(FoldingContext &context, const Scalar &x, if constexpr (Result::category == TypeCategory::Integer) { auto sum{x.AddSigned(y)}; if (sum.overflow) { - context.messages.Say("INTEGER addition overflowed"_en_US); - } else { - return {std::move(sum.value)}; + context.messages.Say( + "INTEGER(KIND=%d) addition overflowed"_en_US, Result::kind); + return std::nullopt; } + return {std::move(sum.value)}; } else { auto sum{x.Add(y, context.rounding)}; RealFlagWarnings(context, sum.flags, "addition"); return {std::move(sum.value)}; } - return std::nullopt; -} - -// Dumping - -template -std::ostream &Operation::Dump(std::ostream &o) const { - operand<0>().Dump(o << derived().prefix()); - if constexpr (operands() > 1) { - operand<1>().Dump(o << derived().infix()); - } - return o << derived().suffix(); } -template std::string Comparison::infix() const { - return "."s + EnumToString(opr) + '.'; -} - -template -std::ostream &DumpExpr(std::ostream &o, const std::variant &u) { - std::visit(common::visitors{[&](const BOZLiteralConstant &x) { - o << "Z'" << x.Hexadecimal() << "'"; - }, - [&](const auto &x) { x.Dump(o); }}, - u); - return o; -} - -template -std::ostream &Expr>::Dump(std::ostream &o) const { - return DumpExpr(o, u); -} - -template -std::ostream &CategoryComparison::Dump(std::ostream &o) const { - return DumpExpr(o, u); -} - -std::ostream &Expr::Dump(std::ostream &o) const { - return DumpExpr(o, u); -} - -template -std::ostream &Binary::Dump( - std::ostream &o, const char *opr, const char *before) const { - return right().Dump(left().Dump(o << before) << opr) << ')'; -} - -template -std::ostream &Expr>::Dump( - std::ostream &o) const { - std::visit(common::visitors{[&](const Scalar &n) { - o << n.SignedDecimal() << '_' << KIND; - }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const Subtract &s) { s.Dump(o, "-"); }, - [&](const Multiply &m) { m.Dump(o, "*"); }, - [&](const Divide &d) { d.Dump(o, "/"); }, - [&](const Power &p) { p.Dump(o, "**"); }, - [&](const Max &m) { m.Dump(o, ",", "MAX("); }, - [&](const Min &m) { m.Dump(o, ",", "MIN("); }, - [&](const auto &x) { x.Dump(o); }}, - u_); - return o; -} - -template -std::ostream &Expr>::Dump( - std::ostream &o) const { - std::visit(common::visitors{[&](const Scalar &n) { - o << n.DumpHexadecimal(); - }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const Subtract &s) { s.Dump(o, "-"); }, - [&](const Multiply &m) { m.Dump(o, "*"); }, - [&](const Divide &d) { d.Dump(o, "/"); }, - [&](const Power &p) { p.Dump(o, "**"); }, - [&](const IntPower &p) { p.Dump(o, "**"); }, - [&](const Max &m) { m.Dump(o, ",", "MAX("); }, - [&](const Min &m) { m.Dump(o, ",", "MIN("); }, - [&](const auto &x) { x.Dump(o); }}, - u_); - return o; -} - -template -std::ostream &Expr>::Dump( - std::ostream &o) const { - std::visit(common::visitors{[&](const Scalar &n) { - o << n.DumpHexadecimal(); - }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const Subtract &s) { s.Dump(o, "-"); }, - [&](const Multiply &m) { m.Dump(o, "*"); }, - [&](const Divide &d) { d.Dump(o, "/"); }, - [&](const Power &p) { p.Dump(o, "**"); }, - [&](const IntPower &p) { p.Dump(o, "**"); }, - [&](const CMPLX &c) { c.Dump(o, ","); }, - [&](const auto &x) { x.Dump(o); }}, - u_); - return o; -} - -template -std::ostream &Expr>::Dump( - std::ostream &o) const { - std::visit(common::visitors{[&](const Scalar &s) { - o << KIND << '_' - << parser::QuoteCharacterLiteral(s); - }, - // [&](const Parentheses &p) { p.Dump(o); }, - [&](const Concat &concat) { concat.Dump(o, "//"); }, - [&](const Max &m) { m.Dump(o, ",", "MAX("); }, - [&](const Min &m) { m.Dump(o, ",", "MIN("); }, - [&](const auto &ind) { ind->Dump(o); }}, - u_); - return o; -} - -template -std::ostream &Expr>::Dump( - std::ostream &o) const { - std::visit(common::visitors{[&](const Scalar &tf) { - o << (tf.IsTrue() ? ".TRUE." : ".FALSE.") << '_' - << KIND; - }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - // [&](const Parentheses &p) { p.Dump(o); }, - [&](const Not &n) { n.Dump(o); }, - [&](const And &a) { a.Dump(o, ".AND."); }, - [&](const Or &a) { a.Dump(o, ".OR."); }, - [&](const Eqv &a) { a.Dump(o, ".EQV."); }, - [&](const Neqv &a) { a.Dump(o, ".NEQV."); }, - [&](const auto &comparison) { comparison.Dump(o); }}, - u_); - return o; -} - -// LEN() -template -Expr Expr>::LEN() const { - return std::visit( - common::visitors{[](const Scalar &c) { - // std::string::size_type isn't convertible to uint64_t - // on Darwin - return Expr{ - static_cast(c.size())}; - }, - [](const Concat &c) { return c.left().LEN() + c.right().LEN(); }, - [](const Max &c) { - return Expr{ - Expr::Max{c.left().LEN(), c.right().LEN()}}; - }, - [](const Min &c) { - return Expr{ - Expr::Max{c.left().LEN(), c.right().LEN()}}; - }, - [](const CopyableIndirection &dr) { return dr->LEN(); }, - [](const CopyableIndirection &ss) { return ss->LEN(); }, - [](const CopyableIndirection &fr) { - return fr->proc().LEN(); - }}, - u_); -} - -// Rank -template -int Binary::Rank() const { - int lrank{left_.Rank()}; - if (lrank > 0) { - return lrank; - } - return right_.Rank(); -} - -// Folding -template -auto Binary::Fold(FoldingContext &context) - -> std::optional> { - std::optional> lc{left_->Fold(context)}; - std::optional> rc{right_->Fold(context)}; - if (lc.has_value() && rc.has_value()) { - return static_cast(this)->FoldScalar(context, *lc, *rc); - } - return std::nullopt; -} - -template -auto Expr>::Subtract::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto diff{a.SubtractSigned(b)}; - if (diff.overflow) { - context.messages.Say("integer subtraction overflowed"_en_US); - return std::nullopt; - } - return {std::move(diff.value)}; -} - -template -auto Expr>::Multiply::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto product{a.MultiplySigned(b)}; - if (product.SignedMultiplicationOverflowed()) { - context.messages.Say("integer multiplication overflowed"_en_US); - return std::nullopt; - } - return {std::move(product.lower)}; -} - -template -auto Expr>::Divide::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto qr{a.DivideSigned(b)}; - if (qr.divisionByZero) { - context.messages.Say("integer division by zero"_en_US); - return std::nullopt; - } - if (qr.overflow) { - context.messages.Say("integer division overflowed"_en_US); - return std::nullopt; - } - return {std::move(qr.quotient)}; -} - -template -auto Expr>::Power::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - typename Scalar::PowerWithErrors power{a.Power(b)}; - if (power.divisionByZero) { - context.messages.Say("zero to negative power"_en_US); - return std::nullopt; - } - if (power.overflow) { - context.messages.Say("integer power overflowed"_en_US); - return std::nullopt; - } - if (power.zeroToZero) { - context.messages.Say("integer 0**0"_en_US); - return std::nullopt; - } - return {std::move(power.power)}; -} - -template -auto Expr>::Max::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - if (a.CompareSigned(b) == Ordering::Greater) { - return {a}; - } - return {b}; -} - -template -auto Expr>::Min::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - if (a.CompareSigned(b) == Ordering::Less) { - return {a}; - } - return {b}; -} - -template -auto Expr>::Fold(FoldingContext &context) - -> std::optional> { - if (auto c{ScalarValue()}) { - return c; - } - return std::visit( - [&](auto &x) -> std::optional> { - using Ty = std::decay_t; - if constexpr (evaluate::FoldableTrait) { - if (auto c{x.Fold(context)}) { - if constexpr (std::is_same_v>) { - // Preserve parentheses around constants. - u_ = Parentheses{Expr{*c}}; - } else { - u_ = *c; - } - return c; - } - } - return std::nullopt; - }, - u_); -} - -template -auto Expr>::Subtract::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto difference{a.Subtract(b, context.rounding)}; - RealFlagWarnings(context, difference.flags, "real subtraction"); - return {std::move(difference.value)}; -} - -template -auto Expr>::Multiply::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto product{a.Multiply(b, context.rounding)}; - RealFlagWarnings(context, product.flags, "real multiplication"); - return {std::move(product.value)}; -} - -template -auto Expr>::Divide::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto quotient{a.Divide(b, context.rounding)}; - RealFlagWarnings(context, quotient.flags, "real division"); - return {std::move(quotient.value)}; -} - -template -auto Expr>::Power::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - return std::nullopt; // TODO -} - -template -auto Expr>::IntPower::FoldScalar( - FoldingContext &context, const Scalar &a, - const SomeKindScalar &b) - -> std::optional> { - return std::visit( - [&](const auto &pow) -> std::optional> { - auto power{evaluate::IntPower(a, pow)}; - RealFlagWarnings(context, power.flags, "raising to integer power"); - return {std::move(power.value)}; - }, - b.u); -} - -template -auto Expr>::Max::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - if (b.IsNotANumber() || a.Compare(b) == Relation::Less) { - return {b}; - } - return {a}; -} - -template -auto Expr>::Min::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - if (b.IsNotANumber() || a.Compare(b) == Relation::Greater) { - return {b}; - } - return {a}; -} - -template -auto Expr>::Fold(FoldingContext &context) - -> std::optional> { - if (auto c{ScalarValue()}) { - return c; - } - return std::visit( - [&](auto &x) -> std::optional> { - using Ty = std::decay_t; - if constexpr (evaluate::FoldableTrait) { - if (auto c{x.Fold(context)}) { - if (context.flushDenormalsToZero) { - *c = c->FlushDenormalToZero(); - } - if constexpr (std::is_same_v>) { - // Preserve parentheses around constants. - u_ = Parentheses{Expr{*c}}; - } else { - u_ = *c; - } - return c; - } - } - return std::nullopt; - }, - u_); -} - -template -auto Expr>::Subtract::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto difference{a.Subtract(b, context.rounding)}; - RealFlagWarnings(context, difference.flags, "complex subtraction"); - return {std::move(difference.value)}; -} - -template -auto Expr>::Multiply::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto product{a.Multiply(b, context.rounding)}; - RealFlagWarnings(context, product.flags, "complex multiplication"); - return {std::move(product.value)}; -} - -template -auto Expr>::Divide::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto quotient{a.Divide(b, context.rounding)}; - RealFlagWarnings(context, quotient.flags, "complex division"); - return {std::move(quotient.value)}; -} - -template -auto Expr>::Power::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - return std::nullopt; // TODO -} - -template -auto Expr>::IntPower::FoldScalar( - FoldingContext &context, const Scalar &a, - const SomeKindScalar &b) - -> std::optional> { - return std::visit( - [&](const auto &pow) -> std::optional> { - auto power{evaluate::IntPower(a, pow)}; - RealFlagWarnings(context, power.flags, "raising to integer power"); - return {std::move(power.value)}; - }, - b.u); +template +auto Subtract::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) -> std::optional> { + if constexpr (Result::category == TypeCategory::Integer) { + auto diff{x.SubtractSigned(y)}; + if (diff.overflow) { + context.messages.Say( + "INTEGER(KIND=%d) subtraction overflowed"_en_US, Result::kind); + return std::nullopt; + } + return {std::move(diff.value)}; + } else { + auto difference{x.Subtract(y, context.rounding)}; + RealFlagWarnings(context, difference.flags, "subtraction"); + return {std::move(difference.value)}; + } } -template -auto Expr>::CMPLX::FoldScalar( - FoldingContext &context, - const Scalar> &a, - const Scalar> &b) - -> std::optional> { - return {Scalar{a, b}}; +template +auto Multiply::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) -> std::optional> { + if constexpr (Result::category == TypeCategory::Integer) { + auto product{x.MultiplySigned(y)}; + if (product.SignedMultiplicationOverflowed()) { + context.messages.Say( + "INTEGER(KIND=%d) multiplication overflowed"_en_US, Result::kind); + return std::nullopt; + } + return {std::move(product.lower)}; + } else { + auto product{x.Multiply(y, context.rounding)}; + RealFlagWarnings(context, product.flags, "multiplication"); + return {std::move(product.value)}; + } } -template -auto Expr>::Fold(FoldingContext &context) - -> std::optional> { - if (auto c{ScalarValue()}) { - return c; +template +auto Divide::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) -> std::optional> { + if constexpr (Result::category == TypeCategory::Integer) { + auto qr{x.DivideSigned(y)}; + if (qr.divisionByZero) { + context.messages.Say("INTEGER division by zero"_en_US); + return std::nullopt; + } + if (qr.overflow) { + context.messages.Say( + "INTEGER(KIND=%d) division overflowed"_en_US, Result::kind); + return std::nullopt; + } + return {std::move(qr.quotient)}; + } else { + auto quotient{x.Divide(y, context.rounding)}; + RealFlagWarnings(context, quotient.flags, "division"); + return {std::move(quotient.value)}; } - return std::visit( - [&](auto &x) -> std::optional> { - using Ty = std::decay_t; - if constexpr (evaluate::FoldableTrait) { - if (auto c{x.Fold(context)}) { - if (context.flushDenormalsToZero) { - *c = c->FlushDenormalToZero(); - } - if constexpr (std::is_same_v>) { - // Preserve parentheses around constants. - u_ = Parentheses{Expr{*c}}; - } else { - u_ = *c; - } - return c; - } - } - return std::nullopt; - }, - u_); } -template -auto Expr>::Concat::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - if constexpr (KIND == 1) { - return {a + b}; +template +auto Power::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) -> std::optional> { + if constexpr (Result::category == TypeCategory::Integer) { + typename Scalar::PowerWithErrors power{x.Power(y)}; + if (power.divisionByZero) { + context.messages.Say("zero to negative power"_en_US); + } else if (power.overflow) { + context.messages.Say( + "INTEGER(KIND=%d) power overflowed"_en_US, Result::kind); + } else if (power.zeroToZero) { + context.messages.Say("INTEGER 0**0 is not defined"_en_US); + } else { + return {std::move(power.power)}; + } + } else { + // TODO: real and complex exponentiation to non-integer powers } return std::nullopt; } -template -auto Expr>::Max::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) +template +auto RealToIntPower::FoldScalar(FoldingContext &context, + const Scalar &x, const Scalar &y) -> std::optional> { - if (Compare(a, b) == Ordering::Less) { - return {b}; + return std::visit( + [&](const auto &pow) -> std::optional> { + auto power{evaluate::IntPower(x, pow)}; + RealFlagWarnings(context, power.flags, "raising to INTEGER power"); + return {std::move(power.value)}; + }, + y.u); +} + +template +auto Extremum::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) const -> std::optional> { + if constexpr (Operand::category == TypeCategory::Integer) { + if (ordering == x.CompareSigned(y)) { + return {x}; + } + } else if constexpr (Operand::category == TypeCategory::Real) { + if (x.IsNotANumber() || + (x.Compare(y) == Relation::Less) == (ordering == Ordering::Less)) { + return {x}; + } + } else { + if (ordering == Compare(x, y)) { + return {x}; + } } - return {a}; + return {y}; } template -auto Expr>::Min::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) +auto ComplexConstructor::FoldScalar( + FoldingContext &context, const Scalar &x, const Scalar &y) -> std::optional> { - if (Compare(a, b) == Ordering::Greater) { - return {b}; - } - return {a}; + return {Scalar{x, y}}; } template -auto Expr>::Fold(FoldingContext &context) - -> std::optional> { - if (auto c{ScalarValue()}) { - return c; +auto Concat::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) -> std::optional> { + if constexpr (KIND == 1) { + return {x + y}; } - return std::visit( - [&](auto &x) -> std::optional> { - using Ty = std::decay_t; - if constexpr (evaluate::FoldableTrait) { - if (auto c{x.Fold(context)}) { - u_ = *c; - return c; - } - } - return std::nullopt; - }, - u_); + return std::nullopt; } template -auto Comparison::FoldScalar(FoldingContext &c, const Scalar &a, +auto Relational::FoldScalar(FoldingContext &c, const Scalar &a, const Scalar &b) -> std::optional> { if constexpr (A::category == TypeCategory::Integer) { switch (a.CompareSigned(b)) { @@ -732,68 +488,166 @@ auto Comparison::FoldScalar(FoldingContext &c, const Scalar &a, } template -auto Expr>::And::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) +auto LogicalOperation::FoldScalar(FoldingContext &context, + const Scalar &x, const Scalar &y) const -> std::optional> { - return {Scalar{a.IsTrue() && b.IsTrue()}}; + bool xt{x.IsTrue()}, yt{y.IsTrue()}; + switch (logicalOperator) { + case LogicalOperator::And: return {Scalar{xt && yt}}; + case LogicalOperator::Or: return {Scalar{xt || yt}}; + case LogicalOperator::Eqv: return {Scalar{xt == yt}}; + case LogicalOperator::Neqv: return {Scalar{xt != yt}}; + } + return std::nullopt; +} + +// Dump + +template +std::ostream &Operation::Dump(std::ostream &o) const { + operand<0>().Dump(o << derived().prefix()); + if constexpr (operands() > 1) { + operand<1>().Dump(o << derived().infix()); + } + return o << derived().suffix(); +} + +template std::string Relational::infix() const { + return "."s + EnumToString(opr) + '.'; +} + +template const char *LogicalOperation::infix() const { + const char *result{nullptr}; + switch (logicalOperator) { + case LogicalOperator::And: result = ".AND."; break; + case LogicalOperator::Or: result = ".OR."; break; + case LogicalOperator::Eqv: result = ".EQV."; break; + case LogicalOperator::Neqv: result = ".NEQV."; break; + } + return result; +} + +template +std::ostream &DumpExpr(std::ostream &o, const std::variant &u) { + std::visit(common::visitors{[&](const BOZLiteralConstant &x) { + o << "Z'" << x.Hexadecimal() << "'"; + }, + [&](const auto &x) { x.Dump(o); }}, + u); + return o; +} + +template +std::ostream &Expr>::Dump(std::ostream &o) const { + return DumpExpr(o, u); +} + +template +std::ostream &Relational>::Dump(std::ostream &o) const { + return DumpExpr(o, u); +} + +std::ostream &Expr::Dump(std::ostream &o) const { + return DumpExpr(o, u); } template -auto Expr>::Or::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - return {Scalar{a.IsTrue() || b.IsTrue()}}; +std::ostream &Expr>::Dump( + std::ostream &o) const { + std::visit(common::visitors{[&](const Scalar &n) { + o << n.SignedDecimal() << '_' << KIND; + }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const auto &x) { x.Dump(o); }}, + u_); + return o; } template -auto Expr>::Eqv::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - return {Scalar{a.IsTrue() == b.IsTrue()}}; +std::ostream &Expr>::Dump( + std::ostream &o) const { + std::visit(common::visitors{[&](const Scalar &n) { + o << n.DumpHexadecimal(); + }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const auto &x) { x.Dump(o); }}, + u_); + return o; } template -auto Expr>::Neqv::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - return {Scalar{a.IsTrue() != b.IsTrue()}}; +std::ostream &Expr>::Dump( + std::ostream &o) const { + std::visit(common::visitors{[&](const Scalar &n) { + o << n.DumpHexadecimal(); + }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const auto &x) { x.Dump(o); }}, + u_); + return o; } template -auto Expr>::Fold(FoldingContext &context) - -> std::optional> { - if (auto c{ScalarValue()}) { - return c; - } - return std::visit( - [&](auto &x) -> std::optional> { - using Ty = std::decay_t; - if constexpr (evaluate::FoldableTrait) { - if (auto c{x.Fold(context)}) { - u_ = *c; - return c; - } - } - return std::nullopt; - }, +std::ostream &Expr>::Dump( + std::ostream &o) const { + std::visit(common::visitors{[&](const Scalar &s) { + o << KIND << '_' + << parser::QuoteCharacterLiteral(s); + }, + // [&](const Parentheses &p) { p.Dump(o); }, + [&](const Concat &c) { c.Dump(o); }, + [&](const Extremum &mm) { mm.Dump(o); }, + [&](const auto &ind) { ind->Dump(o); }}, u_); + return o; } -auto Expr::ScalarValue() const -> std::optional> { +template +std::ostream &Expr>::Dump( + std::ostream &o) const { + std::visit(common::visitors{[&](const Scalar &tf) { + o << (tf.IsTrue() ? ".TRUE." : ".FALSE.") << '_' + << KIND; + }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const auto &x) { x.Dump(o); }}, + u_); + return o; +} + +// LEN() +template +Expr Expr>::LEN() const { return std::visit( - common::visitors{ - [](const BOZLiteralConstant &) -> std::optional> { - return std::nullopt; + common::visitors{[](const Scalar &c) { + // std::string::size_type isn't convertible to uint64_t + // on Darwin + return Expr{ + static_cast(c.size())}; + }, + [](const Concat &c) { + return c.template operand<0>().LEN() + + c.template operand<1>().LEN(); }, - [](const auto &x) -> std::optional> { - if (auto c{x.ScalarValue()}) { - return {Scalar{std::move(*c)}}; - } - return std::nullopt; + [](const Extremum &c) { + return Expr{Extremum{ + c.template operand<0>().LEN(), c.template operand<1>().LEN()}}; + }, + [](const CopyableIndirection &dr) { return dr->LEN(); }, + [](const CopyableIndirection &ss) { return ss->LEN(); }, + [](const CopyableIndirection &fr) { + return fr->proc().LEN(); }}, - u); + u_); } +// ScalarValue + template auto Expr>::ScalarValue() const -> std::optional> { return std::visit( @@ -806,32 +660,14 @@ auto Expr>::ScalarValue() const -> std::optional> { u); } -template -auto Expr>::Fold(FoldingContext &context) - -> std::optional> { - return std::visit( - [&](auto &x) -> std::optional> { - if (auto c{x.Fold(context)}) { - return {Scalar{std::move(*c)}}; - } - return std::nullopt; - }, - u); -} - -template int Expr>::Rank() const { - return std::visit([](const auto &x) { return x.Rank(); }, u); -} - -auto Expr::Fold(FoldingContext &context) - -> std::optional> { +auto Expr::ScalarValue() const -> std::optional> { return std::visit( common::visitors{ - [](BOZLiteralConstant &) -> std::optional> { + [](const BOZLiteralConstant &) -> std::optional> { return std::nullopt; }, - [&](auto &x) -> std::optional> { - if (auto c{x.Fold(context)}) { + [](const auto &x) -> std::optional> { + if (auto c{x.ScalarValue()}) { return {Scalar{std::move(*c)}}; } return std::nullopt; @@ -839,6 +675,12 @@ auto Expr::Fold(FoldingContext &context) u); } +// Rank + +template int Expr>::Rank() const { + return std::visit([](const auto &x) { return x.Rank(); }, u); +} + int Expr::Rank() const { // Written thus, instead of common::visitors, to dodge a bug in G++ 7.2. return std::visit( @@ -853,6 +695,8 @@ int Expr::Rank() const { u); } +// Template instantiations + template class Expr>; template class Expr>; template class Expr>; @@ -870,22 +714,22 @@ template class Expr>; template class Expr>; template class Expr>; // TODO others -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; -template struct Comparison>; // TODO others +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; +template struct Relational>; // TODO others template class Expr>; template class Expr>; diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index d805b3f..9d692a4 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -36,6 +36,10 @@ namespace Fortran::evaluate { using common::RelationalOperator; +// Expr represents an expression whose result is the Fortran type A, +// which can be specific, SomeKind for a type category C, or +// Expr for a wholly generic expression. Instances of Expr<> +// wrap discriminated unions. template class Expr; template @@ -127,7 +131,6 @@ struct ComplexComponent std::optional> FoldScalar( FoldingContext &, const Scalar &) const; - static const char *prefix() { return "(("; } const char *suffix() const { return isRealPart ? "%RE)" : "%IM)"; } bool isRealPart{true}; @@ -138,9 +141,9 @@ struct Not : public Operation, Type, Type> { using Base = Operation, Type>; - using Base::Base; using typename Base::Result; using Operand = typename Base::template Operand<0>; + using Base::Base; static std::optional> FoldScalar( FoldingContext &, const Scalar &); static const char *prefix() { return "(.NOT."; } @@ -150,40 +153,138 @@ struct Not : public Operation, Type, template struct Add : public Operation, A, A, A> { using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; using Base::Base; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); + static constexpr const char *infix() { return "+"; } +}; + +template struct Subtract : public Operation, A, A, A> { + using Base = Operation; using typename Base::Result; using Operand = typename Base::template Operand<0>; + using Base::Base; static std::optional> FoldScalar( FoldingContext &, const Scalar &, const Scalar &); - static const char *infix() { return "+"; } + static constexpr const char *infix() { return "-"; } }; -template -class Binary { -public: - using Result = RESULT; - using Left = A; - using Right = B; - using FoldableTrait = std::true_type; - CLASS_BOILERPLATE(Binary) - Binary(const Expr &a, const Expr &b) : left_{a}, right_{b} {} - Binary(Expr &&a, Expr &&b) - : left_{std::move(a)}, right_{std::move(b)} {} - Binary(CopyableIndirection> &&a, - CopyableIndirection> &&b) - : left_{std::move(a)}, right_{std::move(b)} {} - const Expr &left() const { return *left_; } - Expr &left() { return *left_; } - const Expr &right() const { return *right_; } - Expr &right() { return *right_; } - std::ostream &Dump( - std::ostream &, const char *opr, const char *before = "(") const; - int Rank() const; - std::optional> Fold(FoldingContext &); +template struct Multiply : public Operation, A, A, A> { + using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + using Base::Base; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); + static constexpr const char *infix() { return "*"; } +}; -private: - CopyableIndirection> left_; - CopyableIndirection> right_; +template struct Divide : public Operation, A, A, A> { + using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + using Base::Base; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); + static constexpr const char *infix() { return "/"; } +}; + +template struct Power : public Operation, A, A, A> { + using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + using Base::Base; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); + static constexpr const char *infix() { return "**"; } +}; + +template +struct RealToIntPower : public Operation, A, A, B> { + using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + using ExponentOperand = typename Base::template Operand<1>; + using Base::Base; + static std::optional> FoldScalar(FoldingContext &, + const Scalar &, const Scalar &); + static constexpr const char *infix() { return "**"; } +}; + +template struct Extremum : public Operation, A, A, A> { + using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + CLASS_BOILERPLATE(Extremum) + Extremum(const Expr &x, const Expr &y, + Ordering ord = Ordering::Greater) + : Base{x, y}, ordering{ord} {} + Extremum( + Expr &&x, Expr &&y, Ordering ord = Ordering::Greater) + : Base{std::move(x), std::move(y)}, ordering{ord} {} + + std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &) const; + const char *prefix() const { + return ordering == Ordering::Less ? "MIN(" : "MAX("; + } + + Ordering ordering{Ordering::Greater}; +}; + +template +struct ComplexConstructor + : public Operation, + Type, Type, + Type> { + using Base = Operation, + Type, Type>; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + using Base::Base; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); +}; + +template +struct Concat + : public Operation, Type, + Type, + Type> { + using Base = Operation, + Type, Type>; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + using Base::Base; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); + static constexpr const char *infix() { return "//"; } +}; + +ENUM_CLASS(LogicalOperator, And, Or, Eqv, Neqv) + +template +struct LogicalOperation + : public Operation, Type, + Type, Type> { + using Base = Operation, + Type, Type>; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + CLASS_BOILERPLATE(LogicalOperation) + LogicalOperation( + const Expr &x, const Expr &y, LogicalOperator opr) + : Base{x, y}, logicalOperator{opr} {} + LogicalOperation(Expr &&x, Expr &&y, LogicalOperator opr) + : Base{std::move(x), std::move(y)}, logicalOperator{opr} {} + + std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &) const; + const char *infix() const; + + LogicalOperator logicalOperator; }; // Per-category expressions @@ -192,38 +293,6 @@ template class Expr> { public: using Result = Type; using FoldableTrait = std::true_type; - - template using Bin = Binary; - struct Subtract : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Multiply : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Divide : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Power : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Max : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Min : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; // TODO: R916 type-param-inquiry CLASS_BOILERPLATE(Expr) @@ -265,7 +334,8 @@ private: std::variant, CopyableIndirection, CopyableIndirection, Convert, Convert, Parentheses, Negate, - Add, Subtract, Multiply, Divide, Power, Max, Min> + Add, Subtract, Multiply, Divide, + Power, Extremum> u_; }; @@ -278,43 +348,6 @@ public: // and part access operations (resp.). Conversions between kinds of // Complex are done via decomposition to Real and reconstruction. - template using Bin = Binary; - struct Subtract : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Multiply : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Divide : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Power : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct IntPower : public Binary { - using Binary::Binary; - static std::optional> FoldScalar(FoldingContext &, - const Scalar &, const SomeKindScalar &); - }; - struct Max : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Min : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - CLASS_BOILERPLATE(Expr) Expr(const Scalar &x) : u_{x} {} Expr(const Expr &x) : u_{Convert{x}} {} @@ -352,7 +385,8 @@ private: CopyableIndirection, CopyableIndirection, Convert, Convert, ComplexComponent, Parentheses, Negate, Add, - Subtract, Multiply, Divide, Power, IntPower, Max, Min> + Subtract, Multiply, Divide, Power, + RealToIntPower, Extremum> u_; }; @@ -360,41 +394,6 @@ template class Expr> { public: using Result = Type; using FoldableTrait = std::true_type; - - template using Bin = Binary; - struct Subtract : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Multiply : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Divide : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Power : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct IntPower : public Binary { - using Binary::Binary; - static std::optional> FoldScalar(FoldingContext &, - const Scalar &, const SomeKindScalar &); - }; - struct CMPLX - : public Binary> { - using Binary>::Binary; - static std::optional> FoldScalar(FoldingContext &, - const Scalar> &, - const Scalar> &); - }; - CLASS_BOILERPLATE(Expr) Expr(const Scalar &x) : u_{x} {} template Expr(const A &x) : u_{x} {} @@ -413,7 +412,9 @@ public: private: std::variant, CopyableIndirection, CopyableIndirection, Parentheses, Negate, - Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX> + Add, Subtract, Multiply, Divide, + Power, RealToIntPower, + ComplexConstructor> u_; }; @@ -437,23 +438,6 @@ template class Expr> { public: using Result = Type; using FoldableTrait = std::true_type; - template using Bin = Binary; - struct Concat : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Max : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Min : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - CLASS_BOILERPLATE(Expr) Expr(const Scalar &x) : u_{x} {} Expr(Scalar &&x) : u_{std::move(x)} {} @@ -474,25 +458,29 @@ public: private: std::variant, CopyableIndirection, CopyableIndirection, CopyableIndirection, - // Parentheses, - Concat, Max, Min> + // TODO Parentheses, + Concat, Extremum> u_; }; -// The Comparison class template is a helper for constructing logical +// The Relation class template is a helper for constructing logical // expressions with polymorphism over the cross product of the possible // categories and kinds of comparable operands. +// Fortran defines a numeric relation with distinct types or kinds as +// undergoing the same operand conversions that occur with the addition +// intrinsic operator first. Character relations must have the same kind. +// There are no relations between logicals. template -struct Comparison : public Operation, LogicalResult, A, A> { - using Base = Operation; +struct Relational : public Operation, LogicalResult, A, A> { + using Base = Operation; using typename Base::Result; using Operand = typename Base::template Operand<0>; - CLASS_BOILERPLATE(Comparison) - Comparison( + CLASS_BOILERPLATE(Relational) + Relational( RelationalOperator r, const Expr &a, const Expr &b) : Base{a, b}, opr{r} {} - Comparison(RelationalOperator r, Expr &&a, Expr &&b) + Relational(RelationalOperator r, Expr &&a, Expr &&b) : Base{std::move(a), std::move(b)}, opr{r} {} std::optional> FoldScalar( @@ -502,56 +490,35 @@ struct Comparison : public Operation, LogicalResult, A, A> { RelationalOperator opr; }; -// Dynamically polymorphic comparisons whose operands are expressions of -// the same supported kind of a particular type category. -template struct CategoryComparison { +// A generic relation between two operands of the same kind in some intrinsic +// type category (except LOGICAL). +template struct Relational> { using Result = LogicalResult; - CLASS_BOILERPLATE(CategoryComparison) - template using KindComparison = Comparison>; - template CategoryComparison(const KindComparison &x) : u{x} {} - template - CategoryComparison(KindComparison &&x) : u{std::move(x)} {} + using Operand = SomeKind; + template using KindRelational = Relational>; + + CLASS_BOILERPLATE(Relational) + template Relational(const KindRelational &x) : u{x} {} + template Relational(KindRelational &&x) : u{std::move(x)} {} + + std::optional> Fold(FoldingContext &); std::ostream &Dump(std::ostream &) const; - std::optional> Fold(FoldingContext &c); - int Rank() const { return 1; } // TODO - KindsVariant u; + KindsVariant u; }; template class Expr> { public: using Result = Type; using FoldableTrait = std::true_type; - template using Bin = Binary; - struct And : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Or : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Eqv : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - struct Neqv : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; - CLASS_BOILERPLATE(Expr) Expr(const Scalar &x) : u_{x} {} Expr(bool x) : u_{Scalar{x}} {} template - Expr(const Comparison> &x) : u_{CategoryComparison{x}} {} + Expr(const Relational> &x) : u_{Relational>{x}} {} template - Expr(Comparison> &&x) - : u_{CategoryComparison{std::move(x)}} {} + Expr(Relational> &&x) + : u_{Relational>{std::move(x)}} {} template Expr(const A &x) : u_(x) {} template Expr(std::enable_if_t, A> &&x) : u_{std::move(x)} {} @@ -568,11 +535,12 @@ public: private: std::variant, CopyableIndirection, CopyableIndirection, - // Parentheses, - Not, And, Or, Eqv, Neqv, CategoryComparison, - CategoryComparison, - CategoryComparison, - CategoryComparison> + // TODO Parentheses, + Not, LogicalOperation, + Relational>, + Relational>, + Relational>, + Relational>> u_; }; @@ -662,49 +630,49 @@ Expr> operator-(const Expr> &x) { } BINARY(+, Add) +BINARY(-, Subtract) +BINARY(*, Multiply) +BINARY(/, Divide) #undef BINARY +#if 0 #define OLDBINARY(FUNC, CONSTR) \ template A FUNC(const A &x, const A &y) { \ - return {typename A::CONSTR{x, y}}; \ + return {CONSTR{x, y}}; \ } \ template \ std::enable_if_t, A> FUNC(const A &x, A &&y) { \ - return {typename A::CONSTR{A{x}, std::move(y)}}; \ + return {CONSTR{A{x}, std::move(y)}}; \ } \ template \ std::enable_if_t, A> FUNC(A &&x, const A &y) { \ - return {typename A::CONSTR{std::move(x), A{y}}}; \ + return {CONSTR{std::move(x), A{y}}}; \ } \ template \ std::enable_if_t, A> FUNC(A &&x, A &&y) { \ - return {typename A::CONSTR{std::move(x), std::move(y)}}; \ + return {CONSTR{std::move(x), std::move(y)}}; \ } - -OLDBINARY(operator-, Subtract) -OLDBINARY(operator*, Multiply) -OLDBINARY(operator/, Divide) -OLDBINARY(Power, Power) #undef OLDBINARY +#endif #define BINARY(FUNC, OP) \ template Expr FUNC(const A &x, const A &y) { \ - return {Comparison>{OP, x, y}}; \ + return {Relational>{OP, x, y}}; \ } \ template \ std::enable_if_t, Expr> FUNC( \ const A &x, A &&y) { \ - return {Comparison>{OP, x, std::move(y)}}; \ + return {Relational>{OP, x, std::move(y)}}; \ } \ template \ std::enable_if_t, Expr> FUNC( \ A &&x, const A &y) { \ - return {Comparison>{OP, std::move(x), y}}; \ + return {Relational>{OP, std::move(x), y}}; \ } \ template \ std::enable_if_t, Expr> FUNC( \ A &&x, A &&y) { \ - return {Comparison>{OP, std::move(x), std::move(y)}}; \ + return {Relational>{OP, std::move(x), std::move(y)}}; \ } BINARY(operator<, RelationalOperator::LT) @@ -716,22 +684,22 @@ BINARY(operator>, RelationalOperator::GT) #undef BINARY extern template class Expr>; // TODO others -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; -extern template struct Comparison>; // TODO +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; +extern template struct Relational>; // TODO // more extern template class Expr>; extern template class Expr>; diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 5e3d2c1..ec01f51 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -38,7 +38,6 @@ using common::TypeCategory; // Specific intrinsic types template struct TypeBase { - static constexpr bool knowKind{true}; static constexpr TypeCategory category{C}; static constexpr int kind{KIND}; static constexpr bool hasLen{false}; @@ -259,7 +258,6 @@ struct GenericScalar { // Represents a type of any supported kind within a particular category. template struct SomeKind { - static constexpr bool knowKind{false}; using Scalar = SomeKindScalar; static constexpr TypeCategory category{CAT}; }; @@ -272,7 +270,6 @@ using SomeLogical = SomeKind; // Represents a completely generic type. struct SomeType { - static constexpr bool knowKind{false}; using Scalar = GenericScalar; }; diff --git a/flang/lib/evaluate/variable.cc b/flang/lib/evaluate/variable.cc index 7f36014..7bca1a37 100644 --- a/flang/lib/evaluate/variable.cc +++ b/flang/lib/evaluate/variable.cc @@ -357,7 +357,7 @@ Expr DataRef::LEN() const { u_); } Expr Substring::LEN() const { - return Expr::Max{ + return Extremum{ Expr{0}, last() - first() + Expr{1}}; } Expr ProcedureDesignator::LEN() const { diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index eb69ed8..99f941f 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -589,9 +589,10 @@ std::optional> ExpressionAnalyzer::ConstructComplex( return {std::visit( [](auto &&rx, auto &&ix) -> Expr { using realType = evaluate::ResultType; - using zType = evaluate::SameKind; - using zExpr = Expr; - return {zExpr{typename zExpr::CMPLX{std::move(rx), std::move(ix)}}}; + constexpr int kind{realType::kind}; + using zType = evaluate::Type; + return {Expr{evaluate::ComplexConstructor{ + std::move(rx), std::move(ix)}}}; }, std::move(joined->first.u), std::move(joined->second.u))}; } -- 2.7.4