[flang] Remove GenericExpr, move operator overloads to tools.h

Original-commit: flang-compiler/f18@23e7a6c27c
Reviewed-on: https://github.com/flang-compiler/f18/pull/183
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-08-20 09:29:08 -07:00
parent c0d3a67fac
commit b114c58118
8 changed files with 100 additions and 120 deletions

View File

@ -15,6 +15,7 @@
#include "expression.h" #include "expression.h"
#include "common.h" #include "common.h"
#include "int-power.h" #include "int-power.h"
#include "tools.h"
#include "variable.h" #include "variable.h"
#include "../common/idioms.h" #include "../common/idioms.h"
#include "../parser/characters.h" #include "../parser/characters.h"

View File

@ -42,6 +42,8 @@ using common::RelationalOperator;
// wrap discriminated unions. // wrap discriminated unions.
template<typename A> class Expr; template<typename A> class Expr;
template<typename A> using ResultType = typename std::decay_t<A>::Result;
template<typename DERIVED, typename RESULT, typename... OPERAND> template<typename DERIVED, typename RESULT, typename... OPERAND>
class Operation { class Operation {
public: public:
@ -597,92 +599,6 @@ public:
u; u;
}; };
using GenericExpr = Expr<SomeType>; // TODO: delete name?
template<typename A> using ResultType = typename std::decay_t<A>::Result;
// Convenience functions and operator overloadings for expression construction.
template<TypeCategory C, int K>
Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) {
return {Negate<Type<C, K>>{x}};
}
template<TypeCategory C>
Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) {
return std::visit(
[](const auto &y) -> Expr<SomeKind<C>> { return {-y}; }, x.u);
}
#define BINARY(op, CONSTR) \
template<TypeCategory C, int K> \
Expr<Type<C, K>> operator op( \
const Expr<Type<C, K>> &x, const Expr<Type<C, K>> &y) { \
return {CONSTR<Type<C, K>>{x, y}}; \
} \
template<TypeCategory C> \
Expr<SomeKind<C>> operator op( \
const Expr<SomeKind<C>> &x, const Expr<SomeKind<C>> &y) { \
return std::visit( \
[](const auto &xk, const auto &yk) -> Expr<SomeKind<C>> { \
return {xk op yk}; \
}, \
x.u, y.u); \
}
BINARY(+, Add)
BINARY(-, Subtract)
BINARY(*, Multiply)
BINARY(/, Divide)
#undef BINARY
#if 0
#define OLDBINARY(FUNC, CONSTR) \
template<typename A> A FUNC(const A &x, const A &y) { \
return {CONSTR<typename A::Result>{x, y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, A> FUNC(const A &x, A &&y) { \
return {CONSTR<typename A::Result>{A{x}, std::move(y)}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, const A &y) { \
return {CONSTR<typename A::Result>{std::move(x), A{y}}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, A &&y) { \
return {CONSTR<typename A::Result>{std::move(x), std::move(y)}}; \
}
#undef OLDBINARY
#endif
#define BINARY(FUNC, OP) \
template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \
return {Relational<ResultType<A>>{OP, x, y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
const A &x, A &&y) { \
return {Relational<ResultType<A>>{OP, x, std::move(y)}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
A &&x, const A &y) { \
return {Relational<ResultType<A>>{OP, std::move(x), y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
A &&x, A &&y) { \
return {Relational<ResultType<A>>{OP, std::move(x), std::move(y)}}; \
}
BINARY(operator<, RelationalOperator::LT)
BINARY(operator<=, RelationalOperator::LE)
BINARY(operator==, RelationalOperator::EQ)
BINARY(operator!=, RelationalOperator::NE)
BINARY(operator>=, RelationalOperator::GE)
BINARY(operator>, RelationalOperator::GT)
#undef BINARY
extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO others extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO others
extern template struct Relational<Type<TypeCategory::Integer, 1>>; extern template struct Relational<Type<TypeCategory::Integer, 1>>;
extern template struct Relational<Type<TypeCategory::Integer, 2>>; extern template struct Relational<Type<TypeCategory::Integer, 2>>;

View File

@ -20,20 +20,9 @@ using namespace Fortran::parser::literals;
namespace Fortran::evaluate { namespace Fortran::evaluate {
Expr<SomeReal> ConvertToTypeOf(
const Expr<SomeReal> &to, const Expr<SomeInteger> &from) {
return std::visit(
[&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
}
Expr<SomeReal> ConvertToTypeOf(
const Expr<SomeReal> &to, const Expr<SomeReal> &from) {
return std::visit(
[&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
}
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands( std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) { parser::ContextualMessages &messages, Expr<SomeType> &&x,
Expr<SomeType> &&y) {
return std::visit( return std::visit(
common::visitors{[&](Expr<SomeInteger> &&ix, Expr<SomeInteger> &&iy) { common::visitors{[&](Expr<SomeInteger> &&ix, Expr<SomeInteger> &&iy) {
// Can happen in a CMPLX() constructor. Per F'2018, // Can happen in a CMPLX() constructor. Per F'2018,
@ -43,11 +32,11 @@ std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
Expr<SomeReal>{Expr<DefaultReal>{std::move(iy)}})}; Expr<SomeReal>{Expr<DefaultReal>{std::move(iy)}})};
}, },
[&](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) { [&](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) {
auto rx{ConvertToTypeOf(ry, std::move(ix))}; auto rx{ConvertToTypeAndKindOf(ry, std::move(ix))};
return std::optional{std::make_pair(std::move(rx), std::move(ry))}; return std::optional{std::make_pair(std::move(rx), std::move(ry))};
}, },
[&](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) { [&](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) {
auto ry{ConvertToTypeOf(rx, std::move(iy))}; auto ry{ConvertToTypeAndKindOf(rx, std::move(iy))};
return std::optional{std::make_pair(std::move(rx), std::move(ry))}; return std::optional{std::make_pair(std::move(rx), std::move(ry))};
}, },
[&](Expr<SomeReal> &&rx, Expr<SomeReal> &&ry) { [&](Expr<SomeReal> &&rx, Expr<SomeReal> &&ry) {
@ -63,8 +52,8 @@ std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
} }
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands( std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
parser::ContextualMessages &messages, std::optional<GenericExpr> &&x, parser::ContextualMessages &messages, std::optional<Expr<SomeType>> &&x,
std::optional<GenericExpr> &&y) { std::optional<Expr<SomeType>> &&y) {
if (x.has_value() && y.has_value()) { if (x.has_value() && y.has_value()) {
return ConvertRealOperands(messages, std::move(*x), std::move(*y)); return ConvertRealOperands(messages, std::move(*x), std::move(*y));
} }

View File

@ -23,18 +23,92 @@
namespace Fortran::evaluate { namespace Fortran::evaluate {
// Convert the second argument to the same type and kind of the first. // Convenience functions and operator overloadings for expression construction.
Expr<SomeReal> ConvertToTypeOf( template<TypeCategory C, int K>
const Expr<SomeReal> &to, const Expr<SomeInteger> &from); Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
Expr<SomeReal> ConvertToTypeOf( return {Negate<Type<C, K>>{std::move(x)}};
const Expr<SomeReal> &to, const Expr<SomeReal> &from); }
template<TypeCategory C, int K>
Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Add<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Subtract<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator*(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Multiply<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator/(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Divide<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C> Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x) {
return std::visit(
[](auto &xk) { return Expr<SomeKind<C>>{-std::move(xk)}; }, x.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator+(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) + std::move(yk)};
},
x.u, y.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) - std::move(yk)};
},
x.u, y.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator*(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) * std::move(yk)};
},
x.u, y.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator/(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) / std::move(yk)};
},
x.u, y.u);
}
// Convert the second argument expression to an expression of the same type
// and kind as that of the first.
template<TypeCategory TC, typename F>
Expr<SomeKind<TC>> ConvertToTypeAndKindOf(
const Expr<SomeKind<TC>> &to, Expr<F> &&from) {
return std::visit(
[&](const auto &tk) -> Expr<SomeKind<TC>> {
using SpecificExpr = std::decay_t<decltype(tk)>;
return {SpecificExpr{std::move(from)}};
},
to.u);
}
// Ensure that both operands of an intrinsic REAL operation or CMPLX() // Ensure that both operands of an intrinsic REAL operation or CMPLX()
// are INTEGER or REAL, and convert them as necessary to the same REAL type. // are INTEGER or REAL, and convert them as necessary to the same REAL type.
using ConvertRealOperandsResult = using ConvertRealOperandsResult =
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>>; std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>>;
ConvertRealOperandsResult ConvertRealOperands( ConvertRealOperandsResult ConvertRealOperands(
parser::ContextualMessages &, GenericExpr &&, GenericExpr &&); parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
template<TypeCategory CAT> template<TypeCategory CAT>
void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) { void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) {

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "variable.h" #include "variable.h"
#include "tools.h"
#include "../common/idioms.h" #include "../common/idioms.h"
#include "../parser/char-block.h" #include "../parser/char-block.h"
#include "../parser/characters.h" #include "../parser/characters.h"

View File

@ -25,7 +25,7 @@ namespace Fortran::semantics {
using common::TypeCategory; using common::TypeCategory;
using evaluate::Expr; using evaluate::Expr;
using evaluate::GenericExpr; using evaluate::SomeType;
using evaluate::Type; using evaluate::Type;
using MaybeIntExpr = std::optional<Expr<evaluate::SomeInteger>>; using MaybeIntExpr = std::optional<Expr<evaluate::SomeInteger>>;
@ -117,8 +117,8 @@ static std::optional<Expr<evaluate::SomeCharacter>> AnalyzeLiteral(
} }
template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) { template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
std::function<GenericExpr(A &&)> f{ std::function<Expr<SomeType>(A &&)> f{
[](A &&y) { return GenericExpr{std::move(y)}; }}; [](A &&y) { return Expr<SomeType>{std::move(y)}; }};
return common::MapOptional(f, std::move(x)); return common::MapOptional(f, std::move(x));
} }
@ -153,7 +153,7 @@ MaybeExpr AnalyzeHelper(
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)}; evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)}; Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)};
chExpr.Fold(ea.context()); chExpr.Fold(ea.context());
return {GenericExpr{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}}; return {Expr<SomeType>{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
} }
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant // Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
@ -269,7 +269,7 @@ static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) { AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) {
if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) { if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
if (sign == parser::Sign::Negative) { if (sign == parser::Sign::Negative) {
return {-*result}; return {-std::move(*result)};
} }
} }
return result; return result;
@ -577,12 +577,12 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex( std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex(
MaybeExpr &&real, MaybeExpr &&imaginary) { MaybeExpr &&real, MaybeExpr &&imaginary) {
// TODO: pmk abstract further, this will be a common pattern // TODO: pmk abstract further, this will be a common pattern
auto partial{[&](GenericExpr &&x, GenericExpr &&y) { auto partial{[&](Expr<SomeType> &&x, Expr<SomeType> &&y) {
return evaluate::ConvertRealOperands( return evaluate::ConvertRealOperands(
context_.messages, std::move(x), std::move(y)); context_.messages, std::move(x), std::move(y));
}}; }};
using fType = using fType =
evaluate::ConvertRealOperandsResult(GenericExpr &&, GenericExpr &&); evaluate::ConvertRealOperandsResult(Expr<SomeType> &&, Expr<SomeType> &&);
std::function<fType> f{partial}; std::function<fType> f{partial};
auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))}; auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))};
if (auto joined{common::JoinOptionals(std::move(converted))}) { if (auto joined{common::JoinOptionals(std::move(converted))}) {

View File

@ -23,7 +23,7 @@
namespace Fortran::semantics { namespace Fortran::semantics {
using MaybeExpr = std::optional<evaluate::GenericExpr>; using MaybeExpr = std::optional<evaluate::Expr<evaluate::SomeType>>;
class ExpressionAnalyzer { class ExpressionAnalyzer {
public: public:

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "../../lib/evaluate/expression.h" #include "../../lib/evaluate/expression.h"
#include "../../lib/evaluate/tools.h"
#include "testing.h" #include "testing.h"
#include "../../lib/parser/message.h" #include "../../lib/parser/message.h"
#include <cstdio> #include <cstdio>
@ -41,11 +42,9 @@ int main() {
FoldingContext context{messages}; FoldingContext context{messages};
ex1.Fold(context); ex1.Fold(context);
MATCH("-10_4", Dump(ex1)); MATCH("-10_4", Dump(ex1));
MATCH("(6_4.LE.7_4)", MATCH("(1_4/2_4)", Dump(DefaultIntegerExpr{1} / DefaultIntegerExpr{2}));
Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
DefaultIntegerExpr a{1}; DefaultIntegerExpr a{1};
DefaultIntegerExpr b{2}; DefaultIntegerExpr b{2};
MATCH("(1_4/2_4)", Dump(a / b));
MATCH("1_4", Dump(a)); MATCH("1_4", Dump(a));
a = b; a = b;
MATCH("2_4", Dump(a)); MATCH("2_4", Dump(a));